feat: Only accept NamedNodes as predicates for metadata

* refactor: move toCachedNamedNode (private)

* chore: only NamedNodes predicates in removes

* feat: enforce NamedNode predicates in most cases

* feat: getAll only accepts NamedNodes

* feat: toCachedNamedNode only accepts string arg

* tests: use NamedNodes for getAll calls

* test: remove unnecessary string check for coverage

* tests: fix NamedNodes in new tests after rebase

* feat: metadatawriters store NamedNodes

* refactor: toCachedNamedNode as utility function

* fix: double write of linkRelMap

* test: use the CONTENT_TYPE constant
This commit is contained in:
Jasper Vaneessen
2022-04-15 09:53:39 +02:00
committed by GitHub
parent db906ae872
commit 668d0a331f
26 changed files with 172 additions and 183 deletions

View File

@@ -1,3 +1,4 @@
import { DataFactory } from 'n3';
import type { AuxiliaryIdentifierStrategy } from '../../../../src/http/auxiliary/AuxiliaryIdentifierStrategy';
import { LinkMetadataGenerator } from '../../../../src/http/auxiliary/LinkMetadataGenerator';
import { RepresentationMetadata } from '../../../../src/http/representation/RepresentationMetadata';
@@ -35,7 +36,7 @@ describe('A LinkMetadataGenerator', (): void => {
const metadata = new RepresentationMetadata(subjectId);
await expect(generator.handle(metadata)).resolves.toBeUndefined();
expect(metadata.quads()).toHaveLength(1);
expect(metadata.get(link)?.value).toBe(auxiliaryId.path);
expect(metadata.getAll(link, SOLID_META.terms.ResponseMetadata)).toHaveLength(1);
expect(metadata.get(DataFactory.namedNode(link))?.value).toBe(auxiliaryId.path);
expect(metadata.getAll(DataFactory.namedNode(link), SOLID_META.terms.ResponseMetadata)).toHaveLength(1);
});
});

View File

@@ -22,14 +22,14 @@ describe('A LinkParser', (): void => {
request.headers.link = '<http://test.com/type>;rel="type"';
await expect(parser.handle({ request, metadata })).resolves.toBeUndefined();
expect(metadata.quads()).toHaveLength(1);
expect(metadata.get(RDF.type)?.value).toBe('http://test.com/type');
expect(metadata.get(RDF.terms.type)?.value).toBe('http://test.com/type');
});
it('supports multiple link headers.', async(): Promise<void> => {
request.headers.link = [ '<http://test.com/typeA>;rel="type"', '<http://test.com/typeB>;rel=type' ];
await expect(parser.handle({ request, metadata })).resolves.toBeUndefined();
expect(metadata.quads()).toHaveLength(2);
expect(metadata.getAll(RDF.type).map((term): any => term.value))
expect(metadata.getAll(RDF.terms.type).map((term): any => term.value))
.toEqual([ 'http://test.com/typeA', 'http://test.com/typeB' ]);
});
@@ -37,7 +37,7 @@ describe('A LinkParser', (): void => {
request.headers.link = '<http://test.com/typeA>;rel="type" , <http://test.com/typeB>;rel=type';
await expect(parser.handle({ request, metadata })).resolves.toBeUndefined();
expect(metadata.quads()).toHaveLength(2);
expect(metadata.getAll(RDF.type).map((term): any => term.value))
expect(metadata.getAll(RDF.terms.type).map((term): any => term.value))
.toEqual([ 'http://test.com/typeA', 'http://test.com/typeB' ]);
});

View File

@@ -30,6 +30,6 @@ describe('A SlugParser', (): void => {
request.headers.slug = 'slugA';
await expect(parser.handle({ request, metadata })).resolves.toBeUndefined();
expect(metadata.quads()).toHaveLength(1);
expect(metadata.get(SOLID_HTTP.slug)?.value).toBe('slugA');
expect(metadata.get(SOLID_HTTP.terms.slug)?.value).toBe('slugA');
});
});

View File

@@ -42,7 +42,7 @@ describe('A PatchOperationHandler', (): void => {
expect(store.modifyResource).toHaveBeenCalledTimes(1);
expect(store.modifyResource).toHaveBeenLastCalledWith(operation.target, body, conditions);
expect(result.statusCode).toBe(201);
expect(result.metadata?.get(SOLID_HTTP.location)?.value).toBe(operation.target.path);
expect(result.metadata?.get(SOLID_HTTP.terms.location)?.value).toBe(operation.target.path);
expect(result.data).toBeUndefined();
});

View File

@@ -41,7 +41,7 @@ describe('A PostOperationHandler', (): void => {
const result = await handler.handle({ operation });
expect(result.statusCode).toBe(201);
expect(result.metadata).toBeInstanceOf(RepresentationMetadata);
expect(result.metadata?.get(SOLID_HTTP.location)?.value).toBe('newPath');
expect(result.metadata?.get(SOLID_HTTP.terms.location)?.value).toBe('newPath');
expect(result.data).toBeUndefined();
expect(store.addResource).toHaveBeenCalledTimes(1);
expect(store.addResource).toHaveBeenLastCalledWith(operation.target, body, conditions);

View File

@@ -41,7 +41,7 @@ describe('A PutOperationHandler', (): void => {
expect(store.setRepresentation).toHaveBeenCalledTimes(1);
expect(store.setRepresentation).toHaveBeenLastCalledWith(operation.target, body, conditions);
expect(result.statusCode).toBe(201);
expect(result.metadata?.get(SOLID_HTTP.location)?.value).toBe(operation.target.path);
expect(result.metadata?.get(SOLID_HTTP.terms.location)?.value).toBe(operation.target.path);
expect(result.data).toBeUndefined();
});

View File

@@ -3,7 +3,7 @@ import type { BlankNode } from 'n3';
import { DataFactory } from 'n3';
import type { NamedNode, Quad } from 'rdf-js';
import { RepresentationMetadata } from '../../../../src/http/representation/RepresentationMetadata';
import { CONTENT_TYPE, SOLID_META, RDFS } from '../../../../src/util/Vocabularies';
import { CONTENT_TYPE_TERM, SOLID_META, RDFS } from '../../../../src/util/Vocabularies';
const { defaultGraph, literal, namedNode, quad } = DataFactory;
// Helper functions to filter quads
@@ -82,14 +82,14 @@ describe('A RepresentationMetadata', (): void => {
it('takes overrides for specific predicates.', async(): Promise<void> => {
metadata = new RepresentationMetadata({ predVal: 'objVal' });
expect(metadata.get('predVal')).toEqualRdfTerm(literal('objVal'));
expect(metadata.get(namedNode('predVal'))).toEqualRdfTerm(literal('objVal'));
metadata = new RepresentationMetadata({ predVal: literal('objVal') });
expect(metadata.get('predVal')).toEqualRdfTerm(literal('objVal'));
expect(metadata.get(namedNode('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'));
expect(metadata.getAll(namedNode('predVal'))).toEqualRdfTermArray([ literal('objVal1'), literal('objVal2') ]);
expect(metadata.get(namedNode('predVal2'))).toEqualRdfTerm(literal('objVal3'));
});
it('can combine overrides with an identifier.', async(): Promise<void> => {
@@ -153,7 +153,7 @@ describe('A RepresentationMetadata', (): void => {
// `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');
expectedMetadata.add(namedNode('test:pred'), 'objVal');
expect(metadata.identifier).toEqual(other.identifier);
expect(metadata.quads()).toBeRdfIsomorphic(expectedMetadata.quads());
@@ -161,13 +161,13 @@ describe('A RepresentationMetadata', (): void => {
it('can add a quad.', async(): Promise<void> => {
const newQuad = quad(namedNode('random'), namedNode('new'), literal('triple'));
metadata.addQuad('random', 'new', 'triple');
metadata.addQuad('random', namedNode('new'), 'triple');
expect(metadata.quads()).toBeRdfIsomorphic([ ...inputQuads, newQuad ]);
});
it('can add a quad with a graph.', async(): Promise<void> => {
const newQuad = quad(namedNode('random'), namedNode('new'), literal('triple'), namedNode('graph'));
metadata.addQuad('random', 'new', 'triple', 'graph');
metadata.addQuad('random', namedNode('new'), 'triple', 'graph');
expect(metadata.quads()).toBeRdfIsomorphic([ ...inputQuads, newQuad ]);
});
@@ -186,7 +186,7 @@ describe('A RepresentationMetadata', (): void => {
});
it('removes all matching triples if graph is undefined.', async(): Promise<void> => {
metadata.removeQuad(identifier, 'has', 'data');
metadata.removeQuad(identifier, namedNode('has'), 'data');
expect(metadata.quads()).toHaveLength(inputQuads.length - 2);
expect(metadata.quads()).toBeRdfIsomorphic(removeQuads(inputQuads, identifier.value, 'has', 'data'));
});
@@ -277,7 +277,6 @@ describe('A RepresentationMetadata', (): void => {
it('errors if there are multiple values when getting a value.', async(): Promise<void> => {
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<void> => {
@@ -293,15 +292,15 @@ describe('A RepresentationMetadata', (): void => {
it('has a shorthand for content-type.', async(): Promise<void> => {
expect(metadata.contentType).toBeUndefined();
metadata.contentType = 'a/b';
expect(metadata.get(CONTENT_TYPE)).toEqualRdfTerm(literal('a/b'));
expect(metadata.get(CONTENT_TYPE_TERM)).toEqualRdfTerm(literal('a/b'));
expect(metadata.contentType).toBe('a/b');
metadata.contentType = undefined;
expect(metadata.contentType).toBeUndefined();
});
it('errors if a shorthand has multiple values.', async(): Promise<void> => {
metadata.add(CONTENT_TYPE, 'a/b');
metadata.add(CONTENT_TYPE, 'c/d');
metadata.add(CONTENT_TYPE_TERM, 'a/b');
metadata.add(CONTENT_TYPE_TERM, 'c/d');
expect((): any => metadata.contentType).toThrow();
});