You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

es5.js 33KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784
  1. 'use strict';
  2. var ES = require('../').ES5;
  3. var test = require('tape');
  4. var forEach = require('foreach');
  5. var is = require('object-is');
  6. var debug = require('object-inspect');
  7. var v = require('./helpers/values');
  8. require('./helpers/runManifestTest')(test, ES, 5);
  9. test('ToPrimitive', function (t) {
  10. t.test('primitives', function (st) {
  11. var testPrimitive = function (primitive) {
  12. st.ok(is(ES.ToPrimitive(primitive), primitive), debug(primitive) + ' is returned correctly');
  13. };
  14. forEach(v.primitives, testPrimitive);
  15. st.end();
  16. });
  17. t.test('objects', function (st) {
  18. st.equal(ES.ToPrimitive(v.coercibleObject), v.coercibleObject.valueOf(), 'coercibleObject coerces to valueOf');
  19. st.equal(ES.ToPrimitive(v.coercibleObject, Number), v.coercibleObject.valueOf(), 'coercibleObject with hint Number coerces to valueOf');
  20. st.equal(ES.ToPrimitive(v.coercibleObject, String), v.coercibleObject.toString(), 'coercibleObject with hint String coerces to toString');
  21. st.equal(ES.ToPrimitive(v.coercibleFnObject), v.coercibleFnObject.toString(), 'coercibleFnObject coerces to toString');
  22. st.equal(ES.ToPrimitive(v.toStringOnlyObject), v.toStringOnlyObject.toString(), 'toStringOnlyObject returns toString');
  23. st.equal(ES.ToPrimitive(v.valueOfOnlyObject), v.valueOfOnlyObject.valueOf(), 'valueOfOnlyObject returns valueOf');
  24. st.equal(ES.ToPrimitive({}), '[object Object]', '{} with no hint coerces to Object#toString');
  25. st.equal(ES.ToPrimitive({}, String), '[object Object]', '{} with hint String coerces to Object#toString');
  26. st.equal(ES.ToPrimitive({}, Number), '[object Object]', '{} with hint Number coerces to Object#toString');
  27. st['throws'](function () { return ES.ToPrimitive(v.uncoercibleObject); }, TypeError, 'uncoercibleObject throws a TypeError');
  28. st['throws'](function () { return ES.ToPrimitive(v.uncoercibleFnObject); }, TypeError, 'uncoercibleFnObject throws a TypeError');
  29. st.end();
  30. });
  31. t.end();
  32. });
  33. test('ToBoolean', function (t) {
  34. t.equal(false, ES.ToBoolean(undefined), 'undefined coerces to false');
  35. t.equal(false, ES.ToBoolean(null), 'null coerces to false');
  36. t.equal(false, ES.ToBoolean(false), 'false returns false');
  37. t.equal(true, ES.ToBoolean(true), 'true returns true');
  38. forEach([0, -0, NaN], function (falsyNumber) {
  39. t.equal(false, ES.ToBoolean(falsyNumber), 'falsy number ' + falsyNumber + ' coerces to false');
  40. });
  41. forEach([Infinity, 42, 1, -Infinity], function (truthyNumber) {
  42. t.equal(true, ES.ToBoolean(truthyNumber), 'truthy number ' + truthyNumber + ' coerces to true');
  43. });
  44. t.equal(false, ES.ToBoolean(''), 'empty string coerces to false');
  45. t.equal(true, ES.ToBoolean('foo'), 'nonempty string coerces to true');
  46. forEach(v.objects, function (obj) {
  47. t.equal(true, ES.ToBoolean(obj), 'object coerces to true');
  48. });
  49. t.equal(true, ES.ToBoolean(v.uncoercibleObject), 'uncoercibleObject coerces to true');
  50. t.end();
  51. });
  52. test('ToNumber', function (t) {
  53. t.ok(is(NaN, ES.ToNumber(undefined)), 'undefined coerces to NaN');
  54. t.ok(is(ES.ToNumber(null), 0), 'null coerces to +0');
  55. t.ok(is(ES.ToNumber(false), 0), 'false coerces to +0');
  56. t.equal(1, ES.ToNumber(true), 'true coerces to 1');
  57. t.ok(is(NaN, ES.ToNumber(NaN)), 'NaN returns itself');
  58. forEach([0, -0, 42, Infinity, -Infinity], function (num) {
  59. t.equal(num, ES.ToNumber(num), num + ' returns itself');
  60. });
  61. forEach(['foo', '0', '4a', '2.0', 'Infinity', '-Infinity'], function (numString) {
  62. t.ok(is(+numString, ES.ToNumber(numString)), '"' + numString + '" coerces to ' + Number(numString));
  63. });
  64. forEach(v.objects, function (object) {
  65. t.ok(is(ES.ToNumber(object), ES.ToNumber(ES.ToPrimitive(object))), 'object ' + object + ' coerces to same as ToPrimitive of object does');
  66. });
  67. t['throws'](function () { return ES.ToNumber(v.uncoercibleObject); }, TypeError, 'uncoercibleObject throws');
  68. t.end();
  69. });
  70. test('ToInteger', function (t) {
  71. t.ok(is(0, ES.ToInteger(NaN)), 'NaN coerces to +0');
  72. forEach([0, Infinity, 42], function (num) {
  73. t.ok(is(num, ES.ToInteger(num)), num + ' returns itself');
  74. t.ok(is(-num, ES.ToInteger(-num)), '-' + num + ' returns itself');
  75. });
  76. t.equal(3, ES.ToInteger(Math.PI), 'pi returns 3');
  77. t['throws'](function () { return ES.ToInteger(v.uncoercibleObject); }, TypeError, 'uncoercibleObject throws');
  78. t.end();
  79. });
  80. test('ToInt32', function (t) {
  81. t.ok(is(0, ES.ToInt32(NaN)), 'NaN coerces to +0');
  82. forEach([0, Infinity], function (num) {
  83. t.ok(is(0, ES.ToInt32(num)), num + ' returns +0');
  84. t.ok(is(0, ES.ToInt32(-num)), '-' + num + ' returns +0');
  85. });
  86. t['throws'](function () { return ES.ToInt32(v.uncoercibleObject); }, TypeError, 'uncoercibleObject throws');
  87. t.ok(is(ES.ToInt32(0x100000000), 0), '2^32 returns +0');
  88. t.ok(is(ES.ToInt32(0x100000000 - 1), -1), '2^32 - 1 returns -1');
  89. t.ok(is(ES.ToInt32(0x80000000), -0x80000000), '2^31 returns -2^31');
  90. t.ok(is(ES.ToInt32(0x80000000 - 1), 0x80000000 - 1), '2^31 - 1 returns 2^31 - 1');
  91. forEach([0, Infinity, NaN, 0x100000000, 0x80000000, 0x10000, 0x42], function (num) {
  92. t.ok(is(ES.ToInt32(num), ES.ToInt32(ES.ToUint32(num))), 'ToInt32(x) === ToInt32(ToUint32(x)) for 0x' + num.toString(16));
  93. t.ok(is(ES.ToInt32(-num), ES.ToInt32(ES.ToUint32(-num))), 'ToInt32(x) === ToInt32(ToUint32(x)) for -0x' + num.toString(16));
  94. });
  95. t.end();
  96. });
  97. test('ToUint32', function (t) {
  98. t.ok(is(0, ES.ToUint32(NaN)), 'NaN coerces to +0');
  99. forEach([0, Infinity], function (num) {
  100. t.ok(is(0, ES.ToUint32(num)), num + ' returns +0');
  101. t.ok(is(0, ES.ToUint32(-num)), '-' + num + ' returns +0');
  102. });
  103. t['throws'](function () { return ES.ToUint32(v.uncoercibleObject); }, TypeError, 'uncoercibleObject throws');
  104. t.ok(is(ES.ToUint32(0x100000000), 0), '2^32 returns +0');
  105. t.ok(is(ES.ToUint32(0x100000000 - 1), 0x100000000 - 1), '2^32 - 1 returns 2^32 - 1');
  106. t.ok(is(ES.ToUint32(0x80000000), 0x80000000), '2^31 returns 2^31');
  107. t.ok(is(ES.ToUint32(0x80000000 - 1), 0x80000000 - 1), '2^31 - 1 returns 2^31 - 1');
  108. forEach([0, Infinity, NaN, 0x100000000, 0x80000000, 0x10000, 0x42], function (num) {
  109. t.ok(is(ES.ToUint32(num), ES.ToUint32(ES.ToInt32(num))), 'ToUint32(x) === ToUint32(ToInt32(x)) for 0x' + num.toString(16));
  110. t.ok(is(ES.ToUint32(-num), ES.ToUint32(ES.ToInt32(-num))), 'ToUint32(x) === ToUint32(ToInt32(x)) for -0x' + num.toString(16));
  111. });
  112. t.end();
  113. });
  114. test('ToUint16', function (t) {
  115. t.ok(is(0, ES.ToUint16(NaN)), 'NaN coerces to +0');
  116. forEach([0, Infinity], function (num) {
  117. t.ok(is(0, ES.ToUint16(num)), num + ' returns +0');
  118. t.ok(is(0, ES.ToUint16(-num)), '-' + num + ' returns +0');
  119. });
  120. t['throws'](function () { return ES.ToUint16(v.uncoercibleObject); }, TypeError, 'uncoercibleObject throws');
  121. t.ok(is(ES.ToUint16(0x100000000), 0), '2^32 returns +0');
  122. t.ok(is(ES.ToUint16(0x100000000 - 1), 0x10000 - 1), '2^32 - 1 returns 2^16 - 1');
  123. t.ok(is(ES.ToUint16(0x80000000), 0), '2^31 returns +0');
  124. t.ok(is(ES.ToUint16(0x80000000 - 1), 0x10000 - 1), '2^31 - 1 returns 2^16 - 1');
  125. t.ok(is(ES.ToUint16(0x10000), 0), '2^16 returns +0');
  126. t.ok(is(ES.ToUint16(0x10000 - 1), 0x10000 - 1), '2^16 - 1 returns 2^16 - 1');
  127. t.end();
  128. });
  129. test('ToString', function (t) {
  130. t['throws'](function () { return ES.ToString(v.uncoercibleObject); }, TypeError, 'uncoercibleObject throws');
  131. t.end();
  132. });
  133. test('ToObject', function (t) {
  134. t['throws'](function () { return ES.ToObject(undefined); }, TypeError, 'undefined throws');
  135. t['throws'](function () { return ES.ToObject(null); }, TypeError, 'null throws');
  136. forEach(v.numbers, function (number) {
  137. var obj = ES.ToObject(number);
  138. t.equal(typeof obj, 'object', 'number ' + number + ' coerces to object');
  139. t.equal(true, obj instanceof Number, 'object of ' + number + ' is Number object');
  140. t.ok(is(obj.valueOf(), number), 'object of ' + number + ' coerces to ' + number);
  141. });
  142. t.end();
  143. });
  144. test('CheckObjectCoercible', function (t) {
  145. t['throws'](function () { return ES.CheckObjectCoercible(undefined); }, TypeError, 'undefined throws');
  146. t['throws'](function () { return ES.CheckObjectCoercible(null); }, TypeError, 'null throws');
  147. var checkCoercible = function (value) {
  148. t.doesNotThrow(function () { return ES.CheckObjectCoercible(value); }, debug(value) + ' does not throw');
  149. };
  150. forEach(v.objects.concat(v.nonNullPrimitives), checkCoercible);
  151. t.end();
  152. });
  153. test('IsCallable', function (t) {
  154. t.equal(true, ES.IsCallable(function () {}), 'function is callable');
  155. var nonCallables = [/a/g, {}, Object.prototype, NaN].concat(v.primitives);
  156. forEach(nonCallables, function (nonCallable) {
  157. t.equal(false, ES.IsCallable(nonCallable), debug(nonCallable) + ' is not callable');
  158. });
  159. t.end();
  160. });
  161. test('SameValue', function (t) {
  162. t.equal(true, ES.SameValue(NaN, NaN), 'NaN is SameValue as NaN');
  163. t.equal(false, ES.SameValue(0, -0), '+0 is not SameValue as -0');
  164. forEach(v.objects.concat(v.primitives), function (val) {
  165. t.equal(val === val, ES.SameValue(val, val), debug(val) + ' is SameValue to itself');
  166. });
  167. t.end();
  168. });
  169. test('Type', function (t) {
  170. t.equal(ES.Type(), 'Undefined', 'Type() is Undefined');
  171. t.equal(ES.Type(undefined), 'Undefined', 'Type(undefined) is Undefined');
  172. t.equal(ES.Type(null), 'Null', 'Type(null) is Null');
  173. t.equal(ES.Type(true), 'Boolean', 'Type(true) is Boolean');
  174. t.equal(ES.Type(false), 'Boolean', 'Type(false) is Boolean');
  175. t.equal(ES.Type(0), 'Number', 'Type(0) is Number');
  176. t.equal(ES.Type(NaN), 'Number', 'Type(NaN) is Number');
  177. t.equal(ES.Type('abc'), 'String', 'Type("abc") is String');
  178. t.equal(ES.Type(function () {}), 'Object', 'Type(function () {}) is Object');
  179. t.equal(ES.Type({}), 'Object', 'Type({}) is Object');
  180. t.end();
  181. });
  182. test('IsPropertyDescriptor', function (t) {
  183. forEach(v.primitives, function (primitive) {
  184. t.equal(ES.IsPropertyDescriptor(primitive), false, debug(primitive) + ' is not a Property Descriptor');
  185. });
  186. t.equal(ES.IsPropertyDescriptor({ invalid: true }), false, 'invalid keys not allowed on a Property Descriptor');
  187. t.equal(ES.IsPropertyDescriptor({}), true, 'empty object is an incomplete Property Descriptor');
  188. t.equal(ES.IsPropertyDescriptor(v.accessorDescriptor()), true, 'accessor descriptor is a Property Descriptor');
  189. t.equal(ES.IsPropertyDescriptor(v.mutatorDescriptor()), true, 'mutator descriptor is a Property Descriptor');
  190. t.equal(ES.IsPropertyDescriptor(v.dataDescriptor()), true, 'data descriptor is a Property Descriptor');
  191. t.equal(ES.IsPropertyDescriptor(v.genericDescriptor()), true, 'generic descriptor is a Property Descriptor');
  192. t['throws'](
  193. function () { ES.IsPropertyDescriptor(v.bothDescriptor()); },
  194. TypeError,
  195. 'a Property Descriptor can not be both a Data and an Accessor Descriptor'
  196. );
  197. t['throws'](
  198. function () { ES.IsPropertyDescriptor(v.bothDescriptorWritable()); },
  199. TypeError,
  200. 'a Property Descriptor can not be both a Data and an Accessor Descriptor'
  201. );
  202. t.end();
  203. });
  204. test('IsAccessorDescriptor', function (t) {
  205. forEach(v.nonNullPrimitives.concat(null), function (primitive) {
  206. t['throws'](function () { ES.IsAccessorDescriptor(primitive); }, TypeError, debug(primitive) + ' is not a Property Descriptor');
  207. });
  208. t.equal(ES.IsAccessorDescriptor(), false, 'no value is not an Accessor Descriptor');
  209. t.equal(ES.IsAccessorDescriptor(undefined), false, 'undefined value is not an Accessor Descriptor');
  210. t.equal(ES.IsAccessorDescriptor(v.accessorDescriptor()), true, 'accessor descriptor is an Accessor Descriptor');
  211. t.equal(ES.IsAccessorDescriptor(v.mutatorDescriptor()), true, 'mutator descriptor is an Accessor Descriptor');
  212. t.equal(ES.IsAccessorDescriptor(v.dataDescriptor()), false, 'data descriptor is not an Accessor Descriptor');
  213. t.equal(ES.IsAccessorDescriptor(v.genericDescriptor()), false, 'generic descriptor is not an Accessor Descriptor');
  214. t.end();
  215. });
  216. test('IsDataDescriptor', function (t) {
  217. forEach(v.nonNullPrimitives.concat(null), function (primitive) {
  218. t['throws'](function () { ES.IsDataDescriptor(primitive); }, TypeError, debug(primitive) + ' is not a Property Descriptor');
  219. });
  220. t.equal(ES.IsDataDescriptor(), false, 'no value is not a Data Descriptor');
  221. t.equal(ES.IsDataDescriptor(undefined), false, 'undefined value is not a Data Descriptor');
  222. t.equal(ES.IsDataDescriptor(v.accessorDescriptor()), false, 'accessor descriptor is not a Data Descriptor');
  223. t.equal(ES.IsDataDescriptor(v.mutatorDescriptor()), false, 'mutator descriptor is not a Data Descriptor');
  224. t.equal(ES.IsDataDescriptor(v.dataDescriptor()), true, 'data descriptor is a Data Descriptor');
  225. t.equal(ES.IsDataDescriptor(v.genericDescriptor()), false, 'generic descriptor is not a Data Descriptor');
  226. t.end();
  227. });
  228. test('IsGenericDescriptor', function (t) {
  229. forEach(v.nonNullPrimitives.concat(null), function (primitive) {
  230. t['throws'](
  231. function () { ES.IsGenericDescriptor(primitive); },
  232. TypeError,
  233. debug(primitive) + ' is not a Property Descriptor'
  234. );
  235. });
  236. t.equal(ES.IsGenericDescriptor(), false, 'no value is not a Data Descriptor');
  237. t.equal(ES.IsGenericDescriptor(undefined), false, 'undefined value is not a Data Descriptor');
  238. t.equal(ES.IsGenericDescriptor(v.accessorDescriptor()), false, 'accessor descriptor is not a generic Descriptor');
  239. t.equal(ES.IsGenericDescriptor(v.mutatorDescriptor()), false, 'mutator descriptor is not a generic Descriptor');
  240. t.equal(ES.IsGenericDescriptor(v.dataDescriptor()), false, 'data descriptor is not a generic Descriptor');
  241. t.equal(ES.IsGenericDescriptor(v.genericDescriptor()), true, 'generic descriptor is a generic Descriptor');
  242. t.end();
  243. });
  244. test('FromPropertyDescriptor', function (t) {
  245. t.equal(ES.FromPropertyDescriptor(), undefined, 'no value begets undefined');
  246. t.equal(ES.FromPropertyDescriptor(undefined), undefined, 'undefined value begets undefined');
  247. forEach(v.nonNullPrimitives.concat(null), function (primitive) {
  248. t['throws'](
  249. function () { ES.FromPropertyDescriptor(primitive); },
  250. TypeError,
  251. debug(primitive) + ' is not a Property Descriptor'
  252. );
  253. });
  254. var accessor = v.accessorDescriptor();
  255. t.deepEqual(ES.FromPropertyDescriptor(accessor), {
  256. get: accessor['[[Get]]'],
  257. set: accessor['[[Set]]'],
  258. enumerable: !!accessor['[[Enumerable]]'],
  259. configurable: !!accessor['[[Configurable]]']
  260. });
  261. var mutator = v.mutatorDescriptor();
  262. t.deepEqual(ES.FromPropertyDescriptor(mutator), {
  263. get: mutator['[[Get]]'],
  264. set: mutator['[[Set]]'],
  265. enumerable: !!mutator['[[Enumerable]]'],
  266. configurable: !!mutator['[[Configurable]]']
  267. });
  268. var data = v.dataDescriptor();
  269. t.deepEqual(ES.FromPropertyDescriptor(data), {
  270. value: data['[[Value]]'],
  271. writable: data['[[Writable]]'],
  272. enumerable: !!data['[[Enumerable]]'],
  273. configurable: !!data['[[Configurable]]']
  274. });
  275. t['throws'](
  276. function () { ES.FromPropertyDescriptor(v.genericDescriptor()); },
  277. TypeError,
  278. 'a complete Property Descriptor is required'
  279. );
  280. t.end();
  281. });
  282. test('ToPropertyDescriptor', function (t) {
  283. forEach(v.nonNullPrimitives.concat(null), function (primitive) {
  284. t['throws'](
  285. function () { ES.ToPropertyDescriptor(primitive); },
  286. TypeError,
  287. debug(primitive) + ' is not an Object'
  288. );
  289. });
  290. var accessor = v.accessorDescriptor();
  291. t.deepEqual(ES.ToPropertyDescriptor({
  292. get: accessor['[[Get]]'],
  293. enumerable: !!accessor['[[Enumerable]]'],
  294. configurable: !!accessor['[[Configurable]]']
  295. }), accessor);
  296. var mutator = v.mutatorDescriptor();
  297. t.deepEqual(ES.ToPropertyDescriptor({
  298. set: mutator['[[Set]]'],
  299. enumerable: !!mutator['[[Enumerable]]'],
  300. configurable: !!mutator['[[Configurable]]']
  301. }), mutator);
  302. var data = v.descriptors.nonConfigurable(v.dataDescriptor());
  303. t.deepEqual(ES.ToPropertyDescriptor({
  304. value: data['[[Value]]'],
  305. writable: data['[[Writable]]'],
  306. configurable: !!data['[[Configurable]]']
  307. }), data);
  308. var both = v.bothDescriptor();
  309. t['throws'](
  310. function () {
  311. ES.ToPropertyDescriptor({ get: both['[[Get]]'], value: both['[[Value]]'] });
  312. },
  313. TypeError,
  314. 'data and accessor descriptors are mutually exclusive'
  315. );
  316. t['throws'](
  317. function () { ES.ToPropertyDescriptor({ get: 'not callable' }); },
  318. TypeError,
  319. '"get" must be undefined or callable'
  320. );
  321. t['throws'](
  322. function () { ES.ToPropertyDescriptor({ set: 'not callable' }); },
  323. TypeError,
  324. '"set" must be undefined or callable'
  325. );
  326. t.end();
  327. });
  328. test('Abstract Equality Comparison', function (t) {
  329. t.test('same types use ===', function (st) {
  330. forEach(v.primitives.concat(v.objects), function (value) {
  331. st.equal(ES['Abstract Equality Comparison'](value, value), value === value, debug(value) + ' is abstractly equal to itself');
  332. });
  333. st.end();
  334. });
  335. t.test('different types coerce', function (st) {
  336. var pairs = [
  337. [null, undefined],
  338. [3, '3'],
  339. [true, '3'],
  340. [true, 3],
  341. [false, 0],
  342. [false, '0'],
  343. [3, [3]],
  344. ['3', [3]],
  345. [true, [1]],
  346. [false, [0]],
  347. [String(v.coercibleObject), v.coercibleObject],
  348. [Number(String(v.coercibleObject)), v.coercibleObject],
  349. [Number(v.coercibleObject), v.coercibleObject],
  350. [String(Number(v.coercibleObject)), v.coercibleObject]
  351. ];
  352. forEach(pairs, function (pair) {
  353. var a = pair[0];
  354. var b = pair[1];
  355. // eslint-disable-next-line eqeqeq
  356. st.equal(ES['Abstract Equality Comparison'](a, b), a == b, debug(a) + ' == ' + debug(b));
  357. // eslint-disable-next-line eqeqeq
  358. st.equal(ES['Abstract Equality Comparison'](b, a), b == a, debug(b) + ' == ' + debug(a));
  359. });
  360. st.end();
  361. });
  362. t.end();
  363. });
  364. test('Strict Equality Comparison', function (t) {
  365. t.test('same types use ===', function (st) {
  366. forEach(v.primitives.concat(v.objects), function (value) {
  367. st.equal(ES['Strict Equality Comparison'](value, value), value === value, debug(value) + ' is strictly equal to itself');
  368. });
  369. st.end();
  370. });
  371. t.test('different types are not ===', function (st) {
  372. var pairs = [
  373. [null, undefined],
  374. [3, '3'],
  375. [true, '3'],
  376. [true, 3],
  377. [false, 0],
  378. [false, '0'],
  379. [3, [3]],
  380. ['3', [3]],
  381. [true, [1]],
  382. [false, [0]],
  383. [String(v.coercibleObject), v.coercibleObject],
  384. [Number(String(v.coercibleObject)), v.coercibleObject],
  385. [Number(v.coercibleObject), v.coercibleObject],
  386. [String(Number(v.coercibleObject)), v.coercibleObject]
  387. ];
  388. forEach(pairs, function (pair) {
  389. var a = pair[0];
  390. var b = pair[1];
  391. st.equal(ES['Strict Equality Comparison'](a, b), a === b, debug(a) + ' === ' + debug(b));
  392. st.equal(ES['Strict Equality Comparison'](b, a), b === a, debug(b) + ' === ' + debug(a));
  393. });
  394. st.end();
  395. });
  396. t.end();
  397. });
  398. test('Abstract Relational Comparison', function (t) {
  399. t.test('at least one operand is NaN', function (st) {
  400. st.equal(ES['Abstract Relational Comparison'](NaN, {}, true), undefined, 'LeftFirst: first is NaN, returns undefined');
  401. st.equal(ES['Abstract Relational Comparison']({}, NaN, true), undefined, 'LeftFirst: second is NaN, returns undefined');
  402. st.equal(ES['Abstract Relational Comparison'](NaN, {}, false), undefined, '!LeftFirst: first is NaN, returns undefined');
  403. st.equal(ES['Abstract Relational Comparison']({}, NaN, false), undefined, '!LeftFirst: second is NaN, returns undefined');
  404. st.end();
  405. });
  406. t.equal(ES['Abstract Relational Comparison'](3, 4, true), true, 'LeftFirst: 3 is less than 4');
  407. t.equal(ES['Abstract Relational Comparison'](4, 3, true), false, 'LeftFirst: 3 is not less than 4');
  408. t.equal(ES['Abstract Relational Comparison'](3, 4, false), true, '!LeftFirst: 3 is less than 4');
  409. t.equal(ES['Abstract Relational Comparison'](4, 3, false), false, '!LeftFirst: 3 is not less than 4');
  410. t.equal(ES['Abstract Relational Comparison']('3', '4', true), true, 'LeftFirst: "3" is less than "4"');
  411. t.equal(ES['Abstract Relational Comparison']('4', '3', true), false, 'LeftFirst: "3" is not less than "4"');
  412. t.equal(ES['Abstract Relational Comparison']('3', '4', false), true, '!LeftFirst: "3" is less than "4"');
  413. t.equal(ES['Abstract Relational Comparison']('4', '3', false), false, '!LeftFirst: "3" is not less than "4"');
  414. t.equal(ES['Abstract Relational Comparison'](v.coercibleObject, 42, true), true, 'LeftFirst: coercible object is less than 42');
  415. t.equal(ES['Abstract Relational Comparison'](42, v.coercibleObject, true), false, 'LeftFirst: 42 is not less than coercible object');
  416. t.equal(ES['Abstract Relational Comparison'](v.coercibleObject, 42, false), true, '!LeftFirst: coercible object is less than 42');
  417. t.equal(ES['Abstract Relational Comparison'](42, v.coercibleObject, false), false, '!LeftFirst: 42 is not less than coercible object');
  418. t.equal(ES['Abstract Relational Comparison'](v.coercibleObject, '3', true), false, 'LeftFirst: coercible object is not less than "3"');
  419. t.equal(ES['Abstract Relational Comparison']('3', v.coercibleObject, true), false, 'LeftFirst: "3" is not less than coercible object');
  420. t.equal(ES['Abstract Relational Comparison'](v.coercibleObject, '3', false), false, '!LeftFirst: coercible object is not less than "3"');
  421. t.equal(ES['Abstract Relational Comparison']('3', v.coercibleObject, false), false, '!LeftFirst: "3" is not less than coercible object');
  422. t.end();
  423. });
  424. test('FromPropertyDescriptor', function (t) {
  425. t.equal(ES.FromPropertyDescriptor(), undefined, 'no value begets undefined');
  426. t.equal(ES.FromPropertyDescriptor(undefined), undefined, 'undefined value begets undefined');
  427. forEach(v.nonUndefinedPrimitives, function (primitive) {
  428. t['throws'](
  429. function () { ES.FromPropertyDescriptor(primitive); },
  430. TypeError,
  431. debug(primitive) + ' is not a Property Descriptor'
  432. );
  433. });
  434. var accessor = v.accessorDescriptor();
  435. t.deepEqual(ES.FromPropertyDescriptor(accessor), {
  436. get: accessor['[[Get]]'],
  437. set: accessor['[[Set]]'],
  438. enumerable: !!accessor['[[Enumerable]]'],
  439. configurable: !!accessor['[[Configurable]]']
  440. });
  441. var mutator = v.mutatorDescriptor();
  442. t.deepEqual(ES.FromPropertyDescriptor(mutator), {
  443. get: mutator['[[Get]]'],
  444. set: mutator['[[Set]]'],
  445. enumerable: !!mutator['[[Enumerable]]'],
  446. configurable: !!mutator['[[Configurable]]']
  447. });
  448. var data = v.dataDescriptor();
  449. t.deepEqual(ES.FromPropertyDescriptor(data), {
  450. value: data['[[Value]]'],
  451. writable: data['[[Writable]]'],
  452. enumerable: !!data['[[Enumerable]]'],
  453. configurable: !!data['[[Configurable]]']
  454. });
  455. t['throws'](
  456. function () { ES.FromPropertyDescriptor(v.genericDescriptor()); },
  457. TypeError,
  458. 'a complete Property Descriptor is required'
  459. );
  460. t.end();
  461. });
  462. test('SecFromTime', function (t) {
  463. var now = new Date();
  464. t.equal(ES.SecFromTime(now.getTime()), now.getUTCSeconds(), 'second from Date timestamp matches getUTCSeconds');
  465. t.end();
  466. });
  467. test('MinFromTime', function (t) {
  468. var now = new Date();
  469. t.equal(ES.MinFromTime(now.getTime()), now.getUTCMinutes(), 'minute from Date timestamp matches getUTCMinutes');
  470. t.end();
  471. });
  472. test('HourFromTime', function (t) {
  473. var now = new Date();
  474. t.equal(ES.HourFromTime(now.getTime()), now.getUTCHours(), 'hour from Date timestamp matches getUTCHours');
  475. t.end();
  476. });
  477. test('msFromTime', function (t) {
  478. var now = new Date();
  479. t.equal(ES.msFromTime(now.getTime()), now.getUTCMilliseconds(), 'ms from Date timestamp matches getUTCMilliseconds');
  480. t.end();
  481. });
  482. var msPerSecond = 1e3;
  483. var msPerMinute = 60 * msPerSecond;
  484. var msPerHour = 60 * msPerMinute;
  485. var msPerDay = 24 * msPerHour;
  486. test('Day', function (t) {
  487. var time = Date.UTC(2019, 8, 10, 2, 3, 4, 5);
  488. var add = 2.5;
  489. var later = new Date(time + (add * msPerDay));
  490. t.equal(ES.Day(later.getTime()), ES.Day(time) + Math.floor(add), 'adding 2.5 days worth of ms, gives a Day delta of 2');
  491. t.end();
  492. });
  493. test('TimeWithinDay', function (t) {
  494. var time = Date.UTC(2019, 8, 10, 2, 3, 4, 5);
  495. var add = 2.5;
  496. var later = new Date(time + (add * msPerDay));
  497. t.equal(ES.TimeWithinDay(later.getTime()), ES.TimeWithinDay(time) + (0.5 * msPerDay), 'adding 2.5 days worth of ms, gives a TimeWithinDay delta of +0.5');
  498. t.end();
  499. });
  500. test('DayFromYear', function (t) {
  501. t.equal(ES.DayFromYear(2021) - ES.DayFromYear(2020), 366, '2021 is a leap year, has 366 days');
  502. t.equal(ES.DayFromYear(2020) - ES.DayFromYear(2019), 365, '2020 is not a leap year, has 365 days');
  503. t.equal(ES.DayFromYear(2019) - ES.DayFromYear(2018), 365, '2019 is not a leap year, has 365 days');
  504. t.equal(ES.DayFromYear(2018) - ES.DayFromYear(2017), 365, '2018 is not a leap year, has 365 days');
  505. t.equal(ES.DayFromYear(2017) - ES.DayFromYear(2016), 366, '2017 is a leap year, has 366 days');
  506. t.end();
  507. });
  508. test('TimeFromYear', function (t) {
  509. for (var i = 1900; i < 2100; i += 1) {
  510. t.equal(ES.TimeFromYear(i), Date.UTC(i, 0, 1), 'TimeFromYear matches a Date object’s year: ' + i);
  511. }
  512. t.end();
  513. });
  514. test('YearFromTime', function (t) {
  515. for (var i = 1900; i < 2100; i += 1) {
  516. t.equal(ES.YearFromTime(Date.UTC(i, 0, 1)), i, 'YearFromTime matches a Date object’s year on 1/1: ' + i);
  517. t.equal(ES.YearFromTime(Date.UTC(i, 10, 1)), i, 'YearFromTime matches a Date object’s year on 10/1: ' + i);
  518. }
  519. t.end();
  520. });
  521. test('WeekDay', function (t) {
  522. var now = new Date();
  523. var today = now.getUTCDay();
  524. for (var i = 0; i < 7; i += 1) {
  525. var weekDay = ES.WeekDay(now.getTime() + (i * msPerDay));
  526. t.equal(weekDay, (today + i) % 7, i + ' days after today (' + today + '), WeekDay is ' + weekDay);
  527. }
  528. t.end();
  529. });
  530. test('DaysInYear', function (t) {
  531. t.equal(ES.DaysInYear(2021), 365, '2021 is not a leap year');
  532. t.equal(ES.DaysInYear(2020), 366, '2020 is a leap year');
  533. t.equal(ES.DaysInYear(2019), 365, '2019 is not a leap year');
  534. t.equal(ES.DaysInYear(2018), 365, '2018 is not a leap year');
  535. t.equal(ES.DaysInYear(2017), 365, '2017 is not a leap year');
  536. t.equal(ES.DaysInYear(2016), 366, '2016 is a leap year');
  537. t.end();
  538. });
  539. test('InLeapYear', function (t) {
  540. t.equal(ES.InLeapYear(Date.UTC(2021, 0, 1)), 0, '2021 is not a leap year');
  541. t.equal(ES.InLeapYear(Date.UTC(2020, 0, 1)), 1, '2020 is a leap year');
  542. t.equal(ES.InLeapYear(Date.UTC(2019, 0, 1)), 0, '2019 is not a leap year');
  543. t.equal(ES.InLeapYear(Date.UTC(2018, 0, 1)), 0, '2018 is not a leap year');
  544. t.equal(ES.InLeapYear(Date.UTC(2017, 0, 1)), 0, '2017 is not a leap year');
  545. t.equal(ES.InLeapYear(Date.UTC(2016, 0, 1)), 1, '2016 is a leap year');
  546. t.end();
  547. });
  548. test('DayWithinYear', function (t) {
  549. t.equal(ES.DayWithinYear(Date.UTC(2019, 0, 1)), 0, '1/1 is the 1st day');
  550. t.equal(ES.DayWithinYear(Date.UTC(2019, 11, 31)), 364, '12/31 is the 365th day in a non leap year');
  551. t.equal(ES.DayWithinYear(Date.UTC(2016, 11, 31)), 365, '12/31 is the 366th day in a leap year');
  552. t.end();
  553. });
  554. test('MonthFromTime', function (t) {
  555. t.equal(ES.MonthFromTime(Date.UTC(2019, 0, 1)), 0, 'non-leap: 1/1 gives January');
  556. t.equal(ES.MonthFromTime(Date.UTC(2019, 0, 31)), 0, 'non-leap: 1/31 gives January');
  557. t.equal(ES.MonthFromTime(Date.UTC(2019, 1, 1)), 1, 'non-leap: 2/1 gives February');
  558. t.equal(ES.MonthFromTime(Date.UTC(2019, 1, 28)), 1, 'non-leap: 2/28 gives February');
  559. t.equal(ES.MonthFromTime(Date.UTC(2019, 1, 29)), 2, 'non-leap: 2/29 gives March');
  560. t.equal(ES.MonthFromTime(Date.UTC(2019, 2, 1)), 2, 'non-leap: 3/1 gives March');
  561. t.equal(ES.MonthFromTime(Date.UTC(2019, 2, 31)), 2, 'non-leap: 3/31 gives March');
  562. t.equal(ES.MonthFromTime(Date.UTC(2019, 3, 1)), 3, 'non-leap: 4/1 gives April');
  563. t.equal(ES.MonthFromTime(Date.UTC(2019, 3, 30)), 3, 'non-leap: 4/30 gives April');
  564. t.equal(ES.MonthFromTime(Date.UTC(2019, 4, 1)), 4, 'non-leap: 5/1 gives May');
  565. t.equal(ES.MonthFromTime(Date.UTC(2019, 4, 31)), 4, 'non-leap: 5/31 gives May');
  566. t.equal(ES.MonthFromTime(Date.UTC(2019, 5, 1)), 5, 'non-leap: 6/1 gives June');
  567. t.equal(ES.MonthFromTime(Date.UTC(2019, 5, 30)), 5, 'non-leap: 6/30 gives June');
  568. t.equal(ES.MonthFromTime(Date.UTC(2019, 6, 1)), 6, 'non-leap: 7/1 gives July');
  569. t.equal(ES.MonthFromTime(Date.UTC(2019, 6, 31)), 6, 'non-leap: 7/31 gives July');
  570. t.equal(ES.MonthFromTime(Date.UTC(2019, 7, 1)), 7, 'non-leap: 8/1 gives August');
  571. t.equal(ES.MonthFromTime(Date.UTC(2019, 7, 30)), 7, 'non-leap: 8/30 gives August');
  572. t.equal(ES.MonthFromTime(Date.UTC(2019, 8, 1)), 8, 'non-leap: 9/1 gives September');
  573. t.equal(ES.MonthFromTime(Date.UTC(2019, 8, 30)), 8, 'non-leap: 9/30 gives September');
  574. t.equal(ES.MonthFromTime(Date.UTC(2019, 9, 1)), 9, 'non-leap: 10/1 gives October');
  575. t.equal(ES.MonthFromTime(Date.UTC(2019, 9, 31)), 9, 'non-leap: 10/31 gives October');
  576. t.equal(ES.MonthFromTime(Date.UTC(2019, 10, 1)), 10, 'non-leap: 11/1 gives November');
  577. t.equal(ES.MonthFromTime(Date.UTC(2019, 10, 30)), 10, 'non-leap: 11/30 gives November');
  578. t.equal(ES.MonthFromTime(Date.UTC(2019, 11, 1)), 11, 'non-leap: 12/1 gives December');
  579. t.equal(ES.MonthFromTime(Date.UTC(2019, 11, 31)), 11, 'non-leap: 12/31 gives December');
  580. t.equal(ES.MonthFromTime(Date.UTC(2016, 0, 1)), 0, 'leap: 1/1 gives January');
  581. t.equal(ES.MonthFromTime(Date.UTC(2016, 0, 31)), 0, 'leap: 1/31 gives January');
  582. t.equal(ES.MonthFromTime(Date.UTC(2016, 1, 1)), 1, 'leap: 2/1 gives February');
  583. t.equal(ES.MonthFromTime(Date.UTC(2016, 1, 28)), 1, 'leap: 2/28 gives February');
  584. t.equal(ES.MonthFromTime(Date.UTC(2016, 1, 29)), 1, 'leap: 2/29 gives February');
  585. t.equal(ES.MonthFromTime(Date.UTC(2016, 2, 1)), 2, 'leap: 3/1 gives March');
  586. t.equal(ES.MonthFromTime(Date.UTC(2016, 2, 31)), 2, 'leap: 3/31 gives March');
  587. t.equal(ES.MonthFromTime(Date.UTC(2016, 3, 1)), 3, 'leap: 4/1 gives April');
  588. t.equal(ES.MonthFromTime(Date.UTC(2016, 3, 30)), 3, 'leap: 4/30 gives April');
  589. t.equal(ES.MonthFromTime(Date.UTC(2016, 4, 1)), 4, 'leap: 5/1 gives May');
  590. t.equal(ES.MonthFromTime(Date.UTC(2016, 4, 31)), 4, 'leap: 5/31 gives May');
  591. t.equal(ES.MonthFromTime(Date.UTC(2016, 5, 1)), 5, 'leap: 6/1 gives June');
  592. t.equal(ES.MonthFromTime(Date.UTC(2016, 5, 30)), 5, 'leap: 6/30 gives June');
  593. t.equal(ES.MonthFromTime(Date.UTC(2016, 6, 1)), 6, 'leap: 7/1 gives July');
  594. t.equal(ES.MonthFromTime(Date.UTC(2016, 6, 31)), 6, 'leap: 7/31 gives July');
  595. t.equal(ES.MonthFromTime(Date.UTC(2016, 7, 1)), 7, 'leap: 8/1 gives August');
  596. t.equal(ES.MonthFromTime(Date.UTC(2016, 7, 30)), 7, 'leap: 8/30 gives August');
  597. t.equal(ES.MonthFromTime(Date.UTC(2016, 8, 1)), 8, 'leap: 9/1 gives September');
  598. t.equal(ES.MonthFromTime(Date.UTC(2016, 8, 30)), 8, 'leap: 9/30 gives September');
  599. t.equal(ES.MonthFromTime(Date.UTC(2016, 9, 1)), 9, 'leap: 10/1 gives October');
  600. t.equal(ES.MonthFromTime(Date.UTC(2016, 9, 31)), 9, 'leap: 10/31 gives October');
  601. t.equal(ES.MonthFromTime(Date.UTC(2016, 10, 1)), 10, 'leap: 11/1 gives November');
  602. t.equal(ES.MonthFromTime(Date.UTC(2016, 10, 30)), 10, 'leap: 11/30 gives November');
  603. t.equal(ES.MonthFromTime(Date.UTC(2016, 11, 1)), 11, 'leap: 12/1 gives December');
  604. t.equal(ES.MonthFromTime(Date.UTC(2016, 11, 31)), 11, 'leap: 12/31 gives December');
  605. t.end();
  606. });
  607. test('DateFromTime', function (t) {
  608. var i;
  609. for (i = 1; i <= 28; i += 1) {
  610. t.equal(ES.DateFromTime(Date.UTC(2019, 1, i)), i, '2019.02.' + i + ' is date ' + i);
  611. }
  612. for (i = 1; i <= 29; i += 1) {
  613. t.equal(ES.DateFromTime(Date.UTC(2016, 1, i)), i, '2016.02.' + i + ' is date ' + i);
  614. }
  615. for (i = 1; i <= 30; i += 1) {
  616. t.equal(ES.DateFromTime(Date.UTC(2019, 8, i)), i, '2019.09.' + i + ' is date ' + i);
  617. }
  618. for (i = 1; i <= 31; i += 1) {
  619. t.equal(ES.DateFromTime(Date.UTC(2019, 9, i)), i, '2019.10.' + i + ' is date ' + i);
  620. }
  621. t.end();
  622. });
  623. test('MakeDay', function (t) {
  624. var day2015 = 16687;
  625. t.equal(ES.MakeDay(2015, 8, 9), day2015, '2015.09.09 is day 16687');
  626. var day2016 = day2015 + 366; // 2016 is a leap year
  627. t.equal(ES.MakeDay(2016, 8, 9), day2016, '2015.09.09 is day 17053');
  628. var day2017 = day2016 + 365;
  629. t.equal(ES.MakeDay(2017, 8, 9), day2017, '2017.09.09 is day 17418');
  630. var day2018 = day2017 + 365;
  631. t.equal(ES.MakeDay(2018, 8, 9), day2018, '2018.09.09 is day 17783');
  632. var day2019 = day2018 + 365;
  633. t.equal(ES.MakeDay(2019, 8, 9), day2019, '2019.09.09 is day 18148');
  634. t.end();
  635. });
  636. test('MakeDate', function (t) {
  637. forEach(v.infinities.concat(NaN), function (nonFiniteNumber) {
  638. t.ok(is(ES.MakeDate(nonFiniteNumber, 0), NaN), debug(nonFiniteNumber) + ' is not a finite `day`');
  639. t.ok(is(ES.MakeDate(0, nonFiniteNumber), NaN), debug(nonFiniteNumber) + ' is not a finite `time`');
  640. });
  641. t.equal(ES.MakeDate(0, 0), 0, 'zero day and zero time is zero date');
  642. t.equal(ES.MakeDate(0, 123), 123, 'zero day and nonzero time is a date of the "time"');
  643. t.equal(ES.MakeDate(1, 0), msPerDay, 'day of 1 and zero time is a date of "ms per day"');
  644. t.equal(ES.MakeDate(3, 0), 3 * msPerDay, 'day of 3 and zero time is a date of thrice "ms per day"');
  645. t.equal(ES.MakeDate(1, 123), msPerDay + 123, 'day of 1 and nonzero time is a date of "ms per day" plus the "time"');
  646. t.equal(ES.MakeDate(3, 123), (3 * msPerDay) + 123, 'day of 3 and nonzero time is a date of thrice "ms per day" plus the "time"');
  647. t.end();
  648. });
  649. test('MakeTime', function (t) {
  650. forEach(v.infinities.concat(NaN), function (nonFiniteNumber) {
  651. t.ok(is(ES.MakeTime(nonFiniteNumber, 0, 0, 0), NaN), debug(nonFiniteNumber) + ' is not a finite `hour`');
  652. t.ok(is(ES.MakeTime(0, nonFiniteNumber, 0, 0), NaN), debug(nonFiniteNumber) + ' is not a finite `min`');
  653. t.ok(is(ES.MakeTime(0, 0, nonFiniteNumber, 0), NaN), debug(nonFiniteNumber) + ' is not a finite `sec`');
  654. t.ok(is(ES.MakeTime(0, 0, 0, nonFiniteNumber), NaN), debug(nonFiniteNumber) + ' is not a finite `ms`');
  655. });
  656. t.equal(
  657. ES.MakeTime(1.2, 2.3, 3.4, 4.5),
  658. (1 * msPerHour) + (2 * msPerMinute) + (3 * msPerSecond) + 4,
  659. 'all numbers are converted to integer, multiplied by the right number of ms, and summed'
  660. );
  661. t.end();
  662. });
  663. test('TimeClip', function (t) {
  664. forEach(v.infinities.concat(NaN), function (nonFiniteNumber) {
  665. t.ok(is(ES.TimeClip(nonFiniteNumber), NaN), debug(nonFiniteNumber) + ' is not a finite `time`');
  666. });
  667. t.ok(is(ES.TimeClip(8.64e15 + 1), NaN), '8.64e15 is the largest magnitude considered "finite"');
  668. t.ok(is(ES.TimeClip(-8.64e15 - 1), NaN), '-8.64e15 is the largest magnitude considered "finite"');
  669. forEach(v.zeroes.concat([-10, 10, +new Date()]), function (time) {
  670. t.looseEqual(ES.TimeClip(time), time, debug(time) + ' is a time of ' + debug(time));
  671. });
  672. t.end();
  673. });
  674. test('modulo', function (t) {
  675. t.equal(3 % 2, 1, '+3 % 2 is +1');
  676. t.equal(ES.modulo(3, 2), 1, '+3 mod 2 is +1');
  677. t.equal(-3 % 2, -1, '-3 % 2 is -1');
  678. t.equal(ES.modulo(-3, 2), 1, '-3 mod 2 is +1');
  679. t.end();
  680. });