textmachine/backend/cmd/tmbankprobe/main_test.go

70 lines
3.7 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package main
import (
"strings"
"testing"
"textmachine/backend/internal/pipeline"
)
// main_test.go pins the two rules this probe got WRONG before it got them right. Both produced numbers
// that looked reasonable, which is the only reason they needed a test: a measurement instrument fails by
// reporting, not by crashing.
// TestARowTheBankSettledIsInNeitherDenominator. The settled filter runs BEFORE the first paid call, so a
// row it removed is neither «a candidate at the role's input» nor «a row the role answered». The first
// version of this probe kept it on the pre-call side only: the two denominators then differed by a row
// that reached neither, and every pre-call share was quietly diluted.
func TestARowTheBankSettledIsInNeitherDenominator(t *testing.T) {
s := &source{rows: []pipeline.BankStopRow{
{Src: "方源", Dst: "", SettledByBank: true}, // settled: in neither
{Src: "花家", Dst: ""}, // answered with nothing: in the pre-call one only
{Src: "青茅山", Dst: "гора Цинмао"}, // an ordinary answered row
{Src: "丙等", Dst: "третий разряд"}, //
}}
pre, answered, settled, unresolved := s.denominators()
if pre != 3 || answered != 2 || settled != 1 || unresolved != 1 {
t.Errorf("denominators = pre %d, answered %d, settled %d, unresolved %d; want 3, 2, 1, 1", pre, answered, settled, unresolved)
}
}
// TestTheComparedInputNeverCarriesTheAnswer is the other one, and it is the more dangerous: the §4.4
// comparison asks «did the row's INPUT change where the decision changed», so folding the consolidated
// rendering into the input makes the answer «the input changed» for every row whose answer changed — 100 %
// of the population, by construction, with nothing red anywhere. That is what the first version did (it
// read the signature map's note, which names the top proposal's chunk COUNT but not its text, so the
// rendering had to be substituted for it).
func TestTheComparedInputNeverCarriesTheAnswer(t *testing.T) {
before := pipeline.BankStopRow{
Src: "熊家寨", Dst: "селение Сюн", Type: "place", Origin: "banknote", Freq: 4, Conf: 85,
Variants: []pipeline.BankStopVariant{{Dst: "селение Сюн", Chunks: 1}},
Contexts: []string{"一段"},
}
after := before
after.Dst = "крепость рода Сюн" // the ANSWER moved
after.Conf = 60 // and so did the role's own confidence
after.Invented = true // and the invented mark, which is also an output
if rowInput(before, true) != rowInput(after, true) {
t.Errorf("a row whose ANSWER moved and whose input did not must compare EQUAL:\n before: %s\n after : %s",
rowInput(before, true), rowInput(after, true))
}
// And a row whose input really moved must NOT compare equal — otherwise the test above would pass on a
// function that returns a constant.
moved := before
moved.Variants = []pipeline.BankStopVariant{{Dst: "крепость рода Сюн", Chunks: 2}}
if rowInput(before, true) == rowInput(moved, true) {
t.Error("a row whose draft proposals moved must compare DIFFERENT")
}
// The contexts are part of the input, and they are what the earlier instrument could not see at all.
ctxMoved := before
ctxMoved.Contexts = []string{"другой контекст"}
if rowInput(before, true) == rowInput(ctxMoved, true) {
t.Error("a row whose source contexts moved must compare DIFFERENT when contexts are included")
}
if rowInput(before, false) != rowInput(ctxMoved, false) {
t.Error("and must compare EQUAL when they are not — the two questions are asked separately on purpose")
}
if !strings.Contains(rowInput(before, false), "drafts=[") {
t.Errorf("the compared input must name the drafts it compared: %s", rowInput(before, false))
}
}