1// Copyright 2016 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5// This is intended for permanent JS behavior changes for mocking out
6// non-deterministic behavior. For temporary suppressions, please refer to
7// v8_suppressions.js.
8// This file is loaded before each correctness test cases and won't get
9// minimized.
10
11
12// This will be overridden in the test cases. The override can be minimized.
13var prettyPrinted = function prettyPrinted(msg) { return msg; };
14
15// Mock Math.random.
16(function() {
17  let index = 1;
18  Math.random = function() {
19      const x = Math.sin(index++) * 10000;
20      return x - Math.floor(x);
21  }
22})();
23
24// Mock Math.pow. Work around an optimization for -0.5.
25(function() {
26  const origMathPow = Math.pow;
27  Math.pow = function(a, b) {
28    if (b === -0.5) {
29      return 0;
30    } else {
31      return origMathPow(a, b);
32    }
33  }
34})();
35
36
37// Mock Date.
38(function() {
39  let index = 0;
40  let mockDate = 1477662728696;
41  const mockDateNow = function() {
42    index = (index + 1) % 10;
43    mockDate = mockDate + index + 1;
44    return mockDate;
45  }
46
47  const origDate = Date;
48  const construct = Reflect.construct;
49  const constructDate = function(args) {
50    let result;
51    if (args.length) {
52      result = construct(origDate, args);
53    } else {
54      result = new origDate(mockDateNow());
55    }
56    result.constructor = function(...args) { return constructDate(args); }
57    Object.defineProperty(
58        result, "constructor", { configurable: false, writable: false });
59    return result;
60  }
61
62  origDate.prototype.constructor = function(...args) {
63    return constructDate(args);
64  };
65
66  var handler = {
67    apply: function(target, thisArg, args) {
68      return constructDate(args);
69    },
70    construct: function(target, args, newTarget) {
71      return constructDate(args);
72    },
73    get: function(target, property, receiver) {
74      if (property == "now") {
75        return mockDateNow;
76      }
77      if (property == "prototype") {
78        return origDate.prototype;
79      }
80    },
81  }
82
83  Date = new Proxy(Date, handler);
84})();
85
86// Mock performance methods.
87performance.now = function() { return 1.2; };
88performance.measureMemory = function() { return []; };
89
90// Mock readline so that test cases don't hang.
91readline = function() { return "foo"; };
92
93// Mock stack traces.
94Error.prepareStackTrace = function(error, structuredStackTrace) {
95  return "";
96};
97Object.defineProperty(
98    Error, 'prepareStackTrace', { configurable: false, writable: false });
99
100// Mock buffer access in float typed arrays because of varying NaN patterns.
101(function() {
102  const origArrayFrom = Array.from;
103  const origArrayIsArray = Array.isArray;
104  const origFunctionPrototype = Function.prototype;
105  const origIsNaN = isNaN;
106  const origIterator = Symbol.iterator;
107  const deNaNify = function(value) { return origIsNaN(value) ? 1 : value; };
108  const mock = function(type) {
109
110    // Remove NaN values from parameters to "set" function.
111    const set = type.prototype.set;
112    type.prototype.set = function(array, offset) {
113      if (Array.isArray(array)) {
114        array = array.map(deNaNify);
115      }
116      set.apply(this, [array, offset]);
117    };
118
119    const handler = {
120      // Remove NaN values from parameters to constructor.
121      construct: function(target, args) {
122        for (let i = 0; i < args.length; i++) {
123          if (args[i] != null &&
124              typeof args[i][origIterator] === 'function') {
125            // Consume iterators.
126            args[i] = origArrayFrom(args[i]);
127          }
128          if (origArrayIsArray(args[i])) {
129            args[i] = args[i].map(deNaNify);
130          }
131        }
132
133        const obj = new (
134            origFunctionPrototype.bind.call(type, null, ...args));
135        return new Proxy(obj, {
136          get: function(x, prop) {
137            if (typeof x[prop] == "function")
138              return x[prop].bind(obj);
139            return x[prop];
140          },
141          // Remove NaN values that get assigned.
142          set: function(target, prop, value, receiver) {
143            target[prop] = deNaNify(value);
144            return value;
145          }
146        });
147      },
148    };
149    return new Proxy(type, handler);
150  }
151
152  Float32Array = mock(Float32Array);
153  Float64Array = mock(Float64Array);
154})();
155
156// Mock buffer access via DataViews because of varying NaN patterns.
157(function() {
158  const origIsNaN = isNaN;
159  const deNaNify = function(value) { return origIsNaN(value) ? 1 : value; };
160  const origSetFloat32 = DataView.prototype.setFloat32;
161  DataView.prototype.setFloat32 = function(offset, value, ...rest) {
162    origSetFloat32.call(this, offset, deNaNify(value), ...rest);
163  };
164  const origSetFloat64 = DataView.prototype.setFloat64;
165  DataView.prototype.setFloat64 = function(offset, value, ...rest) {
166    origSetFloat64.call(this, offset, deNaNify(value), ...rest);
167  };
168})();
169
170// Mock Worker.
171(function() {
172  let index = 0;
173  // TODO(machenbach): Randomize this for each test case, but keep stable
174  // during comparison. Also data and random above.
175  const workerMessages = [
176    undefined, 0, -1, "", "foo", 42, [], {}, [0], {"x": 0}
177  ];
178  Worker = function(code){
179    try {
180      print(prettyPrinted(eval(code)));
181    } catch(e) {
182      print(prettyPrinted(e));
183    }
184    this.getMessage = function(){
185      index = (index + 1) % 10;
186      return workerMessages[index];
187    }
188    this.postMessage = function(msg){
189      print(prettyPrinted(msg));
190    }
191  };
192})();
193
194// Mock Realm.
195Realm.eval = function(realm, code) { return eval(code) };
196
197// Mock the nondeterministic parts of WeakRef and FinalizationRegistry.
198WeakRef.prototype.deref = function() { };
199FinalizationRegistry = function(callback) { };
200FinalizationRegistry.prototype.register = function(target, holdings) { };
201FinalizationRegistry.prototype.unregister = function(unregisterToken) { };
202FinalizationRegistry.prototype.cleanupSome = function() { };
203FinalizationRegistry.prototype[Symbol.toStringTag] = "FinalizationRegistry";
204
205// Mock the nondeterministic Atomics.waitAsync.
206Atomics.waitAsync = function() {
207  // Return a mock "Promise" whose "then" function will call the callback
208  // immediately.
209  return {'value': {'then': function (f) { f(); }}};
210}
211