Files
beads/cmd/bd/show_test.go
beads/crew/emma a9c8c952f6 feat(show): add --id flag for IDs that look like flags
When an issue ID starts with dashes (e.g., gt--kzx), it can be
misinterpreted by Cobra's argument parser. The new --id flag allows
these IDs to be passed safely:

  bd show --id=gt--xyz

Multiple --id flags can be used, and they can be combined with
positional arguments.

Closes: bd-ix0ak

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-23 21:14:59 -08:00

197 lines
5.9 KiB
Go

package main
import (
"encoding/json"
"os/exec"
"path/filepath"
"strings"
"testing"
)
func TestShow_ExternalRef(t *testing.T) {
if testing.Short() {
t.Skip("skipping CLI test in short mode")
}
// Build bd binary
tmpBin := filepath.Join(t.TempDir(), "bd")
buildCmd := exec.Command("go", "build", "-o", tmpBin, "./")
buildCmd.Dir = "."
if out, err := buildCmd.CombinedOutput(); err != nil {
t.Fatalf("failed to build bd: %v\n%s", err, out)
}
// Create temp directory for test database
tmpDir := t.TempDir()
// Initialize beads
initCmd := exec.Command(tmpBin, "init", "--prefix", "test", "--quiet")
initCmd.Dir = tmpDir
if out, err := initCmd.CombinedOutput(); err != nil {
t.Fatalf("init failed: %v\n%s", err, out)
}
// Create issue with external ref
// Use --repo . to override auto-routing and create in the test directory
createCmd := exec.Command(tmpBin, "--no-daemon", "create", "External ref test", "-p", "1",
"--external-ref", "https://example.com/spec.md", "--json", "--repo", ".")
createCmd.Dir = tmpDir
createOut, err := createCmd.CombinedOutput()
if err != nil {
t.Fatalf("create failed: %v\n%s", err, createOut)
}
var issue map[string]interface{}
if err := json.Unmarshal(createOut, &issue); err != nil {
t.Fatalf("failed to parse create output: %v, output: %s", err, createOut)
}
id := issue["id"].(string)
// Show the issue and verify external ref is displayed
showCmd := exec.Command(tmpBin, "--no-daemon", "show", id)
showCmd.Dir = tmpDir
showOut, err := showCmd.CombinedOutput()
if err != nil {
t.Fatalf("show failed: %v\n%s", err, showOut)
}
out := string(showOut)
if !strings.Contains(out, "External:") {
t.Errorf("expected 'External:' in output, got: %s", out)
}
if !strings.Contains(out, "https://example.com/spec.md") {
t.Errorf("expected external ref URL in output, got: %s", out)
}
}
func TestShow_NoExternalRef(t *testing.T) {
if testing.Short() {
t.Skip("skipping CLI test in short mode")
}
// Build bd binary
tmpBin := filepath.Join(t.TempDir(), "bd")
buildCmd := exec.Command("go", "build", "-o", tmpBin, "./")
buildCmd.Dir = "."
if out, err := buildCmd.CombinedOutput(); err != nil {
t.Fatalf("failed to build bd: %v\n%s", err, out)
}
tmpDir := t.TempDir()
// Initialize beads
initCmd := exec.Command(tmpBin, "init", "--prefix", "test", "--quiet")
initCmd.Dir = tmpDir
if out, err := initCmd.CombinedOutput(); err != nil {
t.Fatalf("init failed: %v\n%s", err, out)
}
// Create issue WITHOUT external ref
// Use --repo . to override auto-routing and create in the test directory
createCmd := exec.Command(tmpBin, "--no-daemon", "create", "No ref test", "-p", "1", "--json", "--repo", ".")
createCmd.Dir = tmpDir
createOut, err := createCmd.CombinedOutput()
if err != nil {
t.Fatalf("create failed: %v\n%s", err, createOut)
}
var issue map[string]interface{}
if err := json.Unmarshal(createOut, &issue); err != nil {
t.Fatalf("failed to parse create output: %v, output: %s", err, createOut)
}
id := issue["id"].(string)
// Show the issue - should NOT contain External Ref line
showCmd := exec.Command(tmpBin, "--no-daemon", "show", id)
showCmd.Dir = tmpDir
showOut, err := showCmd.CombinedOutput()
if err != nil {
t.Fatalf("show failed: %v\n%s", err, showOut)
}
out := string(showOut)
if strings.Contains(out, "External:") {
t.Errorf("expected no 'External:' line for issue without external ref, got: %s", out)
}
}
func TestShow_IDFlag(t *testing.T) {
if testing.Short() {
t.Skip("skipping CLI test in short mode")
}
// Build bd binary
tmpBin := filepath.Join(t.TempDir(), "bd")
buildCmd := exec.Command("go", "build", "-o", tmpBin, "./")
buildCmd.Dir = "."
if out, err := buildCmd.CombinedOutput(); err != nil {
t.Fatalf("failed to build bd: %v\n%s", err, out)
}
tmpDir := t.TempDir()
// Initialize beads
initCmd := exec.Command(tmpBin, "init", "--prefix", "test", "--quiet")
initCmd.Dir = tmpDir
if out, err := initCmd.CombinedOutput(); err != nil {
t.Fatalf("init failed: %v\n%s", err, out)
}
// Create an issue
createCmd := exec.Command(tmpBin, "--no-daemon", "create", "ID flag test", "-p", "1", "--json", "--repo", ".")
createCmd.Dir = tmpDir
createOut, err := createCmd.CombinedOutput()
if err != nil {
t.Fatalf("create failed: %v\n%s", err, createOut)
}
var issue map[string]interface{}
if err := json.Unmarshal(createOut, &issue); err != nil {
t.Fatalf("failed to parse create output: %v, output: %s", err, createOut)
}
id := issue["id"].(string)
// Test 1: Using --id flag works
showCmd := exec.Command(tmpBin, "--no-daemon", "show", "--id="+id, "--short")
showCmd.Dir = tmpDir
showOut, err := showCmd.CombinedOutput()
if err != nil {
t.Fatalf("show with --id flag failed: %v\n%s", err, showOut)
}
if !strings.Contains(string(showOut), id) {
t.Errorf("expected issue ID in output, got: %s", showOut)
}
// Test 2: Multiple --id flags work
showCmd2 := exec.Command(tmpBin, "--no-daemon", "show", "--id="+id, "--id="+id, "--short")
showCmd2.Dir = tmpDir
showOut2, err := showCmd2.CombinedOutput()
if err != nil {
t.Fatalf("show with multiple --id flags failed: %v\n%s", err, showOut2)
}
// Should see the ID twice (one for each --id flag)
if strings.Count(string(showOut2), id) != 2 {
t.Errorf("expected issue ID twice in output, got: %s", showOut2)
}
// Test 3: Combining positional and --id flag
showCmd3 := exec.Command(tmpBin, "--no-daemon", "show", id, "--id="+id, "--short")
showCmd3.Dir = tmpDir
showOut3, err := showCmd3.CombinedOutput()
if err != nil {
t.Fatalf("show with positional + --id failed: %v\n%s", err, showOut3)
}
// Should see the ID twice
if strings.Count(string(showOut3), id) != 2 {
t.Errorf("expected issue ID twice in output, got: %s", showOut3)
}
// Test 4: No args at all should fail
showCmd4 := exec.Command(tmpBin, "--no-daemon", "show")
showCmd4.Dir = tmpDir
_, err = showCmd4.CombinedOutput()
if err == nil {
t.Error("expected error when no ID provided, but command succeeded")
}
}