import { describe, expect, it } from 'vitest' import { findTemplateFieldIdProblem, nextTemplateFieldId, nextTemplateFieldNumber, templateFieldIdProblems, } from '../src/template-field-policy' const ids = (...values: string[]) => values.map((id) => ({ id })) describe('templateFieldIdProblems', () => { it('유효한 id는 문제가 없다', () => { expect(templateFieldIdProblems(ids('a', 'b', 'c'))).toEqual([null, null, null]) expect(findTemplateFieldIdProblem(ids('a', 'b'))).toBeNull() }) it('빈 id와 공백뿐인 id는 empty', () => { expect(templateFieldIdProblems(ids('a', '', ' '))).toEqual([null, 'empty', 'empty']) }) it('겹치는 id는 모든 행이 duplicate', () => { expect(templateFieldIdProblems(ids('field3', 'x', 'field3'))).toEqual(['duplicate', null, 'duplicate']) }) it('id는 정확히 비교한다(자리표시자 키가 정확 일치이므로)', () => { expect(templateFieldIdProblems(ids('a', ' a', 'A'))).toEqual([null, null, null]) }) it('findTemplateFieldIdProblem은 첫 문제의 위치와 id를 돌려준다', () => { expect(findTemplateFieldIdProblem(ids('a', 'b', 'b'))).toEqual({ index: 1, id: 'b', problem: 'duplicate' }) expect(findTemplateFieldIdProblem(ids('a', ''))).toEqual({ index: 1, id: '', problem: 'empty' }) }) }) describe('nextTemplateFieldId', () => { it('빈 목록이면 field1', () => { expect(nextTemplateFieldId([])).toBe('field1') }) it('중간 필드를 지운 뒤에도 기존 id를 다시 만들지 않는다 (회귀: 개수 기반 번호)', () => { // [field1, field2, field3]에서 field1을 지움 → 개수+1 = field3 (중복) expect(nextTemplateFieldId(ids('field2', 'field3'))).toBe('field4') }) it('사용자가 이름을 바꾼 필드도 번호 계산에 넣는다', () => { expect(nextTemplateFieldNumber(ids('recipient', 'field7', 'body'))).toBe(8) expect(nextTemplateFieldId(ids('recipient', 'body'))).toBe('field1') }) it('추가·삭제를 섞어 반복해도 id가 겹치지 않는다', () => { const fields = ids('field1') for (let i = 0; i < 6; i += 1) { fields.push({ id: nextTemplateFieldId(fields) }) fields.push({ id: nextTemplateFieldId(fields) }) fields.splice(i % fields.length, 1) expect(findTemplateFieldIdProblem(fields)).toBeNull() } }) })