ipld-schema-validator
Version:
IPLD Schema Validator
334 lines (298 loc) • 8.33 kB
JavaScript
/* eslint-env mocha */
import { create } from 'ipld-schema-validator'
import chai from 'chai'
import { lint } from './lint.js'
const { assert } = chai
const fauxCid = {}
fauxCid.asCID = fauxCid
describe('Unions', () => {
it('keyed', async () => {
const validator = create({
types: {
UnionKeyed: {
union: {
members: [
'Bool',
'Int',
'String'
],
representation: {
keyed: {
bar: 'Bool',
foo: 'Int',
baz: 'String'
}
}
}
}
}
}, 'UnionKeyed')
await lint(validator)
assert.isTrue(validator({ foo: 100 }))
assert.isTrue(validator({ bar: true }))
assert.isTrue(validator({ baz: 'yep' }))
assert.isFalse(validator({}))
assert.isFalse(validator({ foo: 'not an int' }))
assert.isFalse(validator({ bar: 'not a bool' }))
assert.isFalse(validator({ baz: true }))
})
it('kinded', async () => {
const validator = create({
types: {
Bar: { bool: {} },
Baz: { string: {} },
Foo: { int: {} },
UnionKinded: {
union: {
members: [
'Foo',
'Bar',
'Baz'
],
representation: {
kinded: {
int: 'Foo',
bool: 'Bar',
string: 'Baz'
}
}
}
}
}
}, 'UnionKinded')
await lint(validator)
assert.isTrue(validator(100))
assert.isTrue(validator(-100))
assert.isTrue(validator(true))
assert.isTrue(validator(false))
assert.isTrue(validator('yep'))
assert.isTrue(validator(''))
assert.isFalse(validator({}))
assert.isFalse(validator([]))
assert.isFalse(validator({ foo: 100 }))
assert.isFalse(validator({ bar: true }))
assert.isFalse(validator({ baz: 'yep' }))
})
describe('kinded complex', () => {
/**
* @param {{expectedType?: string}} link
*/
const run = async (link) => {
const validator = create({
types: {
mylist: {
list: {
valueType: 'String'
}
},
mymap: {
map: {
keyType: 'String',
valueType: 'Int'
}
},
UnionKinded: {
union: {
members: [
'mylist',
'mymap',
{ link }
],
representation: {
kinded: {
list: 'mylist',
map: 'mymap',
link: { link }
}
}
}
}
}
}, 'UnionKinded')
await lint(validator)
for (const obj of [null, 1.01, -0.1, 101, -101, 'a string', false, true, new Uint8Array(0), Uint8Array.from([1, 2, 3]), undefined]) {
assert.isFalse(validator(obj))
}
assert.isTrue(validator(fauxCid))
assert.isTrue(validator([]))
assert.isTrue(validator(['', 'a']))
assert.isFalse(validator(['', 1]))
assert.isFalse(validator([1, 2]))
assert.isTrue(validator({}))
assert.isTrue(validator({ a: 1, b: 2 }))
assert.isFalse(validator({ a: 'a', b: 2 }))
}
it('named link', async () => {
await run({ expectedType: 'MyLink' })
})
it('unnamed link', async () => {
await run({})
})
})
it('inline', async () => {
/*
type Bar struct {
bral String
}
type Foo struct {
froz Bool
}
type UnionInline union {
| Foo "foo"
| Bar "bar"
} representation inline {
discriminantKey "tag"
}
*/
const validator = create({
types: {
UnionInline: {
union: {
members: [
'Foo',
'Bar'
],
representation: {
inline: {
discriminantKey: 'tag',
discriminantTable: {
foo: 'Foo',
bar: 'Bar'
}
}
}
}
},
Foo: {
struct: {
fields: {
froz: { type: 'Bool' }
},
representation: { map: {} }
}
},
Bar: {
struct: {
fields: {
bral: { type: 'String' }
},
representation: { map: {} }
}
}
}
}, 'UnionInline')
await lint(validator)
const obj1 = { tag: 'foo', froz: true }
assert.isTrue(validator(obj1))
assert.deepEqual(obj1, { tag: 'foo', froz: true }) // unmolested
const obj2 = { tag: 'bar', bral: 'zot' }
assert.isTrue(validator(obj2))
assert.deepEqual(obj2, { tag: 'bar', bral: 'zot' }) // unmolested
assert.isFalse(validator({ froz: true }))
assert.isFalse(validator({ bral: 'zot' }))
assert.isFalse(validator({ tag: 'foo' }))
assert.isFalse(validator({ tag: 'bar' }))
assert.isFalse(validator({ tag: 'foo', bral: 'zot' }))
assert.isFalse(validator({ tag: 'bar', froz: true }))
assert.isFalse(validator({ tag: 'foo', froz: 'zot' }))
})
it('envelope', async () => {
/*
type Bar bool
type Baz string
type Foo int
type UnionEnvelope union {
| Foo "foo"
| Bar "bar"
| Baz "baz"
} representation envelope {
discriminantKey "bim"
contentKey "bam"
}
*/
const validator = create({
types: {
Bar: { bool: {} },
Baz: { string: {} },
Foo: { int: {} },
UnionEnvelope: {
union: {
members: [
'Foo',
'Bar',
'Baz'
],
representation: {
envelope: {
discriminantKey: 'bim',
contentKey: 'bam',
discriminantTable: {
foo: 'Foo',
bar: 'Bar',
baz: 'Baz'
}
}
}
}
}
}
}, 'UnionEnvelope')
await lint(validator)
assert.isTrue(validator({ bim: 'foo', bam: 100 }))
assert.isTrue(validator({ bim: 'bar', bam: true }))
assert.isTrue(validator({ bim: 'baz', bam: 'here be baz' }))
assert.isFalse(validator({ bim: 'foo' }))
assert.isFalse(validator({ bim: 'bar' }))
assert.isFalse(validator({ bim: 'baz' }))
assert.isFalse(validator({ bim: 'foo', bam: 'zot' }))
assert.isFalse(validator({ bim: 'bar', bam: 100 }))
assert.isFalse(validator({ bim: 'baz', bam: true }))
assert.isFalse(validator(100))
assert.isFalse(validator(true))
assert.isFalse(validator('here be string'))
assert.isFalse(validator({ }))
assert.isFalse(validator([]))
})
it('bytesprefix', async () => {
/*
type Bls12_381Signature bytes
type Secp256k1Signature bytes
type Signature union {
| Secp256k1Signature 0
| Bls12_381Signature 1
} representation bytesprefix
*/
const validator = create({
types: {
Bls12_381Signature: { bytes: {} },
Secp256k1Signature: { bytes: {} },
Signature: {
union: {
members: [
'Secp256k1Signature',
'Bls12_381Signature'
],
representation: {
bytesprefix: {
Secp256k1Signature: '0',
Bls12_381Signature: '1'
}
}
}
}
}
}, 'Signature')
await lint(validator)
for (const obj of [null, 1.01, -0.1, 101, -101, 'a string', false, true, {}, [], undefined]) {
assert.isFalse(validator(obj))
}
assert.isTrue(validator(Uint8Array.from([0, 1, 2, 3])))
assert.isTrue(validator(Uint8Array.from([0])))
assert.isTrue(validator(Uint8Array.from([1, 1, 2, 3])))
assert.isTrue(validator(Uint8Array.from([1])))
assert.isFalse(validator(Uint8Array.from([2, 1, 2, 3])))
assert.isFalse(validator(Uint8Array.from([2])))
assert.isFalse(validator(Uint8Array.from([0xff, 1, 2, 3])))
assert.isFalse(validator(Uint8Array.from([0xff])))
})
})