From dd8e3035df70ea3a31e1a7182cf7bfd08d3a0f67 Mon Sep 17 00:00:00 2001 From: "Thomas G. Lopes" Date: Wed, 4 Mar 2026 21:20:25 +0000 Subject: [PATCH] add tests for path and config functions --- config_test.go | 119 ++++++++++++++++++++++++++++++++++++ path_test.go | 163 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 282 insertions(+) create mode 100644 config_test.go create mode 100644 path_test.go diff --git a/config_test.go b/config_test.go new file mode 100644 index 0000000..c965c8c --- /dev/null +++ b/config_test.go @@ -0,0 +1,119 @@ +package main + +import ( + "regexp" + "testing" +) + +func TestGlobToRegexp(t *testing.T) { + tests := []struct { + pattern string + matches []string + noMatch []string + }{ + { + pattern: "*.txt", + matches: []string{"file.txt", "foo.txt"}, + noMatch: []string{"file.log", "dir/file.txt", "file.txt.bak"}, + }, + { + pattern: "**/*.txt", + matches: []string{"dir/file.txt", "a/b/c/file.txt"}, + noMatch: []string{"file.txt", "file.log", "file.txt.bak"}, + }, + { + pattern: "cache/**", + matches: []string{"cache/file", "cache/a/b/c"}, + noMatch: []string{"my-cache/file", "cache"}, + }, + { + pattern: "?.log", + matches: []string{"a.log", "1.log"}, + noMatch: []string{"file.log", ".log", "ab.log"}, + }, + { + pattern: "**/.DS_Store", + matches: []string{"foo/.DS_Store", "a/b/.DS_Store"}, + noMatch: []string{".DS_Store", ".DS_Store.bak", "foo/.DS_Store.txt"}, + }, + { + pattern: "./file.txt", + matches: []string{"file.txt"}, + noMatch: []string{"./file.txt"}, // leading ./ is stripped + }, + { + pattern: "/absolute", + matches: []string{"absolute"}, + noMatch: []string{"/absolute"}, // leading / is stripped + }, + } + + for _, tt := range tests { + t.Run(tt.pattern, func(t *testing.T) { + re, err := globToRegexp(tt.pattern) + if err != nil { + t.Fatalf("globToRegexp(%q) error: %v", tt.pattern, err) + } + + for _, m := range tt.matches { + if !re.MatchString(m) { + t.Errorf("pattern %q should match %q, but didn't", tt.pattern, m) + } + } + + for _, m := range tt.noMatch { + if re.MatchString(m) { + t.Errorf("pattern %q should NOT match %q, but did", tt.pattern, m) + } + } + }) + } +} + +func TestShouldIgnorePath(t *testing.T) { + cfg := &packageConfig{ + compiledIgnores: []*regexp.Regexp{}, + } + + // Test with nil config + if shouldIgnorePath("foo.txt", nil) { + t.Error("shouldIgnorePath with nil config should return false") + } + + // Test with empty ignores + if shouldIgnorePath("foo.txt", cfg) { + t.Error("shouldIgnorePath with empty ignores should return false") + } + + // Add some patterns and re-test + patterns := []string{"*.log", "cache/**", "**/.DS_Store"} + compiled, err := compileIgnorePatterns(patterns) + if err != nil { + t.Fatalf("compileIgnorePatterns error: %v", err) + } + cfg.compiledIgnores = compiled + + tests := []struct { + path string + ignored bool + }{ + {"debug.log", true}, + {"app.log", true}, + {"file.txt", false}, + {"cache/foo", true}, + {"cache/a/b", true}, + {"my-cache/foo", false}, + {".DS_Store", false}, // root-level .DS_Store not matched by **/.DS_Store + {"foo/.DS_Store", true}, + {"main.go", false}, + } + + for _, tt := range tests { + t.Run(tt.path, func(t *testing.T) { + got := shouldIgnorePath(tt.path, cfg) + if got != tt.ignored { + t.Errorf("shouldIgnorePath(%q) = %v, want %v", tt.path, got, tt.ignored) + } + }) + } +} diff --git a/path_test.go b/path_test.go new file mode 100644 index 0000000..ade3bbf --- /dev/null +++ b/path_test.go @@ -0,0 +1,163 @@ +package main + +import ( + "os" + "path/filepath" + "runtime" + "testing" +) + +func TestExpandHome(t *testing.T) { + home, err := os.UserHomeDir() + if err != nil { + t.Skipf("cannot get home dir: %v", err) + } + + tests := []struct { + input string + expected string + }{ + {"~", home}, + {"~/foo", filepath.Join(home, "foo")}, + {"~/foo/bar", filepath.Join(home, "foo", "bar")}, + {"/absolute/path", "/absolute/path"}, + {"relative/path", "relative/path"}, + {"", ""}, + } + + for _, tt := range tests { + t.Run(tt.input, func(t *testing.T) { + got := expandHome(tt.input) + if got != tt.expected { + t.Errorf("expandHome(%q) = %q, want %q", tt.input, got, tt.expected) + } + }) + } +} + +func TestCompressHome(t *testing.T) { + home, err := os.UserHomeDir() + if err != nil { + t.Skipf("cannot get home dir: %v", err) + } + + tests := []struct { + input string + expected string + }{ + {home, "~"}, + {filepath.Join(home, "foo"), "~/foo"}, + {filepath.Join(home, "foo", "bar"), "~/foo/bar"}, + {"/other/path", "/other/path"}, + {"relative/path", "relative/path"}, + } + + for _, tt := range tests { + t.Run(tt.input, func(t *testing.T) { + got := compressHome(tt.input) + if got != tt.expected { + t.Errorf("compressHome(%q) = %q, want %q", tt.input, got, tt.expected) + } + }) + } +} + +func TestSplitPackageSpec(t *testing.T) { + tests := []struct { + input string + wantPkg string + wantRel string + wantErr bool + }{ + {"pkg", "pkg", "", false}, + {"pkg:path", "pkg", "path", false}, + {"pkg:path/to/file", "pkg", "path/to/file", false}, + {"pkg:/leading", "pkg", "leading", false}, + {"/leading/pkg", "leading/pkg", "", false}, // leading slash trimmed + {"", "", "", true}, + {":nope", "", "", true}, + } + + for _, tt := range tests { + t.Run(tt.input, func(t *testing.T) { + pkg, rel, err := splitPackageSpec(tt.input) + if (err != nil) != tt.wantErr { + t.Errorf("splitPackageSpec(%q) error = %v, wantErr %v", tt.input, err, tt.wantErr) + return + } + if pkg != tt.wantPkg || rel != tt.wantRel { + t.Errorf("splitPackageSpec(%q) = (%q, %q), want (%q, %q)", tt.input, pkg, rel, tt.wantPkg, tt.wantRel) + } + }) + } +} + +func TestSelectTarget(t *testing.T) { + goos := runtime.GOOS + osKey := goos + if osKey == "darwin" { + osKey = "macos" + } + + tests := []struct { + name string + cfg *packageConfig + want string + wantErr bool + }{ + { + name: "matching os", + cfg: &packageConfig{ + targets: map[string]string{osKey: "/foo"}, + }, + want: filepath.Join("/foo"), + wantErr: false, + }, + { + name: "fallback to default", + cfg: &packageConfig{ + targets: map[string]string{"default": "/bar"}, + }, + want: filepath.Join("/bar"), + wantErr: false, + }, + { + name: "os overrides default", + cfg: &packageConfig{ + targets: map[string]string{osKey: "/os", "default": "/default"}, + }, + want: filepath.Join("/os"), + wantErr: false, + }, + { + name: "disabled target", + cfg: &packageConfig{ + targets: map[string]string{}, + disabled: map[string]bool{osKey: true}, + }, + want: "", + wantErr: true, + }, + { + name: "missing target", + cfg: &packageConfig{ + targets: map[string]string{"other": "/other"}, + }, + want: "", + wantErr: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := selectTarget(tt.cfg) + if (err != nil) != tt.wantErr { + t.Errorf("selectTarget() error = %v, wantErr %v", err, tt.wantErr) + return + } + if got != tt.want { + t.Errorf("selectTarget() = %q, want %q", got, tt.want) + } + }) + } +}