package fridge import ( "bytes" "context" "io" "strings" "testing" "time" "code.t-juice.club/torjus/oubliette/internal/shell" "code.t-juice.club/torjus/oubliette/internal/storage" ) type rwCloser struct { io.Reader io.Writer } func (r *rwCloser) Close() error { return nil } func runShell(t *testing.T, commands string) string { t.Helper() store := storage.NewMemoryStore() sessID, _ := store.CreateSession(context.Background(), "127.0.0.1", "root", "fridge", "") sess := &shell.SessionContext{ SessionID: sessID, Username: "root", Store: store, CommonConfig: shell.ShellCommonConfig{ Hostname: "testhost", }, } rw := &rwCloser{ Reader: bytes.NewBufferString(commands), Writer: &bytes.Buffer{}, } sh := NewFridgeShell() ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() if err := sh.Handle(ctx, sess, rw); err != nil { t.Fatalf("Handle: %v", err) } return rw.Writer.(*bytes.Buffer).String() } func TestFridgeShellName(t *testing.T) { sh := NewFridgeShell() if sh.Name() != "fridge" { t.Errorf("Name() = %q, want %q", sh.Name(), "fridge") } if sh.Description() == "" { t.Error("Description() should not be empty") } } func TestBootBanner(t *testing.T) { output := runShell(t, "exit\r") if !strings.Contains(output, "FridgeOS-ARM") { t.Error("output should contain FridgeOS-ARM in banner") } if !strings.Contains(output, "Samsung Smart Fridge OS") { t.Error("output should contain Samsung Smart Fridge OS") } if !strings.Contains(output, "FridgeOS>") { t.Error("output should contain FridgeOS> prompt") } } func TestHelpCommand(t *testing.T) { output := runShell(t, "help\rexit\r") for _, keyword := range []string{"inventory", "temp", "status", "diagnostics", "alerts", "reboot", "exit"} { if !strings.Contains(output, keyword) { t.Errorf("help output should mention %q", keyword) } } } func TestInventoryList(t *testing.T) { output := runShell(t, "inventory\rexit\r") if !strings.Contains(output, "Fridge Inventory") { t.Error("should show inventory header") } if !strings.Contains(output, "Whole Milk") { t.Error("should list milk") } if !strings.Contains(output, "Eggs") { t.Error("should list eggs") } } func TestInventoryAdd(t *testing.T) { output := runShell(t, "inventory add Cheese\rinventory\rexit\r") if !strings.Contains(output, "Added 'Cheese'") { t.Error("should confirm adding cheese") } if !strings.Contains(output, "Cheese") { t.Error("inventory list should contain cheese") } } func TestInventoryRemove(t *testing.T) { output := runShell(t, "inventory remove milk\rinventory\rexit\r") if !strings.Contains(output, "Removed") { t.Error("should confirm removal") } } func TestTemperature(t *testing.T) { output := runShell(t, "temp\rexit\r") if !strings.Contains(output, "37") { t.Error("should show fridge temp 37°F") } if !strings.Contains(output, "Fridge") { t.Error("should label fridge zone") } if !strings.Contains(output, "Freezer") { t.Error("should label freezer zone") } } func TestTempSetValid(t *testing.T) { output := runShell(t, "temp set fridge 40\rtemp\rexit\r") if !strings.Contains(output, "set to 40") { t.Errorf("should confirm temp set, got: %s", output) } // Second temp call should show 40. if !strings.Contains(output, "40") { t.Error("temperature should now be 40") } } func TestTempSetOutOfRange(t *testing.T) { output := runShell(t, "temp set fridge 100\rexit\r") if !strings.Contains(output, "WARNING") { t.Error("should warn about out-of-range temp") } } func TestTempSetFreezerOutOfRange(t *testing.T) { output := runShell(t, "temp set freezer 50\rexit\r") if !strings.Contains(output, "WARNING") { t.Error("should warn about out-of-range freezer temp") } } func TestStatus(t *testing.T) { output := runShell(t, "status\rexit\r") for _, keyword := range []string{"Compressor", "WiFi", "Ice maker", "TikTok", "Spotify", "SmartHome"} { if !strings.Contains(output, keyword) { t.Errorf("status should contain %q", keyword) } } } func TestDiagnostics(t *testing.T) { output := runShell(t, "diagnostics\rexit\r") if !strings.Contains(output, "ALL SYSTEMS NOMINAL") { t.Error("diagnostics should end with ALL SYSTEMS NOMINAL") } } func TestAlerts(t *testing.T) { output := runShell(t, "alerts\rexit\r") if !strings.Contains(output, "Active Alerts") { t.Error("should show alerts header") } if !strings.Contains(output, "Firmware update") { t.Error("should mention firmware update") } } func TestReboot(t *testing.T) { output := runShell(t, "reboot\r") if !strings.Contains(output, "rebooting") || !strings.Contains(output, "Rebooting") { t.Error("should show reboot message") } } func TestUnknownCommand(t *testing.T) { output := runShell(t, "foobar\rexit\r") if !strings.Contains(output, "unknown command") { t.Error("should show unknown command message") } } func TestExitCommand(t *testing.T) { output := runShell(t, "exit\r") if !strings.Contains(output, "Goodbye") { t.Error("exit should show goodbye message") } } func TestLogoutCommand(t *testing.T) { output := runShell(t, "logout\r") if !strings.Contains(output, "Goodbye") { t.Error("logout should show goodbye message") } } func TestSessionLogs(t *testing.T) { store := storage.NewMemoryStore() sessID, _ := store.CreateSession(context.Background(), "127.0.0.1", "root", "fridge", "") sess := &shell.SessionContext{ SessionID: sessID, Username: "root", Store: store, CommonConfig: shell.ShellCommonConfig{ Hostname: "testhost", }, } rw := &rwCloser{ Reader: bytes.NewBufferString("help\rexit\r"), Writer: &bytes.Buffer{}, } sh := NewFridgeShell() ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() sh.Handle(ctx, sess, rw) if len(store.SessionLogs) < 2 { t.Errorf("expected at least 2 session logs, got %d", len(store.SessionLogs)) } }