import { describe, expect, test } from "bun:test" import { readFileSync } from "node:fs" import { join } from "node:path" import { renderValueHtml } from "./placeholder.mjs" import { DEFECT_CODES } from "./contracts.mjs" import * as polishDiff from "./polish-diff.mjs" import * as polishProject from "./polish-project.mjs" import * as polishRules from "./polish-rules.mjs" const { diffPolish } = polishDiff const SPAN = { fact_id: "F2", kind: "measured", quote: "The bridge has a main span of 320 m.", raw: "320 m", value: "320", unit: "m", qualifier: null } const MAKER = { fact_id: "F5", kind: "measured", quote: "In May, Samsung Electronics shipped 12 units.", raw: "12 units", value: "12", unit: "units", qualifier: null } const SALES = { fact_id: "F6", kind: "measured", quote: "Sales were approximately 7 units.", raw: "7 units", value: "7", unit: "units", qualifier: null } const LEDGER = { schemaVersion: 1, rows: [SPAN, MAKER, SALES], events: [] } const span = renderValueHtml(SPAN, SPAN.raw) const doc = (body: string) => `
\n${body}\n` const codes = (list: { code: string }[]) => list.map((item) => item.code) describe("diffPolish: protected content", () => { test("identical documents have no defects", () => { const html = doc(`The span was about ${span} [S1].
| A |
The span is ${span} [S1].
`) const after = doc(`The span is ${span.replace(">320 m<", ">321 m<")} [S1].
`) expect(codes(diffPolish(before, after, LEDGER))).toEqual(["polish_diff_fail"]) }) test("one numeral that differs outside fact spans is polish_diff_fail", () => { const before = doc("Throughput grew 3.5 times in the pilot [S1].
") const after = doc("Throughput grew 35 times in the pilot [S1].
") expect(codes(diffPolish(before, after, LEDGER))).toEqual(["polish_diff_fail"]) }) test("a dropped table row is polish_diff_fail", () => { const before = doc("| A |
| B |
| A |
AAPL [S1].
"), doc("MSFT [S1].
"), LEDGER))).toEqual(["polish_diff_fail"]) expect(codes(diffPolish(doc("Code 005930 [S1].
"), doc("Code 000660 [S1].
"), LEDGER))).toEqual(["polish_diff_fail"]) }) }) describe("diffPolish: hedges, churn, links and names", () => { test("two hedges removed from claim-only text is polish_hedging_decreased", () => { const before = doc("Results may improve and are provisional. The study covered the pilot only.
") const after = doc("Results improve and are final. The study covered the pilot only.
") expect(codes(diffPolish(before, after, LEDGER))).toEqual(["polish_hedging_decreased"]) }) test("deleting a writer-added hedge the source lacks is not a hedge loss", () => { const before = doc(`The span was about ${span} [S1].
`) const after = doc(`The span was ${span} [S1].
`) expect(diffPolish(before, after, LEDGER)).toEqual([]) }) test("a 60 percent rewrite is polish_text_churn and 50 percent is not", () => { expect(codes(diffPolish(doc("abcdefghij
"), doc("klmnopghij
"), LEDGER))).toEqual(["polish_text_churn"]) expect(diffPolish(doc("abcdefghij
"), doc("klmnofghij
"), LEDGER)).toEqual([]) }) test("a changed link target or an internal link that stops resolving is polish_link_changed", () => { const link = (href: string) => doc(`Reference [S1].
`) expect(codes(diffPolish(link("https://example.invalid/a"), link("https://example.invalid/b"), LEDGER))).toEqual(["polish_diff_fail", "polish_link_changed"]) const before = doc('Method [S1].
') const after = doc('Method [S1].
') expect(codes(diffPolish(before, after, LEDGER))).toEqual(["polish_diff_fail", "polish_link_changed"]) }) test("a ledger-quote name present before and absent after is polish_name_changed", () => { const before = doc("Samsung Electronics shipped more units in the quarter [S1].
") const after = doc("The company shipped more units in the quarter [S1].
") expect(codes(diffPolish(before, after, LEDGER))).toEqual(["polish_name_changed"]) }) test("every defect carries its fixed severity", () => { const before = doc("Results may improve and are provisional [S1].
| A |
| B |
Results improve and are final [S1].
| A |
Samsung Electronics may improve [S1].
x abcdefghij
| A |
| B |
The firm improves [S1].
x klmnopqrstuvwxyz
| A |
The span is ${span} [S1].
`), doc(`The span is ${hidden} [S1].
`), LEDGER))).toContain("polish_diff_fail") }) test("wrapping a hedge changes markup and is blocked before full fidelity verification", () => { const after = doc("Results may improve [S1].
") expect(codes(diffPolish(doc("Results may improve [S1].
"), after, LEDGER))).toEqual(["polish_diff_fail"]) }) test("a ledger hedge the sentence never held is not a decrease", () => { const sales = renderValueHtml(SALES, SALES.raw) const before = doc(`The share of revenue was ${sales} [S1].
`) const after = doc(`The share in revenue was ${sales} [S1].
`) expect(diffPolish(before, after, LEDGER)).toEqual([]) }) test("single-quoted and unquoted href changes are polish_link_changed", () => { expect(codes(diffPolish(doc(""), doc(""), LEDGER))).toEqual(["polish_diff_fail", "polish_link_changed"]) expect(codes(diffPolish(doc(""), doc(""), LEDGER))).toEqual(["polish_diff_fail", "polish_link_changed"]) }) test("the same input gives byte-identical output", () => { const before = doc("Results may improve and are provisional [S1].
") const after = doc("Results improve and are final [S1].
") expect(JSON.stringify(diffPolish(before, after, LEDGER))).toBe(JSON.stringify(diffPolish(before, after, LEDGER))) }) }) describe("claim ids and fact-span scanning (review #11152 round 2, L1 and L2)", () => { test("L1: a changed data-claim id is a blocking polish_diff_fail, as apply treats it, not a minor link change", () => { const defects = diffPolish(doc('Results improve [S1].
'), doc('Results improve [S1].
'), LEDGER) expect(codes(defects)).toEqual(["polish_diff_fail"]) expect(defects[0].severity).toBe(DEFECT_CODES.polish_diff_fail.severity) expect(defects[0].message).toContain("markup changed") }) test("L2: a nested same-name element and a quoted '>' stay inside one fact span", () => { const nested = 'a
db
c
a']) const quoted = 'bc
320 m d
' expect(polishProject.factSpans(quoted).map((s: { id: string; html: string }) => [s.id, s.html])).toEqual([["F2", '320 m']]) }) }) describe("polish policies have one owner (duplication sweep)", () => { test("the named policies are exported once, from their owners", () => { expect(polishRules.POLISH_CHURN_LIMIT).toBe(0.5) expect("Samsung Electronics".match(polishRules.POLISH_NAME)).toEqual(["Samsung", "Electronics"]) expect(polishDiff.TICKER).toBe(polishRules.TICKER) expect(polishProject.POLISH_LINK_ATTRIBUTES).toEqual(["href"]) expect("v1.25 and 3,000".match(polishProject.POLISH_DIGITS)).toEqual(["1.25", "3,000"]) }) })