50 lines
2.9 KiB
Go
50 lines
2.9 KiB
Go
package membank
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"textmachine/backend/internal/store"
|
|
)
|
|
|
|
// memneuter_test.go pins the fix-pack §д money contract of the §3 neuter directive, on the memvoice pin's
|
|
// pattern: gender:neuter now RENDERS a directive where the same row rendered nothing before, so it MUST move
|
|
// memory_version (a loud, re-pinnable --resnapshot); and the tag respects the mined scope exactly as the
|
|
// pack-19 voice fold does, so a mined-only neuter row never re-bills the draft wave that cannot see it.
|
|
//
|
|
// (The neuter-directive-v1 marker itself is not black-box-isolable from the per-row gender field, which is
|
|
// already folded — both move the hash for a neuter row, and no single code version can hold one constant
|
|
// while toggling the other. These tests pin the OBSERVABLE contract; the marker exists to carry the RENDER
|
|
// revision across the deploy that introduced neuter rendering, which the scope test's line-ordering guards.)
|
|
|
|
func TestNeuterRowMovesTheBankVersion(t *testing.T) {
|
|
base := term("元气", "изначальная ци")
|
|
plain := ComputeVersionScopedIn(BankInput{Rows: []store.GlossaryEntry{base}}, false, false)
|
|
neut := base
|
|
neut.Gender = "neuter"
|
|
if withNeuter := ComputeVersionScopedIn(BankInput{Rows: []store.GlossaryEntry{neut}}, false, false); plain == withNeuter {
|
|
t.Fatal("a gender:neuter row left the bank version unchanged — it now renders a directive the snapshot cannot see, a silent re-payment")
|
|
}
|
|
}
|
|
|
|
// TestNeuterFoldRespectsTheMinedScope mirrors TestVoiceFoldRespectsTheMinedScopeBeforeCountingIt: the tag
|
|
// condition is evaluated only AFTER the mined-exclusion filter, so a mined-only neuter row folds into the
|
|
// enriched (edit-wave) version and NEVER the base (draft-wave) one — the draft wave never renders a mined
|
|
// row's directive, so it must not re-pay for one.
|
|
func TestNeuterFoldRespectsTheMinedScope(t *testing.T) {
|
|
minedNeuter := term("元气", "изначальная ци")
|
|
minedNeuter.Source, minedNeuter.Gender = "mined", "neuter"
|
|
minedPlain := minedNeuter
|
|
minedPlain.Gender = ""
|
|
withNeuter := BankInput{Rows: []store.GlossaryEntry{term("方源", "Фан Юань"), minedNeuter}}
|
|
plain := BankInput{Rows: []store.GlossaryEntry{term("方源", "Фан Юань"), minedPlain}}
|
|
|
|
// BASE: the mined neuter row is out of scope, so neither its gender field nor the tag folds → identical.
|
|
if got, want := ComputeVersionScopedIn(withNeuter, false, true), ComputeVersionScopedIn(plain, false, true); got != want {
|
|
t.Fatalf("a mined-only neuter row moved the BASE version — the draft wave would re-pay for a directive it never renders\n got %s\n want %s", got, want)
|
|
}
|
|
// ENRICHED: the mined neuter row IS in scope, so the version moves — a loud re-snapshot for the wire the
|
|
// edit wave sees.
|
|
if ComputeVersionScopedIn(withNeuter, false, false) == ComputeVersionScopedIn(plain, false, false) {
|
|
t.Fatal("a mined neuter row did NOT move the enriched version — the edit wave would miss the directive")
|
|
}
|
|
}
|