Add unit tests for TavernCardValidator (#5366)
* Add unit tests for TavernCardValidator
This commit is contained in:
@@ -0,0 +1,251 @@
|
||||
import { describe, test, expect } from '@jest/globals';
|
||||
import { TavernCardValidator } from '../src/validator/TavernCardValidator';
|
||||
|
||||
const V1_FIELDS = ['name', 'description', 'personality', 'scenario', 'first_mes', 'mes_example'];
|
||||
|
||||
const V2_DATA_FIELDS = [
|
||||
'name', 'description', 'personality', 'scenario', 'first_mes', 'mes_example',
|
||||
'creator_notes', 'system_prompt', 'post_history_instructions',
|
||||
'alternate_greetings', 'tags', 'creator', 'character_version', 'extensions',
|
||||
];
|
||||
|
||||
function makeV1Card() {
|
||||
return Object.fromEntries(V1_FIELDS.map(f => [f, '']));
|
||||
}
|
||||
|
||||
function makeV2Card() {
|
||||
return {
|
||||
spec: 'chara_card_v2',
|
||||
spec_version: '2.0',
|
||||
data: {
|
||||
...Object.fromEntries(V2_DATA_FIELDS.map(f => [f, ''])),
|
||||
alternate_greetings: [],
|
||||
tags: [],
|
||||
extensions: {},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function makeV3Card() {
|
||||
return {
|
||||
spec: 'chara_card_v3',
|
||||
spec_version: '3.0',
|
||||
data: {},
|
||||
};
|
||||
}
|
||||
|
||||
describe('TavernCardValidator', () => {
|
||||
describe('validate', () => {
|
||||
test('returns 1 for valid V1 card', () => {
|
||||
const v = new TavernCardValidator(makeV1Card());
|
||||
expect(v.validate()).toBe(1);
|
||||
});
|
||||
|
||||
test('returns 2 for valid V2 card', () => {
|
||||
const v = new TavernCardValidator(makeV2Card());
|
||||
expect(v.validate()).toBe(2);
|
||||
});
|
||||
|
||||
test('returns 3 for valid V3 card', () => {
|
||||
const v = new TavernCardValidator(makeV3Card());
|
||||
expect(v.validate()).toBe(3);
|
||||
});
|
||||
|
||||
test('returns false for empty object', () => {
|
||||
const v = new TavernCardValidator({});
|
||||
expect(v.validate()).toBe(false);
|
||||
});
|
||||
|
||||
test('prefers V1 when card satisfies both V1 and V2', () => {
|
||||
const card = { ...makeV1Card(), ...makeV2Card() };
|
||||
const v = new TavernCardValidator(card);
|
||||
expect(v.validate()).toBe(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('validateV1', () => {
|
||||
test('accepts card with all required fields', () => {
|
||||
const v = new TavernCardValidator(makeV1Card());
|
||||
expect(v.validateV1()).toBe(true);
|
||||
});
|
||||
|
||||
for (const field of V1_FIELDS) {
|
||||
test(`rejects card missing ${field}`, () => {
|
||||
const card = makeV1Card();
|
||||
delete card[field];
|
||||
const v = new TavernCardValidator(card);
|
||||
expect(v.validateV1()).toBe(false);
|
||||
expect(v.lastValidationError).toBe(field);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
describe('validateV2', () => {
|
||||
test('accepts valid V2 card', () => {
|
||||
const v = new TavernCardValidator(makeV2Card());
|
||||
expect(v.validateV2()).toBe(true);
|
||||
});
|
||||
|
||||
test('rejects wrong spec string', () => {
|
||||
const card = makeV2Card();
|
||||
card.spec = 'chara_card_v1';
|
||||
const v = new TavernCardValidator(card);
|
||||
expect(v.validateV2()).toBe(false);
|
||||
expect(v.lastValidationError).toBe('spec');
|
||||
});
|
||||
|
||||
test('rejects wrong spec_version', () => {
|
||||
const card = makeV2Card();
|
||||
card.spec_version = '1.0';
|
||||
const v = new TavernCardValidator(card);
|
||||
expect(v.validateV2()).toBe(false);
|
||||
expect(v.lastValidationError).toBe('spec_version');
|
||||
});
|
||||
|
||||
test('rejects missing data', () => {
|
||||
const card = makeV2Card();
|
||||
delete card.data;
|
||||
const v = new TavernCardValidator(card);
|
||||
expect(v.validateV2()).toBe(false);
|
||||
});
|
||||
|
||||
for (const field of V2_DATA_FIELDS) {
|
||||
test(`rejects card missing data.${field}`, () => {
|
||||
const card = makeV2Card();
|
||||
delete card.data[field];
|
||||
const v = new TavernCardValidator(card);
|
||||
expect(v.validateV2()).toBe(false);
|
||||
expect(v.lastValidationError).toBe(`data.${field}`);
|
||||
});
|
||||
}
|
||||
|
||||
test('rejects non-array alternate_greetings', () => {
|
||||
const card = makeV2Card();
|
||||
card.data.alternate_greetings = 'not an array';
|
||||
const v = new TavernCardValidator(card);
|
||||
expect(v.validateV2()).toBe(false);
|
||||
});
|
||||
|
||||
test('rejects non-array tags', () => {
|
||||
const card = makeV2Card();
|
||||
card.data.tags = 'not an array';
|
||||
const v = new TavernCardValidator(card);
|
||||
expect(v.validateV2()).toBe(false);
|
||||
});
|
||||
|
||||
test('rejects non-object extensions', () => {
|
||||
const card = makeV2Card();
|
||||
card.data.extensions = 'not an object';
|
||||
const v = new TavernCardValidator(card);
|
||||
expect(v.validateV2()).toBe(false);
|
||||
});
|
||||
|
||||
test('accepts card with optional character_book', () => {
|
||||
const card = makeV2Card();
|
||||
card.data.character_book = {
|
||||
extensions: {},
|
||||
entries: [],
|
||||
};
|
||||
const v = new TavernCardValidator(card);
|
||||
expect(v.validateV2()).toBe(true);
|
||||
});
|
||||
|
||||
test('rejects character_book missing entries', () => {
|
||||
const card = makeV2Card();
|
||||
card.data.character_book = { extensions: {} };
|
||||
const v = new TavernCardValidator(card);
|
||||
expect(v.validateV2()).toBe(false);
|
||||
expect(v.lastValidationError).toBe('data.character_book.entries');
|
||||
});
|
||||
|
||||
test('rejects character_book missing extensions', () => {
|
||||
const card = makeV2Card();
|
||||
card.data.character_book = { entries: [] };
|
||||
const v = new TavernCardValidator(card);
|
||||
expect(v.validateV2()).toBe(false);
|
||||
expect(v.lastValidationError).toBe('data.character_book.extensions');
|
||||
});
|
||||
|
||||
test('rejects character_book with non-array entries', () => {
|
||||
const card = makeV2Card();
|
||||
card.data.character_book = { extensions: {}, entries: 'not array' };
|
||||
const v = new TavernCardValidator(card);
|
||||
expect(v.validateV2()).toBe(false);
|
||||
});
|
||||
|
||||
test('rejects character_book with non-object extensions', () => {
|
||||
const card = makeV2Card();
|
||||
card.data.character_book = { extensions: 'not object', entries: [] };
|
||||
const v = new TavernCardValidator(card);
|
||||
expect(v.validateV2()).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('validateV3', () => {
|
||||
test('accepts valid V3 card', () => {
|
||||
const v = new TavernCardValidator(makeV3Card());
|
||||
expect(v.validateV3()).toBe(true);
|
||||
});
|
||||
|
||||
test('rejects wrong spec string', () => {
|
||||
const card = makeV3Card();
|
||||
card.spec = 'chara_card_v2';
|
||||
const v = new TavernCardValidator(card);
|
||||
expect(v.validateV3()).toBe(false);
|
||||
expect(v.lastValidationError).toBe('spec');
|
||||
});
|
||||
|
||||
test('rejects spec_version below 3.0', () => {
|
||||
const card = makeV3Card();
|
||||
card.spec_version = '2.9';
|
||||
const v = new TavernCardValidator(card);
|
||||
expect(v.validateV3()).toBe(false);
|
||||
expect(v.lastValidationError).toBe('spec_version');
|
||||
});
|
||||
|
||||
test('rejects spec_version at or above 4.0', () => {
|
||||
const card = makeV3Card();
|
||||
card.spec_version = '4.0';
|
||||
const v = new TavernCardValidator(card);
|
||||
expect(v.validateV3()).toBe(false);
|
||||
});
|
||||
|
||||
test('accepts spec_version 3.5', () => {
|
||||
const card = makeV3Card();
|
||||
card.spec_version = '3.5';
|
||||
const v = new TavernCardValidator(card);
|
||||
expect(v.validateV3()).toBe(true);
|
||||
});
|
||||
|
||||
test('rejects missing data', () => {
|
||||
const card = makeV3Card();
|
||||
delete card.data;
|
||||
const v = new TavernCardValidator(card);
|
||||
expect(v.validateV3()).toBe(false);
|
||||
});
|
||||
|
||||
test('rejects non-object data', () => {
|
||||
const card = makeV3Card();
|
||||
card.data = 'not an object';
|
||||
const v = new TavernCardValidator(card);
|
||||
expect(v.validateV3()).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('lastValidationError', () => {
|
||||
test('is null after successful validation', () => {
|
||||
const v = new TavernCardValidator(makeV1Card());
|
||||
v.validate();
|
||||
expect(v.lastValidationError).toBeNull();
|
||||
});
|
||||
|
||||
test('is reset on each validate call', () => {
|
||||
const v = new TavernCardValidator({});
|
||||
v.validate();
|
||||
expect(v.lastValidationError).not.toBeNull();
|
||||
v.card = makeV1Card();
|
||||
v.validate();
|
||||
expect(v.lastValidationError).toBeNull();
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user