94 lines
3.1 KiB
Go
94 lines
3.1 KiB
Go
package businessscope
|
|
|
|
import (
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func validCandidate(row int, vehicleID, customerID int64, vin string) Candidate {
|
|
return Candidate{
|
|
RowNumber: row, VehicleID: vehicleID, VehiclePresent: true, VIN: vin, PlateNumber: "沪A00001",
|
|
CustomerID: customerID, CustomerPresent: true, CustomerProfileExists: true,
|
|
ContractID: vehicleID + 1000, ContractPresent: true, ContractProfileExists: true,
|
|
EffectiveCustomerID: customerID, EffectiveCustomerSet: true,
|
|
ContractCode: "HT-1", ProjectName: "项目", OperationStatus: "1",
|
|
ScopeStartAt: time.Date(2026, 7, 1, 8, 0, 0, 0, time.FixedZone("CST", 8*3600)),
|
|
}
|
|
}
|
|
|
|
func TestBuildSnapshotClassifiesAndNormalizes(t *testing.T) {
|
|
candidates := []Candidate{
|
|
validCandidate(1, 10, 100, " lvin0001 "),
|
|
func() Candidate {
|
|
value := validCandidate(2, 11, 101, "LVIN0002")
|
|
value.CustomerProfileExists = false
|
|
return value
|
|
}(),
|
|
func() Candidate {
|
|
value := validCandidate(3, 12, 102, "LVIN0003")
|
|
value.EffectiveCustomerID = 999
|
|
return value
|
|
}(),
|
|
}
|
|
snapshot, err := BuildSnapshot(candidates, time.Now())
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if snapshot.Candidates != 3 || len(snapshot.Items) != 1 || len(snapshot.Rejections) != 2 {
|
|
t.Fatalf("unexpected accounting: %#v", snapshot)
|
|
}
|
|
if snapshot.Items[0].VIN != "LVIN0001" {
|
|
t.Fatalf("VIN not normalized: %q", snapshot.Items[0].VIN)
|
|
}
|
|
if snapshot.Rejections[0].ReasonCode != ReasonCustomerProfileMissing || snapshot.Rejections[1].ReasonCode != ReasonCustomerMismatch {
|
|
t.Fatalf("unexpected reasons: %#v", snapshot.Rejections)
|
|
}
|
|
}
|
|
|
|
func TestBuildSnapshotRejectsEveryDuplicateVehicle(t *testing.T) {
|
|
snapshot, err := BuildSnapshot([]Candidate{
|
|
validCandidate(1, 10, 100, "LVIN0001"),
|
|
validCandidate(2, 10, 100, "LVIN0001"),
|
|
}, time.Now())
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(snapshot.Items) != 0 || len(snapshot.Rejections) != 2 {
|
|
t.Fatalf("duplicates must all be quarantined: %#v", snapshot)
|
|
}
|
|
for _, rejection := range snapshot.Rejections {
|
|
if rejection.ReasonCode != ReasonDuplicateVehicle {
|
|
t.Fatalf("unexpected duplicate reason: %#v", rejection)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestSnapshotVersionIsContentAddressed(t *testing.T) {
|
|
first := []Candidate{validCandidate(1, 10, 100, "LVIN0001"), validCandidate(2, 11, 101, "LVIN0002")}
|
|
second := []Candidate{first[1], first[0]}
|
|
a, err := BuildSnapshot(first, time.Now())
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
b, err := BuildSnapshot(second, time.Now().Add(time.Hour))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if a.SourceVersion != b.SourceVersion || a.Checksum != b.Checksum {
|
|
t.Fatalf("same content produced different versions: %s %s", a.SourceVersion, b.SourceVersion)
|
|
}
|
|
}
|
|
|
|
func TestValidateSnapshotUsesCountAndRatioGates(t *testing.T) {
|
|
snapshot := Snapshot{Candidates: 639, Items: make([]ScopeItem, 613), Rejections: make([]Rejection, 26)}
|
|
if err := ValidateSnapshot(snapshot, 100, 0.10); err != nil {
|
|
t.Fatalf("production baseline should pass: %v", err)
|
|
}
|
|
if err := ValidateSnapshot(snapshot, 20, 0.10); err == nil {
|
|
t.Fatal("rejection count limit should fail")
|
|
}
|
|
if err := ValidateSnapshot(snapshot, 100, 0.01); err == nil {
|
|
t.Fatal("rejection ratio limit should fail")
|
|
}
|
|
}
|