Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .claude/settings.local.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@
"Bash(go test:*)",
"Bash(git add:*)",
"Bash(make lint:*)",
"Bash(golangci-lint run:*)"
"Bash(golangci-lint run:*)",
"Bash(rm:*)",
"Bash(git rm:*)",
"Bash(grep:*)"
],
"deny": []
}
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@ lint:
.PHONY: test
test:
which go-test-coverage || go install github.com/vladopajic/go-test-coverage/v2@latest
go test -v ./... -coverprofile=./cover.out -covermode=atomic -coverpkg=./...
go test -v ./... -coverprofile=./cover.out -covermode=atomic -coverpkg=./... -json | python3 testutil/colourise-go-test-output.py
go-test-coverage --config=./.testcoverage.yaml
148 changes: 148 additions & 0 deletions config_internal_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
package hal

import (
"os"
"path/filepath"
"testing"

"gotest.tools/v3/assert"
)

func TestSearchParentsForFile(t *testing.T) {
t.Parallel()

t.Run("finds file in current directory", func(t *testing.T) {
t.Parallel()
tmpDir := t.TempDir()
testFile := "test.txt"
testPath := filepath.Join(tmpDir, testFile)

err := os.WriteFile(testPath, []byte("test"), 0o644)
assert.NilError(t, err)

foundPath, err := searchParentsForFile(testFile, tmpDir)
assert.NilError(t, err)
assert.Equal(t, foundPath, testPath)
})

t.Run("finds file in parent directory", func(t *testing.T) {
t.Parallel()
tmpDir := t.TempDir()
subDir := filepath.Join(tmpDir, "subdir")
err := os.Mkdir(subDir, 0o755)
assert.NilError(t, err)

testFile := "test.txt"
testPath := filepath.Join(tmpDir, testFile)

err = os.WriteFile(testPath, []byte("test"), 0o644)
assert.NilError(t, err)

foundPath, err := searchParentsForFile(testFile, subDir)
assert.NilError(t, err)
assert.Equal(t, foundPath, testPath)
})

t.Run("returns empty string when file not found", func(t *testing.T) {
t.Parallel()
tmpDir := t.TempDir()
foundPath, err := searchParentsForFile("nonexistent.txt", tmpDir)
assert.NilError(t, err)
assert.Equal(t, foundPath, "")
})
}

//nolint:paralleltest // This test changes working directory and cannot run in parallel
func TestSearchParentsForFileFromCwd(t *testing.T) {
t.Run("searches from current working directory", func(t *testing.T) {
tmpDir := t.TempDir()
originalDir, _ := os.Getwd()
defer os.Chdir(originalDir)

testFile := "test.txt"
testPath := filepath.Join(tmpDir, testFile)

err := os.WriteFile(testPath, []byte("test"), 0o644)
assert.NilError(t, err)

err = os.Chdir(tmpDir)
assert.NilError(t, err)

foundPath, err := searchParentsForFileFromCwd(testFile)
assert.NilError(t, err)

// Resolve symlinks to handle macOS /private/var vs /var differences
resolvedFound, err := filepath.EvalSymlinks(foundPath)
assert.NilError(t, err)
resolvedExpected, err := filepath.EvalSymlinks(testPath)
assert.NilError(t, err)

assert.Equal(t, resolvedFound, resolvedExpected)
})
}

func TestGetParents(t *testing.T) {
t.Parallel()

t.Run("returns correct parent paths", func(t *testing.T) {
t.Parallel()
if filepath.Separator == '\\' {
// Windows paths
paths := getParents("C:\\Users\\test\\project")
expected := []string{
"C:\\Users\\test\\project",
"C:\\Users\\test",
"C:\\Users",
"C:\\",
"/",
}
assert.DeepEqual(t, paths, expected)
} else {
// Unix paths
paths := getParents("/home/user/project")
expected := []string{
"/home/user/project",
"/home/user",
"/home",
"/",
}
assert.DeepEqual(t, paths, expected)
}
})

t.Run("handles root directory", func(t *testing.T) {
t.Parallel()
paths := getParents("/")
expected := []string{"/"}
assert.DeepEqual(t, paths, expected)
})
}

func TestFileExists(t *testing.T) {
t.Parallel()

t.Run("returns true for existing file", func(t *testing.T) {
t.Parallel()
tmpDir := t.TempDir()
testPath := filepath.Join(tmpDir, "test.txt")

err := os.WriteFile(testPath, []byte("test"), 0o644)
assert.NilError(t, err)

exists := fileExists(testPath)
assert.Equal(t, exists, true)
})

t.Run("returns false for non-existent file", func(t *testing.T) {
t.Parallel()
exists := fileExists("/nonexistent/path/file.txt")
assert.Equal(t, exists, false)
})

t.Run("returns true for existing directory", func(t *testing.T) {
t.Parallel()
tmpDir := t.TempDir()
exists := fileExists(tmpDir)
assert.Equal(t, exists, true)
})
}
138 changes: 8 additions & 130 deletions config_test.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
package hal
package hal_test

import (
"os"
"path/filepath"
"testing"

"github.com/dansimau/hal"
"gotest.tools/v3/assert"
)

//nolint:paralleltest // This test changes working directory and cannot run in parallel
func TestLoadConfig(t *testing.T) {
t.Run("loads valid config", func(t *testing.T) {
// Create a temporary directory and config file
Expand All @@ -24,14 +26,14 @@ location:
lng: -122.4194`

configPath := filepath.Join(tmpDir, "hal.yaml")
err := os.WriteFile(configPath, []byte(configContent), 0644)
err := os.WriteFile(configPath, []byte(configContent), 0o644)
assert.NilError(t, err)

// Change to temp directory
err = os.Chdir(tmpDir)
assert.NilError(t, err)

config, err := LoadConfig()
config, err := hal.LoadConfig()
assert.NilError(t, err)
assert.Equal(t, config.HomeAssistant.Host, "localhost:8123")
assert.Equal(t, config.HomeAssistant.Token, "test-token")
Expand All @@ -48,7 +50,7 @@ location:
err := os.Chdir(tmpDir)
assert.NilError(t, err)

_, err = LoadConfig()
_, err = hal.LoadConfig()
assert.ErrorContains(t, err, "no such file or directory")
})

Expand All @@ -59,137 +61,13 @@ location:

invalidContent := `invalid: yaml: content:`
configPath := filepath.Join(tmpDir, "hal.yaml")
err := os.WriteFile(configPath, []byte(invalidContent), 0644)
err := os.WriteFile(configPath, []byte(invalidContent), 0o644)
assert.NilError(t, err)

err = os.Chdir(tmpDir)
assert.NilError(t, err)

_, err = LoadConfig()
_, err = hal.LoadConfig()
assert.ErrorContains(t, err, "yaml")
})
}

func TestSearchParentsForFile(t *testing.T) {
t.Run("finds file in current directory", func(t *testing.T) {
tmpDir := t.TempDir()
testFile := "test.txt"
testPath := filepath.Join(tmpDir, testFile)

err := os.WriteFile(testPath, []byte("test"), 0644)
assert.NilError(t, err)

foundPath, err := searchParentsForFile(testFile, tmpDir)
assert.NilError(t, err)
assert.Equal(t, foundPath, testPath)
})

t.Run("finds file in parent directory", func(t *testing.T) {
tmpDir := t.TempDir()
subDir := filepath.Join(tmpDir, "subdir")
err := os.Mkdir(subDir, 0755)
assert.NilError(t, err)

testFile := "test.txt"
testPath := filepath.Join(tmpDir, testFile)

err = os.WriteFile(testPath, []byte("test"), 0644)
assert.NilError(t, err)

foundPath, err := searchParentsForFile(testFile, subDir)
assert.NilError(t, err)
assert.Equal(t, foundPath, testPath)
})

t.Run("returns empty string when file not found", func(t *testing.T) {
tmpDir := t.TempDir()
foundPath, err := searchParentsForFile("nonexistent.txt", tmpDir)
assert.NilError(t, err)
assert.Equal(t, foundPath, "")
})
}

func TestSearchParentsForFileFromCwd(t *testing.T) {
t.Run("searches from current working directory", func(t *testing.T) {
tmpDir := t.TempDir()
originalDir, _ := os.Getwd()
defer os.Chdir(originalDir)

testFile := "test.txt"
testPath := filepath.Join(tmpDir, testFile)

err := os.WriteFile(testPath, []byte("test"), 0644)
assert.NilError(t, err)

err = os.Chdir(tmpDir)
assert.NilError(t, err)

foundPath, err := searchParentsForFileFromCwd(testFile)
assert.NilError(t, err)

// Resolve symlinks to handle macOS /private/var vs /var differences
resolvedFound, err := filepath.EvalSymlinks(foundPath)
assert.NilError(t, err)
resolvedExpected, err := filepath.EvalSymlinks(testPath)
assert.NilError(t, err)

assert.Equal(t, resolvedFound, resolvedExpected)
})
}

func TestGetParents(t *testing.T) {
t.Run("returns correct parent paths", func(t *testing.T) {
if filepath.Separator == '\\' {
// Windows paths
paths := getParents("C:\\Users\\test\\project")
expected := []string{
"C:\\Users\\test\\project",
"C:\\Users\\test",
"C:\\Users",
"C:\\",
"/",
}
assert.DeepEqual(t, paths, expected)
} else {
// Unix paths
paths := getParents("/home/user/project")
expected := []string{
"/home/user/project",
"/home/user",
"/home",
"/",
}
assert.DeepEqual(t, paths, expected)
}
})

t.Run("handles root directory", func(t *testing.T) {
paths := getParents("/")
expected := []string{"/"}
assert.DeepEqual(t, paths, expected)
})
}

func TestFileExists(t *testing.T) {
t.Run("returns true for existing file", func(t *testing.T) {
tmpDir := t.TempDir()
testPath := filepath.Join(tmpDir, "test.txt")

err := os.WriteFile(testPath, []byte("test"), 0644)
assert.NilError(t, err)

exists := fileExists(testPath)
assert.Equal(t, exists, true)
})

t.Run("returns false for non-existent file", func(t *testing.T) {
exists := fileExists("/nonexistent/path/file.txt")
assert.Equal(t, exists, false)
})

t.Run("returns true for existing directory", func(t *testing.T) {
tmpDir := t.TempDir()
exists := fileExists(tmpDir)
assert.Equal(t, exists, true)
})
}
Loading