update
This commit is contained in:
321
internal/scriptkit/engine_test.go
Normal file
321
internal/scriptkit/engine_test.go
Normal file
@@ -0,0 +1,321 @@
|
||||
package scriptkit
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"git.iwork-ai.com/xdc/iqudo-top1/internal/model"
|
||||
)
|
||||
|
||||
func buildTestPackage() *Package {
|
||||
// symptom dimension: vomiting, diarrhea
|
||||
// disease dimension: gastritis, enteritis
|
||||
pkg := &Package{Package: model.ScriptPackage{Base: model.Base{ID: 1}, StartStageKey: "symptom"}}
|
||||
pkg.Dimensions = []model.PackageDimension{
|
||||
{Base: model.Base{ID: 1}, PackageID: 1, DimKey: "symptom", Name: "症状"},
|
||||
{Base: model.Base{ID: 2}, PackageID: 1, DimKey: "disease", Name: "疾病"},
|
||||
}
|
||||
pkg.Values = []model.DimensionValue{
|
||||
{Base: model.Base{ID: 11}, PackageID: 1, DimensionID: 1, ValueKey: "vomiting", Name: "呕吐"},
|
||||
{Base: model.Base{ID: 12}, PackageID: 1, DimensionID: 1, ValueKey: "diarrhea", Name: "腹泻"},
|
||||
{Base: model.Base{ID: 21}, PackageID: 1, DimensionID: 2, ValueKey: "gastritis", Name: "胃肠炎"},
|
||||
{Base: model.Base{ID: 22}, PackageID: 1, DimensionID: 2, ValueKey: "enteritis", Name: "肠炎"},
|
||||
}
|
||||
pkg.Stages = []model.PackageStage{
|
||||
{Base: model.Base{ID: 31}, PackageID: 1, StageKey: "symptom", Name: "症状确认", PrimaryDimensionID: 1},
|
||||
{Base: model.Base{ID: 32}, PackageID: 1, StageKey: "diagnosis", Name: "拟诊确认", PrimaryDimensionID: 2},
|
||||
}
|
||||
vomiting := uint64(11)
|
||||
diarrhea := uint64(12)
|
||||
pkg.Scripts = []model.StageScript{
|
||||
{Base: model.Base{ID: 101}, PackageID: 1, StageID: 31, ScriptKey: "vomiting_info", Name: "呕吐细节", ScriptType: "info", Content: "吐的是什么?", DimensionValueID: &vomiting, ShowThreshold: 5, ConfirmThreshold: 3},
|
||||
{Base: model.Base{ID: 102}, PackageID: 1, StageID: 31, ScriptKey: "vomiting_confirm", Name: "确认呕吐", ScriptType: "confirm", Content: "有呕吐吗?", DimensionValueID: &vomiting, ShowThreshold: 5, ConfirmThreshold: 3},
|
||||
{Base: model.Base{ID: 103}, PackageID: 1, StageID: 31, ScriptKey: "diarrhea_confirm", Name: "确认腹泻", ScriptType: "confirm", Content: "有腹泻吗?", DimensionValueID: &diarrhea, ShowThreshold: 5, ConfirmThreshold: 3},
|
||||
{Base: model.Base{ID: 104}, PackageID: 1, StageID: 31, ScriptKey: "symptom_fallback", Name: "兜底", ScriptType: "fallback", Content: "哪里不舒服?"},
|
||||
{Base: model.Base{ID: 105}, PackageID: 1, StageID: 32, ScriptKey: "gastritis_confirm", Name: "确认胃肠炎", ScriptType: "confirm", Content: "更像胃肠炎吗?", DimensionValueID: u64(21), ShowThreshold: 10, ConfirmThreshold: 5},
|
||||
{Base: model.Base{ID: 106}, PackageID: 1, StageID: 32, ScriptKey: "gastritis_msg", Name: "胃肠炎话术", ScriptType: "message", Content: "更符合胃肠炎方向。", DimensionValueID: u64(21), ShowThreshold: 10, ConfirmThreshold: 5},
|
||||
}
|
||||
pkg.Options = []model.ScriptOption{
|
||||
{Base: model.Base{ID: 201}, PackageID: 1, ScriptID: 102, OptionKey: "yes", Label: "有", TargetDimensionValueID: &vomiting, Effect: "set", EffectValue: 8},
|
||||
{Base: model.Base{ID: 202}, PackageID: 1, ScriptID: 102, OptionKey: "no", Label: "没有", TargetDimensionValueID: &vomiting, Effect: "zero"},
|
||||
{Base: model.Base{ID: 203}, PackageID: 1, ScriptID: 103, OptionKey: "yes", Label: "有", TargetDimensionValueID: &diarrhea, Effect: "set", EffectValue: 8},
|
||||
{Base: model.Base{ID: 204}, PackageID: 1, ScriptID: 103, OptionKey: "no", Label: "没有", TargetDimensionValueID: &diarrhea, Effect: "zero"},
|
||||
{Base: model.Base{ID: 205}, PackageID: 1, ScriptID: 105, OptionKey: "yes", Label: "对,是这样", TargetDimensionValueID: u64(21), Effect: "set", EffectValue: 10},
|
||||
{Base: model.Base{ID: 206}, PackageID: 1, ScriptID: 105, OptionKey: "no", Label: "不是这样", TargetDimensionValueID: u64(21), Effect: "zero"},
|
||||
}
|
||||
pkg.Linkages = []model.DimensionLinkage{
|
||||
{Base: model.Base{ID: 301}, PackageID: 1, FromDimensionValueID: 11, ToDimensionValueID: 21, RelationType: "contributes_to", Contribution: 5},
|
||||
{Base: model.Base{ID: 302}, PackageID: 1, FromDimensionValueID: 12, ToDimensionValueID: 21, RelationType: "contributes_to", Contribution: 5},
|
||||
{Base: model.Base{ID: 303}, PackageID: 1, FromDimensionValueID: 12, ToDimensionValueID: 22, RelationType: "contributes_to", Contribution: 5},
|
||||
}
|
||||
pkg.Adapters = []model.PackageAdapter{
|
||||
{PackageID: 1, SourceField: "input.tags", MatchValue: "呕吐", TargetDimensionValueID: 11, Weight: 8},
|
||||
{PackageID: 1, SourceField: "input.tags", MatchValue: "腹泻", TargetDimensionValueID: 12, Weight: 3},
|
||||
}
|
||||
return pkg
|
||||
}
|
||||
|
||||
func u64(value uint64) *uint64 { return &value }
|
||||
|
||||
func TestFuzzyWeightShowsConfirmationOnly(t *testing.T) {
|
||||
pkg := buildTestPackage()
|
||||
ctx := RenderContext{Input: map[string]interface{}{"tags": []interface{}{"腹泻"}}, Derived: map[string]interface{}{}, Form: map[string]interface{}{}}
|
||||
weights := pkg.RecomputeWeights(pkg.InitialWeights(ctx), ScriptState{ScriptAnswers: map[string][]string{}, DimensionSelects: map[string]bool{}}, ctx)
|
||||
if weights[12] != 3 {
|
||||
t.Fatalf("diarrhea weight = %d, want 3", weights[12])
|
||||
}
|
||||
stage, _ := pkg.StageByKey("symptom")
|
||||
view := pkg.BuildStageView(stage, weights, ctx, ScriptState{ScriptAnswers: map[string][]string{}, DimensionSelects: map[string]bool{}}, nil)
|
||||
if len(view.Scripts) != 1 || view.Scripts[0].ScriptKey != "diarrhea_confirm" {
|
||||
t.Fatalf("fuzzy weight should only show the confirmation script, got %#v", view.Scripts)
|
||||
}
|
||||
}
|
||||
|
||||
func TestScreeningRequiredWithMoreThanThreeCandidates(t *testing.T) {
|
||||
a, b, c, d := uint64(11), uint64(12), uint64(13), uint64(14)
|
||||
pkg := &Package{Package: model.ScriptPackage{Base: model.Base{ID: 1}, StartStageKey: "symptom"}}
|
||||
pkg.Dimensions = []model.PackageDimension{{Base: model.Base{ID: 1}, PackageID: 1, DimKey: "symptom", Name: "症状"}}
|
||||
pkg.Values = []model.DimensionValue{
|
||||
{Base: model.Base{ID: a}, PackageID: 1, DimensionID: 1, ValueKey: "a", Name: "A", InitialWeight: 3},
|
||||
{Base: model.Base{ID: b}, PackageID: 1, DimensionID: 1, ValueKey: "b", Name: "B", InitialWeight: 3},
|
||||
{Base: model.Base{ID: c}, PackageID: 1, DimensionID: 1, ValueKey: "c", Name: "C", InitialWeight: 3},
|
||||
{Base: model.Base{ID: d}, PackageID: 1, DimensionID: 1, ValueKey: "d", Name: "D", InitialWeight: 3},
|
||||
}
|
||||
pkg.Stages = []model.PackageStage{{Base: model.Base{ID: 31}, PackageID: 1, StageKey: "symptom", Name: "症状确认", PrimaryDimensionID: 1}}
|
||||
pkg.Scripts = []model.StageScript{
|
||||
{Base: model.Base{ID: 101}, PackageID: 1, StageID: 31, ScriptKey: "symptom_screen", Name: "症状筛选", ScriptType: "screen", Content: "有什么表现?", Multiple: true},
|
||||
{Base: model.Base{ID: 102}, PackageID: 1, StageID: 31, ScriptKey: "confirm_a", Name: "确认A", ScriptType: "confirm", Content: "有A吗?", DimensionValueID: &a, ShowThreshold: 5, ConfirmThreshold: 3},
|
||||
{Base: model.Base{ID: 103}, PackageID: 1, StageID: 31, ScriptKey: "choice_a", Name: "A细节", ScriptType: "choice", Content: "A多久了?", DimensionValueID: &a, ShowThreshold: 5, ConfirmThreshold: 3},
|
||||
}
|
||||
pkg.Options = []model.ScriptOption{
|
||||
{Base: model.Base{ID: 201}, PackageID: 1, ScriptID: 101, OptionKey: "a", Label: "A", TargetDimensionValueID: &a, Effect: "set", EffectValue: 10},
|
||||
{Base: model.Base{ID: 202}, PackageID: 1, ScriptID: 101, OptionKey: "b", Label: "B", TargetDimensionValueID: &b, Effect: "set", EffectValue: 10},
|
||||
{Base: model.Base{ID: 203}, PackageID: 1, ScriptID: 101, OptionKey: "c", Label: "C", TargetDimensionValueID: &c, Effect: "set", EffectValue: 10},
|
||||
{Base: model.Base{ID: 204}, PackageID: 1, ScriptID: 101, OptionKey: "d", Label: "D", TargetDimensionValueID: &d, Effect: "set", EffectValue: 10},
|
||||
{Base: model.Base{ID: 205}, PackageID: 1, ScriptID: 102, OptionKey: "yes", Label: "有", TargetDimensionValueID: &a, Effect: "set", EffectValue: 8},
|
||||
{Base: model.Base{ID: 206}, PackageID: 1, ScriptID: 102, OptionKey: "no", Label: "没有", TargetDimensionValueID: &a, Effect: "zero"},
|
||||
}
|
||||
stage, _ := pkg.StageByKey("symptom")
|
||||
ctx := RenderContext{Input: map[string]interface{}{}, Derived: map[string]interface{}{}, Form: map[string]interface{}{}}
|
||||
emptyState := ScriptState{ScriptAnswers: map[string][]string{}, DimensionSelects: map[string]bool{}}
|
||||
weights := pkg.RecomputeWeights(pkg.InitialWeights(ctx), emptyState, ctx)
|
||||
view := pkg.BuildStageView(stage, weights, ctx, emptyState, nil)
|
||||
if !view.ScreeningRequired {
|
||||
t.Fatalf("4 candidates should require the screening question, got %#v", view)
|
||||
}
|
||||
// 阶段视图带出完整题目集合:筛选题 + 每个候选的确认题与细节题,
|
||||
// 客户端本地作答、结束时一次性提交。
|
||||
keys := map[string]bool{}
|
||||
for _, script := range view.Scripts {
|
||||
keys[script.ScriptKey] = true
|
||||
}
|
||||
if !keys["symptom_screen"] || !keys["confirm_a"] || !keys["choice_a"] {
|
||||
t.Fatalf("stage view should carry the complete question set, got %v", keys)
|
||||
}
|
||||
// 筛选:只选 A、B -> A/B 确认(10),C/D 归零;筛选不再要求。
|
||||
state := ScriptState{ScriptAnswers: map[string][]string{"symptom_screen": {"a", "b"}}, DimensionSelects: map[string]bool{"a": true, "b": true, "c": false, "d": false}}
|
||||
weights = pkg.RecomputeWeights(pkg.InitialWeights(ctx), state, ctx)
|
||||
if weights[a] != 10 || weights[b] != 10 || weights[c] != 0 || weights[d] != 0 {
|
||||
t.Fatalf("screening weights = %v", weights)
|
||||
}
|
||||
view = pkg.BuildStageView(stage, weights, ctx, state, nil)
|
||||
if view.ScreeningRequired {
|
||||
t.Fatalf("screening should not be required after selection, got %#v", view)
|
||||
}
|
||||
for _, script := range view.Scripts {
|
||||
if script.ScriptKey == "confirm_a" {
|
||||
t.Fatalf("confirmed value should not carry its confirm question, got %#v", view.Scripts)
|
||||
}
|
||||
if script.ScriptKey == "choice_a" && script.Weight != 10 {
|
||||
t.Fatalf("selected value details should carry weight 10, got %#v", script)
|
||||
}
|
||||
}
|
||||
// 候选 <= 3 时不要求筛选。
|
||||
lessState := ScriptState{ScriptAnswers: map[string][]string{}, DimensionSelects: map[string]bool{"c": false, "d": false}}
|
||||
lessWeights := pkg.RecomputeWeights(pkg.InitialWeights(ctx), lessState, ctx)
|
||||
lessView := pkg.BuildStageView(stage, lessWeights, ctx, lessState, nil)
|
||||
if lessView.ScreeningRequired {
|
||||
t.Fatalf("screening should not be required with <=3 candidates, got %#v", lessView)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFuzzyHintDoesNotPropagateDisease(t *testing.T) {
|
||||
pkg := buildTestPackage()
|
||||
ctx := RenderContext{Input: map[string]interface{}{"tags": []interface{}{"腹泻"}}, Derived: map[string]interface{}{}, Form: map[string]interface{}{}}
|
||||
weights := pkg.RecomputeWeights(pkg.InitialWeights(ctx), ScriptState{ScriptAnswers: map[string][]string{}, DimensionSelects: map[string]bool{}}, ctx)
|
||||
if weights[12] != 3 {
|
||||
t.Fatalf("diarrhea weight = %d, want 3", weights[12])
|
||||
}
|
||||
if weights[21] != 0 || weights[22] != 0 {
|
||||
t.Fatalf("fuzzy hint must not pull diseases in: %v", weights)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStrongWeightShowsInfoScripts(t *testing.T) {
|
||||
pkg := buildTestPackage()
|
||||
ctx := RenderContext{Input: map[string]interface{}{"tags": []interface{}{"呕吐"}}, Derived: map[string]interface{}{}, Form: map[string]interface{}{}}
|
||||
weights := pkg.RecomputeWeights(pkg.InitialWeights(ctx), ScriptState{ScriptAnswers: map[string][]string{}, DimensionSelects: map[string]bool{}}, ctx)
|
||||
stage, _ := pkg.StageByKey("symptom")
|
||||
view := pkg.BuildStageView(stage, weights, ctx, ScriptState{ScriptAnswers: map[string][]string{}, DimensionSelects: map[string]bool{}}, nil)
|
||||
if len(view.Scripts) != 1 || view.Scripts[0].ScriptKey != "vomiting_info" {
|
||||
t.Fatalf("strong weight should show the info script, got %#v", view.Scripts)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAllZeroShowsFallback(t *testing.T) {
|
||||
pkg := buildTestPackage()
|
||||
ctx := RenderContext{Input: map[string]interface{}{}, Derived: map[string]interface{}{}, Form: map[string]interface{}{}}
|
||||
weights := pkg.RecomputeWeights(pkg.InitialWeights(ctx), ScriptState{ScriptAnswers: map[string][]string{}, DimensionSelects: map[string]bool{}}, ctx)
|
||||
stage, _ := pkg.StageByKey("symptom")
|
||||
view := pkg.BuildStageView(stage, weights, ctx, ScriptState{ScriptAnswers: map[string][]string{}, DimensionSelects: map[string]bool{}}, nil)
|
||||
if len(view.Scripts) != 1 || view.Scripts[0].Type != "fallback" {
|
||||
t.Fatalf("all zero weights should show fallback, got %#v", view.Scripts)
|
||||
}
|
||||
if view.Fallback != "哪里不舒服?" {
|
||||
t.Fatalf("fallback = %q", view.Fallback)
|
||||
}
|
||||
}
|
||||
|
||||
func TestConfirmYesSetsWeightAndPropagatesDisease(t *testing.T) {
|
||||
pkg := buildTestPackage()
|
||||
ctx := RenderContext{Input: map[string]interface{}{}, Derived: map[string]interface{}{}, Form: map[string]interface{}{}}
|
||||
state := ScriptState{ScriptAnswers: map[string][]string{"vomiting_confirm": {"yes"}}, DimensionSelects: map[string]bool{}}
|
||||
weights := pkg.RecomputeWeights(pkg.InitialWeights(ctx), state, ctx)
|
||||
if weights[11] != 8 {
|
||||
t.Fatalf("vomiting weight = %d, want 8", weights[11])
|
||||
}
|
||||
if weights[21] != 5 {
|
||||
t.Fatalf("gastritis weight = %d, want 5 via linkage", weights[21])
|
||||
}
|
||||
// 候选疾病先带出确认题和确认后话术(完整题目集合,客户端本地作答后
|
||||
// 一次性提交;确认后话术在本地确认后再展示)。
|
||||
stage, _ := pkg.StageByKey("diagnosis")
|
||||
view := pkg.BuildStageView(stage, weights, ctx, state, nil)
|
||||
keys := map[string]bool{}
|
||||
for _, script := range view.Scripts {
|
||||
keys[script.ScriptKey] = true
|
||||
}
|
||||
if !keys["gastritis_confirm"] || !keys["gastritis_msg"] {
|
||||
t.Fatalf("candidate disease should carry confirm question and follow-up copy, got %v", keys)
|
||||
}
|
||||
// 确认疾病后(对,是这样 -> 权重10),确认题隐藏,只保留该疾病话术。
|
||||
state.ScriptAnswers["gastritis_confirm"] = []string{"yes"}
|
||||
weights = pkg.RecomputeWeights(pkg.InitialWeights(ctx), state, ctx)
|
||||
if weights[21] != 10 {
|
||||
t.Fatalf("confirmed gastritis weight = %d, want 10", weights[21])
|
||||
}
|
||||
view = pkg.BuildStageView(stage, weights, ctx, state, nil)
|
||||
if len(view.Scripts) != 1 || view.Scripts[0].ScriptKey != "gastritis_msg" {
|
||||
t.Fatalf("confirmed disease should keep only its copy, got %#v", view.Scripts)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMultipleDiseasesCanBeConfirmed(t *testing.T) {
|
||||
pkg := buildTestPackage()
|
||||
ctx := RenderContext{Input: map[string]interface{}{}, Derived: map[string]interface{}{}, Form: map[string]interface{}{}}
|
||||
// 两个症状都确认(呕吐、腹泻),再确认两个疾病方向。
|
||||
state := ScriptState{ScriptAnswers: map[string][]string{
|
||||
"vomiting_confirm": {"yes"},
|
||||
"diarrhea_confirm": {"yes"},
|
||||
"gastritis_confirm": {"yes"},
|
||||
}, DimensionSelects: map[string]bool{"enteritis": true}}
|
||||
weights := pkg.RecomputeWeights(pkg.InitialWeights(ctx), state, ctx)
|
||||
if weights[21] != 10 {
|
||||
t.Fatalf("gastritis weight = %d, want 10 after confirmation", weights[21])
|
||||
}
|
||||
if weights[22] < 10 {
|
||||
t.Fatalf("enteritis weight = %d, want >= 10 after confirmation", weights[22])
|
||||
}
|
||||
}
|
||||
|
||||
func TestConfirmNoZeroesWeight(t *testing.T) {
|
||||
pkg := buildTestPackage()
|
||||
ctx := RenderContext{Input: map[string]interface{}{"tags": []interface{}{"腹泻"}}, Derived: map[string]interface{}{}, Form: map[string]interface{}{}}
|
||||
state := ScriptState{ScriptAnswers: map[string][]string{"diarrhea_confirm": {"no"}}, DimensionSelects: map[string]bool{}}
|
||||
weights := pkg.RecomputeWeights(pkg.InitialWeights(ctx), state, ctx)
|
||||
if weights[12] != 0 {
|
||||
t.Fatalf("diarrhea weight = %d, want 0", weights[12])
|
||||
}
|
||||
}
|
||||
|
||||
func TestDirectSelectSetsHighWeight(t *testing.T) {
|
||||
pkg := buildTestPackage()
|
||||
ctx := RenderContext{Input: map[string]interface{}{}, Derived: map[string]interface{}{}, Form: map[string]interface{}{}}
|
||||
state := ScriptState{ScriptAnswers: map[string][]string{}, DimensionSelects: map[string]bool{"vomiting": true}}
|
||||
weights := pkg.RecomputeWeights(pkg.InitialWeights(ctx), state, ctx)
|
||||
if weights[11] != SelectWeight {
|
||||
t.Fatalf("selected weight = %d, want %d", weights[11], SelectWeight)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRecomputeIsDeterministic(t *testing.T) {
|
||||
pkg := buildTestPackage()
|
||||
ctx := RenderContext{Input: map[string]interface{}{"tags": []interface{}{"腹泻"}}, Derived: map[string]interface{}{}, Form: map[string]interface{}{}}
|
||||
state := ScriptState{ScriptAnswers: map[string][]string{"diarrhea_confirm": {"yes"}}, DimensionSelects: map[string]bool{}}
|
||||
first := pkg.RecomputeWeights(pkg.InitialWeights(ctx), state, ctx)
|
||||
for range 5 {
|
||||
again := pkg.RecomputeWeights(pkg.InitialWeights(ctx), state, ctx)
|
||||
if !weightsEqual(first, again) {
|
||||
t.Fatalf("recompute is not deterministic: %v vs %v", first, again)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRenderTemplate(t *testing.T) {
|
||||
ctx := RenderContext{
|
||||
Input: map[string]interface{}{"customer_name": "王女士", "products": []interface{}{"商品A", "商品B"}},
|
||||
Derived: map[string]interface{}{},
|
||||
Form: map[string]interface{}{"note": "已接受"},
|
||||
}
|
||||
got := RenderTemplate("您好{{input.customer_name}},看到{{input.products}},备注{{form.note}}。", ctx)
|
||||
if got != "您好王女士,看到商品A、商品B,备注已接受。" {
|
||||
t.Fatalf("RenderTemplate = %q", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDiagnosisRequiresConfirmedDiseaseBeforeAdvancing(t *testing.T) {
|
||||
pkg := buildTestPackage()
|
||||
ctx := RenderContext{Input: map[string]interface{}{}, Derived: map[string]interface{}{}, Form: map[string]interface{}{}}
|
||||
// 症状确认带出候选疾病(权重5),但还没有确认任何疾病方向。
|
||||
state := ScriptState{ScriptAnswers: map[string][]string{"vomiting_confirm": {"yes"}}, DimensionSelects: map[string]bool{}}
|
||||
weights := pkg.RecomputeWeights(pkg.InitialWeights(ctx), state, ctx)
|
||||
stage, _ := pkg.StageByKey("diagnosis")
|
||||
view := pkg.BuildStageView(stage, weights, ctx, state, nil)
|
||||
if view.CanNext {
|
||||
t.Fatalf("diagnosis should require a confirmed disease before advancing, got can_next=%v", view.CanNext)
|
||||
}
|
||||
if view.CanNextReason == "" {
|
||||
t.Fatalf("diagnosis block should carry a reason, got %q", view.CanNextReason)
|
||||
}
|
||||
// 确认疾病后(权重10)才能进入药品推荐。
|
||||
state.ScriptAnswers["gastritis_confirm"] = []string{"yes"}
|
||||
weights = pkg.RecomputeWeights(pkg.InitialWeights(ctx), state, ctx)
|
||||
view = pkg.BuildStageView(stage, weights, ctx, state, nil)
|
||||
if !view.CanNext {
|
||||
t.Fatalf("confirmed disease should allow advancing, got can_next=%v reason=%q", view.CanNext, view.CanNextReason)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStageViewOnlyShowsPrimaryDimension(t *testing.T) {
|
||||
pkg := buildTestPackage()
|
||||
ctx := RenderContext{Input: map[string]interface{}{"tags": []interface{}{"呕吐"}}, Derived: map[string]interface{}{}, Form: map[string]interface{}{}}
|
||||
state := ScriptState{ScriptAnswers: map[string][]string{"vomiting_confirm": {"yes"}}, DimensionSelects: map[string]bool{}}
|
||||
weights := pkg.RecomputeWeights(pkg.InitialWeights(ctx), state, ctx)
|
||||
// 症状阶段:症状与疾病(联动权重5)都有值,但只显示主维度症状。
|
||||
stage, _ := pkg.StageByKey("symptom")
|
||||
view := pkg.BuildStageView(stage, weights, ctx, state, nil)
|
||||
if len(view.Dimensions) != 1 || view.Dimensions[0].DimKey != "symptom" {
|
||||
t.Fatalf("symptom stage should only show the symptom dimension, got %#v", view.Dimensions)
|
||||
}
|
||||
// 拟诊阶段:只显示疾病维度,不显示症状。
|
||||
diagStage, _ := pkg.StageByKey("diagnosis")
|
||||
diagView := pkg.BuildStageView(diagStage, weights, ctx, state, nil)
|
||||
if len(diagView.Dimensions) != 1 || diagView.Dimensions[0].DimKey != "disease" {
|
||||
t.Fatalf("diagnosis stage should only show the disease dimension, got %#v", diagView.Dimensions)
|
||||
}
|
||||
// 没有主维度的阶段(开场)不显示任何维度。
|
||||
openStage := model.PackageStage{Base: model.Base{ID: 33}, PackageID: 1, StageKey: "opening", Name: "开场", PrimaryDimensionID: 0}
|
||||
openView := pkg.BuildStageView(openStage, weights, ctx, state, nil)
|
||||
if len(openView.Dimensions) != 0 {
|
||||
t.Fatalf("opening stage should show no dimensions, got %#v", openView.Dimensions)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user