lipgloss/list/list_test.go
Carlos Alexandro Becker d21c576fdf
feat: trees and lists (#264)
* feat: implement list renderer

* feat: data model for list

* feat: add Offset, Height, Indent

* feat: tree renderer

* fix: list example

* test: last tree node is a subtree

Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>

* fix: tree

Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>

* fix: lint

Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>

* docs: example

Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>

* test: inc cov

Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>

* fix: multiline items

Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>

* feat: one approach to sublists

Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>

* fix: tree improvements

* wip

Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>

* wip

Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>

* wip

Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>

* wip

Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>

* fix: prevent having to pass renderer to all trees

* test: force linux line endings

* fix: windows

* fix: lint issues

* fix: ignore lint issue failing forever

* fix: renames

* fix: renderer

* ci: fix coveralls hopefully

* wip

Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>

* fix: style

* docs: update

Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>

* fix: renderer

Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>

* test: cover with tests

Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>

* feat: more list enumerators

* fix: drop renderer api

Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>

* feat: improve api

Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>

* fix: prealloc

* fix: clean up

* fix: list setup

* fix: improve sublist tests

* fix: improve sublists

* refactor: simplify

* docs: more examples, readme updates

Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>

* docs: readme

* fix: set item style

* fix(tree): do not use golden files

* test: do not use golden files

* refactor: remove unused code

* feat: hide nodes

* feat: filter

* fix: allow fmt.Stringer

* test: table within a tree

* docs: update

* fix: rename atter to data

* test: test public api only

* docs: sublist with table example

* docs: update example

* fix: lint issues

Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>

* docs: update examples

* docs: update

* feat: offset

* feat: offsetstart && offsetend

* fix: remove last from enumerator

* refactor: make tree more explicit

* `New()` now take no args
* added a new `Root(string)` method
* added a new `Items(...any)` method

* refactor: improve list

* docs: fix examples

* test: ensure embed lists in trees

* docs: sublist example with list as tree node

Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>

* refactor: first pass at examples cleanup

* refactor: first pass at examples cleanup

* fix: support multi-line prefixes

* test: more glow-style lists within trees

* docs: simplify examples

* fix: improve handling of different types

* chore: go mod tidy

Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>

* fix: code review suggestions

Co-authored-by: Ayman Bagabas <ayman.bagabas@gmail.com>
Co-authored-by: bashbunni <15822994+bashbunni@users.noreply.github.com>

* fix: apply code review suggestion

* feat(tree): rounded enumerator (#280)

* chore(examples): go mod tidy

* feat(tree): add rounded corner enumerator

* test: rounded enumerator test

* docs: readme updates

Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>

* docs: readme updates

Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>

* chore: fmt

Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>

* docs: godoc

* docs: godoc

* fix: bash's issue

* fix: bad example

Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>

* docs: improve godoc for trees and lists (#296)

* docs(godoc): add overview

* docs(godoc): include examples in godoc

* docs(godoc): fix roman numerals example

* docs(godoc): fix tree examples

* docs(godoc): attempt to fix list Enumerator examples

* docs: added some examples to godoc

* fix(list): New(items...) with sublist

* docs: update examples

* chore(tree): improve var names in rounded example

* fix: use padding instead of margin to better styles

* fix: lint

---------

Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>
Co-authored-by: Maas Lalani <maas@lalani.dev>
Co-authored-by: Ayman Bagabas <ayman.bagabas@gmail.com>
Co-authored-by: bashbunni <15822994+bashbunni@users.noreply.github.com>
Co-authored-by: Christian Rocha <christian@rocha.is>
2024-05-24 12:02:18 -03:00

548 lines
9.4 KiB
Go

package list_test
import (
"fmt"
"strings"
"testing"
"github.com/charmbracelet/lipgloss"
"github.com/charmbracelet/lipgloss/internal/require"
"github.com/charmbracelet/lipgloss/list"
"github.com/charmbracelet/lipgloss/tree"
)
// XXX: can't write multi-line examples if the underlying string uses
// lipgloss.JoinVertical.
func ExampleNew() {
list := list.New().
Item("First")
fmt.Print(list)
// Output:• First
}
func ExampleNew_customEnumerator() {
list := list.New().
Enumerator(list.Arabic).
Item("First")
fmt.Print(list)
// Output:1. First
}
func TestList(t *testing.T) {
l := list.New().
Item("Foo").
Item("Bar").
Item("Baz")
expected := `
• Foo
• Bar
• Baz
`
require.Equal(t, expected, l.String())
}
func TestListItems(t *testing.T) {
l := list.New().
Items([]string{"Foo", "Bar", "Baz"})
expected := `
• Foo
• Bar
• Baz
`
require.Equal(t, expected, l.String())
}
func TestSublist(t *testing.T) {
l := list.New().
Item("Foo").
Item("Bar").
Item(list.New("Hi", "Hello", "Halo").Enumerator(list.Roman)).
Item("Qux")
expected := `
• Foo
• Bar
I. Hi
II. Hello
III. Halo
• Qux
`
require.Equal(t, expected, l.String())
}
func TestSublistItems(t *testing.T) {
l := list.New(
"A",
"B",
"C",
list.New(
"D",
"E",
"F",
).Enumerator(list.Roman),
"G",
)
expected := `
• A
• B
• C
I. D
II. E
III. F
• G
`
require.Equal(t, expected, l.String())
}
func TestComplexSublist(t *testing.T) {
style1 := lipgloss.NewStyle().
Foreground(lipgloss.Color("99")).
PaddingRight(1)
style2 := lipgloss.NewStyle().
Foreground(lipgloss.Color("212")).
PaddingRight(1)
l := list.New().
Item("Foo").
Item("Bar").
Item(list.New("foo2", "bar2")).
Item("Qux").
Item(
list.New("aaa", "bbb").
EnumeratorStyle(style1).
Enumerator(list.Roman),
).
Item("Deep").
Item(
list.New().
EnumeratorStyle(style2).
Enumerator(list.Alphabet).
Item("foo").
Item("Deeper").
Item(
list.New().
EnumeratorStyle(style1).
Enumerator(list.Arabic).
Item("a").
Item("b").
Item("Even Deeper, inherit parent renderer").
Item(
list.New().
Enumerator(list.Asterisk).
EnumeratorStyle(style2).
Item("sus").
Item("d minor").
Item("f#").
Item("One ore level, with another renderer").
Item(
list.New().
EnumeratorStyle(style1).
Enumerator(list.Dash).
Item("a\nmultine\nstring").
Item("hoccus poccus").
Item("abra kadabra").
Item("And finally, a tree within all this").
Item(
tree.New().
EnumeratorStyle(style2).
Item("another\nmultine\nstring").
Item("something").
Item("a subtree").
Item(
tree.New().
EnumeratorStyle(style2).
Item("yup").
Item("many itens").
Item("another"),
).
Item("hallo").
Item("wunderbar!"),
).
Item("this is a tree\nand other obvious statements"),
),
),
).
Item("bar"),
).
Item("Baz")
expected := `
• Foo
• Bar
• foo2
• bar2
• Qux
I. aaa
II. bbb
• Deep
A. foo
B. Deeper
1. a
2. b
3. Even Deeper, inherit parent renderer
* sus
* d minor
* f#
* One ore level, with another renderer
- a
multine
string
- hoccus poccus
- abra kadabra
- And finally, a tree within all this
├── another
│ multine
│ string
├── something
├── a subtree
│ ├── yup
│ ├── many itens
│ └── another
├── hallo
└── wunderbar!
- this is a tree
and other obvious statements
C. bar
• Baz
`
require.Equal(t, expected, l.String())
}
func TestMultiline(t *testing.T) {
l := list.New().
Item("Item1\nline 2\nline 3").
Item("Item2\nline 2\nline 3").
Item("3")
expected := `
• Item1
line 2
line 3
• Item2
line 2
line 3
• 3
`
require.Equal(t, expected, l.String())
}
func TestListIntegers(t *testing.T) {
l := list.New().
Item("1").
Item("2").
Item("3")
expected := `
• 1
• 2
• 3
`
require.Equal(t, expected, l.String())
}
func TestEnumerators(t *testing.T) {
tests := map[string]struct {
enumerator list.Enumerator
expected string
}{
"alphabet": {
enumerator: list.Alphabet,
expected: `
A. Foo
B. Bar
C. Baz
`,
},
"arabic": {
enumerator: list.Arabic,
expected: `
1. Foo
2. Bar
3. Baz
`,
},
"roman": {
enumerator: list.Roman,
expected: `
I. Foo
II. Bar
III. Baz
`,
},
"bullet": {
enumerator: list.Bullet,
expected: `
• Foo
• Bar
• Baz
`,
},
"asterisk": {
enumerator: list.Asterisk,
expected: `
* Foo
* Bar
* Baz
`,
},
"dash": {
enumerator: list.Dash,
expected: `
- Foo
- Bar
- Baz
`,
},
}
for name, test := range tests {
t.Run(name, func(t *testing.T) {
l := list.New().
Enumerator(test.enumerator).
Item("Foo").
Item("Bar").
Item("Baz")
require.Equal(t, test.expected, l.String())
})
}
}
func TestEnumeratorsTransform(t *testing.T) {
tests := map[string]struct {
enumeration list.Enumerator
style lipgloss.Style
expected string
}{
"alphabet lower": {
enumeration: list.Alphabet,
style: lipgloss.NewStyle().PaddingRight(1).Transform(strings.ToLower),
expected: `
a. Foo
b. Bar
c. Baz
`,
},
"arabic)": {
enumeration: list.Arabic,
style: lipgloss.NewStyle().PaddingRight(1).Transform(func(s string) string {
return strings.Replace(s, ".", ")", 1)
}),
expected: `
1) Foo
2) Bar
3) Baz
`,
},
"roman within ()": {
enumeration: list.Roman,
style: lipgloss.NewStyle().Transform(func(s string) string {
return "(" + strings.Replace(strings.ToLower(s), ".", "", 1) + ") "
}),
expected: `
(i) Foo
(ii) Bar
(iii) Baz
`,
},
"bullet is dash": {
enumeration: list.Bullet,
style: lipgloss.NewStyle().Transform(func(s string) string {
return "- " // this is better done by replacing the enumerator.
}),
expected: `
- Foo
- Bar
- Baz
`,
},
}
for name, test := range tests {
t.Run(name, func(t *testing.T) {
l := list.New().
EnumeratorStyle(test.style).
Enumerator(test.enumeration).
Item("Foo").
Item("Bar").
Item("Baz")
require.Equal(t, test.expected, l.String())
})
}
}
func TestBullet(t *testing.T) {
tests := []struct {
enum list.Enumerator
i int
exp string
}{
{list.Alphabet, 0, "A"},
{list.Alphabet, 25, "Z"},
{list.Alphabet, 26, "AA"},
{list.Alphabet, 51, "AZ"},
{list.Alphabet, 52, "BA"},
{list.Alphabet, 79, "CB"},
{list.Alphabet, 701, "ZZ"},
{list.Alphabet, 702, "AAA"},
{list.Alphabet, 801, "ADV"},
{list.Alphabet, 1000, "ALM"},
{list.Roman, 0, "I"},
{list.Roman, 25, "XXVI"},
{list.Roman, 26, "XXVII"},
{list.Roman, 50, "LI"},
{list.Roman, 100, "CI"},
{list.Roman, 701, "DCCII"},
{list.Roman, 1000, "MI"},
}
for _, test := range tests {
prefix := test.enum(nil, test.i)
bullet := strings.TrimSuffix(prefix, ".")
if bullet != test.exp {
t.Errorf("expected: %s, got: %s\n", test.exp, bullet)
}
}
}
func TestEnumeratorsAlign(t *testing.T) {
fooList := strings.Split(strings.TrimSuffix(strings.Repeat("Foo ", 100), " "), " ")
l := list.New().Enumerator(list.Roman)
for _, f := range fooList {
l.Item(f)
}
expected := strings.TrimPrefix(`
I. Foo
II. Foo
III. Foo
IV. Foo
V. Foo
VI. Foo
VII. Foo
VIII. Foo
IX. Foo
X. Foo
XI. Foo
XII. Foo
XIII. Foo
XIV. Foo
XV. Foo
XVI. Foo
XVII. Foo
XVIII. Foo
XIX. Foo
XX. Foo
XXI. Foo
XXII. Foo
XXIII. Foo
XXIV. Foo
XXV. Foo
XXVI. Foo
XXVII. Foo
XXVIII. Foo
XXIX. Foo
XXX. Foo
XXXI. Foo
XXXII. Foo
XXXIII. Foo
XXXIV. Foo
XXXV. Foo
XXXVI. Foo
XXXVII. Foo
XXXVIII. Foo
XXXIX. Foo
XL. Foo
XLI. Foo
XLII. Foo
XLIII. Foo
XLIV. Foo
XLV. Foo
XLVI. Foo
XLVII. Foo
XLVIII. Foo
XLIX. Foo
L. Foo
LI. Foo
LII. Foo
LIII. Foo
LIV. Foo
LV. Foo
LVI. Foo
LVII. Foo
LVIII. Foo
LIX. Foo
LX. Foo
LXI. Foo
LXII. Foo
LXIII. Foo
LXIV. Foo
LXV. Foo
LXVI. Foo
LXVII. Foo
LXVIII. Foo
LXIX. Foo
LXX. Foo
LXXI. Foo
LXXII. Foo
LXXIII. Foo
LXXIV. Foo
LXXV. Foo
LXXVI. Foo
LXXVII. Foo
LXXVIII. Foo
LXXIX. Foo
LXXX. Foo
LXXXI. Foo
LXXXII. Foo
LXXXIII. Foo
LXXXIV. Foo
LXXXV. Foo
LXXXVI. Foo
LXXXVII. Foo
LXXXVIII. Foo
LXXXIX. Foo
XC. Foo
XCI. Foo
XCII. Foo
XCIII. Foo
XCIV. Foo
XCV. Foo
XCVI. Foo
XCVII. Foo
XCVIII. Foo
XCIX. Foo
C. Foo`, "\n")
require.Equal(t, expected, l.String())
}
func TestSubListItems(t *testing.T) {
l := list.New().Items(
"S",
list.New().Items("neovim", "vscode"),
"HI",
list.New().Items([]string{"vim", "doom emacs"}),
"Parent 2",
list.New().Item("I like fuzzy socks"),
)
expected := `
• S
• neovim
• vscode
• HI
• vim
• doom emacs
• Parent 2
• I like fuzzy socks
`
require.Equal(t, expected, l.String())
}