Opens a modal with a text field supporting autocomplete of column names. Enter comma-separated column names in priority order; rows are sorted ascending using locale-aware numeric comparison, first by the first column, then by the second, and so on. Autocomplete filters to matching headers, excludes already-chosen columns, and supports keyboard navigation (arrows + enter). Co-authored-by: Shelley <shelley@exe.dev>
125 lines
2.8 KiB
Go
125 lines
2.8 KiB
Go
package main
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestFormatAsMarkdown(t *testing.T) {
|
|
app := NewApp()
|
|
headers := []string{"Name", "Age", "City"}
|
|
rows := [][]string{
|
|
{"Alice", "30", "New York"},
|
|
{"Bob", "25", "SF"},
|
|
}
|
|
result := app.FormatAsMarkdown(headers, rows)
|
|
expected := `| Name | Age | City |
|
|
| --- | --- | --- |
|
|
| Alice | 30 | New York |
|
|
| Bob | 25 | SF |
|
|
`
|
|
if result != expected {
|
|
t.Errorf("FormatAsMarkdown:\ngot:\n%s\nwant:\n%s", result, expected)
|
|
}
|
|
}
|
|
|
|
func TestFormatAsJira(t *testing.T) {
|
|
app := NewApp()
|
|
headers := []string{"Name", "Age"}
|
|
rows := [][]string{
|
|
{"Alice", "30"},
|
|
}
|
|
result := app.FormatAsJira(headers, rows)
|
|
expected := `|| Name || Age ||
|
|
| Alice | 30 |
|
|
`
|
|
if result != expected {
|
|
t.Errorf("FormatAsJira:\ngot:\n%s\nwant:\n%s", result, expected)
|
|
}
|
|
}
|
|
|
|
func TestFormatAsSingleColumn(t *testing.T) {
|
|
app := NewApp()
|
|
rows := [][]string{{"Alice"}, {"Bob"}, {"Charlie"}}
|
|
result := app.FormatAsSingleColumn(rows)
|
|
if result != "Alice\nBob\nCharlie" {
|
|
t.Errorf("FormatAsSingleColumn: got %q", result)
|
|
}
|
|
}
|
|
|
|
func TestFormatRowsAsCSV(t *testing.T) {
|
|
app := NewApp()
|
|
rows := [][]string{
|
|
{"Alice", "30", "New York"},
|
|
{"Bob", "25", "San Francisco"},
|
|
}
|
|
result := app.FormatRowsAsCSV(rows)
|
|
lines := strings.Split(strings.TrimSpace(result), "\n")
|
|
if len(lines) != 2 {
|
|
t.Fatalf("expected 2 lines, got %d: %v", len(lines), lines)
|
|
}
|
|
if lines[0] != "Alice,30,New York" {
|
|
t.Errorf("line 0: got %q", lines[0])
|
|
}
|
|
}
|
|
|
|
func TestFormatAsCSV(t *testing.T) {
|
|
app := NewApp()
|
|
headers := []string{"Name", "Age"}
|
|
rows := [][]string{{"Alice", "30"}}
|
|
result := app.FormatAsCSV(headers, rows)
|
|
lines := strings.Split(strings.TrimSpace(result), "\n")
|
|
if len(lines) != 2 {
|
|
t.Fatalf("expected 2 lines, got %d", len(lines))
|
|
}
|
|
if lines[0] != "Name,Age" {
|
|
t.Errorf("header line: got %q", lines[0])
|
|
}
|
|
}
|
|
|
|
func TestParseCSVString(t *testing.T) {
|
|
app := NewApp()
|
|
input := "Name,Age\nAlice,30\nBob,25"
|
|
data, err := app.ParseCSVString(input)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(data.Headers) != 2 {
|
|
t.Errorf("headers: got %d", len(data.Headers))
|
|
}
|
|
if len(data.Rows) != 2 {
|
|
t.Errorf("rows: got %d", len(data.Rows))
|
|
}
|
|
if data.Headers[0] != "Name" {
|
|
t.Errorf("header[0]: got %q", data.Headers[0])
|
|
}
|
|
}
|
|
|
|
func TestGetCommands(t *testing.T) {
|
|
reg := NewCommandRegistry()
|
|
cmds := reg.GetCommands()
|
|
if len(cmds) != 15 {
|
|
t.Errorf("expected 12 commands, got %d", len(cmds))
|
|
}
|
|
// Check that all have IDs
|
|
for _, cmd := range cmds {
|
|
if cmd.ID == "" {
|
|
t.Error("found command with empty ID")
|
|
}
|
|
if cmd.Name == "" {
|
|
t.Error("found command with empty Name")
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestPadRow(t *testing.T) {
|
|
row := []string{"a", "b"}
|
|
padded := padRow(row, 4)
|
|
if len(padded) != 4 {
|
|
t.Errorf("expected 4 cols, got %d", len(padded))
|
|
}
|
|
if padded[2] != "" || padded[3] != "" {
|
|
t.Error("expected empty padding")
|
|
}
|
|
}
|