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-09-15 18:23:09 +03:00
|
|
|
* - normalizeIndent(..)/normalizeTextIndent(..) -- tab_size values...
|
2020-08-17 15:56:08 +03:00
|
|
|
* - object.mixout(..)
|
|
|
|
|
* - 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-10-16 04:45:49 +03:00
|
|
|
// data wrapper...
|
|
|
|
|
var data = function(d){ return d }
|
|
|
|
|
|
|
|
|
|
// text test runner...
|
|
|
|
|
var testText = function(assert, func, input, expect){
|
|
|
|
|
var res
|
|
|
|
|
return assert((res = object[func](input)) == expect,
|
|
|
|
|
func +'(..):'
|
|
|
|
|
+'\n---input---\n'
|
|
|
|
|
+ (input instanceof Array ?
|
|
|
|
|
input[0]
|
|
|
|
|
: input)
|
|
|
|
|
+'\n---Expected---\n'
|
|
|
|
|
+ expect
|
|
|
|
|
+'\n---Got---\n'
|
|
|
|
|
+ res
|
|
|
|
|
+'\n---') }
|
|
|
|
|
|
2020-06-04 00:20:45 +03:00
|
|
|
|
|
|
|
|
|
2020-05-24 02:41:30 +03:00
|
|
|
//---------------------------------------------------------------------
|
2020-10-16 04:45:49 +03:00
|
|
|
// General 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-10-16 04:39:40 +03:00
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------
|
2020-10-16 04:45:49 +03:00
|
|
|
// Text util tests...
|
2020-10-16 04:39:40 +03:00
|
|
|
|
|
|
|
|
var text = test.TestSet()
|
2020-10-16 04:45:49 +03:00
|
|
|
test.Case('text', text)
|
2020-10-16 04:39:40 +03:00
|
|
|
|
|
|
|
|
// XXX still need to test tab_size values (0, ...)
|
|
|
|
|
// ...a good candidate for modifiers...
|
|
|
|
|
// XXX naming is not clear -- should be close to automatic...
|
|
|
|
|
// XXX still need to test tab_size values (0, ...)
|
|
|
|
|
text.setups({
|
2020-09-17 15:25:46 +03:00
|
|
|
// sanity checks...
|
2020-10-16 04:45:49 +03:00
|
|
|
'""': data({
|
2020-09-17 15:25:46 +03:00
|
|
|
input: '',
|
|
|
|
|
all: '', }),
|
2020-10-16 04:45:49 +03:00
|
|
|
'"abc"': data({
|
2020-09-17 15:25:46 +03:00
|
|
|
input: 'abc',
|
|
|
|
|
all: 'abc'}),
|
2020-10-16 04:45:49 +03:00
|
|
|
'leading whitespace': data({
|
2020-09-17 15:25:46 +03:00
|
|
|
input: '\n\t\tabc',
|
|
|
|
|
all: 'abc'}),
|
|
|
|
|
|
|
|
|
|
// NOTE: there is no way to know what is the indent of 'a'
|
|
|
|
|
// relative to the rest of the text...
|
2020-10-16 04:45:49 +03:00
|
|
|
text_04: data({
|
2020-09-17 15:25:46 +03:00
|
|
|
input: `a
|
|
|
|
|
c`,
|
|
|
|
|
text: 'a\nc',
|
|
|
|
|
doc: 'a\n c'}),
|
2020-10-16 04:45:49 +03:00
|
|
|
text_05: data({
|
2020-09-17 15:25:46 +03:00
|
|
|
input: `a\nc`,
|
|
|
|
|
text: 'a\nc',
|
|
|
|
|
doc: 'a\nc'}),
|
2020-10-16 04:45:49 +03:00
|
|
|
text_06: data({
|
2020-09-17 15:25:46 +03:00
|
|
|
input: `\
|
|
|
|
|
a
|
|
|
|
|
c`,
|
|
|
|
|
all: 'a\n c'}),
|
2020-10-16 04:45:49 +03:00
|
|
|
text_07: data({
|
2020-09-17 15:25:46 +03:00
|
|
|
input: `
|
|
|
|
|
a
|
|
|
|
|
c`,
|
|
|
|
|
all: 'a\n c'}),
|
2020-10-16 04:45:49 +03:00
|
|
|
text_08: data({
|
2020-09-17 15:25:46 +03:00
|
|
|
input: `
|
|
|
|
|
a
|
|
|
|
|
c`,
|
|
|
|
|
all: 'a\n c' }),
|
|
|
|
|
|
2020-10-16 04:45:49 +03:00
|
|
|
text_09: data({
|
2020-09-17 15:25:46 +03:00
|
|
|
input: `a
|
|
|
|
|
b
|
|
|
|
|
c`,
|
|
|
|
|
text: 'a\nb\nc',
|
|
|
|
|
doc: 'a\n b\n c' }),
|
|
|
|
|
|
2020-10-16 04:45:49 +03:00
|
|
|
text_10: data({
|
2020-09-17 15:25:46 +03:00
|
|
|
input: `
|
|
|
|
|
a
|
|
|
|
|
b
|
|
|
|
|
c`,
|
|
|
|
|
all: 'a\nb\n c' }),
|
2020-10-16 04:45:49 +03:00
|
|
|
text_11: data({
|
2020-09-17 15:25:46 +03:00
|
|
|
input: `
|
|
|
|
|
a
|
|
|
|
|
b
|
|
|
|
|
c`,
|
|
|
|
|
all: 'a\n b\n c' }),
|
|
|
|
|
|
2020-10-16 04:45:49 +03:00
|
|
|
text_12: data({
|
2020-09-17 15:25:46 +03:00
|
|
|
input: `a
|
|
|
|
|
b
|
|
|
|
|
c`,
|
|
|
|
|
all: `a\n b\nc` }),
|
2020-10-16 04:45:49 +03:00
|
|
|
text_13: data({
|
2020-09-17 15:25:46 +03:00
|
|
|
input: `a
|
|
|
|
|
b
|
|
|
|
|
c`,
|
|
|
|
|
all: `a\nb\n c` }),
|
2020-10-16 04:45:49 +03:00
|
|
|
text_14: data({
|
2020-09-17 15:25:46 +03:00
|
|
|
input: `
|
|
|
|
|
a
|
|
|
|
|
b
|
|
|
|
|
c`,
|
|
|
|
|
all: `a\n b\n c` }),
|
2020-10-16 04:45:49 +03:00
|
|
|
text_15: data({
|
2020-09-17 15:25:46 +03:00
|
|
|
input: `a
|
|
|
|
|
b
|
|
|
|
|
b
|
|
|
|
|
b
|
|
|
|
|
c`,
|
|
|
|
|
all: `a\n b\n b\n b\nc` }),
|
2020-10-16 04:45:49 +03:00
|
|
|
text_16: data({
|
2020-09-17 15:25:46 +03:00
|
|
|
input: `a
|
|
|
|
|
b
|
|
|
|
|
b
|
|
|
|
|
b
|
|
|
|
|
c`,
|
|
|
|
|
all: `a\n b\n b\n b\nc` }),
|
2020-10-16 04:45:49 +03:00
|
|
|
text_17: data({
|
2020-09-17 15:25:46 +03:00
|
|
|
input: `
|
|
|
|
|
a
|
|
|
|
|
b
|
|
|
|
|
c`,
|
|
|
|
|
all: `a\n b\nc` }),
|
2020-10-16 04:45:49 +03:00
|
|
|
text_18: data({
|
2020-09-17 15:25:46 +03:00
|
|
|
input: `a
|
|
|
|
|
b
|
|
|
|
|
c
|
|
|
|
|
d`,
|
|
|
|
|
text: `a\n b\nc\nd`,
|
|
|
|
|
// XXX not sure about this...
|
|
|
|
|
doc: `a\n b\n c\n d` }),
|
2020-06-09 22:31:19 +03:00
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
2020-10-16 04:39:40 +03:00
|
|
|
text.tests({
|
|
|
|
|
doc: function(assert, data){
|
|
|
|
|
var e = data.doc != null ?
|
|
|
|
|
data.doc
|
|
|
|
|
: data.all
|
|
|
|
|
data.doc != null
|
|
|
|
|
&& testText(assert, 'normalizeIndent', data.input, data.doc)
|
|
|
|
|
&& testText(assert, 'doc', [data.input], data.doc) },
|
|
|
|
|
text: function(assert, data){
|
|
|
|
|
var e = data.text != null ?
|
|
|
|
|
data.text
|
|
|
|
|
: data.all
|
|
|
|
|
e != null
|
|
|
|
|
&& testText(assert, 'normalizeTextIndent', data.input, e)
|
|
|
|
|
&& testText(assert, 'text', [data.input], e) },
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
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 })
|