/* eslint-disable import/namespace */ import * as spec from '.'; describe('style-spec', () => { ['v8', 'latest'].forEach((version) => { ['', 'min'].forEach((kind) => { const v = version + kind; test(v, () => { for (const k in spec[v]) { // Exception for version. if (k === '$version') { expect(typeof spec[v].$version).toBe('number'); } else { validSchema(k, v, spec[v][k], spec[v], version, kind); } } }); }); }); test('v8 Spec SDK Support section', () => { const v = 'v8'; const propObjs = [].concat(spec[v].paint).concat(spec[v].layout); propObjs.forEach((objKey) => { const props = spec[v][objKey]; const propKeys = Object.keys(props); propKeys.forEach((key) => { expect(props[key]['sdk-support']).toBeTruthy(); if (props[key]['sdk-support']) { expect(props[key]['sdk-support']['basic functionality']).toBeTruthy(); if (props[key]['property-type'].includes('constant')) { expect(props[key]['sdk-support']['data-driven styling']).toBeFalsy(); } else { expect(props[key]['sdk-support']['data-driven styling']).toBeTruthy(); } } }); }); const expressions = spec[v].expression_name.values; const expressionNames = Object.keys(expressions); expressionNames.forEach((expr) => { expect(expressions[expr]['sdk-support']).toBeTruthy(); if (expressions[expr]['sdk-support']) { expect(expressions[expr]['sdk-support']['basic functionality']).toBeTruthy(); } }); }); }); function validSchema(k, v, obj, ref, version, kind) { const scalar = ['boolean', 'string', 'number']; const types = Object.keys(ref).concat(['boolean', 'string', 'number', 'array', 'enum', 'color', '*', // new in v8 'opacity', 'translate-array', 'dash-array', 'offset-array', 'font-array', 'field-template', // new enums in v8 'line-cap-enum', 'line-join-enum', 'symbol-placement-enum', 'rotation-alignment-enum', 'text-justify-enum', 'text-anchor-enum', 'text-transform-enum', 'visibility-enum', 'property-type', 'formatted', 'resolvedImage', 'promoteId', 'padding', 'variableAnchorOffsetCollection', 'sprite' ]); const keys = [ 'default', 'doc', 'example', 'function', 'zoom-function', 'property-function', 'function-output', 'expression', 'property-type', 'length', 'min-length', 'required', 'transition', 'type', 'value', 'units', 'tokens', 'values', 'maximum', 'minimum', 'period', 'requires', 'sdk-support', 'overridable' ]; // Schema object. if (Array.isArray(obj.type) || typeof obj.type === 'string') { // schema must have only known keys for (const attr in obj) { expect(keys.indexOf(attr) !== -1).toBeTruthy(); } // schema type must be js native, 'color', or present in ref root object. expect(types.indexOf(obj.type) !== -1).toBeTruthy(); // schema type is an enum, it must have 'values' and they must be // objects (>=v8) or scalars (<=v7). If objects, check that doc key // (if present) is a string. if (obj.type === 'enum') { const values = (ref.$version >= 8 ? Object.keys(obj.values) : obj.values); expect(Array.isArray(values) && values.every((v) => { return scalar.indexOf(typeof v) !== -1; })).toBeTruthy(); if (ref.$version >= 8) { for (const v in obj.values) { if (Array.isArray(obj.values) === false) { // skips $root.version if (obj.values[v].doc !== undefined) { expect('string').toBe(typeof obj.values[v].doc); expect(kind).not.toBe('min'); } else { expect(v).not.toBe('latest'); } } } } } // schema type is array, it must have 'value' and it must be a type. if (obj.value !== undefined) { if (Array.isArray(obj.value)) { obj.value.forEach((i) => { expect(types.indexOf(i) !== -1).toBeTruthy(); }); } else if (typeof obj.value === 'object') { validSchema(`${k}.value`, v, obj.value, ref, undefined, undefined); } else { expect(types.indexOf(obj.value) !== -1).toBeTruthy(); } } // schema key doc checks if (obj.doc !== undefined) { expect('string').toBe(typeof obj.doc); expect(kind).not.toBe('min'); } else { expect(v).not.toBe('latest'); } // schema key example checks if (kind === 'min') { expect(obj.example).toBeDefined(); } // schema key function checks if (obj.function !== undefined) { expect(ref.$version < 8).toBeTruthy(); if (ref.$version >= 7) { expect(true).toBe(['interpolated', 'piecewise-constant'].indexOf(obj.function) >= 0); } else { expect('boolean').toBe(typeof obj.function); } } else if (obj.expression !== undefined) { const expression = obj.expression; expect(ref['property-type'][obj['property-type']]).toBeTruthy(); expect('boolean').toBe(typeof expression.interpolated); expect(true).toBe(Array.isArray(expression.parameters)); if (obj['property-type'] !== 'color-ramp') expect(true).toBe( expression.parameters.every(k => k === 'zoom' || k === 'feature' || k === 'feature-state') ); } // schema key required checks if (obj.required !== undefined) { expect('boolean').toBe(typeof obj.required); } // schema key transition checks if (obj.transition !== undefined) { expect('boolean').toBe(typeof obj.transition); } // schema key requires checks if (obj.requires !== undefined) { expect(true).toBe(Array.isArray(obj.requires)); } } else if (Array.isArray(obj)) { obj.forEach((child, j) => { if (typeof child === 'string' && scalar.indexOf(child) !== -1) return; validSchema(`${k}[${j}]`, v, typeof child === 'string' ? ref[child] : child, ref, undefined, undefined); }); // Container object. } else if (typeof obj === 'object') { for (const j in obj) validSchema(`${k}.${j}`, v, obj[j], ref, undefined, undefined); // Invalid ref object. } else { expect(false).toBeTruthy(); } }