import { describe, expect, it } from 'vitest' import { isQuestionHardFilteredAfterAnswers } from '@/lib/gekanatorQuestionFilters' import type { GekanatorAnswerLog, GekanatorAnswerValue, GekanatorQuestion, GekanatorQuestionCondition, } from '@/lib/gekanator' const question = ( condition: GekanatorQuestionCondition, ): GekanatorQuestion => ({ id: `${ condition.type }:candidate`, text: 'candidate?', kind: condition.type === 'source' ? 'source' : condition.type.startsWith ('original-') ? 'original_date' : condition.type.startsWith ('title-') ? 'title' : 'tag', condition, source: 'default', priorityWeight: 1, test: () => false, }) const answer = ( condition: GekanatorQuestionCondition, value: GekanatorAnswerValue, ): GekanatorAnswerLog => ({ questionId: 'previous', questionText: 'previous?', questionCondition: condition, answer: value, originalAnswer: value, }) const blocked = ( candidate: GekanatorQuestionCondition, previous: GekanatorQuestionCondition, value: GekanatorAnswerValue, ): boolean => isQuestionHardFilteredAfterAnswers (question (candidate), [answer (previous, value)]) describe('isQuestionHardFilteredAfterAnswers', () => { it('blocks only contradictory or redundant month questions after a yes answer', () => { const previous: GekanatorQuestionCondition = { type: 'original-month', month: 12 } expect(blocked ({ type: 'original-month', month: 12 }, previous, 'yes')).toBe(true) expect(blocked ({ type: 'original-month', month: 2 }, previous, 'yes')).toBe(true) expect(blocked ({ type: 'original-month-day', monthDay: '2-14' }, previous, 'yes')) .toBe(true) expect(blocked ({ type: 'original-month-day', monthDay: '12-25' }, previous, 'yes')) .toBe(false) expect(blocked ({ type: 'original-year', year: 2024 }, previous, 'yes')).toBe(false) expect(blocked ({ type: 'source', host: 'example.com' }, previous, 'yes')).toBe(false) expect(blocked ({ type: 'tag', key: 'character:喜多郁代' }, previous, 'yes')).toBe(false) }) it('blocks same-month facts after a no answer', () => { const previous: GekanatorQuestionCondition = { type: 'original-month', month: 12 } expect(blocked ({ type: 'original-month', month: 12 }, previous, 'no')).toBe(true) expect(blocked ({ type: 'original-month', month: 2 }, previous, 'no')).toBe(false) expect(blocked ({ type: 'original-month-day', monthDay: '12-25' }, previous, 'no')) .toBe(true) expect(blocked ({ type: 'original-month-day', monthDay: '2-14' }, previous, 'no')) .toBe(false) }) it('blocks all month and month-day questions after a month-day yes answer', () => { const previous: GekanatorQuestionCondition = { type: 'original-month-day', monthDay: '12-25', } expect(blocked ({ type: 'original-month', month: 12 }, previous, 'yes')).toBe(true) expect(blocked ({ type: 'original-month', month: 2 }, previous, 'yes')).toBe(true) expect(blocked ({ type: 'original-month-day', monthDay: '12-25' }, previous, 'yes')) .toBe(true) expect(blocked ({ type: 'original-month-day', monthDay: '12-26' }, previous, 'yes')) .toBe(true) }) it('blocks the same month-day only after a month-day no answer', () => { const previous: GekanatorQuestionCondition = { type: 'original-month-day', monthDay: '12-25', } expect(blocked ({ type: 'original-month-day', monthDay: '12-25' }, previous, 'no')) .toBe(true) expect(blocked ({ type: 'original-month-day', monthDay: '12-26' }, previous, 'no')) .toBe(false) expect(blocked ({ type: 'original-month', month: 12 }, previous, 'no')).toBe(false) }) it('blocks year and source as single-value facts', () => { expect(blocked ( { type: 'original-year', year: 2025 }, { type: 'original-year', year: 2024 }, 'yes', )).toBe(true) expect(blocked ( { type: 'original-year', year: 2024 }, { type: 'original-year', year: 2024 }, 'no', )).toBe(true) expect(blocked ( { type: 'source', host: 'b.example' }, { type: 'source', host: 'a.example' }, 'yes', )).toBe(true) expect(blocked ( { type: 'source', host: 'b.example' }, { type: 'source', host: 'a.example' }, 'no', )).toBe(false) }) it('does not hard-filter partial, probably_no, or unknown fact answers', () => { const previous: GekanatorQuestionCondition = { type: 'original-month', month: 12 } const candidate: GekanatorQuestionCondition = { type: 'original-month', month: 2 } expect(blocked (candidate, previous, 'partial')).toBe(false) expect(blocked (candidate, previous, 'probably_no')).toBe(false) expect(blocked (candidate, previous, 'unknown')).toBe(false) }) it('keeps title-length hard redundancy for yes and no only', () => { const previous: GekanatorQuestionCondition = { type: 'title-length-at-least', length: 30, } expect(blocked ({ type: 'title-length-at-least', length: 20 }, previous, 'yes')) .toBe(true) expect(blocked ({ type: 'title-length-at-least', length: 40 }, previous, 'yes')) .toBe(false) expect(blocked ({ type: 'title-length-at-least', length: 40 }, previous, 'no')) .toBe(true) expect(blocked ({ type: 'title-length-at-least', length: 20 }, previous, 'no')) .toBe(false) expect(blocked ({ type: 'title-length-at-least', length: 20 }, previous, 'partial')) .toBe(false) }) })