Advertisement
Guest User

Untitled

a guest
Sep 22nd, 2013
204
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. /**
  2.  * testr.js 1.0.2
  3.  * https://www.github.com/mattfysh/testr.js
  4.  * Distributed under the MIT license
  5.  */
  6.  
  7. var testr, define;
  8.  
  9. (function() {
  10.     var version = '1.0.2',
  11.         origDefine = define,
  12.         cjsRequireRegExp = /require\s*\(\s*["']([^'"\s]+)["']\s*\)/g,
  13.         noop = function() {},
  14.         moduleMap = window.mm = {},
  15.         pluginPaths = {},
  16.         baseUrl = require.toUrl('.').replace(/\.$/, ''),
  17.         config = {
  18.             autoLoad: false
  19.         };
  20.  
  21.     // type detection
  22.     function isArray(a) {
  23.         return toString.call(a) == '[object Array]';
  24.     }
  25.     function isObject(o) {
  26.         return typeof o === 'object' && !isArray(o);
  27.     }
  28.  
  29.     // deep copy
  30.     function deepCopy(src) {
  31.         var tgt = isObject(src) ? {} : [];
  32.         each(src, function(val, key) {
  33.             tgt[key] = (isArray(val) || isObject(val)) ? deepCopy(val) : val;
  34.         });
  35.         return tgt;
  36.     }
  37.  
  38.     // each
  39.     function each(items, callback) {
  40.         if (!items) {
  41.             return;
  42.         } else if (typeof items.length === 'number') {
  43.             for (var i = 0; i < items.length; i += 1) {
  44.                 callback(items[i], i);
  45.             }
  46.         } else if (isObject(items)) {
  47.             for (var prop in items) {
  48.                 if (items.hasOwnProperty(prop)) {
  49.                     callback(items[prop], prop);
  50.                 }
  51.             }
  52.         }
  53.     }
  54.  
  55.     // normalize paths
  56.     function normalize(path, contextReq) {
  57.         if (path.indexOf('!') === -1) {
  58.             // regular path
  59.             return contextReq(path);
  60.         } else {
  61.             // plugin
  62.             path = path.split('!');
  63.             if (path[1]) {
  64.                 path[1] = contextReq.toUrl(path[1]).substring(baseUrl.length);
  65.             }
  66.             return path.join('!');
  67.         }
  68.     }
  69.  
  70.     // override define
  71.     define = function() {
  72.         var args = [].slice.call(arguments),
  73.             factory = args.pop(),
  74.             deps = args.pop(),
  75.             name = args.pop(),
  76.             depPaths = ['require', 'module'],
  77.             extractedPaths = [],
  78.             pluginLocs = [],
  79.             exportsLocs = [],
  80.             requireLocs = [],
  81.             wrap = !deps && typeof factory === 'function',
  82.             defineArgs;
  83.  
  84.         // account for signature variation
  85.         if (typeof deps === 'string') {
  86.             name = deps;
  87.             deps = [];
  88.         }
  89.  
  90.         // process the dependency ids
  91.         each(deps, function(path, index) {
  92.             if (path.indexOf('!') > -1) {
  93.                 pluginPaths[path.split('!')[0]] = true;
  94.                 pluginLocs.push(index);
  95.             } else if (path === 'exports') {
  96.                 exportsLocs.push(index);
  97.             } else if (path === 'require') {
  98.                 requireLocs.push(index);
  99.             }
  100.             depPaths.push(path);
  101.         });
  102.  
  103.         // find cjs wrapped require calls
  104.         if (!deps) {
  105.             factory.toString().replace(cjsRequireRegExp, function (match, dep) {
  106.                 extractedPaths.push(dep);
  107.             });
  108.         }
  109.        
  110.  
  111.         // rewrite the function that requirejs executes when defining the module
  112.         function trojan(contextReq, module) {
  113.             var offset = 2,
  114.                 deps = [].slice.call(arguments, offset);
  115.  
  116.             if (!module || pluginPaths[module.id]) {
  117.                 // jquery or plugin, give requirejs the real module
  118.                 return (typeof factory === 'function') ? factory.apply(null, deps) : factory;
  119.             }
  120.  
  121.             // alter plugin storage
  122.             each(pluginLocs, function(loc) {
  123.                 // normalize path names
  124.                 var path = depPaths[loc + offset];
  125.                 deps[loc] = normalize(path, contextReq);
  126.             });
  127.  
  128.             // alter exports deps
  129.             each(exportsLocs, function(loc) {
  130.                 deps[loc] = 'exports';
  131.             });
  132.  
  133.             // alter require deps
  134.             each(requireLocs, function(loc) {
  135.                 deps[loc] = 'require';
  136.             });
  137.  
  138.             // save the module
  139.             moduleMap[module.id] = {
  140.                 factory: factory,
  141.                 deps: wrap ? ['require', 'exports'] : deps,
  142.                 require: contextReq
  143.             };
  144.  
  145.             if (module.uri.indexOf('./stub') === 0) {
  146.                 // stub has been saved to module map, no further processing needed
  147.                 return;
  148.             }
  149.  
  150.             // auto load associated files
  151.             if (config.autoLoad) {
  152.                 require({
  153.                     context: module.id,
  154.                     baseUrl: '.',
  155.                     deps: ['stub/' + module.id + '.stub', 'spec/' + module.id + '.spec']
  156.                 });
  157.             }
  158.            
  159.             // define the module as its path name, used by dependants
  160.             return module.id;
  161.         };
  162.  
  163.         // hook back into the loader with modified dependancy paths
  164.         // to trigger dependency loading, and execute the trojan
  165.         if (extractedPaths.length) {
  166.  
  167.         }
  168.         defineArgs = [depPaths.concat(extractedPaths), trojan];
  169.         name && defineArgs.unshift(name);
  170.         origDefine.apply(null, defineArgs);
  171.         name && require([name]); // force requirejs to load the module immediately and call the trojan
  172.     };
  173.  
  174.     // copy amd properties
  175.     define.amd = origDefine.amd;
  176.  
  177.     // create new modules with the factory
  178.     function buildModule(moduleName, stubs, useExternal, subject) {
  179.         var depModules = [],
  180.             exports = {},
  181.             moduleDef, factory, deps, contextReq,
  182.             getModule = function(depName) {
  183.                 return stubs && stubs[depName] || buildModule(depName, stubs, useExternal);
  184.             };
  185.  
  186.         // get module definition from map
  187.         moduleDef = (!subject && useExternal && moduleMap['stub/' + moduleName + '.stub']) || moduleMap[moduleName];
  188.         if (!moduleDef) {
  189.             // module may be stored in requirejs, e.g. plugin-loaded dependencies
  190.             try {
  191.                 return require(moduleName);
  192.             } catch(e) {
  193.                 throw new Error('module has not been loaded: ' + moduleName);
  194.             }
  195.         }
  196.  
  197.         // shortcuts
  198.         factory = moduleDef.factory;
  199.         deps = moduleDef.deps;
  200.         contextReq = moduleDef.require;
  201.  
  202.         // normalize stubs object paths on first call
  203.         if (subject) {
  204.             each(stubs, function(stub, path) {
  205.                 var nPath = normalize(path, contextReq);
  206.                 if (nPath !== path) {
  207.                     stubs[nPath] = stub;
  208.                     delete stubs[path];
  209.                 }
  210.             });
  211.         }
  212.  
  213.         // load up dependencies
  214.         each(deps, function(dep) {
  215.             // determine what to pass to the factory
  216.             if (dep == 'exports') {
  217.                 dep = exports;
  218.             } else if (dep === 'require') {
  219.                 dep = function(path) {
  220.                     return getModule(normalize(path, contextReq));
  221.                 };
  222.             } else {
  223.                 dep = getModule(dep);
  224.             }
  225.  
  226.             // add dependency to array
  227.             depModules.push(dep);
  228.         });
  229.  
  230.         if (typeof factory !== 'function') {
  231.             // return clean copy of module object
  232.             return deepCopy(factory);
  233.         } else {
  234.             // return clean instance of module
  235.             return factory.apply(exports, depModules) || exports;
  236.         }
  237.     }
  238.  
  239.     // testr API
  240.     testr = function(moduleName, stubs, useExternal) {
  241.         // check module name
  242.         if (typeof moduleName !== 'string') {
  243.             throw Error('module name must be a string');
  244.         }
  245.  
  246.         // check stubs
  247.         if (!useExternal && typeof stubs === 'boolean') {
  248.             useExternal = stubs;
  249.             stubs = {};
  250.         } else if (stubs && !isObject(stubs)) {
  251.             throw Error('stubs must be given as an object');
  252.         }
  253.  
  254.         // build the module under test
  255.         return buildModule(moduleName, stubs, useExternal, true);
  256.     };
  257.  
  258.     // testr config
  259.     testr.config = function(userConfig) {
  260.         each(userConfig, function(val, key) {
  261.             config[key] = val;
  262.         });
  263.     };
  264.  
  265.     // attach version
  266.     testr.version = version;
  267.  
  268. }());
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement