2026-07-07 17:11:25 +08:00
|
|
|
package model
|
|
|
|
|
|
2026-07-08 10:37:06 +08:00
|
|
|
import (
|
|
|
|
|
"fmt"
|
2026-07-10 11:02:56 +08:00
|
|
|
"reflect"
|
2026-07-09 16:31:19 +08:00
|
|
|
"strings"
|
2026-07-08 10:37:06 +08:00
|
|
|
"testing"
|
|
|
|
|
|
|
|
|
|
"modelRT/constants"
|
|
|
|
|
)
|
2026-07-07 17:11:25 +08:00
|
|
|
|
|
|
|
|
func TestFuzzyRecommendOffsetUsesFullMatchedInput(t *testing.T) {
|
|
|
|
|
tests := []struct {
|
|
|
|
|
name string
|
|
|
|
|
searchPrefix string
|
|
|
|
|
searchInput string
|
|
|
|
|
want int
|
|
|
|
|
}{
|
|
|
|
|
{
|
|
|
|
|
name: "zone fuzzy prefix",
|
|
|
|
|
searchPrefix: "grid000",
|
|
|
|
|
searchInput: "z",
|
|
|
|
|
want: len([]rune("grid000.z")),
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "level one fuzzy",
|
|
|
|
|
searchPrefix: "",
|
|
|
|
|
searchInput: "g",
|
|
|
|
|
want: len([]rune("g")),
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "measurement fuzzy preserves config token",
|
|
|
|
|
searchPrefix: "grid.zone.station.nspath.comp.config",
|
|
|
|
|
searchInput: "m",
|
|
|
|
|
want: len([]rune("grid.zone.station.nspath.comp.config.m")),
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for _, tt := range tests {
|
|
|
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
|
|
|
got := fuzzyRecommendOffset(tt.searchPrefix, tt.searchInput)
|
|
|
|
|
if got != tt.want {
|
|
|
|
|
t.Fatalf("expected offset %d, got %d", tt.want, got)
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-07-08 10:37:06 +08:00
|
|
|
|
2026-07-10 16:03:16 +08:00
|
|
|
func TestFuzzyRecommendMemberSetKeyUsesLocalNSPathSet(t *testing.T) {
|
|
|
|
|
setKey, ok := fuzzyRecommendMemberSetKey(constants.CompNSPathRecommendHierarchyType, constants.IsLocalRecommendLength, "")
|
|
|
|
|
if !ok {
|
|
|
|
|
t.Fatalf("expected local nspath fuzzy member check to use a redis set")
|
|
|
|
|
}
|
|
|
|
|
if setKey != constants.RedisAllCompNSPathSetKey {
|
|
|
|
|
t.Fatalf("expected set key %q, got %q", constants.RedisAllCompNSPathSetKey, setKey)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestNormalizeRecommendResultsKeepsFuzzyExactContinuation(t *testing.T) {
|
|
|
|
|
tests := []struct {
|
|
|
|
|
name string
|
|
|
|
|
input string
|
|
|
|
|
recommendType constants.RecommendHierarchyType
|
|
|
|
|
offset int
|
|
|
|
|
}{
|
|
|
|
|
{
|
|
|
|
|
name: "local nspath typo completes current level",
|
|
|
|
|
input: "110kV_TV-demoProjectx",
|
|
|
|
|
recommendType: constants.CompNSPathRecommendHierarchyType,
|
|
|
|
|
offset: len([]rune("110kV_TV-demoProject")),
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "grid typo completes current level",
|
|
|
|
|
input: "grid000x",
|
|
|
|
|
recommendType: constants.GridRecommendHierarchyType,
|
|
|
|
|
offset: len([]rune("grid000")),
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "zone typo completes current level",
|
|
|
|
|
input: "grid000.zone000x",
|
|
|
|
|
recommendType: constants.ZoneRecommendHierarchyType,
|
|
|
|
|
offset: len([]rune("grid000.zone000")),
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "station typo completes current level",
|
|
|
|
|
input: "grid000.zone000.station000x",
|
|
|
|
|
recommendType: constants.StationRecommendHierarchyType,
|
|
|
|
|
offset: len([]rune("grid000.zone000.station000")),
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "full nspath typo completes current level",
|
|
|
|
|
input: "grid000.zone000.station000.110kV_TV-demoProjectx",
|
|
|
|
|
recommendType: constants.CompNSPathRecommendHierarchyType,
|
|
|
|
|
offset: len([]rune("grid000.zone000.station000.110kV_TV-demoProject")),
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for _, tt := range tests {
|
|
|
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
|
|
|
results := map[string]SearchResult{
|
|
|
|
|
tt.recommendType.String(): {
|
|
|
|
|
RecommendType: tt.recommendType,
|
|
|
|
|
QueryDatas: []string{"."},
|
|
|
|
|
IsFuzzy: true,
|
|
|
|
|
Offset: tt.offset,
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
got := normalizeRecommendResults(tt.input, results)
|
|
|
|
|
result := got[tt.recommendType.String()]
|
|
|
|
|
if result.Offset != tt.offset {
|
|
|
|
|
t.Fatalf("expected offset %d, got %d", tt.offset, result.Offset)
|
|
|
|
|
}
|
|
|
|
|
if !reflect.DeepEqual(result.QueryDatas, []string{"."}) {
|
|
|
|
|
t.Fatalf("expected fuzzy exact continuation '.', got %#v", result.QueryDatas)
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-09 16:31:19 +08:00
|
|
|
func TestNormalizeRecommendResultsUsesInputLengthForExactCompletion(t *testing.T) {
|
|
|
|
|
tests := []struct {
|
|
|
|
|
name string
|
|
|
|
|
input string
|
|
|
|
|
}{
|
|
|
|
|
{
|
|
|
|
|
name: "full token1 to token7 structure",
|
|
|
|
|
input: "grid000.zone000.station000.220kV_学府路1-testProject1.compTag.config.IA_rms_CTA-testProject1",
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "local token4 to token7 structure",
|
|
|
|
|
input: "220kV_学府路1-testProject1.IA_rms_CTA-testProject1",
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for _, tt := range tests {
|
|
|
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
|
|
|
results := map[string]SearchResult{
|
|
|
|
|
constants.MeasTagRecommendHierarchyType.String(): {
|
|
|
|
|
RecommendType: constants.MeasTagRecommendHierarchyType,
|
|
|
|
|
QueryDatas: []string{""},
|
|
|
|
|
IsFuzzy: false,
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
got := normalizeRecommendResults(tt.input, results)
|
|
|
|
|
result := got[constants.MeasTagRecommendHierarchyType.String()]
|
|
|
|
|
wantOffset := len([]rune(tt.input))
|
|
|
|
|
if result.Offset != wantOffset {
|
|
|
|
|
t.Fatalf("expected offset %d, got %d", wantOffset, result.Offset)
|
|
|
|
|
}
|
|
|
|
|
if len(result.QueryDatas) != 0 {
|
|
|
|
|
t.Fatalf("expected exact completion to return no suffix, got %v", result.QueryDatas)
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestNormalizeRecommendResultsUsesInputLengthForLevelContinuation(t *testing.T) {
|
|
|
|
|
tests := []struct {
|
|
|
|
|
name string
|
|
|
|
|
input string
|
|
|
|
|
recommendType constants.RecommendHierarchyType
|
|
|
|
|
}{
|
|
|
|
|
{
|
|
|
|
|
name: "token1 grid can continue",
|
|
|
|
|
input: "grid000",
|
|
|
|
|
recommendType: constants.GridRecommendHierarchyType,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "token1 token2 zone can continue",
|
|
|
|
|
input: "grid000.zone000",
|
|
|
|
|
recommendType: constants.ZoneRecommendHierarchyType,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "token1 token2 token3 station can continue",
|
|
|
|
|
input: "grid000.zone000.station000",
|
|
|
|
|
recommendType: constants.StationRecommendHierarchyType,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "token1 token2 token3 token4 nspath can continue",
|
|
|
|
|
input: "grid000.zone000.station000.110kV_TV-demoProject",
|
|
|
|
|
recommendType: constants.CompNSPathRecommendHierarchyType,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "token1 token2 token3 token4 token5 compTag can continue",
|
|
|
|
|
input: "grid000.zone000.station000.110kV_TV-demoProject.cable_26-demoProject110kV_TV",
|
|
|
|
|
recommendType: constants.CompTagRecommendHierarchyType,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "token1 through token6 config can continue",
|
|
|
|
|
input: "grid000.zone000.station000.110kV_TV-demoProject.cable_26-demoProject110kV_TV.base_extend",
|
|
|
|
|
recommendType: constants.ConfigRecommendHierarchyType,
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for _, tt := range tests {
|
|
|
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
|
|
|
results := map[string]SearchResult{
|
|
|
|
|
tt.recommendType.String(): {
|
|
|
|
|
RecommendType: tt.recommendType,
|
|
|
|
|
QueryDatas: []string{"."},
|
|
|
|
|
IsFuzzy: false,
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
got := normalizeRecommendResults(tt.input, results)
|
|
|
|
|
result := got[tt.recommendType.String()]
|
|
|
|
|
wantOffset := len([]rune(tt.input))
|
|
|
|
|
if result.Offset != wantOffset {
|
|
|
|
|
t.Fatalf("expected offset %d, got %d", wantOffset, result.Offset)
|
|
|
|
|
}
|
|
|
|
|
if len(result.QueryDatas) != 1 || result.QueryDatas[0] != "." {
|
|
|
|
|
t.Fatalf("expected level continuation '.', got %v", result.QueryDatas)
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestNormalizeRecommendResultsKeepsFallbackOffsetZero(t *testing.T) {
|
|
|
|
|
input := "x"
|
|
|
|
|
results := map[string]SearchResult{
|
|
|
|
|
constants.GridRecommendHierarchyType.String(): {
|
|
|
|
|
RecommendType: constants.GridRecommendHierarchyType,
|
|
|
|
|
QueryDatas: []string{"grid000", "grid001"},
|
|
|
|
|
IsFuzzy: true,
|
|
|
|
|
IsFallback: true,
|
|
|
|
|
Offset: 0,
|
|
|
|
|
},
|
|
|
|
|
constants.CompNSPathRecommendHierarchyType.String(): {
|
|
|
|
|
RecommendType: constants.CompNSPathRecommendHierarchyType,
|
|
|
|
|
QueryDatas: []string{"nspath000", "nspath001"},
|
|
|
|
|
IsFuzzy: true,
|
|
|
|
|
IsFallback: true,
|
|
|
|
|
Offset: 0,
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
got := normalizeRecommendResults(input, results)
|
|
|
|
|
for key, result := range got {
|
|
|
|
|
if result.Offset != 0 {
|
|
|
|
|
t.Fatalf("expected fallback offset 0 for %s, got %d", key, result.Offset)
|
|
|
|
|
}
|
|
|
|
|
if len(result.QueryDatas) != 2 {
|
|
|
|
|
t.Fatalf("expected fallback recommends to remain intact for %s, got %v", key, result.QueryDatas)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestNormalizeRecommendResultsKeepsParentPrefixOffsetForSpecificFallback(t *testing.T) {
|
|
|
|
|
nsPath := "220kV_学府路1-testProject1"
|
|
|
|
|
input := nsPath + ".x"
|
|
|
|
|
offset := recommendPrefixOffset([]string{nsPath})
|
|
|
|
|
results := map[string]SearchResult{
|
|
|
|
|
constants.CompTagRecommendHierarchyType.String(): {
|
|
|
|
|
RecommendType: constants.CompTagRecommendHierarchyType,
|
|
|
|
|
QueryDatas: []string{
|
|
|
|
|
nsPath + ".CTA-testProject1220kV_学府路1",
|
|
|
|
|
nsPath + ".CB-testProject1220kV_学府路1",
|
|
|
|
|
},
|
|
|
|
|
IsFuzzy: true,
|
|
|
|
|
IsFallback: true,
|
|
|
|
|
Offset: offset,
|
|
|
|
|
},
|
|
|
|
|
constants.MeasTagRecommendHierarchyType.String(): {
|
|
|
|
|
RecommendType: constants.MeasTagRecommendHierarchyType,
|
|
|
|
|
QueryDatas: []string{
|
|
|
|
|
nsPath + ".IA_rms_CTA-testProject1",
|
|
|
|
|
nsPath + ".IB_rms_CTA-testProject1",
|
|
|
|
|
},
|
|
|
|
|
IsFuzzy: true,
|
|
|
|
|
IsFallback: true,
|
|
|
|
|
Offset: offset,
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
got := normalizeRecommendResults(input, results)
|
|
|
|
|
if offset != 24 {
|
|
|
|
|
t.Fatalf("expected sample parent prefix offset 24, got %d", offset)
|
|
|
|
|
}
|
|
|
|
|
for key, result := range got {
|
|
|
|
|
if result.Offset != 24 {
|
|
|
|
|
t.Fatalf("expected specific fallback offset 24 for %s, got %d", key, result.Offset)
|
|
|
|
|
}
|
|
|
|
|
for _, recommend := range result.QueryDatas {
|
|
|
|
|
if strings.HasPrefix(recommend, nsPath+".") {
|
|
|
|
|
t.Fatalf("expected trimmed fallback recommend for %s, got %s", key, recommend)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-10 11:02:56 +08:00
|
|
|
func TestNormalizeRecommendResultsTrimsConfigFuzzySuffixes(t *testing.T) {
|
|
|
|
|
input := "110kV_TV-testProject1.cable_22-testProject1110kV_TV.base_extend.c"
|
|
|
|
|
offset := len([]rune(input))
|
|
|
|
|
results := map[string]SearchResult{
|
|
|
|
|
constants.MeasTagRecommendHierarchyType.String(): {
|
|
|
|
|
RecommendType: constants.MeasTagRecommendHierarchyType,
|
|
|
|
|
QueryDatas: []string{
|
|
|
|
|
input + "apacity",
|
|
|
|
|
input + "ategory",
|
|
|
|
|
input + "urrent",
|
|
|
|
|
input + "ode",
|
|
|
|
|
},
|
|
|
|
|
IsFuzzy: true,
|
|
|
|
|
Offset: offset,
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
got := normalizeRecommendResults(input, results)
|
|
|
|
|
result := got[constants.MeasTagRecommendHierarchyType.String()]
|
|
|
|
|
want := []string{"apacity", "ategory", "urrent", "ode"}
|
|
|
|
|
if result.Offset != offset {
|
|
|
|
|
t.Fatalf("expected offset %d, got %d", offset, result.Offset)
|
|
|
|
|
}
|
|
|
|
|
if !reflect.DeepEqual(result.QueryDatas, want) {
|
|
|
|
|
t.Fatalf("expected trimmed recommends %#v, got %#v", want, result.QueryDatas)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestNormalizeRecommendResultsTrimsToken4FallbackCandidates(t *testing.T) {
|
|
|
|
|
nsPath := "110kV_TV-testProject1"
|
|
|
|
|
input := nsPath + ".x"
|
|
|
|
|
offset := recommendPrefixOffset([]string{nsPath})
|
|
|
|
|
results := map[string]SearchResult{
|
|
|
|
|
constants.CompTagRecommendHierarchyType.String(): {
|
|
|
|
|
RecommendType: constants.CompTagRecommendHierarchyType,
|
|
|
|
|
QueryDatas: []string{
|
|
|
|
|
nsPath + ".cable_22-testProject1110kV_TV",
|
|
|
|
|
nsPath + ".cable_23-testProject1110kV_TV",
|
|
|
|
|
},
|
|
|
|
|
IsFuzzy: true,
|
|
|
|
|
IsFallback: true,
|
|
|
|
|
Offset: offset,
|
|
|
|
|
},
|
|
|
|
|
constants.MeasTagRecommendHierarchyType.String(): {
|
|
|
|
|
RecommendType: constants.MeasTagRecommendHierarchyType,
|
|
|
|
|
QueryDatas: []string{
|
|
|
|
|
nsPath + ".IA_rms_CTA-testProject1",
|
|
|
|
|
nsPath + ".IB_rms_CTA-testProject1",
|
|
|
|
|
},
|
|
|
|
|
IsFuzzy: true,
|
|
|
|
|
IsFallback: true,
|
|
|
|
|
Offset: offset,
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
got := normalizeRecommendResults(input, results)
|
|
|
|
|
for key, result := range got {
|
|
|
|
|
if result.Offset != offset {
|
|
|
|
|
t.Fatalf("expected offset %d for %s, got %d", offset, key, result.Offset)
|
|
|
|
|
}
|
|
|
|
|
for _, recommend := range result.QueryDatas {
|
|
|
|
|
if strings.HasPrefix(recommend, nsPath+".") {
|
|
|
|
|
t.Fatalf("expected trimmed token4 fallback recommend for %s, got %s", key, recommend)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if got[constants.CompTagRecommendHierarchyType.String()].QueryDatas[0] != "cable_22-testProject1110kV_TV" {
|
|
|
|
|
t.Fatalf("expected token5 suffixes, got %v", got[constants.CompTagRecommendHierarchyType.String()].QueryDatas)
|
|
|
|
|
}
|
|
|
|
|
if got[constants.MeasTagRecommendHierarchyType.String()].QueryDatas[0] != "IA_rms_CTA-testProject1" {
|
|
|
|
|
t.Fatalf("expected token7 suffixes, got %v", got[constants.MeasTagRecommendHierarchyType.String()].QueryDatas)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestNormalizeRecommendResultsKeepsFullAndLocalConfigMeasurementSuffixesConsistent(t *testing.T) {
|
|
|
|
|
fullPrefix := "grid000.zone000.station000.110kV_TV-demoProject.cable_22-testProject1110kV_TV.base_extend"
|
|
|
|
|
localPrefix := "110kV_TV-demoProject.cable_22-testProject1110kV_TV.base_extend"
|
|
|
|
|
members := []string{"capacity", "category", "current"}
|
|
|
|
|
|
|
|
|
|
fullResults := map[string]SearchResult{
|
|
|
|
|
constants.MeasTagRecommendHierarchyType.String(): {
|
|
|
|
|
RecommendType: constants.MeasTagRecommendHierarchyType,
|
|
|
|
|
QueryDatas: combineQueryResultByInput(constants.MeasTagRecommendHierarchyType, constants.FullRecommendLength, strings.Split(fullPrefix+".", "."), members),
|
|
|
|
|
IsFuzzy: false,
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
localResults := map[string]SearchResult{
|
|
|
|
|
constants.MeasTagRecommendHierarchyType.String(): {
|
|
|
|
|
RecommendType: constants.MeasTagRecommendHierarchyType,
|
|
|
|
|
QueryDatas: combineQueryResultByInput(constants.MeasTagRecommendHierarchyType, constants.IsLocalRecommendLength, strings.Split(localPrefix+".", "."), members),
|
|
|
|
|
IsFuzzy: false,
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fullGot := normalizeRecommendResults(fullPrefix+".", fullResults)
|
|
|
|
|
localGot := normalizeRecommendResults(localPrefix+".", localResults)
|
|
|
|
|
fullRecommends := fullGot[constants.MeasTagRecommendHierarchyType.String()].QueryDatas
|
|
|
|
|
localRecommends := localGot[constants.MeasTagRecommendHierarchyType.String()].QueryDatas
|
|
|
|
|
if !reflect.DeepEqual(fullRecommends, localRecommends) {
|
|
|
|
|
t.Fatalf("expected full/local config measurement suffixes to match, full=%#v local=%#v", fullRecommends, localRecommends)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestNormalizeRecommendResultsKeepsFullAndLocalBayMeasurementSuffixesConsistent(t *testing.T) {
|
|
|
|
|
fullPrefix := "grid000.zone000.station000.110kV_TV-demoProject.cable_22-testProject1110kV_TV.bay"
|
|
|
|
|
localPrefix := "110kV_TV-demoProject.cable_22-testProject1110kV_TV.bay"
|
|
|
|
|
members := []string{"IA_rms", "IB_rms", "IC_rms"}
|
|
|
|
|
|
|
|
|
|
fullResults := map[string]SearchResult{
|
|
|
|
|
constants.MeasTagRecommendHierarchyType.String(): {
|
|
|
|
|
RecommendType: constants.MeasTagRecommendHierarchyType,
|
|
|
|
|
QueryDatas: combineQueryResultByInput(constants.MeasTagRecommendHierarchyType, constants.FullRecommendLength, strings.Split(fullPrefix+".", "."), members),
|
|
|
|
|
IsFuzzy: false,
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
localResults := map[string]SearchResult{
|
|
|
|
|
constants.MeasTagRecommendHierarchyType.String(): {
|
|
|
|
|
RecommendType: constants.MeasTagRecommendHierarchyType,
|
|
|
|
|
QueryDatas: combineQueryResultByInput(constants.MeasTagRecommendHierarchyType, constants.IsLocalRecommendLength, strings.Split(localPrefix+".", "."), members),
|
|
|
|
|
IsFuzzy: false,
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fullGot := normalizeRecommendResults(fullPrefix+".", fullResults)
|
|
|
|
|
localGot := normalizeRecommendResults(localPrefix+".", localResults)
|
|
|
|
|
fullRecommends := fullGot[constants.MeasTagRecommendHierarchyType.String()].QueryDatas
|
|
|
|
|
localRecommends := localGot[constants.MeasTagRecommendHierarchyType.String()].QueryDatas
|
|
|
|
|
if !reflect.DeepEqual(fullRecommends, localRecommends) {
|
|
|
|
|
t.Fatalf("expected full/local bay measurement suffixes to match, full=%#v local=%#v", fullRecommends, localRecommends)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-10 16:03:16 +08:00
|
|
|
func TestNormalizeRecommendResultsKeepsConfigMismatchFallbackConsistentWithEmptyInput(t *testing.T) {
|
|
|
|
|
prefix := "110kV_TV-demoProject.cable_22-testProject1110kV_TV"
|
|
|
|
|
members := []string{"bay", "base_extend", "model", "component"}
|
|
|
|
|
groupResults := combineQueryResultByInput(constants.ConfigRecommendHierarchyType, constants.IsLocalRecommendLength, strings.Split(prefix+".", "."), members)
|
|
|
|
|
offset := recommendPrefixOffset(strings.Split(prefix, "."))
|
|
|
|
|
|
|
|
|
|
emptyInputResults := map[string]SearchResult{
|
|
|
|
|
constants.ConfigRecommendHierarchyType.String(): {
|
|
|
|
|
RecommendType: constants.ConfigRecommendHierarchyType,
|
|
|
|
|
QueryDatas: append([]string{}, groupResults...),
|
|
|
|
|
IsFuzzy: false,
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
mismatchFallbackResults := map[string]SearchResult{
|
|
|
|
|
constants.ConfigRecommendHierarchyType.String(): {
|
|
|
|
|
RecommendType: constants.ConfigRecommendHierarchyType,
|
|
|
|
|
QueryDatas: append([]string{}, groupResults...),
|
|
|
|
|
IsFuzzy: true,
|
|
|
|
|
IsFallback: true,
|
|
|
|
|
Offset: offset,
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
emptyGot := normalizeRecommendResults(prefix+".", emptyInputResults)
|
|
|
|
|
mismatchGot := normalizeRecommendResults(prefix+".x", mismatchFallbackResults)
|
|
|
|
|
emptyResult := emptyGot[constants.ConfigRecommendHierarchyType.String()]
|
|
|
|
|
mismatchResult := mismatchGot[constants.ConfigRecommendHierarchyType.String()]
|
|
|
|
|
|
|
|
|
|
if mismatchResult.Offset != emptyResult.Offset {
|
|
|
|
|
t.Fatalf("expected config mismatch fallback offset %d, got %d", emptyResult.Offset, mismatchResult.Offset)
|
|
|
|
|
}
|
|
|
|
|
if !reflect.DeepEqual(mismatchResult.QueryDatas, emptyResult.QueryDatas) {
|
|
|
|
|
t.Fatalf("expected config mismatch fallback recommends to match empty input, empty=%#v mismatch=%#v", emptyResult.QueryDatas, mismatchResult.QueryDatas)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestNormalizeRecommendResultsKeepsMeasurementMismatchFallbackConsistentWithEmptyInput(t *testing.T) {
|
|
|
|
|
prefix := "grid000.zone000.station000.110kV_TV-demoProject.cable_22-testProject1110kV_TV.bay"
|
|
|
|
|
members := []string{"IA_rms_CTA-testProject1", "IB_rms_CTA-testProject1", "IC_rms_CTA-testProject1"}
|
|
|
|
|
groupResults := combineQueryResultByInput(constants.MeasTagRecommendHierarchyType, constants.FullRecommendLength, strings.Split(prefix+".", "."), members)
|
|
|
|
|
offset := recommendPrefixOffset(strings.Split(prefix, "."))
|
|
|
|
|
|
|
|
|
|
emptyInputResults := map[string]SearchResult{
|
|
|
|
|
constants.MeasTagRecommendHierarchyType.String(): {
|
|
|
|
|
RecommendType: constants.MeasTagRecommendHierarchyType,
|
|
|
|
|
QueryDatas: append([]string{}, groupResults...),
|
|
|
|
|
IsFuzzy: false,
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
mismatchFallbackResults := map[string]SearchResult{
|
|
|
|
|
constants.MeasTagRecommendHierarchyType.String(): {
|
|
|
|
|
RecommendType: constants.MeasTagRecommendHierarchyType,
|
|
|
|
|
QueryDatas: append([]string{}, groupResults...),
|
|
|
|
|
IsFuzzy: true,
|
|
|
|
|
IsFallback: true,
|
|
|
|
|
Offset: offset,
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
emptyGot := normalizeRecommendResults(prefix+".", emptyInputResults)
|
|
|
|
|
mismatchGot := normalizeRecommendResults(prefix+".x", mismatchFallbackResults)
|
|
|
|
|
emptyResult := emptyGot[constants.MeasTagRecommendHierarchyType.String()]
|
|
|
|
|
mismatchResult := mismatchGot[constants.MeasTagRecommendHierarchyType.String()]
|
|
|
|
|
|
|
|
|
|
if mismatchResult.Offset != emptyResult.Offset {
|
|
|
|
|
t.Fatalf("expected measurement mismatch fallback offset %d, got %d", emptyResult.Offset, mismatchResult.Offset)
|
|
|
|
|
}
|
|
|
|
|
if !reflect.DeepEqual(mismatchResult.QueryDatas, emptyResult.QueryDatas) {
|
|
|
|
|
t.Fatalf("expected measurement mismatch fallback recommends to match empty input, empty=%#v mismatch=%#v", emptyResult.QueryDatas, mismatchResult.QueryDatas)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-09 16:31:19 +08:00
|
|
|
func TestRecommendGroupTokens(t *testing.T) {
|
|
|
|
|
tests := []struct {
|
|
|
|
|
name string
|
|
|
|
|
inputSlice []string
|
|
|
|
|
wantCompTag string
|
|
|
|
|
wantConfig string
|
|
|
|
|
wantOK bool
|
|
|
|
|
}{
|
|
|
|
|
{
|
|
|
|
|
name: "full token1 to token7 input",
|
|
|
|
|
inputSlice: []string{"grid000", "zone000", "station000", "nspath", "comp_tag", "base_extend", ""},
|
|
|
|
|
wantCompTag: "comp_tag",
|
|
|
|
|
wantConfig: "base_extend",
|
|
|
|
|
wantOK: true,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "local token4 to token7 input",
|
|
|
|
|
inputSlice: []string{"nspath", "comp_tag", "component", ""},
|
|
|
|
|
wantCompTag: "comp_tag",
|
|
|
|
|
wantConfig: "component",
|
|
|
|
|
wantOK: true,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "missing config token",
|
|
|
|
|
inputSlice: []string{"nspath", ""},
|
|
|
|
|
wantOK: false,
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for _, tt := range tests {
|
|
|
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
|
|
|
gotCompTag, gotConfig, gotOK := recommendGroupTokens(tt.inputSlice)
|
|
|
|
|
if gotOK != tt.wantOK {
|
|
|
|
|
t.Fatalf("expected ok %t, got %t", tt.wantOK, gotOK)
|
|
|
|
|
}
|
|
|
|
|
if gotCompTag != tt.wantCompTag || gotConfig != tt.wantConfig {
|
|
|
|
|
t.Fatalf("expected compTag/config %q/%q, got %q/%q", tt.wantCompTag, tt.wantConfig, gotCompTag, gotConfig)
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-10 11:02:56 +08:00
|
|
|
func TestConfigRecommendCompTag(t *testing.T) {
|
|
|
|
|
tests := []struct {
|
|
|
|
|
name string
|
|
|
|
|
inputSlice []string
|
|
|
|
|
want string
|
|
|
|
|
wantOK bool
|
|
|
|
|
}{
|
|
|
|
|
{
|
|
|
|
|
name: "full token1 to token6 input",
|
|
|
|
|
inputSlice: []string{"grid000", "zone000", "station000", "nspath", "comp_tag", "b"},
|
|
|
|
|
want: "comp_tag",
|
|
|
|
|
wantOK: true,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "local token4 to token6 input",
|
|
|
|
|
inputSlice: []string{"nspath", "comp_tag", "b"},
|
|
|
|
|
want: "comp_tag",
|
|
|
|
|
wantOK: true,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "missing comp tag",
|
|
|
|
|
inputSlice: []string{"nspath"},
|
|
|
|
|
wantOK: false,
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for _, tt := range tests {
|
|
|
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
|
|
|
got, gotOK := configRecommendCompTag(tt.inputSlice)
|
|
|
|
|
if gotOK != tt.wantOK {
|
|
|
|
|
t.Fatalf("expected ok %t, got %t", tt.wantOK, gotOK)
|
|
|
|
|
}
|
|
|
|
|
if got != tt.want {
|
|
|
|
|
t.Fatalf("expected compTag %q, got %q", tt.want, got)
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestFilterMembersByTrimmedPrefix(t *testing.T) {
|
|
|
|
|
tests := []struct {
|
|
|
|
|
name string
|
|
|
|
|
members []string
|
|
|
|
|
searchInput string
|
|
|
|
|
wantMembers []string
|
|
|
|
|
wantMatchInput string
|
|
|
|
|
}{
|
|
|
|
|
{
|
|
|
|
|
name: "config typo falls back to previous rune",
|
|
|
|
|
members: []string{"bay", "base_extend", "model", "rated", "stable", "component"},
|
|
|
|
|
searchInput: "bx",
|
|
|
|
|
wantMembers: []string{"bay", "base_extend"},
|
|
|
|
|
wantMatchInput: "b",
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "measurement typo falls back to previous rune",
|
|
|
|
|
members: []string{"I_A_rms", "I_B_rms", "U_A_rms"},
|
|
|
|
|
searchInput: "Ix",
|
|
|
|
|
wantMembers: []string{"I_A_rms", "I_B_rms"},
|
|
|
|
|
wantMatchInput: "I",
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "no fallback to empty prefix",
|
|
|
|
|
members: []string{"bay", "base_extend"},
|
|
|
|
|
searchInput: "x",
|
|
|
|
|
wantMembers: []string{},
|
|
|
|
|
wantMatchInput: "",
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for _, tt := range tests {
|
|
|
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
|
|
|
gotMembers, gotMatchInput := filterMembersByTrimmedPrefix(tt.members, tt.searchInput)
|
|
|
|
|
if !reflect.DeepEqual(gotMembers, tt.wantMembers) {
|
|
|
|
|
t.Fatalf("expected members %#v, got %#v", tt.wantMembers, gotMembers)
|
|
|
|
|
}
|
|
|
|
|
if gotMatchInput != tt.wantMatchInput {
|
|
|
|
|
t.Fatalf("expected matched input %q, got %q", tt.wantMatchInput, gotMatchInput)
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestDotAndTypoInputsShareTrimmedPrefixFallback(t *testing.T) {
|
|
|
|
|
tests := []struct {
|
|
|
|
|
name string
|
|
|
|
|
dotInput string
|
|
|
|
|
typoInput string
|
|
|
|
|
members []string
|
|
|
|
|
wantSuffix []string
|
|
|
|
|
}{
|
|
|
|
|
{
|
|
|
|
|
name: "token1 grid",
|
|
|
|
|
dotInput: "g.",
|
|
|
|
|
typoInput: "gx",
|
|
|
|
|
members: []string{"grid000", "grid001", "zone000"},
|
|
|
|
|
wantSuffix: []string{"grid000", "grid001"},
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "token2 zone",
|
|
|
|
|
dotInput: "z.",
|
|
|
|
|
typoInput: "zx",
|
|
|
|
|
members: []string{"zone000", "zone001", "station000"},
|
|
|
|
|
wantSuffix: []string{"zone000", "zone001"},
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "token3 station",
|
|
|
|
|
dotInput: "s.",
|
|
|
|
|
typoInput: "sx",
|
|
|
|
|
members: []string{"station000", "station001", "zone000"},
|
|
|
|
|
wantSuffix: []string{"station000", "station001"},
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "token4 nspath",
|
|
|
|
|
dotInput: "1.",
|
|
|
|
|
typoInput: "1x",
|
|
|
|
|
members: []string{"110kV_TV-demoProject", "110kV_TV-testProject1", "220kV_TV-demoProject"},
|
|
|
|
|
wantSuffix: []string{"110kV_TV-demoProject", "110kV_TV-testProject1"},
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "token5 component tag",
|
|
|
|
|
dotInput: "c.",
|
|
|
|
|
typoInput: "cx",
|
|
|
|
|
members: []string{"cable_22-testProject1110kV_TV", "cable_26-demoProject110kV_TV", "bay"},
|
|
|
|
|
wantSuffix: []string{"cable_22-testProject1110kV_TV", "cable_26-demoProject110kV_TV"},
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "token6 config",
|
|
|
|
|
dotInput: "b.",
|
|
|
|
|
typoInput: "bx",
|
|
|
|
|
members: []string{"bay", "base_extend", "component"},
|
|
|
|
|
wantSuffix: []string{"bay", "base_extend"},
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "token7 measurement",
|
|
|
|
|
dotInput: "I.",
|
|
|
|
|
typoInput: "Ix",
|
|
|
|
|
members: []string{"IA_rms", "IB_rms", "UA_rms"},
|
|
|
|
|
wantSuffix: []string{"IA_rms", "IB_rms"},
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for _, tt := range tests {
|
|
|
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
|
|
|
dotSearchInput := strings.TrimSuffix(tt.dotInput, ".")
|
|
|
|
|
typoSearchInput := trimLastRune(tt.typoInput)
|
|
|
|
|
dotMembers, dotMatchedInput := filterMembersByTrimmedPrefix(tt.members, dotSearchInput)
|
|
|
|
|
typoMembers, typoMatchedInput := filterMembersByTrimmedPrefix(tt.members, typoSearchInput)
|
|
|
|
|
|
|
|
|
|
if dotMatchedInput != typoMatchedInput {
|
|
|
|
|
t.Fatalf("expected dot and typo matched input to be equal, dot=%q typo=%q", dotMatchedInput, typoMatchedInput)
|
|
|
|
|
}
|
|
|
|
|
if !reflect.DeepEqual(dotMembers, typoMembers) {
|
|
|
|
|
t.Fatalf("expected dot and typo members to be equal, dot=%#v typo=%#v", dotMembers, typoMembers)
|
|
|
|
|
}
|
|
|
|
|
if !reflect.DeepEqual(dotMembers, tt.wantSuffix) {
|
|
|
|
|
t.Fatalf("expected members %#v, got %#v", tt.wantSuffix, dotMembers)
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestExactMatchChecksForInput(t *testing.T) {
|
|
|
|
|
tests := []struct {
|
|
|
|
|
name string
|
|
|
|
|
inputSlice []string
|
|
|
|
|
want []exactMatchCheck
|
|
|
|
|
}{
|
|
|
|
|
{
|
|
|
|
|
name: "token1 can be grid or local nspath",
|
|
|
|
|
inputSlice: []string{"g"},
|
|
|
|
|
want: []exactMatchCheck{
|
|
|
|
|
{setKey: constants.RedisAllGridSetKey, member: "g"},
|
|
|
|
|
{setKey: constants.RedisAllCompNSPathSetKey, member: "g"},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "token1 token2 can be zone comp tag or nspath meas",
|
|
|
|
|
inputSlice: []string{"grid000", "z"},
|
|
|
|
|
want: []exactMatchCheck{
|
|
|
|
|
{setKey: fmt.Sprintf(constants.RedisSpecGridZoneSetKey, "grid000"), member: "z"},
|
|
|
|
|
{setKey: fmt.Sprintf(constants.RedisSpecCompNSPathCompTagSetKey, "grid000"), member: "z"},
|
|
|
|
|
{setKey: constants.RedisAllCompTagSetKey, member: "z"},
|
|
|
|
|
{setKey: fmt.Sprintf(constants.RedisSpecCompNSPathMeasSetKey, "grid000"), member: "z"},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "token1 token2 token3 can be station or local config",
|
|
|
|
|
inputSlice: []string{"grid000", "zone000", "s"},
|
|
|
|
|
want: []exactMatchCheck{
|
|
|
|
|
{setKey: fmt.Sprintf(constants.RedisSpecZoneStationSetKey, "zone000"), member: "s"},
|
|
|
|
|
{setKey: constants.RedisAllConfigSetKey, member: "s"},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "token1 token2 token3 token4 can be nspath or local meas",
|
|
|
|
|
inputSlice: []string{"grid000", "zone000", "station000", "1"},
|
|
|
|
|
want: []exactMatchCheck{
|
|
|
|
|
{setKey: fmt.Sprintf(constants.RedisSpecStationCompNSPATHSetKey, "station000"), member: "1"},
|
|
|
|
|
{setKey: fmt.Sprintf(constants.RedisSpecCompTagMeasSetKey, "zone000"), member: "1"},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "token1 through token5 component tag",
|
|
|
|
|
inputSlice: []string{"grid000", "zone000", "station000", "nspath", "c"},
|
|
|
|
|
want: []exactMatchCheck{
|
|
|
|
|
{setKey: fmt.Sprintf(constants.RedisSpecCompNSPathCompTagSetKey, "nspath"), member: "c"},
|
|
|
|
|
{setKey: constants.RedisAllCompTagSetKey, member: "c"},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "token1 through token6 config",
|
|
|
|
|
inputSlice: []string{"grid000", "zone000", "station000", "nspath", "comp_tag", "b"},
|
|
|
|
|
want: []exactMatchCheck{
|
|
|
|
|
{setKey: constants.RedisAllConfigSetKey, member: "b"},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "token1 through token7 measurement",
|
|
|
|
|
inputSlice: []string{"grid000", "zone000", "station000", "nspath", "comp_tag", "bay", "I"},
|
|
|
|
|
want: []exactMatchCheck{
|
|
|
|
|
{setKey: fmt.Sprintf(constants.RedisSpecCompTagMeasSetKey, "comp_tag"), member: "I"},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for _, tt := range tests {
|
|
|
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
|
|
|
got := exactMatchChecksForInput(tt.inputSlice)
|
|
|
|
|
if !reflect.DeepEqual(got, tt.want) {
|
|
|
|
|
t.Fatalf("expected checks %#v, got %#v", tt.want, got)
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-08 10:37:06 +08:00
|
|
|
func TestFallbackSpecificSetKey(t *testing.T) {
|
|
|
|
|
tests := []struct {
|
|
|
|
|
name string
|
|
|
|
|
hierarchy constants.RecommendHierarchyType
|
|
|
|
|
inputSlice []string
|
|
|
|
|
want string
|
|
|
|
|
wantOK bool
|
|
|
|
|
}{
|
|
|
|
|
{
|
|
|
|
|
name: "zone fallback uses grid specific set",
|
|
|
|
|
hierarchy: constants.ZoneRecommendHierarchyType,
|
|
|
|
|
inputSlice: []string{"grid000", "z"},
|
|
|
|
|
want: fmt.Sprintf(constants.RedisSpecGridZoneSetKey, "grid000"),
|
|
|
|
|
wantOK: true,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "component tag fallback uses previous nspath token",
|
|
|
|
|
hierarchy: constants.CompTagRecommendHierarchyType,
|
|
|
|
|
inputSlice: []string{"grid000", "I"},
|
|
|
|
|
want: fmt.Sprintf(constants.RedisSpecCompNSPathCompTagSetKey, "grid000"),
|
|
|
|
|
wantOK: true,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "measurement fallback skips config token and uses component tag",
|
|
|
|
|
hierarchy: constants.MeasTagRecommendHierarchyType,
|
|
|
|
|
inputSlice: []string{"nspath", "comp_tag", "config", "m"},
|
|
|
|
|
want: fmt.Sprintf(constants.RedisSpecCompTagMeasSetKey, "comp_tag"),
|
|
|
|
|
wantOK: true,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "config fallback has no parent specific set",
|
|
|
|
|
hierarchy: constants.ConfigRecommendHierarchyType,
|
|
|
|
|
inputSlice: []string{"nspath", "comp_tag", ""},
|
|
|
|
|
wantOK: false,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "missing previous token",
|
|
|
|
|
hierarchy: constants.ZoneRecommendHierarchyType,
|
|
|
|
|
inputSlice: []string{"z"},
|
|
|
|
|
wantOK: false,
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for _, tt := range tests {
|
|
|
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
|
|
|
got, ok := fallbackSpecificSetKey(tt.hierarchy, tt.inputSlice)
|
|
|
|
|
if ok != tt.wantOK {
|
|
|
|
|
t.Fatalf("expected ok %t, got %t", tt.wantOK, ok)
|
|
|
|
|
}
|
|
|
|
|
if got != tt.want {
|
|
|
|
|
t.Fatalf("expected key %q, got %q", tt.want, got)
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-07-08 17:19:07 +08:00
|
|
|
|
|
|
|
|
func TestShouldFallbackToInitialRecommend(t *testing.T) {
|
|
|
|
|
tests := []struct {
|
|
|
|
|
input string
|
|
|
|
|
want bool
|
|
|
|
|
}{
|
|
|
|
|
{input: "", want: false},
|
|
|
|
|
{input: ".", want: true},
|
|
|
|
|
{input: ".x", want: true},
|
|
|
|
|
{input: "..x", want: true},
|
|
|
|
|
{input: "...x", want: true},
|
|
|
|
|
{input: "grid000", want: false},
|
|
|
|
|
{input: "grid000.", want: false},
|
|
|
|
|
{input: "grid000.zone000", want: false},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for _, tt := range tests {
|
|
|
|
|
t.Run(tt.input, func(t *testing.T) {
|
|
|
|
|
got := shouldFallbackToInitialRecommend(tt.input)
|
|
|
|
|
if got != tt.want {
|
|
|
|
|
t.Fatalf("expected %t, got %t", tt.want, got)
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|