116 lines
4.6 KiB
TypeScript
116 lines
4.6 KiB
TypeScript
import { expect, test } from 'bun:test';
|
|
import { PropertyMapper } from 'packages/obsidian/src/settings/PropertyMapper';
|
|
import { PropertyMapping, PropertyMappingModel, PropertyMappingOption } from 'packages/obsidian/src/settings/PropertyMapping';
|
|
import { MediaType } from 'packages/obsidian/src/utils/MediaType';
|
|
import { PropertyMappingNameConflictError, PropertyMappingValidationError } from 'packages/obsidian/src/utils/Utils';
|
|
|
|
test('PropertyMapping validates locked and remapped property constraints', () => {
|
|
expect(new PropertyMapping('title', 'title', PropertyMappingOption.Default, true).validate()).toEqual({ res: true });
|
|
|
|
const lockedRemoval = new PropertyMapping('title', 'title', PropertyMappingOption.Remove, true).validate();
|
|
expect(lockedRemoval.res).toBe(false);
|
|
expect(lockedRemoval.err).toBeInstanceOf(PropertyMappingValidationError);
|
|
|
|
const invalidSource = new PropertyMapping('bad property', 'name', PropertyMappingOption.Map).validate();
|
|
expect(invalidSource.res).toBe(false);
|
|
expect(invalidSource.err).toBeInstanceOf(PropertyMappingValidationError);
|
|
|
|
const invalidTarget = new PropertyMapping('title', 'bad-property', PropertyMappingOption.Map).validate();
|
|
expect(invalidTarget.res).toBe(false);
|
|
expect(invalidTarget.err).toBeInstanceOf(PropertyMappingValidationError);
|
|
});
|
|
|
|
test('PropertyMappingModel detects conflicting mapped property names', () => {
|
|
const duplicateTarget = new PropertyMappingModel(MediaType.Movie, [
|
|
new PropertyMapping('title', 'name', PropertyMappingOption.Map),
|
|
new PropertyMapping('englishTitle', 'name', PropertyMappingOption.Map),
|
|
]).validate();
|
|
|
|
expect(duplicateTarget.res).toBe(false);
|
|
expect(duplicateTarget.err).toBeInstanceOf(PropertyMappingNameConflictError);
|
|
|
|
const targetMatchesOriginal = new PropertyMappingModel(MediaType.Movie, [
|
|
new PropertyMapping('title', 'year', PropertyMappingOption.Map),
|
|
new PropertyMapping('year', 'year', PropertyMappingOption.Default),
|
|
]).validate();
|
|
|
|
expect(targetMatchesOriginal.res).toBe(false);
|
|
expect(targetMatchesOriginal.err).toBeInstanceOf(PropertyMappingNameConflictError);
|
|
});
|
|
|
|
test('PropertyMappingModel serializes, copies, and migrates without sharing mutable property objects', () => {
|
|
const model = new PropertyMappingModel(MediaType.Movie, [new PropertyMapping('title', 'name', PropertyMappingOption.Map, false, true)]);
|
|
const copy = model.copy();
|
|
|
|
copy.properties[0].newProperty = 'label';
|
|
|
|
expect(model.properties[0].newProperty).toBe('name');
|
|
expect(PropertyMappingModel.fromJSON(model.toJSON())).toEqual(model);
|
|
|
|
const migrated = PropertyMappingModel.migrateModels(
|
|
[
|
|
{
|
|
type: MediaType.Movie,
|
|
properties: [{ property: 'title', newProperty: 'customTitle', mapping: PropertyMappingOption.Map, locked: false, wikilink: true }],
|
|
},
|
|
],
|
|
[
|
|
new PropertyMappingModel(MediaType.Movie, [
|
|
new PropertyMapping('title', 'title', PropertyMappingOption.Default, true),
|
|
new PropertyMapping('year', 'year', PropertyMappingOption.Default, false),
|
|
]),
|
|
new PropertyMappingModel(MediaType.Book, [new PropertyMapping('author', 'author', PropertyMappingOption.Default)]),
|
|
],
|
|
);
|
|
|
|
expect(migrated).toEqual([
|
|
new PropertyMappingModel(MediaType.Movie, [
|
|
new PropertyMapping('title', 'customTitle', PropertyMappingOption.Map, true, true),
|
|
new PropertyMapping('year', 'year', PropertyMappingOption.Default, false),
|
|
]),
|
|
new PropertyMappingModel(MediaType.Book, [new PropertyMapping('author', 'author', PropertyMappingOption.Default)]),
|
|
]);
|
|
});
|
|
|
|
test('PropertyMapper converts objects according to mapping and wikilink rules', () => {
|
|
const mapper = new PropertyMapper({
|
|
settings: {
|
|
propertyMappingModels: [
|
|
new PropertyMappingModel(MediaType.Movie, [
|
|
new PropertyMapping('title', 'name', PropertyMappingOption.Map, false, true),
|
|
new PropertyMapping('genres', 'genres', PropertyMappingOption.Default, false, true),
|
|
new PropertyMapping('year', 'year', PropertyMappingOption.Remove),
|
|
]),
|
|
],
|
|
},
|
|
} as never);
|
|
|
|
expect(
|
|
mapper.convertObject({
|
|
type: MediaType.Movie,
|
|
title: 'Arrival',
|
|
genres: ['Drama', 2016],
|
|
year: '2016',
|
|
rating: 8,
|
|
}),
|
|
).toEqual({
|
|
type: MediaType.Movie,
|
|
name: '[[Arrival]]',
|
|
genres: ['[[Drama]]', 2016],
|
|
rating: 8,
|
|
});
|
|
});
|
|
|
|
test('PropertyMapper restores mapped properties and migrates legacy manga type', () => {
|
|
const mapper = new PropertyMapper({
|
|
settings: {
|
|
propertyMappingModels: [new PropertyMappingModel(MediaType.ComicManga, [new PropertyMapping('title', 'name', PropertyMappingOption.Map)])],
|
|
},
|
|
} as never);
|
|
|
|
expect(mapper.convertObjectBack({ type: 'manga', name: 'Berserk', year: '1989' })).toEqual({
|
|
type: MediaType.ComicManga,
|
|
title: 'Berserk',
|
|
year: '1989',
|
|
});
|
|
});
|