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