| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374 | 
							- "use strict";
 
- var assert = require("assert"),
 
- 	aggregate = require("../../");
 
- // Utility to test the various use cases of `aggregate`
 
- function testAggregate(opts){
 
- 	// SYNC: test one-off usage
 
- 	var results = aggregate(opts.pipeline, opts.inputs);
 
- 	assert.equal(JSON.stringify(results), JSON.stringify(opts.expected));
 
- 	// SYNC: test one-off usage with context
 
- 	results = aggregate(opts.pipeline, {hi: "there"}, opts.inputs);
 
- 	assert.equal(JSON.stringify(results), JSON.stringify(opts.expected));
 
- 	// SYNC: test use with context
 
- 	var aggregator = aggregate(opts.pipeline, {hi: "there"});
 
- 	results = aggregator(opts.inputs);
 
- 	assert.equal(JSON.stringify(results), JSON.stringify(opts.expected));
 
- 	// SYNC: test reusable aggregator functionality
 
- 	aggregator = aggregate(opts.pipeline);
 
- 	results = aggregator(opts.inputs);
 
- 	assert.equal(JSON.stringify(results), JSON.stringify(opts.expected));
 
- 	// SYNC: test that it is actually reusable
 
- 	results = aggregator(opts.inputs);
 
- 	assert.equal(JSON.stringify(results), JSON.stringify(opts.expected), "Reuse of aggregator should yield the same results!");
 
- 	// ASYNC: test one-off usage
 
- 	aggregate(opts.pipeline, opts.inputs, function(err, results){
 
- 		assert.ifError(err);
 
- 		assert.equal(JSON.stringify(results), JSON.stringify(opts.expected));
 
- 		// ASYNC: test one-off usage with context
 
- 		aggregate(opts.pipeline, {hi: "there"}, opts.inputs, function(err, results){
 
- 			assert.ifError(err);
 
- 			assert.equal(JSON.stringify(results), JSON.stringify(opts.expected));
 
- 			// ASYNC: test reusable aggregator functionality with context
 
- 			var aggregator = aggregate(opts.pipeline);
 
- 			aggregator({hi: "there"}, opts.inputs, function(err, results){
 
- 				assert.ifError(err);
 
- 				assert.equal(JSON.stringify(results), JSON.stringify(opts.expected));
 
- 				// ASYNC: test reusable aggregator functionality
 
- 				var aggregator = aggregate(opts.pipeline);
 
- 				aggregator(opts.inputs, function(err, results){
 
- 					assert.ifError(err);
 
- 					assert.equal(JSON.stringify(results), JSON.stringify(opts.expected));
 
- 					// ASYNC: test that it is actually reusable
 
- 					aggregator(opts.inputs, function(err, results){
 
- 						assert.ifError(err);
 
- 						assert.equal(JSON.stringify(results), JSON.stringify(opts.expected), "Reuse of aggregator should yield the same results!");
 
- 						// success!
 
- 						return opts.next();
 
- 					});
 
- 				});
 
- 			});
 
- 		});
 
- 	});
 
- }
 
- module.exports = {
 
- 	"aggregate": {
 
- 		"should be able to use an empty pipeline (no-op)": function(next){
 
- 			testAggregate({
 
- 				inputs: [1, 2, 3],
 
- 				pipeline: [],
 
- 				expected: [1, 2, 3],
 
- 				next: next
 
- 			});
 
- 		},
 
- 		"should be able to use a limit operator": function(next){
 
- 			testAggregate({
 
- 				inputs: [{_id:0}, {_id:1}, {_id:2}, {_id:3}, {_id:4}, {_id:5}],
 
- 				pipeline: [{$limit:2}],
 
- 				expected: [{_id:0}, {_id:1}],
 
- 				next: next
 
- 			});
 
- 		},
 
- 		"should be able to use a match operator": function(next){
 
- 			testAggregate({
 
- 				inputs: [{_id:0, e:1}, {_id:1, e:0}, {_id:2, e:1}, {_id:3, e:0}, {_id:4, e:1}, {_id:5, e:0}],
 
- 				pipeline: [{$match:{e:1}}],
 
- 				expected: [{_id:0, e:1}, {_id:2, e:1}, {_id:4, e:1}],
 
- 				next: next
 
- 			});
 
- 		},
 
- 		"should be able to use a skip operator": function(next){
 
- 			testAggregate({
 
- 				inputs: [{_id:0}, {_id:1}, {_id:2}, {_id:3}, {_id:4}, {_id:5}],
 
- 				pipeline: [{$skip:2}, {$skip:1}],	//testing w/ 2 ensures independent state variables
 
- 				expected: [{_id:3}, {_id:4}, {_id:5}],
 
- 				next: next
 
- 			});
 
- 		},
 
- 		"should be able to use a skip and then a limit operator together in the same pipeline": function(next){
 
- 			testAggregate({
 
- 				inputs: [{_id:0, e:1}, {_id:1, e:0}, {_id:2, e:1}, {_id:3, e:0}, {_id:4, e:1}, {_id:5, e:0}],
 
- 				pipeline: [{$skip:2}, {$limit:1}],
 
- 				expected: [{_id:2, e:1}],
 
- 				next: next
 
- 			});
 
- 		},
 
- 		"should be able to construct an instance with unwind operators properly": function(next){
 
- 			testAggregate({
 
- 				inputs: [
 
- 					{_id:0, nodes:[
 
- 						{one:[11], two:[2,2]},
 
- 						{one:[1,1], two:[22]}
 
- 					]},
 
- 					{_id:1, nodes:[
 
- 						{two:[22], three:[333]},
 
- 						{one:[1], three:[3,3,3]}
 
- 					]}
 
- 				],
 
- 				pipeline: [{$unwind:"$nodes"}, {$unwind:"$nodes.two"}],
 
- 				expected: [
 
- 					{_id:0,nodes:{one:[11],two:2}},
 
- 					{_id:0,nodes:{one:[11],two:2}},
 
- 					{_id:0,nodes:{one:[1,1],two:22}},
 
- 					{_id:1,nodes:{two:22,three:[333]}}
 
- 				],
 
- 				next: next
 
- 			});
 
- 		},
 
- 		"should be able to use a project operator": function(next){
 
- 			// NOTE: Test case broken until expression is fixed
 
- 			testAggregate({
 
- 				inputs: [{_id:0, e:1, f:23}, {_id:2, e:2, g:34}, {_id:4, e:3}],
 
- 				pipeline: [
 
- 					{$project:{
 
- 						e:1,
 
- 						a:{$add:["$e", "$e"]},
 
- 						b:{$cond:[{$eq:["$e", 2]}, "two", "not two"]}
 
- 						//TODO: high level test of all other expression operators
 
- 					}}
 
- 				],
 
- 				expected: [{_id:0, e:1, a:2, b:"not two"}, {_id:2, e:2, a:4, b:"two"}, {_id:4, e:3, a:6, b:"not two"}],
 
- 				next: next
 
- 			});
 
- 		},
 
- 		"should be able to use a project operator to exclude the _id field": function(next){
 
- 			// NOTE: Test case broken until expression is fixed
 
- 			testAggregate({
 
- 				inputs: [{_id:0, e:1, f:23}, {_id:2, e:2, g:34}, {_id:4, e:3}],
 
- 				pipeline: [
 
- 					{$project:{
 
- 						_id:0,
 
- 						e:1
 
- 						//TODO: high level test of all other expression operators
 
- 					}}
 
- 				],
 
- 				expected: [{e:1}, {e:2}, {e:3}],
 
- 				next: next
 
- 			});
 
- 		},
 
- 		"should be able to project out a whole document and leave an empty": function(next) {
 
- 			testAggregate({
 
- 				inputs: [{_id:0, a:1}, {_id:1, a:2, b:1}, {_id:2, b:2, c:1}],
 
- 				pipeline: [
 
- 					{$project:{
 
- 						_id:0,
 
- 						a:1
 
- 						//TODO: high level test of all other expression operators
 
- 					}}
 
- 				],
 
- 				expected: [{a:1}, {a:2}, {}],
 
- 				next: next
 
- 			});
 
- 		},
 
- 		"should be able to construct an instance with sort operators properly (ascending)": function(next){
 
- 			testAggregate({
 
- 				inputs: [
 
- 					{_id:3.14159}, {_id:-273.15},
 
- 					{_id:42}, {_id:11}, {_id:1},
 
- 					{_id:null}, {_id:NaN}
 
- 				],
 
- 				pipeline: [{$sort:{_id:1}}],
 
- 				expected: [
 
- 					{_id:null}, {_id:NaN},
 
- 					{_id:-273.15}, {_id:1}, {_id:3.14159}, {_id:11}, {_id:42}
 
- 				],
 
- 				next: next
 
- 			});
 
- 		},
 
- 		"should be able to construct an instance with $group operators properly": function(next){
 
- 			// NOTE: Test case broken until expression is fixed
 
- 			testAggregate({
 
- 				inputs: [
 
- 					{_id:0, a:1},
 
- 					{_id:0, a:2},
 
- 					{_id:0, a:3},
 
- 					{_id:0, a:4},
 
- 					{_id:0, a:1.5},
 
- 					{_id:0, a:null},
 
- 					{_id:1, b:"a"},
 
- 					{_id:1, b:"b"},
 
- 					{_id:1, b:"b"},
 
- 					{_id:1, b:"c"}
 
- 				],
 
- 				pipeline:[
 
- 					{$group:{
 
- 						_id:"$_id",
 
- 						sum_a:{$sum:"$a"},
 
- 						//min_a:{$min:"$a"}, //this is busted in this version of mongo
 
- 						max_a:{$max:"$a"},
 
- 						avg_a:{$avg:"$a"},
 
- 						first_b:{$first:"$b"},
 
- 						last_b:{$last:"$b"},
 
- 						addToSet_b:{$addToSet:"$b"},
 
- 						push_b:{$push:"$b"}
 
- 					}}
 
- 				],
 
- 				expected: [
 
- 					{
 
- 						_id:0,
 
- 						sum_a:11.5,
 
- 						//min_a:1,
 
- 						max_a:4,
 
- 						avg_a:2.3,
 
- 						first_b:undefined,
 
- 						last_b:undefined,
 
- 						addToSet_b:[],
 
- 						push_b:[]
 
- 					},
 
- 					{
 
- 						_id:1,
 
- 						sum_a:0,
 
- 						//min_a:null,
 
- 						max_a:undefined,
 
- 						avg_a:0,
 
- 						first_b:"a",
 
- 						last_b:"c",
 
- 						addToSet_b:["a", "b", "c"],
 
- 						push_b:["a", "b", "b", "c"]
 
- 					}
 
- 				],
 
- 				next: next
 
- 			});
 
- 		},
 
- 		"should be able to construct an instance with $group using concat": function(next){
 
- 			// NOTE: Test case broken until expression is fixed; not sure if that concat is supposed to work
 
- 			testAggregate({
 
- 				inputs: [
 
- 					{_id:0, a:null},
 
- 					{_id:1, a:"a"},
 
- 					{_id:1, a:"b"},
 
- 					{_id:1, a:"b"},
 
- 					{_id:1, a:"c"}
 
- 				],
 
- 				pipeline: [
 
- 					{$group:{
 
- 						_id:{$concat:["$a"]}
 
- 					}}
 
- 				],
 
- 				expected: [
 
- 					{_id: null},
 
- 					{_id: "a"},
 
- 					{_id: "b"},
 
- 					{_id: "c"}
 
- 				],
 
- 				next: next
 
- 			});
 
- 		},
 
- 		"should be able to successfully use comparisions of objects to nulls without throwing an exception": function(next){
 
- 			testAggregate({
 
- 				inputs: [
 
- 					{
 
- 						cond:{$or:[
 
- 							{$eq:["$server","Starmetal.demo.com"]},
 
- 						]},
 
- 						value:"PII"
 
- 					},
 
- 					{
 
- 						cond:{$or:[
 
- 							{$eq:["$server","Specium.demo.com"]},
 
- 							{$eq:["$server","Germanium.demo.com"]},
 
- 							{$eq:["$server","Runite.demo.com"]}
 
- 						]},
 
- 						value:"PI"
 
- 					},
 
- 					{
 
- 						cond:{$or:[
 
- 							{$eq:["$server","Primal.demo.com"]}
 
- 						]},
 
- 						value:"Confidential"
 
- 					},
 
- 					{
 
- 						cond:{$or:[
 
- 							{$eq:["$server","Polarite.demo.com"]},
 
- 							{$eq:["$server","Ryanium.demo.com"]}
 
- 						]},
 
- 						value:"Proprietary"
 
- 					},
 
- 					{
 
- 						cond:{$or:[
 
- 							{$eq:["$server","Phazon.demo.com"]}
 
- 						]},
 
- 						value:"PHI"
 
- 					},
 
- 					{
 
- 						cond:null,
 
- 						value:"Authorized"
 
- 					}
 
- 				],
 
- 				pipeline: [
 
- 					{$skip:1},
 
- 					{$limit:1},
 
- 					{$project:{
 
- 						retValue:{$cond:[
 
- 							{$ne:["$cond", null]},
 
- 							null,
 
- 							"$value"
 
- 						]}
 
- 					}}
 
- 				],
 
- 				expected: [{"retValue":null}],
 
- 				next: next
 
- 			});
 
- 		},
 
- 		"should be able to successfully compare a null to a null": function(next){
 
- 			testAggregate({
 
- 				inputs: [
 
- 					{
 
- 						cond:null,
 
- 						value:"Authorized"
 
- 					}
 
- 				],
 
- 				pipeline: [
 
- 					{$project:{
 
- 						retValue:{$cond:[
 
- 							{$eq:["$cond", null]},
 
- 							"$value",
 
- 							null
 
- 						]}
 
- 					}}
 
- 				],
 
- 				expected: [{"retValue":"Authorized"}],
 
- 				next: next
 
- 			});
 
- 		},
 
- 	}
 
- };
 
- if (!module.parent)(new(require("mocha"))()).ui("exports").reporter("spec").addFile(__filename).grep(process.env.MOCHA_GREP || '').run(process.exit);
 
 
  |