mirror of
https://github.com/CommunitySolidServer/CommunitySolidServer.git
synced 2024-10-03 14:55:10 +00:00
refactor: Clean up utility functions
This commit is contained in:
@@ -51,7 +51,7 @@ export class AuthenticatedDataAccessorBasedConfig implements ServerConfig {
|
||||
const operationHandler = getOperationHandler(this.store);
|
||||
|
||||
const responseWriter = getResponseWriter();
|
||||
const authorizer = getWebAclAuthorizer(this.store, this.base);
|
||||
const authorizer = getWebAclAuthorizer(this.store);
|
||||
|
||||
const handler = new AuthenticatedLdpHandler({
|
||||
requestParser,
|
||||
|
||||
@@ -27,7 +27,6 @@ import {
|
||||
LinkRelMetadataWriter,
|
||||
LinkTypeParser,
|
||||
MappedMetadataWriter,
|
||||
MetadataController,
|
||||
PatchingStore,
|
||||
PatchOperationHandler,
|
||||
PostOperationHandler,
|
||||
@@ -38,7 +37,6 @@ import {
|
||||
SlugParser,
|
||||
SparqlUpdatePatchHandler,
|
||||
UrlBasedAclManager,
|
||||
UrlContainerManager,
|
||||
WebAclAuthorizer,
|
||||
} from '../../index';
|
||||
import { CONTENT_TYPE, HTTP, RDF } from '../../src/util/UriConstants';
|
||||
@@ -52,19 +50,14 @@ export const BASE = 'http://test.com';
|
||||
export const getRootFilePath = (subfolder: string): string => join(__dirname, '../testData', subfolder);
|
||||
|
||||
/**
|
||||
* Gives a file data accessor store based on (default) runtime config.
|
||||
* Gives a data accessor store with the given data accessor.
|
||||
* @param base - Base URL.
|
||||
* @param rootFilepath - The root file path.
|
||||
* @param dataAccessor - DataAccessor to use.
|
||||
*
|
||||
* @returns The data accessor based store.
|
||||
*/
|
||||
export const getDataAccessorStore = (base: string, dataAccessor: DataAccessor): DataAccessorBasedStore =>
|
||||
new DataAccessorBasedStore(
|
||||
dataAccessor,
|
||||
base,
|
||||
new MetadataController(),
|
||||
new UrlContainerManager(base),
|
||||
);
|
||||
new DataAccessorBasedStore(dataAccessor, base);
|
||||
|
||||
/**
|
||||
* Gives an in memory resource store based on (default) base url.
|
||||
@@ -73,7 +66,7 @@ export const getDataAccessorStore = (base: string, dataAccessor: DataAccessor):
|
||||
* @returns The in memory resource store.
|
||||
*/
|
||||
export const getInMemoryResourceStore = (base = BASE): DataAccessorBasedStore =>
|
||||
getDataAccessorStore(base, new InMemoryDataAccessor(BASE, new MetadataController()));
|
||||
getDataAccessorStore(base, new InMemoryDataAccessor(BASE));
|
||||
|
||||
/**
|
||||
* Gives a converting store given some converters.
|
||||
@@ -172,15 +165,11 @@ export const getBasicRequestParser = (bodyParsers: BodyParser[] = []): BasicRequ
|
||||
};
|
||||
|
||||
/**
|
||||
* Gives a web acl authorizer, using a UrlContainerManager & based on a (default) runtimeConfig.
|
||||
* Gives a web acl authorizer based on a (default) runtimeConfig.
|
||||
* @param store - Initial resource store.
|
||||
* @param base - Base URI of the pod.
|
||||
* @param aclManager - Optional acl manager, default is UrlBasedAclManager.
|
||||
*
|
||||
* @returns The acl authorizer.
|
||||
*/
|
||||
export const getWebAclAuthorizer =
|
||||
(store: ResourceStore, base = BASE, aclManager = new UrlBasedAclManager()): WebAclAuthorizer => {
|
||||
const containerManager = new UrlContainerManager(base);
|
||||
return new WebAclAuthorizer(aclManager, containerManager, store);
|
||||
};
|
||||
export const getWebAclAuthorizer = (store: ResourceStore, aclManager = new UrlBasedAclManager()): WebAclAuthorizer =>
|
||||
new WebAclAuthorizer(aclManager, store);
|
||||
|
||||
@@ -5,9 +5,8 @@ import { RepresentationMetadata } from '../../src/ldp/representation/Representat
|
||||
import { FileDataAccessor } from '../../src/storage/accessors/FileDataAccessor';
|
||||
import { InMemoryDataAccessor } from '../../src/storage/accessors/InMemoryDataAccessor';
|
||||
import { ExtensionBasedMapper } from '../../src/storage/ExtensionBasedMapper';
|
||||
import { MetadataController } from '../../src/util/MetadataController';
|
||||
import { ensureTrailingSlash } from '../../src/util/PathUtil';
|
||||
import { CONTENT_TYPE, LDP } from '../../src/util/UriConstants';
|
||||
import { ensureTrailingSlash } from '../../src/util/Util';
|
||||
import { AuthenticatedDataAccessorBasedConfig } from '../configs/AuthenticatedDataAccessorBasedConfig';
|
||||
import type { ServerConfig } from '../configs/ServerConfig';
|
||||
import { BASE, getRootFilePath } from '../configs/Util';
|
||||
@@ -16,12 +15,11 @@ import { AclTestHelper, FileTestHelper } from '../util/TestHelpers';
|
||||
const dataAccessorStore: [string, (rootFilePath: string) => ServerConfig] = [
|
||||
'AuthenticatedFileDataAccessorBasedStore',
|
||||
(rootFilePath: string): ServerConfig => new AuthenticatedDataAccessorBasedConfig(BASE,
|
||||
new FileDataAccessor(new ExtensionBasedMapper(BASE, rootFilePath), new MetadataController())),
|
||||
new FileDataAccessor(new ExtensionBasedMapper(BASE, rootFilePath))),
|
||||
];
|
||||
const inMemoryDataAccessorStore: [string, (rootFilePath: string) => ServerConfig] = [
|
||||
'AuthenticatedInMemoryDataAccessorBasedStore',
|
||||
(): ServerConfig => new AuthenticatedDataAccessorBasedConfig(BASE,
|
||||
new InMemoryDataAccessor(BASE, new MetadataController())),
|
||||
(): ServerConfig => new AuthenticatedDataAccessorBasedConfig(BASE, new InMemoryDataAccessor(BASE)),
|
||||
];
|
||||
|
||||
describe.each([ dataAccessorStore, inMemoryDataAccessorStore ])('A server using a %s', (name, configFn): void => {
|
||||
|
||||
@@ -4,7 +4,6 @@ import type { HttpHandler } from '../../src/server/HttpHandler';
|
||||
import { FileDataAccessor } from '../../src/storage/accessors/FileDataAccessor';
|
||||
import { InMemoryDataAccessor } from '../../src/storage/accessors/InMemoryDataAccessor';
|
||||
import { ExtensionBasedMapper } from '../../src/storage/ExtensionBasedMapper';
|
||||
import { MetadataController } from '../../src/util/MetadataController';
|
||||
import { LDP } from '../../src/util/UriConstants';
|
||||
import { DataAccessorBasedConfig } from '../configs/DataAccessorBasedConfig';
|
||||
import type { ServerConfig } from '../configs/ServerConfig';
|
||||
@@ -14,12 +13,11 @@ import { FileTestHelper } from '../util/TestHelpers';
|
||||
const fileDataAccessorStore: [string, (rootFilePath: string) => ServerConfig] = [
|
||||
'FileDataAccessorBasedStore',
|
||||
(rootFilePath: string): ServerConfig => new DataAccessorBasedConfig(BASE,
|
||||
new FileDataAccessor(new ExtensionBasedMapper(BASE, rootFilePath), new MetadataController())),
|
||||
new FileDataAccessor(new ExtensionBasedMapper(BASE, rootFilePath))),
|
||||
];
|
||||
const inMemoryDataAccessorStore: [string, (rootFilePath: string) => ServerConfig] = [
|
||||
'InMemoryDataAccessorBasedStore',
|
||||
(): ServerConfig => new DataAccessorBasedConfig(BASE,
|
||||
new InMemoryDataAccessor(BASE, new MetadataController())),
|
||||
(): ServerConfig => new DataAccessorBasedConfig(BASE, new InMemoryDataAccessor(BASE)),
|
||||
];
|
||||
|
||||
const configs = [ fileDataAccessorStore, inMemoryDataAccessorStore ];
|
||||
|
||||
@@ -4,8 +4,8 @@ import { RepresentationMetadata } from '../../src/ldp/representation/Representat
|
||||
import { ChainedConverter } from '../../src/storage/conversion/ChainedConverter';
|
||||
import { QuadToRdfConverter } from '../../src/storage/conversion/QuadToRdfConverter';
|
||||
import { RdfToQuadConverter } from '../../src/storage/conversion/RdfToQuadConverter';
|
||||
import { readableToString } from '../../src/util/StreamUtil';
|
||||
import { CONTENT_TYPE } from '../../src/util/UriConstants';
|
||||
import { readableToString } from '../../src/util/Util';
|
||||
|
||||
describe('A ChainedConverter', (): void => {
|
||||
const converters = [
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
import { SparqlDataAccessor } from '../../src/storage/accessors/SparqlDataAccessor';
|
||||
import { UrlContainerManager } from '../../src/storage/UrlContainerManager';
|
||||
import { INTERNAL_QUADS } from '../../src/util/ContentTypes';
|
||||
import { MetadataController } from '../../src/util/MetadataController';
|
||||
import { DataAccessorBasedConfig } from '../configs/DataAccessorBasedConfig';
|
||||
import { BASE } from '../configs/Util';
|
||||
import { describeIf, FileTestHelper } from '../util/TestHelpers';
|
||||
@@ -9,10 +7,7 @@ import { describeIf, FileTestHelper } from '../util/TestHelpers';
|
||||
describeIf('docker', 'a server with a SPARQL endpoint as storage', (): void => {
|
||||
describe('without acl', (): void => {
|
||||
const config = new DataAccessorBasedConfig(BASE,
|
||||
new SparqlDataAccessor('http://localhost:4000/sparql',
|
||||
BASE,
|
||||
new UrlContainerManager(BASE),
|
||||
new MetadataController()),
|
||||
new SparqlDataAccessor('http://localhost:4000/sparql', BASE),
|
||||
INTERNAL_QUADS);
|
||||
const handler = config.getHttpHandler();
|
||||
const fileHelper = new FileTestHelper(handler, new URL(BASE));
|
||||
|
||||
@@ -6,11 +6,11 @@ import { WebAclAuthorizer } from '../../../src/authorization/WebAclAuthorizer';
|
||||
import type { PermissionSet } from '../../../src/ldp/permissions/PermissionSet';
|
||||
import type { Representation } from '../../../src/ldp/representation/Representation';
|
||||
import type { ResourceIdentifier } from '../../../src/ldp/representation/ResourceIdentifier';
|
||||
import type { ContainerManager } from '../../../src/storage/ContainerManager';
|
||||
import type { ResourceStore } from '../../../src/storage/ResourceStore';
|
||||
import { ForbiddenHttpError } from '../../../src/util/errors/ForbiddenHttpError';
|
||||
import { NotFoundHttpError } from '../../../src/util/errors/NotFoundHttpError';
|
||||
import { UnauthorizedHttpError } from '../../../src/util/errors/UnauthorizedHttpError';
|
||||
import { getParentContainer } from '../../../src/util/PathUtil';
|
||||
|
||||
const nn = namedNode;
|
||||
|
||||
@@ -23,10 +23,6 @@ describe('A WebAclAuthorizer', (): void => {
|
||||
id.path.endsWith('.acl') ? id : { path: `${id.path}.acl` },
|
||||
isAcl: async(id: ResourceIdentifier): Promise<boolean> => id.path.endsWith('.acl'),
|
||||
};
|
||||
const containerManager: ContainerManager = {
|
||||
getContainer: async(id: ResourceIdentifier): Promise<ResourceIdentifier> =>
|
||||
({ path: new URL('..', id.path).toString() }),
|
||||
};
|
||||
let permissions: PermissionSet;
|
||||
let credentials: Credentials;
|
||||
let identifier: ResourceIdentifier;
|
||||
@@ -42,7 +38,7 @@ describe('A WebAclAuthorizer', (): void => {
|
||||
});
|
||||
|
||||
it('handles all inputs.', async(): Promise<void> => {
|
||||
authorizer = new WebAclAuthorizer(aclManager, containerManager, null as any);
|
||||
authorizer = new WebAclAuthorizer(aclManager, null as any);
|
||||
await expect(authorizer.canHandle({} as any)).resolves.toBeUndefined();
|
||||
});
|
||||
|
||||
@@ -54,7 +50,7 @@ describe('A WebAclAuthorizer', (): void => {
|
||||
quad(nn('auth'), nn(`${acl}mode`), nn(`${acl}Read`)),
|
||||
]) } as Representation),
|
||||
} as unknown as ResourceStore;
|
||||
authorizer = new WebAclAuthorizer(aclManager, containerManager, store);
|
||||
authorizer = new WebAclAuthorizer(aclManager, store);
|
||||
await expect(authorizer.handle({ identifier, permissions, credentials })).resolves.toBeUndefined();
|
||||
});
|
||||
|
||||
@@ -67,13 +63,13 @@ describe('A WebAclAuthorizer', (): void => {
|
||||
return {
|
||||
data: streamifyArray([
|
||||
quad(nn('auth'), nn(`${acl}agentClass`), nn('http://xmlns.com/foaf/0.1/Agent')),
|
||||
quad(nn('auth'), nn(`${acl}default`), nn((await containerManager.getContainer(identifier)).path)),
|
||||
quad(nn('auth'), nn(`${acl}default`), nn(getParentContainer(identifier).path)),
|
||||
quad(nn('auth'), nn(`${acl}mode`), nn(`${acl}Read`)),
|
||||
]),
|
||||
} as Representation;
|
||||
},
|
||||
} as unknown as ResourceStore;
|
||||
authorizer = new WebAclAuthorizer(aclManager, containerManager, store);
|
||||
authorizer = new WebAclAuthorizer(aclManager, store);
|
||||
await expect(authorizer.handle({ identifier, permissions, credentials })).resolves.toBeUndefined();
|
||||
});
|
||||
|
||||
@@ -85,7 +81,7 @@ describe('A WebAclAuthorizer', (): void => {
|
||||
quad(nn('auth'), nn(`${acl}mode`), nn(`${acl}Read`)),
|
||||
]) } as Representation),
|
||||
} as unknown as ResourceStore;
|
||||
authorizer = new WebAclAuthorizer(aclManager, containerManager, store);
|
||||
authorizer = new WebAclAuthorizer(aclManager, store);
|
||||
credentials.webID = 'http://test.com/user';
|
||||
await expect(authorizer.handle({ identifier, permissions, credentials })).resolves.toBeUndefined();
|
||||
});
|
||||
@@ -98,7 +94,7 @@ describe('A WebAclAuthorizer', (): void => {
|
||||
quad(nn('auth'), nn(`${acl}mode`), nn(`${acl}Read`)),
|
||||
]) } as Representation),
|
||||
} as unknown as ResourceStore;
|
||||
authorizer = new WebAclAuthorizer(aclManager, containerManager, store);
|
||||
authorizer = new WebAclAuthorizer(aclManager, store);
|
||||
await expect(authorizer.handle({ identifier, permissions, credentials })).rejects.toThrow(UnauthorizedHttpError);
|
||||
});
|
||||
|
||||
@@ -111,7 +107,7 @@ describe('A WebAclAuthorizer', (): void => {
|
||||
quad(nn('auth'), nn(`${acl}mode`), nn(`${acl}Read`)),
|
||||
]) } as Representation),
|
||||
} as unknown as ResourceStore;
|
||||
authorizer = new WebAclAuthorizer(aclManager, containerManager, store);
|
||||
authorizer = new WebAclAuthorizer(aclManager, store);
|
||||
await expect(authorizer.handle({ identifier, permissions, credentials })).resolves.toBeUndefined();
|
||||
});
|
||||
|
||||
@@ -124,7 +120,7 @@ describe('A WebAclAuthorizer', (): void => {
|
||||
quad(nn('auth'), nn(`${acl}mode`), nn(`${acl}Read`)),
|
||||
]) } as Representation),
|
||||
} as unknown as ResourceStore;
|
||||
authorizer = new WebAclAuthorizer(aclManager, containerManager, store);
|
||||
authorizer = new WebAclAuthorizer(aclManager, store);
|
||||
await expect(authorizer.handle({ identifier, permissions, credentials })).rejects.toThrow(ForbiddenHttpError);
|
||||
});
|
||||
|
||||
@@ -139,7 +135,7 @@ describe('A WebAclAuthorizer', (): void => {
|
||||
]) } as Representation),
|
||||
} as unknown as ResourceStore;
|
||||
identifier = await aclManager.getAcl(identifier);
|
||||
authorizer = new WebAclAuthorizer(aclManager, containerManager, store);
|
||||
authorizer = new WebAclAuthorizer(aclManager, store);
|
||||
await expect(authorizer.handle({ identifier, permissions, credentials })).resolves.toBeUndefined();
|
||||
});
|
||||
|
||||
@@ -154,7 +150,7 @@ describe('A WebAclAuthorizer', (): void => {
|
||||
]) } as Representation),
|
||||
} as unknown as ResourceStore;
|
||||
identifier = await aclManager.getAcl(identifier);
|
||||
authorizer = new WebAclAuthorizer(aclManager, containerManager, store);
|
||||
authorizer = new WebAclAuthorizer(aclManager, store);
|
||||
await expect(authorizer.handle({ identifier, permissions, credentials })).rejects.toThrow(ForbiddenHttpError);
|
||||
});
|
||||
|
||||
@@ -164,7 +160,7 @@ describe('A WebAclAuthorizer', (): void => {
|
||||
throw new Error('TEST!');
|
||||
},
|
||||
} as unknown as ResourceStore;
|
||||
authorizer = new WebAclAuthorizer(aclManager, containerManager, store);
|
||||
authorizer = new WebAclAuthorizer(aclManager, store);
|
||||
await expect(authorizer.handle({ identifier, permissions, credentials })).rejects.toThrow('TEST!');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -8,7 +8,7 @@ import { RepresentationMetadata } from '../../../../src/ldp/representation/Repre
|
||||
import type { HttpRequest } from '../../../../src/server/HttpRequest';
|
||||
import { UnsupportedHttpError } from '../../../../src/util/errors/UnsupportedHttpError';
|
||||
import { UnsupportedMediaTypeHttpError } from '../../../../src/util/errors/UnsupportedMediaTypeHttpError';
|
||||
import { readableToString } from '../../../../src/util/Util';
|
||||
import { readableToString } from '../../../../src/util/StreamUtil';
|
||||
|
||||
describe('A SparqlUpdateBodyParser', (): void => {
|
||||
const bodyParser = new SparqlUpdateBodyParser();
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { LinkRelMetadataWriter } from '../../../../../src/ldp/http/metadata/LinkRelMetadataWriter';
|
||||
import { RepresentationMetadata } from '../../../../../src/ldp/representation/RepresentationMetadata';
|
||||
import * as util from '../../../../../src/util/HeaderUtil';
|
||||
import { LDP, RDF } from '../../../../../src/util/UriConstants';
|
||||
import { toNamedNode } from '../../../../../src/util/UriUtil';
|
||||
import * as util from '../../../../../src/util/Util';
|
||||
|
||||
describe('A LinkRelMetadataWriter', (): void => {
|
||||
const writer = new LinkRelMetadataWriter({ [RDF.type]: 'type', dummy: 'dummy' });
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { MappedMetadataWriter } from '../../../../../src/ldp/http/metadata/MappedMetadataWriter';
|
||||
import { RepresentationMetadata } from '../../../../../src/ldp/representation/RepresentationMetadata';
|
||||
import * as util from '../../../../../src/util/HeaderUtil';
|
||||
import { CONTENT_TYPE } from '../../../../../src/util/UriConstants';
|
||||
import * as util from '../../../../../src/util/Util';
|
||||
|
||||
describe('A MappedMetadataWriter', (): void => {
|
||||
const writer = new MappedMetadataWriter({ [CONTENT_TYPE]: 'content-type', dummy: 'dummy' });
|
||||
|
||||
@@ -6,7 +6,6 @@ import type { Representation } from '../../../src/ldp/representation/Representat
|
||||
import { RepresentationMetadata } from '../../../src/ldp/representation/RepresentationMetadata';
|
||||
import type { ResourceIdentifier } from '../../../src/ldp/representation/ResourceIdentifier';
|
||||
import type { DataAccessor } from '../../../src/storage/accessors/DataAccessor';
|
||||
import type { ContainerManager } from '../../../src/storage/ContainerManager';
|
||||
import { DataAccessorBasedStore } from '../../../src/storage/DataAccessorBasedStore';
|
||||
import { INTERNAL_QUADS } from '../../../src/util/ContentTypes';
|
||||
import { ConflictHttpError } from '../../../src/util/errors/ConflictHttpError';
|
||||
@@ -14,10 +13,9 @@ import { MethodNotAllowedHttpError } from '../../../src/util/errors/MethodNotAll
|
||||
import { NotFoundHttpError } from '../../../src/util/errors/NotFoundHttpError';
|
||||
import { NotImplementedError } from '../../../src/util/errors/NotImplementedError';
|
||||
import { UnsupportedHttpError } from '../../../src/util/errors/UnsupportedHttpError';
|
||||
import { MetadataController } from '../../../src/util/MetadataController';
|
||||
import * as quadUtil from '../../../src/util/QuadUtil';
|
||||
import { CONTENT_TYPE, HTTP, LDP, RDF } from '../../../src/util/UriConstants';
|
||||
import { toNamedNode } from '../../../src/util/UriUtil';
|
||||
import { ensureTrailingSlash } from '../../../src/util/Util';
|
||||
|
||||
class SimpleDataAccessor implements DataAccessor {
|
||||
public readonly data: Record<string, Representation> = {};
|
||||
@@ -68,8 +66,6 @@ class SimpleDataAccessor implements DataAccessor {
|
||||
describe('A DataAccessorBasedStore', (): void => {
|
||||
let store: DataAccessorBasedStore;
|
||||
let accessor: SimpleDataAccessor;
|
||||
let containerManager: ContainerManager;
|
||||
let metadataController: MetadataController;
|
||||
const root = 'http://test.com/';
|
||||
let containerMetadata: RepresentationMetadata;
|
||||
let representation: Representation;
|
||||
@@ -78,20 +74,7 @@ describe('A DataAccessorBasedStore', (): void => {
|
||||
beforeEach(async(): Promise<void> => {
|
||||
accessor = new SimpleDataAccessor();
|
||||
|
||||
metadataController = new MetadataController();
|
||||
|
||||
containerManager = {
|
||||
async getContainer(id: ResourceIdentifier): Promise<ResourceIdentifier> {
|
||||
return { path: new URL('..', ensureTrailingSlash(id.path)).toString() };
|
||||
},
|
||||
};
|
||||
|
||||
store = new DataAccessorBasedStore(
|
||||
accessor,
|
||||
root,
|
||||
metadataController,
|
||||
containerManager,
|
||||
);
|
||||
store = new DataAccessorBasedStore(accessor, root);
|
||||
|
||||
containerMetadata = new RepresentationMetadata(
|
||||
{ [RDF.type]: [ DataFactory.namedNode(LDP.Container), DataFactory.namedNode(LDP.BasicContainer) ]},
|
||||
@@ -171,11 +154,12 @@ describe('A DataAccessorBasedStore', (): void => {
|
||||
|
||||
it('passes the result along if the MetadataController throws a non-Error.', async(): Promise<void> => {
|
||||
const resourceID = { path: root };
|
||||
metadataController.parseQuads = async(): Promise<any> => {
|
||||
const mock = jest.spyOn(quadUtil, 'parseQuads').mockImplementationOnce(async(): Promise<any> => {
|
||||
throw 'apple';
|
||||
};
|
||||
});
|
||||
representation.metadata.add(RDF.type, toNamedNode(LDP.Container));
|
||||
await expect(store.addResource(resourceID, representation)).rejects.toBe('apple');
|
||||
mock.mockRestore();
|
||||
});
|
||||
|
||||
it('can write resources.', async(): Promise<void> => {
|
||||
|
||||
@@ -2,7 +2,7 @@ import fs from 'fs';
|
||||
import { ExtensionBasedMapper } from '../../../src/storage/ExtensionBasedMapper';
|
||||
import { NotFoundHttpError } from '../../../src/util/errors/NotFoundHttpError';
|
||||
import { UnsupportedHttpError } from '../../../src/util/errors/UnsupportedHttpError';
|
||||
import { trimTrailingSlashes } from '../../../src/util/Util';
|
||||
import { trimTrailingSlashes } from '../../../src/util/PathUtil';
|
||||
|
||||
jest.mock('fs');
|
||||
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
import { UrlContainerManager } from '../../../src/storage/UrlContainerManager';
|
||||
|
||||
describe('An UrlContainerManager', (): void => {
|
||||
it('returns the parent URl for a single call.', async(): Promise<void> => {
|
||||
const manager = new UrlContainerManager('http://test.com/foo/');
|
||||
await expect(manager.getContainer({ path: 'http://test.com/foo/bar' }))
|
||||
.resolves.toEqual({ path: 'http://test.com/foo/' });
|
||||
await expect(manager.getContainer({ path: 'http://test.com/foo/bar/' }))
|
||||
.resolves.toEqual({ path: 'http://test.com/foo/' });
|
||||
});
|
||||
|
||||
it('errors when getting the container of root.', async(): Promise<void> => {
|
||||
let manager = new UrlContainerManager('http://test.com/foo/');
|
||||
await expect(manager.getContainer({ path: 'http://test.com/foo/' }))
|
||||
.rejects.toThrow('Root does not have a container');
|
||||
await expect(manager.getContainer({ path: 'http://test.com/foo' }))
|
||||
.rejects.toThrow('Root does not have a container');
|
||||
|
||||
manager = new UrlContainerManager('http://test.com/foo/');
|
||||
await expect(manager.getContainer({ path: 'http://test.com/foo/' }))
|
||||
.rejects.toThrow('Root does not have a container');
|
||||
await expect(manager.getContainer({ path: 'http://test.com/foo' }))
|
||||
.rejects.toThrow('Root does not have a container');
|
||||
});
|
||||
|
||||
it('errors when the root of an URl is reached that does not match the input root.', async(): Promise<void> => {
|
||||
const manager = new UrlContainerManager('http://test.com/foo/');
|
||||
await expect(manager.getContainer({ path: 'http://test.com/' }))
|
||||
.rejects.toThrow('URL root reached');
|
||||
});
|
||||
});
|
||||
@@ -9,10 +9,9 @@ import { ConflictHttpError } from '../../../../src/util/errors/ConflictHttpError
|
||||
import { NotFoundHttpError } from '../../../../src/util/errors/NotFoundHttpError';
|
||||
import type { SystemError } from '../../../../src/util/errors/SystemError';
|
||||
import { UnsupportedMediaTypeHttpError } from '../../../../src/util/errors/UnsupportedMediaTypeHttpError';
|
||||
import { MetadataController } from '../../../../src/util/MetadataController';
|
||||
import { readableToString } from '../../../../src/util/StreamUtil';
|
||||
import { CONTENT_TYPE, DCTERMS, LDP, POSIX, RDF, XSD } from '../../../../src/util/UriConstants';
|
||||
import { toNamedNode, toTypedLiteral } from '../../../../src/util/UriUtil';
|
||||
import { readableToString } from '../../../../src/util/Util';
|
||||
import { mockFs } from '../../../util/Util';
|
||||
|
||||
jest.mock('fs');
|
||||
@@ -28,10 +27,7 @@ describe('A FileDataAccessor', (): void => {
|
||||
|
||||
beforeEach(async(): Promise<void> => {
|
||||
cache = mockFs(rootFilePath, now);
|
||||
accessor = new FileDataAccessor(
|
||||
new ExtensionBasedMapper(base, rootFilePath),
|
||||
new MetadataController(),
|
||||
);
|
||||
accessor = new FileDataAccessor(new ExtensionBasedMapper(base, rootFilePath));
|
||||
|
||||
metadata = new RepresentationMetadata({ [CONTENT_TYPE]: APPLICATION_OCTET_STREAM });
|
||||
});
|
||||
|
||||
@@ -3,10 +3,9 @@ import { RepresentationMetadata } from '../../../../src/ldp/representation/Repre
|
||||
import { InMemoryDataAccessor } from '../../../../src/storage/accessors/InMemoryDataAccessor';
|
||||
import { APPLICATION_OCTET_STREAM } from '../../../../src/util/ContentTypes';
|
||||
import { NotFoundHttpError } from '../../../../src/util/errors/NotFoundHttpError';
|
||||
import { MetadataController } from '../../../../src/util/MetadataController';
|
||||
import { readableToString } from '../../../../src/util/StreamUtil';
|
||||
import { CONTENT_TYPE, LDP, RDF } from '../../../../src/util/UriConstants';
|
||||
import { toNamedNode } from '../../../../src/util/UriUtil';
|
||||
import { readableToString } from '../../../../src/util/Util';
|
||||
|
||||
describe('An InMemoryDataAccessor', (): void => {
|
||||
const base = 'http://test.com/';
|
||||
@@ -14,10 +13,7 @@ describe('An InMemoryDataAccessor', (): void => {
|
||||
let metadata: RepresentationMetadata;
|
||||
|
||||
beforeEach(async(): Promise<void> => {
|
||||
accessor = new InMemoryDataAccessor(
|
||||
base,
|
||||
new MetadataController(),
|
||||
);
|
||||
accessor = new InMemoryDataAccessor(base);
|
||||
|
||||
metadata = new RepresentationMetadata({ [CONTENT_TYPE]: APPLICATION_OCTET_STREAM });
|
||||
});
|
||||
|
||||
@@ -6,13 +6,11 @@ import type { Quad } from 'rdf-js';
|
||||
import streamifyArray from 'streamify-array';
|
||||
import { RepresentationMetadata } from '../../../../src/ldp/representation/RepresentationMetadata';
|
||||
import { SparqlDataAccessor } from '../../../../src/storage/accessors/SparqlDataAccessor';
|
||||
import { UrlContainerManager } from '../../../../src/storage/UrlContainerManager';
|
||||
import { INTERNAL_QUADS } from '../../../../src/util/ContentTypes';
|
||||
import { ConflictHttpError } from '../../../../src/util/errors/ConflictHttpError';
|
||||
import { NotFoundHttpError } from '../../../../src/util/errors/NotFoundHttpError';
|
||||
import { UnsupportedHttpError } from '../../../../src/util/errors/UnsupportedHttpError';
|
||||
import { UnsupportedMediaTypeHttpError } from '../../../../src/util/errors/UnsupportedMediaTypeHttpError';
|
||||
import { MetadataController } from '../../../../src/util/MetadataController';
|
||||
import { CONTENT_TYPE, LDP, RDF } from '../../../../src/util/UriConstants';
|
||||
import { toNamedNode } from '../../../../src/util/UriUtil';
|
||||
|
||||
@@ -60,7 +58,7 @@ describe('A SparqlDataAccessor', (): void => {
|
||||
}));
|
||||
|
||||
// This needs to be last so the fetcher can be mocked first
|
||||
accessor = new SparqlDataAccessor(endpoint, base, new UrlContainerManager(base), new MetadataController());
|
||||
accessor = new SparqlDataAccessor(endpoint, base);
|
||||
});
|
||||
|
||||
it('can only handle quad data.', async(): Promise<void> => {
|
||||
|
||||
@@ -2,7 +2,7 @@ import type { Representation } from '../../../../src/ldp/representation/Represen
|
||||
import { RepresentationMetadata } from '../../../../src/ldp/representation/RepresentationMetadata';
|
||||
import type { RepresentationPreferences } from '../../../../src/ldp/representation/RepresentationPreferences';
|
||||
import { ChainedConverter } from '../../../../src/storage/conversion/ChainedConverter';
|
||||
import { checkRequest } from '../../../../src/storage/conversion/ConversionUtil';
|
||||
import { validateRequestArgs } from '../../../../src/storage/conversion/ConversionUtil';
|
||||
import type { RepresentationConverterArgs } from '../../../../src/storage/conversion/RepresentationConverter';
|
||||
import { TypedRepresentationConverter } from '../../../../src/storage/conversion/TypedRepresentationConverter';
|
||||
import { CONTENT_TYPE } from '../../../../src/util/UriConstants';
|
||||
@@ -26,7 +26,7 @@ class DummyConverter extends TypedRepresentationConverter {
|
||||
}
|
||||
|
||||
public async canHandle(input: RepresentationConverterArgs): Promise<void> {
|
||||
checkRequest(input, Object.keys(this.inTypes), Object.keys(this.outTypes));
|
||||
validateRequestArgs(input, Object.keys(this.inTypes), Object.keys(this.outTypes));
|
||||
}
|
||||
|
||||
public async handle(input: RepresentationConverterArgs): Promise<Representation> {
|
||||
|
||||
@@ -2,11 +2,15 @@ import type { Representation } from '../../../../src/ldp/representation/Represen
|
||||
import { RepresentationMetadata } from '../../../../src/ldp/representation/RepresentationMetadata';
|
||||
import type { RepresentationPreferences } from '../../../../src/ldp/representation/RepresentationPreferences';
|
||||
import type { ResourceIdentifier } from '../../../../src/ldp/representation/ResourceIdentifier';
|
||||
import { checkRequest, matchingTypes } from '../../../../src/storage/conversion/ConversionUtil';
|
||||
import {
|
||||
matchingMediaType,
|
||||
matchingTypes,
|
||||
validateRequestArgs,
|
||||
} from '../../../../src/storage/conversion/ConversionUtil';
|
||||
import { InternalServerError } from '../../../../src/util/errors/InternalServerError';
|
||||
import { UnsupportedHttpError } from '../../../../src/util/errors/UnsupportedHttpError';
|
||||
|
||||
describe('A ConversionUtil', (): void => {
|
||||
describe('ConversionUtil', (): void => {
|
||||
const identifier: ResourceIdentifier = { path: 'path' };
|
||||
let representation: Representation;
|
||||
let metadata: RepresentationMetadata;
|
||||
@@ -16,31 +20,31 @@ describe('A ConversionUtil', (): void => {
|
||||
representation = { metadata } as Representation;
|
||||
});
|
||||
|
||||
describe('#checkRequest', (): void => {
|
||||
describe('#validateRequestArgs', (): void => {
|
||||
it('requires an input type.', async(): Promise<void> => {
|
||||
const preferences: RepresentationPreferences = {};
|
||||
expect((): any => checkRequest({ identifier, representation, preferences }, [ 'a/x' ], [ 'a/x' ]))
|
||||
expect((): any => validateRequestArgs({ identifier, representation, preferences }, [ 'a/x' ], [ 'a/x' ]))
|
||||
.toThrow('Input type required for conversion.');
|
||||
});
|
||||
|
||||
it('requires a matching input type.', async(): Promise<void> => {
|
||||
metadata.contentType = 'a/x';
|
||||
const preferences: RepresentationPreferences = { type: [{ value: 'b/x', weight: 1 }]};
|
||||
expect((): any => checkRequest({ identifier, representation, preferences }, [ 'c/x' ], [ 'a/x' ]))
|
||||
expect((): any => validateRequestArgs({ identifier, representation, preferences }, [ 'c/x' ], [ 'a/x' ]))
|
||||
.toThrow('Can only convert from c/x to a/x.');
|
||||
});
|
||||
|
||||
it('requires a matching output type.', async(): Promise<void> => {
|
||||
metadata.contentType = 'a/x';
|
||||
const preferences: RepresentationPreferences = { type: [{ value: 'b/x', weight: 1 }]};
|
||||
expect((): any => checkRequest({ identifier, representation, preferences }, [ 'a/x' ], [ 'c/x' ]))
|
||||
expect((): any => validateRequestArgs({ identifier, representation, preferences }, [ 'a/x' ], [ 'c/x' ]))
|
||||
.toThrow('Can only convert from a/x to c/x.');
|
||||
});
|
||||
|
||||
it('succeeds with a valid input and output type.', async(): Promise<void> => {
|
||||
metadata.contentType = 'a/x';
|
||||
const preferences: RepresentationPreferences = { type: [{ value: 'b/x', weight: 1 }]};
|
||||
expect(checkRequest({ identifier, representation, preferences }, [ 'a/x' ], [ 'b/x' ]))
|
||||
expect(validateRequestArgs({ identifier, representation, preferences }, [ 'a/x' ], [ 'b/x' ]))
|
||||
.toBeUndefined();
|
||||
});
|
||||
});
|
||||
@@ -91,4 +95,18 @@ describe('A ConversionUtil', (): void => {
|
||||
.toEqual([{ value: 'a/x', weight: 1 }, { value: 'internal/quads', weight: 0.5 }]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#matchingMediaType', (): void => {
|
||||
it('matches all possible media types.', async(): Promise<void> => {
|
||||
expect(matchingMediaType('*/*', 'text/turtle')).toBeTruthy();
|
||||
expect(matchingMediaType('text/*', '*/*')).toBeTruthy();
|
||||
expect(matchingMediaType('text/*', 'text/turtle')).toBeTruthy();
|
||||
expect(matchingMediaType('text/plain', 'text/*')).toBeTruthy();
|
||||
expect(matchingMediaType('text/turtle', 'text/turtle')).toBeTruthy();
|
||||
|
||||
expect(matchingMediaType('text/*', 'application/*')).toBeFalsy();
|
||||
expect(matchingMediaType('text/plain', 'application/*')).toBeFalsy();
|
||||
expect(matchingMediaType('text/plain', 'text/turtle')).toBeFalsy();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import type { HttpResponse } from '../../../src/server/HttpResponse';
|
||||
import {
|
||||
addHeader,
|
||||
parseAccept,
|
||||
parseAcceptCharset,
|
||||
parseAcceptEncoding,
|
||||
@@ -6,7 +8,7 @@ import {
|
||||
} from '../../../src/util/HeaderUtil';
|
||||
|
||||
describe('HeaderUtil', (): void => {
|
||||
describe('parseAccept function', (): void => {
|
||||
describe('#parseAccept', (): void => {
|
||||
it('parses empty Accept headers.', async(): Promise<void> => {
|
||||
expect(parseAccept('')).toEqual([]);
|
||||
});
|
||||
@@ -71,7 +73,7 @@ describe('HeaderUtil', (): void => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('parseCharset function', (): void => {
|
||||
describe('#parseCharset', (): void => {
|
||||
it('parses Accept-Charset headers.', async(): Promise<void> => {
|
||||
expect(parseAcceptCharset('iso-8859-5, unicode-1-1;q=0.8')).toEqual([
|
||||
{ range: 'iso-8859-5', weight: 1 },
|
||||
@@ -86,7 +88,7 @@ describe('HeaderUtil', (): void => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('parseEncoding function', (): void => {
|
||||
describe('#parseEncoding', (): void => {
|
||||
it('parses empty Accept-Encoding headers.', async(): Promise<void> => {
|
||||
expect(parseAcceptCharset('')).toEqual([]);
|
||||
});
|
||||
@@ -106,7 +108,7 @@ describe('HeaderUtil', (): void => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('parseLanguage function', (): void => {
|
||||
describe('#parseLanguage', (): void => {
|
||||
it('parses Accept-Language headers.', async(): Promise<void> => {
|
||||
expect(parseAcceptLanguage('da, en-gb;q=0.8, en;q=0.7')).toEqual([
|
||||
{ range: 'da', weight: 1 },
|
||||
@@ -127,4 +129,41 @@ describe('HeaderUtil', (): void => {
|
||||
expect((): any => parseAcceptCharset('a; c=d')).toThrow('Only q parameters are allowed');
|
||||
});
|
||||
});
|
||||
|
||||
describe('#addHeader', (): void => {
|
||||
let response: HttpResponse;
|
||||
|
||||
beforeEach(async(): Promise<void> => {
|
||||
const headers: Record<string, string | number | string[]> = {};
|
||||
response = {
|
||||
hasHeader: (name: string): boolean => Boolean(headers[name]),
|
||||
getHeader: (name: string): number | string | string[] | undefined => headers[name],
|
||||
setHeader(name: string, value: number | string | string[]): void {
|
||||
headers[name] = value;
|
||||
},
|
||||
} as any;
|
||||
});
|
||||
|
||||
it('adds values if there are none already.', async(): Promise<void> => {
|
||||
expect(addHeader(response, 'name', 'value')).toBeUndefined();
|
||||
expect(response.getHeader('name')).toBe('value');
|
||||
|
||||
expect(addHeader(response, 'names', [ 'value1', 'values2' ])).toBeUndefined();
|
||||
expect(response.getHeader('names')).toEqual([ 'value1', 'values2' ]);
|
||||
});
|
||||
|
||||
it('appends values to already existing values.', async(): Promise<void> => {
|
||||
response.setHeader('name', 'oldValue');
|
||||
expect(addHeader(response, 'name', 'value')).toBeUndefined();
|
||||
expect(response.getHeader('name')).toEqual([ 'oldValue', 'value' ]);
|
||||
|
||||
response.setHeader('number', 5);
|
||||
expect(addHeader(response, 'number', 'value')).toBeUndefined();
|
||||
expect(response.getHeader('number')).toEqual([ '5', 'value' ]);
|
||||
|
||||
response.setHeader('names', [ 'oldValue1', 'oldValue2' ]);
|
||||
expect(addHeader(response, 'names', [ 'value1', 'values2' ])).toBeUndefined();
|
||||
expect(response.getHeader('names')).toEqual([ 'oldValue1', 'oldValue2', 'value1', 'values2' ]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
43
test/unit/util/PathUtil.test.ts
Normal file
43
test/unit/util/PathUtil.test.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
import {
|
||||
decodeUriPathComponents,
|
||||
encodeUriPathComponents,
|
||||
ensureTrailingSlash,
|
||||
getParentContainer,
|
||||
toCanonicalUriPath,
|
||||
} from '../../../src/util/PathUtil';
|
||||
|
||||
describe('PathUtil', (): void => {
|
||||
describe('#ensureTrailingSlash', (): void => {
|
||||
it('makes sure there is always exactly 1 slash.', async(): Promise<void> => {
|
||||
expect(ensureTrailingSlash('http://test.com')).toEqual('http://test.com/');
|
||||
expect(ensureTrailingSlash('http://test.com/')).toEqual('http://test.com/');
|
||||
expect(ensureTrailingSlash('http://test.com//')).toEqual('http://test.com/');
|
||||
expect(ensureTrailingSlash('http://test.com///')).toEqual('http://test.com/');
|
||||
});
|
||||
});
|
||||
|
||||
describe('UriPath functions', (): void => {
|
||||
it('makes sure only the necessary parts are encoded with toCanonicalUriPath.', async(): Promise<void> => {
|
||||
expect(toCanonicalUriPath('/a%20path&/name')).toEqual('/a%20path%26/name');
|
||||
});
|
||||
|
||||
it('decodes all parts of a path with decodeUriPathComponents.', async(): Promise<void> => {
|
||||
expect(decodeUriPathComponents('/a%20path&/name')).toEqual('/a path&/name');
|
||||
});
|
||||
|
||||
it('encodes all parts of a path with encodeUriPathComponents.', async(): Promise<void> => {
|
||||
expect(encodeUriPathComponents('/a%20path&/name')).toEqual('/a%2520path%26/name');
|
||||
});
|
||||
});
|
||||
|
||||
describe('#getParentContainer', (): void => {
|
||||
it('returns the parent URl for a single call.', async(): Promise<void> => {
|
||||
expect(getParentContainer({ path: 'http://test.com/foo/bar' })).toEqual({ path: 'http://test.com/foo/' });
|
||||
expect(getParentContainer({ path: 'http://test.com/foo/bar/' })).toEqual({ path: 'http://test.com/foo/' });
|
||||
});
|
||||
|
||||
it('errors when the root of an URl is reached that does not match the input root.', async(): Promise<void> => {
|
||||
expect((): any => getParentContainer({ path: 'http://test.com/' })).toThrow('URL root reached');
|
||||
});
|
||||
});
|
||||
});
|
||||
15
test/unit/util/QuadUtil.test.ts
Normal file
15
test/unit/util/QuadUtil.test.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import { DataFactory } from 'n3';
|
||||
import type { Quad } from 'rdf-js';
|
||||
import { pushQuad } from '../../../src/util/QuadUtil';
|
||||
|
||||
describe('QuadUtil', (): void => {
|
||||
describe('#pushQuad', (): void => {
|
||||
it('creates a quad and adds it to the given array.', async(): Promise<void> => {
|
||||
const quads: Quad[] = [];
|
||||
pushQuad(quads, DataFactory.namedNode('sub'), DataFactory.namedNode('pred'), DataFactory.literal('obj'));
|
||||
expect(quads).toEqualRdfQuadArray([
|
||||
DataFactory.quad(DataFactory.namedNode('sub'), DataFactory.namedNode('pred'), DataFactory.literal('obj')),
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
||||
43
test/unit/util/StreamUtil.test.ts
Normal file
43
test/unit/util/StreamUtil.test.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
import { PassThrough } from 'stream';
|
||||
import streamifyArray from 'streamify-array';
|
||||
import { pipeSafely, readableToString } from '../../../src/util/StreamUtil';
|
||||
|
||||
describe('StreamUtil', (): void => {
|
||||
describe('#readableToString', (): void => {
|
||||
it('concatenates all elements of a Readable.', async(): Promise<void> => {
|
||||
const stream = streamifyArray([ 'a', 'b', 'c' ]);
|
||||
await expect(readableToString(stream)).resolves.toEqual('abc');
|
||||
});
|
||||
});
|
||||
|
||||
describe('#pipeSafely', (): void => {
|
||||
it('pipes data from one stream to the other.', async(): Promise<void> => {
|
||||
const input = streamifyArray([ 'data' ]);
|
||||
const output = new PassThrough();
|
||||
const piped = pipeSafely(input, output);
|
||||
await expect(readableToString(piped)).resolves.toEqual('data');
|
||||
});
|
||||
|
||||
it('pipes errors from one stream to the other.', async(): Promise<void> => {
|
||||
const input = new PassThrough();
|
||||
input.read = (): any => {
|
||||
input.emit('error', new Error('error'));
|
||||
return null;
|
||||
};
|
||||
const output = new PassThrough();
|
||||
const piped = pipeSafely(input, output);
|
||||
await expect(readableToString(piped)).rejects.toThrow(new Error('error'));
|
||||
});
|
||||
|
||||
it('supports mapping errors to something else.', async(): Promise<void> => {
|
||||
const input = streamifyArray([ 'data' ]);
|
||||
input.read = (): any => {
|
||||
input.emit('error', new Error('error'));
|
||||
return null;
|
||||
};
|
||||
const output = new PassThrough();
|
||||
const piped = pipeSafely(input, output, (): any => new Error('other error'));
|
||||
await expect(readableToString(piped)).rejects.toThrow(new Error('other error'));
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,138 +0,0 @@
|
||||
import { PassThrough } from 'stream';
|
||||
import { DataFactory } from 'n3';
|
||||
import type { Quad } from 'rdf-js';
|
||||
import streamifyArray from 'streamify-array';
|
||||
import type { HttpResponse } from '../../../src/server/HttpResponse';
|
||||
import {
|
||||
addHeader,
|
||||
decodeUriPathComponents,
|
||||
encodeUriPathComponents,
|
||||
ensureTrailingSlash,
|
||||
matchingMediaType, pipeSafe, pushQuad,
|
||||
readableToString,
|
||||
toCanonicalUriPath,
|
||||
} from '../../../src/util/Util';
|
||||
|
||||
describe('Util function', (): void => {
|
||||
describe('ensureTrailingSlash', (): void => {
|
||||
it('makes sure there is always exactly 1 slash.', async(): Promise<void> => {
|
||||
expect(ensureTrailingSlash('http://test.com')).toEqual('http://test.com/');
|
||||
expect(ensureTrailingSlash('http://test.com/')).toEqual('http://test.com/');
|
||||
expect(ensureTrailingSlash('http://test.com//')).toEqual('http://test.com/');
|
||||
expect(ensureTrailingSlash('http://test.com///')).toEqual('http://test.com/');
|
||||
});
|
||||
});
|
||||
|
||||
describe('readableToString', (): void => {
|
||||
it('concatenates all elements of a Readable.', async(): Promise<void> => {
|
||||
const stream = streamifyArray([ 'a', 'b', 'c' ]);
|
||||
await expect(readableToString(stream)).resolves.toEqual('abc');
|
||||
});
|
||||
});
|
||||
|
||||
describe('matchingMediaType', (): void => {
|
||||
it('matches all possible media types.', async(): Promise<void> => {
|
||||
expect(matchingMediaType('*/*', 'text/turtle')).toBeTruthy();
|
||||
expect(matchingMediaType('text/*', '*/*')).toBeTruthy();
|
||||
expect(matchingMediaType('text/*', 'text/turtle')).toBeTruthy();
|
||||
expect(matchingMediaType('text/plain', 'text/*')).toBeTruthy();
|
||||
expect(matchingMediaType('text/turtle', 'text/turtle')).toBeTruthy();
|
||||
|
||||
expect(matchingMediaType('text/*', 'application/*')).toBeFalsy();
|
||||
expect(matchingMediaType('text/plain', 'application/*')).toBeFalsy();
|
||||
expect(matchingMediaType('text/plain', 'text/turtle')).toBeFalsy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('pipeStreamsAndErrors', (): void => {
|
||||
it('pipes data from one stream to the other.', async(): Promise<void> => {
|
||||
const input = streamifyArray([ 'data' ]);
|
||||
const output = new PassThrough();
|
||||
const piped = pipeSafe(input, output);
|
||||
await expect(readableToString(piped)).resolves.toEqual('data');
|
||||
});
|
||||
|
||||
it('pipes errors from one stream to the other.', async(): Promise<void> => {
|
||||
const input = new PassThrough();
|
||||
input.read = (): any => {
|
||||
input.emit('error', new Error('error'));
|
||||
return null;
|
||||
};
|
||||
const output = new PassThrough();
|
||||
const piped = pipeSafe(input, output);
|
||||
await expect(readableToString(piped)).rejects.toThrow(new Error('error'));
|
||||
});
|
||||
|
||||
it('supports mapping errors to something else.', async(): Promise<void> => {
|
||||
const input = streamifyArray([ 'data' ]);
|
||||
input.read = (): any => {
|
||||
input.emit('error', new Error('error'));
|
||||
return null;
|
||||
};
|
||||
const output = new PassThrough();
|
||||
const piped = pipeSafe(input, output, (): any => new Error('other error'));
|
||||
await expect(readableToString(piped)).rejects.toThrow(new Error('other error'));
|
||||
});
|
||||
});
|
||||
|
||||
describe('UriPath functions', (): void => {
|
||||
it('makes sure only the necessary parts are encoded with toCanonicalUriPath.', async(): Promise<void> => {
|
||||
expect(toCanonicalUriPath('/a%20path&/name')).toEqual('/a%20path%26/name');
|
||||
});
|
||||
|
||||
it('decodes all parts of a path with decodeUriPathComponents.', async(): Promise<void> => {
|
||||
expect(decodeUriPathComponents('/a%20path&/name')).toEqual('/a path&/name');
|
||||
});
|
||||
|
||||
it('encodes all parts of a path with encodeUriPathComponents.', async(): Promise<void> => {
|
||||
expect(encodeUriPathComponents('/a%20path&/name')).toEqual('/a%2520path%26/name');
|
||||
});
|
||||
});
|
||||
|
||||
describe('pushQuad', (): void => {
|
||||
it('creates a quad and adds it to the given array.', async(): Promise<void> => {
|
||||
const quads: Quad[] = [];
|
||||
pushQuad(quads, DataFactory.namedNode('sub'), DataFactory.namedNode('pred'), DataFactory.literal('obj'));
|
||||
expect(quads).toEqualRdfQuadArray([
|
||||
DataFactory.quad(DataFactory.namedNode('sub'), DataFactory.namedNode('pred'), DataFactory.literal('obj')),
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('addHeader', (): void => {
|
||||
let response: HttpResponse;
|
||||
|
||||
beforeEach(async(): Promise<void> => {
|
||||
const headers: Record<string, string | number | string[]> = {};
|
||||
response = {
|
||||
hasHeader: (name: string): boolean => Boolean(headers[name]),
|
||||
getHeader: (name: string): number | string | string[] | undefined => headers[name],
|
||||
setHeader(name: string, value: number | string | string[]): void {
|
||||
headers[name] = value;
|
||||
},
|
||||
} as any;
|
||||
});
|
||||
|
||||
it('adds values if there are none already.', async(): Promise<void> => {
|
||||
expect(addHeader(response, 'name', 'value')).toBeUndefined();
|
||||
expect(response.getHeader('name')).toBe('value');
|
||||
|
||||
expect(addHeader(response, 'names', [ 'value1', 'values2' ])).toBeUndefined();
|
||||
expect(response.getHeader('names')).toEqual([ 'value1', 'values2' ]);
|
||||
});
|
||||
|
||||
it('appends values to already existing values.', async(): Promise<void> => {
|
||||
response.setHeader('name', 'oldValue');
|
||||
expect(addHeader(response, 'name', 'value')).toBeUndefined();
|
||||
expect(response.getHeader('name')).toEqual([ 'oldValue', 'value' ]);
|
||||
|
||||
response.setHeader('number', 5);
|
||||
expect(addHeader(response, 'number', 'value')).toBeUndefined();
|
||||
expect(response.getHeader('number')).toEqual([ '5', 'value' ]);
|
||||
|
||||
response.setHeader('names', [ 'oldValue1', 'oldValue2' ]);
|
||||
expect(addHeader(response, 'names', [ 'value1', 'values2' ])).toBeUndefined();
|
||||
expect(response.getHeader('names')).toEqual([ 'oldValue1', 'oldValue2', 'value1', 'values2' ]);
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user