Added only/never repeated string fields to ManifestEntry proto. Updated convert.go for round-trip. Targeting test in convert_test.go. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
165 lines
4.4 KiB
Go
165 lines
4.4 KiB
Go
package server
|
|
|
|
import (
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/kisom/sgard/manifest"
|
|
)
|
|
|
|
func TestManifestRoundTrip(t *testing.T) {
|
|
now := time.Date(2026, 1, 1, 12, 0, 0, 0, time.UTC)
|
|
m := &manifest.Manifest{
|
|
Version: 1,
|
|
Created: now,
|
|
Updated: now,
|
|
Message: "test checkpoint",
|
|
Files: []manifest.Entry{
|
|
{Path: "~/.bashrc", Hash: "abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234", Type: "file", Mode: "0644", Updated: now},
|
|
{Path: "~/.config/nvim", Type: "directory", Mode: "0755", Updated: now},
|
|
{Path: "~/.vimrc", Type: "link", Target: "~/.config/nvim/init.vim", Updated: now},
|
|
},
|
|
}
|
|
|
|
proto := ManifestToProto(m)
|
|
back := ProtoToManifest(proto)
|
|
|
|
if back.Version != m.Version {
|
|
t.Errorf("Version: got %d, want %d", back.Version, m.Version)
|
|
}
|
|
if !back.Created.Equal(m.Created) {
|
|
t.Errorf("Created: got %v, want %v", back.Created, m.Created)
|
|
}
|
|
if !back.Updated.Equal(m.Updated) {
|
|
t.Errorf("Updated: got %v, want %v", back.Updated, m.Updated)
|
|
}
|
|
if back.Message != m.Message {
|
|
t.Errorf("Message: got %q, want %q", back.Message, m.Message)
|
|
}
|
|
if len(back.Files) != len(m.Files) {
|
|
t.Fatalf("Files count: got %d, want %d", len(back.Files), len(m.Files))
|
|
}
|
|
for i, want := range m.Files {
|
|
got := back.Files[i]
|
|
if got.Path != want.Path {
|
|
t.Errorf("Files[%d].Path: got %q, want %q", i, got.Path, want.Path)
|
|
}
|
|
if got.Hash != want.Hash {
|
|
t.Errorf("Files[%d].Hash: got %q, want %q", i, got.Hash, want.Hash)
|
|
}
|
|
if got.Type != want.Type {
|
|
t.Errorf("Files[%d].Type: got %q, want %q", i, got.Type, want.Type)
|
|
}
|
|
if got.Mode != want.Mode {
|
|
t.Errorf("Files[%d].Mode: got %q, want %q", i, got.Mode, want.Mode)
|
|
}
|
|
if got.Target != want.Target {
|
|
t.Errorf("Files[%d].Target: got %q, want %q", i, got.Target, want.Target)
|
|
}
|
|
if !got.Updated.Equal(want.Updated) {
|
|
t.Errorf("Files[%d].Updated: got %v, want %v", i, got.Updated, want.Updated)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestEmptyManifestRoundTrip(t *testing.T) {
|
|
now := time.Date(2026, 6, 15, 8, 30, 0, 0, time.UTC)
|
|
m := &manifest.Manifest{
|
|
Version: 1,
|
|
Created: now,
|
|
Updated: now,
|
|
Files: []manifest.Entry{},
|
|
}
|
|
|
|
proto := ManifestToProto(m)
|
|
back := ProtoToManifest(proto)
|
|
|
|
if back.Version != m.Version {
|
|
t.Errorf("Version: got %d, want %d", back.Version, m.Version)
|
|
}
|
|
if !back.Created.Equal(m.Created) {
|
|
t.Errorf("Created: got %v, want %v", back.Created, m.Created)
|
|
}
|
|
if !back.Updated.Equal(m.Updated) {
|
|
t.Errorf("Updated: got %v, want %v", back.Updated, m.Updated)
|
|
}
|
|
if back.Message != "" {
|
|
t.Errorf("Message: got %q, want empty", back.Message)
|
|
}
|
|
if len(back.Files) != 0 {
|
|
t.Errorf("Files count: got %d, want 0", len(back.Files))
|
|
}
|
|
}
|
|
|
|
func TestTargetingRoundTrip(t *testing.T) {
|
|
now := time.Date(2026, 3, 24, 0, 0, 0, 0, time.UTC)
|
|
|
|
onlyEntry := manifest.Entry{
|
|
Path: "~/.bashrc.linux",
|
|
Type: "file",
|
|
Hash: "abcd",
|
|
Only: []string{"os:linux", "tag:work"},
|
|
Updated: now,
|
|
}
|
|
|
|
proto := EntryToProto(onlyEntry)
|
|
back := ProtoToEntry(proto)
|
|
|
|
if len(back.Only) != 2 || back.Only[0] != "os:linux" || back.Only[1] != "tag:work" {
|
|
t.Errorf("Only round-trip: got %v, want [os:linux tag:work]", back.Only)
|
|
}
|
|
if len(back.Never) != 0 {
|
|
t.Errorf("Never should be empty, got %v", back.Never)
|
|
}
|
|
|
|
neverEntry := manifest.Entry{
|
|
Path: "~/.config/heavy",
|
|
Type: "file",
|
|
Hash: "efgh",
|
|
Never: []string{"arch:arm64"},
|
|
Updated: now,
|
|
}
|
|
|
|
proto2 := EntryToProto(neverEntry)
|
|
back2 := ProtoToEntry(proto2)
|
|
|
|
if len(back2.Never) != 1 || back2.Never[0] != "arch:arm64" {
|
|
t.Errorf("Never round-trip: got %v, want [arch:arm64]", back2.Never)
|
|
}
|
|
if len(back2.Only) != 0 {
|
|
t.Errorf("Only should be empty, got %v", back2.Only)
|
|
}
|
|
}
|
|
|
|
func TestEntryEmptyOptionalFieldsRoundTrip(t *testing.T) {
|
|
now := time.Date(2026, 3, 1, 0, 0, 0, 0, time.UTC)
|
|
e := manifest.Entry{
|
|
Path: "~/.profile",
|
|
Type: "file",
|
|
Updated: now,
|
|
// Hash, Mode, Target intentionally empty
|
|
}
|
|
|
|
proto := EntryToProto(e)
|
|
back := ProtoToEntry(proto)
|
|
|
|
if back.Path != e.Path {
|
|
t.Errorf("Path: got %q, want %q", back.Path, e.Path)
|
|
}
|
|
if back.Hash != "" {
|
|
t.Errorf("Hash: got %q, want empty", back.Hash)
|
|
}
|
|
if back.Type != e.Type {
|
|
t.Errorf("Type: got %q, want %q", back.Type, e.Type)
|
|
}
|
|
if back.Mode != "" {
|
|
t.Errorf("Mode: got %q, want empty", back.Mode)
|
|
}
|
|
if back.Target != "" {
|
|
t.Errorf("Target: got %q, want empty", back.Target)
|
|
}
|
|
if !back.Updated.Equal(e.Updated) {
|
|
t.Errorf("Updated: got %v, want %v", back.Updated, e.Updated)
|
|
}
|
|
}
|