72 lines
3.1 KiB
Go
72 lines
3.1 KiB
Go
package pipeline
|
||
|
||
import (
|
||
"strings"
|
||
"testing"
|
||
)
|
||
|
||
func TestMessagesInjectionLayout(t *testing.T) {
|
||
tpl := writeTemplate(t, "Стабильный системный префикс.\n---USER---\nПереведи: {{text}}")
|
||
v := RenderVars{Book: testBook(), Text: "исходный чанк"}
|
||
injection := "ГЛОССАРИЙ:\n阿Q → А-кью"
|
||
|
||
msgs, err := MessagesWithInjection(tpl, v, injection)
|
||
if err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
if len(msgs) != 3 {
|
||
t.Fatalf("want 3 messages (system, injection, user), got %d", len(msgs))
|
||
}
|
||
// [0] stable system prefix carries the cache boundary.
|
||
if msgs[0].Role != "system" || !msgs[0].CacheBoundary {
|
||
t.Errorf("msg[0] must be the system prefix with CacheBoundary=true: %+v", msgs[0])
|
||
}
|
||
// [1] injection sits AFTER the boundary (volatile → CacheBoundary=false).
|
||
if msgs[1].Role != "system" || msgs[1].CacheBoundary || msgs[1].Content != injection {
|
||
t.Errorf("msg[1] must be the injection with CacheBoundary=false: %+v", msgs[1])
|
||
}
|
||
// [2] the volatile user chunk. It must contain ONLY the rendered chunk, never the
|
||
// glossary (ch.Text stays clean — the 3a contract; the coverage gate reads ch.Text).
|
||
if msgs[2].Role != "user" {
|
||
t.Errorf("msg[2] must be user: %+v", msgs[2])
|
||
}
|
||
if strings.Contains(msgs[2].Content, "ГЛОССАРИЙ") || strings.Contains(msgs[2].Content, "阿Q") {
|
||
t.Errorf("glossary leaked into the user (ch.Text) message: %q", msgs[2].Content)
|
||
}
|
||
if !strings.Contains(msgs[2].Content, "исходный чанк") {
|
||
t.Errorf("user message lost the chunk: %q", msgs[2].Content)
|
||
}
|
||
}
|
||
|
||
func TestMessagesEmptyInjectionIdentical(t *testing.T) {
|
||
tpl := writeTemplate(t, "Системный префикс.\n---USER---\nТекст: {{text}}")
|
||
v := RenderVars{Book: testBook(), Text: "чанк"}
|
||
plain, _ := Messages(tpl, v)
|
||
withEmpty, _ := MessagesWithInjection(tpl, v, " ") // whitespace-only → no injection
|
||
if len(plain) != 2 || len(withEmpty) != 2 {
|
||
t.Fatalf("empty injection must yield 2 messages: %d vs %d", len(plain), len(withEmpty))
|
||
}
|
||
for i := range plain {
|
||
if plain[i] != withEmpty[i] {
|
||
t.Errorf("empty-injection message %d differs from plain: %+v vs %+v", i, withEmpty[i], plain[i])
|
||
}
|
||
}
|
||
}
|
||
|
||
// TestInjectionChangesRequestHash: the injection is folded into request_hash via the
|
||
// messages, so a different glossary is a different request (a changed approved term
|
||
// re-derives the chunk, never serves a stale checkpoint).
|
||
func TestInjectionChangesRequestHash(t *testing.T) {
|
||
tpl := writeTemplate(t, "Префикс.\n---USER---\n{{text}}")
|
||
v := RenderVars{Book: testBook(), Text: "чанк"}
|
||
none, _ := Messages(tpl, v)
|
||
inj, _ := MessagesWithInjection(tpl, v, "ГЛОССАРИЙ:\n阿Q → А-кью")
|
||
req := Request{BookID: "b", Chapter: 1, Stage: "draft", Role: "translator", Model: "m",
|
||
Temperature: 0.3, Reasoning: "off", MaxTokens: 1024, SnapshotID: "snap"}
|
||
reqNone, reqInj := req, req
|
||
reqNone.Messages, reqInj.Messages = none, inj
|
||
hNone, hInj := RequestHash(reqNone), RequestHash(reqInj)
|
||
if hNone == hInj {
|
||
t.Error("injection did not change request_hash — a glossary change would silently hit a stale checkpoint")
|
||
}
|
||
}
|