Skip to content

Commit

Permalink
Merge branch 'main' into optionalify
Browse files Browse the repository at this point in the history
  • Loading branch information
EvanHahn committed Sep 16, 2024
2 parents 4403044 + 3f44efb commit 0850932
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 39 deletions.
10 changes: 9 additions & 1 deletion src/lib/decode-conversions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ import { ProjectSettings_1_ConfigMetadata } from '../proto/projectSettings/v1.js
import { ProjectSettings } from '../schema/projectSettings.js'
import type { Position } from '../schema/observation.js'
import {
ensure,
assert,
ExhaustivenessError,
getVersionId,
VersionIdObject,
Expand All @@ -49,6 +49,14 @@ type ConvertFunction<TSchemaName extends SchemaName> = (
versionObj: VersionIdObject
) => FilterBySchemaName<MapeoDocDecode, TSchemaName>

function ensure(
condition: unknown,
objectName: string,
propertyName: string
): asserts condition {
assert(condition, `${objectName} missing required property ${propertyName}`)
}

export const convertProjectSettings: ConvertFunction<'projectSettings'> = (
message,
versionObj
Expand Down
14 changes: 12 additions & 2 deletions src/lib/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ export function getOwn<T extends object, K extends keyof T>(
return Object.hasOwn(obj, key) ? obj[key] : undefined
}

export function assert(condition: unknown, message: string): asserts condition {
if (!condition) throw new Error(message)
}

export class ExhaustivenessError extends Error {
constructor(value: never) {
super(`Exhaustiveness check failed. ${value} should be impossible`)
Expand Down Expand Up @@ -61,8 +65,14 @@ export type VersionIdObject = {
* @returns versionId string
*/
export function getVersionId({ coreDiscoveryKey, index }: VersionIdObject) {
ensure(coreDiscoveryKey.byteLength >= 32, 'versionId', 'coreDiscoveryKey')
ensure(Number.isSafeInteger(index) && index >= 0, 'versionId', 'index')
assert(
coreDiscoveryKey.byteLength >= 32,
'version ID core discovery key must be have at least 32 bytes'
)
assert(
Number.isSafeInteger(index) && index >= 0,
'version ID index must be a non-negative integer'
)
return coreDiscoveryKey.toString('hex') + '/' + index
}

Expand Down
19 changes: 19 additions & 0 deletions test/fixtures/bad-docs.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,25 @@ export const badDocs = [
deleted: false,
},
},
{
text: 'core ownership with empty core ID',
/** @type {import('../../dist/index.js').CoreOwnership} */
doc: {
docId: cachedValues.docId,
versionId: cachedValues.versionId,
originalVersionId: cachedValues.versionId,
schemaName: 'coreOwnership',
createdAt: cachedValues.createdAt,
updatedAt: cachedValues.updatedAt,
links: [],
deleted: false,
authCoreId: cachedValues.coreId,
configCoreId: '',
dataCoreId: cachedValues.coreId,
blobCoreId: cachedValues.coreId,
blobIndexCoreId: cachedValues.coreId,
},
},
{
text: 'role doc with empty roleId',
/** @type {import('../../dist/index.js').Role} */
Expand Down
67 changes: 31 additions & 36 deletions test/lib/utils.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,37 +2,11 @@
import assert from 'node:assert/strict'
import test from 'node:test'
import {
ensure,
ExhaustivenessError,
getOwn,
getVersionId,
} from '../../dist/lib/utils.js'

test('ensure', () => {
// These should not throw.
ensure(true, 'ignored', 'ignored')
ensure(123, 'ignored', 'ignored')

assert.throws(
() => ensure(false, 'ABC', 'XYZ'),
(err) => {
assert(err instanceof Error)
assert(err.message.includes('ABC'))
assert(err.message.includes('XYZ'))
return true
}
)
assert.throws(
() => ensure(null, 'ABC', 'XYZ'),
(err) => {
assert(err instanceof Error)
assert(err.message.includes('ABC'))
assert(err.message.includes('XYZ'))
return true
}
)
})

test('getOwn', () => {
class Foo {
ownProperty = 123
Expand Down Expand Up @@ -77,18 +51,39 @@ test('getVersionId', () => {
index: 123,
}

assert.equal(getVersionId(valid), coreDiscoveryKeyHex + '/' + 123)
assert.equal(
getVersionId(valid),
coreDiscoveryKeyHex + '/' + 123,
'serializing version ID'
)

assert.throws(() => getVersionId({ ...valid, index: -1 }))
assert.throws(() => getVersionId({ ...valid, index: 1.2 }))
assert.throws(
() => getVersionId({ ...valid, index: -1 }),
'throws when index is negative'
)
assert.throws(
() => getVersionId({ ...valid, index: 1.2 }),
'throws when index is not an integer'
)
assert.throws(
() => getVersionId({ ...valid, index: NaN }),
'throws when index is NaN'
)
assert.throws(
() => getVersionId({ ...valid, index: Infinity }),
'throws when index is Infinity'
)

assert.throws(() =>
getVersionId({ ...valid, coreDiscoveryKey: Buffer.alloc(0) })
assert.throws(
() => getVersionId({ ...valid, coreDiscoveryKey: Buffer.alloc(0) }),
'throws when core discovery key is empty'
)
assert.throws(() =>
getVersionId({
...valid,
coreDiscoveryKey: valid.coreDiscoveryKey.subarray(0, 31),
})
assert.throws(
() =>
getVersionId({
...valid,
coreDiscoveryKey: valid.coreDiscoveryKey.subarray(0, 31),
}),
'throws when core discovery key is too short'
)
})

0 comments on commit 0850932

Please sign in to comment.