Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 90 additions & 0 deletions internal/output/output_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2114,6 +2114,96 @@ func TestFormatCellCollapsesNewlines(t *testing.T) {
})
}

func TestFormatCellDoesNotTruncateURLs(t *testing.T) {
longURL := "https://3.basecampapi.com/1234567/buckets/12345678/todolists/9876543210.json"

t.Run("long URL preserved", func(t *testing.T) {
result := formatCell(longURL)
assert.Equal(t, longURL, result)
})

t.Run("non-URL still truncated", func(t *testing.T) {
long := "This is a very long string that exceeds forty runes"
result := formatCell(long)
assert.Equal(t, "This is a very long string that excee...", result)
})

t.Run("short URL unchanged", func(t *testing.T) {
short := "https://example.com"
result := formatCell(short)
assert.Equal(t, short, result)
})

t.Run("http URL preserved", func(t *testing.T) {
httpURL := "http://3.basecampapi.com/1234567/buckets/12345678/todolists/9876543210.json"
result := formatCell(httpURL)
assert.Equal(t, httpURL, result)
})

t.Run("URL-like string with spaces is truncated", func(t *testing.T) {
// After newline collapsing, a value like "https://example.com\n(extra...)"
// becomes "https://example.com (extra...)" — not a real URL.
notURL := "https://example.com (extra text that makes this quite long)"
result := formatCell(notURL)
assert.Len(t, []rune(result), 40)
assert.True(t, strings.HasSuffix(result, "..."))
})
}

func TestStyledRenderObjectPreservesURLs(t *testing.T) {
url := "https://3.basecampapi.com/1234567/buckets/12345678/todolists/9876543210.json"
data := map[string]any{
"name": "Todoset",
"app_todolists_url": url,
}
var buf bytes.Buffer
w := New(Options{Format: FormatStyled, Writer: &buf})
err := w.OK(data)
require.NoError(t, err)

assert.Contains(t, buf.String(), url)
}

func TestMarkdownRenderObjectPreservesURLs(t *testing.T) {
url := "https://3.basecampapi.com/1234567/buckets/12345678/todolists/9876543210.json"
data := map[string]any{
"name": "Todoset",
"todolists_url": url,
}
var buf bytes.Buffer
w := New(Options{Format: FormatMarkdown, Writer: &buf})
err := w.OK(data)
require.NoError(t, err)

assert.Contains(t, buf.String(), url)
}

func TestStyledRenderTablePreservesURLs(t *testing.T) {
url := "https://3.basecampapi.com/1234567/buckets/12345678/todolists/9876543210.json"
data := []any{
map[string]any{"name": "Tasks", "todolists_url": url},
}
var buf bytes.Buffer
w := New(Options{Format: FormatStyled, Writer: &buf})
err := w.OK(data)
require.NoError(t, err)

assert.Contains(t, buf.String(), url)
}

func TestMarkdownRenderTablePreservesURLs(t *testing.T) {
url := "https://3.basecampapi.com/1234567/buckets/12345678/todolists/9876543210.json"
data := []any{
map[string]any{"name": "Tasks", "todolists_url": url},
}
var buf bytes.Buffer
w := New(Options{Format: FormatMarkdown, Writer: &buf})
err := w.OK(data)
require.NoError(t, err)

assert.Contains(t, buf.String(), url)
}

func TestRenderDataStripsEscapesFromTopLevelStrings(t *testing.T) {
tests := []struct {
name string
Expand Down
10 changes: 8 additions & 2 deletions internal/output/render.go
Original file line number Diff line number Diff line change
Expand Up @@ -670,8 +670,9 @@ func formatCell(val any) string {
if strings.ContainsAny(v, "\n\r") {
v = strings.Join(strings.Fields(v), " ")
}
// Truncate long strings (rune-safe for multi-byte UTF-8)
if utf8.RuneCountInString(v) > 40 {
// Truncate long strings (rune-safe for multi-byte UTF-8).
// HTTP(S) URLs are never truncated — a truncated URL is useless.
if utf8.RuneCountInString(v) > 40 && !isURL(v) {
Comment thread
jeremy marked this conversation as resolved.
Resolved
runes := []rune(v)
return string(runes[:37]) + "..."
}
Expand Down Expand Up @@ -733,6 +734,11 @@ func formatCell(val any) string {
}
}

func isURL(s string) bool {
return (strings.HasPrefix(s, "https://") || strings.HasPrefix(s, "http://")) &&
!strings.ContainsRune(s, ' ')
}
Comment thread
jeremy marked this conversation as resolved.
Resolved

// formatDateValue formats date fields in a human-readable way.
// For date columns (created_at, updated_at, due_on, due_date), it converts
// ISO8601 timestamps to a more readable format.
Expand Down
Loading