879 lines
28 KiB
Go
879 lines
28 KiB
Go
package build
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"dappco.re/go/core/build/internal/ax"
|
|
|
|
"dappco.re/go/core/io"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
// setupTestDir creates a temporary directory with the specified marker files.
|
|
func setupTestDir(t *testing.T, markers ...string) string {
|
|
t.Helper()
|
|
dir := t.TempDir()
|
|
for _, m := range markers {
|
|
path := ax.Join(dir, m)
|
|
err := ax.WriteFile(path, []byte("{}"), 0644)
|
|
require.NoError(t, err)
|
|
}
|
|
return dir
|
|
}
|
|
|
|
func TestDiscovery_Discover_Good(t *testing.T) {
|
|
fs := io.Local
|
|
t.Run("detects Go project", func(t *testing.T) {
|
|
dir := setupTestDir(t, "go.mod")
|
|
types, err := Discover(fs, dir)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, []ProjectType{ProjectTypeGo}, types)
|
|
})
|
|
|
|
t.Run("detects Go workspace project", func(t *testing.T) {
|
|
dir := setupTestDir(t, "go.work")
|
|
types, err := Discover(fs, dir)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, []ProjectType{ProjectTypeGo}, types)
|
|
})
|
|
|
|
t.Run("detects Wails project with priority over Go", func(t *testing.T) {
|
|
dir := setupTestDir(t, "wails.json", "go.mod")
|
|
types, err := Discover(fs, dir)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, []ProjectType{ProjectTypeWails, ProjectTypeGo}, types)
|
|
})
|
|
|
|
t.Run("detects Node.js project", func(t *testing.T) {
|
|
dir := setupTestDir(t, "package.json")
|
|
types, err := Discover(fs, dir)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, []ProjectType{ProjectTypeNode}, types)
|
|
})
|
|
|
|
t.Run("detects nested Node.js project", func(t *testing.T) {
|
|
dir := t.TempDir()
|
|
nested := ax.Join(dir, "apps", "web")
|
|
require.NoError(t, ax.MkdirAll(nested, 0755))
|
|
require.NoError(t, ax.WriteFile(ax.Join(nested, "package.json"), []byte("{}"), 0644))
|
|
|
|
types, err := Discover(fs, dir)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, []ProjectType{ProjectTypeNode}, types)
|
|
})
|
|
|
|
t.Run("detects PHP project", func(t *testing.T) {
|
|
dir := setupTestDir(t, "composer.json")
|
|
types, err := Discover(fs, dir)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, []ProjectType{ProjectTypePHP}, types)
|
|
})
|
|
|
|
t.Run("detects docs project", func(t *testing.T) {
|
|
dir := setupTestDir(t, "mkdocs.yml")
|
|
types, err := Discover(fs, dir)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, []ProjectType{ProjectTypeDocs}, types)
|
|
})
|
|
|
|
t.Run("detects docs project with mkdocs.yaml", func(t *testing.T) {
|
|
dir := setupTestDir(t, "mkdocs.yaml")
|
|
types, err := Discover(fs, dir)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, []ProjectType{ProjectTypeDocs}, types)
|
|
})
|
|
|
|
t.Run("detects docs project in docs directory", func(t *testing.T) {
|
|
dir := t.TempDir()
|
|
require.NoError(t, ax.MkdirAll(ax.Join(dir, "docs"), 0755))
|
|
require.NoError(t, ax.WriteFile(ax.Join(dir, "docs", "mkdocs.yml"), []byte("site_name: Demo\n"), 0644))
|
|
|
|
types, err := Discover(fs, dir)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, []ProjectType{ProjectTypeDocs}, types)
|
|
})
|
|
|
|
t.Run("detects docs project in docs directory with mkdocs.yaml", func(t *testing.T) {
|
|
dir := t.TempDir()
|
|
require.NoError(t, ax.MkdirAll(ax.Join(dir, "docs"), 0755))
|
|
require.NoError(t, ax.WriteFile(ax.Join(dir, "docs", "mkdocs.yaml"), []byte("site_name: Demo\n"), 0644))
|
|
|
|
types, err := Discover(fs, dir)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, []ProjectType{ProjectTypeDocs}, types)
|
|
})
|
|
|
|
t.Run("detects Python project with pyproject.toml", func(t *testing.T) {
|
|
dir := setupTestDir(t, "pyproject.toml")
|
|
types, err := Discover(fs, dir)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, []ProjectType{ProjectTypePython}, types)
|
|
})
|
|
|
|
t.Run("detects Python project with requirements.txt", func(t *testing.T) {
|
|
dir := setupTestDir(t, "requirements.txt")
|
|
types, err := Discover(fs, dir)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, []ProjectType{ProjectTypePython}, types)
|
|
})
|
|
|
|
t.Run("detects Python only once with both markers", func(t *testing.T) {
|
|
dir := setupTestDir(t, "pyproject.toml", "requirements.txt")
|
|
types, err := Discover(fs, dir)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, []ProjectType{ProjectTypePython}, types)
|
|
})
|
|
|
|
t.Run("detects Rust project", func(t *testing.T) {
|
|
dir := setupTestDir(t, "Cargo.toml")
|
|
types, err := Discover(fs, dir)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, []ProjectType{ProjectTypeRust}, types)
|
|
})
|
|
|
|
t.Run("detects Docker project", func(t *testing.T) {
|
|
dir := setupTestDir(t, "Dockerfile")
|
|
types, err := Discover(fs, dir)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, []ProjectType{ProjectTypeDocker}, types)
|
|
})
|
|
|
|
t.Run("detects Containerfile project", func(t *testing.T) {
|
|
dir := setupTestDir(t, "Containerfile")
|
|
types, err := Discover(fs, dir)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, []ProjectType{ProjectTypeDocker}, types)
|
|
})
|
|
|
|
t.Run("detects LinuxKit project", func(t *testing.T) {
|
|
dir := t.TempDir()
|
|
lkDir := ax.Join(dir, ".core", "linuxkit")
|
|
require.NoError(t, ax.MkdirAll(lkDir, 0755))
|
|
require.NoError(t, ax.WriteFile(ax.Join(lkDir, "server.yml"), []byte("kernel:\n"), 0644))
|
|
|
|
types, err := Discover(fs, dir)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, []ProjectType{ProjectTypeLinuxKit}, types)
|
|
})
|
|
|
|
t.Run("detects LinuxKit project from yaml config", func(t *testing.T) {
|
|
dir := t.TempDir()
|
|
require.NoError(t, ax.WriteFile(ax.Join(dir, "linuxkit.yaml"), []byte("kernel:\n"), 0644))
|
|
|
|
types, err := Discover(fs, dir)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, []ProjectType{ProjectTypeLinuxKit}, types)
|
|
})
|
|
|
|
t.Run("detects C++ project", func(t *testing.T) {
|
|
dir := setupTestDir(t, "CMakeLists.txt")
|
|
types, err := Discover(fs, dir)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, []ProjectType{ProjectTypeCPP}, types)
|
|
})
|
|
|
|
t.Run("detects Taskfile project", func(t *testing.T) {
|
|
dir := setupTestDir(t, "Taskfile.yml")
|
|
types, err := Discover(fs, dir)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, []ProjectType{ProjectTypeTaskfile}, types)
|
|
})
|
|
|
|
t.Run("detects multiple project types", func(t *testing.T) {
|
|
dir := setupTestDir(t, "go.mod", "package.json")
|
|
types, err := Discover(fs, dir)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, []ProjectType{ProjectTypeGo, ProjectTypeNode}, types)
|
|
})
|
|
|
|
t.Run("preserves priority when core and fallback markers overlap", func(t *testing.T) {
|
|
dir := setupTestDir(t, "go.mod", "Dockerfile", "Taskfile.yml")
|
|
types, err := Discover(fs, dir)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, []ProjectType{ProjectTypeGo, ProjectTypeDocker, ProjectTypeTaskfile}, types)
|
|
})
|
|
|
|
t.Run("empty directory returns empty slice", func(t *testing.T) {
|
|
dir := t.TempDir()
|
|
types, err := Discover(fs, dir)
|
|
assert.NoError(t, err)
|
|
assert.Empty(t, types)
|
|
})
|
|
}
|
|
|
|
func TestDiscovery_Discover_Bad(t *testing.T) {
|
|
fs := io.Local
|
|
t.Run("non-existent directory returns empty slice", func(t *testing.T) {
|
|
types, err := Discover(fs, "/non/existent/path")
|
|
assert.NoError(t, err) // ax.Stat fails silently in fileExists
|
|
assert.Empty(t, types)
|
|
})
|
|
|
|
t.Run("directory marker is ignored", func(t *testing.T) {
|
|
dir := t.TempDir()
|
|
// Create go.mod as a directory instead of a file
|
|
err := ax.Mkdir(ax.Join(dir, "go.mod"), 0755)
|
|
require.NoError(t, err)
|
|
|
|
types, err := Discover(fs, dir)
|
|
assert.NoError(t, err)
|
|
assert.Empty(t, types)
|
|
})
|
|
}
|
|
|
|
func TestDiscovery_PrimaryType_Good(t *testing.T) {
|
|
fs := io.Local
|
|
t.Run("returns wails for wails project", func(t *testing.T) {
|
|
dir := setupTestDir(t, "wails.json", "go.mod")
|
|
primary, err := PrimaryType(fs, dir)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, ProjectTypeWails, primary)
|
|
})
|
|
|
|
t.Run("returns go for go-only project", func(t *testing.T) {
|
|
dir := setupTestDir(t, "go.mod")
|
|
primary, err := PrimaryType(fs, dir)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, ProjectTypeGo, primary)
|
|
})
|
|
|
|
t.Run("returns node for nested package.json project", func(t *testing.T) {
|
|
dir := t.TempDir()
|
|
nested := ax.Join(dir, "apps", "web")
|
|
require.NoError(t, ax.MkdirAll(nested, 0755))
|
|
require.NoError(t, ax.WriteFile(ax.Join(nested, "package.json"), []byte("{}"), 0644))
|
|
|
|
primary, err := PrimaryType(fs, dir)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, ProjectTypeNode, primary)
|
|
})
|
|
|
|
t.Run("returns empty string for empty directory", func(t *testing.T) {
|
|
dir := t.TempDir()
|
|
primary, err := PrimaryType(fs, dir)
|
|
assert.NoError(t, err)
|
|
assert.Empty(t, primary)
|
|
})
|
|
}
|
|
|
|
func TestDiscovery_IsGoProject_Good(t *testing.T) {
|
|
fs := io.Local
|
|
t.Run("true with go.mod", func(t *testing.T) {
|
|
dir := setupTestDir(t, "go.mod")
|
|
assert.True(t, IsGoProject(fs, dir))
|
|
})
|
|
|
|
t.Run("true with go.work", func(t *testing.T) {
|
|
dir := setupTestDir(t, "go.work")
|
|
assert.True(t, IsGoProject(fs, dir))
|
|
})
|
|
|
|
t.Run("true with wails.json", func(t *testing.T) {
|
|
dir := setupTestDir(t, "wails.json")
|
|
assert.True(t, IsGoProject(fs, dir))
|
|
})
|
|
|
|
t.Run("false without markers", func(t *testing.T) {
|
|
dir := t.TempDir()
|
|
assert.False(t, IsGoProject(fs, dir))
|
|
})
|
|
}
|
|
|
|
func TestDiscovery_IsWailsProject_Good(t *testing.T) {
|
|
fs := io.Local
|
|
t.Run("true with wails.json", func(t *testing.T) {
|
|
dir := setupTestDir(t, "wails.json")
|
|
assert.True(t, IsWailsProject(fs, dir))
|
|
})
|
|
|
|
t.Run("false with only go.mod", func(t *testing.T) {
|
|
dir := setupTestDir(t, "go.mod")
|
|
assert.False(t, IsWailsProject(fs, dir))
|
|
})
|
|
}
|
|
|
|
func TestDiscovery_IsNodeProject_Good(t *testing.T) {
|
|
fs := io.Local
|
|
t.Run("true with package.json", func(t *testing.T) {
|
|
dir := setupTestDir(t, "package.json")
|
|
assert.True(t, IsNodeProject(fs, dir))
|
|
})
|
|
|
|
t.Run("false without package.json", func(t *testing.T) {
|
|
dir := t.TempDir()
|
|
assert.False(t, IsNodeProject(fs, dir))
|
|
})
|
|
}
|
|
|
|
func TestDiscovery_IsPHPProject_Good(t *testing.T) {
|
|
fs := io.Local
|
|
t.Run("true with composer.json", func(t *testing.T) {
|
|
dir := setupTestDir(t, "composer.json")
|
|
assert.True(t, IsPHPProject(fs, dir))
|
|
})
|
|
|
|
t.Run("false without composer.json", func(t *testing.T) {
|
|
dir := t.TempDir()
|
|
assert.False(t, IsPHPProject(fs, dir))
|
|
})
|
|
}
|
|
|
|
func TestDiscovery_Target_Good(t *testing.T) {
|
|
target := Target{OS: "linux", Arch: "amd64"}
|
|
assert.Equal(t, "linux/amd64", target.String())
|
|
}
|
|
|
|
func TestDiscovery_FileExists_Good(t *testing.T) {
|
|
fs := io.Local
|
|
t.Run("returns true for existing file", func(t *testing.T) {
|
|
dir := t.TempDir()
|
|
path := ax.Join(dir, "test.txt")
|
|
err := ax.WriteFile(path, []byte("content"), 0644)
|
|
require.NoError(t, err)
|
|
assert.True(t, fileExists(fs, path))
|
|
})
|
|
|
|
t.Run("returns false for directory", func(t *testing.T) {
|
|
dir := t.TempDir()
|
|
assert.False(t, fileExists(fs, dir))
|
|
})
|
|
|
|
t.Run("returns false for non-existent path", func(t *testing.T) {
|
|
assert.False(t, fileExists(fs, "/non/existent/file"))
|
|
})
|
|
}
|
|
|
|
// TestDiscover_Testdata tests discovery using the testdata fixtures.
|
|
// These serve as integration tests with realistic project structures.
|
|
func TestDiscovery_DiscoverTestdata_Good(t *testing.T) {
|
|
fs := io.Local
|
|
testdataDir, err := ax.Abs("testdata")
|
|
require.NoError(t, err)
|
|
|
|
tests := []struct {
|
|
name string
|
|
dir string
|
|
expected []ProjectType
|
|
}{
|
|
{"go-project", "go-project", []ProjectType{ProjectTypeGo}},
|
|
{"wails-project", "wails-project", []ProjectType{ProjectTypeWails, ProjectTypeGo}},
|
|
{"node-project", "node-project", []ProjectType{ProjectTypeNode}},
|
|
{"php-project", "php-project", []ProjectType{ProjectTypePHP}},
|
|
{"multi-project", "multi-project", []ProjectType{ProjectTypeGo, ProjectTypeNode}},
|
|
{"empty-project", "empty-project", []ProjectType{}},
|
|
{"docs-project", "docs-project", []ProjectType{ProjectTypeDocs}},
|
|
{"python-project", "python-project", []ProjectType{ProjectTypePython}},
|
|
{"rust-project", "rust-project", []ProjectType{ProjectTypeRust}},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
dir := ax.Join(testdataDir, tt.dir)
|
|
types, err := Discover(fs, dir)
|
|
assert.NoError(t, err)
|
|
if len(tt.expected) == 0 {
|
|
assert.Empty(t, types)
|
|
} else {
|
|
assert.Equal(t, tt.expected, types)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestDiscovery_IsMkDocsProject_Good(t *testing.T) {
|
|
fs := io.Local
|
|
t.Run("true with mkdocs.yml", func(t *testing.T) {
|
|
dir := setupTestDir(t, "mkdocs.yml")
|
|
assert.True(t, IsMkDocsProject(fs, dir))
|
|
})
|
|
|
|
t.Run("true with mkdocs.yaml", func(t *testing.T) {
|
|
dir := setupTestDir(t, "mkdocs.yaml")
|
|
assert.True(t, IsMkDocsProject(fs, dir))
|
|
})
|
|
|
|
t.Run("false without mkdocs.yml", func(t *testing.T) {
|
|
dir := t.TempDir()
|
|
assert.False(t, IsMkDocsProject(fs, dir))
|
|
})
|
|
}
|
|
|
|
func TestDiscovery_IsMkDocsProject_Bad(t *testing.T) {
|
|
fs := io.Local
|
|
t.Run("false for non-existent directory", func(t *testing.T) {
|
|
assert.False(t, IsMkDocsProject(fs, "/non/existent/path"))
|
|
})
|
|
}
|
|
|
|
func TestDiscovery_IsMkDocsProject_Ugly(t *testing.T) {
|
|
fs := io.Local
|
|
t.Run("false when mkdocs.yml is a directory", func(t *testing.T) {
|
|
dir := t.TempDir()
|
|
err := ax.Mkdir(ax.Join(dir, "mkdocs.yml"), 0755)
|
|
require.NoError(t, err)
|
|
assert.False(t, IsMkDocsProject(fs, dir))
|
|
})
|
|
}
|
|
|
|
func TestDiscovery_HasSubtreeNpm_Good(t *testing.T) {
|
|
fs := io.Local
|
|
t.Run("true with depth 1 nested package.json", func(t *testing.T) {
|
|
dir := t.TempDir()
|
|
subdir := ax.Join(dir, "packages", "web")
|
|
err := ax.MkdirAll(subdir, 0755)
|
|
require.NoError(t, err)
|
|
err = ax.WriteFile(ax.Join(dir, "packages", "package.json"), []byte("{}"), 0644)
|
|
require.NoError(t, err)
|
|
assert.True(t, HasSubtreeNpm(fs, dir))
|
|
})
|
|
|
|
t.Run("true with depth 2 nested package.json", func(t *testing.T) {
|
|
dir := t.TempDir()
|
|
nested := ax.Join(dir, "apps", "web")
|
|
err := ax.MkdirAll(nested, 0755)
|
|
require.NoError(t, err)
|
|
err = ax.WriteFile(ax.Join(nested, "package.json"), []byte("{}"), 0644)
|
|
require.NoError(t, err)
|
|
assert.True(t, HasSubtreeNpm(fs, dir))
|
|
})
|
|
|
|
t.Run("false with only root package.json", func(t *testing.T) {
|
|
dir := setupTestDir(t, "package.json")
|
|
assert.False(t, HasSubtreeNpm(fs, dir))
|
|
})
|
|
|
|
t.Run("false with empty directory", func(t *testing.T) {
|
|
dir := t.TempDir()
|
|
assert.False(t, HasSubtreeNpm(fs, dir))
|
|
})
|
|
}
|
|
|
|
func TestDiscovery_HasSubtreeNpm_Bad(t *testing.T) {
|
|
fs := io.Local
|
|
t.Run("false for non-existent directory", func(t *testing.T) {
|
|
assert.False(t, HasSubtreeNpm(fs, "/non/existent/path"))
|
|
})
|
|
|
|
t.Run("ignores node_modules at depth 1", func(t *testing.T) {
|
|
dir := t.TempDir()
|
|
nmDir := ax.Join(dir, "node_modules", "some-pkg")
|
|
err := ax.MkdirAll(nmDir, 0755)
|
|
require.NoError(t, err)
|
|
err = ax.WriteFile(ax.Join(nmDir, "package.json"), []byte("{}"), 0644)
|
|
require.NoError(t, err)
|
|
assert.False(t, HasSubtreeNpm(fs, dir))
|
|
})
|
|
|
|
t.Run("ignores node_modules at depth 2", func(t *testing.T) {
|
|
dir := t.TempDir()
|
|
nmDir := ax.Join(dir, "apps", "node_modules", "some-pkg")
|
|
err := ax.MkdirAll(nmDir, 0755)
|
|
require.NoError(t, err)
|
|
err = ax.WriteFile(ax.Join(nmDir, "package.json"), []byte("{}"), 0644)
|
|
require.NoError(t, err)
|
|
// Also need the apps dir to be listable — it is since we created nmDir inside it
|
|
assert.False(t, HasSubtreeNpm(fs, dir))
|
|
})
|
|
}
|
|
|
|
func TestDiscovery_HasSubtreeNpm_Ugly(t *testing.T) {
|
|
fs := io.Local
|
|
t.Run("false when nested package.json is beyond depth 2", func(t *testing.T) {
|
|
dir := t.TempDir()
|
|
deep := ax.Join(dir, "a", "b", "c")
|
|
err := ax.MkdirAll(deep, 0755)
|
|
require.NoError(t, err)
|
|
err = ax.WriteFile(ax.Join(deep, "package.json"), []byte("{}"), 0644)
|
|
require.NoError(t, err)
|
|
assert.False(t, HasSubtreeNpm(fs, dir))
|
|
})
|
|
}
|
|
|
|
func TestDiscovery_IsPythonProject_Good(t *testing.T) {
|
|
fs := io.Local
|
|
t.Run("true with pyproject.toml", func(t *testing.T) {
|
|
dir := setupTestDir(t, "pyproject.toml")
|
|
assert.True(t, IsPythonProject(fs, dir))
|
|
})
|
|
|
|
t.Run("true with requirements.txt", func(t *testing.T) {
|
|
dir := setupTestDir(t, "requirements.txt")
|
|
assert.True(t, IsPythonProject(fs, dir))
|
|
})
|
|
|
|
t.Run("true with both markers", func(t *testing.T) {
|
|
dir := setupTestDir(t, "pyproject.toml", "requirements.txt")
|
|
assert.True(t, IsPythonProject(fs, dir))
|
|
})
|
|
|
|
t.Run("false without markers", func(t *testing.T) {
|
|
dir := t.TempDir()
|
|
assert.False(t, IsPythonProject(fs, dir))
|
|
})
|
|
}
|
|
|
|
func TestDiscovery_IsPythonProject_Bad(t *testing.T) {
|
|
fs := io.Local
|
|
t.Run("false for non-existent directory", func(t *testing.T) {
|
|
assert.False(t, IsPythonProject(fs, "/non/existent/path"))
|
|
})
|
|
}
|
|
|
|
func TestDiscovery_IsPythonProject_Ugly(t *testing.T) {
|
|
fs := io.Local
|
|
t.Run("false when pyproject.toml is a directory", func(t *testing.T) {
|
|
dir := t.TempDir()
|
|
err := ax.Mkdir(ax.Join(dir, "pyproject.toml"), 0755)
|
|
require.NoError(t, err)
|
|
assert.False(t, IsPythonProject(fs, dir))
|
|
})
|
|
}
|
|
|
|
func TestDiscovery_IsRustProject_Good(t *testing.T) {
|
|
fs := io.Local
|
|
t.Run("true with Cargo.toml", func(t *testing.T) {
|
|
dir := setupTestDir(t, "Cargo.toml")
|
|
assert.True(t, IsRustProject(fs, dir))
|
|
})
|
|
|
|
t.Run("false without Cargo.toml", func(t *testing.T) {
|
|
dir := t.TempDir()
|
|
assert.False(t, IsRustProject(fs, dir))
|
|
})
|
|
}
|
|
|
|
func TestDiscovery_IsRustProject_Bad(t *testing.T) {
|
|
fs := io.Local
|
|
t.Run("false for non-existent directory", func(t *testing.T) {
|
|
assert.False(t, IsRustProject(fs, "/non/existent/path"))
|
|
})
|
|
}
|
|
|
|
func TestDiscovery_IsRustProject_Ugly(t *testing.T) {
|
|
fs := io.Local
|
|
t.Run("false when Cargo.toml is a directory", func(t *testing.T) {
|
|
dir := t.TempDir()
|
|
err := ax.Mkdir(ax.Join(dir, "Cargo.toml"), 0755)
|
|
require.NoError(t, err)
|
|
assert.False(t, IsRustProject(fs, dir))
|
|
})
|
|
}
|
|
|
|
func TestDiscovery_DiscoverFull_Good(t *testing.T) {
|
|
fs := io.Local
|
|
t.Run("returns complete result for Go project", func(t *testing.T) {
|
|
dir := setupTestDir(t, "go.mod")
|
|
result, err := DiscoverFull(fs, dir)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, []ProjectType{ProjectTypeGo}, result.Types)
|
|
assert.Equal(t, "go", result.PrimaryStack)
|
|
assert.False(t, result.HasFrontend)
|
|
assert.False(t, result.HasSubtreeNpm)
|
|
assert.True(t, result.Markers["go.mod"])
|
|
assert.False(t, result.Markers["wails.json"])
|
|
})
|
|
|
|
t.Run("returns complete result for Go workspace project", func(t *testing.T) {
|
|
dir := setupTestDir(t, "go.work")
|
|
result, err := DiscoverFull(fs, dir)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, []ProjectType{ProjectTypeGo}, result.Types)
|
|
assert.Equal(t, "go", result.PrimaryStack)
|
|
assert.True(t, result.Markers["go.work"])
|
|
})
|
|
|
|
t.Run("returns complete result for Wails project with frontend", func(t *testing.T) {
|
|
dir := t.TempDir()
|
|
// Create wails.json, go.mod, and frontend/package.json
|
|
err := ax.WriteFile(ax.Join(dir, "wails.json"), []byte("{}"), 0644)
|
|
require.NoError(t, err)
|
|
err = ax.WriteFile(ax.Join(dir, "go.mod"), []byte("{}"), 0644)
|
|
require.NoError(t, err)
|
|
err = ax.MkdirAll(ax.Join(dir, "frontend"), 0755)
|
|
require.NoError(t, err)
|
|
err = ax.WriteFile(ax.Join(dir, "frontend", "package.json"), []byte("{}"), 0644)
|
|
require.NoError(t, err)
|
|
|
|
result, err := DiscoverFull(fs, dir)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, []ProjectType{ProjectTypeWails, ProjectTypeGo, ProjectTypeNode}, result.Types)
|
|
assert.Equal(t, "wails", result.PrimaryStack)
|
|
assert.True(t, result.HasFrontend)
|
|
assert.True(t, result.Markers["wails.json"])
|
|
assert.True(t, result.Markers["go.mod"])
|
|
})
|
|
|
|
t.Run("detects subtree npm as frontend", func(t *testing.T) {
|
|
dir := t.TempDir()
|
|
err := ax.WriteFile(ax.Join(dir, "go.mod"), []byte("{}"), 0644)
|
|
require.NoError(t, err)
|
|
nested := ax.Join(dir, "apps", "web")
|
|
err = ax.MkdirAll(nested, 0755)
|
|
require.NoError(t, err)
|
|
err = ax.WriteFile(ax.Join(nested, "package.json"), []byte("{}"), 0644)
|
|
require.NoError(t, err)
|
|
|
|
result, err := DiscoverFull(fs, dir)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, []ProjectType{ProjectTypeGo, ProjectTypeNode}, result.Types)
|
|
assert.True(t, result.HasSubtreeNpm)
|
|
assert.True(t, result.HasFrontend)
|
|
})
|
|
|
|
t.Run("detects root package.json as frontend", func(t *testing.T) {
|
|
dir := t.TempDir()
|
|
require.NoError(t, ax.WriteFile(ax.Join(dir, "package.json"), []byte("{}"), 0644))
|
|
|
|
result, err := DiscoverFull(fs, dir)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, []ProjectType{ProjectTypeNode}, result.Types)
|
|
assert.Equal(t, "node", result.PrimaryStack)
|
|
assert.True(t, result.HasFrontend)
|
|
assert.False(t, result.HasSubtreeNpm)
|
|
})
|
|
|
|
t.Run("detects frontend deno manifest at project root", func(t *testing.T) {
|
|
dir := t.TempDir()
|
|
err := ax.WriteFile(ax.Join(dir, "go.mod"), []byte("{}"), 0644)
|
|
require.NoError(t, err)
|
|
frontendDir := ax.Join(dir, "frontend")
|
|
require.NoError(t, ax.MkdirAll(frontendDir, 0755))
|
|
require.NoError(t, ax.WriteFile(ax.Join(frontendDir, "deno.json"), []byte("{}"), 0644))
|
|
|
|
result, err := DiscoverFull(fs, dir)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, []ProjectType{ProjectTypeGo}, result.Types)
|
|
assert.True(t, result.HasFrontend)
|
|
assert.False(t, result.HasSubtreeNpm)
|
|
assert.True(t, result.Markers["frontend/deno.json"])
|
|
assert.False(t, result.Markers["frontend/package.json"])
|
|
})
|
|
|
|
t.Run("detects nested deno frontend manifests", func(t *testing.T) {
|
|
dir := t.TempDir()
|
|
err := ax.WriteFile(ax.Join(dir, "go.mod"), []byte("{}"), 0644)
|
|
require.NoError(t, err)
|
|
frontendDir := ax.Join(dir, "apps", "site")
|
|
require.NoError(t, ax.MkdirAll(frontendDir, 0755))
|
|
require.NoError(t, ax.WriteFile(ax.Join(frontendDir, "deno.jsonc"), []byte("{}"), 0644))
|
|
|
|
result, err := DiscoverFull(fs, dir)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, []ProjectType{ProjectTypeGo}, result.Types)
|
|
assert.True(t, result.HasFrontend)
|
|
assert.False(t, result.HasSubtreeNpm)
|
|
})
|
|
|
|
t.Run("records frontend package manifest markers", func(t *testing.T) {
|
|
dir := t.TempDir()
|
|
frontendDir := ax.Join(dir, "frontend")
|
|
require.NoError(t, ax.MkdirAll(frontendDir, 0755))
|
|
require.NoError(t, ax.WriteFile(ax.Join(frontendDir, "package.json"), []byte("{}"), 0644))
|
|
require.NoError(t, ax.WriteFile(ax.Join(frontendDir, "deno.jsonc"), []byte("{}"), 0644))
|
|
|
|
result, err := DiscoverFull(fs, dir)
|
|
require.NoError(t, err)
|
|
assert.True(t, result.HasFrontend)
|
|
assert.True(t, result.Markers["frontend/package.json"])
|
|
assert.True(t, result.Markers["frontend/deno.jsonc"])
|
|
})
|
|
|
|
t.Run("empty directory returns empty result", func(t *testing.T) {
|
|
dir := t.TempDir()
|
|
result, err := DiscoverFull(fs, dir)
|
|
require.NoError(t, err)
|
|
assert.Empty(t, result.Types)
|
|
assert.Empty(t, result.PrimaryStack)
|
|
assert.False(t, result.HasFrontend)
|
|
assert.False(t, result.HasSubtreeNpm)
|
|
})
|
|
|
|
t.Run("detects docs project markers", func(t *testing.T) {
|
|
dir := setupTestDir(t, "mkdocs.yml")
|
|
result, err := DiscoverFull(fs, dir)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, []ProjectType{ProjectTypeDocs}, result.Types)
|
|
assert.Equal(t, "docs", result.PrimaryStack)
|
|
assert.True(t, result.Markers["mkdocs.yml"])
|
|
})
|
|
|
|
t.Run("detects docs project markers with mkdocs.yaml", func(t *testing.T) {
|
|
dir := setupTestDir(t, "mkdocs.yaml")
|
|
result, err := DiscoverFull(fs, dir)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, []ProjectType{ProjectTypeDocs}, result.Types)
|
|
assert.Equal(t, "docs", result.PrimaryStack)
|
|
assert.True(t, result.Markers["mkdocs.yaml"])
|
|
})
|
|
|
|
t.Run("detects docs project markers in docs directory", func(t *testing.T) {
|
|
dir := t.TempDir()
|
|
require.NoError(t, ax.MkdirAll(ax.Join(dir, "docs"), 0755))
|
|
require.NoError(t, ax.WriteFile(ax.Join(dir, "docs", "mkdocs.yaml"), []byte("site_name: Demo\n"), 0644))
|
|
|
|
result, err := DiscoverFull(fs, dir)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, []ProjectType{ProjectTypeDocs}, result.Types)
|
|
assert.Equal(t, "docs", result.PrimaryStack)
|
|
assert.True(t, result.Markers["docs/mkdocs.yaml"])
|
|
})
|
|
|
|
t.Run("detects Rust project markers", func(t *testing.T) {
|
|
dir := setupTestDir(t, "Cargo.toml")
|
|
result, err := DiscoverFull(fs, dir)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, []ProjectType{ProjectTypeRust}, result.Types)
|
|
assert.Equal(t, "rust", result.PrimaryStack)
|
|
assert.True(t, result.Markers["Cargo.toml"])
|
|
})
|
|
|
|
t.Run("detects Python project markers", func(t *testing.T) {
|
|
dir := setupTestDir(t, "pyproject.toml")
|
|
result, err := DiscoverFull(fs, dir)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, []ProjectType{ProjectTypePython}, result.Types)
|
|
assert.Equal(t, "python", result.PrimaryStack)
|
|
assert.True(t, result.Markers["pyproject.toml"])
|
|
})
|
|
|
|
t.Run("detects Docker project markers", func(t *testing.T) {
|
|
dir := setupTestDir(t, "Dockerfile")
|
|
result, err := DiscoverFull(fs, dir)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, []ProjectType{ProjectTypeDocker}, result.Types)
|
|
assert.Equal(t, "docker", result.PrimaryStack)
|
|
assert.True(t, result.Markers["Dockerfile"])
|
|
})
|
|
|
|
t.Run("records alternate Docker manifest markers", func(t *testing.T) {
|
|
dir := setupTestDir(t, "Containerfile", "dockerfile", "containerfile")
|
|
|
|
result, err := DiscoverFull(fs, dir)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, []ProjectType{ProjectTypeDocker}, result.Types)
|
|
assert.Equal(t, "docker", result.PrimaryStack)
|
|
assert.True(t, result.Markers["Containerfile"])
|
|
assert.True(t, result.Markers["dockerfile"])
|
|
assert.True(t, result.Markers["containerfile"])
|
|
})
|
|
|
|
t.Run("detects LinuxKit project markers in .core/linuxkit", func(t *testing.T) {
|
|
dir := t.TempDir()
|
|
lkDir := ax.Join(dir, ".core", "linuxkit")
|
|
require.NoError(t, ax.MkdirAll(lkDir, 0755))
|
|
require.NoError(t, ax.WriteFile(ax.Join(lkDir, "server.yml"), []byte("kernel:\n image: test"), 0644))
|
|
|
|
result, err := DiscoverFull(fs, dir)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, []ProjectType{ProjectTypeLinuxKit}, result.Types)
|
|
assert.Equal(t, "linuxkit", result.PrimaryStack)
|
|
assert.True(t, result.Markers[".core/linuxkit/*.yml"])
|
|
assert.True(t, result.Markers[".core/linuxkit/*.yaml"])
|
|
})
|
|
|
|
t.Run("detects LinuxKit project markers in linuxkit.yaml", func(t *testing.T) {
|
|
dir := setupTestDir(t, "linuxkit.yaml")
|
|
|
|
result, err := DiscoverFull(fs, dir)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, []ProjectType{ProjectTypeLinuxKit}, result.Types)
|
|
assert.Equal(t, "linuxkit", result.PrimaryStack)
|
|
assert.True(t, result.Markers["linuxkit.yaml"])
|
|
})
|
|
|
|
t.Run("detects C++ project markers", func(t *testing.T) {
|
|
dir := setupTestDir(t, "CMakeLists.txt")
|
|
result, err := DiscoverFull(fs, dir)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, []ProjectType{ProjectTypeCPP}, result.Types)
|
|
assert.Equal(t, "cpp", result.PrimaryStack)
|
|
assert.True(t, result.Markers["CMakeLists.txt"])
|
|
})
|
|
|
|
t.Run("detects Taskfile project markers", func(t *testing.T) {
|
|
dir := setupTestDir(t, "Taskfile.yaml")
|
|
result, err := DiscoverFull(fs, dir)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, []ProjectType{ProjectTypeTaskfile}, result.Types)
|
|
assert.Equal(t, "taskfile", result.PrimaryStack)
|
|
assert.True(t, result.Markers["Taskfile.yaml"])
|
|
})
|
|
}
|
|
|
|
func TestDiscovery_DiscoverFull_Bad(t *testing.T) {
|
|
fs := io.Local
|
|
t.Run("non-existent directory returns empty result", func(t *testing.T) {
|
|
result, err := DiscoverFull(fs, "/non/existent/path")
|
|
require.NoError(t, err)
|
|
assert.Empty(t, result.Types)
|
|
assert.Empty(t, result.PrimaryStack)
|
|
})
|
|
}
|
|
|
|
func TestDiscovery_DiscoverFull_Ugly(t *testing.T) {
|
|
fs := io.Local
|
|
t.Run("markers map is never nil even for empty directory", func(t *testing.T) {
|
|
dir := t.TempDir()
|
|
result, err := DiscoverFull(fs, dir)
|
|
require.NoError(t, err)
|
|
assert.NotNil(t, result.Markers)
|
|
})
|
|
}
|
|
|
|
func TestDiscovery_ParseOSReleaseDistro_Good(t *testing.T) {
|
|
t.Run("returns ubuntu version id", func(t *testing.T) {
|
|
content := `
|
|
NAME="Ubuntu"
|
|
ID=ubuntu
|
|
VERSION_ID="24.04"
|
|
ID_LIKE=debian
|
|
`
|
|
assert.Equal(t, "24.04", parseOSReleaseDistro(content))
|
|
})
|
|
|
|
t.Run("accepts ubuntu-style values without quotes", func(t *testing.T) {
|
|
content := `
|
|
ID=ubuntu
|
|
VERSION_ID=25.10
|
|
`
|
|
assert.Equal(t, "25.10", parseOSReleaseDistro(content))
|
|
})
|
|
}
|
|
|
|
func TestDiscovery_ParseOSReleaseDistro_Bad(t *testing.T) {
|
|
t.Run("returns empty for non-ubuntu distro", func(t *testing.T) {
|
|
content := `
|
|
ID=fedora
|
|
VERSION_ID=41
|
|
`
|
|
assert.Empty(t, parseOSReleaseDistro(content))
|
|
})
|
|
|
|
t.Run("returns empty when version missing", func(t *testing.T) {
|
|
content := `
|
|
ID=ubuntu
|
|
`
|
|
assert.Empty(t, parseOSReleaseDistro(content))
|
|
})
|
|
}
|
|
|
|
func TestDiscovery_DetectDistroVersion_Good(t *testing.T) {
|
|
fs := io.NewMockMedium()
|
|
require.NoError(t, fs.Write("/etc/os-release", `
|
|
ID=ubuntu
|
|
VERSION_ID="24.04"
|
|
`))
|
|
|
|
assert.Equal(t, "24.04", detectDistroVersion(fs))
|
|
}
|
|
|
|
func TestDiscovery_DetectDistroVersion_Bad(t *testing.T) {
|
|
fs := io.NewMockMedium()
|
|
require.NoError(t, fs.Write("/etc/os-release", `
|
|
ID=fedora
|
|
VERSION_ID=41
|
|
`))
|
|
|
|
assert.Empty(t, detectDistroVersion(fs))
|
|
}
|