| 
									
										
										
										
											2020-05-24 02:41:30 +03:00
										 |  |  | /********************************************************************** | 
					
						
							|  |  |  | *  | 
					
						
							|  |  |  | * | 
					
						
							|  |  |  | * | 
					
						
							|  |  |  | * | 
					
						
							|  |  |  | **********************************************************************/ | 
					
						
							|  |  |  | ((typeof define)[0]=='u'?function(f){module.exports=f(require)}:define) | 
					
						
							|  |  |  | (function(require){ var module={} // make module AMD/node compatible...
 | 
					
						
							|  |  |  | /*********************************************************************/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var object = require('./object') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-24 23:59:01 +03:00
										 |  |  | //---------------------------------------------------------------------
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-30 00:35:06 +03:00
										 |  |  | // NOTE: to test in verbose mode do:
 | 
					
						
							|  |  |  | // 			$ export VERBOSE=1 && npm test
 | 
					
						
							|  |  |  | // 		or
 | 
					
						
							|  |  |  | // 			$ export VERBOSE=1 && node test.js
 | 
					
						
							|  |  |  | // 		or set this manually after require('./test') but before running 
 | 
					
						
							|  |  |  | // 		the runner(..)
 | 
					
						
							|  |  |  | // 		XXX this may change in the future...
 | 
					
						
							|  |  |  | module.VERBOSE = process ? | 
					
						
							|  |  |  | 	process.env.VERBOSE | 
					
						
							|  |  |  | 	: false | 
					
						
							| 
									
										
										
										
											2020-05-24 23:59:01 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-24 02:41:30 +03:00
										 |  |  | //---------------------------------------------------------------------
 | 
					
						
							|  |  |  | // helpers...
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-30 00:39:36 +03:00
										 |  |  | // a constructor is a thing that starts with a capital and has a .prototype
 | 
					
						
							| 
									
										
										
										
											2020-05-24 02:41:30 +03:00
										 |  |  | var constructors = function(obj){ | 
					
						
							|  |  |  | 	return Object.entries(obj) | 
					
						
							|  |  |  | 		.filter(function([k, o]){ | 
					
						
							| 
									
										
										
										
											2020-05-30 00:39:36 +03:00
										 |  |  | 			return k[0] == k[0].toUpperCase()  | 
					
						
							|  |  |  | 				&& o.prototype }) } | 
					
						
							| 
									
										
										
										
											2020-05-24 02:41:30 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-30 00:39:36 +03:00
										 |  |  | // an instance is a thing that starts with a lowercase and has a .constructor
 | 
					
						
							| 
									
										
										
										
											2020-05-24 02:41:30 +03:00
										 |  |  | var instances = function(obj){ | 
					
						
							|  |  |  | 	return Object.entries(obj) | 
					
						
							|  |  |  | 		.filter(function([k, o]){ | 
					
						
							| 
									
										
										
										
											2020-05-30 00:39:36 +03:00
										 |  |  | 			return k[0] == k[0].toLowerCase()  | 
					
						
							|  |  |  | 				&& o.constructor }) } | 
					
						
							| 
									
										
										
										
											2020-05-24 02:41:30 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-30 00:39:36 +03:00
										 |  |  | var makeAssert = function(pre, stats){ | 
					
						
							| 
									
										
										
										
											2020-05-24 23:59:01 +03:00
										 |  |  | 	return function(e, msg, ...args){ | 
					
						
							|  |  |  | 		stats | 
					
						
							|  |  |  | 			&& (stats.assertions += 1) | 
					
						
							|  |  |  | 			&& !e | 
					
						
							|  |  |  | 				&& (stats.failures += 1) | 
					
						
							|  |  |  | 		module.VERBOSE | 
					
						
							|  |  |  | 			&& console.log(pre +': '+ msg, ...args) | 
					
						
							|  |  |  | 		console.assert(e, pre +': '+ msg, ...args) | 
					
						
							|  |  |  | 		return e } } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-24 02:41:30 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-30 00:20:07 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-24 02:41:30 +03:00
										 |  |  | //---------------------------------------------------------------------
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var setups = { | 
					
						
							| 
									
										
										
										
											2020-05-30 00:20:07 +03:00
										 |  |  | 	// basic constructor and inheritance...
 | 
					
						
							| 
									
										
										
										
											2020-05-24 23:59:01 +03:00
										 |  |  | 	basic: function(assert){ | 
					
						
							| 
									
										
										
										
											2020-05-24 02:41:30 +03:00
										 |  |  | 		var X, Y, A, B, C | 
					
						
							|  |  |  | 		return { | 
					
						
							| 
									
										
										
										
											2020-05-24 23:59:01 +03:00
										 |  |  | 			X: X = assert(object.Constructor('A'), `Constructor`), | 
					
						
							|  |  |  | 			Y: Y = assert(object.C('Y', { }), ` C`), | 
					
						
							| 
									
										
										
										
											2020-05-24 02:41:30 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-24 23:59:01 +03:00
										 |  |  | 			A: A = assert(object.C('A', Y, { }), `inherit (gen1)`), | 
					
						
							|  |  |  | 			B: B = assert(object.C('B', A, { }), `inherit (gen2)`), | 
					
						
							|  |  |  | 			C: C = assert(object.C('C', B, { }), `inherit (gen3)`), | 
					
						
							| 
									
										
										
										
											2020-05-24 02:41:30 +03:00
										 |  |  | 		} }, | 
					
						
							| 
									
										
										
										
											2020-05-30 00:20:07 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// initialization...
 | 
					
						
							| 
									
										
										
										
											2020-05-24 23:59:01 +03:00
										 |  |  | 	init: function(assert){ | 
					
						
							| 
									
										
										
										
											2020-05-24 02:41:30 +03:00
										 |  |  | 		return { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		} }, | 
					
						
							| 
									
										
										
										
											2020-05-30 00:20:07 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// callable instances...
 | 
					
						
							| 
									
										
										
										
											2020-05-24 23:59:01 +03:00
										 |  |  | 	call: function(assert){ | 
					
						
							| 
									
										
										
										
											2020-05-30 00:20:07 +03:00
										 |  |  | 		// constructors...
 | 
					
						
							| 
									
										
										
										
											2020-05-24 23:59:01 +03:00
										 |  |  | 		var A, B, C, D, F, G | 
					
						
							| 
									
										
										
										
											2020-05-30 00:20:07 +03:00
										 |  |  | 		var res = { | 
					
						
							| 
									
										
										
										
											2020-05-24 23:59:01 +03:00
										 |  |  | 			A: A = assert(object.C('A',  | 
					
						
							|  |  |  | 				function(){ | 
					
						
							| 
									
										
										
										
											2020-05-25 00:53:56 +03:00
										 |  |  | 					return 'A' | 
					
						
							| 
									
										
										
										
											2020-05-24 23:59:01 +03:00
										 |  |  | 				}), 'callable'), | 
					
						
							|  |  |  | 			B: B = assert(object.C('B', { | 
					
						
							|  |  |  | 				__call__: function(){ | 
					
						
							| 
									
										
										
										
											2020-05-25 00:53:56 +03:00
										 |  |  | 					return 'B' | 
					
						
							| 
									
										
										
										
											2020-05-24 23:59:01 +03:00
										 |  |  | 				}, | 
					
						
							|  |  |  | 			}), 'callable'), | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			C: C = assert(object.C('C', A, {}), 'basic inherit'), | 
					
						
							|  |  |  | 			D: D = assert(object.C('D', B, {}), 'basic inherit'), | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			E: E = assert(object.C('E', A, | 
					
						
							|  |  |  | 				function(){ | 
					
						
							| 
									
										
										
										
											2020-05-25 00:53:56 +03:00
										 |  |  | 					assert( | 
					
						
							|  |  |  | 						object.parentCall(E.prototype, '__call__', this, ...arguments) == 'A',  | 
					
						
							|  |  |  | 						'parrent call') | 
					
						
							|  |  |  | 					return 'E' | 
					
						
							| 
									
										
										
										
											2020-05-24 23:59:01 +03:00
										 |  |  | 				}), 'call parent'), | 
					
						
							|  |  |  | 			F: F = assert(object.C('F', B, { | 
					
						
							|  |  |  | 				__call__: function(){ | 
					
						
							| 
									
										
										
										
											2020-05-25 00:53:56 +03:00
										 |  |  | 					assert( | 
					
						
							|  |  |  | 						object.parentCall(F.prototype, '__call__', this, ...arguments) == 'B',  | 
					
						
							|  |  |  | 						'parent call') | 
					
						
							|  |  |  | 					return 'F' | 
					
						
							| 
									
										
										
										
											2020-05-24 23:59:01 +03:00
										 |  |  | 				}, | 
					
						
							|  |  |  | 			}), 'call parent\'s .__call__'), | 
					
						
							| 
									
										
										
										
											2020-05-30 00:20:07 +03:00
										 |  |  | 		}  | 
					
						
							|  |  |  | 		// create instances...
 | 
					
						
							|  |  |  | 		var objs = tests.instance(assert, res) | 
					
						
							|  |  |  | 		// all instances must be callable...
 | 
					
						
							|  |  |  | 		// NOTE: not all instances are going to be instanceof Function...
 | 
					
						
							|  |  |  | 		Object.entries(objs) | 
					
						
							|  |  |  | 			.forEach(function([k, o]){ | 
					
						
							|  |  |  | 				assert(typeof(o) == 'function', 'instance is callable', k) }) | 
					
						
							|  |  |  | 		return Object.assign(res, objs) }, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// inherit from native constructors...
 | 
					
						
							| 
									
										
										
										
											2020-05-24 23:59:01 +03:00
										 |  |  | 	native: function(assert){ | 
					
						
							| 
									
										
										
										
											2020-05-30 00:20:07 +03:00
										 |  |  | 		return [ | 
					
						
							|  |  |  | 			Object, | 
					
						
							|  |  |  | 			Array, | 
					
						
							|  |  |  | 			Number, | 
					
						
							|  |  |  | 			Map, | 
					
						
							|  |  |  | 			Set, | 
					
						
							|  |  |  | 		].reduce(function(res, type){ | 
					
						
							|  |  |  | 			var n = type.name | 
					
						
							|  |  |  | 			// direct inherit...
 | 
					
						
							|  |  |  | 			var O = res[n] =  | 
					
						
							|  |  |  | 				assert(object.C(n, type, {}), 'inherit from '+n) | 
					
						
							|  |  |  | 			return res | 
					
						
							|  |  |  | 		}, {}) }, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// mixins...
 | 
					
						
							| 
									
										
										
										
											2020-05-24 23:59:01 +03:00
										 |  |  | 	mixin: function(assert){ | 
					
						
							| 
									
										
										
										
											2020-05-24 02:41:30 +03:00
										 |  |  | 		return { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		} }, | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var modifiers = { | 
					
						
							| 
									
										
										
										
											2020-05-24 23:59:01 +03:00
										 |  |  | 	// default...
 | 
					
						
							|  |  |  | 	'as-is': function(assert, setup){ | 
					
						
							| 
									
										
										
										
											2020-05-30 00:20:07 +03:00
										 |  |  | 		return setup }, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// make gen2-3 constructors...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// NOTE: there is almost no need to test below gen3...
 | 
					
						
							|  |  |  | 	gen2: function(assert, setup, gen){ | 
					
						
							|  |  |  | 		gen = gen || 2 | 
					
						
							|  |  |  | 		return constructors(setup) | 
					
						
							|  |  |  | 			.reduce(function(res, [n, O]){ | 
					
						
							|  |  |  | 				res[n+'g'+gen] = object.C(n+'g'+gen, O, {}) | 
					
						
							|  |  |  | 				return res }, {}) }, | 
					
						
							|  |  |  | 	gen3: function(assert, setup){ | 
					
						
							|  |  |  | 		return this.gen2(assert, this.gen2(assert, setup), '3') } | 
					
						
							| 
									
										
										
										
											2020-05-24 23:59:01 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// XXX
 | 
					
						
							| 
									
										
										
										
											2020-05-24 02:41:30 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var tests = { | 
					
						
							| 
									
										
										
										
											2020-05-30 00:20:07 +03:00
										 |  |  | 	// instance creation...
 | 
					
						
							| 
									
										
										
										
											2020-05-24 23:59:01 +03:00
										 |  |  | 	instance: function(assert, setup, mode){ | 
					
						
							| 
									
										
										
										
											2020-05-28 14:20:47 +03:00
										 |  |  | 			return constructors(setup)  | 
					
						
							|  |  |  | 				.reduce(function(res, [k, O]){ | 
					
						
							|  |  |  | 					var o = res[k.toLowerCase()] =  | 
					
						
							|  |  |  | 						mode == 'no_new' ? | 
					
						
							|  |  |  | 							assert(O(), `new:`, k) | 
					
						
							|  |  |  | 						: mode == 'raw' ? | 
					
						
							|  |  |  | 							assert(O.__rawinstance__(), `.__rawinstance__()`, k)	 | 
					
						
							|  |  |  | 						: assert(new O(), `new:`, k) | 
					
						
							|  |  |  | 					assert(o instanceof O, `instanceof:`, k) | 
					
						
							|  |  |  | 					O.__proto__ instanceof Function | 
					
						
							|  |  |  | 						&& assert(o instanceof O.__proto__, `instanceof-nested:`, k) | 
					
						
							|  |  |  | 					assert(o.constructor === O, `.constructor:`, k) | 
					
						
							|  |  |  | 					assert(o.__proto__ === O.prototype, `.__proto__:`, k) | 
					
						
							|  |  |  | 					return res }, {}) }, | 
					
						
							| 
									
										
										
										
											2020-05-24 23:59:01 +03:00
										 |  |  | 	instance_no_new: function(assert, setup){ | 
					
						
							|  |  |  | 		return this.instance(assert, setup, 'no_new') }, | 
					
						
							|  |  |  | 	instance_raw: function(assert, setup){ | 
					
						
							|  |  |  | 		return this.instance(assert, setup, 'raw') }, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-30 00:20:07 +03:00
										 |  |  | 	// XXX
 | 
					
						
							| 
									
										
										
										
											2020-05-24 23:59:01 +03:00
										 |  |  | 	attributes: function(assert, setup){ | 
					
						
							|  |  |  | 		return {} | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// XXX
 | 
					
						
							|  |  |  | 	methods: function(assert, setup){ | 
					
						
							|  |  |  | 		constructors(setup) | 
					
						
							|  |  |  | 			.forEach(function([k, O]){ | 
					
						
							|  |  |  | 				Object.keys(O).forEach(function(m){ | 
					
						
							|  |  |  | 					typeof(O[m]) == 'function' | 
					
						
							|  |  |  | 						&& O[m]() }) | 
					
						
							|  |  |  | 			}) | 
					
						
							|  |  |  | 		return {} | 
					
						
							|  |  |  | 	}, | 
					
						
							| 
									
										
										
										
											2020-05-25 00:53:56 +03:00
										 |  |  | 	callables: function(assert, setup){ | 
					
						
							|  |  |  | 		return instances(setup) | 
					
						
							|  |  |  | 			.map(function([k, o]){ | 
					
						
							| 
									
										
										
										
											2020-05-28 14:20:47 +03:00
										 |  |  | 				// NOTE: not all callables are instances of Function...
 | 
					
						
							| 
									
										
										
										
											2020-05-30 00:24:03 +03:00
										 |  |  | 				//assert(typeof(o) == 'function' 
 | 
					
						
							| 
									
										
										
										
											2020-05-30 00:35:06 +03:00
										 |  |  | 				//	&& o instanceof Function, 'instanceof Function', k)
 | 
					
						
							| 
									
										
										
										
											2020-05-25 00:53:56 +03:00
										 |  |  | 				return typeof(o) == 'function' | 
					
						
							|  |  |  | 					&& assert(o(), 'call', k) }) }, | 
					
						
							| 
									
										
										
										
											2020-05-24 02:41:30 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // specific independent cases...
 | 
					
						
							|  |  |  | // XXX not sure about these...
 | 
					
						
							|  |  |  | var cases = { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-24 23:59:01 +03:00
										 |  |  | //---------------------------------------------------------------------
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // XXX need to have two modes:
 | 
					
						
							|  |  |  | // 		- clean
 | 
					
						
							|  |  |  | // 		- reuse test results again...
 | 
					
						
							| 
									
										
										
										
											2020-05-24 02:41:30 +03:00
										 |  |  | var runner = function(){ | 
					
						
							| 
									
										
										
										
											2020-05-24 23:59:01 +03:00
										 |  |  | 	var stats = { | 
					
						
							|  |  |  | 		tests: 0, | 
					
						
							|  |  |  | 		assertions: 0, | 
					
						
							|  |  |  | 		failures: 0, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-24 02:41:30 +03:00
										 |  |  | 	// tests...
 | 
					
						
							|  |  |  | 	Object.keys(tests) | 
					
						
							|  |  |  | 		.forEach(function(t){ | 
					
						
							|  |  |  | 			// modifiers...
 | 
					
						
							|  |  |  | 			Object.keys(modifiers) | 
					
						
							|  |  |  | 				.forEach(function(m){ | 
					
						
							|  |  |  | 					// setups...
 | 
					
						
							|  |  |  | 					Object.keys(setups) | 
					
						
							|  |  |  | 						.forEach(function(s){ | 
					
						
							| 
									
										
										
										
											2020-05-28 14:20:47 +03:00
										 |  |  | 							if(typeof(setups[s]) != 'function'){ | 
					
						
							|  |  |  | 								return } | 
					
						
							| 
									
										
										
										
											2020-05-24 02:41:30 +03:00
										 |  |  | 							// run the test...
 | 
					
						
							| 
									
										
										
										
											2020-05-24 23:59:01 +03:00
										 |  |  | 							stats.tests += 1 | 
					
						
							| 
									
										
										
										
											2020-05-30 00:39:36 +03:00
										 |  |  | 							var _assert = makeAssert(`test:${t}.${s}.${m}`, stats) | 
					
						
							| 
									
										
										
										
											2020-05-24 23:59:01 +03:00
										 |  |  | 							tests[t](_assert,  | 
					
						
							|  |  |  | 								modifiers[m](_assert,  | 
					
						
							|  |  |  | 									setups[s](_assert))) }) }) })  | 
					
						
							| 
									
										
										
										
											2020-05-24 02:41:30 +03:00
										 |  |  | 	// cases...
 | 
					
						
							|  |  |  | 	Object.keys(cases) | 
					
						
							|  |  |  | 		.forEach(function(c){ | 
					
						
							| 
									
										
										
										
											2020-05-24 23:59:01 +03:00
										 |  |  | 			stats.tests += 1 | 
					
						
							| 
									
										
										
										
											2020-05-30 00:39:36 +03:00
										 |  |  | 			cases[c]( makeAssert(`case:${c}:`, stats) ) })  | 
					
						
							| 
									
										
										
										
											2020-05-24 23:59:01 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// stats...
 | 
					
						
							|  |  |  | 	console.log('Tests:', stats.tests,  | 
					
						
							|  |  |  | 		'Assertions:', stats.assertions,  | 
					
						
							| 
									
										
										
										
											2020-05-28 14:20:47 +03:00
										 |  |  | 		'Failures:', stats.failures)  | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return stats } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | //---------------------------------------------------------------------
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var stats = runner() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // report error status to the OS...
 | 
					
						
							|  |  |  | process | 
					
						
							|  |  |  | 	&& process.exit(stats.failures) | 
					
						
							| 
									
										
										
										
											2020-05-24 02:41:30 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /********************************************************************** | 
					
						
							|  |  |  | * vim:set ts=4 sw=4 :                               */ return module }) |