Files
larksuite-cli/internal/output/flatten_test.go
梁硕 83dfb068ad feat: open-source lark-cli — the official CLI for Lark/Feishu
Change-Id: I113d9cdb5403cec347efe4595415e34a18b7decf
2026-03-28 10:36:25 +08:00

163 lines
3.6 KiB
Go

// Copyright (c) 2026 Lark Technologies Pte. Ltd.
// SPDX-License-Identifier: MIT
package output
import (
"testing"
)
func TestFlattenObjectSimple(t *testing.T) {
obj := map[string]interface{}{
"name": "Alice",
"age": float64(30),
}
entries := flattenObject(obj, "", 0)
m := rowMap(entries)
if m["name"] != "Alice" {
t.Errorf("name = %q, want %q", m["name"], "Alice")
}
if m["age"] != "30" {
t.Errorf("age = %q, want %q", m["age"], "30")
}
}
func TestFlattenObjectNested(t *testing.T) {
obj := map[string]interface{}{
"user": map[string]interface{}{
"name": "Alice",
"addr": map[string]interface{}{
"city": "Beijing",
},
},
}
entries := flattenObject(obj, "", 0)
m := rowMap(entries)
if m["user.name"] != "Alice" {
t.Errorf("user.name = %q, want %q", m["user.name"], "Alice")
}
if m["user.addr.city"] != "Beijing" {
t.Errorf("user.addr.city = %q, want %q", m["user.addr.city"], "Beijing")
}
}
func TestFlattenObjectDeepLimit(t *testing.T) {
// Create depth=4 nesting — should serialize the innermost object as JSON
obj := map[string]interface{}{
"a": map[string]interface{}{
"b": map[string]interface{}{
"c": map[string]interface{}{
"d": "deep",
},
},
},
}
entries := flattenObject(obj, "", 0)
m := rowMap(entries)
// depth 0 → a (map), depth 1 → b (map), depth 2 → c (map), depth 3 ≥ maxFlattenDepth → serialize
if v, ok := m["a.b.c"]; !ok {
t.Errorf("expected key a.b.c, got keys: %v", m)
} else if v != `{"d":"deep"}` {
t.Errorf("a.b.c = %q, want JSON string", v)
}
}
func TestFlattenObjectArrayLeaf(t *testing.T) {
obj := map[string]interface{}{
"tags": []interface{}{"a", "b"},
}
entries := flattenObject(obj, "", 0)
m := rowMap(entries)
if m["tags"] != `["a","b"]` {
t.Errorf("tags = %q, want %q", m["tags"], `["a","b"]`)
}
}
func TestFlattenObjectNilValue(t *testing.T) {
obj := map[string]interface{}{
"empty": nil,
}
entries := flattenObject(obj, "", 0)
m := rowMap(entries)
if m["empty"] != "" {
t.Errorf("empty = %q, want %q", m["empty"], "")
}
}
func TestCollectColumns(t *testing.T) {
rows := [][]flatEntry{
{{Key: "a", Value: "1"}, {Key: "b", Value: "2"}},
{{Key: "b", Value: "3"}, {Key: "c", Value: "4"}},
}
cols := collectColumns(rows)
// Should contain a, b, c (union)
colSet := map[string]bool{}
for _, c := range cols {
colSet[c] = true
}
for _, expected := range []string{"a", "b", "c"} {
if !colSet[expected] {
t.Errorf("missing column %q in %v", expected, cols)
}
}
if len(cols) != 3 {
t.Errorf("got %d columns, want 3", len(cols))
}
}
func TestTruncateToWidth(t *testing.T) {
tests := []struct {
input string
maxWidth int
want string
}{
{"hello", 10, "hello"},
{"hello", 5, "hello"},
{"hello", 4, "hell…"},
{"hello", 3, "hel…"},
{"hello", 1, "h…"},
{"hello", 0, ""},
// CJK: each char is width 2
{"你好世界", 8, "你好世界"},
{"你好世界", 6, "你好世…"},
{"你好世界", 4, "你好…"},
{"你好世界", 3, "你…"},
}
for _, tt := range tests {
t.Run(tt.input, func(t *testing.T) {
got := truncateToWidth(tt.input, tt.maxWidth)
if got != tt.want {
t.Errorf("truncateToWidth(%q, %d) = %q, want %q", tt.input, tt.maxWidth, got, tt.want)
}
})
}
}
func TestStringWidth(t *testing.T) {
tests := []struct {
input string
want int
}{
{"hello", 5},
{"你好", 4},
{"ab你好cd", 8},
{"", 0},
}
for _, tt := range tests {
t.Run(tt.input, func(t *testing.T) {
got := stringWidth(tt.input)
if got != tt.want {
t.Errorf("stringWidth(%q) = %d, want %d", tt.input, got, tt.want)
}
})
}
}