110 lines
4 KiB
TypeScript
110 lines
4 KiB
TypeScript
// packages/core/__tests__/dictionary-policy.test.ts
|
|
// 사전 편집 정책 순수 함수 테스트 — 발음 지우기, 단어 검증, UNIQUE 판별, 폼 → 요청 변환.
|
|
|
|
import { describe, expect, it } from 'vitest'
|
|
import { ErrorCode } from '../src/errors'
|
|
import {
|
|
buildDictionaryUpdatePatch,
|
|
dictionarySaveErrorKey,
|
|
isUniqueConstraintViolation,
|
|
normalizeDictionaryPronunciation,
|
|
normalizeDictionaryWord,
|
|
toDictionaryAddParams,
|
|
toDictionaryUpdateParams
|
|
} from '../src/dictionary-policy'
|
|
|
|
describe('normalizeDictionaryWord', () => {
|
|
it('앞뒤 공백을 제거한다', () => {
|
|
expect(normalizeDictionaryWord(' GPT ')).toBe('GPT')
|
|
})
|
|
it('공백뿐이면 null이다', () => {
|
|
expect(normalizeDictionaryWord(' ')).toBeNull()
|
|
expect(normalizeDictionaryWord('')).toBeNull()
|
|
})
|
|
})
|
|
|
|
describe('normalizeDictionaryPronunciation', () => {
|
|
it('undefined는 변경 없음으로 유지한다', () => {
|
|
expect(normalizeDictionaryPronunciation(undefined)).toBeUndefined()
|
|
})
|
|
it('null과 빈 문자열은 지우기(null)다', () => {
|
|
expect(normalizeDictionaryPronunciation(null)).toBeNull()
|
|
expect(normalizeDictionaryPronunciation('')).toBeNull()
|
|
expect(normalizeDictionaryPronunciation(' ')).toBeNull()
|
|
})
|
|
it('값은 trim 한다', () => {
|
|
expect(normalizeDictionaryPronunciation(' gee-pee-tee ')).toBe('gee-pee-tee')
|
|
})
|
|
})
|
|
|
|
describe('buildDictionaryUpdatePatch', () => {
|
|
it('발음 null은 패치에 null로 들어간다 (지우기)', () => {
|
|
const result = buildDictionaryUpdatePatch({ id: 'a', pronunciation: null })
|
|
expect(result).toEqual({ ok: true, patch: { pronunciation: null } })
|
|
})
|
|
it('빈 발음 문자열도 null로 지운다', () => {
|
|
const result = buildDictionaryUpdatePatch({ id: 'a', pronunciation: ' ' })
|
|
expect(result).toEqual({ ok: true, patch: { pronunciation: null } })
|
|
})
|
|
it('지정하지 않은 필드는 패치에 없다', () => {
|
|
const result = buildDictionaryUpdatePatch({ id: 'a' })
|
|
expect(result).toEqual({ ok: true, patch: {} })
|
|
})
|
|
it('단어는 trim 하고, 비면 거부한다', () => {
|
|
expect(buildDictionaryUpdatePatch({ id: 'a', word: ' GPT ', category: 'technical' })).toEqual({
|
|
ok: true,
|
|
patch: { word: 'GPT', category: 'technical' }
|
|
})
|
|
expect(buildDictionaryUpdatePatch({ id: 'a', word: ' ' })).toEqual({
|
|
ok: false,
|
|
reason: 'empty-word'
|
|
})
|
|
})
|
|
})
|
|
|
|
describe('isUniqueConstraintViolation', () => {
|
|
it('SQLite UNIQUE 오류를 판별한다', () => {
|
|
expect(
|
|
isUniqueConstraintViolation(
|
|
new Error('UNIQUE constraint failed: dictionary.word, dictionary.category')
|
|
)
|
|
).toBe(true)
|
|
expect(isUniqueConstraintViolation('unique violation')).toBe(true)
|
|
expect(isUniqueConstraintViolation(new Error('disk I/O error'))).toBe(false)
|
|
})
|
|
})
|
|
|
|
describe('폼 → 요청 변환', () => {
|
|
it('추가: 빈 발음은 보내지 않는다', () => {
|
|
expect(toDictionaryAddParams({ word: ' GPT ', pronunciation: ' ' })).toEqual({ word: 'GPT' })
|
|
expect(toDictionaryAddParams({ word: 'GPT', pronunciation: ' 지피티 ' })).toEqual({
|
|
word: 'GPT',
|
|
pronunciation: '지피티'
|
|
})
|
|
})
|
|
it('편집: 비운 발음은 null로 보내 지우기를 명시한다', () => {
|
|
expect(toDictionaryUpdateParams('id-1', { word: 'GPT', pronunciation: '' })).toEqual({
|
|
id: 'id-1',
|
|
word: 'GPT',
|
|
pronunciation: null
|
|
})
|
|
expect(toDictionaryUpdateParams('id-1', { word: 'GPT', pronunciation: 'x' }).pronunciation).toBe(
|
|
'x'
|
|
)
|
|
})
|
|
})
|
|
|
|
describe('dictionarySaveErrorKey', () => {
|
|
it('오류 코드를 i18n 키로 바꾼다', () => {
|
|
expect(dictionarySaveErrorKey(ErrorCode.DictionaryDuplicate)).toBe(
|
|
'mobile.dictionary.error.duplicate'
|
|
)
|
|
expect(dictionarySaveErrorKey(ErrorCode.DictionaryNotFound)).toBe(
|
|
'mobile.dictionary.error.notFound'
|
|
)
|
|
expect(dictionarySaveErrorKey(ErrorCode.DictionaryImportInvalidFormat)).toBe(
|
|
'mobile.dictionary.error.validation'
|
|
)
|
|
expect(dictionarySaveErrorKey(ErrorCode.DBWriteFailed)).toBe('mobile.dictionary.error.server')
|
|
})
|
|
})
|