test.js
5.41 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
'use strict';
/* eslint no-magic-numbers: 1 */
var test = require('tape');
var isCallable = require('./');
var hasSymbols = typeof Symbol === 'function' && typeof Symbol('foo') === 'symbol';
var genFn = require('make-generator-function');
var arrowFn = require('make-arrow-function')();
var weirdlyCommentedArrowFn;
var asyncFn;
var asyncArrowFn;
try {
/* eslint no-new-func: 0 */
weirdlyCommentedArrowFn = Function('return cl/*/**/=>/**/ass - 1;')();
asyncFn = Function('return async function foo() {};')();
asyncArrowFn = Function('return async () => {};')();
} catch (e) { /**/ }
var forEach = require('foreach');
var noop = function () {};
var classFake = function classFake() { }; // eslint-disable-line func-name-matching
var returnClass = function () { return ' class '; };
var return3 = function () { return 3; };
/* for coverage */
noop();
classFake();
returnClass();
return3();
/* end for coverage */
var invokeFunction = function invokeFunctionString(str) {
var result;
try {
/* eslint-disable no-new-func */
var fn = Function(str);
/* eslint-enable no-new-func */
result = fn();
} catch (e) {}
return result;
};
var classConstructor = invokeFunction('"use strict"; return class Foo {}');
var commentedClass = invokeFunction('"use strict"; return class/*kkk*/\n//blah\n Bar\n//blah\n {}');
var commentedClassOneLine = invokeFunction('"use strict"; return class/**/A{}');
var classAnonymous = invokeFunction('"use strict"; return class{}');
var classAnonymousCommentedOneLine = invokeFunction('"use strict"; return class/*/*/{}');
test('not callables', function (t) {
t.test('non-number/string primitives', function (st) {
st.notOk(isCallable(), 'undefined is not callable');
st.notOk(isCallable(null), 'null is not callable');
st.notOk(isCallable(false), 'false is not callable');
st.notOk(isCallable(true), 'true is not callable');
st.end();
});
t.notOk(isCallable([]), 'array is not callable');
t.notOk(isCallable({}), 'object is not callable');
t.notOk(isCallable(/a/g), 'regex literal is not callable');
t.notOk(isCallable(new RegExp('a', 'g')), 'regex object is not callable');
t.notOk(isCallable(new Date()), 'new Date() is not callable');
t.test('numbers', function (st) {
st.notOk(isCallable(42), 'number is not callable');
st.notOk(isCallable(Object(42)), 'number object is not callable');
st.notOk(isCallable(NaN), 'NaN is not callable');
st.notOk(isCallable(Infinity), 'Infinity is not callable');
st.end();
});
t.test('strings', function (st) {
st.notOk(isCallable('foo'), 'string primitive is not callable');
st.notOk(isCallable(Object('foo')), 'string object is not callable');
st.end();
});
t.test('non-function with function in its [[Prototype]] chain', function (st) {
var Foo = function Bar() {};
Foo.prototype = noop;
st.equal(true, isCallable(Foo), 'sanity check: Foo is callable');
st.equal(false, isCallable(new Foo()), 'instance of Foo is not callable');
st.end();
});
t.end();
});
test('@@toStringTag', { skip: !hasSymbols || !Symbol.toStringTag }, function (t) {
var fakeFunction = {
toString: function () { return String(return3); },
valueOf: return3
};
fakeFunction[Symbol.toStringTag] = 'Function';
t.equal(String(fakeFunction), String(return3));
t.equal(Number(fakeFunction), return3());
t.notOk(isCallable(fakeFunction), 'fake Function with @@toStringTag "Function" is not callable');
t.end();
});
var typedArrayNames = [
'Int8Array',
'Uint8Array',
'Uint8ClampedArray',
'Int16Array',
'Uint16Array',
'Int32Array',
'Uint32Array',
'Float32Array',
'Float64Array'
];
test('Functions', function (t) {
t.ok(isCallable(noop), 'function is callable');
t.ok(isCallable(classFake), 'function with name containing "class" is callable');
t.ok(isCallable(returnClass), 'function with string " class " is callable');
t.ok(isCallable(isCallable), 'isCallable is callable');
t.end();
});
test('Typed Arrays', function (st) {
forEach(typedArrayNames, function (typedArray) {
/* istanbul ignore if : covered in node 0.6 */
if (typeof global[typedArray] === 'undefined') {
st.comment('# SKIP typed array "' + typedArray + '" not supported');
} else {
st.ok(isCallable(global[typedArray]), typedArray + ' is callable');
}
});
st.end();
});
test('Generators', { skip: !genFn }, function (t) {
t.ok(isCallable(genFn), 'generator function is callable');
t.end();
});
test('Arrow functions', { skip: !arrowFn }, function (t) {
t.ok(isCallable(arrowFn), 'arrow function is callable');
t.ok(isCallable(weirdlyCommentedArrowFn), 'weirdly commented arrow functions are callable');
t.end();
});
test('"Class" constructors', { skip: !classConstructor || !commentedClass || !commentedClassOneLine || !classAnonymous }, function (t) {
t.notOk(isCallable(classConstructor), 'class constructors are not callable');
t.notOk(isCallable(commentedClass), 'class constructors with comments in the signature are not callable');
t.notOk(isCallable(commentedClassOneLine), 'one-line class constructors with comments in the signature are not callable');
t.notOk(isCallable(classAnonymous), 'anonymous class constructors are not callable');
t.notOk(isCallable(classAnonymousCommentedOneLine), 'anonymous one-line class constructors with comments in the signature are not callable');
t.end();
});
test('`async function`s', { skip: !asyncFn }, function (t) {
t.ok(isCallable(asyncFn), '`async function`s are callable');
t.ok(isCallable(asyncArrowFn), '`async` arrow functions are callable');
t.end();
});