Files
gitea-mcp-server/mcp/operation/actions/workflows_test.go
T

399 lines
8.6 KiB
Go

package actions
import (
"testing"
)
func TestMatchPattern(t *testing.T) {
tests := []struct {
filename string
pattern string
want bool
}{
{"build.yml", "*", true},
{"build.yml", "*.*", true},
{"build.yml", "*.yml", true},
{"build.yaml", "*.yml", true},
{"build.yaml", "*.yaml", true},
{"build-test.yml", "build-*.yml", true},
{"build-test.yml", "*-test.yml", true},
{"build.yml", "deploy*.yml", false},
{"build.yml", "*.yaml", false},
{"BUILD.YML", "*.yml", true},
{"build.yml", "build.yml", true},
{"deploy.yml", "build.yml", false},
}
for _, tt := range tests {
t.Run(tt.filename+"_"+tt.pattern, func(t *testing.T) {
got := matchPattern(tt.filename, tt.pattern)
if got != tt.want {
t.Fatalf("matchPattern(%q, %q) = %v, want %v", tt.filename, tt.pattern, got, tt.want)
}
})
}
}
func TestConvertYamlToInterface(t *testing.T) {
tests := []struct {
name string
input interface{}
expected interface{}
}{
{
name: "string value",
input: "hello",
expected: "hello",
},
{
name: "int value",
input: 42,
expected: 42,
},
{
name: "simple map",
input: map[string]interface{}{
"name": "test",
"val": 123,
},
expected: map[string]interface{}{
"name": "test",
"val": 123,
},
},
{
name: "nested map",
input: map[string]interface{}{
"level1": map[string]interface{}{
"level2": "value",
},
},
expected: map[string]interface{}{
"level1": map[string]interface{}{
"level2": "value",
},
},
},
{
name: "slice",
input: []interface{}{"a", "b", "c"},
expected: []interface{}{"a", "b", "c"},
},
{
name: "map with interface keys",
input: map[interface{}]interface{}{
"key": "value",
123: "numeric key",
},
expected: map[string]interface{}{
"key": "value",
"123": "numeric key",
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := convertYamlToInterface(tt.input)
if !deepEqual(got, tt.expected) {
t.Fatalf("convertYamlToInterface() = %v, want %v", got, tt.expected)
}
})
}
}
func deepEqual(a, b interface{}) bool {
switch av := a.(type) {
case map[string]interface{}:
bv, ok := b.(map[string]interface{})
if !ok || len(av) != len(bv) {
return false
}
for k, v := range av {
if !deepEqual(v, bv[k]) {
return false
}
}
return true
case []interface{}:
bv, ok := b.([]interface{})
if !ok || len(av) != len(bv) {
return false
}
for i, v := range av {
if !deepEqual(v, bv[i]) {
return false
}
}
return true
default:
return a == b
}
}
func TestWorkflowFileStruct(t *testing.T) {
wf := WorkflowFile{
Name: "test.yml",
Path: ".gitea/workflows/test.yml",
SHA: "abc123",
Size: 1024,
Content: map[string]interface{}{"name": "Test Workflow"},
RawContent: "name: Test Workflow",
Encoding: "base64",
}
if wf.Name != "test.yml" {
t.Fatalf("Name = %q, want %q", wf.Name, "test.yml")
}
if wf.Path != ".gitea/workflows/test.yml" {
t.Fatalf("Path = %q, want %q", wf.Path, ".gitea/workflows/test.yml")
}
}
func TestMatchPattern_EdgeCases(t *testing.T) {
tests := []struct {
filename string
pattern string
want bool
}{
// Edge cases for empty strings
{"", "*", true},
{"file.yml", "", false},
{"", "", true},
// Edge cases for special characters
{"file-name.yml", "*-name.yml", true},
{"file_name.yml", "*.yml", true},
{"file.name.yml", "*.yml", true},
// Edge case: only wildcard
{"anything", "*", true},
{"", "*", true},
// Edge case: pattern equals filename
{"exact.yml", "exact.yml", true},
{"exact.yml", "exact.yaml", false},
// Edge case: case sensitivity
{"FILE.YML", "*.yml", true},
{"File.Yml", "*.yml", true},
// Edge case: middle wildcards
{"build-test-deploy.yml", "*test*.yml", true},
{"build-prod-deploy.yml", "*test*.yml", false},
// Edge case: multiple extensions
{"file.tar.gz", "*.gz", true},
{"file.tar.gz", "*.tar.gz", true},
// Edge case: dots in filename
{".github/workflows/build.yml", "*.yml", true},
// Edge case: numeric patterns
{"build-123.yml", "build-*.yml", true},
{"build-abc.yml", "build-*.yml", true},
}
for _, tt := range tests {
t.Run(tt.filename+"_"+tt.pattern, func(t *testing.T) {
got := matchPattern(tt.filename, tt.pattern)
if got != tt.want {
t.Fatalf("matchPattern(%q, %q) = %v, want %v", tt.filename, tt.pattern, got, tt.want)
}
})
}
}
func TestConvertYamlToInterface_EdgeCases(t *testing.T) {
tests := []struct {
name string
input interface{}
expected interface{}
}{
{
name: "nil value",
input: nil,
expected: nil,
},
{
name: "empty map",
input: map[string]interface{}{},
expected: map[string]interface{}{},
},
{
name: "empty slice",
input: []interface{}{},
expected: []interface{}{},
},
{
name: "nested empty structures",
input: map[string]interface{}{
"empty_map": map[string]interface{}{},
"empty_slice": []interface{}{},
},
expected: map[string]interface{}{
"empty_map": map[string]interface{}{},
"empty_slice": []interface{}{},
},
},
{
name: "boolean value",
input: true,
expected: true,
},
{
name: "float value",
input: 3.14,
expected: 3.14,
},
{
name: "deeply nested map",
input: map[string]interface{}{
"level1": map[string]interface{}{
"level2": map[string]interface{}{
"level3": map[string]interface{}{
"value": "deep",
},
},
},
},
expected: map[string]interface{}{
"level1": map[string]interface{}{
"level2": map[string]interface{}{
"level3": map[string]interface{}{
"value": "deep",
},
},
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := convertYamlToInterface(tt.input)
if !deepEqual(got, tt.expected) {
t.Fatalf("convertYamlToInterface() = %v, want %v", got, tt.expected)
}
})
}
}
func TestWorkflowFileStruct_EdgeCases(t *testing.T) {
tests := []struct {
name string
file WorkflowFile
want WorkflowFile
}{
{
name: "empty file",
file: WorkflowFile{},
want: WorkflowFile{},
},
{
name: "file with zero size",
file: WorkflowFile{
Name: "empty.yml",
Path: ".gitea/workflows/empty.yml",
SHA: "abc123",
Size: 0,
Content: nil,
RawContent: "",
Encoding: "",
},
want: WorkflowFile{
Name: "empty.yml",
Path: ".gitea/workflows/empty.yml",
SHA: "abc123",
Size: 0,
},
},
{
name: "file with large size",
file: WorkflowFile{
Name: "large.yml",
Path: ".gitea/workflows/large.yml",
SHA: "def456",
Size: 1024 * 1024 * 10, // 10MB
Content: map[string]interface{}{"name": "Large Workflow"},
RawContent: "name: Large Workflow\\n# ... lots of content ...",
Encoding: "base64",
},
want: WorkflowFile{
Name: "large.yml",
Path: ".gitea/workflows/large.yml",
SHA: "def456",
Size: 1024 * 1024 * 10,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if tt.file.Name != tt.want.Name {
t.Errorf("Name = %q, want %q", tt.file.Name, tt.want.Name)
}
if tt.file.Path != tt.want.Path {
t.Errorf("Path = %q, want %q", tt.file.Path, tt.want.Path)
}
if tt.file.SHA != tt.want.SHA {
t.Errorf("SHA = %q, want %q", tt.file.SHA, tt.want.SHA)
}
if tt.file.Size != tt.want.Size {
t.Errorf("Size = %d, want %d", tt.file.Size, tt.want.Size)
}
})
}
}
func TestWorkflowFilesResultStruct_EdgeCases(t *testing.T) {
tests := []struct {
name string
result WorkflowFilesResult
}{
{
name: "empty result",
result: WorkflowFilesResult{
Directory: "",
Files: []WorkflowFile{},
TotalCount: 0,
},
},
{
name: "nil files",
result: WorkflowFilesResult{
Directory: ".gitea/workflows",
Files: nil,
TotalCount: 0,
},
},
{
name: "single file",
result: WorkflowFilesResult{
Directory: ".github/workflows",
Files: []WorkflowFile{
{Name: "ci.yml"},
},
TotalCount: 1,
},
},
{
name: "many files",
result: WorkflowFilesResult{
Directory: ".gitea/workflows",
Files: []WorkflowFile{
{Name: "build.yml"},
{Name: "test.yml"},
{Name: "deploy.yml"},
{Name: "lint.yml"},
{Name: "security.yml"},
},
TotalCount: 5,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if len(tt.result.Files) != tt.result.TotalCount {
t.Errorf("Files length (%d) != TotalCount (%d)", len(tt.result.Files), tt.result.TotalCount)
}
})
}
}