mirror of
https://github.com/CommunitySolidServer/CommunitySolidServer.git
synced 2024-10-03 14:55:10 +00:00
feat: Incorporate server-side representation quality.
Closes https://github.com/solid/community-server/issues/467
This commit is contained in:
@@ -42,7 +42,7 @@ describe('A RepresentationConvertingStore', (): void => {
|
||||
expect(source.getRepresentation).toHaveBeenCalledTimes(1);
|
||||
expect(source.getRepresentation).toHaveBeenLastCalledWith(
|
||||
{ path: 'path' },
|
||||
{ type: { 'application/*': 0, 'text/turtle': 1, 'internal/*': 0 }},
|
||||
{ type: { 'application/*': 0, 'text/turtle': 1 }},
|
||||
undefined,
|
||||
);
|
||||
expect(outConverter.handleSafe).toHaveBeenCalledTimes(0);
|
||||
@@ -70,7 +70,7 @@ describe('A RepresentationConvertingStore', (): void => {
|
||||
expect(outConverter.handleSafe).toHaveBeenLastCalledWith({
|
||||
identifier: { path: 'path' },
|
||||
representation: { data: 'data', metadata },
|
||||
preferences: { type: { 'text/plain': 1, 'text/turtle': 0, 'internal/*': 0 }},
|
||||
preferences: { type: { 'text/plain': 1, 'text/turtle': 0 }},
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@ import type {
|
||||
RepresentationPreferences,
|
||||
} from '../../../../src/ldp/representation/RepresentationPreferences';
|
||||
import { ChainedConverter } from '../../../../src/storage/conversion/ChainedConverter';
|
||||
import { supportsConversion } 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/Vocabularies';
|
||||
@@ -28,10 +27,6 @@ class DummyConverter extends TypedRepresentationConverter {
|
||||
return this.outTypes;
|
||||
}
|
||||
|
||||
public async canHandle(input: RepresentationConverterArgs): Promise<void> {
|
||||
supportsConversion(input, Object.keys(this.inTypes), Object.keys(this.outTypes));
|
||||
}
|
||||
|
||||
public async handle(input: RepresentationConverterArgs): Promise<Representation> {
|
||||
const metadata = new RepresentationMetadata(input.representation.metadata,
|
||||
{ [CONTENT_TYPE]: Object.keys(input.preferences.type!)[0] });
|
||||
@@ -85,7 +80,7 @@ describe('A ChainedConverter', (): void => {
|
||||
});
|
||||
|
||||
it('errors if the end of the chain does not support the preferences.', async(): Promise<void> => {
|
||||
delete preferences.type;
|
||||
preferences.type = { 'abc/def': 1 };
|
||||
await expect(converter.canHandle(args)).rejects.toThrow();
|
||||
});
|
||||
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import type { Representation } from '../../../../src/ldp/representation/Representation';
|
||||
import { RepresentationMetadata } from '../../../../src/ldp/representation/RepresentationMetadata';
|
||||
import type { RepresentationPreferences } from '../../../../src/ldp/representation/RepresentationPreferences';
|
||||
import type {
|
||||
ValuePreferences,
|
||||
RepresentationPreferences,
|
||||
} from '../../../../src/ldp/representation/RepresentationPreferences';
|
||||
import type { ResourceIdentifier } from '../../../../src/ldp/representation/ResourceIdentifier';
|
||||
import {
|
||||
matchesMediaType,
|
||||
@@ -22,15 +25,19 @@ describe('ConversionUtil', (): void => {
|
||||
describe('#supportsConversion', (): void => {
|
||||
it('requires an input type.', async(): Promise<void> => {
|
||||
const preferences: RepresentationPreferences = {};
|
||||
expect((): any => supportsConversion({ identifier, representation, preferences }, [ 'a/x' ], [ 'a/x' ]))
|
||||
.toThrow('Input type required for conversion.');
|
||||
expect((): any => supportsConversion({ identifier, representation, preferences },
|
||||
{ 'a/x': 1 },
|
||||
{ 'a/x': 1 }))
|
||||
.toThrow('No content type indicated on request.');
|
||||
});
|
||||
|
||||
it('requires a matching input type.', async(): Promise<void> => {
|
||||
metadata.contentType = 'a/x';
|
||||
const preferences: RepresentationPreferences =
|
||||
{ type: { 'b/x': 1 }};
|
||||
expect((): any => supportsConversion({ identifier, representation, preferences }, [ 'c/x' ], [ 'a/x' ]))
|
||||
expect((): any => supportsConversion({ identifier, representation, preferences },
|
||||
{ 'c/x': 1 },
|
||||
{ 'a/x': 1 }))
|
||||
.toThrow('Can only convert from c/x to a/x.');
|
||||
});
|
||||
|
||||
@@ -38,7 +45,9 @@ describe('ConversionUtil', (): void => {
|
||||
metadata.contentType = 'a/x';
|
||||
const preferences: RepresentationPreferences =
|
||||
{ type: { 'b/x': 1 }};
|
||||
expect((): any => supportsConversion({ identifier, representation, preferences }, [ 'a/x' ], [ 'c/x' ]))
|
||||
expect((): any => supportsConversion({ identifier, representation, preferences },
|
||||
{ 'a/x': 1 },
|
||||
{ 'c/x': 1 }))
|
||||
.toThrow('Can only convert from a/x to c/x.');
|
||||
});
|
||||
|
||||
@@ -46,58 +55,58 @@ describe('ConversionUtil', (): void => {
|
||||
metadata.contentType = 'a/x';
|
||||
const preferences: RepresentationPreferences =
|
||||
{ type: { 'b/x': 1 }};
|
||||
expect(supportsConversion({ identifier, representation, preferences }, [ 'a/x' ], [ 'b/x' ]))
|
||||
expect(supportsConversion({ identifier, representation, preferences },
|
||||
{ 'a/x': 1 },
|
||||
{ 'b/x': 1 }))
|
||||
.toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('#matchingMediaTypes', (): void => {
|
||||
it('requires type preferences.', async(): Promise<void> => {
|
||||
const preferences: RepresentationPreferences =
|
||||
{};
|
||||
expect((): any => matchingMediaTypes(preferences, [ 'a/b' ]))
|
||||
.toThrow('Output type required for conversion.');
|
||||
it('returns the empty array if no preferences specified.', async(): Promise<void> => {
|
||||
expect(matchingMediaTypes())
|
||||
.toEqual([]);
|
||||
});
|
||||
|
||||
it('returns matching types if weight > 0.', async(): Promise<void> => {
|
||||
const preferences: RepresentationPreferences =
|
||||
{ type: { 'a/x': 1, 'b/x': 0.5, 'c/x': 0 }};
|
||||
expect(matchingMediaTypes(preferences, [ 'b/x', 'c/x' ]))
|
||||
const preferences: ValuePreferences = { 'a/x': 1, 'b/x': 0.5, 'c/x': 0 };
|
||||
expect(matchingMediaTypes(preferences, { 'b/x': 1, 'c/x': 1 }))
|
||||
.toEqual([ 'b/x' ]);
|
||||
});
|
||||
|
||||
it('sorts by descending weight.', async(): Promise<void> => {
|
||||
const preferences: RepresentationPreferences =
|
||||
{ type: { 'a/x': 1, 'b/x': 0.5, 'c/x': 0.8 }};
|
||||
expect(matchingMediaTypes(preferences, [ 'a/x', 'b/x', 'c/x' ]))
|
||||
const preferences: ValuePreferences = { 'a/x': 1, 'b/x': 0.5, 'c/x': 0.8 };
|
||||
expect(matchingMediaTypes(preferences, { 'a/x': 1, 'b/x': 1, 'c/x': 1 }))
|
||||
.toEqual([ 'a/x', 'c/x', 'b/x' ]);
|
||||
});
|
||||
|
||||
it('incorporates representation qualities when calculating weight.', async(): Promise<void> => {
|
||||
const preferences: ValuePreferences = { 'a/x': 1, 'b/x': 0.5, 'c/x': 0.8 };
|
||||
expect(matchingMediaTypes(preferences, { 'a/x': 0.1, 'b/x': 1, 'c/x': 0.6 }))
|
||||
.toEqual([ 'b/x', 'c/x', 'a/x' ]);
|
||||
});
|
||||
|
||||
it('errors if there invalid types.', async(): Promise<void> => {
|
||||
const preferences: RepresentationPreferences =
|
||||
{ type: { 'b/x': 1 }};
|
||||
expect((): any => matchingMediaTypes(preferences, [ 'noType' ]))
|
||||
const preferences: ValuePreferences = { 'b/x': 1 };
|
||||
expect((): any => matchingMediaTypes(preferences, { noType: 1 }))
|
||||
.toThrow(new InternalServerError(`Unexpected type preference: noType`));
|
||||
});
|
||||
|
||||
it('filters out internal types.', async(): Promise<void> => {
|
||||
const preferences: RepresentationPreferences =
|
||||
{ type: { '*/*': 1 }};
|
||||
expect(matchingMediaTypes(preferences, [ 'a/x', 'internal/quads' ]))
|
||||
const preferences: ValuePreferences = { '*/*': 1 };
|
||||
expect(matchingMediaTypes(preferences, { 'a/x': 1, 'internal/quads': 1 }))
|
||||
.toEqual([ 'a/x' ]);
|
||||
});
|
||||
|
||||
it('keeps internal types that are specifically requested.', async(): Promise<void> => {
|
||||
const preferences: RepresentationPreferences =
|
||||
{ type: { '*/*': 1, 'internal/*': 0.5 }};
|
||||
expect(matchingMediaTypes(preferences, [ 'a/x', 'internal/quads' ]))
|
||||
const preferences: ValuePreferences = { '*/*': 1, 'internal/*': 0.5 };
|
||||
expect(matchingMediaTypes(preferences, { 'a/x': 1, 'internal/quads': 1 }))
|
||||
.toEqual([ 'a/x', 'internal/quads' ]);
|
||||
});
|
||||
|
||||
it('takes the most relevant weight for a type.', async(): Promise<void> => {
|
||||
const preferences: RepresentationPreferences =
|
||||
{ type: { '*/*': 1, 'internal/quads': 0.5 }};
|
||||
expect(matchingMediaTypes(preferences, [ 'a/x', 'internal/quads' ]))
|
||||
const preferences: ValuePreferences = { '*/*': 1, 'internal/quads': 0.5 };
|
||||
expect(matchingMediaTypes(preferences, { 'a/x': 1, 'internal/quads': 1 }))
|
||||
.toEqual([ 'a/x', 'internal/quads' ]);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user