package storage_test import ( "errors" "testing" "github.com/uopi/uopi/internal/storage" ) const sampleXML = `` func newStore(t *testing.T) *storage.Store { t.Helper() s, err := storage.New(t.TempDir()) if err != nil { t.Fatalf("New: %v", err) } return s } // -------------------------------------------------------------------------- // // List // // -------------------------------------------------------------------------- // func TestListEmpty(t *testing.T) { s := newStore(t) list, err := s.List() if err != nil { t.Fatalf("List: %v", err) } if len(list) != 0 { t.Errorf("expected empty list, got %d items", len(list)) } } func TestListAfterCreate(t *testing.T) { s := newStore(t) if _, err := s.Create([]byte(sampleXML)); err != nil { t.Fatalf("Create: %v", err) } list, err := s.List() if err != nil { t.Fatalf("List: %v", err) } if len(list) != 1 { t.Fatalf("expected 1 item, got %d", len(list)) } if list[0].Name != "Test Interface" { t.Errorf("Name = %q, want %q", list[0].Name, "Test Interface") } if list[0].Version != 1 { t.Errorf("Version = %d, want 1", list[0].Version) } } // -------------------------------------------------------------------------- // // Create + Get // // -------------------------------------------------------------------------- // func TestCreateAndGet(t *testing.T) { s := newStore(t) id, err := s.Create([]byte(sampleXML)) if err != nil { t.Fatalf("Create: %v", err) } if id == "" { t.Fatal("Create returned empty ID") } data, err := s.Get(id) if err != nil { t.Fatalf("Get(%q): %v", id, err) } if string(data) != sampleXML { t.Errorf("Get returned %q, want %q", data, sampleXML) } } func TestCreateUsesEmbeddedID(t *testing.T) { s := newStore(t) id, err := s.Create([]byte(sampleXML)) if err != nil { t.Fatalf("Create: %v", err) } // ID derived from xml id attr or name slug. if id == "" { t.Error("ID should not be empty") } } func TestCreateDuplicateGetsUniqueID(t *testing.T) { s := newStore(t) id1, err := s.Create([]byte(sampleXML)) if err != nil { t.Fatalf("first Create: %v", err) } id2, err := s.Create([]byte(sampleXML)) if err != nil { t.Fatalf("second Create: %v", err) } if id1 == id2 { t.Errorf("duplicate Create returned same ID %q", id1) } } func TestCreateInvalidXML(t *testing.T) { s := newStore(t) _, err := s.Create([]byte("not xml")) if err == nil { t.Error("expected error for invalid XML") } } // -------------------------------------------------------------------------- // // Get errors // // -------------------------------------------------------------------------- // func TestGetNotFound(t *testing.T) { s := newStore(t) _, err := s.Get("does-not-exist") if !errors.Is(err, storage.ErrNotFound) { t.Errorf("Get missing: want ErrNotFound, got %v", err) } } func TestGetInvalidID(t *testing.T) { s := newStore(t) _, err := s.Get("../traversal") if !errors.Is(err, storage.ErrNotFound) { t.Errorf("Get path-traversal ID: want ErrNotFound, got %v", err) } } func TestGetEmptyID(t *testing.T) { s := newStore(t) _, err := s.Get("") if !errors.Is(err, storage.ErrNotFound) { t.Errorf("Get empty ID: want ErrNotFound, got %v", err) } } // -------------------------------------------------------------------------- // // Update // // -------------------------------------------------------------------------- // func TestUpdate(t *testing.T) { s := newStore(t) id, err := s.Create([]byte(sampleXML)) if err != nil { t.Fatalf("Create: %v", err) } updated := `` if err := s.Update(id, []byte(updated)); err != nil { t.Fatalf("Update: %v", err) } data, err := s.Get(id) if err != nil { t.Fatalf("Get after update: %v", err) } if string(data) != updated { t.Errorf("post-update content mismatch") } } func TestUpdateNotFound(t *testing.T) { s := newStore(t) err := s.Update("no-such-id", []byte(sampleXML)) if !errors.Is(err, storage.ErrNotFound) { t.Errorf("Update missing: want ErrNotFound, got %v", err) } } // -------------------------------------------------------------------------- // // Delete // // -------------------------------------------------------------------------- // func TestDelete(t *testing.T) { s := newStore(t) id, err := s.Create([]byte(sampleXML)) if err != nil { t.Fatalf("Create: %v", err) } if err := s.Delete(id); err != nil { t.Fatalf("Delete: %v", err) } _, err = s.Get(id) if !errors.Is(err, storage.ErrNotFound) { t.Errorf("Get after delete: want ErrNotFound, got %v", err) } } func TestDeleteNotFound(t *testing.T) { s := newStore(t) err := s.Delete("ghost") if !errors.Is(err, storage.ErrNotFound) { t.Errorf("Delete missing: want ErrNotFound, got %v", err) } } // -------------------------------------------------------------------------- // // Clone // // -------------------------------------------------------------------------- // func TestClone(t *testing.T) { s := newStore(t) id, err := s.Create([]byte(sampleXML)) if err != nil { t.Fatalf("Create: %v", err) } newID, err := s.Clone(id) if err != nil { t.Fatalf("Clone: %v", err) } if newID == id { t.Error("Clone should produce a different ID") } orig, _ := s.Get(id) copy, _ := s.Get(newID) if string(orig) != string(copy) { t.Error("Clone content should match original") } } func TestCloneNotFound(t *testing.T) { s := newStore(t) _, err := s.Clone("ghost") if !errors.Is(err, storage.ErrNotFound) { t.Errorf("Clone missing: want ErrNotFound, got %v", err) } }