package guard import ( "context" "math/rand/v2" "strings" "testing" ) // Found on the PoC: a word held back at one release was dropped at the next, // when that release had nothing to rewrite and sent the engine's own events. func TestAWordHeldBackIsNeverLost(t *testing.T) { g := gate(t, lib(map[string]Policy{"p": {Output: Rules{PII: map[string]string{"email": "redact"}}}}, "p")) got, _, _ := stream(g.Output(context.Background(), Subject{Stream: true}), "1", ".", " Red", "\n", "2", ".", " Green", "\n", "3", ".", " Blue") if got != "1. Red\n2. Green\n3. Blue" { t.Errorf("client got %q", got) } } // However an answer is cut into tokens, the client is sent exactly the // whole answer, rewritten. func TestEverySplitOfAnAnswerArrivesWhole(t *testing.T) { g := gate(t, lib(map[string]Policy{"p": {Output: Rules{PII: map[string]string{"email": "redact"}}}}, "p")) text := "Hello. Mail bob@example.com or ann@example.org! Lists:\n1. Red\n2. Green and a long tail without stops " + strings.Repeat("word ", 50) + "end?" want := strings.NewReplacer("bob@example.com", "[EMAIL_1]", "ann@example.org", "[EMAIL_2]").Replace(text) rng := rand.New(rand.NewPCG(1, 2)) for i := range 300 { var parts []string for rest := text; rest != ""; { n := 1 + rng.IntN(8) n = min(n, len(rest)) parts = append(parts, rest[:n]) rest = rest[n:] } got, _, _ := stream(g.Output(context.Background(), Subject{Stream: true}), parts...) if got != want { t.Fatalf("split %d: client got\n%q\nwant\n%q", i, got, want) } } }