Browse Source

Refs #5126, #5131: Add test cases/fixes

Chris Sexton 11 years ago
parent
commit
5e7f4d8681

+ 26 - 24
lib/pipeline/documentSources/MatchDocumentSource.js

@@ -116,7 +116,7 @@ proto.redactSafePortion = function redactSafePortion() {
 	// input is well formed.
 
 	var isAllDigits = function(n) {
-		return typeof n == 'number' && !isNaN(n - n);
+		return !isNaN(n);
 	};
 
 	var isFieldnameRedactSafe = function isFieldnameRedactSafe(field) {
@@ -151,14 +151,14 @@ proto.redactSafePortion = function redactSafePortion() {
 			if (field === '$type' || field === '$regex' || field === '$options' || field === '$mod') {
 				output[field] = value;
 			} else if (field === '$lte' || field === '$gte' || field === '$lt' || field === '$gt') {
-				if (isTypeRedactSaveInComparison(field))
+				if (isTypeRedactSafeInComparison(field))
 					output[field] = value;
 			} else if (field === '$in') {
 				// TODO: value/elem/field/etc may be mixed up and wrong here
 				var allOk = true;
-				for (j = 0; j < Object.keys(value); j++) {
+				for (j = 0; j < Object.keys(value).length; j++) {
 					elem = Object.keys(value)[j];
-					if (!isTypeRedactSaveInComparison(elem)) {
+					if (!isTypeRedactSafeInComparison(value[elem])) {
 						allOk = false;
 						break;
 					}
@@ -170,16 +170,16 @@ proto.redactSafePortion = function redactSafePortion() {
 			} else if (field === '$all') {
 				// TODO: value/elem/field/etc may be mixed up and wrong here
 				var matches = [];
-				for (j = 0; j < field.length; j++) {
+				for (j = 0; j < value.length; j++) {
 					elem = Object.keys(value)[j];
-					if (isTypeRedactSaveInComparison(elem))
+					if (isTypeRedactSafeInComparison(value[elem]))
 						matches.push(value[elem]);
 				}
 				if (matches.length)
 					output[field] = matches;
 
 			} else if (field === '$elemMatch') {
-				var subIn = field,
+				var subIn = value,
 					subOut;
 
 				if (subIn[0] === '$')
@@ -187,7 +187,7 @@ proto.redactSafePortion = function redactSafePortion() {
 				else
 					subOut = redactSafePortionTopLevel(subIn);
 
-				if (subOut)
+				if (subOut && Object.keys(subOut).length)
 					output[field] = subOut;
 
 				break;
@@ -201,8 +201,8 @@ proto.redactSafePortion = function redactSafePortion() {
 		return output;
 	};
 
-	var isTypeRedactSaveInComparison = function isTypeRedactSaveInComparison(type) {
-		if (type instanceof Array || type instanceof Object || type === null || type === undefined)
+	var isTypeRedactSafeInComparison = function isTypeRedactSafeInComparison(type) {
+		if (type instanceof Array || (type instanceof Object && type.constructor === Object) || type === null || type === undefined)
 			return false;
 		return true;
 	};
@@ -213,21 +213,21 @@ proto.redactSafePortion = function redactSafePortion() {
 	var redactSafePortionTopLevel = function(topQuery) {
 		var output = {},
 			okClauses = [],
-			keys = Object.keys(query),
+			keys = topQuery ? Object.keys(topQuery) : [],
 			j, elm, clause;
 
 		for (var i = 0; i < keys.length; i++) {
 			var field = keys[i],
-				query = topQuery[field];
+				value = topQuery[field];
 
 			if (field.length && field[0] === '$') {
 				if (field === '$or') {
 					okClauses = [];
-					for (j = 0; j < Object.keys(field).length; j++) {
-						elm = field[Object.keys(field)[j]];
+					for (j = 0; j < Object.keys(value).length; j++) {
+						elm = value[Object.keys(value)[j]];
 						clause = redactSafePortionTopLevel(elm);
 
-						if (!clause) {
+						if (!clause || Object.keys(clause).length === 0) {
 							okClauses = [];
 							break;
 						}
@@ -235,16 +235,16 @@ proto.redactSafePortion = function redactSafePortion() {
 						okClauses.push(clause);
 					}
 
-					if (okClauses) {
+					if (okClauses && okClauses.length) {
 						output.$or = okClauses;
 					}
 				} else if (field === '$and') {
 					okClauses = [];
-					for (j = 0; j < Object.keys(field).length; j++) {
-						elm = field[Object.keys(field)[j]];
+					for (j = 0; j < Object.keys(value).length; j++) {
+						elm = value[Object.keys(value)[j]];
 						clause = redactSafePortionTopLevel(elm);
 
-						if (clause)
+						if (clause && Object.keys(clause).length)
 							okClauses.push(clause);
 					}
 
@@ -258,15 +258,17 @@ proto.redactSafePortion = function redactSafePortion() {
 			if (!isFieldnameRedactSafe(field))
 					continue;
 
-			if (field instanceof Array || !field) {
+			if (value instanceof Array || !value) {
 				continue;
-			} else {
-				// subobjects
-				var sub = redactSavePortionDollarOps(field);
-				if (sub)
+			} else if (value instanceof Object && value.constructor === Object) {
+				// subobjects (not regex etc)
+				var sub = redactSavePortionDollarOps(value);
+				if (sub && Object.keys(sub).length)
 					output[field] = sub;
 
 				break;
+			} else {
+				output[field] = value;
 			}
 		}
 

+ 2 - 2
lib/pipeline/documentSources/RedactDocumentSource.js

@@ -66,7 +66,7 @@ proto.redactValue = function redactValue(input) {
 		var newArr,
 			arr = input;
 		for (var i = 0; i < arr.length; i++) {
-			if (arr[i] instanceof Object || arr[i] instanceof Array) {
+			if ((arr[i] instanceof Object && arr[i].constructor === Object) || arr[i] instanceof Array) {
 				var toAdd = this.redactValue(arr[i]);
 				if (toAdd)
 					newArr.push(arr[i]);
@@ -75,7 +75,7 @@ proto.redactValue = function redactValue(input) {
 			}
 		}
 		return newArr;
-	} else if (input instanceof Object) {
+	} else if (input instanceof Object && input.constructor === Object) {
 		this._variables.setValue(this._currentId, input);
 		var result = this.redactObject();
 		if (result !== DocumentSource.EOF)

+ 141 - 3
test/lib/pipeline/documentSources/MatchDocumentSource.js

@@ -4,6 +4,11 @@ var assert = require("assert"),
 	DocumentSource = require("../../../../lib/pipeline/documentSources/DocumentSource"),
 	MatchDocumentSource = require("../../../../lib/pipeline/documentSources/MatchDocumentSource");
 
+var testRedactSafe = function testRedactSafe(input, safePortion) {
+	var match = MatchDocumentSource.createFromJson(input);
+	assert.deepEqual(match.redactSafePortion(), safePortion);
+};
+
 
 module.exports = {
 
@@ -173,9 +178,142 @@ module.exports = {
 
 		"#redactSafePortion()": {
 
-			"should throw unimplemented, for now": function() {
-				var mds = new MatchDocumentSource({$gt:1});
-				assert.throws(mds.redactSafePortion);
+			"empty match": function() {
+				testRedactSafe({}, {});
+			},
+
+			"basic allowed things": function () {
+				testRedactSafe({a:1},
+					{a:1});
+
+				testRedactSafe({a:'asdf'},
+					{a:'asdf'});
+
+				testRedactSafe({a:/asdf/i},
+					{a:/asdf/i});
+
+				testRedactSafe({a: {$regex: 'adsf'}},
+					{a: {$regex: 'adsf'}});
+
+				testRedactSafe({a: {$regex: 'adsf', $options: 'i'}},
+					{a: {$regex: 'adsf', $options: 'i'}});
+
+				testRedactSafe({a: {$mod: [1, 0]}},
+					{a: {$mod: [1, 0]}});
+
+				testRedactSafe({a: {$type: 1}},
+					{a: {$type: 1}});
+
+			},
+
+			"basic disallowed things": function() {
+
+				testRedactSafe({a: null},
+					{});
+
+				testRedactSafe({a: {}},
+					{});
+
+				testRedactSafe({a: []},
+					{});
+
+				testRedactSafe({'a.0': 1},
+					{});
+
+				testRedactSafe({'a.0.b': 1},
+					{});
+
+				testRedactSafe({a: {$ne: 1}},
+					{});
+
+				testRedactSafe({a: {$nin: [1, 2, 3]}},
+					{});
+
+				testRedactSafe({a: {$exists: true}}, // could be allowed but currently isn't
+					{});
+
+				testRedactSafe({a: {$exists: false}}, // can never be allowed
+					{});
+
+				testRedactSafe({a: {$size: 1}},
+					{});
+
+				testRedactSafe({$nor: [{a:1}]},
+					{});
+
+			},
+
+			"Combinations": function() {
+				testRedactSafe({a:1, b: 'asdf'},
+					{a:1, b: 'asdf'});
+
+				testRedactSafe({a:1, b: null},
+					{a:1});
+
+				testRedactSafe({a:null, b: null},
+					{});
+			},
+
+			"$elemMatch": function() {
+				testRedactSafe({a: {$elemMatch: {b: 1}}},
+					{a:{$elemMatch:{b: 1}}});
+
+				testRedactSafe({a:{$elemMatch:{b:null}}},
+					{});
+
+				testRedactSafe({a:{$elemMatch:{b:null, c:1}}},
+					{a:{$elemMatch:{c: 1}}});
+			},
+
+			"explicit $and": function(){
+				testRedactSafe({$and:[{a: 1}]},
+					{$and:[{a: 1}]});
+
+				testRedactSafe({$and:[{a: 1},{b: null}]},
+					{$and:[{a: 1}]});
+
+				testRedactSafe({$and:[{a: 1},{b: null, c:1}]},
+					{$and:[{a: 1},{c:1}]});
+
+				testRedactSafe({$and:[{a: null},{b: null}]},
+					{});
+			},
+
+			"explicit $or": function() {
+				testRedactSafe({$or:[{a: 1}]},
+					{$or:[{a: 1}]});
+
+				testRedactSafe({$or:[{a: 1},{b: null}]},
+					{});
+
+				testRedactSafe({$or:[{a: 1},{b: null, c:1}]},
+					{$or:[{a: 1}, {c:1}]});
+
+				testRedactSafe({$or:[{a: null},{b: null}]},
+					{});
+
+				testRedactSafe({},
+					{});
+			},
+
+			"$all and $in": function() {
+				testRedactSafe({a:{$all: [1, 0]}},
+					{a: {$all: [1, 0]}});
+
+				testRedactSafe({a:{$all: [1, 0, null]}},
+					{a: {$all: [1, 0]}});
+
+				testRedactSafe({a:{$all: [{$elemMatch: {b:1}}]}}, // could be allowed but currently isn't
+					{});
+
+				testRedactSafe({a:{$all: [1, 0, null]}},
+					{a: {$all: [1, 0]}});
+
+				testRedactSafe({a:{$in: [1, 0]}},
+					{a: {$in: [1, 0]}});
+
+				testRedactSafe({a:{$in: [1, 0, null]}},
+					{});
 			}
 
 		}