import { literal, namedNode, quad } from '@rdfjs/data-model'; import type { Literal, NamedNode, Quad } from 'rdf-js'; import { RepresentationMetadata } from '../../../../src/ldp/representation/RepresentationMetadata'; import { MA_CONTENT_TYPE } from '../../../../src/util/MetadataTypes'; describe('A RepresentationMetadata', (): void => { let metadata: RepresentationMetadata; const identifier = namedNode('http://example.com/id'); const inputQuads = [ quad(identifier, namedNode('has'), literal('data')), quad(identifier, namedNode('has'), literal('moreData')), quad(identifier, namedNode('hasOne'), literal('otherData')), quad(namedNode('otherNode'), namedNode('linksTo'), identifier), quad(namedNode('otherNode'), namedNode('has'), literal('otherData')), ]; describe('constructor', (): void => { it('creates a blank node if no identifier was given.', async(): Promise => { metadata = new RepresentationMetadata(); expect(metadata.identifier.termType).toEqual('BlankNode'); expect(metadata.quads()).toHaveLength(0); }); it('stores the given identifier if given.', async(): Promise => { metadata = new RepresentationMetadata(namedNode('identifier')); expect(metadata.identifier).toEqualRdfTerm(namedNode('identifier')); }); it('converts identifier strings to named nodes.', async(): Promise => { metadata = new RepresentationMetadata('identifier'); expect(metadata.identifier).toEqualRdfTerm(namedNode('identifier')); }); it('copies an other metadata object.', async(): Promise => { const other = new RepresentationMetadata('otherId', { 'test:pred': 'objVal' }); metadata = new RepresentationMetadata(other); expect(metadata.identifier).toEqualRdfTerm(namedNode('otherId')); expect(metadata.quads()).toBeRdfIsomorphic([ quad(namedNode('otherId'), namedNode('test:pred'), literal('objVal')) ]); }); it('takes overrides for specific predicates.', async(): Promise => { metadata = new RepresentationMetadata({ predVal: 'objVal' }); expect(metadata.get('predVal')).toEqualRdfTerm(literal('objVal')); metadata = new RepresentationMetadata({ predVal: literal('objVal') }); expect(metadata.get('predVal')).toEqualRdfTerm(literal('objVal')); metadata = new RepresentationMetadata({ predVal: [ 'objVal1', literal('objVal2') ], predVal2: 'objVal3' }); expect(metadata.getAll('predVal')).toEqualRdfTermArray([ literal('objVal1'), literal('objVal2') ]); expect(metadata.get('predVal2')).toEqualRdfTerm(literal('objVal3')); }); it('can combine overrides with an identifier.', async(): Promise => { metadata = new RepresentationMetadata(identifier, { predVal: 'objVal' }); expect(metadata.quads()).toBeRdfIsomorphic([ quad(identifier, namedNode('predVal'), literal('objVal')) ]); }); it('can combine overrides with other metadata.', async(): Promise => { const other = new RepresentationMetadata('otherId', { 'test:pred': 'objVal' }); metadata = new RepresentationMetadata(other, { 'test:pred': 'objVal2' }); expect(metadata.quads()).toBeRdfIsomorphic([ quad(namedNode('otherId'), namedNode('test:pred'), literal('objVal2')) ]); }); }); describe('instantiated', (): void => { beforeEach(async(): Promise => { metadata = new RepresentationMetadata(identifier).addQuads(inputQuads); }); it('can get all quads.', async(): Promise => { expect(metadata.quads()).toBeRdfIsomorphic(inputQuads); }); it('can change the stored identifier.', async(): Promise => { const newIdentifier = namedNode('newNode'); metadata.identifier = newIdentifier; const newQuads = inputQuads.map((triple): Quad => { if (triple.subject.equals(identifier)) { return quad(newIdentifier, triple.predicate, triple.object); } if (triple.object.equals(identifier)) { return quad(triple.subject, triple.predicate, newIdentifier); } return triple; }); expect(metadata.identifier).toEqualRdfTerm(newIdentifier); expect(metadata.quads()).toBeRdfIsomorphic(newQuads); }); it('can copy metadata.', async(): Promise => { const other = new RepresentationMetadata(identifier, { 'test:pred': 'objVal' }); metadata.setMetadata(other); expect(metadata.identifier).toEqual(other.identifier); expect(metadata.quads()).toBeRdfIsomorphic(inputQuads.concat([ quad(identifier, namedNode('test:pred'), literal('objVal')) ])); }); it('updates its identifier when copying metadata.', async(): Promise => { const other = new RepresentationMetadata('otherId', { 'test:pred': 'objVal' }); metadata.setMetadata(other); // `setMetadata` should have the same result as the following const expectedMetadata = new RepresentationMetadata(identifier).addQuads(inputQuads); expectedMetadata.identifier = namedNode('otherId'); expectedMetadata.add('test:pred', 'objVal'); expect(metadata.identifier).toEqual(other.identifier); expect(metadata.quads()).toBeRdfIsomorphic(expectedMetadata.quads()); }); it('can add quads.', async(): Promise => { const newQuads: Quad[] = [ quad(namedNode('random'), namedNode('new'), namedNode('triple')), ]; metadata.addQuads(newQuads); expect(metadata.quads()).toBeRdfIsomorphic(newQuads.concat(inputQuads)); }); it('can remove quads.', async(): Promise => { metadata.removeQuads([ inputQuads[0] ]); expect(metadata.quads()).toBeRdfIsomorphic(inputQuads.slice(1)); }); it('can add a single value for a predicate.', async(): Promise => { const newQuad = quad(identifier, namedNode('new'), namedNode('triple')); metadata.add(newQuad.predicate as NamedNode, newQuad.object as NamedNode); expect(metadata.quads()).toBeRdfIsomorphic([ newQuad ].concat(inputQuads)); }); it('can add single values as string.', async(): Promise => { const newQuad = quad(identifier, namedNode('new'), literal('triple')); metadata.add(newQuad.predicate as NamedNode, newQuad.object.value); expect(metadata.quads()).toBeRdfIsomorphic([ newQuad ].concat(inputQuads)); }); it('can remove a single value for a predicate.', async(): Promise => { metadata.remove(inputQuads[0].predicate as NamedNode, inputQuads[0].object as Literal); expect(metadata.quads()).toBeRdfIsomorphic(inputQuads.slice(1)); }); it('can remove single values as string.', async(): Promise => { metadata.remove(inputQuads[0].predicate as NamedNode, inputQuads[0].object.value); expect(metadata.quads()).toBeRdfIsomorphic(inputQuads.slice(1)); }); it('can remove all values for a predicate.', async(): Promise => { const pred = namedNode('has'); metadata.removeAll(pred); const updatedNodes = inputQuads.filter((triple): boolean => !triple.subject.equals(identifier) || !triple.predicate.equals(pred)); expect(metadata.quads()).toBeRdfIsomorphic(updatedNodes); }); it('can get all values for a predicate.', async(): Promise => { expect(metadata.getAll(namedNode('has'))).toEqualRdfTermArray([ literal('data'), literal('moreData') ]); }); it('can get the single value for a predicate.', async(): Promise => { expect(metadata.get(namedNode('hasOne'))).toEqualRdfTerm(literal('otherData')); }); it('returns undefined if getting an undefined predicate.', async(): Promise => { expect(metadata.get(namedNode('doesntExist'))).toBeUndefined(); }); it('errors if there are multiple values when getting a value.', async(): Promise => { expect((): any => metadata.get(namedNode('has'))).toThrow(Error); expect((): any => metadata.get('has')).toThrow(Error); }); it('can set the value of a predicate.', async(): Promise => { metadata.set(namedNode('has'), literal('singleValue')); expect(metadata.get(namedNode('has'))).toEqualRdfTerm(literal('singleValue')); }); it('has a shorthand for content-type.', async(): Promise => { expect(metadata.contentType).toBeUndefined(); metadata.contentType = 'a/b'; expect(metadata.get(MA_CONTENT_TYPE)).toEqualRdfTerm(literal('a/b')); expect(metadata.contentType).toEqual('a/b'); metadata.contentType = undefined; expect(metadata.contentType).toBeUndefined(); }); it('errors if a shorthand has multiple values.', async(): Promise => { metadata.add(MA_CONTENT_TYPE, 'a/b'); metadata.add(MA_CONTENT_TYPE, 'c/d'); expect((): any => metadata.contentType).toThrow(); }); }); });