Skip to content

Commit

Permalink
fix bug, add more tests
Browse files Browse the repository at this point in the history
  • Loading branch information
pikomonde committed Jul 3, 2024
1 parent 602bbd7 commit a48fd36
Show file tree
Hide file tree
Showing 2 changed files with 183 additions and 9 deletions.
7 changes: 4 additions & 3 deletions viewport/viewport.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,9 @@ func (m *Model) SetContent(s string) {
s = strings.ReplaceAll(s, "\r\n", "\n") // normalize line endings
m.lines = strings.Split(s, "\n")

wrapLines := m.wrapContent(strings.Join(m.lines, "\n"), false)
m.lines = strings.Split(wrapLines, "\n")
joinedLines := strings.Join(m.lines, "\n")
wrapContents := m.wrapContent(joinedLines, false)
m.lines = strings.Split(wrapContents, "\n")

if m.YOffset > len(m.lines)-1 {
m.GotoBottom()
Expand Down Expand Up @@ -377,7 +378,7 @@ func (m Model) wrapContent(content string, trimHeight bool) string {
Width(contentWidth). // pad to width.
MaxWidth(contentWidth) // truncate width if wider.
if trimHeight {
contents = lipgloss.NewStyle().
contents = contents.
Height(contentHeight). // pad to height.
MaxHeight(contentHeight) // truncate height if taller.
}
Expand Down
185 changes: 179 additions & 6 deletions viewport/viewport_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,147 @@ import (
"github.com/charmbracelet/lipgloss"
)

func Test_SetContent(t *testing.T) {
func TestSetContent(t *testing.T) {
// Normal case
m := New(10, 10) // Create a new Model with width 10 and height 10
m.SetContent("This is a test string")
if len(m.lines) != 3 {
t.Errorf("Expected 3 line, but got %d", len(m.lines))
}

// Edge case: empty string
m.SetContent("")
if len(m.lines) != 1 {
t.Errorf("Expected 1 lines, but got %d", len(m.lines))
}

// Edge case: single newline
m.SetContent("\n")
if len(m.lines) != 2 {
t.Errorf("Expected 2 line, but got %d", len(m.lines))
}

// Edge case: multiple newlines
m.SetContent("\n\n\n")
if len(m.lines) != 4 {
t.Errorf("Expected 4 lines, but got %d", len(m.lines))
}

// Extreme case: very long string
longString := strings.Repeat("This is a test string ", 1000)
m.SetContent(longString)
if len(m.lines) != (3 * 1000) { // Depending on the width of the Model, this might wrap to multiple lines
t.Errorf("Expected 3000 lines, but got %d", len(m.lines))
}

// Extreme case: string with ANSI escape codes
ansiString := "\x1b[31mThis is a test string\x1b[0m"
m.SetContent(ansiString)
if len(m.lines) != 3 {
t.Errorf("Expected 3 line, but got %d", len(m.lines))
}

// Extreme case: 2-width characters (Japanese characters)
japaneseString :=
"this is a really long text that should wrap around the viewport\n" +
"これはビューポートを囲む必要がある非常に長い日本語のテキストです"
m.SetContent(japaneseString)
if len(m.lines) != 15 {
t.Errorf("Expected 15 line, but got %d", len(m.lines))
}
}

func escapeString(s string) string {
s = strings.ReplaceAll(s, "\n", "\\n")
s = strings.ReplaceAll(s, "\r", "\\r")
s = strings.ReplaceAll(s, "\t", "\\t")
s = strings.ReplaceAll(s, " ", "\\s")
return s
}

func TestView(t *testing.T) {
// Normal case
m := New(10, 10) // Create a new Model with width 10 and height 10
m.SetContent("This is a test string")
view := m.View()
expected := "" +
"This is a \n" +
"test \n" +
"string "
if !strings.HasPrefix(view, expected) {
t.Errorf("Expected view to start with a newline, but got %s", escapeString(view))
}

// Edge case: empty content
m.SetContent("")
view = m.View()
expected = "" +
" \n"
if !strings.HasPrefix(view, expected) {
t.Errorf("Expected empty view, but got %s", escapeString(view))
}

// Edge case: single newline
m.SetContent("\n")
view = m.View()
expected = "" +
" \n"
if !strings.HasPrefix(view, expected) {
t.Errorf("Expected view to be a single newline, but got %s", escapeString(view))
}

// Edge case: multiple newlines
m.SetContent("\n\n\n")
view = m.View()
expected = "" +
" \n"
if !strings.HasPrefix(view, expected) {
t.Errorf("Expected view to contain multiple newlines, but got %s", escapeString(view))
}

// Extreme case: very long content
longString := strings.Repeat("This is a test string ", 1000)
m.SetContent(longString)
view = m.View()
if len(view) < (10 * 10) { // Depending on the width of the Model, this might wrap to multiple lines
t.Errorf("Expected view to be at least 100 characters long, but got %s", escapeString(view))
}

// Extreme case: content with ANSI escape codes
ansiString := "\x1b[31mThis is a test string\x1b[0m"
m.SetContent(ansiString)
expected = "" +
"\x1b[31mThis is a \n" +
"test \n" +
"string\x1b[0m "
view = m.View()
if !strings.HasPrefix(view, expected) {
t.Errorf("Expected view to contain ANSI escape codes, but got %s", escapeString(view))
}

// Test case: 2-width characters (Japanese characters)
japaneseString :=
"this is a really long text that should wrap around the viewport\n" +
"これはビューポートを囲む必要がある非常に長い日本語のテキストです"
m.SetContent(japaneseString)
view = m.View()
expected = "" +
"this is a \n" +
"really \n" +
"long text \n" +
"that \n" +
"should \n" +
"wrap \n" +
"around the\n" +
"viewport \n" +
"これはビュ\n" +
"ーポートを"
if !strings.HasPrefix(view, expected) {
t.Errorf("Expected view to contain Japanese characters, but got %s", escapeString(view))
}
}

func TestSetContent_NormalCase(t *testing.T) {
vp := New(0, 0)
vp.SetContent("test")

Expand Down Expand Up @@ -38,7 +178,7 @@ func assertArray(t *testing.T, actual, expected []string) {
}
}

func Test_SetContent_WithLargeText(t *testing.T) {
func TestSetContent_WithLargeText(t *testing.T) {
content := []string{
"this is a really long text that should wrap around the viewport",
}
Expand All @@ -52,7 +192,7 @@ func Test_SetContent_WithLargeText(t *testing.T) {
})
}

func Test_SetContent_WithMultipleLineLargeTest(t *testing.T) {
func TestSetContent_WithMultipleLineLargeTest(t *testing.T) {
content := []string{
"this is a really long text that should wrap around the viewport",
"this is a really long text that should wrap around the viewport",
Expand All @@ -70,7 +210,7 @@ func Test_SetContent_WithMultipleLineLargeTest(t *testing.T) {
})
}

func Test_SetContent_WithStyledLargeText(t *testing.T) {
func TestSetContent_WithStyledLargeText(t *testing.T) {
content := []string{
lipgloss.NewStyle().Foreground(lipgloss.Color("1")).Render("this ") + "is a really long text that should wrap around the viewport",
}
Expand All @@ -84,7 +224,7 @@ func Test_SetContent_WithStyledLargeText(t *testing.T) {
})
}

func Test_SetContent_WithLargeTextWithViewportPadding(t *testing.T) {
func TestSetContent_WithLargeTextWithViewportPadding(t *testing.T) {
content := []string{
"this is a really long text that should wrap around the viewport",
}
Expand All @@ -99,7 +239,7 @@ func Test_SetContent_WithLargeTextWithViewportPadding(t *testing.T) {
})
}

func Test_SetContent_WithLargeTextWithWideCharacter(t *testing.T) {
func TestSetContent_WithLargeTextWithWideCharacter(t *testing.T) {
content := []string{
"this is a really long text that should wrap around the viewport",
"これはビューポートを囲む必要がある非常に長い日本語のテキストです",
Expand All @@ -116,3 +256,36 @@ func Test_SetContent_WithLargeTextWithWideCharacter(t *testing.T) {
"です ",
})
}

func TestWrapContent_WidthPaddingAndMaxWidth(t *testing.T) {
m := Model{
Width: 10,
Style: lipgloss.NewStyle(),
}

// Test case 1: Content width is less than model width
content := "Hello"
expected := "Hello "
actual := m.wrapContent(content, false)
if actual != expected {
t.Errorf("Expected '%s' but got '%s'", expected, actual)
}

// Test case 2: Content width is equal to model width
content = "abcdefghij"
expected = "abcdefghij"
actual = m.wrapContent(content, false)
if actual != expected {
t.Errorf("Expected '%s' but got '%s'", expected, actual)
}

// Test case 3: Content width is greater than model width
content = "abcdefghijk"
expected = "" +
"abcdefghij\n" +
"k "
actual = m.wrapContent(content, false)
if actual != expected {
t.Errorf("Expected '%s' but got '%s'", expected, actual)
}
}

0 comments on commit a48fd36

Please sign in to comment.