package paperformatter import ( "os" "path/filepath" "strings" "testing" ) func TestFormatPapers(t *testing.T) { // Create temporary directory for test files tmpDir, err := os.MkdirTemp("", "paperformatter-test-*") if err != nil { t.Fatalf("Failed to create temp directory: %v", err) } defer os.RemoveAll(tmpDir) tests := []struct { name string input string wantErr bool errContains string checkOutput func(t *testing.T, output string) }{ { name: "happy path - mixed decisions", input: `[ { "paper": { "title": "Test Paper 1", "abstract": "Abstract 1", "arxiv_id": "2301.0001" }, "decision": "accept", "explanation": "Good paper" }, { "paper": { "title": "Test Paper 2", "abstract": "Abstract 2", "arxiv_id": "2301.0002" }, "decision": "reject", "explanation": "Needs work" } ]`, wantErr: false, checkOutput: func(t *testing.T, output string) { // Check sections exist if !strings.Contains(output, "# Accepted Papers") { t.Error("Output missing Accepted Papers section") } if !strings.Contains(output, "# Rejected Papers") { t.Error("Output missing Rejected Papers section") } // Check paper details if !strings.Contains(output, "## Test Paper 1") { t.Error("Output missing accepted paper title") } if !strings.Contains(output, "## Test Paper 2") { t.Error("Output missing rejected paper title") } // Check formatting if !strings.Contains(output, "[arXiv:2301.0001]") { t.Error("Output missing arXiv link for accepted paper") } if !strings.Contains(output, "> Abstract 1") { t.Error("Output missing abstract blockquote for accepted paper") } if !strings.Contains(output, "**Decision:** accept") { t.Error("Output missing decision for accepted paper") } }, }, { name: "empty input array", input: `[]`, wantErr: false, checkOutput: func(t *testing.T, output string) { if !strings.Contains(output, "# Accepted Papers") { t.Error("Output missing Accepted Papers section") } if !strings.Contains(output, "# Rejected Papers") { t.Error("Output missing Rejected Papers section") } }, }, { name: "invalid JSON", input: `not json`, wantErr: true, errContains: "JSON parsing error", }, { name: "missing title", input: `[ { "paper": { "title": "", "abstract": "Abstract", "arxiv_id": "2301.0001" }, "decision": "accept", "explanation": "Good paper" } ]`, wantErr: true, errContains: "validation error for title: title cannot be empty", }, { name: "missing abstract", input: `[ { "paper": { "title": "Test Paper", "abstract": "", "arxiv_id": "2301.0001" }, "decision": "accept", "explanation": "Good paper" } ]`, wantErr: true, errContains: "validation error for abstract: abstract cannot be empty", }, { name: "invalid decision", input: `[ { "paper": { "title": "Test Paper", "abstract": "Abstract", "arxiv_id": "2301.0001" }, "decision": "maybe", "explanation": "Good paper" } ]`, wantErr: true, errContains: "decision must be either 'accept' or 'reject'", }, { name: "case insensitive decision", input: `[ { "paper": { "title": "Test Paper", "abstract": "Abstract", "arxiv_id": "2301.0001" }, "decision": "ACCEPT", "explanation": "Good paper" } ]`, wantErr: false, checkOutput: func(t *testing.T, output string) { if !strings.Contains(output, "## Test Paper") { t.Error("Output missing paper with uppercase decision") } }, }, { name: "multiline abstract", input: `[ { "paper": { "title": "Test Paper", "abstract": "Line 1\nLine 2\nLine 3", "arxiv_id": "2301.0001" }, "decision": "accept", "explanation": "Good paper" } ]`, wantErr: false, checkOutput: func(t *testing.T, output string) { if !strings.Contains(output, "> Line 1\n> Line 2\n> Line 3") { t.Error("Output not handling multiline abstract correctly") } }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { // Create input file inputPath := filepath.Join(tmpDir, "input.json") if err := os.WriteFile(inputPath, []byte(tt.input), 0644); err != nil { t.Fatalf("Failed to write input file: %v", err) } // Create output path outputPath := filepath.Join(tmpDir, "output.md") // Run the formatter err := FormatPapers(inputPath, outputPath) // Check error cases if tt.wantErr { if err == nil { t.Error("Expected error but got none") } else if tt.errContains != "" && !strings.Contains(err.Error(), tt.errContains) { t.Errorf("Expected error containing %q but got %q", tt.errContains, err.Error()) } return } // Check success cases if err != nil { t.Fatalf("Unexpected error: %v", err) } // Read and verify output output, err := os.ReadFile(outputPath) if err != nil { t.Fatalf("Failed to read output file: %v", err) } if tt.checkOutput != nil { tt.checkOutput(t, string(output)) } }) } } func TestFormatPapersFileErrors(t *testing.T) { // Test non-existent input file err := FormatPapers("nonexistent.json", "output.md") if err == nil { t.Error("Expected error for non-existent input file") } // Test invalid output path tmpfile, err := os.CreateTemp("", "test.json") if err != nil { t.Fatalf("Failed to create temp file: %v", err) } defer os.Remove(tmpfile.Name()) err = FormatPapers(tmpfile.Name(), "/nonexistent/directory/output.md") if err == nil { t.Error("Expected error for invalid output path") } }