PageRenderTime 166ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/wwwroot/vendor/jack.js

http://github.com/AF83/ucengine
JavaScript | 903 lines | 798 code | 74 blank | 31 comment | 213 complexity | fe057367a28f77908e83035c7a85cfa8 MD5 | raw file
  1. /**
  2. *
  3. * JACK :: JavaScript Mocking.
  4. * Version: $Id$
  5. *
  6. */
  7. function jack() {} // This needs to be here to make error reporting work correctly in IE.
  8. (function (){ // START HIDING FROM GLOBAL SCOPE
  9. /** EXPORT JACK **/
  10. window.jack = new Jack();
  11. window.jack.matchers = new Matchers();
  12. window.jack.util = new Util();
  13. window.jack.FunctionSpecification = FunctionSpecification;
  14. window.jack.FunctionGrab = FunctionGrab;
  15. return;
  16. /**
  17. * Constructor for object that will be exposed as the global jack
  18. */
  19. function Jack() {
  20. var functionGrabs = {};
  21. var objectGrabs = {};
  22. var environment = new Environment();
  23. var reportMessages = [];
  24. var currentExpectation = null;
  25. var publicApi = createPublicApi();
  26. return publicApi;
  27. function createPublicApi() {
  28. var api = jackFunction;
  29. api.grab = grab;
  30. api.create = create;
  31. api.inspect = inspect;
  32. api.expect = expect;
  33. api.verify = verify;
  34. api.report = report;
  35. api.reportAll = reportAll;
  36. api.env = environment;
  37. return api;
  38. }
  39. function jackFunction(delegate) {
  40. before();
  41. firstPass(delegate);
  42. // secondPass(delegate);
  43. after();
  44. }
  45. function before() {
  46. functionGrabs = {};
  47. objectGrabs = {};
  48. environment.reset();
  49. }
  50. function firstPass(delegate) {
  51. delegate();
  52. }
  53. function secondPass(delegate) {
  54. var oldExpect = publicApi.expect;
  55. publicApi.expect = function(name) {
  56. var fakeEx = {};
  57. var grab = findGrab(name);
  58. if(grab._beenThroughSecondPass) {
  59. var ex = grab.expect();
  60. for(prop in ex) {
  61. if(typeof ex[prop] == "function") {
  62. fakeEx[prop] = function() { return fakeEx; }
  63. }
  64. }
  65. }
  66. grab._beenThroughSecondPass = true;
  67. return fakeEx;
  68. };
  69. var findMore = true;
  70. for(var i=0; findMore && i<10; i++) {
  71. try {
  72. delegate();
  73. findMore = false;
  74. } catch(exception) {
  75. var line = -1;
  76. if(exception.lineNumber != null) {
  77. line = exception.lineNumber;
  78. } else if(exception['opera#sourceloc'] != null) {
  79. line = exception['opera#sourceloc'];
  80. }
  81. currentExpectation._lineNumber = line;
  82. }
  83. }
  84. publicApi.expect = oldExpect;
  85. }
  86. function after() {
  87. var reports = getTextReports();
  88. resetGrabs();
  89. if(reports.length > 0) {
  90. environment.report(reports[0]);
  91. }
  92. }
  93. function getTextReports() {
  94. var failedReports = [];
  95. for(var name in functionGrabs) {
  96. var reports = functionGrabs[name].reportAll(name);
  97. for(var i=0; i<reports.length; i++) {
  98. if(reports[i].fail) {
  99. failedReports.push(reports[i].message);
  100. }
  101. }
  102. }
  103. for(var name in objectGrabs) {
  104. var reports = objectGrabs[name].report(name);
  105. for(var i=0; i<reports.length; i++) {
  106. if(reports[i].fail) {
  107. failedReports.push(reports[i].message);
  108. }
  109. }
  110. }
  111. return failedReports;
  112. }
  113. function grab() {
  114. if("object" == typeof arguments[0] && "string" == typeof arguments[1]) {
  115. var parentObject = arguments[0];
  116. var name = arguments[1];
  117. var fullName = "[local]." + name;
  118. return grabFunction(fullName, parentObject[name], parentObject);
  119. } else {
  120. var grabbed = null;
  121. eval("grabbed = " + arguments[0]);
  122. if("function" == typeof grabbed) {
  123. var functionGrab = grabFunction(arguments[0], grabbed);
  124. eval("grabbed = " + arguments[0]);
  125. grabObject(arguments[0], grabbed);
  126. return functionGrab;
  127. } else if("object" == typeof grabbed) {
  128. return grabObject(arguments[0], grabbed);
  129. }
  130. return null;
  131. }
  132. }
  133. function grabFunction(fullName, grabbed, parentObject) {
  134. if(parentObject == null) {
  135. parentObject = window;
  136. }
  137. var functionName = fullName;
  138. var nameParts = fullName.split(".");
  139. if(nameParts[0] == "[local]") {
  140. functionName = nameParts[1];
  141. } else if(nameParts.length > 1) {
  142. functionName = nameParts.pop();
  143. if(parentObject == window) {
  144. var parentName = nameParts.join(".");
  145. eval("parentObject = " + parentName);
  146. }
  147. }
  148. functionGrabs[fullName] = new FunctionGrab(functionName, grabbed, parentObject);
  149. return functionGrabs[fullName];
  150. }
  151. function grabObject(name, grabbed) {
  152. objectGrabs[name] = new ObjectGrab(name, grabbed);
  153. return objectGrabs[name];
  154. }
  155. function create(objectName, functionNames) {
  156. var mockObject = {};
  157. for(var i=0; i<functionNames.length; i++) {
  158. mockObject[functionNames[i]] = function() {};
  159. var fullName = objectName+"."+functionNames[i];
  160. grabFunction(fullName, mockObject[functionNames[i]], mockObject);
  161. }
  162. return mockObject;
  163. }
  164. function inspect(name) {
  165. return findGrab(name);
  166. }
  167. function expect(name) {
  168. if(findGrab(name) == null) {
  169. grab(name);
  170. }
  171. currentExpectation = findGrab(name).expect().once();
  172. return currentExpectation;
  173. }
  174. function verify(name) {
  175. if(findGrab(name) == null) {
  176. grab(name);
  177. }
  178. currentExpectation = findGrab(name).expect().once();
  179. return currentExpectation;
  180. }
  181. function report(name, expectation) {
  182. return findGrab(name).report(expectation, name);
  183. }
  184. function reportAll(name) {
  185. return findGrab(name).reportAll(name);
  186. }
  187. function findGrab(name) {
  188. var parts = name.split(".");
  189. if(parts.length == 1 && functionGrabs[name] != null) {
  190. return functionGrabs[name];
  191. } else if(parts.length == 1 && objectGrabs[name] != null) {
  192. return objectGrabs[name];
  193. } else {
  194. if(functionGrabs[name] != null) {
  195. return functionGrabs[name];
  196. }
  197. if(objectGrabs[name] != null) {
  198. return objectGrabs[name];
  199. }
  200. if(objectGrabs[parts[0]] != null) {
  201. return objectGrabs[parts[0]].examine(parts[1]);
  202. }
  203. return undefined;
  204. }
  205. }
  206. function resetGrabs() {
  207. for(var g in functionGrabs) {
  208. functionGrabs[g].reset();
  209. }
  210. for(var g in objectGrabs) {
  211. objectGrabs[g].reset();
  212. }
  213. }
  214. } // END Jack()
  215. /**
  216. * @functionName Name of grabbed function
  217. * @grabbedFunction Reference to grabbed function
  218. * @parentObject The object the function was grabbed from
  219. */
  220. function FunctionGrab(functionName, grabbedFunction, parentObject) {
  221. var invocations = [];
  222. var specifications = [];
  223. var emptyFunction = function(){};
  224. init();
  225. return {
  226. 'times': function() { return invocations.length; },
  227. 'reset': reset,
  228. 'expect': expect,
  229. 'specify': specify,
  230. 'report': report,
  231. 'reportAll': reportAll,
  232. 'mock': mock,
  233. 'stub': stub,
  234. 'arguments': getArguments,
  235. 'name': function() { return functionName }
  236. };
  237. function init() {
  238. var original = parentObject[functionName];
  239. var handler = function() {
  240. return handleInvocation.apply(this,arguments);
  241. }
  242. for(var prop in original) {
  243. handler[prop] = original[prop];
  244. }
  245. parentObject[functionName] = handler;
  246. }
  247. function handleInvocation() {
  248. var invocation = new FunctionSpecification();
  249. for(var i=0; i<arguments.length; i++) {
  250. invocation.whereArgument(i).is(arguments[i]);
  251. }
  252. invocations.push(invocation);
  253. var specification = findSpecificationFor(invocation);
  254. if(specification == null) {
  255. return grabbedFunction.apply(this, arguments);
  256. } else if(specification.hasMockImplementation()) {
  257. return specification.invoke.apply(this, arguments);
  258. } else {
  259. specification.invoke.apply(this, arguments);
  260. return grabbedFunction.apply(this, arguments);
  261. }
  262. }
  263. function matchInvocationsToSpecifications() {
  264. for(var i=0; i<invocations.length; i++) {
  265. var spec = findSpecificationFor(invocations[i]);
  266. if(spec != null) {
  267. }
  268. }
  269. }
  270. function findSpecificationFor(invocation) {
  271. for(var i=0; i<specifications.length; i++) {
  272. var specification = specifications[i];
  273. if(invocation.satisfies(specification)) {
  274. return specification;
  275. }
  276. }
  277. return null;
  278. }
  279. function isArgumentContstraintsMatching(invocation, expectation) {
  280. var constr = expectation._argumentConstraints;
  281. var arg = invocation.arguments;
  282. if(constr == null) {
  283. return true;
  284. } else if(constr.length != arg.length) {
  285. return false;
  286. } else {
  287. for(var i=0; i<constr.length; i++) {
  288. if(!constr[i]) { continue; }
  289. for(var j=0; j<constr[i].length; j++) {
  290. if(typeof constr[i][j] == "function" && !constr[i][j](arg[i])) {
  291. return false;
  292. }
  293. }
  294. }
  295. return true;
  296. }
  297. }
  298. function reset() {
  299. parentObject[functionName] = grabbedFunction;
  300. }
  301. function specify() {
  302. var spec = new FunctionSpecification();
  303. spec._id = specifications.length;
  304. specifications.push(spec);
  305. return spec;
  306. }
  307. function verify() {
  308. }
  309. function expect() {
  310. return specify();
  311. }
  312. function mock(implementation) {
  313. return expect().mock(implementation);
  314. }
  315. function stub() {
  316. return expect();
  317. }
  318. function parseTimes(expression) {
  319. var result = 0;
  320. if("number" == typeof expression) {
  321. result = expression;
  322. } else if("string" == typeof expression) {
  323. var parts = expression.split(" ");
  324. result = parseInt(parts[0]);
  325. }
  326. return result;
  327. }
  328. function reportAll(fullName) {
  329. var reports = [];
  330. for(var i=0; i<specifications.length; i++) {
  331. reports.push(report(specifications[i], fullName));
  332. }
  333. return reports;
  334. }
  335. function report(specification, fullName) {
  336. if(specification == null) {
  337. if(specifications.length == 0) {
  338. var spec = specify().never();
  339. for(var i=0; i<invocations.length; i++) {
  340. spec.invoke();
  341. }
  342. }
  343. specification = specifications[0];
  344. }
  345. var report = {};
  346. report.expected = specification.invocations().expected;
  347. report.actual = specification.invocations().actual;
  348. report.success = specification.testTimes(report.actual);
  349. report.fail = !report.success;
  350. if(report.fail) {
  351. report.message = "Expectation failed: " + specification.describe(fullName);
  352. }
  353. return report;
  354. }
  355. function generateReportMessage(report, fullName, argumentsDisplay) {
  356. return report.messageParts.template
  357. .replace("{name}",fullName)
  358. .replace("{arguments}",argumentsDisplay)
  359. .replace("{quantifier}",report.messageParts.quantifier)
  360. .replace("{expected}",report.expected)
  361. .replace("{actual}",report.actual);
  362. }
  363. function getArgumentsDisplay(expectation) {
  364. if(expectation == null) {
  365. return "";
  366. }
  367. var displayValues = [];
  368. var constraints = expectation._argumentConstraints;
  369. if(constraints == null) {
  370. return "";
  371. } else {
  372. for(var i=0; i<constraints.length; i++) {
  373. if(constraints[i] != null) {
  374. displayValues.push(constraints[i][0].display);
  375. } else {
  376. displayValues.push('[any]');
  377. }
  378. }
  379. return displayValues.join(', ');
  380. }
  381. }
  382. function getArguments() {
  383. return invocations[0].getArgumentValues();
  384. }
  385. } // END FunctionGrab()
  386. /**
  387. *
  388. */
  389. function ObjectGrab(objectName, grabbedObject) {
  390. var grabs = {};
  391. init();
  392. return {
  393. 'examine': getGrab,
  394. 'report': report,
  395. 'getGrab': getGrab,
  396. 'getGrabs': function() { return grabs },
  397. 'reset': reset
  398. };
  399. function init() {
  400. for(key in grabbedObject) {
  401. var property = grabbedObject[key];
  402. if("function" == typeof property) {
  403. grabs[key] = new FunctionGrab(key, property, grabbedObject);
  404. }
  405. }
  406. }
  407. function report(name) {
  408. var allReports = [];
  409. for(var g in grabs) {
  410. var reports = grabs[g].reportAll(name+"."+grabs[g].name());
  411. for(var i=0; i<reports.length; i++) {
  412. allReports.push(reports[i]);
  413. }
  414. }
  415. return allReports;
  416. }
  417. function getGrab(name) {
  418. return grabs[name];
  419. }
  420. function reset() {
  421. for(var g in grabs) {
  422. grabs[g].reset();
  423. }
  424. }
  425. }
  426. /**
  427. *
  428. */
  429. function Environment() {
  430. var reportingEnabled = true;
  431. init();
  432. return {
  433. 'isJSSpec': isJSSpec,
  434. 'isScriptaculous': isScriptaculous,
  435. 'isQunit': isQunit,
  436. 'isJsTestDriver': isJsTestDriver,
  437. 'isYuiTest': isYuiTest,
  438. 'report': report,
  439. 'disableReporting': function() { reportingEnabled = false; },
  440. 'enableReporting': function() { reportingEnabled = true; },
  441. 'reset': function() {}
  442. }
  443. function init() {
  444. }
  445. function isJSSpec() {
  446. return window.JSSpec != null;
  447. }
  448. function isScriptaculous() {
  449. return window.Test != null && window.Test.Unit != null && window.Test.Unit.Runner != null;
  450. }
  451. function isQunit() {
  452. return window.QUnit != null;
  453. }
  454. function isJsTestDriver() {
  455. return window.jstestdriver != null;
  456. }
  457. function isYuiTest() {
  458. var y = window.YAHOO;
  459. return y != null && y.tool != null && y.tool.TestCase != null;
  460. }
  461. function report(message) {
  462. if(!reportingEnabled) { return; }
  463. if(isYuiTest()) {
  464. YAHOO.util.Assert.fail(message);
  465. } else if(isJsTestDriver()) {
  466. fail(message);
  467. } else if(isScriptaculous()) {
  468. throw new Error(message);
  469. } else if(isQunit()) {
  470. ok(false, message);
  471. } else if(isJSSpec()) {
  472. throw new Error(message);
  473. }
  474. }
  475. }
  476. /**
  477. *
  478. */
  479. function Util() {
  480. return {
  481. 'displayValue': displayValue
  482. }
  483. function displayValue() {
  484. var value = arguments[0];
  485. var prefix = "";
  486. if(arguments.length > 1) {
  487. value = arguments[1];
  488. prefix = arguments[0];
  489. }
  490. if(value == undefined) {
  491. return displayValueNullOrUndefined(value);
  492. }
  493. var display = displayValueDefault(value);
  494. if('string' == typeof value) {
  495. display = displayValueString(value);
  496. } else if(value.constructor == Array) {
  497. display = displayValueArray(value);
  498. } else if(value.constructor == RegExp) {
  499. display = displayValueRegExp(value);
  500. } else if('object' == typeof value) {
  501. display = displayValueObject(value);
  502. }
  503. return prefix + display;
  504. }
  505. function displayValueDefault(value) {
  506. return value.toString();
  507. }
  508. function displayValueString(value) {
  509. return "'" + value + "'";
  510. }
  511. function displayValueArray(value) {
  512. var displayValues = [];
  513. for(var i=0; i<value.length; i++) {
  514. displayValues.push(displayValue(value[i]));
  515. }
  516. return "[" + displayValues.join(",") + "]";
  517. }
  518. function displayValueNullOrUndefined(value) {
  519. if(value === undefined) {
  520. return "undefined";
  521. } else if(value === null) {
  522. return "null";
  523. }
  524. }
  525. function displayValueRegExp(value) {
  526. return value.toString();
  527. }
  528. function displayValueObject(value) {
  529. var keyValues = [];
  530. for(var p in value) {
  531. keyValues.push(p + ':' + displayValue(value[p]));
  532. }
  533. return '{' + keyValues.join(',') + '}';
  534. }
  535. }
  536. /**
  537. *
  538. */
  539. function FunctionSpecification() {
  540. var constraints = null;
  541. var argumentValues = [];
  542. var mockImplementation = null;
  543. var timing = {actual: 0, expected: 1, modifier: 0};
  544. var api = createApi();
  545. return api;
  546. function createApi() {
  547. var api = {};
  548. mixinMatchers(api);
  549. mixinTiming(api);
  550. api.test = test;
  551. api.testTimes = testTimes;
  552. api.satisfies = satisfies;
  553. api.invoke = invoke;
  554. api.mock = mock;
  555. api.stub = stub;
  556. api.returnValue = returnValue;
  557. api.returnValues = returnValues;
  558. api.describe = describe;
  559. api.invocations = invocations;
  560. api.getArgumentValues = getArgumentValues;
  561. api.hasMockImplementation = hasMockImplementation;
  562. return api;
  563. }
  564. function mixinMatchers(api) {
  565. api.whereArgument = function(argIndex) {
  566. var collected = {};
  567. for(var name in jack.matchers) {
  568. addMatcher(argIndex, name, collected)
  569. }
  570. return collected;
  571. }
  572. api.withArguments = function() {
  573. for(var i=0; i<arguments.length; i++) {
  574. api.whereArgument(i).is(arguments[i]);
  575. }
  576. return api;
  577. }
  578. api.withNoArguments = function() { constraints = []; return api; }
  579. return api;
  580. function addMatcher(argIndex, name, collection) {
  581. collection[name] = function() {
  582. addConstraint(argIndex, jack.matchers[name], arguments);
  583. if(name == "is") {
  584. addArgumentValue(argIndex, arguments[0]);
  585. }
  586. return api;
  587. }
  588. }
  589. }
  590. function mixinTiming(api) {
  591. api.exactly = function(times) {
  592. timing.expected = parseTimes(times);
  593. return api;
  594. }
  595. api.once = function() {
  596. timing.expected = 1;
  597. return api;
  598. }
  599. api.atLeast = function(times) {
  600. timing.expected = parseTimes(times);
  601. timing.modifier = 1;
  602. return api;
  603. }
  604. api.atMost = function(times) {
  605. timing.expected = parseTimes(times);
  606. timing.modifier = -1;
  607. return api;
  608. }
  609. api.never = function() {
  610. timing.expected = 0;
  611. return api;
  612. }
  613. function parseTimes(times) {
  614. return parseInt(times);
  615. }
  616. }
  617. function addArgumentValue(index, value) {
  618. argumentValues[index] = value;
  619. }
  620. function addConstraint(argIndex, matcher, matcherArguments) {
  621. createConstraintsArrayIfNull(argIndex);
  622. var constraint = function(value) {
  623. var allArguments = [value];
  624. for(var i=0; i<matcherArguments.length; i++) {
  625. allArguments.push(matcherArguments[i]);
  626. }
  627. var test = matcher.apply(null, allArguments);
  628. return test.result;
  629. }
  630. constraints[argIndex].push(constraint);
  631. constraints[argIndex].describe = function() {
  632. var allArguments = [""];
  633. for(var i=0; i<matcherArguments.length; i++) {
  634. allArguments.push(matcherArguments[i]);
  635. }
  636. return matcher.apply(null, allArguments).expected;
  637. }
  638. }
  639. function createConstraintsArrayIfNull(argIndex) {
  640. if(constraints == null) {
  641. constraints = [];
  642. }
  643. if(constraints[argIndex] == null) {
  644. constraints[argIndex] = [];
  645. }
  646. }
  647. function test() {
  648. var result = true;
  649. if(constraints != null) {
  650. if(constraints.length != arguments.length) {
  651. result = false;
  652. } else {
  653. for (var i = 0; i < constraints.length; i++) {
  654. var oneArgumentsConstraints = constraints[i];
  655. if (oneArgumentsConstraints != null) {
  656. for (var j = 0; j < oneArgumentsConstraints.length; j++) {
  657. var constraint = oneArgumentsConstraints[j];
  658. if (constraint && !constraint(arguments[i])) {
  659. result = false;
  660. }
  661. }
  662. }
  663. }
  664. }
  665. }
  666. return result;
  667. }
  668. function testTimes(times) {
  669. if(timing.modifier == 0) {
  670. return times == timing.expected;
  671. } else if(timing.modifier == 1) {
  672. return times >= timing.expected;
  673. } else if(timing.modifier == -1) {
  674. return times <= timing.expected;
  675. }
  676. }
  677. function satisfies(other) {
  678. return other.test.apply(this, argumentValues);
  679. }
  680. function invoke() {
  681. timing.actual++;
  682. if(mockImplementation != null) {
  683. return mockImplementation.apply(this, arguments);
  684. }
  685. }
  686. function mock(implementation) {
  687. mockImplementation = implementation;
  688. return api;
  689. }
  690. function stub() {
  691. mockImplementation = function() {};
  692. return api;
  693. }
  694. function returnValue(value) {
  695. mockImplementation = function() {
  696. return value;
  697. }
  698. }
  699. function returnValues() {
  700. var values = [], orig = this;
  701. for (var i = 0, len = arguments.length; i < len; i++) { values.push(arguments[i]); }
  702. mockImplementation = function() {
  703. return values.shift();
  704. };
  705. }
  706. function hasMockImplementation() {
  707. return mockImplementation != null;
  708. }
  709. function invocations() {
  710. return {
  711. actual: timing.actual,
  712. expected: timing.expected
  713. };
  714. }
  715. function getArgumentValues() {
  716. return argumentValues;
  717. }
  718. function describe(name) {
  719. return name +"(" + describeConstraints() + ") " + describeTimes();
  720. }
  721. function describeConstraints() {
  722. if(constraints == null) {
  723. return "";
  724. }
  725. var descriptions = [];
  726. for(var i=0; i<constraints.length; i++) {
  727. if(constraints[i] != null) {
  728. descriptions.push(constraints[i].describe());
  729. } else {
  730. descriptions.push("[any]");
  731. }
  732. }
  733. return descriptions.join(", ");
  734. }
  735. function describeTimes() {
  736. var description = timing.expected;
  737. if(timing.expected == 1) {
  738. description += " time";
  739. } else {
  740. description += " times";
  741. }
  742. if(timing.modifier == 0) {
  743. description = "expected exactly " + description;
  744. } else if(timing.modifier > 0) {
  745. description = "expected at least " + description;
  746. } else if(timing.modifier < 0) {
  747. description = "expected at most " + description;
  748. }
  749. description += ", called " + timing.actual + " time";
  750. if(timing.actual != 1) {
  751. description += "s";
  752. }
  753. return description;
  754. }
  755. }
  756. /**
  757. *
  758. */
  759. function Matchers() {
  760. return {
  761. 'is':
  762. function(a, b) {
  763. return result(a==b, a, '', b);
  764. },
  765. 'isNot':
  766. function(a, b) {
  767. return result(a!=b, a, 'not:', b);
  768. },
  769. 'isType':
  770. function(a, b) {
  771. return result(b == typeof a, a, 'type:', b);
  772. },
  773. 'matches':
  774. function(a, b) {
  775. return result(b.test(a), a, 'matching:', b)
  776. },
  777. 'hasProperty':
  778. function(a, b, c) {
  779. var match = c ? a[b]==c : a[b]!=undefined;
  780. var bDisplay = b;
  781. if(c != null) {
  782. bDisplay = {};
  783. bDisplay[b] = c;
  784. }
  785. return result(match, a, 'property:', bDisplay)
  786. },
  787. 'hasProperties':
  788. function(a, b) {
  789. var match = true;
  790. for(var p in b) {
  791. if(a[p] != b[p]) {
  792. match = false;
  793. }
  794. }
  795. return result(match, a, 'properties:', b);
  796. },
  797. 'isGreaterThan':
  798. function(a, b) {
  799. return result(b < a, a, '>', b);
  800. },
  801. 'isLessThan':
  802. function(a, b) {
  803. return result(b > a, a, '<', b);
  804. },
  805. 'isOneOf':
  806. function() {
  807. var a = arguments[0];
  808. var b = [];
  809. for(var i=1; i<arguments.length; i++) {
  810. b.push(arguments[i]);
  811. }
  812. var match = false;
  813. for(var i=0; i<b.length; i++) {
  814. if(b[i] == a) {
  815. match = true;
  816. }
  817. }
  818. return result(match, a, 'oneOf:', b);
  819. }
  820. }
  821. function result(match, actual, prefix, expected) {
  822. return {
  823. result: match,
  824. actual: jack.util.displayValue(actual),
  825. expected: jack.util.displayValue(prefix, expected)
  826. }
  827. }
  828. }
  829. })(); // END HIDING FROM GLOBAL SCOPE