Browse Source

EAGLESIX-2651: Multiply: better sync w/ 2.6.5 code (mainly reordering), reformat tests a little bit

Kyle P Davis 11 years ago
parent
commit
6ab5e9996c

+ 26 - 28
lib/pipeline/expressions/MultiplyExpression.js

@@ -7,45 +7,43 @@
  * @namespace mungedb-aggregate.pipeline.expressions
  * @module mungedb-aggregate
  * @constructor
- **/
+ */
 var MultiplyExpression = module.exports = function MultiplyExpression(){
-	if (arguments.length !== 0) throw new Error("Zero args expected");
+if (arguments.length !== 0) throw new Error(klass.name + ": no args expected");
 	base.call(this);
 }, klass = MultiplyExpression, base = require("./VariadicExpressionT")(MultiplyExpression), proto = klass.prototype = Object.create(base.prototype, {constructor:{value:klass}});
 
-// DEPENDENCIES
 var Value = require("../Value"),
- Expression = require("./Expression");
+	Expression = require("./Expression");
 
-// PROTOTYPE MEMBERS
-klass.opName = "$multiply";
-proto.getOpName = function getOpName(){
-	return klass.opName;
-};
+proto.evaluateInternal = function evaluateInternal(vars) {
+	var product = 1; //NOTE: DEVIATION FROM MONGO: no need to track narrowest so just use one var
 
-proto.isAssociativeAndCommutative = function isAssociativeAndCommutative() { return true; };
+	var n = this.operands.length;
+	for (var i = 0; i < n; ++i) {
+		var val = this.operands[i].evaluateInternal(vars);
 
-/**
- * Takes an array of one or more numbers and multiples them, returning the resulting product.
- * @method evaluateInternal
- **/
-proto.evaluateInternal = function evaluateInternal(vars){
-	var product = 1;
-	for(var i = 0, n = this.operands.length; i < n; ++i){
-		var value = this.operands[i].evaluateInternal(vars);
-		if (typeof value == "number") {
-			product *= Value.coerceToDouble(value);
-		} else if (value == null || value == undefined) {
+		if (typeof val === "number") {
+			product *= Value.coerceToDouble(val);
+		} else if (val === undefined || val === null) {
 			return null;
 		} else {
-			throw new Error("$multiply only supports numeric types, not "+typeof value+"; code 16555");
+			throw new Error("$multiply only supports numeric types, not " +
+			 	Value.getType(val) + "; uasserted code 16555");
 		}
 	}
-	//NOTE: DEVIATION FROM MONGO: The c++ code (expressions.cpp line 1659) deals with types that
-	// do not seem to apply to javascript.
-	if(typeof(product) != "number") throw new Error("$multiply resulted in a non-numeric type; code 16418");
-	return product;
+
+	if (typeof product === "number")
+		return product;
+	throw new Error("$multiply resulted in a non-numeric type; massert code 16418");
 };
 
-/** Register Expression */
-Expression.registerExpression(klass.opName, base.parse);
+Expression.registerExpression("$multiply", base.parse);
+
+proto.getOpName = function getOpName(){
+	return "$multiply";
+};
+
+proto.isAssociativeAndCommutative = function isAssociativeAndCommutative() {
+	return true;
+};

+ 87 - 85
test/lib/pipeline/expressions/MultiplyExpression_test.js

@@ -7,104 +7,106 @@ var assert = require("assert"),
 	ConstantExpression = require("../../../../lib/pipeline/expressions/ConstantExpression"),
 	Expression = require("../../../../lib/pipeline/expressions/Expression");
 
+// Mocha one-liner to make these tests self-hosted
+if(!module.parent)return(require.cache[__filename]=null,(new(require("mocha"))({ui:"exports",reporter:"spec",grep:process.env.TEST_GREP})).addFile(__filename).run(process.exit));
 
-module.exports = {
+exports.MultiplyExpression = {
 
-	"MultiplyExpression": {
+	beforeEach: function(){
+		this.vps = new VariablesParseState(new VariablesIdGenerator());
+	},
 
-		beforeEach: function(){
-			this.vps = new VariablesParseState(new VariablesIdGenerator());
+	"constructor()": {
+
+		"should not throw Error when constructing without args": function() {
+			assert.doesNotThrow(function(){
+				new MultiplyExpression();
+			});
 		},
 
-		"constructor()": {
+		"should throw Error when constructing with args": function() {
+			assert.throws(function(){
+				new MultiplyExpression(1);
+			});
+		},
 
-			"should not throw Error when constructing without args": function testConstructor(){
-				assert.doesNotThrow(function(){
-					new MultiplyExpression();
-				});
-			},
+	},
 
-			"should throw Error when constructing with args": function testConstructor(){
-				assert.throws(function(){
-					new MultiplyExpression(1);
-				});
-			}
+	"#getOpName()": {
 
+		"should return the correct op name; $multiply": function() {
+			assert.equal(new MultiplyExpression().getOpName(), "$multiply");
 		},
 
-		"#getOpName()": {
+	},
 
-			"should return the correct op name; $multiply": function testOpName(){
-				assert.equal(new MultiplyExpression().getOpName(), "$multiply");
-			}
+	"#evaluate()": {
 
+		"should multiply constants": function () {
+			assert.strictEqual(Expression.parseOperand({$multiply: [2, 3, 4]}, this.vps).evaluate(), 2 * 3 * 4);
 		},
 
-		"#evaluate()": {
-			"should multiply constants": function () {
-				assert.strictEqual(Expression.parseOperand({$multiply: [2, 3, 4]}, this.vps).evaluate(), 2 * 3 * 4);
-			},
-
-			"should 'splode if an operand is a string": function () {
-				assert.throws(function () {
-					Expression.parseOperand({$multiply: [2, "x", 4]}, this.vps).evaluate();
-				});
-			},
-
-			"should 'splode if an operand is a boolean": function () {
-				assert.throws(function () {
-					Expression.parseOperand({$multiply: [2, "x", 4]}, this.vps).evaluate();
-				});
-			},
-
-			"should 'splode if an operand is a date": function () {
-				assert.throws(function () {
-					Expression.parseOperand({$multiply: [2, "x", 4]}, this.vps).evaluate();
-				});
-			},
-
-			"should handle a null operand": function(){
-				assert.strictEqual(Expression.parseOperand({$multiply: [2, null]}, this.vps).evaluate(), null);
-			},
-
-			"should handle an undefined operand": function(){
-				assert.strictEqual(Expression.parseOperand({$multiply: [2, undefined]}, this.vps).evaluate(), null);
-			},
-
-			"should multiply mixed numbers": function () {
-				assert.strictEqual(Expression.parseOperand({$multiply: [2.1, 3, 4.4]}, this.vps).evaluate(), 2.1 * 3 * 4.4);
-			},
-
-			"should return result of multiplying simple variables": function () {
-				assert.equal(Expression.parseOperand({$multiply: ["$a", "$b"]}, this.vps).evaluate({a: 1, b: 2}), 1 * 2);
-			},
-
-			"should return result of multiplying large variables": function () {
-				assert.strictEqual(Expression.parseOperand({$multiply: ["$a", "$b", "$c"]}, this.vps).evaluate({a: 1.345, b: 2e45, c: 0}), 1.345 * 2e45 * 0);
-			},
-
-			"should return result of multiplying one number": function () {
-				assert.strictEqual(Expression.parseOperand({$multiply: ["$a"]}, this.vps).evaluate({a: 1}), 1);
-			},
-
-			"should throw an exception if the result is not a number": function () {
-				assert.throws(
-					function () {
-						Expression.parseOperand({$multiply: ["$a", "$b"]}, this.vps).evaluate({a: 1e199, b: 1e199});
-					});
-			}
+		"should 'splode if an operand is a string": function () {
+			assert.throws(function () {
+				Expression.parseOperand({$multiply: [2, "x", 4]}, this.vps).evaluate();
+			});
+		},
+
+		"should 'splode if an operand is a boolean": function () {
+			assert.throws(function () {
+				Expression.parseOperand({$multiply: [2, "x", 4]}, this.vps).evaluate();
+			});
+		},
+
+		"should 'splode if an operand is a date": function () {
+			assert.throws(function () {
+				Expression.parseOperand({$multiply: [2, "x", 4]}, this.vps).evaluate();
+			});
 		},
-		"optimize": {
-			"should optimize out constants separated by a variable": function () {
-				var a = Expression.parseOperand({$multiply: [2, 3, 4, 5, '$a', 6, 7, 8]}, this.vps).optimize();
-				assert(a instanceof MultiplyExpression);
-				assert.equal(a.operands.length, 2);
-				assert(a.operands[0] instanceof FieldPathExpression);
-				assert(a.operands[1] instanceof ConstantExpression);
-				assert.equal(a.operands[1].evaluateInternal(), 2*3*4*5*6*7*8);
-			}
-		}
-	}
-};
 
-if (!module.parent)(new(require("mocha"))()).ui("exports").reporter("spec").addFile(__filename).run(process.exit);
+		"should handle a null operand": function(){
+			assert.strictEqual(Expression.parseOperand({$multiply: [2, null]}, this.vps).evaluate(), null);
+		},
+
+		"should handle an undefined operand": function(){
+			assert.strictEqual(Expression.parseOperand({$multiply: [2, undefined]}, this.vps).evaluate(), null);
+		},
+
+		"should multiply mixed numbers": function () {
+			assert.strictEqual(Expression.parseOperand({$multiply: [2.1, 3, 4.4]}, this.vps).evaluate(), 2.1 * 3 * 4.4);
+		},
+
+		"should return result of multiplying simple variables": function () {
+			assert.equal(Expression.parseOperand({$multiply: ["$a", "$b"]}, this.vps).evaluate({a: 1, b: 2}), 1 * 2);
+		},
+
+		"should return result of multiplying large variables": function () {
+			assert.strictEqual(Expression.parseOperand({$multiply: ["$a", "$b", "$c"]}, this.vps).evaluate({a: 1.345, b: 2e45, c: 0}), 1.345 * 2e45 * 0);
+		},
+
+		"should return result of multiplying one number": function () {
+			assert.strictEqual(Expression.parseOperand({$multiply: ["$a"]}, this.vps).evaluate({a: 1}), 1);
+		},
+
+		"should throw an exception if the result is not a number": function () {
+			assert.throws(function() {
+				Expression.parseOperand({$multiply: ["$a", "$b"]}, this.vps).evaluate({a: 1e199, b: 1e199});
+			});
+		},
+
+	},
+
+	"optimize": {
+
+		"should optimize out constants separated by a variable": function () {
+			var a = Expression.parseOperand({$multiply: [2, 3, 4, 5, '$a', 6, 7, 8]}, this.vps).optimize();
+			assert(a instanceof MultiplyExpression);
+			assert.equal(a.operands.length, 2);
+			assert(a.operands[0] instanceof FieldPathExpression);
+			assert(a.operands[1] instanceof ConstantExpression);
+			assert.equal(a.operands[1].evaluateInternal(), 2*3*4*5*6*7*8);
+		},
+
+	},
+
+};