1bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org// Copyright 2013 the V8 project authors. All rights reserved.
2bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org// Redistribution and use in source and binary forms, with or without
3bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org// modification, are permitted provided that the following conditions are
4bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org// met:
5bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org//
6bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org//     * Redistributions of source code must retain the above copyright
7bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org//       notice, this list of conditions and the following disclaimer.
8bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org//     * Redistributions in binary form must reproduce the above
9bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org//       copyright notice, this list of conditions and the following
10bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org//       disclaimer in the documentation and/or other materials provided
11bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org//       with the distribution.
12bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org//     * Neither the name of Google Inc. nor the names of its
13bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org//       contributors may be used to endorse or promote products derived
14bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org//       from this software without specific prior written permission.
15bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org//
16bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org
28bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org// Some methods are taken from v8/test/mjsunit/mjsunit.js
29bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org
30bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org/**
31bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org * Compares two objects for key/value equality.
32bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org * Returns true if they are equal, false otherwise.
33bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org */
34bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.orgfunction deepObjectEquals(a, b) {
35bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org  var aProps = Object.keys(a);
36bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org  aProps.sort();
37bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org  var bProps = Object.keys(b);
38bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org  bProps.sort();
39bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org  if (!deepEquals(aProps, bProps)) {
40bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org    return false;
41bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org  }
42bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org  for (var i = 0; i < aProps.length; i++) {
43bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org    if (!deepEquals(a[aProps[i]], b[aProps[i]])) {
44bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org      return false;
45bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org    }
46bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org  }
47bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org  return true;
48bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org}
49bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org
50bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org
51bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org/**
52bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org * Compares two JavaScript values for type and value equality.
53bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org * It checks internals of arrays and objects.
54bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org */
55bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.orgfunction deepEquals(a, b) {
56bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org  if (a === b) {
57bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org    // Check for -0.
58bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org    if (a === 0) return (1 / a) === (1 / b);
59bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org    return true;
60bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org  }
61bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org  if (typeof a != typeof b) return false;
62bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org  if (typeof a == 'number') return isNaN(a) && isNaN(b);
63bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org  if (typeof a !== 'object' && typeof a !== 'function') return false;
64bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org  // Neither a nor b is primitive.
65bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org  var objectClass = classOf(a);
66bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org  if (objectClass !== classOf(b)) return false;
67bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org  if (objectClass === 'RegExp') {
68bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org    // For RegExp, just compare pattern and flags using its toString.
69bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org    return (a.toString() === b.toString());
70bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org  }
71bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org  // Functions are only identical to themselves.
72bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org  if (objectClass === 'Function') return false;
73bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org  if (objectClass === 'Array') {
74bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org    var elementCount = 0;
75bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org    if (a.length != b.length) {
76bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org      return false;
77bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org    }
78bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org    for (var i = 0; i < a.length; i++) {
79bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org      if (!deepEquals(a[i], b[i])) return false;
80bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org    }
81bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org    return true;
82bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org  }
83bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org  if (objectClass == 'String' || objectClass == 'Number' ||
84bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org      objectClass == 'Boolean' || objectClass == 'Date') {
85bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org    if (a.valueOf() !== b.valueOf()) return false;
86bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org  }
87bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org  return deepObjectEquals(a, b);
88bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org}
89bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org
90bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org
91bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org/**
92bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org * Throws an exception, and prints the values in case of error.
93bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org */
94bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.orgfunction fail(expected, found) {
95bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org  // TODO(cira): Replace String with PrettyPrint for objects and arrays.
96bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org  var message = 'Failure: expected <' + String(expected) + '>, found <' +
97bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org      String(found) + '>.';
98bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org  throw new Error(message);
99bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org}
100bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org
101bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org
102bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org/**
103bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org * Throws if two variables have different types or values.
104bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org */
105bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.orgfunction assertEquals(expected, found) {
106bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org  if (!deepEquals(expected, found)) {
107bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org    fail(expected, found);
108bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org  }
109bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org}
110bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org
111bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org
112bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org/**
113bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org * Throws if value is false.
114bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org */
115bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.orgfunction assertTrue(value) {
116bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org  assertEquals(true, value)
117bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org}
118bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org
119bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org
120bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org/**
121bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org * Throws if value is true.
122bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org */
123bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.orgfunction assertFalse(value) {
124bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org  assertEquals(false, value);
125bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org}
126bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org
127bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org
128bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org/**
129bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org * Returns true if code throws specified exception.
130bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org */
131bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.orgfunction assertThrows(code, type_opt, cause_opt) {
132bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org  var threwException = true;
133bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org  try {
134bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org    if (typeof code == 'function') {
135bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org      code();
136bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org    } else {
137bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org      eval(code);
138bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org    }
139bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org    threwException = false;
140bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org  } catch (e) {
141bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org    if (typeof type_opt == 'function') {
142bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org      assertInstanceof(e, type_opt);
143bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org    }
144bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org    if (arguments.length >= 3) {
145bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org      assertEquals(e.type, cause_opt);
146bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org    }
147bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org    // Success.
148bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org    return;
149bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org  }
150bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org  throw new Error("Did not throw exception");
151bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org}
152bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org
153bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org
154bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org/**
155bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org * Throws an exception if code throws.
156bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org */
157bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.orgfunction assertDoesNotThrow(code, name_opt) {
158bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org  try {
159bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org    if (typeof code == 'function') {
160bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org      code();
161bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org    } else {
162bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org      eval(code);
163bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org    }
164bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org  } catch (e) {
165bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org    fail("threw an exception: ", e.message || e, name_opt);
166bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org  }
167bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org}
168bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org
169bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org
170bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org/**
171bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org * Throws if obj is not of given type.
172bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org */
173bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.orgfunction assertInstanceof(obj, type) {
174bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org  if (!(obj instanceof type)) {
175bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org    var actualTypeName = null;
176bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org    var actualConstructor = Object.prototypeOf(obj).constructor;
177bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org    if (typeof actualConstructor == "function") {
178bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org      actualTypeName = actualConstructor.name || String(actualConstructor);
179bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org    }
180bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org    throw new Error('Object <' + obj + '> is not an instance of <' +
181bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org         (type.name || type) + '>' +
182bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org         (actualTypeName ? ' but of < ' + actualTypeName + '>' : ''));
183bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org  }
184bee51999422c0eeaae85ed99b5c0bd4126510ff1danno@chromium.org}
185