| 
									
										
										
										
											2020-06-03 02:48:38 +03:00
										 |  |  | #!/usr/bin/env node
 | 
					
						
							| 
									
										
										
										
											2020-05-24 02:41:30 +03:00
										 |  |  | /********************************************************************** | 
					
						
							|  |  |  | *  | 
					
						
							| 
									
										
										
										
											2020-08-17 15:56:08 +03:00
										 |  |  | * TODO: | 
					
						
							|  |  |  | * 	- test:  | 
					
						
							| 
									
										
										
										
											2020-08-17 22:33:07 +03:00
										 |  |  | * 		- ASAP: method calls from methods from different contexts: | 
					
						
							|  |  |  | * 			- constructor | 
					
						
							|  |  |  | * 			- instance | 
					
						
							|  |  |  | * 			- sub-instance | 
					
						
							|  |  |  | * 			- callable | 
					
						
							|  |  |  | * 			- .call(..) and friends | 
					
						
							| 
									
										
										
										
											2020-08-17 15:56:08 +03:00
										 |  |  | * 		- object.mixout(..) | 
					
						
							|  |  |  | * 		- object.normalizeTextIndent(..) | 
					
						
							|  |  |  | * 		- object.doc`...` | 
					
						
							|  |  |  | * 		- object.text`...` | 
					
						
							|  |  |  | * 		- callback STOP in object.mixins(..) | 
					
						
							|  |  |  | * 		- props arg in object.values(..) | 
					
						
							|  |  |  | * 		- RawInstance(..).toString() | 
					
						
							|  |  |  | * | 
					
						
							| 
									
										
										
										
											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...
 | 
					
						
							|  |  |  | /*********************************************************************/ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-04 00:11:45 +03:00
										 |  |  | var colors = require('colors') | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-15 18:59:21 +03:00
										 |  |  | var test = require('ig-test') | 
					
						
							| 
									
										
										
										
											2020-05-24 23:59:01 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-15 18:59:21 +03:00
										 |  |  | var object = require('./object') | 
					
						
							| 
									
										
										
										
											2020-05-24 23:59:01 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-24 02:41:30 +03:00
										 |  |  | //---------------------------------------------------------------------
 | 
					
						
							|  |  |  | // helpers...
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-03 21:09:19 +03:00
										 |  |  | // compare two arrays by items...
 | 
					
						
							|  |  |  | var arrayCmp = function(a, b){ | 
					
						
							|  |  |  | 	var ka = Object.keys(a) | 
					
						
							|  |  |  | 	var kb = Object.keys(a) | 
					
						
							|  |  |  | 	return a === b | 
					
						
							| 
									
										
										
										
											2020-06-07 21:28:04 +03:00
										 |  |  | 		|| (a.length == b.length | 
					
						
							|  |  |  | 			&& ka | 
					
						
							|  |  |  | 				// keep only non matching stuff...
 | 
					
						
							|  |  |  | 				.filter(function(k){ | 
					
						
							|  |  |  | 					return a[k] !== b[k]  | 
					
						
							|  |  |  | 						&& a[k] != a[k] }) | 
					
						
							|  |  |  | 				.length == 0) } | 
					
						
							| 
									
										
										
										
											2020-06-03 21:09:19 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-04 00:20:45 +03:00
										 |  |  | // a constructor is a thing that starts with a capital and has a .prototype
 | 
					
						
							|  |  |  | var constructors = function(obj){ | 
					
						
							|  |  |  | 	return Object.entries(obj) | 
					
						
							|  |  |  | 		.filter(function([k, o]){ | 
					
						
							| 
									
										
										
										
											2020-06-08 04:16:03 +03:00
										 |  |  | 			return !k.startsWith('_') | 
					
						
							|  |  |  | 				&& k[0] == k[0].toUpperCase()  | 
					
						
							| 
									
										
										
										
											2020-06-04 00:20:45 +03:00
										 |  |  | 				&& o.prototype }) } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // an instance is a thing that starts with a lowercase and has a .constructor
 | 
					
						
							|  |  |  | var instances = function(obj){ | 
					
						
							|  |  |  | 	return Object.entries(obj) | 
					
						
							|  |  |  | 		.filter(function([k, o]){ | 
					
						
							| 
									
										
										
										
											2020-06-08 04:16:03 +03:00
										 |  |  | 			return !k.startsWith('_') | 
					
						
							|  |  |  | 				&& k[0] == k[0].toLowerCase()  | 
					
						
							| 
									
										
										
										
											2020-06-04 00:20:45 +03:00
										 |  |  | 				&& o.constructor }) } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-24 02:41:30 +03:00
										 |  |  | //---------------------------------------------------------------------
 | 
					
						
							| 
									
										
										
										
											2020-06-04 00:20:45 +03:00
										 |  |  | // Tests...
 | 
					
						
							| 
									
										
										
										
											2020-05-24 02:41:30 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-15 18:59:21 +03:00
										 |  |  | var setups = test.Setups({ | 
					
						
							| 
									
										
										
										
											2020-05-30 00:20:07 +03:00
										 |  |  | 	// basic constructor and inheritance...
 | 
					
						
							| 
									
										
										
										
											2020-06-08 04:54:40 +03:00
										 |  |  | 	//
 | 
					
						
							|  |  |  | 	//	X
 | 
					
						
							| 
									
										
										
										
											2020-06-16 01:28:28 +03:00
										 |  |  | 	//	Y <- A <- B <- C <- D <- E	
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// This will test:
 | 
					
						
							|  |  |  | 	// 	- object creation
 | 
					
						
							|  |  |  | 	// 	- basic inheritance
 | 
					
						
							|  |  |  | 	// 		- general usecase
 | 
					
						
							|  |  |  | 	// 		- .__extends__
 | 
					
						
							|  |  |  | 	// 	- method overloading
 | 
					
						
							|  |  |  | 	// 		- .parent(..)
 | 
					
						
							|  |  |  | 	// 		- .parentCall(..)
 | 
					
						
							|  |  |  | 	// 		- .parentProperty(..)
 | 
					
						
							|  |  |  | 	// 	- constructor methods (XXX not done...)
 | 
					
						
							| 
									
										
										
										
											2020-06-08 04:54:40 +03:00
										 |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2020-05-24 23:59:01 +03:00
										 |  |  | 	basic: function(assert){ | 
					
						
							| 
									
										
										
										
											2020-06-16 01:28:28 +03:00
										 |  |  | 		var X, Y, A, B, C, D, E | 
					
						
							| 
									
										
										
										
											2020-05-24 02:41:30 +03:00
										 |  |  | 		return { | 
					
						
							| 
									
										
										
										
											2020-06-08 04:54:40 +03:00
										 |  |  | 			X: X = assert(object.Constructor('X'), `.Constructor(..)`), | 
					
						
							|  |  |  | 			Y: Y = assert(object.C('Y', {  | 
					
						
							|  |  |  | 				method: function(){ | 
					
						
							|  |  |  | 					var x | 
					
						
							|  |  |  | 					assert( | 
					
						
							|  |  |  | 						(x = object.parentCall(Y.prototype.method, this, ...arguments)) === undefined,  | 
					
						
							|  |  |  | 						'y.method(..): expected:', undefined, 'got:', x) | 
					
						
							|  |  |  | 					return 'Y' | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 			}), `.C(..)`), | 
					
						
							| 
									
										
										
										
											2020-05-24 02:41:30 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-08 04:54:40 +03:00
										 |  |  | 			A: A = assert(object.C('A', Y, {  | 
					
						
							| 
									
										
										
										
											2020-06-16 01:28:28 +03:00
										 |  |  | 				get prop(){ | 
					
						
							|  |  |  | 					return 'A.prop' }, | 
					
						
							| 
									
										
										
										
											2020-06-08 04:54:40 +03:00
										 |  |  | 				method: function(){ | 
					
						
							|  |  |  | 					var x | 
					
						
							|  |  |  | 					assert( | 
					
						
							|  |  |  | 						(x = object.parentCall(A.prototype.method, this, ...arguments)) == 'Y',  | 
					
						
							|  |  |  | 						'a.method(..): expected:', 'Y', 'got:', x) | 
					
						
							|  |  |  | 					return 'A' | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 			}), `inherit (gen1)`), | 
					
						
							|  |  |  | 			B: B = assert(object.C('B', A, {  | 
					
						
							|  |  |  | 				// XXX constructor methods...
 | 
					
						
							| 
									
										
										
										
											2020-08-09 14:05:30 +03:00
										 |  |  | 				testRelations: function(){ | 
					
						
							|  |  |  | 					assert(object.parentOf(A, this),  | 
					
						
							|  |  |  | 						'parentOf(A, B): expected to be true') | 
					
						
							|  |  |  | 					assert(object.childOf(this, A),  | 
					
						
							|  |  |  | 						'childOf(B, A): expected to be true') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					assert(!object.parentOf(X, this),  | 
					
						
							|  |  |  | 						'parentOf(X, B): expected to be false') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					assert(object.parentOf(A, E),  | 
					
						
							|  |  |  | 						'parentOf(A, E): expected to be true') | 
					
						
							|  |  |  | 					assert(object.childOf(E, A),  | 
					
						
							|  |  |  | 						'childOf(E, A): expected to be true') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					assert(object.related(A, E) && object.related(E, A),  | 
					
						
							|  |  |  | 						'related(A, E) and related(E, A): expected to be true') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					assert(!object.related(X, E)  | 
					
						
							|  |  |  | 						&& !object.related(E, X),  | 
					
						
							|  |  |  | 						'related(X, E) and related(E, X): expected to be flase') | 
					
						
							|  |  |  | 				}, | 
					
						
							| 
									
										
										
										
											2020-06-08 04:54:40 +03:00
										 |  |  | 			}, {  | 
					
						
							| 
									
										
										
										
											2020-06-16 01:28:28 +03:00
										 |  |  | 				get prop(){ | 
					
						
							|  |  |  | 					return 'B.prop' }, | 
					
						
							| 
									
										
										
										
											2020-06-08 04:54:40 +03:00
										 |  |  | 				// XXX methods...
 | 
					
						
							|  |  |  | 			}), `inherit (gen2) with constructor mixin`), | 
					
						
							|  |  |  | 			C: C = assert(object.C('C', B, {  | 
					
						
							|  |  |  | 				method: function(){ | 
					
						
							|  |  |  | 					var x | 
					
						
							|  |  |  | 					assert( | 
					
						
							|  |  |  | 						(x = object.parentCall(C.prototype.method, this, ...arguments)) == 'A',  | 
					
						
							|  |  |  | 						'c.method(..): expected:', 'A', 'got:', x) | 
					
						
							| 
									
										
										
										
											2020-06-16 01:28:28 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 					assert(this.prop == 'B.prop',  | 
					
						
							|  |  |  | 						'get property value') | 
					
						
							|  |  |  | 					// NOTE: these get "next visible" not "outside current object",
 | 
					
						
							|  |  |  | 					// 		this is intentional, the "outside" value is simply 
 | 
					
						
							|  |  |  | 					// 		accessible via:
 | 
					
						
							|  |  |  | 					// 			C.prototype.prop
 | 
					
						
							|  |  |  | 					assert(object.parent(C.prototype, 'prop') == 'A.prop',  | 
					
						
							|  |  |  | 						'get parent property value') | 
					
						
							|  |  |  | 					assert(object.parentProperty(C.prototype, 'prop').get() == 'A.prop',  | 
					
						
							|  |  |  | 						'get parent property') | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-29 01:14:21 +03:00
										 |  |  | 					assert(object.parentProperty(C.prototype, 'does-not-exist') === undefined,  | 
					
						
							|  |  |  | 						'get non-existent property') | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-08 04:54:40 +03:00
										 |  |  | 					return 'C' | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 			}), `inherit (gen3)`), | 
					
						
							| 
									
										
										
										
											2020-06-16 01:28:28 +03:00
										 |  |  | 			D: D = assert(object.C('D', {}, { | 
					
						
							|  |  |  | 				__extends__: C, | 
					
						
							|  |  |  | 				method: function(){ | 
					
						
							|  |  |  | 					var x | 
					
						
							|  |  |  | 					assert( | 
					
						
							|  |  |  | 						(x = object.parentCall(D.prototype.method, this, ...arguments)) == 'C',  | 
					
						
							|  |  |  | 						'c.method(..): expected:', 'C', 'got:', x) | 
					
						
							|  |  |  | 					return 'D' | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 			}), '.__extends__ test'), | 
					
						
							|  |  |  | 			E: E = assert(object.C('E', { | 
					
						
							|  |  |  | 				__extends__: C, | 
					
						
							|  |  |  | 			}, { | 
					
						
							|  |  |  | 				method: function(){ | 
					
						
							|  |  |  | 					var x | 
					
						
							|  |  |  | 					assert( | 
					
						
							|  |  |  | 						(x = object.parentCall(D.prototype.method, this, ...arguments)) === undefined,  | 
					
						
							|  |  |  | 						'c.method(..): expected:', undefined, 'got:', x) | 
					
						
							|  |  |  | 					return 'E' | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 			}), '.__extends__ test'), | 
					
						
							| 
									
										
										
										
											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-06-01 02:49:00 +03:00
										 |  |  | 		var A, B, C | 
					
						
							| 
									
										
										
										
											2020-05-24 02:41:30 +03:00
										 |  |  | 		return { | 
					
						
							| 
									
										
										
										
											2020-06-01 02:49:00 +03:00
										 |  |  | 			// init...
 | 
					
						
							|  |  |  | 			A: A = assert(object.C('A', { | 
					
						
							|  |  |  | 				msg: '.__init__()', | 
					
						
							|  |  |  | 				__init__: function(){ | 
					
						
							|  |  |  | 					this.init_has_run = true }, | 
					
						
							|  |  |  | 				test_init: function(){ | 
					
						
							|  |  |  | 					this.__created_raw ? | 
					
						
							|  |  |  | 						assert(!this.init_has_run, this.msg+' did not run') | 
					
						
							|  |  |  | 						: assert(this.init_has_run, this.msg+' run') }, | 
					
						
							|  |  |  | 			}), 'basic .__init__(..)'), | 
					
						
							|  |  |  | 			// new...
 | 
					
						
							|  |  |  | 			B: B = assert(object.C('B', { | 
					
						
							|  |  |  | 				__new__: function(){ | 
					
						
							|  |  |  | 					var o = {} | 
					
						
							|  |  |  | 					o.new_has_run = true | 
					
						
							|  |  |  | 					return o | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 				test_new: function(){ | 
					
						
							|  |  |  | 					assert(this.new_has_run, '.__new__() run') }, | 
					
						
							|  |  |  | 			}), 'basic .__new__(..)'), | 
					
						
							|  |  |  | 			// new + init...
 | 
					
						
							|  |  |  | 			C: C = assert(object.C('C', B, {  | 
					
						
							|  |  |  | 				msg: '.__init__() after .__new__()', | 
					
						
							|  |  |  | 				__init__: function(){ | 
					
						
							|  |  |  | 					this.init_has_run = true }, | 
					
						
							|  |  |  | 				test_init: A.prototype.test_init, | 
					
						
							|  |  |  | 			}), `inherit .__new__()`), | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// XXX
 | 
					
						
							| 
									
										
										
										
											2020-05-24 02:41:30 +03:00
										 |  |  | 		} }, | 
					
						
							| 
									
										
										
										
											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', { | 
					
						
							| 
									
										
										
										
											2020-06-01 02:49:00 +03:00
										 |  |  | 				__non_function: true, | 
					
						
							| 
									
										
										
										
											2020-05-24 23:59:01 +03:00
										 |  |  | 				__call__: function(){ | 
					
						
							| 
									
										
										
										
											2020-06-08 04:16:03 +03:00
										 |  |  | 					assert( | 
					
						
							|  |  |  | 						object.parentCall(B.prototype, '__call__', this, ...arguments) === undefined,  | 
					
						
							|  |  |  | 							'call non-existent parent method', 'B') | 
					
						
							| 
									
										
										
										
											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) }) | 
					
						
							| 
									
										
										
										
											2020-06-07 21:28:04 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-30 00:20:07 +03:00
										 |  |  | 		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 | 
					
						
							|  |  |  | 		}, {}) }, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-03 21:09:19 +03:00
										 |  |  | 	// compatibility: native constructors...
 | 
					
						
							|  |  |  | 	js_constructors: function(assert){ | 
					
						
							|  |  |  | 		return { | 
					
						
							|  |  |  | 			Object, | 
					
						
							|  |  |  | 			Array, | 
					
						
							|  |  |  | 			Number, | 
					
						
							|  |  |  | 			Map, | 
					
						
							|  |  |  | 			Set, | 
					
						
							|  |  |  | 		}}, | 
					
						
							| 
									
										
										
										
											2020-06-04 00:11:45 +03:00
										 |  |  | 	// compatibility: prototype tree...
 | 
					
						
							| 
									
										
										
										
											2020-06-03 21:09:19 +03:00
										 |  |  | 	js_prototype: function(assert){ | 
					
						
							|  |  |  | 		var a, b, c, d | 
					
						
							|  |  |  | 		return { | 
					
						
							|  |  |  | 			a: a = { | 
					
						
							|  |  |  | 				x: 'a', | 
					
						
							|  |  |  | 				method: function(){ | 
					
						
							|  |  |  | 					return 'a' }, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			b: b = { | 
					
						
							|  |  |  | 				__proto__: a, | 
					
						
							|  |  |  | 				x: 'b', | 
					
						
							|  |  |  | 			},  | 
					
						
							|  |  |  | 			c: c = { | 
					
						
							|  |  |  | 				__proto__: b, | 
					
						
							|  |  |  | 				x: 'c', | 
					
						
							|  |  |  | 				method: function(){ | 
					
						
							| 
									
										
										
										
											2020-06-08 19:23:41 +03:00
										 |  |  | 					var x, y | 
					
						
							| 
									
										
										
										
											2020-06-16 01:28:28 +03:00
										 |  |  | 					assert.array( | 
					
						
							|  |  |  | 						object.values(c, 'x'),  | 
					
						
							|  |  |  | 						['c', 'a', 'b'],  | 
					
						
							|  |  |  | 							'reach all values of attr') | 
					
						
							|  |  |  | 					assert.array( | 
					
						
							|  |  |  | 						object.values(c, 'x', function(v, o){ | 
					
						
							| 
									
										
										
										
											2020-06-07 21:28:04 +03:00
										 |  |  | 							return v.toUpperCase() }),  | 
					
						
							| 
									
										
										
										
											2020-06-16 01:28:28 +03:00
										 |  |  | 						['C', 'A', 'B'],  | 
					
						
							|  |  |  | 							'reach all values of attr') | 
					
						
							|  |  |  | 					assert.array( | 
					
						
							|  |  |  | 						object.sources(c, 'method'), | 
					
						
							| 
									
										
										
										
											2020-06-08 19:23:41 +03:00
										 |  |  | 						// NOTE: not passing an explicit list as we need 
 | 
					
						
							|  |  |  | 						// 		to account for mixins...
 | 
					
						
							| 
									
										
										
										
											2020-06-16 01:28:28 +03:00
										 |  |  | 						object.sources(c) | 
					
						
							| 
									
										
										
										
											2020-06-08 19:23:41 +03:00
										 |  |  | 								.filter(function(s){  | 
					
						
							| 
									
										
										
										
											2020-06-16 01:28:28 +03:00
										 |  |  | 									return s.hasOwnProperty('method') }),  | 
					
						
							|  |  |  | 							'reach all values of method') | 
					
						
							| 
									
										
										
										
											2020-06-07 21:28:04 +03:00
										 |  |  | 					assert( | 
					
						
							| 
									
										
										
										
											2020-06-08 19:23:41 +03:00
										 |  |  | 						(x = object.parent(c, 'x')) == 'b',  | 
					
						
							|  |  |  | 							'reach parent attr: expected:', 'b', 'got:'.bold.yellow, x) | 
					
						
							| 
									
										
										
										
											2020-06-07 21:28:04 +03:00
										 |  |  | 					assert( | 
					
						
							| 
									
										
										
										
											2020-06-08 19:23:41 +03:00
										 |  |  | 						(x = object.parentCall(c.method, this)) == (y = a.method()),  | 
					
						
							|  |  |  | 							'reach parent method: expected:', y, 'got:'.bold.yellow, x) | 
					
						
							| 
									
										
										
										
											2020-06-03 21:09:19 +03:00
										 |  |  | 					return 'c' }, | 
					
						
							|  |  |  | 			},  | 
					
						
							|  |  |  | 			d: d = { | 
					
						
							|  |  |  | 				__proto__: c, | 
					
						
							|  |  |  | 				method: function(){ | 
					
						
							|  |  |  | 					assert(object.parentCall(d.method, this) == 'c', 'reach parent method', 'd') | 
					
						
							|  |  |  | 					return 'd' }, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 		}}, | 
					
						
							| 
									
										
										
										
											2020-06-04 00:11:45 +03:00
										 |  |  | 	// compatibility: class/instance...
 | 
					
						
							| 
									
										
										
										
											2020-06-03 21:09:19 +03:00
										 |  |  | 	js_class: function(assert){ | 
					
						
							|  |  |  | 		var X, Y, Z | 
					
						
							|  |  |  | 		return { | 
					
						
							|  |  |  | 			X: X = class { | 
					
						
							|  |  |  | 				x = 'x' | 
					
						
							|  |  |  | 				method(){ | 
					
						
							|  |  |  | 					return 'x' } | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			Y: Y = class extends X { | 
					
						
							|  |  |  | 				x = 'y' | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			Z: Z = class extends Y { | 
					
						
							|  |  |  | 				x = 'z' | 
					
						
							|  |  |  | 				method(){ | 
					
						
							| 
									
										
										
										
											2020-06-07 21:28:04 +03:00
										 |  |  | 					// XXX this is almost the same as for js_prototype...
 | 
					
						
							| 
									
										
										
										
											2020-06-16 01:28:28 +03:00
										 |  |  | 					assert.array( | 
					
						
							| 
									
										
										
										
											2020-06-07 21:28:04 +03:00
										 |  |  | 						object.values(c, 'x'),  | 
					
						
							| 
									
										
										
										
											2020-06-16 01:28:28 +03:00
										 |  |  | 						['z', 'y', 'x'],  | 
					
						
							| 
									
										
										
										
											2020-06-03 21:09:19 +03:00
										 |  |  | 							'reach all values of attr (class)') | 
					
						
							| 
									
										
										
										
											2020-06-16 01:28:28 +03:00
										 |  |  | 					assert.array( | 
					
						
							| 
									
										
										
										
											2020-06-07 21:28:04 +03:00
										 |  |  | 						object.values(c, 'x', function(v, o){ | 
					
						
							|  |  |  | 							return v.toUpperCase() }),  | 
					
						
							| 
									
										
										
										
											2020-06-16 01:28:28 +03:00
										 |  |  | 						['C', 'A', 'B'],  | 
					
						
							| 
									
										
										
										
											2020-06-07 21:28:04 +03:00
										 |  |  | 							'reach all values of attr (class)') | 
					
						
							| 
									
										
										
										
											2020-06-16 01:28:28 +03:00
										 |  |  | 					assert.array( | 
					
						
							| 
									
										
										
										
											2020-06-03 21:09:19 +03:00
										 |  |  | 						object.sources(c, 'method'),  | 
					
						
							| 
									
										
										
										
											2020-06-16 01:28:28 +03:00
										 |  |  | 						[Z.prototype, X.prototype],  | 
					
						
							| 
									
										
										
										
											2020-06-03 21:09:19 +03:00
										 |  |  | 							'reach all values of method (class)') | 
					
						
							|  |  |  | 					assert( | 
					
						
							|  |  |  | 						object.parent(c, 'x') == super.x,  | 
					
						
							|  |  |  | 							'reach super attr (class)') | 
					
						
							|  |  |  | 					assert( | 
					
						
							|  |  |  | 						object.parentCall(c.method, this) == super.method(),  | 
					
						
							|  |  |  | 							'reach super method (class)') | 
					
						
							|  |  |  | 					return 'c' } | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 		}}, | 
					
						
							| 
									
										
										
										
											2020-08-15 18:59:21 +03:00
										 |  |  | }) | 
					
						
							| 
									
										
										
										
											2020-05-24 02:41:30 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-01 04:09:40 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-15 18:59:21 +03:00
										 |  |  | var modifiers = test.Modifiers({ | 
					
						
							| 
									
										
										
										
											2020-05-30 00:20:07 +03:00
										 |  |  | 	// 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){ | 
					
						
							| 
									
										
										
										
											2020-06-01 02:49:00 +03:00
										 |  |  | 		return this.gen2(assert, this.gen2(assert, setup), '3') }, | 
					
						
							| 
									
										
										
										
											2020-05-24 23:59:01 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-09 17:41:18 +03:00
										 |  |  | 	// create instance clones via Object.create(..)
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	clones: function(assert, setup){ | 
					
						
							|  |  |  | 		return instances(setup) | 
					
						
							|  |  |  | 			.reduce(function(res, [k, o]){ | 
					
						
							|  |  |  | 				res[k] = Object.create(o)  | 
					
						
							|  |  |  | 				return res }, {}) }, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-01 02:49:00 +03:00
										 |  |  | 	// generate instances...
 | 
					
						
							| 
									
										
										
										
											2020-06-02 03:05:55 +03:00
										 |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2020-06-01 02:49:00 +03:00
										 |  |  | 	// NOTE: these are re-used as tests too...
 | 
					
						
							|  |  |  | 	instance: function(assert, setup, mode){ | 
					
						
							|  |  |  | 		return constructors(setup)  | 
					
						
							|  |  |  | 			.reduce(function(res, [k, O]){ | 
					
						
							| 
									
										
										
										
											2020-06-03 21:09:19 +03:00
										 |  |  | 				// native JS constructors do not support no_new or raw modes...
 | 
					
						
							|  |  |  | 				if((mode == 'raw' || mode == 'no_new') && !O.__rawinstance__){ | 
					
						
							|  |  |  | 					return res } | 
					
						
							| 
									
										
										
										
											2020-06-02 03:05:55 +03:00
										 |  |  | 				// create instance with lowercase name of constructor...
 | 
					
						
							|  |  |  | 				// NOTE: constructor is expected to be capitalized...
 | 
					
						
							| 
									
										
										
										
											2020-06-01 02:49:00 +03:00
										 |  |  | 				var o = res[k.toLowerCase()] =  | 
					
						
							|  |  |  | 					mode == 'no_new' ? | 
					
						
							|  |  |  | 						assert(O(), `new:`, k) | 
					
						
							|  |  |  | 					: mode == 'raw' ? | 
					
						
							|  |  |  | 						assert(O.__rawinstance__(), `.__rawinstance__()`, k)	 | 
					
						
							|  |  |  | 					: assert(new O(), `new:`, k) | 
					
						
							| 
									
										
										
										
											2020-06-08 16:07:54 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-01 02:49:00 +03:00
										 |  |  | 				assert(o instanceof O, `instanceof:`, k) | 
					
						
							| 
									
										
										
										
											2020-06-08 16:07:54 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-01 02:49:00 +03:00
										 |  |  | 				O.__proto__ instanceof Function | 
					
						
							| 
									
										
										
										
											2020-06-08 16:07:54 +03:00
										 |  |  | 					// XXX need to test this for constructor mixins too...
 | 
					
						
							|  |  |  | 					&& !(O.__mixin_constructors && !O.__mixin_flat) | 
					
						
							|  |  |  | 					&& assert(o instanceof o.constructor.__proto__, `instanceof-nested:`, k) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-01 02:49:00 +03:00
										 |  |  | 				assert(o.constructor === O, `.constructor:`, k) | 
					
						
							| 
									
										
										
										
											2020-06-08 16:07:54 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-01 02:49:00 +03:00
										 |  |  | 				assert(o.__proto__ === O.prototype, `.__proto__:`, k) | 
					
						
							| 
									
										
										
										
											2020-06-08 16:07:54 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-01 02:49:00 +03:00
										 |  |  | 				return res }, {}) }, | 
					
						
							|  |  |  | 	instance_no_new: function(assert, setup){ | 
					
						
							|  |  |  | 		return this.instance(assert, setup, 'no_new') }, | 
					
						
							| 
									
										
										
										
											2020-06-02 03:05:55 +03:00
										 |  |  | 	// NOTE: here we mark the raw instances with .__created_raw, this is
 | 
					
						
							|  |  |  | 	// 		done to be able to distinguish them from fully initialized 
 | 
					
						
							|  |  |  | 	// 		instances...
 | 
					
						
							| 
									
										
										
										
											2020-06-01 02:49:00 +03:00
										 |  |  | 	instance_raw: function(assert, setup){ | 
					
						
							|  |  |  | 		var res = this.instance(assert, setup, 'raw')  | 
					
						
							|  |  |  | 		Object.values(res) | 
					
						
							|  |  |  | 			.forEach(function(e){ | 
					
						
							|  |  |  | 				Object.assign( | 
					
						
							|  |  |  | 					e,  | 
					
						
							|  |  |  | 					{__created_raw: true}) }) | 
					
						
							|  |  |  | 		return res }, | 
					
						
							| 
									
										
										
										
											2020-06-01 04:09:40 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-08 04:16:03 +03:00
										 |  |  | 	// mixins...
 | 
					
						
							| 
									
										
										
										
											2020-06-08 20:18:35 +03:00
										 |  |  | 	// NOTE: running this in flat mode will have side-effects -- overwriting
 | 
					
						
							|  |  |  | 	// 		existing attributes and methods...
 | 
					
						
							| 
									
										
										
										
											2020-06-08 19:23:41 +03:00
										 |  |  | 	// XXX might be a good idea to get the method name from the context... how?
 | 
					
						
							| 
									
										
										
										
											2020-06-08 16:07:54 +03:00
										 |  |  | 	mixin_instance: function(assert, setup, flat, filter, get){ | 
					
						
							|  |  |  | 		filter = filter || instances | 
					
						
							|  |  |  | 		var attr = '__mixin_' + filter.name | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		var mixin = setup[attr] = { | 
					
						
							| 
									
										
										
										
											2020-06-09 22:31:19 +03:00
										 |  |  | 			// NOTE: in the real world mixins should have no state, just 
 | 
					
						
							|  |  |  | 			// 		methods...
 | 
					
						
							| 
									
										
										
										
											2020-06-08 19:23:41 +03:00
										 |  |  | 			__mixin: true, | 
					
						
							| 
									
										
										
										
											2020-06-08 16:07:54 +03:00
										 |  |  | 			[attr]: true, | 
					
						
							|  |  |  | 			__mixin_flat: !!flat,  | 
					
						
							| 
									
										
										
										
											2020-06-08 04:16:03 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-08 19:23:41 +03:00
										 |  |  | 			method: function(){ | 
					
						
							|  |  |  | 				var res = object.parent(mixin.method, this) !== undefined ? | 
					
						
							|  |  |  | 					assert( | 
					
						
							|  |  |  | 						object.parentCall(mixin.method, this, ...arguments), | 
					
						
							|  |  |  | 							'mixin method parent call') | 
					
						
							|  |  |  | 					: false  | 
					
						
							|  |  |  | 				return res  | 
					
						
							|  |  |  | 					|| 'mixin' }, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			mixinMethod: function(){ | 
					
						
							|  |  |  | 				return 'mixin' }, | 
					
						
							| 
									
										
										
										
											2020-06-08 04:16:03 +03:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2020-06-08 16:07:54 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		mixin[attr] = mixin | 
					
						
							|  |  |  | 		filter(setup) | 
					
						
							| 
									
										
										
										
											2020-06-08 04:16:03 +03:00
										 |  |  | 			.forEach(function([n, o]){ | 
					
						
							| 
									
										
										
										
											2020-06-08 16:07:54 +03:00
										 |  |  | 				o = get ? get(o) : o | 
					
						
							| 
									
										
										
										
											2020-06-08 04:16:03 +03:00
										 |  |  | 				// mixin once per chain...
 | 
					
						
							| 
									
										
										
										
											2020-06-08 16:07:54 +03:00
										 |  |  | 				if(!o || o[attr]){ | 
					
						
							| 
									
										
										
										
											2020-06-08 04:16:03 +03:00
										 |  |  | 					return } | 
					
						
							|  |  |  | 				assert(!object.hasMixin(o, mixin), 'pre mixin test', n) | 
					
						
							|  |  |  | 				assert(flat ? | 
					
						
							|  |  |  | 						object.mixinFlat(o, mixin) | 
					
						
							|  |  |  | 						: object.mixin(o, mixin),  | 
					
						
							|  |  |  | 					flat ?  | 
					
						
							|  |  |  | 						'mixin (flat)' | 
					
						
							|  |  |  | 						:'mixin', n) | 
					
						
							|  |  |  | 				assert(object.hasMixin(o, mixin), 'mixin test', n) | 
					
						
							| 
									
										
										
										
											2020-06-09 22:31:19 +03:00
										 |  |  | 				assert(o.mixinMethod() == 'mixin', 'mixin method call') | 
					
						
							| 
									
										
										
										
											2020-06-08 04:16:03 +03:00
										 |  |  | 			}) | 
					
						
							|  |  |  | 		return setup }, | 
					
						
							|  |  |  | 	mixin_instance_flat: function(assert, setup){ | 
					
						
							|  |  |  | 		return this.mixin_instance(assert, setup, true) }, | 
					
						
							|  |  |  | 	mixin_constructor: function(assert, setup, flat){ | 
					
						
							| 
									
										
										
										
											2020-06-08 16:07:54 +03:00
										 |  |  | 		return this.mixin_instance(assert, setup, false, constructors) }, | 
					
						
							|  |  |  | 	mixin_constructor_proto: function(assert, setup, flat){ | 
					
						
							|  |  |  | 		return this.mixin_instance(assert, setup, false, constructors,  | 
					
						
							|  |  |  | 			function(o){  | 
					
						
							|  |  |  | 				// skip mixing into Object.prototype...
 | 
					
						
							|  |  |  | 				return o !== Object  | 
					
						
							|  |  |  | 					&& o.prototype }) }, | 
					
						
							| 
									
										
										
										
											2020-06-08 04:16:03 +03:00
										 |  |  | 	mixin_constructor_flat: function(assert, setup){ | 
					
						
							| 
									
										
										
										
											2020-06-08 16:07:54 +03:00
										 |  |  | 		return this.mixin_constructor_proto(assert, setup, true) }, | 
					
						
							| 
									
										
										
										
											2020-06-08 04:16:03 +03:00
										 |  |  | 	/*/ XXX | 
					
						
							|  |  |  | 	mixout: function(assert, setup){ | 
					
						
							|  |  |  | 		return {} | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 	//*/
 | 
					
						
							| 
									
										
										
										
											2020-06-01 04:09:40 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// sanity checks...
 | 
					
						
							| 
									
										
										
										
											2020-06-02 03:05:55 +03:00
										 |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2020-06-01 04:09:40 +03:00
										 |  |  | 	// NOTE: these should have no side-effects but since we can run 
 | 
					
						
							| 
									
										
										
										
											2020-06-02 03:05:55 +03:00
										 |  |  | 	// 		them why not run them and verify ;)
 | 
					
						
							| 
									
										
										
										
											2020-06-01 04:09:40 +03:00
										 |  |  | 	get methods(){ return tests.methods }, | 
					
						
							|  |  |  | 	get constructor_methods(){ return tests.constructor_methods }, | 
					
						
							|  |  |  | 	get callables(){ return tests.callables }, | 
					
						
							| 
									
										
										
										
											2020-08-15 18:59:21 +03:00
										 |  |  | }) | 
					
						
							| 
									
										
										
										
											2020-05-24 02:41:30 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-15 18:59:21 +03:00
										 |  |  | var tests = test.Tests({ | 
					
						
							| 
									
										
										
										
											2020-05-30 00:20:07 +03:00
										 |  |  | 	// instance creation...
 | 
					
						
							| 
									
										
										
										
											2020-06-01 02:49:00 +03:00
										 |  |  | 	instance: modifiers.instance, | 
					
						
							|  |  |  | 	instance_no_new: modifiers.instance_no_new, | 
					
						
							|  |  |  | 	instance_raw: modifiers.instance_raw, | 
					
						
							| 
									
										
										
										
											2020-05-24 23:59:01 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-30 00:53:17 +03:00
										 |  |  | 	/*/ XXX | 
					
						
							| 
									
										
										
										
											2020-05-24 23:59:01 +03:00
										 |  |  | 	attributes: function(assert, setup){ | 
					
						
							| 
									
										
										
										
											2020-05-30 00:53:17 +03:00
										 |  |  | 		return {} }, | 
					
						
							|  |  |  | 	//*/
 | 
					
						
							| 
									
										
										
										
											2020-05-24 23:59:01 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-01 04:09:40 +03:00
										 |  |  | 	// methods...
 | 
					
						
							| 
									
										
										
										
											2020-05-24 23:59:01 +03:00
										 |  |  | 	methods: function(assert, setup){ | 
					
						
							| 
									
										
										
										
											2020-06-01 02:49:00 +03:00
										 |  |  | 		instances(setup) | 
					
						
							|  |  |  | 			.forEach(function([k, o]){ | 
					
						
							| 
									
										
										
										
											2020-06-14 04:29:27 +03:00
										 |  |  | 				object.deepKeys(o) | 
					
						
							| 
									
										
										
										
											2020-06-01 02:49:00 +03:00
										 |  |  | 					.forEach(function(m){ | 
					
						
							|  |  |  | 						typeof(o[m]) == 'function' | 
					
						
							|  |  |  | 							// skip special methods...
 | 
					
						
							|  |  |  | 							&& !m.startsWith('__') | 
					
						
							|  |  |  | 							&& o[m]() }) }) | 
					
						
							| 
									
										
										
										
											2020-06-01 04:09:40 +03:00
										 |  |  | 		return setup }, | 
					
						
							| 
									
										
										
										
											2020-06-01 02:49:00 +03:00
										 |  |  | 	constructor_methods: function(assert, setup){ | 
					
						
							| 
									
										
										
										
											2020-05-24 23:59:01 +03:00
										 |  |  | 		constructors(setup) | 
					
						
							|  |  |  | 			.forEach(function([k, O]){ | 
					
						
							| 
									
										
										
										
											2020-06-14 04:29:27 +03:00
										 |  |  | 				object.deepKeys(O) | 
					
						
							| 
									
										
										
										
											2020-06-01 02:49:00 +03:00
										 |  |  | 					.forEach(function(m){ | 
					
						
							|  |  |  | 						typeof(O[m]) == 'function' | 
					
						
							|  |  |  | 							// skip special methods...
 | 
					
						
							|  |  |  | 							&& !m.startsWith('__') | 
					
						
							|  |  |  | 							&& O[m]() }) }) | 
					
						
							| 
									
										
										
										
											2020-06-01 04:09:40 +03:00
										 |  |  | 		return setup }, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// callables...
 | 
					
						
							| 
									
										
										
										
											2020-05-25 00:53:56 +03:00
										 |  |  | 	callables: function(assert, setup){ | 
					
						
							| 
									
										
										
										
											2020-06-07 21:28:04 +03:00
										 |  |  | 		// test special case .values(x, '__call__')
 | 
					
						
							|  |  |  | 		var test = function(obj, name){ | 
					
						
							|  |  |  | 			var a, b | 
					
						
							|  |  |  | 			return assert(arrayCmp( | 
					
						
							|  |  |  | 				a = object.values(obj, '__call__') | 
					
						
							|  |  |  | 					.map(function(func){ | 
					
						
							|  |  |  | 						return func.call(obj) }) | 
					
						
							|  |  |  | 					.flat(),  | 
					
						
							|  |  |  | 				// get all callables in prototype chain and call them...
 | 
					
						
							|  |  |  | 				b = object.sources(obj) | 
					
						
							|  |  |  | 					.filter(function(o){  | 
					
						
							|  |  |  | 						return typeof(o) == 'function'  | 
					
						
							|  |  |  | 							|| o.hasOwnProperty('__call__') }) | 
					
						
							|  |  |  | 					.map(function(o){  | 
					
						
							|  |  |  | 						return o.hasOwnProperty('__call__') ? | 
					
						
							|  |  |  | 							o.__call__.call(obj) | 
					
						
							|  |  |  | 							// NOTE: not all callables are instances of Function...
 | 
					
						
							|  |  |  | 							: Reflect.apply(Function.prototype, o, [obj]) })),  | 
					
						
							|  |  |  | 				'values of .__call__ of '+ name +': got:', a, 'expected:', b) } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-01 04:09:40 +03:00
										 |  |  | 		instances(setup) | 
					
						
							| 
									
										
										
										
											2020-06-07 21:28:04 +03:00
										 |  |  | 			.filter(function([_, o]){ | 
					
						
							| 
									
										
										
										
											2020-05-28 14:20:47 +03:00
										 |  |  | 				// NOTE: not all callables are instances of Function...
 | 
					
						
							| 
									
										
										
										
											2020-08-09 17:41:18 +03:00
										 |  |  | 				return typeof(o) == 'function'  | 
					
						
							|  |  |  | 					|| !!o.__call__ }) | 
					
						
							| 
									
										
										
										
											2020-06-07 21:28:04 +03:00
										 |  |  | 			.forEach(function([k, o]){ | 
					
						
							|  |  |  | 				o.__non_function ? | 
					
						
							|  |  |  | 					assert(!(o instanceof Function), 'non-instanceof Function', k) | 
					
						
							|  |  |  | 					: assert(o instanceof Function, 'instanceof Function', k) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-09 17:41:18 +03:00
										 |  |  | 				typeof(o) == 'function' | 
					
						
							|  |  |  | 					&& assert(o(), 'call', k)  | 
					
						
							|  |  |  | 				 | 
					
						
							|  |  |  | 				assert(o.call(), '.call(..)', k) | 
					
						
							|  |  |  | 				assert(o.apply(), 'apply(..)', k) | 
					
						
							|  |  |  | 				assert(o.bind(null)(), '.bind(..)(..)', k) | 
					
						
							| 
									
										
										
										
											2020-06-07 21:28:04 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 				test(o, k) | 
					
						
							|  |  |  | 			})  | 
					
						
							| 
									
										
										
										
											2020-06-01 04:09:40 +03:00
										 |  |  | 		return setup }, | 
					
						
							| 
									
										
										
										
											2020-08-15 18:59:21 +03:00
										 |  |  | }) | 
					
						
							| 
									
										
										
										
											2020-05-24 02:41:30 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-15 18:59:21 +03:00
										 |  |  | var cases = test.Cases({ | 
					
						
							| 
									
										
										
										
											2020-06-10 04:48:07 +03:00
										 |  |  | 	'edge-cases': function(assert){ | 
					
						
							| 
									
										
										
										
											2020-06-16 01:28:28 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		assert.error('double __extends__ fail', function(){ | 
					
						
							|  |  |  | 			var X = object.C('X', { | 
					
						
							|  |  |  | 				__extends__: Object, | 
					
						
							|  |  |  | 			}, { | 
					
						
							|  |  |  | 				__extends__: Function, | 
					
						
							|  |  |  | 			}) | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// native constructor...
 | 
					
						
							|  |  |  | 		assert.array( | 
					
						
							|  |  |  | 			object.RawInstance(null, Array, 'a', 'b', 'c'),  | 
					
						
							|  |  |  | 			['a', 'b', 'c'],  | 
					
						
							|  |  |  | 			'native constructor') | 
					
						
							|  |  |  | 		assert(object.RawInstance(null, Number, '123') == 123, 'native constructor') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-10 04:48:07 +03:00
										 |  |  | 		var x, y | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// object.match(..)
 | 
					
						
							|  |  |  | 		assert(object.match(x = {a: 123, b: '333', c: []}, x) === true, 'match self') | 
					
						
							|  |  |  | 		assert(object.match(x, {a: x.a, b: x.b, c: []}) == false, 'strict mismatch') | 
					
						
							|  |  |  | 		assert(object.match(x, {a: 123, b: 333, c: x.c}, true) === true, 'non-strict match') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// object.matchPartial(..)
 | 
					
						
							|  |  |  | 		assert(object.matchPartial(x, {a: x.a}, true) === true, 'non-strict partial match') | 
					
						
							|  |  |  | 		assert(object.matchPartial(x, {a: x.a, b: x.b, c: x.c}) === true, 'strict partial match') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// object.parent(..)
 | 
					
						
							|  |  |  | 		assert(object.parent({}) === {}.__proto__, 'basic proto') | 
					
						
							|  |  |  | 		assert.error('.parent(..) of anonymous function', function(){  | 
					
						
							|  |  |  | 			object.parent(function(){}, {}) }) | 
					
						
							| 
									
										
										
										
											2020-05-30 00:53:17 +03:00
										 |  |  | 	}, | 
					
						
							| 
									
										
										
										
											2020-06-16 01:28:28 +03:00
										 |  |  | 	deepKeys: function(assert){ | 
					
						
							| 
									
										
										
										
											2020-06-14 17:54:01 +03:00
										 |  |  | 		var a = { | 
					
						
							|  |  |  | 			a: true | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		var b = { | 
					
						
							|  |  |  | 			__proto__: a, | 
					
						
							|  |  |  | 			b: true, | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		var c = { | 
					
						
							|  |  |  | 			__proto__: b, | 
					
						
							|  |  |  | 			c: true, | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-15 16:59:42 +03:00
										 |  |  | 		assert.array(object.deepKeys(c), ['c', 'b', 'a'], 'full chain') | 
					
						
							|  |  |  | 		assert.array(object.deepKeys(c, a), ['c', 'b', 'a'], 'full chain') | 
					
						
							|  |  |  | 		assert.array(object.deepKeys(c, b), ['c', 'b'], 'partial chain') | 
					
						
							|  |  |  | 		assert.array(object.deepKeys(c, c), ['c'], 'partial chain') | 
					
						
							| 
									
										
										
										
											2020-06-14 17:54:01 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-09 17:19:17 +03:00
										 |  |  | 	}, | 
					
						
							|  |  |  | 	funcMethods: function(assert){ | 
					
						
							|  |  |  | 		var X = object.C('X', { | 
					
						
							|  |  |  | 			__call__: function(){ | 
					
						
							|  |  |  | 				return true }, | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		var x = new X() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		assert(x(), 'x()') | 
					
						
							|  |  |  | 		assert(x.call(null), 'x.call(null)') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		var xx = Object.create(x) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		assert(typeof(xx.call) == 'function', 'xx.call is a function') | 
					
						
							|  |  |  | 		assert(xx.call(null), 'xx.call(null)') | 
					
						
							|  |  |  | 	}, | 
					
						
							| 
									
										
										
										
											2020-06-09 22:31:19 +03:00
										 |  |  | }) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-28 14:20:47 +03:00
										 |  |  | //---------------------------------------------------------------------
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-15 18:59:21 +03:00
										 |  |  | typeof(__filename) != 'undefined' | 
					
						
							|  |  |  | 	&& __filename == (require.main || {}).filename | 
					
						
							|  |  |  | 	&& test.run() | 
					
						
							| 
									
										
										
										
											2020-05-24 02:41:30 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-03 02:48:38 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-24 02:41:30 +03:00
										 |  |  | /********************************************************************** | 
					
						
							|  |  |  | * vim:set ts=4 sw=4 :                               */ return module }) |