Skip to content
Merged
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
235 changes: 202 additions & 33 deletions pkg/cli/add_command_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ package cli
import (
"testing"

"github.com/spf13/cobra"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
Expand Down Expand Up @@ -83,68 +84,236 @@ func TestNewAddCommand(t *testing.T) {
assert.NotNil(t, stopAfterFlag, "Should have 'stop-after' flag")
}

func TestAddWorkflows_EmptyWorkflows(t *testing.T) {
_, err := AddWorkflows([]string{}, 1, false, "", "", false, "", false, false, false, "", false, "")
require.Error(t, err, "Should error when no workflows are provided")
assert.Contains(t, err.Error(), "at least one workflow", "Error should mention missing workflow")
func TestAddWorkflows(t *testing.T) {
tests := []struct {
name string
workflows []string
number int
expectError bool
errorContains string
}{
{
name: "empty workflows list",
workflows: []string{},
number: 1,
expectError: true,
errorContains: "at least one workflow",
},
{
name: "repo-only spec (should list workflows)",
workflows: []string{"owner/repo"},
number: 1,
expectError: true, // Will error on workflow listing, but tests repo-only detection
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
_, err := AddWorkflows(tt.workflows, tt.number, false, "", "", false, "", false, false, false, "", false, "")

if tt.expectError {
require.Error(t, err, "Expected error for test case: %s", tt.name)
if tt.errorContains != "" {
assert.Contains(t, err.Error(), tt.errorContains, "Error should contain expected message")
}
} else {
assert.NoError(t, err, "Should not error for test case: %s", tt.name)
}
})
}
}

func TestAddWorkflows_InvalidNumber(t *testing.T) {
// TestUpdateWorkflowTitle is tested in commands_utils_test.go
// Removed duplicate test to avoid redeclaration

// TestAddCommandStructure removed - redundant with TestNewAddCommand

func TestAddResolvedWorkflows(t *testing.T) {
tests := []struct {
name string
number int
expectError bool
name string
number int
expectError bool
errorContains string
}{
{
name: "valid number",
number: 1,
expectError: false,
name: "invalid number - zero",
number: 0,
expectError: true,
errorContains: "number of copies must be a positive integer",
},
{
name: "zero number",
number: 0,
expectError: true,
name: "invalid number - negative",
number: -1,
expectError: true,
errorContains: "number of copies must be a positive integer",
},
{
name: "negative number",
number: -1,
expectError: true,
name: "valid number - one",
number: 1,
expectError: true, // Will still error due to missing workflow, but validates number check
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// Note: This test checks validation logic exists
// Full integration would require actual workflow specs
if tt.expectError && tt.number <= 0 {
// The function should validate number > 0
// This is a placeholder - actual validation may occur in the function
assert.LessOrEqual(t, tt.number, 0, "Invalid number should be non-positive")
// Create a minimal resolved workflow structure
resolved := &ResolvedWorkflows{
Workflows: []*ResolvedWorkflow{
{
Spec: &WorkflowSpec{
RepoSpec: RepoSpec{
RepoSlug: "test/repo",
},
WorkflowName: "test-workflow",
WorkflowPath: "test.md",
},
},
},
}

_, err := AddResolvedWorkflows(
[]string{"test/repo/test-workflow"},
resolved,
tt.number,
false, // verbose
false, // quiet
"", // engineOverride
"", // name
false, // force
"", // appendText
false, // createPR
false, // push
false, // noGitattributes
"", // workflowDir
false, // noStopAfter
"", // stopAfter
)

if tt.expectError {
require.Error(t, err, "Expected error for test case: %s", tt.name)
if tt.errorContains != "" {
assert.Contains(t, err.Error(), tt.errorContains, "Error should contain expected message")
}
} else {
assert.NoError(t, err, "Should not error for test case: %s", tt.name)
}
})
}
}

// TestUpdateWorkflowTitle is tested in commands_utils_test.go
// Removed duplicate test to avoid redeclaration
func TestAddWorkflowsResult(t *testing.T) {
tests := []struct {
name string
prNumber int
prURL string
hasWorkflowDispatch bool
}{
{
name: "default values",
prNumber: 0,
prURL: "",
hasWorkflowDispatch: false,
},
{
name: "with PR number",
prNumber: 123,
prURL: "",
hasWorkflowDispatch: false,
},
{
name: "with PR URL",
prNumber: 0,
prURL: "https://github.com/owner/repo/pull/123",
hasWorkflowDispatch: false,
},
{
name: "with workflow dispatch",
prNumber: 0,
prURL: "",
hasWorkflowDispatch: true,
},
{
name: "all fields set",
prNumber: 456,
prURL: "https://github.com/owner/repo/pull/456",
hasWorkflowDispatch: true,
},
}

func TestAddCommandStructure(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := &AddWorkflowsResult{
PRNumber: tt.prNumber,
PRURL: tt.prURL,
HasWorkflowDispatch: tt.hasWorkflowDispatch,
}

// Verify all fields are accessible and have expected values
assert.Equal(t, tt.prNumber, result.PRNumber, "PRNumber should match")
assert.Equal(t, tt.prURL, result.PRURL, "PRURL should match")
assert.Equal(t, tt.hasWorkflowDispatch, result.HasWorkflowDispatch, "HasWorkflowDispatch should match")
})
}
}

func TestAddCommandFlagInteractions(t *testing.T) {
tests := []struct {
name string
commandCreator func() interface{}
name string
flagSetup func(cmd *cobra.Command)
expectValid bool
description string
}{
{
name: "add command exists",
commandCreator: func() interface{} {
return NewAddCommand(validateEngineStub)
name: "no-stop-after and stop-after together",
flagSetup: func(cmd *cobra.Command) {
cmd.Flags().Set("no-stop-after", "true")
cmd.Flags().Set("stop-after", "+48h")
},
expectValid: true, // Both flags can be set, stop-after takes precedence
description: "Both no-stop-after and stop-after flags can be set",
},
{
name: "create-pull-request and pr alias",
flagSetup: func(cmd *cobra.Command) {
cmd.Flags().Set("create-pull-request", "true")
cmd.Flags().Set("pr", "true")
},
expectValid: true, // Both aliases should work
description: "Both create-pull-request and pr flags can be set (aliases)",
},
{
name: "force flag with number",
flagSetup: func(cmd *cobra.Command) {
cmd.Flags().Set("force", "true")
cmd.Flags().Set("number", "3")
},
expectValid: true,
description: "Force flag should work with multiple numbered copies",
},
{
name: "dir flag with subdirectory",
flagSetup: func(cmd *cobra.Command) {
cmd.Flags().Set("dir", "shared")
},
expectValid: true,
description: "Dir flag should accept subdirectory name",
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
cmd := tt.commandCreator()
require.NotNil(t, cmd, "Command should not be nil")
cmd := NewAddCommand(validateEngineStub)

// Apply flag setup
tt.flagSetup(cmd)

// Verify flags are set correctly
flags := cmd.Flags()
assert.NotNil(t, flags, "Command flags should not be nil")

// The actual validation happens during RunE execution
// Here we just verify the flags can be set without panic
assert.True(t, tt.expectValid, tt.description)
})
}
}
Expand Down
Loading