Skip to content

Commit 789f170

Browse files
committed
v0.1.1: Restore test suite
1 parent a750e9e commit 789f170

6 files changed

Lines changed: 309 additions & 308 deletions

File tree

.github/workflows/deno-ci.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@ jobs:
2828
with:
2929
deno-version: ${{ matrix.deno-version }}
3030

31-
# - name: Test
32-
# run: time deno test --allow-net ./test/*.ts
31+
- name: Test
32+
run: time deno test
3333

3434
- name: Check publish rules
3535
run: time deno publish --dry-run

custom_models_for_tests.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { EJSON } from './ejson';
1+
import { EJSON } from './ejson.js';
22

33
class Address {
44
constructor(city, state) {

ejson.js

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@ import {
1414
import {
1515
canonicalStringify,
1616
} from './stringify.js';
17+
import {
18+
decodeBase64,
19+
encodeBase64,
20+
} from 'jsr:@std/encoding@1.0.9/base64';
1721

1822
/**
1923
* @namespace
@@ -171,10 +175,10 @@ const builtinConverters = [
171175
|| (obj && hasOwn(obj, '$Uint8ArrayPolyfill'));
172176
},
173177
toJSONValue(obj) {
174-
return {$binary: Base64.encode(obj)};
178+
return {$binary: encodeBase64(obj)};
175179
},
176180
fromJSONValue(obj) {
177-
return Base64.decode(obj.$binary);
181+
return decodeBase64(obj.$binary);
178182
},
179183
},
180184
{ // Escaping one level
@@ -216,7 +220,7 @@ const builtinConverters = [
216220
return EJSON._isCustomType(obj);
217221
},
218222
toJSONValue(obj) {
219-
const jsonValue = Meteor._noYieldsAllowed(() => obj.toJSONValue());
223+
const jsonValue = obj.toJSONValue();
220224
return {$type: obj.typeName(), $value: jsonValue};
221225
},
222226
fromJSONValue(obj) {
@@ -225,7 +229,7 @@ const builtinConverters = [
225229
throw new Error(`Custom EJSON type ${typeName} is not defined`);
226230
}
227231
const converter = customTypes.get(typeName);
228-
return Meteor._noYieldsAllowed(() => converter(obj.$value));
232+
return converter(obj.$value);
229233
},
230234
},
231235
];
@@ -617,11 +621,6 @@ EJSON.clone = v => {
617621
* @locus Anywhere
618622
* @param {Number} size The number of bytes of binary data to allocate.
619623
*/
620-
// EJSON.newBinary is the public documented API for this functionality,
621-
// but the implementation is in the 'base64' package to avoid
622-
// introducing a circular dependency. (If the implementation were here,
623-
// then 'base64' would have to use EJSON.newBinary, and 'ejson' would
624-
// also have to use 'base64'.)
625-
EJSON.newBinary = Base64.newBinary;
624+
EJSON.newBinary = (size) => new Uint8Array(new ArrayBuffer(size));
626625

627626
export { EJSON };

ejson.test.js

Lines changed: 296 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,296 @@
1+
import { assertEquals, assertThrows, assertNotEquals } from "jsr:@std/assert@1.0.12";
2+
3+
import { EJSON } from './ejson.js';
4+
import EJSONTest from './custom_models_for_tests.js';
5+
6+
Deno.test('ejson - keyOrderSensitive', test => {
7+
assertEquals(true, EJSON.equals({
8+
a: {b: 1, c: 2},
9+
d: {e: 3, f: 4},
10+
}, {
11+
d: {f: 4, e: 3},
12+
a: {c: 2, b: 1},
13+
}));
14+
15+
assertEquals(false, EJSON.equals({
16+
a: {b: 1, c: 2},
17+
d: {e: 3, f: 4},
18+
}, {
19+
d: {f: 4, e: 3},
20+
a: {c: 2, b: 1},
21+
}, {keyOrderSensitive: true}));
22+
23+
assertEquals(false, EJSON.equals({
24+
a: {b: 1, c: 2},
25+
d: {e: 3, f: 4},
26+
}, {
27+
a: {c: 2, b: 1},
28+
d: {f: 4, e: 3},
29+
}, {keyOrderSensitive: true}));
30+
assertEquals(false, EJSON.equals({a: {}}, {a: {b: 2}}, {keyOrderSensitive: true}));
31+
assertEquals(false, EJSON.equals({a: {b: 2}}, {a: {}}, {keyOrderSensitive: true}));
32+
});
33+
34+
Deno.test('ejson - nesting and literal', test => {
35+
const d = new Date();
36+
const obj = {$date: d};
37+
const eObj = EJSON.toJSONValue(obj);
38+
const roundTrip = EJSON.fromJSONValue(eObj);
39+
assertEquals(obj, roundTrip);
40+
});
41+
42+
Deno.test('ejson - some equality tests', test => {
43+
assertEquals(true, EJSON.equals({a: 1, b: 2, c: 3}, {a: 1, c: 3, b: 2}));
44+
assertEquals(false, EJSON.equals({a: 1, b: 2}, {a: 1, c: 3, b: 2}));
45+
assertEquals(false, EJSON.equals({a: 1, b: 2, c: 3}, {a: 1, b: 2}));
46+
assertEquals(false, EJSON.equals({a: 1, b: 2, c: 3}, {a: 1, c: 3, b: 4}));
47+
assertEquals(false, EJSON.equals({a: {}}, {a: {b: 2}}));
48+
assertEquals(false, EJSON.equals({a: {b: 2}}, {a: {}}));
49+
// XXX: Object and Array were previously mistaken, which is why
50+
// we add some extra tests for them here
51+
assertEquals(true, EJSON.equals([1, 2, 3, 4, 5], [1, 2, 3, 4, 5]));
52+
assertEquals(false, EJSON.equals([1, 2, 3, 4, 5], [1, 2, 3, 4]));
53+
assertEquals(false, EJSON.equals([1,2,3,4], {0: 1, 1: 2, 2: 3, 3: 4}));
54+
assertEquals(false, EJSON.equals({0: 1, 1: 2, 2: 3, 3: 4}, [1,2,3,4]));
55+
assertEquals(false, EJSON.equals({}, []));
56+
assertEquals(false, EJSON.equals([], {}));
57+
});
58+
59+
Deno.test('ejson - equality and falsiness', test => {
60+
assertEquals(true, EJSON.equals(null, null));
61+
assertEquals(true, EJSON.equals(undefined, undefined));
62+
assertEquals(false, EJSON.equals({foo: 'foo'}, null));
63+
assertEquals(false, EJSON.equals(null, {foo: 'foo'}));
64+
assertEquals(false, EJSON.equals(undefined, {foo: 'foo'}));
65+
assertEquals(false, EJSON.equals({foo: 'foo'}, undefined));
66+
});
67+
68+
Deno.test('ejson - NaN and Inf', test => {
69+
assertEquals(EJSON.parse('{"$InfNaN": 1}'), Infinity);
70+
assertEquals(EJSON.parse('{"$InfNaN": -1}'), -Infinity);
71+
assertEquals(true, Number.isNaN(EJSON.parse('{"$InfNaN": 0}')));
72+
assertEquals(EJSON.parse(EJSON.stringify(Infinity)), Infinity);
73+
assertEquals(EJSON.parse(EJSON.stringify(-Infinity)), -Infinity);
74+
assertEquals(true, Number.isNaN(EJSON.parse(EJSON.stringify(NaN))));
75+
assertEquals(true, EJSON.equals(NaN, NaN));
76+
assertEquals(true, EJSON.equals(Infinity, Infinity));
77+
assertEquals(true, EJSON.equals(-Infinity, -Infinity));
78+
assertEquals(false, EJSON.equals(Infinity, -Infinity));
79+
assertEquals(false, EJSON.equals(Infinity, NaN));
80+
assertEquals(false, EJSON.equals(Infinity, 0));
81+
assertEquals(false, EJSON.equals(NaN, 0));
82+
83+
assertEquals(true, EJSON.equals(
84+
EJSON.parse('{"a": {"$InfNaN": 1}}'),
85+
{a: Infinity}
86+
));
87+
assertEquals(true, EJSON.equals(
88+
EJSON.parse('{"a": {"$InfNaN": 0}}'),
89+
{a: NaN}
90+
));
91+
});
92+
93+
Deno.test('ejson - clone', test => {
94+
const cloneTest = (x, identical) => {
95+
const y = EJSON.clone(x);
96+
assertEquals(true, EJSON.equals(x, y));
97+
assertEquals(x === y, !!identical);
98+
};
99+
cloneTest(null, true);
100+
cloneTest(undefined, true);
101+
cloneTest(42, true);
102+
cloneTest('asdf', true);
103+
cloneTest([1, 2, 3]);
104+
cloneTest([1, 'fasdf', {foo: 42}]);
105+
cloneTest({x: 42, y: 'asdf'});
106+
107+
function testCloneArgs(/*arguments*/) {
108+
const clonedArgs = EJSON.clone(arguments);
109+
assertEquals(clonedArgs, [1, 2, 'foo', [4]]);
110+
};
111+
testCloneArgs(1, 2, 'foo', [4]);
112+
});
113+
114+
Deno.test('ejson - stringify', test => {
115+
assertEquals(EJSON.stringify(null), 'null');
116+
assertEquals(EJSON.stringify(true), 'true');
117+
assertEquals(EJSON.stringify(false), 'false');
118+
assertEquals(EJSON.stringify(123), '123');
119+
assertEquals(EJSON.stringify('abc'), '"abc"');
120+
121+
assertEquals(EJSON.stringify([1, 2, 3]),
122+
'[1,2,3]'
123+
);
124+
assertEquals(EJSON.stringify([1, 2, 3], {indent: true}),
125+
'[\n 1,\n 2,\n 3\n]'
126+
);
127+
assertEquals(EJSON.stringify([1, 2, 3], {canonical: false}),
128+
'[1,2,3]'
129+
);
130+
assertEquals(EJSON.stringify([1, 2, 3], {indent: true, canonical: false}),
131+
'[\n 1,\n 2,\n 3\n]'
132+
);
133+
134+
assertEquals(EJSON.stringify([1, 2, 3], {indent: 4}),
135+
'[\n 1,\n 2,\n 3\n]'
136+
);
137+
assertEquals(EJSON.stringify([1, 2, 3], {indent: '--'}),
138+
'[\n--1,\n--2,\n--3\n]'
139+
);
140+
141+
assertEquals(
142+
EJSON.stringify(
143+
{b: [2, {d: 4, c: 3}], a: 1},
144+
{canonical: true}
145+
),
146+
'{"a":1,"b":[2,{"c":3,"d":4}]}'
147+
);
148+
assertEquals(
149+
EJSON.stringify(
150+
{b: [2, {d: 4, c: 3}], a: 1},
151+
{
152+
indent: true,
153+
canonical: true,
154+
}
155+
),
156+
'{\n' +
157+
' "a": 1,\n' +
158+
' "b": [\n' +
159+
' 2,\n' +
160+
' {\n' +
161+
' "c": 3,\n' +
162+
' "d": 4\n' +
163+
' }\n' +
164+
' ]\n' +
165+
'}'
166+
);
167+
assertEquals(
168+
EJSON.stringify(
169+
{b: [2, {d: 4, c: 3}], a: 1},
170+
{canonical: false}
171+
),
172+
'{"b":[2,{"d":4,"c":3}],"a":1}'
173+
);
174+
assertEquals(
175+
EJSON.stringify(
176+
{b: [2, {d: 4, c: 3}], a: 1},
177+
{indent: true, canonical: false}
178+
),
179+
'{\n' +
180+
' "b": [\n' +
181+
' 2,\n' +
182+
' {\n' +
183+
' "d": 4,\n' +
184+
' "c": 3\n' +
185+
' }\n' +
186+
' ],\n' +
187+
' "a": 1\n' +
188+
'}'
189+
);
190+
191+
assertThrows(
192+
() => {
193+
const col = new Mongo.Collection('test');
194+
EJSON.stringify(col)
195+
},
196+
/Converting circular structure to JSON/
197+
);
198+
});
199+
200+
Deno.test('ejson - parse', test => {
201+
assertEquals(EJSON.parse('[1,2,3]'), [1, 2, 3]);
202+
assertThrows(
203+
() => { EJSON.parse(null); },
204+
/argument should be a string/
205+
);
206+
});
207+
208+
Deno.test("ejson - regexp", test => {
209+
assertEquals(EJSON.stringify(/foo/gi), "{\"$regexp\":\"foo\",\"$flags\":\"gi\"}");
210+
var d = new RegExp("foo", "gi");
211+
var obj = { $regexp: "foo", $flags: "gi" };
212+
213+
var eObj = EJSON.toJSONValue(obj);
214+
var roundTrip = EJSON.fromJSONValue(eObj);
215+
assertEquals(obj, roundTrip);
216+
});
217+
218+
Deno.test('ejson - custom types', test => {
219+
const testSameConstructors = (someObj, compareWith) => {
220+
assertEquals(someObj.constructor, compareWith.constructor);
221+
if (typeof someObj === 'object') {
222+
Object.keys(someObj).forEach(key => {
223+
const value = someObj[key];
224+
testSameConstructors(value, compareWith[key]);
225+
});
226+
}
227+
};
228+
229+
const testReallyEqual = (someObj, compareWith) => {
230+
assertEquals(someObj, compareWith);
231+
testSameConstructors(someObj, compareWith);
232+
};
233+
234+
const testRoundTrip = (someObj) => {
235+
const str = EJSON.stringify(someObj);
236+
const roundTrip = EJSON.parse(str);
237+
testReallyEqual(someObj, roundTrip);
238+
};
239+
240+
const testCustomObject = (someObj) => {
241+
testRoundTrip(someObj);
242+
testReallyEqual(someObj, EJSON.clone(someObj));
243+
};
244+
245+
const a = new EJSONTest.Address('Montreal', 'Quebec');
246+
testCustomObject( {address: a} );
247+
// Test that difference is detected even if they
248+
// have similar toJSONValue results:
249+
const nakedA = {city: 'Montreal', state: 'Quebec'};
250+
assertNotEquals(nakedA, a);
251+
assertNotEquals(a, nakedA);
252+
const holder = new EJSONTest.Holder(nakedA);
253+
assertEquals(holder.toJSONValue(), a.toJSONValue()); // sanity check
254+
assertNotEquals(holder, a);
255+
assertNotEquals(a, holder);
256+
257+
const d = new Date();
258+
const obj = new EJSONTest.Person('John Doe', d, a);
259+
testCustomObject( obj );
260+
261+
// Test clone is deep:
262+
const clone = EJSON.clone(obj);
263+
clone.address.city = 'Sherbrooke';
264+
assertNotEquals( obj, clone );
265+
});
266+
267+
// Verify objects with a property named "length" can be handled by the EJSON
268+
// API properly (see https://github.com/meteor/meteor/issues/5175).
269+
Deno.test('ejson - handle objects with properties named "length"', test => {
270+
class Widget {
271+
constructor() {
272+
this.length = 10;
273+
}
274+
}
275+
const widget = new Widget();
276+
277+
const toJsonWidget = EJSON.toJSONValue(widget);
278+
assertEquals({...widget}, toJsonWidget);
279+
280+
const fromJsonWidget = EJSON.fromJSONValue(widget);
281+
assertEquals({...widget}, fromJsonWidget);
282+
283+
const stringifiedWidget = EJSON.stringify(widget);
284+
assertEquals(stringifiedWidget, '{"length":10}');
285+
286+
const parsedWidget = EJSON.parse('{"length":10}');
287+
assertEquals({ length: 10 }, parsedWidget);
288+
289+
assertEquals(false, EJSON.isBinary(widget));
290+
291+
const widget2 = new Widget();
292+
assertEquals(widget, widget2);
293+
294+
const clonedWidget = EJSON.clone(widget);
295+
assertEquals({...widget}, clonedWidget);
296+
});

0 commit comments

Comments
 (0)