Files
beads/cmd/bd/markdown_test.go
Steve Yegge a86f3e139e Add native Windows support (#91)
- Native Windows daemon using TCP loopback endpoints
- Direct-mode fallback for CLI/daemon compatibility
- Comment operations over RPC
- PowerShell installer script
- Go 1.24 requirement
- Cross-OS testing documented

Co-authored-by: danshapiro <danshapiro@users.noreply.github.com>
Amp-Thread-ID: https://ampcode.com/threads/T-c6230265-055f-4af1-9712-4481061886db
Co-authored-by: Amp <amp@ampcode.com>
2025-10-20 21:08:49 -07:00

239 lines
5.1 KiB
Go

package main
import (
"os"
"path/filepath"
"testing"
)
func TestParseMarkdownFile(t *testing.T) {
tests := []struct {
name string
content string
expected []*IssueTemplate
wantErr bool
}{
{
name: "simple issue",
content: `## Fix authentication bug
This is a critical bug in the auth system.
### Priority
1
### Type
bug
`,
expected: []*IssueTemplate{
{
Title: "Fix authentication bug",
Description: "This is a critical bug in the auth system.",
Priority: 1,
IssueType: "bug",
},
},
},
{
name: "multiple issues",
content: `## First Issue
Description for first issue.
### Priority
0
### Type
feature
## Second Issue
Description for second issue.
### Priority
2
### Type
task
`,
expected: []*IssueTemplate{
{
Title: "First Issue",
Description: "Description for first issue.",
Priority: 0,
IssueType: "feature",
},
{
Title: "Second Issue",
Description: "Description for second issue.",
Priority: 2,
IssueType: "task",
},
},
},
{
name: "issue with all fields",
content: `## Comprehensive Issue
Initial description text.
### Priority
1
### Type
feature
### Description
Detailed description here.
Multi-line support.
### Design
Design notes go here.
### Acceptance Criteria
- Must do this
- Must do that
### Assignee
alice
### Labels
backend, urgent
### Dependencies
bd-10, bd-20
`,
expected: []*IssueTemplate{
{
Title: "Comprehensive Issue",
Description: "Detailed description here.\nMulti-line support.",
Design: "Design notes go here.",
AcceptanceCriteria: "- Must do this\n- Must do that",
Priority: 1,
IssueType: "feature",
Assignee: "alice",
Labels: []string{"backend", "urgent"},
Dependencies: []string{"bd-10", "bd-20"},
},
},
},
{
name: "dependencies with types",
content: `## Issue with typed dependencies
### Priority
2
### Type
task
### Dependencies
blocks:bd-10, discovered-from:bd-20
`,
expected: []*IssueTemplate{
{
Title: "Issue with typed dependencies",
Priority: 2,
IssueType: "task",
Dependencies: []string{"blocks:bd-10", "discovered-from:bd-20"},
},
},
},
{
name: "default values",
content: `## Minimal Issue
Just a title and description.
`,
expected: []*IssueTemplate{
{
Title: "Minimal Issue",
Description: "Just a title and description.",
Priority: 2, // default
IssueType: "task", // default
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// Create temp file
tmpDir := t.TempDir()
tmpFile := filepath.Join(tmpDir, "test.md")
if err := os.WriteFile(tmpFile, []byte(tt.content), 0600); err != nil {
t.Fatalf("Failed to create test file: %v", err)
}
// Parse file
got, err := parseMarkdownFile(tmpFile)
if (err != nil) != tt.wantErr {
t.Errorf("parseMarkdownFile() error = %v, wantErr %v", err, tt.wantErr)
return
}
if len(got) != len(tt.expected) {
t.Errorf("parseMarkdownFile() got %d issues, want %d", len(got), len(tt.expected))
return
}
// Compare each issue
for i, gotIssue := range got {
wantIssue := tt.expected[i]
if gotIssue.Title != wantIssue.Title {
t.Errorf("Issue %d: Title = %q, want %q", i, gotIssue.Title, wantIssue.Title)
}
if gotIssue.Description != wantIssue.Description {
t.Errorf("Issue %d: Description = %q, want %q", i, gotIssue.Description, wantIssue.Description)
}
if gotIssue.Priority != wantIssue.Priority {
t.Errorf("Issue %d: Priority = %d, want %d", i, gotIssue.Priority, wantIssue.Priority)
}
if gotIssue.IssueType != wantIssue.IssueType {
t.Errorf("Issue %d: IssueType = %q, want %q", i, gotIssue.IssueType, wantIssue.IssueType)
}
if gotIssue.Design != wantIssue.Design {
t.Errorf("Issue %d: Design = %q, want %q", i, gotIssue.Design, wantIssue.Design)
}
if gotIssue.AcceptanceCriteria != wantIssue.AcceptanceCriteria {
t.Errorf("Issue %d: AcceptanceCriteria = %q, want %q", i, gotIssue.AcceptanceCriteria, wantIssue.AcceptanceCriteria)
}
if gotIssue.Assignee != wantIssue.Assignee {
t.Errorf("Issue %d: Assignee = %q, want %q", i, gotIssue.Assignee, wantIssue.Assignee)
}
// Compare slices
if !stringSlicesEqual(gotIssue.Labels, wantIssue.Labels) {
t.Errorf("Issue %d: Labels = %v, want %v", i, gotIssue.Labels, wantIssue.Labels)
}
if !stringSlicesEqual(gotIssue.Dependencies, wantIssue.Dependencies) {
t.Errorf("Issue %d: Dependencies = %v, want %v", i, gotIssue.Dependencies, wantIssue.Dependencies)
}
}
})
}
}
func TestParseMarkdownFile_FileNotFound(t *testing.T) {
_, err := parseMarkdownFile("/nonexistent/file.md")
if err == nil {
t.Error("Expected error for non-existent file, got nil")
}
}
func stringSlicesEqual(a, b []string) bool {
if len(a) != len(b) {
return false
}
if len(a) == 0 && len(b) == 0 {
return true
}
for i := range a {
if a[i] != b[i] {
return false
}
}
return true
}