mirror of
https://github.com/ivuorinen/gh-action-readme.git
synced 2026-01-26 11:14:04 +00:00
* chore(lint): added nlreturn, run linting * chore(lint): replace some fmt.Sprintf calls * chore(lint): replace fmt.Sprintf with strconv * chore(lint): add goconst, use http lib for status codes, and methods * chore(lint): use errors lib, errCodes from internal/errors * chore(lint): dupl, thelper and usetesting * chore(lint): fmt.Errorf %v to %w, more linters * chore(lint): paralleltest, where possible * perf(test): optimize test performance by 78% - Implement shared binary building with package-level cache to eliminate redundant builds - Add strategic parallelization to 15+ tests while preserving environment variable isolation - Implement thread-safe fixture caching with RWMutex to reduce I/O operations - Remove unnecessary working directory changes by leveraging embedded templates - Add embedded template system with go:embed directive for reliable template resolution - Fix linting issues: rename sharedBinaryError to errSharedBinary, add nolint directive Performance improvements: - Total test execution time: 12+ seconds → 2.7 seconds (78% faster) - Binary build overhead: 14+ separate builds → 1 shared build (93% reduction) - Parallel execution: Limited → 15+ concurrent tests (60-70% better CPU usage) - I/O operations: 66+ fixture reads → cached with sync.RWMutex (50% reduction) All tests maintain 100% success rate and coverage while running nearly 4x faster.
309 lines
7.4 KiB
Go
309 lines
7.4 KiB
Go
package helpers
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/ivuorinen/gh-action-readme/internal"
|
|
"github.com/ivuorinen/gh-action-readme/testutil"
|
|
)
|
|
|
|
func TestGetCurrentDir(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
t.Run("successfully get current directory", func(t *testing.T) {
|
|
currentDir, err := GetCurrentDir()
|
|
|
|
testutil.AssertNoError(t, err)
|
|
|
|
if currentDir == "" {
|
|
t.Error("expected non-empty current directory")
|
|
}
|
|
|
|
// Verify it's an absolute path
|
|
if !filepath.IsAbs(currentDir) {
|
|
t.Errorf("expected absolute path, got: %s", currentDir)
|
|
}
|
|
|
|
// Verify the directory actually exists
|
|
if _, err := os.Stat(currentDir); os.IsNotExist(err) {
|
|
t.Errorf("current directory does not exist: %s", currentDir)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestSetupGeneratorContext(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tests := []struct {
|
|
name string
|
|
config *internal.AppConfig
|
|
}{
|
|
{
|
|
name: "basic config",
|
|
config: &internal.AppConfig{
|
|
Theme: "default",
|
|
OutputFormat: "md",
|
|
OutputDir: ".",
|
|
Verbose: false,
|
|
Quiet: false,
|
|
},
|
|
},
|
|
{
|
|
name: "verbose config",
|
|
config: &internal.AppConfig{
|
|
Theme: "github",
|
|
OutputFormat: "html",
|
|
OutputDir: "/tmp",
|
|
Verbose: true,
|
|
Quiet: false,
|
|
},
|
|
},
|
|
{
|
|
name: "quiet config",
|
|
config: &internal.AppConfig{
|
|
Theme: "minimal",
|
|
OutputFormat: "json",
|
|
OutputDir: ".",
|
|
Verbose: false,
|
|
Quiet: true,
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
generator, currentDir, err := SetupGeneratorContext(tt.config)
|
|
|
|
// Verify no error occurred
|
|
testutil.AssertNoError(t, err)
|
|
|
|
// Verify generator was created
|
|
if generator == nil {
|
|
t.Error("expected generator to be created")
|
|
|
|
return
|
|
}
|
|
|
|
// Verify current directory is returned
|
|
if currentDir == "" {
|
|
t.Error("expected non-empty current directory")
|
|
}
|
|
|
|
if !filepath.IsAbs(currentDir) {
|
|
t.Errorf("expected absolute path, got: %s", currentDir)
|
|
}
|
|
|
|
// Verify generator has the correct config
|
|
if generator.Config != tt.config {
|
|
t.Error("expected generator to have the provided config")
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestFindGitRepoRoot(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tests := []struct {
|
|
name string
|
|
setupFunc func(t *testing.T, tmpDir string) string
|
|
expectGit bool
|
|
}{
|
|
{
|
|
name: "directory with git repository",
|
|
setupFunc: func(t *testing.T, tmpDir string) string {
|
|
t.Helper()
|
|
// Create .git directory
|
|
gitDir := filepath.Join(tmpDir, ".git")
|
|
err := os.MkdirAll(gitDir, 0750) // #nosec G301 -- test directory permissions
|
|
testutil.AssertNoError(t, err)
|
|
|
|
// Create subdirectory to test from
|
|
subDir := filepath.Join(tmpDir, "subdir")
|
|
err = os.MkdirAll(subDir, 0750) // #nosec G301 -- test directory permissions
|
|
testutil.AssertNoError(t, err)
|
|
|
|
return subDir
|
|
},
|
|
expectGit: true,
|
|
},
|
|
{
|
|
name: "directory without git repository",
|
|
setupFunc: func(_ *testing.T, tmpDir string) string {
|
|
// Just return the temp directory without .git
|
|
return tmpDir
|
|
},
|
|
expectGit: false,
|
|
},
|
|
{
|
|
name: "nested directory in git repository",
|
|
setupFunc: func(t *testing.T, tmpDir string) string {
|
|
t.Helper()
|
|
// Create .git directory at root
|
|
gitDir := filepath.Join(tmpDir, ".git")
|
|
err := os.MkdirAll(gitDir, 0750) // #nosec G301 -- test directory permissions
|
|
testutil.AssertNoError(t, err)
|
|
|
|
// Create deeply nested subdirectory
|
|
nestedDir := filepath.Join(tmpDir, "a", "b", "c")
|
|
err = os.MkdirAll(nestedDir, 0750) // #nosec G301 -- test directory permissions
|
|
testutil.AssertNoError(t, err)
|
|
|
|
return nestedDir
|
|
},
|
|
expectGit: true,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tmpDir, cleanup := testutil.TempDir(t)
|
|
defer cleanup()
|
|
|
|
testDir := tt.setupFunc(t, tmpDir)
|
|
repoRoot := FindGitRepoRoot(testDir)
|
|
|
|
if tt.expectGit {
|
|
if repoRoot == "" {
|
|
t.Error("expected to find git repository root, got empty string")
|
|
}
|
|
if !strings.Contains(repoRoot, tmpDir) {
|
|
t.Errorf("expected repo root to be within %s, got %s", tmpDir, repoRoot)
|
|
}
|
|
} else if repoRoot != "" {
|
|
t.Errorf("expected empty string for non-git directory, got %s", repoRoot)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestGetGitRepoRootAndInfo(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
t.Run("valid git repository with complete info", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tmpDir, cleanup := testutil.TempDir(t)
|
|
defer cleanup()
|
|
|
|
testDir := setupCompleteGitRepo(t, tmpDir)
|
|
repoRoot, gitInfo, err := GetGitRepoRootAndInfo(testDir)
|
|
|
|
testutil.AssertNoError(t, err)
|
|
verifyRepoRoot(t, repoRoot, tmpDir)
|
|
if gitInfo == nil {
|
|
t.Error("expected git info to be returned, got nil")
|
|
}
|
|
})
|
|
|
|
t.Run("git repository but info detection fails", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tmpDir, cleanup := testutil.TempDir(t)
|
|
defer cleanup()
|
|
|
|
testDir := setupMinimalGitRepo(t, tmpDir)
|
|
repoRoot, gitInfo, err := GetGitRepoRootAndInfo(testDir)
|
|
|
|
testutil.AssertNoError(t, err)
|
|
verifyRepoRoot(t, repoRoot, tmpDir)
|
|
if gitInfo != nil {
|
|
t.Logf("got unexpected git info: %+v", gitInfo)
|
|
}
|
|
})
|
|
|
|
t.Run("directory without git repository", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tmpDir, cleanup := testutil.TempDir(t)
|
|
defer cleanup()
|
|
|
|
repoRoot, gitInfo, err := GetGitRepoRootAndInfo(tmpDir)
|
|
|
|
if err == nil {
|
|
t.Error("expected error, got nil")
|
|
}
|
|
if repoRoot != "" {
|
|
t.Errorf("expected empty repo root, got: %s", repoRoot)
|
|
}
|
|
if gitInfo != nil {
|
|
t.Errorf("expected nil git info, got: %+v", gitInfo)
|
|
}
|
|
})
|
|
}
|
|
|
|
// Helper functions to reduce complexity.
|
|
func setupCompleteGitRepo(t *testing.T, tmpDir string) string {
|
|
t.Helper()
|
|
// Create .git directory
|
|
gitDir := filepath.Join(tmpDir, ".git")
|
|
err := os.MkdirAll(gitDir, 0750) // #nosec G301 -- test directory permissions
|
|
testutil.AssertNoError(t, err)
|
|
|
|
// Create a basic git config to make it look like a real repo
|
|
configContent := `[core]
|
|
repositoryformatversion = 0
|
|
filemode = true
|
|
bare = false
|
|
[remote "origin"]
|
|
url = https://github.com/test/repo.git
|
|
fetch = +refs/heads/*:refs/remotes/origin/*
|
|
[branch "main"]
|
|
remote = origin
|
|
merge = refs/heads/main
|
|
`
|
|
configPath := filepath.Join(gitDir, "config")
|
|
err = os.WriteFile(configPath, []byte(configContent), 0600) // #nosec G306 -- test file permissions
|
|
testutil.AssertNoError(t, err)
|
|
|
|
return tmpDir
|
|
}
|
|
|
|
func setupMinimalGitRepo(t *testing.T, tmpDir string) string {
|
|
t.Helper()
|
|
// Create .git directory but with minimal content
|
|
gitDir := filepath.Join(tmpDir, ".git")
|
|
err := os.MkdirAll(gitDir, 0750) // #nosec G301 -- test directory permissions
|
|
testutil.AssertNoError(t, err)
|
|
|
|
return tmpDir
|
|
}
|
|
|
|
func verifyRepoRoot(t *testing.T, repoRoot, tmpDir string) {
|
|
t.Helper()
|
|
if repoRoot != "" && !strings.Contains(repoRoot, tmpDir) {
|
|
t.Errorf("expected repo root to be within %s, got %s", tmpDir, repoRoot)
|
|
}
|
|
}
|
|
|
|
// Test error handling in GetGitRepoRootAndInfo.
|
|
func TestGetGitRepoRootAndInfo_ErrorHandling(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
t.Run("nonexistent directory", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
nonexistentPath := "/this/path/should/not/exist"
|
|
repoRoot, gitInfo, err := GetGitRepoRootAndInfo(nonexistentPath)
|
|
|
|
if err == nil {
|
|
t.Error("expected error for nonexistent directory")
|
|
}
|
|
|
|
if repoRoot != "" {
|
|
t.Errorf("expected empty repo root, got: %s", repoRoot)
|
|
}
|
|
|
|
if gitInfo != nil {
|
|
t.Errorf("expected nil git info, got: %+v", gitInfo)
|
|
}
|
|
})
|
|
}
|