123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273 |
- /**
- * Module dependencies
- */
- var util = require('util');
- var assert = require('assert');
- var _ = require('@sailshq/lodash');
- var rttc = require('../');
- describe('.intersection()', function() {
- // ┌─┐┬─┐ ┬┌┬┐┬ ┬┬─┐┌─┐┌─┐
- // ├┤ │┌┴┬┘ │ │ │├┬┘├┤ └─┐
- // └ ┴┴ └─ ┴ └─┘┴└─└─┘└─┘
- // Fixtures
- var LYDIA = {
- id: 102432,
- name: 'Lydia Villa-Komaroff',
- age: 68,
- meta: '===',
- coordinates: { x: 10, y: -4 },
- friends: [
- {
- id: 93825,
- name: 'José Orozco',
- age: 65,
- meta: '===',
- coordinates: { x: -391, y: 47.3295 }
- }
- ]
- };
- // Shortcut used below for convenience:
- var given = function (exemplar0, exemplar1){
- return {
- expect: function (expectedResult){
- // Perform the standard, usual call to `rttc.intersection()`
- // (using exemplars rather than type schemas and with `strict` set to `false`)
- var actualResult = rttc.intersection(exemplar0, exemplar1, true, false);
- assert.deepEqual(expectedResult, actualResult);
- }
- };
- };
- // ┌┬┐┌─┐┌─┐┌┬┐┌─┐
- // │ ├┤ └─┐ │ └─┐
- // ┴ └─┘└─┘ ┴ └─┘
- describe('using exemplars & loose validation rules', function() {
- // Types always intersect with themselves, with an identity result.
- describe('when intersected with the same type', function (){
- describe('should result in an exemplar with the same type schema', function (){
- // "string" ∩ "string" <====> "string"
- it('"string" ∩ "string"', function (){
- given('foo', 'bar').expect('bar');
- given('bar', 'foo').expect('foo');
- });
- // "number" ∩ "number" <====> "number"
- it('"number" ∩ "number"', function (){
- given(-9, 32).expect(32);
- given(32, -9).expect(-9);
- });
- // "boolean" ∩ "boolean" <====> "boolean"
- it('"boolean" ∩ "boolean"', function (){
- given(true, true).expect(true);
- given(false, false).expect(false);
- given(false, true).expect(true);
- given(true, false).expect(false);
- });
- // "lamda" ∩ "lamda" <====> "lamda"
- it('"lamda" ∩ "lamda"', function (){
- given('->', '->').expect('->');
- });
- // Generic dictionary exemplars
- it('Generic dictionary exemplars', function (){
- given({}, {}).expect({});
- });
- // "json" ∩ "json" <====> "json"
- it('"json" ∩ "json"', function (){
- given('*', '*').expect('*');
- });
- // "ref" ∩ "ref" <====> "ref"
- it('"ref" ∩ "ref"', function (){
- given('===', '===').expect('===');
- });
- // "Generic array" exemplars (for compatibility)
- // [] ∩ []
- // -AKA- <====> ["*"]
- // ["*"] ∩ ["*"]
- it('"Generic array" exemplars (for compatibility)', function (){
- given([], []).expect([]);
- given([], ['*']).expect(['*']);
- given(['*'], []).expect(['*']);
- given(['*'], ['*']).expect(['*']);
- });
- // Array exemplars (i.e. patterned arrays)
- // [...] ∩ [...] <====> [...]
- it('Array exemplars (i.e. patterned arrays, `[...]`)', function (){
- given(['==='], ['===']).expect(['===']);
- });
- // Faceted dictionary exemplars
- // {...} ∩ {...} <====> {...}
- it('Faceted dictionary exemplars (`{...}`)', function (){
- given(LYDIA, LYDIA).expect(LYDIA);
- });
- });//</should result in an exemplar with the same type schema>
- });//</when intersected with the same type>
- // Every type intersects with "ref", with an identity result.
- describe('when intersected with "ref"', function (){
- // Simple helper used below for convenience/conciseness.
- var testVsRef = function (exemplar){
- given(exemplar, '===').expect(exemplar);
- given('===', exemplar).expect(exemplar);
- };
- describe('every type should result in an identity result', function (){
- it('"string" ∩ "ref" <====> "string"', function (){
- testVsRef('foo');
- });
- it('"number" ∩ "ref" <====> "number"', function (){
- testVsRef(-9);
- testVsRef(32);
- });
- it('"boolean" ∩ "ref" <====> "boolean"', function (){
- testVsRef(true);
- testVsRef(false);
- });
- it('"lamda" ∩ "ref" <====> "lamda"', function (){
- testVsRef('->');
- });
- it('"json" ∩ "ref" <====> "json"', function (){
- testVsRef('*');
- });
- it('{} ∩ "ref" <====> {}', function (){
- testVsRef({});
- });
- // "Generic array" exemplars (for compatibility)
- it(' [] ∩ "ref" <====> []', function (){
- testVsRef([]);
- });
- it('{...} ∩ "ref" <====> {...}', function (){
- testVsRef(LYDIA);
- });
- it('[...] ∩ "ref" <====> [...]', function (){
- testVsRef([LYDIA]);
- testVsRef(LYDIA.friends);
- });
- });//</every type should result in an identity result>
- });//</when intersected with "ref">
- // Now run the suite of tests in the specification directory (`spec/`).
- var TEST_SUITE = require('../spec/intersection.spec');
- _.each(TEST_SUITE, function (testDef){
- it('`'+util.inspect(testDef.e0, {depth: null})+'` ∩ `'+util.inspect(testDef.e1, {depth: null})+'`', function (){
- given(testDef.e0, testDef.e1).expect(testDef.result);
- });
- });
- // Additional notes:
- // Every type except "ref" and "lamda" intersects with "json", with an identity result.
- // "string" ∩ "json" <====> "string"
- // "number" ∩ "json" <====> "number"
- // "boolean" ∩ "json" <====> "boolean"
- // {} ∩ "json" <====> {}
- // [] ∩ "json" <====> []
- // {x:"string"} ∩ "json" <====> {x:"string"}
- // ["string"] ∩ "json" <====> ["string"]
- // Strings, numbers, booleans, and lamdas do not intersect with each other,
- // or with any sort of dictionary or array type.
- // "string" ∩ (anything else) <==/==> (ERROR)
- // "number" ∩ (anything else) <==/==> (ERROR)
- // "boolean" ∩ (anything else) <==/==> (ERROR)
- // "lamda" ∩ (anything else) <==/==> (ERROR)
- // Faceted dictionaries intersect with generic dictionaries, with an identity result.
- // {a:"string"} ∩ {} <====> {a:"string"}
- // {a:{}} ∩ {} <====> {a:{}}
- // Patterned arrays intersect with generic arrays, with an identity result.
- // ["string"] ∩ [] <====> ["string"]
- // [[{}]] ∩ [] <====> [[{}]]
- // [{}] ∩ ["string"] <====> ["string"]
- // Faceted dictionaries intersect with other faceted dictionaries as long as recursive
- // types also successfully intersect. The result is the merged schema.
- // (extra keys are ok, since they'll just be ignored)
- // {a:"string"} ∩ {a:"string",b:"string"} <====> {a:"string", b: "string"}
- // {x:"string"} ∩ {a:"string",b:"string"} <====> {a:"string", b: "string", x: "string"}
- // {x:"string", a:"number"} ∩ {a:"string",b:"string"} <==/=> (ERROR)
- // {x:"string", a:"json"} ∩ {a:"string",b:"string"} <====> {a:"string", b: "string", x: "string"}
- // Patterned arrays intersect with other patterned arrays as long as the recursive
- // types also successfully intersect. The result is the merged schema.
- // ["number"] ∩ ["json"] <====> ["number"]
- // ["number"] ∩ ["string"] <==/=> (ERROR)
- // [{a:"number"}] ∩ [{}] <====> [{a:"number"}]
- // Exceptions when NOT using strict validation:
- // "number" ∩ "string" <====> "number"
- // "boolean" ∩ "string" <====> "boolean"
- // "number" ∩ "boolean" <====> "boolean"
- // // Special cases:
- // describe('special cases', function (){
- // it('inside a generic dictionary keypath: should act like `json`', function (){
- // assert.deepEqual({ x: 'foo' }, intersection({ x: 'foo' }, {}));
- // assert.deepEqual({ x: 'foo' }, intersection({}, { x: 'foo' }));
- // });
- // it('inside a generic array keypath: should act like `json`', function (){
- // assert.deepEqual({ x: 'foo' }, intersection({ x: 'foo' }, []));
- // assert.deepEqual({ x: 'foo' }, intersection({ x: 'foo' }, ['*']));
- // assert.deepEqual({ x: 'foo' }, intersection([], { x: 'foo' }));
- // assert.deepEqual({ x: 'foo' }, intersection(['*'], { x: 'foo' }));
- // });
- // it('inside a JSON keypath: should act like `json`', function (){
- // assert.deepEqual({ x: 'foo' }, intersection({ x: 'foo' }, '*'));
- // assert.deepEqual({ x: 'foo' }, intersection('*', { x: 'foo' }));
- // });
- // it('inside a ref keypath: should act like `ref`', function (){
- // assert.deepEqual({ x: 'foo' }, intersection({ x: 'foo' }, '==='));
- // assert.deepEqual({ x: 'foo' }, intersection('===', { x: 'foo' }));
- // });
- // it('inside any other keypath: should throw an error', function (){
- // // TODO: come back to this
- // });
- // });//</special cases>
- });//</using exemplars & loose validation rules>
- });//</.intersection()>
|