Add unit test for assertions

This commit is contained in:
Bán Dénes 2021-05-22 19:06:57 +02:00
parent c7b86c7556
commit 9baae154cb
7 changed files with 94 additions and 17 deletions

View file

@ -11,7 +11,7 @@ const anchor = module.exports = (raw, name, points={}, check_unexpected=true, de
} }
return current return current
} }
if (check_unexpected) a.detect_unexpected(raw, name, ['ref', 'orient', 'shift', 'rotate', 'affect']) if (check_unexpected) a.unexpected(raw, name, ['ref', 'orient', 'shift', 'rotate', 'affect'])
let point = default_point.clone() let point = default_point.clone()
if (raw.ref !== undefined) { if (raw.ref !== undefined) {
if (a.type(raw.ref)() == 'array') { if (a.type(raw.ref)() == 'array') {

View file

@ -29,7 +29,7 @@ const sane = exports.sane = (val, name, _type) => units => {
return val return val
} }
const detect_unexpected = exports.detect_unexpected = (obj, name, expected) => { const unexpected = exports.unexpected = (obj, name, expected) => {
const sane_obj = sane(obj, name, 'object')() const sane_obj = sane(obj, name, 'object')()
for (const key of Object.keys(sane_obj)) { for (const key of Object.keys(sane_obj)) {
assert(expected.includes(key), `Unexpected key "${key}" within field "${name}"!`) assert(expected.includes(key), `Unexpected key "${key}" within field "${name}"!`)

View file

@ -57,7 +57,7 @@ exports.parse = (config, outlines, units) => {
} }
const part_qname = `cases.${case_name}.${part_name}` const part_qname = `cases.${case_name}.${part_name}`
const part_var = `${case_name}__part_${part_name}` const part_var = `${case_name}__part_${part_name}`
a.detect_unexpected(part, part_qname, ['type', 'name', 'extrude', 'shift', 'rotate', 'operation']) a.unexpected(part, part_qname, ['type', 'name', 'extrude', 'shift', 'rotate', 'operation'])
const type = a.in(part.type || 'outline', `${part_qname}.type`, ['outline', 'case']) const type = a.in(part.type || 'outline', `${part_qname}.type`, ['outline', 'case'])
const name = a.sane(part.name, `${part_qname}.name`, 'string')() const name = a.sane(part.name, `${part_qname}.name`, 'string')()
const shift = a.numarr(part.shift || [0, 0, 0], `${part_qname}.shift`, 3)(units) const shift = a.numarr(part.shift || [0, 0, 0], `${part_qname}.shift`, 3)(units)

View file

@ -37,10 +37,10 @@ const layout = exports._layout = (config = {}, points = {}, units = {}) => {
const parsed_glue = u.deepcopy(a.sane(config, 'outlines.glue', 'object')()) const parsed_glue = u.deepcopy(a.sane(config, 'outlines.glue', 'object')())
for (let [gkey, gval] of Object.entries(parsed_glue)) { for (let [gkey, gval] of Object.entries(parsed_glue)) {
a.detect_unexpected(gval, `outlines.glue.${gkey}`, ['top', 'bottom', 'waypoints', 'extra']) a.unexpected(gval, `outlines.glue.${gkey}`, ['top', 'bottom', 'waypoints', 'extra'])
for (const y of ['top', 'bottom']) { for (const y of ['top', 'bottom']) {
a.detect_unexpected(gval[y], `outlines.glue.${gkey}.${y}`, ['left', 'right']) a.unexpected(gval[y], `outlines.glue.${gkey}.${y}`, ['left', 'right'])
gval[y].left = make_anchor(gval[y].left, `outlines.glue.${gkey}.${y}.left`, points) gval[y].left = make_anchor(gval[y].left, `outlines.glue.${gkey}.${y}.left`, points)
if (a.type(gval[y].right)(units) != 'number') { if (a.type(gval[y].right)(units) != 'number') {
gval[y].right = make_anchor(gval[y].right, `outlines.glue.${gkey}.${y}.right`, points) gval[y].right = make_anchor(gval[y].right, `outlines.glue.${gkey}.${y}.right`, points)
@ -51,7 +51,7 @@ const layout = exports._layout = (config = {}, points = {}, units = {}) => {
let wi = 0 let wi = 0
gval.waypoints = gval.waypoints.map(w => { gval.waypoints = gval.waypoints.map(w => {
const name = `outlines.glue.${gkey}.waypoints[${++wi}]` const name = `outlines.glue.${gkey}.waypoints[${++wi}]`
a.detect_unexpected(w, name, ['percent', 'width']) a.unexpected(w, name, ['percent', 'width'])
w.percent = a.sane(w.percent, name + '.percent', 'number')(units) w.percent = a.sane(w.percent, name + '.percent', 'number')(units)
w.width = a.wh(w.width, name + '.width')(units) w.width = a.wh(w.width, name + '.width')(units)
return w return w
@ -67,7 +67,7 @@ const layout = exports._layout = (config = {}, points = {}, units = {}) => {
// Layout params sanitization // Layout params sanitization
a.detect_unexpected(params, `${export_name}`, expected.concat(['side', 'tags', 'glue', 'size', 'corner', 'bevel', 'bound'])) a.unexpected(params, `${export_name}`, expected.concat(['side', 'tags', 'glue', 'size', 'corner', 'bevel', 'bound']))
const size = a.wh(params.size, `${export_name}.size`)(units) const size = a.wh(params.size, `${export_name}.size`)(units)
const relative_units = prep.extend({ const relative_units = prep.extend({
sx: size[0], sx: size[0],
@ -216,7 +216,7 @@ const layout = exports._layout = (config = {}, points = {}, units = {}) => {
} }
exports.parse = (config = {}, points = {}, units = {}) => { exports.parse = (config = {}, points = {}, units = {}) => {
a.detect_unexpected(config, 'outline', ['glue', 'exports']) a.unexpected(config, 'outline', ['glue', 'exports'])
const layout_fn = layout(config.glue, points, units) const layout_fn = layout(config.glue, points, units)
const outlines = {} const outlines = {}
@ -249,7 +249,7 @@ exports.parse = (config = {}, points = {}, units = {}) => {
arg = layout_fn(part, name, expected) arg = layout_fn(part, name, expected)
break break
case 'rectangle': case 'rectangle':
a.detect_unexpected(part, name, expected.concat(['ref', 'shift', 'rotate', 'size', 'corner', 'bevel', 'mirror'])) a.unexpected(part, name, expected.concat(['ref', 'shift', 'rotate', 'size', 'corner', 'bevel', 'mirror']))
const size = a.wh(part.size, `${name}.size`)(units) const size = a.wh(part.size, `${name}.size`)(units)
const rec_units = prep.extend({ const rec_units = prep.extend({
sx: size[0], sx: size[0],
@ -271,7 +271,7 @@ exports.parse = (config = {}, points = {}, units = {}) => {
} }
break break
case 'circle': case 'circle':
a.detect_unexpected(part, name, expected.concat(['ref', 'shift', 'rotate', 'radius', 'mirror'])) a.unexpected(part, name, expected.concat(['ref', 'shift', 'rotate', 'radius', 'mirror']))
anchor = make_anchor(part, name, points, false)(units) anchor = make_anchor(part, name, points, false)(units)
const radius = a.sane(part.radius, `${name}.radius`, 'number')(units) const radius = a.sane(part.radius, `${name}.radius`, 'number')(units)
const circle_mirror = a.sane(part.mirror || false, `${name}.mirror`, 'boolean')() const circle_mirror = a.sane(part.mirror || false, `${name}.mirror`, 'boolean')()
@ -285,7 +285,7 @@ exports.parse = (config = {}, points = {}, units = {}) => {
} }
break break
case 'polygon': case 'polygon':
a.detect_unexpected(part, name, expected.concat(['points', 'mirror'])) a.unexpected(part, name, expected.concat(['points', 'mirror']))
const poly_points = a.sane(part.points, `${name}.points`, 'array')() const poly_points = a.sane(part.points, `${name}.points`, 'array')()
const poly_mirror = a.sane(part.mirror || false, `${name.mirror}`, 'boolean')() const poly_mirror = a.sane(part.mirror || false, `${name.mirror}`, 'boolean')()
const parsed_points = [] const parsed_points = []
@ -309,7 +309,7 @@ exports.parse = (config = {}, points = {}, units = {}) => {
} }
break break
case 'outline': case 'outline':
a.detect_unexpected(part, name, expected.concat(['name', 'fillet'])) a.unexpected(part, name, expected.concat(['name', 'fillet']))
a.assert(outlines[part.name], `Field "${name}.name" does not name an existing outline!`) a.assert(outlines[part.name], `Field "${name}.name" does not name an existing outline!`)
const fillet = a.sane(part.fillet || 0, `${name}.fillet`, 'number')(units) const fillet = a.sane(part.fillet || 0, `${name}.fillet`, 'number')(units)
arg = u.deepcopy(outlines[part.name]) arg = u.deepcopy(outlines[part.name])

View file

@ -148,7 +148,7 @@ const footprint = exports._footprint = (config, name, points, point, net_indexer
if (config === false) return '' if (config === false) return ''
// config sanitization // config sanitization
a.detect_unexpected(config, name, ['type', 'anchor', 'nets', 'params']) a.unexpected(config, name, ['type', 'anchor', 'nets', 'params'])
const type = a.in(config.type, `${name}.type`, Object.keys(footprint_types)) const type = a.in(config.type, `${name}.type`, Object.keys(footprint_types))
let anchor = make_anchor(config.anchor || {}, `${name}.anchor`, points, true, point)(units) let anchor = make_anchor(config.anchor || {}, `${name}.anchor`, points, true, point)(units)
const nets = a.sane(config.nets || {}, `${name}.nets`, 'object')() const nets = a.sane(config.nets || {}, `${name}.nets`, 'object')()
@ -210,7 +210,7 @@ exports.parse = (config, points, outlines, units) => {
for (const [pcb_name, pcb_config] of Object.entries(pcbs)) { for (const [pcb_name, pcb_config] of Object.entries(pcbs)) {
// config sanitization // config sanitization
a.detect_unexpected(pcb_config, `pcbs.${pcb_name}`, ['outlines', 'footprints']) a.unexpected(pcb_config, `pcbs.${pcb_name}`, ['outlines', 'footprints'])
// outline conversion // outline conversion
if (a.type(pcb_config.outlines)() == 'array') { if (a.type(pcb_config.outlines)() == 'array') {

View file

@ -19,7 +19,7 @@ const render_zone = exports._render_zone = (zone_name, zone, anchor, global_key,
// zone-wide sanitization // zone-wide sanitization
a.detect_unexpected(zone, `points.zones.${zone_name}`, ['columns', 'rows', 'key']) a.unexpected(zone, `points.zones.${zone_name}`, ['columns', 'rows', 'key'])
// the anchor comes from "above", because it needs other zones too (for references) // the anchor comes from "above", because it needs other zones too (for references)
const cols = a.sane(zone.columns || {}, `points.zones.${zone_name}.columns`, 'object')() const cols = a.sane(zone.columns || {}, `points.zones.${zone_name}.columns`, 'object')()
const zone_wide_rows = a.sane(zone.rows || {}, `points.zones.${zone_name}.rows`, 'object')() const zone_wide_rows = a.sane(zone.rows || {}, `points.zones.${zone_name}.rows`, 'object')()
@ -47,7 +47,7 @@ const render_zone = exports._render_zone = (zone_name, zone, anchor, global_key,
col = col || {} col = col || {}
a.detect_unexpected( a.unexpected(
col, col,
`points.zones.${zone_name}.columns.${col_name}`, `points.zones.${zone_name}.columns.${col_name}`,
['stagger', 'spread', 'rotate', 'origin', 'rows', 'row_overrides', 'key'] ['stagger', 'spread', 'rotate', 'origin', 'rows', 'row_overrides', 'key']
@ -229,7 +229,7 @@ exports.parse = (config = {}) => {
} }
// config sanitization // config sanitization
a.detect_unexpected(config, 'points', ['units', 'zones', 'key', 'rotate', 'mirror']) a.unexpected(config, 'points', ['units', 'zones', 'key', 'rotate', 'mirror'])
const zones = a.sane(config.zones || {}, 'points.zones', 'object')() const zones = a.sane(config.zones || {}, 'points.zones', 'object')()
const global_key = a.sane(config.key || {}, 'points.key', 'object')() const global_key = a.sane(config.key || {}, 'points.key', 'object')()
const global_rotate = a.sane(config.rotate || 0, 'points.rotate', 'number')(units) const global_rotate = a.sane(config.rotate || 0, 'points.rotate', 'number')(units)

77
test/unit/assert.js Normal file
View file

@ -0,0 +1,77 @@
const a = require('../../src/assert')
describe('Assert', function() {
it('mathnum', function() {
a.mathnum('1')().should.equal(1)
a.mathnum('1 + 2')().should.equal(3)
a.mathnum('nope').should.throw('symbol')
})
it('assert', function() {
a.assert.bind(this, false, 'msg').should.throw('msg')
a.assert.bind(this, true, 'msg').should.not.throw('msg')
})
it('type', function() {
// a more complete `typeof` operator
a.type(undefined)().should.equal('undefined')
a.type(null)().should.equal('null')
a.type(false)().should.equal('boolean')
a.type(0)().should.equal('number')
a.type(3.14)().should.equal('number')
a.type('arst')().should.equal('string')
a.type('1 + 2')().should.equal('number') // formulas are also numbers here!
a.type('arst')({arst: 2}).should.equal('number') // and variables count, too!
a.type([])().should.equal('array')
a.type({})().should.equal('object')
})
it('sane', function() {
a.sane('arst', 'name', 'string')().should.equal('arst')
a.sane('arst', 'name', 'number').should.throw('name')
a.sane('arst', 'name', 'number')({arst: 2}).should.equal(2)
})
it('unexpected', function() {
const good_keys = ['good']
a.unexpected.bind(this, [], 'name', good_keys).should.throw('object')
a.unexpected.bind(this, {}, 'name', good_keys).should.not.throw()
a.unexpected.bind(this, {good: true}, 'name', good_keys).should.not.throw()
a.unexpected.bind(this, {good: true, bad: true}, 'name', good_keys).should.throw('bad')
})
it('in', function() {
a.in('match', 'name', ['match']).should.equal('match')
a.in.bind(this, 'not.a.match', 'name', ['match']).should.throw('name')
})
it('arr', function() {
// non-arrays are bad
a.arr('val', 'name', 0, 'string', '').should.throw('array')
// arrays are good
a.arr(['val'], 'name', 0, 'string', '')().should.deep.equal(['val'])
// length check works
a.arr(['val'], 'name', 2, 'string', '').should.throw('length')
// defaults get filled
a.arr([undefined, 'val'], 'name', 2, 'string', 'def')().should.deep.equal(['def', 'val'])
// mathnums are supported
a.arr(['1 + 2'], 'name', 0, 'number', '')().should.deep.equal([3])
// arr derivatives
a.strarr(['val'], 'name').should.deep.equal(a.arr(['val'], 'name', 0, 'string', '')())
a.numarr([1], 'name', 1)().should.deep.equal(a.arr([1], 'name', 1, 'number', 0)())
a.xy([1, 2], 'name')().should.deep.equal(a.arr([1, 2], 'name', 2, 'number', 0)())
// wh adds array expansion
a.wh([1, 2], 'name')().should.deep.equal(a.arr([1, 2], 'name', 2, 'number', 0)())
a.wh(1, 'name')().should.deep.equal(a.arr([1, 1], 'name', 2, 'number', 0)())
// trbl adds 1->4 and 2->4 array expansions
a.trbl([1, 2, 3, 4], 'name')().should.deep.equal(a.arr([1, 2, 3, 4], 'name', 4, 'number', 0)())
a.trbl(1, 'name')().should.deep.equal(a.arr([1, 1, 1, 1], 'name', 4, 'number', 0)())
// the 2->4 is "inverted", because 2 number usually mean x,y, so the first is the horizontal
// while for 4, it start with top, which is vertical
a.trbl([1, 2], 'name')().should.deep.equal(a.arr([2, 1, 2, 1], 'name', 4, 'number', 0)())
})
})