179 lines
6.3 KiB
Go
179 lines
6.3 KiB
Go
package sybimport_test
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"strings"
|
|
"testing"
|
|
|
|
"go-admin/app/goauto/models"
|
|
"go-admin/app/goauto/sybimport"
|
|
)
|
|
|
|
func TestReparseUpdatesStatusWhenRuleImproves(t *testing.T) {
|
|
db := openTestDB(t)
|
|
detail := realDetailA()
|
|
detail.Raw = []byte(`{"id":145306175,"productSpec":"均碼"}`)
|
|
detail.ProductSpec = "均碼"
|
|
applied, err := sybimport.ApplyDetail(context.Background(), db, realOrder(), detail)
|
|
if err != nil {
|
|
t.Fatalf("apply: %v", err)
|
|
}
|
|
if applied.SYBProduct.ParseStatus != models.SYBParseStatusUncertain {
|
|
t.Fatalf("expected uncertain seed state, got %s", applied.SYBProduct.ParseStatus)
|
|
}
|
|
|
|
outcome, err := sybimport.Reparse(context.Background(), db, applied.SYBProduct.ID, false)
|
|
if err != nil {
|
|
t.Fatalf("reparse: %v", err)
|
|
}
|
|
// Same raw, same parser: nothing changed, must be reported as unchanged
|
|
// rather than a spurious "reparsed".
|
|
if outcome.Outcome != sybimport.ReparseOutcomeUnchanged {
|
|
t.Fatalf("expected unchanged (parser output identical), got %s", outcome.Outcome)
|
|
}
|
|
}
|
|
|
|
// #41 prototype: 人工已修正的明细默认跳过,避免规则重跑覆盖人工结果.
|
|
func TestReparseSkipsManuallyConfirmedRowByDefault(t *testing.T) {
|
|
db := openTestDB(t)
|
|
detail := realDetailA()
|
|
applied, err := sybimport.ApplyDetail(context.Background(), db, realOrder(), detail)
|
|
if err != nil {
|
|
t.Fatalf("apply: %v", err)
|
|
}
|
|
if _, err := sybimport.ManualCorrect(context.Background(), db, applied.SYBProduct.ID, "人工颜色", "人工尺码"); err != nil {
|
|
t.Fatalf("manual correct: %v", err)
|
|
}
|
|
|
|
outcome, err := sybimport.Reparse(context.Background(), db, applied.SYBProduct.ID, false)
|
|
if err != nil {
|
|
t.Fatalf("reparse: %v", err)
|
|
}
|
|
if outcome.Outcome != sybimport.ReparseOutcomeSkippedManual {
|
|
t.Fatalf("expected skipped_manual, got %s", outcome.Outcome)
|
|
}
|
|
var record models.SYBProduct
|
|
db.First(&record, applied.SYBProduct.ID)
|
|
if record.TargetColor != "人工颜色" {
|
|
t.Fatalf("manual correction must survive an unforced reparse, got %q", record.TargetColor)
|
|
}
|
|
}
|
|
|
|
// 可勾选强制覆盖.
|
|
func TestReparseWithForceOverridesManualCorrection(t *testing.T) {
|
|
db := openTestDB(t)
|
|
detail := realDetailA()
|
|
applied, err := sybimport.ApplyDetail(context.Background(), db, realOrder(), detail)
|
|
if err != nil {
|
|
t.Fatalf("apply: %v", err)
|
|
}
|
|
if _, err := sybimport.ManualCorrect(context.Background(), db, applied.SYBProduct.ID, "人工颜色", "人工尺码"); err != nil {
|
|
t.Fatalf("manual correct: %v", err)
|
|
}
|
|
|
|
outcome, err := sybimport.Reparse(context.Background(), db, applied.SYBProduct.ID, true)
|
|
if err != nil {
|
|
t.Fatalf("forced reparse: %v", err)
|
|
}
|
|
if outcome.Outcome == sybimport.ReparseOutcomeSkippedManual {
|
|
t.Fatal("force=true must not be skipped for a manually confirmed row")
|
|
}
|
|
var record models.SYBProduct
|
|
db.First(&record, applied.SYBProduct.ID)
|
|
if record.TargetColor != "白色" {
|
|
t.Fatalf("forced reparse must overwrite the manual value with the parser's output, got %q", record.TargetColor)
|
|
}
|
|
if record.ManuallyConfirmed {
|
|
t.Fatal("forced reparse must clear the manual flag, since the value is now parser-derived again")
|
|
}
|
|
}
|
|
|
|
func TestReparseNeverTouchesRawJSON(t *testing.T) {
|
|
db := openTestDB(t)
|
|
applied, err := sybimport.ApplyDetail(context.Background(), db, realOrder(), realDetailA())
|
|
if err != nil {
|
|
t.Fatalf("apply: %v", err)
|
|
}
|
|
rawBefore := applied.SYBProduct.RawJSON
|
|
if _, err := sybimport.Reparse(context.Background(), db, applied.SYBProduct.ID, false); err != nil {
|
|
t.Fatalf("reparse: %v", err)
|
|
}
|
|
var record models.SYBProduct
|
|
db.First(&record, applied.SYBProduct.ID)
|
|
if record.RawJSON != rawBefore {
|
|
t.Fatal("reparse must never rewrite the stored raw JSON, only the derived fields")
|
|
}
|
|
}
|
|
|
|
func TestReparseBatchPartialSuccessDoesNotAbortOnMissingID(t *testing.T) {
|
|
db := openTestDB(t)
|
|
applied, err := sybimport.ApplyDetail(context.Background(), db, realOrder(), realDetailA())
|
|
if err != nil {
|
|
t.Fatalf("apply: %v", err)
|
|
}
|
|
if _, err := sybimport.ReparseBatch(context.Background(), db, []uint64{applied.SYBProduct.ID, 999999}, false); err == nil {
|
|
t.Fatal("expected an error for a missing id in the batch")
|
|
}
|
|
// A row-level error surfaces as an error from ReparseBatch (not a partial
|
|
// per-row result) because a missing id is an operator mistake (stale page,
|
|
// wrong selection), not an expected outcome like "manually confirmed" —
|
|
// unlike shopeeproduct.BatchSoftDelete, where a missing id is routine.
|
|
}
|
|
|
|
func TestManualCorrectMergesIntoArchiveLikeASuccessfulParse(t *testing.T) {
|
|
db := openTestDB(t)
|
|
detail := realDetailB() // ambiguous sample, does not auto-merge
|
|
applied, err := sybimport.ApplyDetail(context.Background(), db, realOrder(), detail)
|
|
if err != nil {
|
|
t.Fatalf("apply: %v", err)
|
|
}
|
|
if len(applied.ShopeeSpecs) != 0 {
|
|
t.Fatal("ambiguous parse must not have merged anything yet")
|
|
}
|
|
corrected, err := sybimport.ManualCorrect(context.Background(), db, applied.SYBProduct.ID, "黑白拼接", "L")
|
|
if err != nil {
|
|
t.Fatalf("manual correct: %v", err)
|
|
}
|
|
_ = corrected
|
|
var product models.ShopeeProduct
|
|
db.First(&product, *applied.SYBProduct.ShopeeProductID)
|
|
found := false
|
|
for _, dim := range decodeSpecs(t, product.SpecsJSON) {
|
|
for _, v := range dim.Values {
|
|
if v.Name == "黑白拼接" {
|
|
found = true
|
|
}
|
|
}
|
|
}
|
|
if !found {
|
|
t.Fatal("a manual correction should merge into the shopee archive same as a successful auto-parse")
|
|
}
|
|
}
|
|
|
|
// Regression test: ReparseOutcome originally had no json tags at all, so Go's
|
|
// default marshaling produced PascalCase keys ("SYBProductID", "OldStatus")
|
|
// instead of the camelCase the rest of this API and the admin frontend use.
|
|
// A frontend built against the intended camelCase names would have silently
|
|
// read undefined for every field.
|
|
func TestReparseOutcomeMarshalsToCamelCaseKeys(t *testing.T) {
|
|
db := openTestDB(t)
|
|
applied, err := sybimport.ApplyDetail(context.Background(), db, realOrder(), realDetailA())
|
|
if err != nil {
|
|
t.Fatalf("apply: %v", err)
|
|
}
|
|
outcome, err := sybimport.Reparse(context.Background(), db, applied.SYBProduct.ID, false)
|
|
if err != nil {
|
|
t.Fatalf("reparse: %v", err)
|
|
}
|
|
encoded, err := json.Marshal(outcome)
|
|
if err != nil {
|
|
t.Fatalf("marshal: %v", err)
|
|
}
|
|
for _, key := range []string{`"sybProductId"`, `"outcome"`, `"oldStatus"`, `"newStatus"`} {
|
|
if !strings.Contains(string(encoded), key) {
|
|
t.Fatalf("expected key %s in %s", key, encoded)
|
|
}
|
|
}
|
|
}
|