package utils import ( "os" "path/filepath" "testing" "github.com/stretchr/testify/assert" ) func TestAggregateGlobsWithDuplicates(t *testing.T) { commands := []ModifyCommand{ {Files: []string{"*.txt", "*.md"}}, {Files: []string{"*.txt", "*.go"}}, // *.txt is duplicate {Files: []string{"test/**/*.xml"}}, } globs := AggregateGlobs(commands) // Should deduplicate assert.Equal(t, 4, len(globs)) // AggregateGlobs resolves paths, which uses forward slashes internally assert.Contains(t, globs, ResolvePath("*.txt")) assert.Contains(t, globs, ResolvePath("*.md")) assert.Contains(t, globs, ResolvePath("*.go")) assert.Contains(t, globs, ResolvePath("test/**/*.xml")) } func TestExpandGlobsWithActualFiles(t *testing.T) { // Create temp dir with test files tmpDir, err := os.MkdirTemp("", "glob-test-*") assert.NoError(t, err) defer os.RemoveAll(tmpDir) // Create test files testFile1 := filepath.Join(tmpDir, "test1.txt") testFile2 := filepath.Join(tmpDir, "test2.txt") testFile3 := filepath.Join(tmpDir, "test.md") os.WriteFile(testFile1, []byte("test"), 0644) os.WriteFile(testFile2, []byte("test"), 0644) os.WriteFile(testFile3, []byte("test"), 0644) // Change to temp directory so glob pattern can find files origDir, _ := os.Getwd() defer os.Chdir(origDir) os.Chdir(tmpDir) // Test expanding globs using ResolvePath to normalize the pattern globs := map[string]struct{}{ ResolvePath("*.txt"): {}, } files, err := ExpandGlobs(globs) assert.NoError(t, err) assert.Equal(t, 2, len(files)) } func TestSplitPatternWithTilde(t *testing.T) { pattern := "~/test/*.txt" static, pat := SplitPattern(pattern) // Should expand ~ assert.NotEqual(t, "~", static) assert.Contains(t, pat, "*.txt") } func TestLoadCommandsWithDisabled(t *testing.T) { tmpDir, err := os.MkdirTemp("", "disabled-test-*") assert.NoError(t, err) defer os.RemoveAll(tmpDir) yamlContent := ` variables: test: "value" commands: - name: "enabled_cmd" regex: "test" lua: "v1 * 2" files: ["*.txt"] - name: "disabled_cmd" regex: "test2" lua: "v1 * 3" files: ["*.txt"] disable: true ` yamlFile := filepath.Join(tmpDir, "test.yml") err = os.WriteFile(yamlFile, []byte(yamlContent), 0644) assert.NoError(t, err) // Change to temp directory so LoadCommands can find the file with a simple pattern origDir, _ := os.Getwd() defer os.Chdir(origDir) os.Chdir(tmpDir) commands, variables, err := LoadCommands([]string{"test.yml"}) assert.NoError(t, err) // Should only load enabled command assert.Equal(t, 1, len(commands)) assert.Equal(t, "enabled_cmd", commands[0].Name) // Should still load variables assert.Equal(t, 1, len(variables)) } func TestFilterCommandsByName(t *testing.T) { commands := []ModifyCommand{ {Name: "test_multiply"}, {Name: "test_divide"}, {Name: "other_command"}, {Name: "test_add"}, } // Filter by "test" filtered := FilterCommands(commands, "test") assert.Equal(t, 3, len(filtered)) // Filter by multiple filtered = FilterCommands(commands, "multiply,divide") assert.Equal(t, 2, len(filtered)) } func TestCountGlobsBeforeDedup(t *testing.T) { commands := []ModifyCommand{ {Files: []string{"*.txt", "*.md", "*.go"}}, {Files: []string{"*.xml"}}, {Files: []string{"test/**/*.txt", "data/**/*.json"}}, } count := CountGlobsBeforeDedup(commands) assert.Equal(t, 6, count) } func TestMatchesWithMemoization(t *testing.T) { path := "test/file.txt" glob := "**/*.txt" // First call matches1, err1 := Matches(path, glob) assert.NoError(t, err1) assert.True(t, matches1) // Second call should use memo matches2, err2 := Matches(path, glob) assert.NoError(t, err2) assert.Equal(t, matches1, matches2) } func TestValidateCommand(t *testing.T) { tests := []struct { name string cmd ModifyCommand wantErr bool }{ { name: "Valid command", cmd: ModifyCommand{ Regex: "test", Lua: "v1 * 2", Files: []string{"*.txt"}, }, wantErr: false, }, { name: "Valid JSON mode without regex", cmd: ModifyCommand{ JSON: true, Lua: "data.value = data.value * 2; modified = true", Files: []string{"*.json"}, }, wantErr: false, }, { name: "Missing regex in non-JSON mode", cmd: ModifyCommand{ Lua: "v1 * 2", Files: []string{"*.txt"}, }, wantErr: true, }, { name: "Missing Lua", cmd: ModifyCommand{ Regex: "test", Files: []string{"*.txt"}, }, wantErr: true, }, { name: "Missing files", cmd: ModifyCommand{ Regex: "test", Lua: "v1 * 2", }, wantErr: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { err := tt.cmd.Validate() if tt.wantErr { assert.Error(t, err) } else { assert.NoError(t, err) } }) } } func TestLoadCommandsFromTomlWithVariables(t *testing.T) { tmpDir, err := os.MkdirTemp("", "toml-vars-test-*") assert.NoError(t, err) defer os.RemoveAll(tmpDir) tomlContent := `[variables] multiplier = 3 prefix = "PREFIX_" [[commands]] name = "test_cmd" regex = "value = !num" lua = "v1 * multiplier" files = ["*.txt"] ` tomlFile := filepath.Join(tmpDir, "test.toml") err = os.WriteFile(tomlFile, []byte(tomlContent), 0644) assert.NoError(t, err) // Change to temp directory so glob pattern can find the file origDir, _ := os.Getwd() defer os.Chdir(origDir) os.Chdir(tmpDir) commands, variables, err := LoadCommandsFromTomlFiles("test.toml") assert.NoError(t, err) assert.Equal(t, 1, len(commands)) assert.Equal(t, 2, len(variables)) assert.Equal(t, int64(3), variables["multiplier"]) assert.Equal(t, "PREFIX_", variables["prefix"]) } func TestConvertYAMLToTOMLSkipExisting(t *testing.T) { tmpDir, err := os.MkdirTemp("", "convert-skip-test-*") assert.NoError(t, err) defer os.RemoveAll(tmpDir) // Create YAML file yamlContent := ` commands: - name: "test" regex: "value" lua: "v1 * 2" files: ["*.txt"] ` yamlFile := filepath.Join(tmpDir, "test.yml") err = os.WriteFile(yamlFile, []byte(yamlContent), 0644) assert.NoError(t, err) // Create TOML file (should skip conversion) tomlFile := filepath.Join(tmpDir, "test.toml") err = os.WriteFile(tomlFile, []byte("# existing"), 0644) assert.NoError(t, err) // Change to temp dir origDir, _ := os.Getwd() defer os.Chdir(origDir) os.Chdir(tmpDir) // Should skip existing TOML err = ConvertYAMLToTOML("test.yml") assert.NoError(t, err) // TOML content should be unchanged content, _ := os.ReadFile(tomlFile) assert.Equal(t, "# existing", string(content)) } func TestLoadCommandsWithTomlExtension(t *testing.T) { tmpDir, err := os.MkdirTemp("", "toml-ext-test-*") assert.NoError(t, err) defer os.RemoveAll(tmpDir) tomlContent := ` [variables] test_var = "value" [[commands]] name = "TestCmd" regex = "test" lua = "return true" files = ["*.txt"] ` tomlFile := filepath.Join(tmpDir, "test.toml") err = os.WriteFile(tomlFile, []byte(tomlContent), 0644) assert.NoError(t, err) origDir, _ := os.Getwd() defer os.Chdir(origDir) os.Chdir(tmpDir) // This should trigger the .toml suffix check in LoadCommands commands, variables, err := LoadCommands([]string{"test.toml"}) assert.NoError(t, err) assert.Len(t, commands, 1) assert.Equal(t, "TestCmd", commands[0].Name) assert.Len(t, variables, 1) assert.Equal(t, "value", variables["test_var"]) }