package backup import ( "strings" "testing" ) // R-351 — THE SCENARIO TABLE from the task, as a truth table. // // Each row states the WRONG outcome it exists to prevent, because a row whose expectation is only // "want X" tells the next reader nothing about why the value matters. // // The live values in these fixtures are the ones measured on demo-hp 2026-08-21, not invented ones: // // calibre-web (declares a data path) drive=/mnt/felhom-drives/hdd_1 // opengist (declares NONE, 40-of-53) drive=/mnt/sys_drive func TestCheckPlacement_ScenarioTable(t *testing.T) { const dataDrive = "/mnt/felhom-drives/hdd_1" const sysDrive = "/mnt/sys_drive" for _, tc := range []struct { name string man *RecoveryManifest liveDrive string wantKnown bool wantMismatch bool wrongOutcome string }{ { name: "A/D - recorded drive is where we are restoring", man: &RecoveryManifest{Drive: dataDrive, NamespaceRoot: dataDrive}, liveDrive: dataDrive, wantKnown: true, wantMismatch: false, wrongOutcome: "a new question or obstacle on the ordinary path", }, { name: "C - the destination differs from what the backup recorded", man: &RecoveryManifest{Drive: dataDrive, NamespaceRoot: dataDrive}, liveDrive: "/mnt/felhom-drives/hdd_2", wantKnown: true, wantMismatch: true, wrongOutcome: "silently accepted - a restore into the wrong place under a green message", }, { name: "E - the backup records no drive (older unit, missing field)", man: &RecoveryManifest{Drive: "", NamespaceRoot: ""}, liveDrive: dataDrive, wantKnown: false, wantMismatch: false, wrongOutcome: "an empty prefill presented as if it were the recorded value", }, { name: "E - the manifest could not be read at all", man: nil, liveDrive: dataDrive, wantKnown: false, wantMismatch: false, wrongOutcome: "a nil manifest treated as a match, or as a refusal that strands every old backup", }, { name: "no declared data path - the app has no field, but the record is still the truth", man: &RecoveryManifest{Drive: sysDrive, NamespaceRoot: sysDrive + "/felhom-data"}, liveDrive: sysDrive, wantKnown: true, wantMismatch: false, wrongOutcome: "falling into the unknown case just because the app has no storage field", }, { name: "no declared data path - and it moved to a real drive", man: &RecoveryManifest{Drive: sysDrive, NamespaceRoot: sysDrive + "/felhom-data"}, liveDrive: dataDrive, wantKnown: true, wantMismatch: true, wrongOutcome: "the 40-of-53 class silently exempted from the mismatch check", }, { name: "a trailing slash is the same destination", man: &RecoveryManifest{Drive: dataDrive + "/", NamespaceRoot: dataDrive}, liveDrive: dataDrive, wantKnown: true, wantMismatch: false, wrongOutcome: "a manufactured mismatch the customer has to dismiss for no reason", }, { name: "live destination unresolvable", man: &RecoveryManifest{Drive: dataDrive, NamespaceRoot: dataDrive}, liveDrive: "", wantKnown: true, wantMismatch: false, wrongOutcome: "comparing against nothing and calling it a difference; the not-installed refusal owns this case", }, } { t.Run(tc.name, func(t *testing.T) { c := CheckPlacement(tc.man, tc.liveDrive, tc.liveDrive) if c.Known != tc.wantKnown { t.Errorf("Known = %v, want %v — wrong outcome guarded: %s", c.Known, tc.wantKnown, tc.wrongOutcome) } if c.Mismatch != tc.wantMismatch { t.Errorf("Mismatch = %v, want %v — wrong outcome guarded: %s", c.Mismatch, tc.wantMismatch, tc.wrongOutcome) } }) } } // The refusal must NAME BOTH VALUES. "The destination differs" without saying from what leaves the // customer holding a decision they have no way to make — which is the same defect in a politer form. func TestPlacementMismatchMessage_NamesBothPlaces(t *testing.T) { c := CheckPlacement( &RecoveryManifest{Drive: "/mnt/felhom-drives/hdd_1"}, "/mnt/sys_drive", "/mnt/sys_drive/felhom-data") if !c.Mismatch { t.Fatal("fixture: these differ, or the message under test is never reached") } msg := PlacementMismatchMessage("opengist", c) for _, must := range []string{"opengist", "/mnt/felhom-drives/hdd_1", "/mnt/sys_drive"} { if !strings.Contains(msg, must) { t.Errorf("the refusal must name %q; got: %s", must, msg) } } } // An UNKNOWN recording must never be rendered as a value. Scenario E's wrong outcome is precisely an // empty string shown where a recorded path belongs, which reads as "the backup says it lived // nowhere" — a fabricated fact. func TestRecordedPlacement_UnknownIsNotAValue(t *testing.T) { for _, drive := range []string{"", " ", "\t"} { if (RecordedPlacement{Drive: drive}).Known() { t.Errorf("a blank drive (%q) must not count as a recorded value", drive) } } if !(RecordedPlacement{Drive: "/mnt/sys_drive"}).Known() { t.Error("a real recorded drive must count as known, or the whole check is inert") } }