package builders import ( "os" "path/filepath" "testing" "github.com/host-uk/core/pkg/build" "github.com/host-uk/core/pkg/io" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestCPPBuilder_Name_Good(t *testing.T) { builder := NewCPPBuilder() assert.Equal(t, "cpp", builder.Name()) } func TestCPPBuilder_Detect_Good(t *testing.T) { fs := io.Local t.Run("detects C++ project with CMakeLists.txt", func(t *testing.T) { dir := t.TempDir() err := os.WriteFile(filepath.Join(dir, "CMakeLists.txt"), []byte("cmake_minimum_required(VERSION 3.16)"), 0644) require.NoError(t, err) builder := NewCPPBuilder() detected, err := builder.Detect(fs, dir) assert.NoError(t, err) assert.True(t, detected) }) t.Run("returns false for non-C++ project", func(t *testing.T) { dir := t.TempDir() err := os.WriteFile(filepath.Join(dir, "go.mod"), []byte("module test"), 0644) require.NoError(t, err) builder := NewCPPBuilder() detected, err := builder.Detect(fs, dir) assert.NoError(t, err) assert.False(t, detected) }) t.Run("returns false for empty directory", func(t *testing.T) { dir := t.TempDir() builder := NewCPPBuilder() detected, err := builder.Detect(fs, dir) assert.NoError(t, err) assert.False(t, detected) }) } func TestCPPBuilder_Build_Bad(t *testing.T) { t.Run("returns error for nil config", func(t *testing.T) { builder := NewCPPBuilder() artifacts, err := builder.Build(nil, nil, []build.Target{{OS: "linux", Arch: "amd64"}}) assert.Error(t, err) assert.Nil(t, artifacts) assert.Contains(t, err.Error(), "config is nil") }) } func TestCPPBuilder_TargetToProfile_Good(t *testing.T) { builder := NewCPPBuilder() tests := []struct { os, arch string expected string }{ {"linux", "amd64", "gcc-linux-x86_64"}, {"linux", "x86_64", "gcc-linux-x86_64"}, {"linux", "arm64", "gcc-linux-armv8"}, {"darwin", "arm64", "apple-clang-armv8"}, {"darwin", "amd64", "apple-clang-x86_64"}, {"windows", "amd64", "msvc-194-x86_64"}, } for _, tt := range tests { t.Run(tt.os+"/"+tt.arch, func(t *testing.T) { profile := builder.targetToProfile(build.Target{OS: tt.os, Arch: tt.arch}) assert.Equal(t, tt.expected, profile) }) } } func TestCPPBuilder_TargetToProfile_Bad(t *testing.T) { builder := NewCPPBuilder() t.Run("returns empty for unknown target", func(t *testing.T) { profile := builder.targetToProfile(build.Target{OS: "plan9", Arch: "mips"}) assert.Empty(t, profile) }) } func TestCPPBuilder_FindArtifacts_Good(t *testing.T) { fs := io.Local t.Run("finds packages in build/packages", func(t *testing.T) { dir := t.TempDir() packagesDir := filepath.Join(dir, "build", "packages") require.NoError(t, os.MkdirAll(packagesDir, 0755)) // Create mock package files require.NoError(t, os.WriteFile(filepath.Join(packagesDir, "test-1.0-linux-x86_64.tar.xz"), []byte("pkg"), 0644)) require.NoError(t, os.WriteFile(filepath.Join(packagesDir, "test-1.0-linux-x86_64.tar.xz.sha256"), []byte("checksum"), 0644)) require.NoError(t, os.WriteFile(filepath.Join(packagesDir, "test-1.0-linux-x86_64.rpm"), []byte("rpm"), 0644)) builder := NewCPPBuilder() target := build.Target{OS: "linux", Arch: "amd64"} artifacts, err := builder.findArtifacts(fs, dir, target) require.NoError(t, err) // Should find tar.xz and rpm but not sha256 assert.Len(t, artifacts, 2) for _, a := range artifacts { assert.Equal(t, "linux", a.OS) assert.Equal(t, "amd64", a.Arch) assert.False(t, filepath.Ext(a.Path) == ".sha256") } }) t.Run("falls back to binaries in build/release/src", func(t *testing.T) { dir := t.TempDir() binDir := filepath.Join(dir, "build", "release", "src") require.NoError(t, os.MkdirAll(binDir, 0755)) // Create mock binary (executable) binPath := filepath.Join(binDir, "test-daemon") require.NoError(t, os.WriteFile(binPath, []byte("binary"), 0755)) // Create a library (should be skipped) require.NoError(t, os.WriteFile(filepath.Join(binDir, "libcrypto.a"), []byte("lib"), 0644)) builder := NewCPPBuilder() target := build.Target{OS: "linux", Arch: "amd64"} artifacts, err := builder.findArtifacts(fs, dir, target) require.NoError(t, err) // Should find the executable but not the library assert.Len(t, artifacts, 1) assert.Contains(t, artifacts[0].Path, "test-daemon") }) } func TestCPPBuilder_Interface_Good(t *testing.T) { var _ build.Builder = (*CPPBuilder)(nil) var _ build.Builder = NewCPPBuilder() }