75 lines
3.1 KiB
TypeScript
75 lines
3.1 KiB
TypeScript
// tests/red/dictionary-redteam-r1-12.test.ts
|
|
// 회귀: 사전 편집에서 발음을 지울 수 없던 문제, 같은 단어로 이름을 바꿀 때
|
|
// DictionaryDuplicate 대신 일반 DB 오류로 조용히 실패하던 문제.
|
|
|
|
import { describe, it, expect } from 'vitest'
|
|
import { D3ROError, ErrorCode } from '@d3ro/core/errors'
|
|
import { IPC_CHANNELS } from '@d3ro/core/ipc-channels'
|
|
import { toDictionaryUpdateParams } from '@d3ro/core/dictionary-policy'
|
|
import { getDictionaryService } from '../../src/main/services/DictionaryService'
|
|
import { registerDictionaryHandlers } from '../../src/main/ipc/dictionary-handlers'
|
|
import { invokeIpc, useRedHarness } from './harness'
|
|
|
|
useRedHarness()
|
|
|
|
describe('사전 편집 회귀 (redteam r1 #12)', () => {
|
|
it('편집에서 발음 입력을 비우면 저장된 발음이 지워진다', () => {
|
|
const svc = getDictionaryService()
|
|
const entry = svc.add({ word: 'GPT', pronunciation: 'gee-pee-tee' })
|
|
|
|
const updated = svc.update(toDictionaryUpdateParams(entry.id, { word: 'GPT', pronunciation: '' }))
|
|
|
|
expect(updated?.pronunciation).toBeNull()
|
|
const reloaded = svc.list({ page: 0, pageSize: 10 }).entries.find((e) => e.id === entry.id)
|
|
expect(reloaded?.pronunciation).toBeNull()
|
|
})
|
|
|
|
it('pronunciation: null 은 발음을 지우고, 생략하면 유지한다', () => {
|
|
const svc = getDictionaryService()
|
|
const entry = svc.add({ word: 'Whisper', pronunciation: '위스퍼' })
|
|
|
|
expect(svc.update({ id: entry.id, word: 'Whisper2' })?.pronunciation).toBe('위스퍼')
|
|
expect(svc.update({ id: entry.id, pronunciation: null })?.pronunciation).toBeNull()
|
|
})
|
|
|
|
it('공백뿐인 발음은 빈 문자열로 저장하지 않고 지운다', () => {
|
|
const svc = getDictionaryService()
|
|
const entry = svc.add({ word: 'Blank', pronunciation: '블랭크' })
|
|
|
|
expect(svc.update({ id: entry.id, pronunciation: ' ' })?.pronunciation).toBeNull()
|
|
})
|
|
|
|
it('같은 카테고리의 기존 단어로 이름을 바꾸면 DictionaryDuplicate 이다', () => {
|
|
const svc = getDictionaryService()
|
|
svc.add({ word: 'Ollama' })
|
|
const other = svc.add({ word: 'Llama' })
|
|
|
|
try {
|
|
svc.update({ id: other.id, word: 'Ollama' })
|
|
expect.unreachable()
|
|
} catch (err) {
|
|
expect(err).toBeInstanceOf(D3ROError)
|
|
expect((err as D3ROError).code).toBe(ErrorCode.DictionaryDuplicate)
|
|
}
|
|
})
|
|
|
|
it('IPC update 도 이름 중복을 DictionaryDuplicate 로 돌려준다', async () => {
|
|
registerDictionaryHandlers()
|
|
const svc = getDictionaryService()
|
|
svc.add({ word: 'dup-target' })
|
|
const other = svc.add({ word: 'dup-source' })
|
|
|
|
const res = await invokeIpc(IPC_CHANNELS.DICTIONARY.UPDATE, { id: other.id, word: 'dup-target' })
|
|
|
|
expect(res.success).toBe(false)
|
|
if (!res.success) expect(res.error.code).toBe(ErrorCode.DictionaryDuplicate)
|
|
})
|
|
|
|
it('편집에서 단어를 비우면 거부하고, 단어는 trim 해 저장한다', () => {
|
|
const svc = getDictionaryService()
|
|
const entry = svc.add({ word: 'Trim' })
|
|
|
|
expect(() => svc.update({ id: entry.id, word: ' ' })).toThrow(D3ROError)
|
|
expect(svc.update({ id: entry.id, word: ' Trimmed ' })?.word).toBe('Trimmed')
|
|
})
|
|
})
|