mirror of https://github.com/mongodb/mongo
312 lines
10 KiB
JavaScript
312 lines
10 KiB
JavaScript
/**
|
|
* This tests mongo shell functions bsonWoCompare & bsonBinaryEqual.
|
|
*/
|
|
|
|
let t = db.getCollection("bson");
|
|
t.drop();
|
|
function testObjectsAreEqual(obj1, obj2, equalityFunc, func_name) {
|
|
let assert_msg = func_name + " " + tojson(obj1) + " " + tojson(obj2);
|
|
assert(equalityFunc(obj1, obj2), assert_msg);
|
|
}
|
|
|
|
function testObjectsAreNotEqual(obj1, obj2, equalityFunc, func_name) {
|
|
let assert_msg = func_name + " " + tojson(obj1) + " " + tojson(obj2);
|
|
assert(!equalityFunc(obj1, obj2), assert_msg);
|
|
}
|
|
|
|
function runTests(func, testFunc) {
|
|
// Tests on numbers.
|
|
testObjectsAreEqual(0, 0, func, testFunc);
|
|
testObjectsAreEqual(-5, -5, func, testFunc);
|
|
testObjectsAreEqual(1.1, 1.1, func, testFunc);
|
|
testObjectsAreEqual(1, 1, func, testFunc);
|
|
testObjectsAreEqual(1.1, 1.1, func, testFunc);
|
|
let nl0 = new NumberLong("18014398509481984");
|
|
let nl1 = new NumberLong("18014398509481985");
|
|
testObjectsAreEqual(nl0, nl0, func, testFunc);
|
|
testObjectsAreNotEqual(nl0, nl1, func, testFunc);
|
|
|
|
// Test on key name.
|
|
t.insertMany([{a: 0}, {A: 0}]);
|
|
testObjectsAreNotEqual(t.findOne({a: 0}), t.findOne({A: 0}), func, testFunc);
|
|
|
|
// Tests on strings.
|
|
testObjectsAreEqual("abc", "abc", func, testFunc);
|
|
testObjectsAreNotEqual("abc", "aBc", func, testFunc);
|
|
|
|
// Tests on boolean.
|
|
testObjectsAreEqual(true, true, func, testFunc);
|
|
testObjectsAreNotEqual(true, false, func, testFunc);
|
|
testObjectsAreEqual(false, false, func, testFunc);
|
|
|
|
// Tests on date & timestamp.
|
|
let d0 = new Date(0);
|
|
let d1 = new Date(1);
|
|
let ts0 = new Timestamp(0, 1);
|
|
let ts1 = new Timestamp(1, 1);
|
|
testObjectsAreEqual(d0, d0, func, testFunc);
|
|
testObjectsAreNotEqual(d0, d1, func, testFunc);
|
|
testObjectsAreNotEqual(d1, ts1, func, testFunc);
|
|
testObjectsAreEqual(ts0, ts0, func, testFunc);
|
|
testObjectsAreNotEqual(ts0, ts1, func, testFunc);
|
|
|
|
// Tests on regex.
|
|
testObjectsAreEqual(/3/, /3/, func, testFunc);
|
|
testObjectsAreNotEqual(/3/, /3/i, func, testFunc);
|
|
|
|
// Tests on DBPointer.
|
|
let dbp0 = new DBPointer("test", new ObjectId());
|
|
let dbp1 = new DBPointer("test", new ObjectId());
|
|
testObjectsAreEqual(dbp0, dbp0, func, testFunc);
|
|
testObjectsAreNotEqual(dbp0, dbp1, func, testFunc);
|
|
|
|
// Tests on JavaScript.
|
|
let js0 = Function.prototype;
|
|
let js1 = function () {};
|
|
testObjectsAreEqual(js0, Function.prototype, func, testFunc);
|
|
testObjectsAreNotEqual(js0, js1, func, testFunc);
|
|
|
|
// Tests on arrays.
|
|
testObjectsAreEqual([0, 1], [0, 1], func, testFunc);
|
|
testObjectsAreNotEqual([0, 1], [0], func, testFunc);
|
|
testObjectsAreNotEqual([1, 0], [0, 1], func, testFunc);
|
|
|
|
// Tests on BinData & HexData.
|
|
testObjectsAreEqual(
|
|
new BinData(0, "JANgqwetkqwklEWRbWERKKJREtbq"),
|
|
new BinData(0, "JANgqwetkqwklEWRbWERKKJREtbq"),
|
|
func,
|
|
testFunc,
|
|
);
|
|
testObjectsAreEqual(new BinData(0, "AAaa"), new BinData(0, "AAaa"), func, testFunc);
|
|
testObjectsAreNotEqual(new BinData(0, "AAaa"), new BinData(0, "aaAA"), func, testFunc);
|
|
|
|
testObjectsAreEqual(new HexData(0, "AAaa"), new HexData(0, "AAaa"), func, testFunc);
|
|
testObjectsAreEqual(new HexData(0, "AAaa"), new HexData(0, "aaAA"), func, testFunc);
|
|
testObjectsAreNotEqual(new HexData(0, "AAaa"), new BinData(0, "AAaa"), func, testFunc);
|
|
|
|
// Tests on ObjectId
|
|
testObjectsAreEqual(
|
|
new ObjectId("57d1b31cd311a43091fe592f"),
|
|
new ObjectId("57d1b31cd311a43091fe592f"),
|
|
func,
|
|
testFunc,
|
|
);
|
|
testObjectsAreNotEqual(
|
|
new ObjectId("57d1b31cd311a43091fe592f"),
|
|
new ObjectId("57d1b31ed311a43091fe5930"),
|
|
func,
|
|
testFunc,
|
|
);
|
|
|
|
// Tests on miscellaneous types.
|
|
testObjectsAreEqual(NaN, NaN, func, testFunc);
|
|
testObjectsAreEqual(null, null, func, testFunc);
|
|
testObjectsAreNotEqual(null, -null, func, testFunc);
|
|
testObjectsAreEqual(MinKey, MinKey, func, testFunc);
|
|
testObjectsAreEqual(MaxKey, MaxKey, func, testFunc);
|
|
testObjectsAreNotEqual(MinKey, MaxKey, func, testFunc);
|
|
|
|
// Test on object ordering.
|
|
testObjectsAreNotEqual({a: 1, b: 2}, {b: 2, a: 1}, func, testFunc);
|
|
}
|
|
|
|
// Create wrapper function for bsonWoCompare, such that it returns boolean result.
|
|
let bsonWoCompareWrapper = function (obj1, obj2) {
|
|
return bsonWoCompare(obj1, obj2) === 0;
|
|
};
|
|
|
|
// Test Object.entries() enumerates lazy property keys and values correctly.
|
|
function runObjectEntriesTest() {
|
|
t.drop();
|
|
t.insertOne({_id: 1, a: "a", b: "b"});
|
|
let res = t.findOne();
|
|
assert.eq(
|
|
[
|
|
["_id", 1],
|
|
["a", "a"],
|
|
["b", "b"],
|
|
],
|
|
Object.entries(res),
|
|
);
|
|
// Test that we don't re-define properties in Object.entries() after they've been already been
|
|
// defined. We can test this by updating the object here and ensuring the overwrite is reflected
|
|
// in Object.entries().
|
|
res.a = "b";
|
|
assert.eq(
|
|
[
|
|
["_id", 1],
|
|
["a", "b"],
|
|
["b", "b"],
|
|
],
|
|
Object.entries(res),
|
|
);
|
|
}
|
|
|
|
function runObjectEntriesArrayTypesTest() {
|
|
t.drop();
|
|
// Test enumerating "dense" array.
|
|
t.insertOne({_id: 1, a: [1, 2, 3, 4, 5], b: "b"});
|
|
let res = t.findOne();
|
|
assert.eq(
|
|
[
|
|
["_id", 1],
|
|
["a", [1, 2, 3, 4, 5]],
|
|
["b", "b"],
|
|
],
|
|
Object.entries(res),
|
|
);
|
|
assert.eq(
|
|
[
|
|
["0", 1],
|
|
["1", 2],
|
|
["2", 3],
|
|
["3", 4],
|
|
["4", 5],
|
|
],
|
|
Object.entries(res.a),
|
|
);
|
|
t.update({_id: 1}, {$set: {"a.9": 10}});
|
|
res = t.findOne();
|
|
// Test enumerating "sparse" array.
|
|
assert.eq(
|
|
[
|
|
["_id", 1],
|
|
["a", [1, 2, 3, 4, 5, null, null, null, null, 10]],
|
|
["b", "b"],
|
|
],
|
|
Object.entries(res),
|
|
);
|
|
assert.eq(
|
|
[
|
|
["0", 1],
|
|
["1", 2],
|
|
["2", 3],
|
|
["3", 4],
|
|
["4", 5],
|
|
["5", null],
|
|
["6", null],
|
|
["7", null],
|
|
["8", null],
|
|
["9", 10],
|
|
],
|
|
Object.entries(res.a),
|
|
);
|
|
|
|
// Test overwriting the native object is not affected by the Object.entries() call.
|
|
res.a = [5, 6, 7, 8, 9];
|
|
assert.eq(
|
|
[
|
|
["_id", 1],
|
|
["a", [5, 6, 7, 8, 9]],
|
|
["b", "b"],
|
|
],
|
|
Object.entries(res),
|
|
);
|
|
assert.eq(
|
|
[
|
|
["0", 5],
|
|
["1", 6],
|
|
["2", 7],
|
|
["3", 8],
|
|
["4", 9],
|
|
],
|
|
Object.entries(res.a),
|
|
);
|
|
|
|
// Test enumerating nested array.
|
|
t.update({_id: 1}, {$set: {"a.10": [1, 2, 3, 4, 5]}});
|
|
res = t.findOne();
|
|
assert.eq(
|
|
[
|
|
["_id", 1],
|
|
["a", [1, 2, 3, 4, 5, null, null, null, null, 10, [1, 2, 3, 4, 5]]],
|
|
["b", "b"],
|
|
],
|
|
Object.entries(res),
|
|
);
|
|
assert.eq(
|
|
[
|
|
["0", 1],
|
|
["1", 2],
|
|
["2", 3],
|
|
["3", 4],
|
|
["4", 5],
|
|
],
|
|
Object.entries(res.a[10]),
|
|
);
|
|
// Test overwriting the native object is not affected by the Object.entries() call.
|
|
res.a[10] = [5, 6, 7, 8, 9];
|
|
assert.eq(
|
|
[
|
|
["_id", 1],
|
|
["a", [1, 2, 3, 4, 5, null, null, null, null, 10, [5, 6, 7, 8, 9]]],
|
|
["b", "b"],
|
|
],
|
|
Object.entries(res),
|
|
);
|
|
assert.eq(
|
|
[
|
|
["0", 5],
|
|
["1", 6],
|
|
["2", 7],
|
|
["3", 8],
|
|
["4", 9],
|
|
],
|
|
Object.entries(res.a[10]),
|
|
);
|
|
}
|
|
|
|
function runBuildInvalidBsonTest() {
|
|
// We want to ensure that fieldnames in BSONObj can't contain null terminators.
|
|
assert.throws(
|
|
function () {
|
|
let invalidBson = _buildBsonObj("_id", 2, "\0\0", 3);
|
|
},
|
|
[],
|
|
"BSON field name must not contain null terminators.",
|
|
);
|
|
}
|
|
|
|
function runFindEmptyKeyTest() {
|
|
const emptyKeyObj = _buildBsonObj("_id", 0, "", 1);
|
|
assert.eq(true, emptyKeyObj.hasOwnProperty(""));
|
|
assert.eq(1, emptyKeyObj[""]);
|
|
}
|
|
|
|
// Ensure operations can't use \0 in field names. Confirm that these operations both
|
|
// execute without error and don't change the value of emptyKeyObj.
|
|
function runNoNullTerminatedFieldNameTest() {
|
|
const emptyKeyObj = _buildBsonObj("_id", 0, "", 1, "abc", 2);
|
|
for (const n of ["\0", "\0abc", "ab\0c", "ab\0c\0"]) {
|
|
let obj = emptyKeyObj;
|
|
assert.eq(false, obj.hasOwnProperty(n));
|
|
assert.eq(true, delete obj[n]);
|
|
// Delete should not have modified obj.
|
|
testObjectsAreEqual(obj, emptyKeyObj, bsonWoCompareWrapper, "bsonWoCompare");
|
|
}
|
|
}
|
|
|
|
// Run the tests which work the same for both comparators.
|
|
runTests(bsonWoCompareWrapper, "bsonWoCompare");
|
|
runTests(bsonBinaryEqual, "bsonBinaryEqual");
|
|
|
|
// Run the tests which differ between comparators.
|
|
testObjectsAreEqual(NaN, -NaN, bsonWoCompareWrapper, "bsonWoCompare");
|
|
testObjectsAreNotEqual(NaN, -NaN, bsonBinaryEqual, "bsonBinaryEqual");
|
|
testObjectsAreEqual(1, NumberLong("1"), bsonWoCompareWrapper, "bsonWoCompare");
|
|
testObjectsAreNotEqual(1, NumberLong("1"), bsonBinaryEqual, "bsonBinaryEqual");
|
|
testObjectsAreEqual(1.0, NumberLong("1"), bsonWoCompareWrapper, "bsonWoCompare");
|
|
testObjectsAreNotEqual(1.0, NumberLong("1"), bsonBinaryEqual, "bsonBinaryEqual");
|
|
testObjectsAreEqual(NumberInt("1"), NumberLong("1"), bsonWoCompareWrapper, "bsonWoCompare");
|
|
testObjectsAreNotEqual(NumberInt("1"), NumberLong("1"), bsonBinaryEqual, "bsonBinaryEqual");
|
|
testObjectsAreEqual(NumberInt("1"), NumberDecimal("1.0"), bsonWoCompareWrapper, "bsonWoCompare");
|
|
testObjectsAreNotEqual(NumberInt("1"), NumberDecimal("1.0"), bsonBinaryEqual, "bsonBinaryEqual");
|
|
testObjectsAreEqual(NumberLong("1"), NumberDecimal("1.0"), bsonWoCompareWrapper, "bsonWoCompare");
|
|
testObjectsAreNotEqual(NumberLong("1"), NumberDecimal("1.0"), bsonBinaryEqual, "bsonBinaryEqual");
|
|
runObjectEntriesTest();
|
|
runObjectEntriesArrayTypesTest();
|
|
runBuildInvalidBsonTest();
|
|
runFindEmptyKeyTest();
|
|
runNoNullTerminatedFieldNameTest();
|