UNPKG

hyperpubee

Version:

Self-publishing over the decentralised internet

374 lines (314 loc) 12.6 kB
const { strict: nodeAssert } = require('assert') const { expect } = require('chai') const PubeeBuilder = require('../lib/creation/pubee-builder') const { CONTENT, EMPTY, STRUCTURE, ROOT, EMBEDDING_HASH, EMBEDDING_LOCATION, EMBEDDING, EMBEDDING_PATCH, METADATA, LINK } = require('../lib/core/constants') const hexlexi = require('../lib/core/hexlexi') const { createArrayFromStream, getAbsoluteKey } = require('../lib/core/utils') const { hyperInterfaceFactory } = require('./fixtures') describe('Test pubeebuilder', function () { let builder let index0, index1 let hyperbee let hyperInterface this.beforeEach(async function () { hyperInterface = await hyperInterfaceFactory() hyperbee = await hyperInterface.createHyperbee('testbee') builder = new PubeeBuilder(hyperbee) index0 = hexlexi.pack(0) index1 = hexlexi.pack(1) }) this.afterEach(async function () { await hyperInterface.close() }) it('throws an error when passing a non-empty bee to init', async function () { await hyperbee.put('something', 'which makes it non-empty') expect(() => new PubeeBuilder(hyperbee)).to.throw( 'Cannot init a pubeebuilder with a non-empty bee' ) }) it('throws an error when adding an empty content', async function () { await nodeAssert.rejects(builder.addContent(''), { message: 'Cannot add an empty content.' }) }) it('throws an error when adding an empty structure', async function () { await nodeAssert.rejects(builder.addStructure('name', []), { message: 'Cannot add an empty structure.' }) }) it('throws an error when adding a structure without name', async function () { await nodeAssert.rejects(builder.addStructure('', ['mockChildKey']), { message: 'Cannot add a structure without name.' }) }) it('returns the correct hexlex-indexed key when adding content', async function () { const firstKey = await builder.addContent('some content') const secondKey = await builder.addContent('some more content') const expectedKey1 = [CONTENT, EMPTY, hexlexi.pack(0)].join('') const expectedKey2 = [CONTENT, EMPTY, hexlexi.pack(1)].join('') expect(firstKey).to.equal(expectedKey1) expect(secondKey).to.equal(expectedKey2) }) it('returns the correct hexlex-indexed key when adding content asyncronously', async function () { const firstKeyPromise = builder.addContent('some content') const secondKeyPromise = builder.addContent('some more content') const firstKey = await firstKeyPromise const secondKey = await secondKeyPromise const expectedKey1 = [CONTENT, EMPTY, hexlexi.pack(0)].join('') const expectedKey2 = [CONTENT, EMPTY, hexlexi.pack(1)].join('') expect(firstKey).to.equal(expectedKey1) expect(secondKey).to.equal(expectedKey2) }) describe('Test structure adding', function () { let contentKey1 let contentKey2 let expectedStructKey1 let expectedStructKey2 let expectedStructKey3 this.beforeEach(async function () { contentKey1 = await builder.addContent('some content') contentKey2 = await builder.addContent('some more content') expectedStructKey1 = [ STRUCTURE, EMPTY, 'struct1', EMPTY, hexlexi.pack(0) ].join('') expectedStructKey2 = [ STRUCTURE, EMPTY, 'struct1', EMPTY, hexlexi.pack(1) ].join('') expectedStructKey3 = [ STRUCTURE, EMPTY, 'highLvlStruct', EMPTY, hexlexi.pack(0) ].join('') }) it('returns the correct hexlex-indexed key when adding structure', async function () { const structKey1 = await builder.addStructure('struct1', [contentKey1]) const structKey2 = await builder.addStructure('struct1', [contentKey2]) const structKey3 = await builder.addStructure('highLvlStruct', [ structKey1, structKey2 ]) expect(structKey1).to.equal(expectedStructKey1) expect(structKey2).to.equal(expectedStructKey2) expect(structKey3).to.equal(expectedStructKey3) }) it('returns the correct hexlex-indexed key when adding structure asyncronously', async function () { const promises = [ builder.addStructure('struct1', [contentKey1]), builder.addStructure('struct1', [contentKey2]) ] const structKey1 = await promises[0] const structKey2 = await promises[1] const structKey3 = await builder.addStructure('highLvlStruct', [ structKey1, structKey2 ]) expect(structKey1).to.equal(expectedStructKey1) expect(structKey2).to.equal(expectedStructKey2) expect(structKey3).to.equal(expectedStructKey3) }) it('can add the root', async function () { const structKey1 = await builder.addStructure('struct1', [contentKey1]) const rootKey = await builder.addRoot([structKey1]) const expectedRootKey = [STRUCTURE, EMPTY, ROOT].join('') expect(rootKey).to.equal(expectedRootKey) }) it('cannot add the root twice', async function () { const structKey1 = await builder.addStructure('struct1', [contentKey1]) await builder.addRoot([structKey1]) await nodeAssert.rejects(builder.addRoot([structKey1]), { message: 'Cannot add the root more than once.' }) }) }) describe('Test build method', function () { let contentKey1 let contentKey2 let structKey1 let structKey2 let highLvlStructKey this.beforeEach(async function () { contentKey1 = await builder.addContent('content nr 1') contentKey2 = await builder.addContent('content nr 2') structKey1 = await builder.addStructure('struct1', [contentKey1]) structKey2 = await builder.addStructure('struct1', [contentKey2]) highLvlStructKey = await builder.addStructure('highLvlStruct', [ structKey1, structKey2 ]) await builder.addMetadata({}) }) it('throws a validation error when building an empty bee', async function () { hyperbee = await hyperInterface.createHyperbee('emptyBee') builder = new PubeeBuilder(hyperbee) await nodeAssert.rejects(builder.build(), { name: 'ValidationError' }) }) it('returns the correct hyperbee when building', async function () { await builder.addRoot([highLvlStructKey]) const pubee = await builder.build() const bee = await pubee.getReadOnlyBee() const content = bee.sub(CONTENT) const { value: content0 } = await content.get(hexlexi.pack(0)) const { value: content1 } = await content.get(hexlexi.pack(1)) const allContent = await createArrayFromStream( content.createReadStream() ) expect(content0).to.equal('content nr 1') expect(content1).to.equal('content nr 2') expect(allContent.length).to.equal(2) // Ensure: no additional values const structureSub = bee.sub(STRUCTURE) const struct1Sub = structureSub.sub('struct1') const { value: lowLvlStruct1 } = await struct1Sub.get(hexlexi.pack(0)) const { value: lowLvlStruct2 } = await struct1Sub.get(hexlexi.pack(1)) const { value: highLvlStruct } = await structureSub .sub('highLvlStruct') .get(hexlexi.pack(0)) const { value: root } = await structureSub.get(ROOT) const allStructures = await createArrayFromStream( structureSub.createReadStream() ) expect(lowLvlStruct1).to.deep.equal([contentKey1]) expect(lowLvlStruct2).to.deep.equal([contentKey2]) expect(highLvlStruct).to.deep.equal([structKey1, structKey2]) expect(root).to.deep.equal([highLvlStructKey]) expect(allStructures.length).to.equal(4) // Ensure: no additional values const allEntries = await createArrayFromStream(bee.createReadStream()) expect(allEntries.length).to.equal(4 + 2 + 1) // 4 struct, 2 content, 1 metadata }) it('can build a hyperbee with embeddings', async function () { const embedding = {} embedding[EMBEDDING_HASH] = 'a'.repeat(64) embedding[EMBEDDING_LOCATION] = getAbsoluteKey(CONTENT, index0) embedding[EMBEDDING_PATCH] = [] const embeddingKey = await builder.addEmbedding(embedding) await builder.addRoot([highLvlStructKey, embeddingKey]) const pubee = await builder.build() const bee = await pubee.getReadOnlyBee() const { value: extractedEmbedding } = await bee .sub(EMBEDDING) .get(index0) expect(extractedEmbedding.referencedHash).to.equal( embedding[EMBEDDING_HASH] ) expect(extractedEmbedding.referencedLocation).to.equal( embedding[EMBEDDING_LOCATION] ) }) it('can build a hyperbee with patched embeddings', async function () { const embedding = {} embedding[EMBEDDING_HASH] = 'a'.repeat(64) embedding[EMBEDDING_LOCATION] = getAbsoluteKey(CONTENT, index0) embedding[EMBEDDING_PATCH] = [[-1, 'Goo'], [1, 'Ba'], [0, 'd dog']] const embeddingKey = await builder.addEmbedding(embedding) await builder.addRoot([highLvlStructKey, embeddingKey]) const pubee = await builder.build() const bee = await pubee.getReadOnlyBee() const { value: extractedEmbedding } = await bee .sub(EMBEDDING) .get(index0) expect(extractedEmbedding.referencedHash).to.equal( embedding[EMBEDDING_HASH] ) expect(extractedEmbedding.referencedLocation).to.equal( embedding[EMBEDDING_LOCATION] ) expect(extractedEmbedding.patch).to.deep.equal( [[-1, 'Goo'], [1, 'Ba'], [0, 'd dog']] ) }) it('Can build a hyperpubee with a link', async function () { const link = { linkedHash: 'a'.repeat(64), linkedLocation: getAbsoluteKey(CONTENT, index0) } const linkKey = await builder.addLink(link) await builder.addRoot([highLvlStructKey, linkKey]) const pubee = await builder.build() const bee = await pubee.getReadOnlyBee() const { value: extractedLink } = await bee .sub(LINK) .get(index0) expect(extractedLink.linkedHash).to.equal( 'a'.repeat(64) ) expect(extractedLink.linkedLocation).to.equal( getAbsoluteKey(CONTENT, index0) ) }) }) describe('test Link builder logic', async function () { let link this.beforeEach(function () { link = { linkedHash: 'a'.repeat(64), linkedLocation: getAbsoluteKey(CONTENT, index0) } }) it('Returns the correct hexlexed location when adding a link', async function () { const key = await builder.addLink(link) const key2 = await builder.addLink(link) expect(key).to.equal(getAbsoluteKey(LINK, index0)) expect(key2).to.equal(getAbsoluteKey(LINK, index1)) }) }) describe('test addEmbedding', async function () { it('Returns the correct hexlexed location when adding an embedding', async function () { const embedding = {} embedding[EMBEDDING_HASH] = 'a'.repeat(64) embedding[EMBEDDING_LOCATION] = getAbsoluteKey(CONTENT, index0) embedding[EMBEDDING_PATCH] = [] const embeddingKey = await builder.addEmbedding(embedding) expect(embeddingKey).to.equal(getAbsoluteKey(EMBEDDING, index0)) }) }) describe('Test metadata', function () { it('throws a validation error when building without metadata', async function () { hyperbee = await hyperInterface.createHyperbee('testbee') builder = new PubeeBuilder(hyperbee) const key = await builder.addContent('My content') await builder.addRoot([key]) await nodeAssert.rejects(builder.build(), { message: 'A pubee must have a metadata key' }) }) it('Correctly adds metadata', async function () { hyperbee = await hyperInterface.createHyperbee('testbee') builder = new PubeeBuilder(hyperbee) const key = await builder.addContent('My content') await builder.addRoot([key]) await builder.addMetadata({ author: 'someone' }) const bee = await builder.build() expect((await bee.get(METADATA))).to.deep.equal({ author: 'someone' }) }) it('throws when adding metadata twice', async function () { hyperbee = await hyperInterface.createHyperbee('testbee') builder = new PubeeBuilder(hyperbee) await builder.addMetadata({}) await nodeAssert.rejects(builder.addMetadata({}), { message: 'Metadata can only be added once' }) }) }) })