Skip to content

Commit c3abe87

Browse files
authored
test: improve app package coverage\ (#94)
1 parent 2dfd54e commit c3abe87

File tree

13 files changed

+337
-81
lines changed

13 files changed

+337
-81
lines changed

internal/app/lazytable.go

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -77,9 +77,10 @@ func (m lazyTableModel) handleKey(msg tea.KeyMsg, render bool) (lazyTableModel,
7777
// this function increases the viewport offset by 1 if possible. (scrolls down)
7878
increaseOffset := func() {
7979
maxOffset := max(m.entries.Len()-m.table.Height(), 0)
80-
o := min(m.offset+1, maxOffset)
81-
if o != m.offset {
82-
m.offset = o
80+
81+
offset := min(m.offset+1, maxOffset)
82+
if offset != m.offset {
83+
m.offset = offset
8384
render = true
8485
} else {
8586
// we were at the last item, so we should follow the log
@@ -111,12 +112,14 @@ func (m lazyTableModel) handleKey(msg tea.KeyMsg, render bool) (lazyTableModel,
111112
increaseOffset() // move the viewport
112113
}
113114
}
115+
114116
if key.Matches(msg, m.Application.keys.Up) {
115117
m.follow = false
116118
if m.table.Cursor() == 0 {
117119
decreaseOffset() // move the viewport
118120
}
119121
}
122+
120123
if key.Matches(msg, m.Application.keys.GotoTop) {
121124
if m.reverse {
122125
// when follow is enabled, rendering will handle setting the offset to the correct value
@@ -127,6 +130,7 @@ func (m lazyTableModel) handleKey(msg tea.KeyMsg, render bool) (lazyTableModel,
127130
}
128131
render = true
129132
}
133+
130134
if key.Matches(msg, m.Application.keys.GotoBottom) {
131135
if m.reverse {
132136
m.follow = false

internal/app/stateerror_test.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,26 +23,41 @@ func TestStateError(t *testing.T) {
2323

2424
_, ok := model.(app.StateErrorModel)
2525
assert.Truef(t, ok, "%s", model)
26+
2627
return model
2728
}
2829

2930
t.Run("rendered", func(t *testing.T) {
3031
t.Parallel()
32+
3133
model := setup()
3234
rendered := model.View()
3335
assert.Contains(t, rendered, errTest.Error())
3436
})
3537

3638
t.Run("any_key_msg", func(t *testing.T) {
3739
t.Parallel()
40+
3841
model := setup()
3942

4043
_, cmd := model.Update(tea.KeyMsg{})
4144
assert.Equal(t, tea.Quit(), cmd())
4245
})
4346

47+
t.Run("unknown_message", func(t *testing.T) {
48+
t.Parallel()
49+
50+
model := setup()
51+
52+
model, _ = model.Update(nil)
53+
54+
_, ok := model.(app.StateErrorModel)
55+
assert.Truef(t, ok, "%s", model)
56+
})
57+
4458
t.Run("stringer", func(t *testing.T) {
4559
t.Parallel()
60+
4661
model := setup()
4762

4863
stringer, ok := model.(fmt.Stringer)

internal/app/statefiltered.go

Lines changed: 50 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -56,55 +56,76 @@ func (s StateFilteredModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
5656

5757
s.Application.Update(msg)
5858

59-
switch typedMsg := msg.(type) {
60-
case *StateFilteredModel:
61-
entries, err := s.Application.Entries.Filter(s.filterText)
62-
if err != nil {
63-
return s, events.ShowError(err)
64-
}
65-
s.logEntries = entries
66-
s.table = newLogsTableModel(s.Application, entries)
67-
msg = events.LogEntriesUpdateMsg(entries)
68-
case events.LogEntriesUpdateMsg:
69-
entries, err := s.Application.Entries.Filter(s.filterText)
70-
if err != nil {
71-
return s, events.ShowError(err)
72-
}
73-
s.logEntries = entries
74-
msg = events.LogEntriesUpdateMsg(entries)
59+
if _, ok := msg.(*StateFilteredModel); ok {
60+
s, msg = s.handleStateFilteredModel()
61+
}
62+
63+
if _, ok := msg.(*events.LogEntriesUpdateMsg); ok {
64+
s, msg = s.handleLogEntriesUpdateMsg()
65+
}
7566

67+
switch typedMsg := msg.(type) {
7668
case events.ErrorOccuredMsg:
7769
return s.handleErrorOccuredMsg(typedMsg)
7870
case events.OpenJSONRowRequestedMsg:
7971
return s.handleOpenJSONRowRequestedMsg(typedMsg, s)
8072
case tea.KeyMsg:
81-
switch {
82-
case key.Matches(typedMsg, s.keys.Back):
83-
return s.previousState.refresh()
84-
case key.Matches(typedMsg, s.keys.Filter):
85-
return s.handleFilterKeyClickedMsg()
86-
case key.Matches(typedMsg, s.keys.ToggleViewArrow), key.Matches(typedMsg, s.keys.Open):
87-
return s.handleRequestOpenJSON()
88-
}
89-
if cmd := s.handleKeyMsg(typedMsg); cmd != nil {
90-
return s, cmd
73+
if mdl, cmd := s.handleKeyMsg(typedMsg); mdl != nil {
74+
return mdl, cmd
9175
}
9276
default:
9377
s.table, cmdBatch = batched(s.table.Update(typedMsg))(cmdBatch)
9478
}
9579

9680
s.table, cmdBatch = batched(s.table.Update(msg))(cmdBatch)
81+
9782
return s, tea.Batch(cmdBatch...)
9883
}
9984

85+
func (s StateFilteredModel) handleKeyMsg(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
86+
switch {
87+
case key.Matches(msg, s.keys.Back):
88+
return s.previousState.refresh()
89+
case key.Matches(msg, s.keys.Filter):
90+
return s.handleFilterKeyClickedMsg()
91+
case key.Matches(msg, s.keys.ToggleViewArrow), key.Matches(msg, s.keys.Open):
92+
return s.handleRequestOpenJSON()
93+
default:
94+
return nil, nil
95+
}
96+
}
97+
98+
func (s StateFilteredModel) handleLogEntriesUpdateMsg() (StateFilteredModel, tea.Msg) {
99+
entries, err := s.Application.Entries.Filter(s.filterText)
100+
if err != nil {
101+
return s, events.ShowError(err)()
102+
}
103+
104+
s.logEntries = entries
105+
106+
return s, events.LogEntriesUpdateMsg(entries)
107+
}
108+
109+
func (s StateFilteredModel) handleStateFilteredModel() (StateFilteredModel, tea.Msg) {
110+
entries, err := s.Application.Entries.Filter(s.filterText)
111+
if err != nil {
112+
return s, events.ShowError(err)()
113+
}
114+
115+
s.logEntries = entries
116+
s.table = newLogsTableModel(s.Application, entries)
117+
118+
return s, events.LogEntriesUpdateMsg(entries)
119+
}
120+
100121
func (s StateFilteredModel) handleFilterKeyClickedMsg() (tea.Model, tea.Cmd) {
101122
state := newStateFiltering(s.previousState)
102123
return initializeModel(state)
103124
}
104125

105126
func (s StateFilteredModel) handleRequestOpenJSON() (tea.Model, tea.Cmd) {
106127
if s.logEntries.Len() == 0 {
107-
return s, events.BackKeyClicked
128+
return s, events.EscKeyClicked
108129
}
109130

110131
return s, events.OpenJSONRowRequested(s.logEntries, s.table.Cursor())
@@ -114,9 +135,9 @@ func (s StateFilteredModel) getApplication() *Application {
114135
return s.Application
115136
}
116137

117-
func (s StateFilteredModel) refresh() (stateModel, tea.Cmd) {
118-
var cmd tea.Cmd
138+
func (s StateFilteredModel) refresh() (_ stateModel, cmd tea.Cmd) {
119139
s.table, cmd = s.table.Update(s.Application.LastWindowSize)
140+
120141
return s, cmd
121142
}
122143

internal/app/statefiltered_test.go

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ func TestStateFiltered(t *testing.T) {
4747
// Write term to search by.
4848
model = handleUpdate(model, tea.KeyMsg{
4949
Type: tea.KeyRunes,
50-
Runes: []rune(termIncluded),
50+
Runes: []rune(termIncluded[1:]),
5151
})
5252

5353
// Filter.
@@ -59,14 +59,16 @@ func TestStateFiltered(t *testing.T) {
5959
if assert.Truef(t, ok, "%s", model) {
6060
rendered = model.View()
6161
assert.Contains(t, rendered, termIncluded)
62-
assert.Contains(t, rendered, "filtered 1 by: "+termIncluded)
62+
assert.Contains(t, rendered, "filtered 1 by: "+termIncluded[1:])
6363
assert.NotContains(t, rendered, termExcluded)
6464
}
65+
6566
return model
6667
}
6768

6869
t.Run("reopen_filter", func(t *testing.T) {
6970
t.Parallel()
71+
7072
model := setup()
7173
model = handleUpdate(model, tea.KeyMsg{
7274
Type: tea.KeyRunes,
@@ -79,6 +81,7 @@ func TestStateFiltered(t *testing.T) {
7981

8082
t.Run("open_hide_json_view", func(t *testing.T) {
8183
t.Parallel()
84+
8285
model := setup()
8386
model = handleUpdate(model, tea.KeyMsg{
8487
Type: tea.KeyEnter,
@@ -97,6 +100,7 @@ func TestStateFiltered(t *testing.T) {
97100

98101
t.Run("error", func(t *testing.T) {
99102
t.Parallel()
103+
100104
model := setup()
101105
model = handleUpdate(model, events.ErrorOccuredMsg{Err: getTestError()})
102106

@@ -106,6 +110,7 @@ func TestStateFiltered(t *testing.T) {
106110

107111
t.Run("navigation", func(t *testing.T) {
108112
t.Parallel()
113+
109114
model := setup()
110115
model = handleUpdate(model, tea.KeyMsg{
111116
Type: tea.KeyUp,
@@ -117,6 +122,7 @@ func TestStateFiltered(t *testing.T) {
117122

118123
t.Run("returned", func(t *testing.T) {
119124
t.Parallel()
125+
120126
model := setup()
121127
model = handleUpdate(model, tea.KeyMsg{
122128
Type: tea.KeyEsc,
@@ -128,10 +134,21 @@ func TestStateFiltered(t *testing.T) {
128134

129135
t.Run("stringer", func(t *testing.T) {
130136
t.Parallel()
137+
131138
model := setup()
132139
stringer, ok := model.(fmt.Stringer)
133140
if assert.True(t, ok) {
134141
assert.Contains(t, stringer.String(), "StateFiltered")
135142
}
136143
})
144+
145+
t.Run("updated", func(t *testing.T) {
146+
t.Parallel()
147+
148+
model := setup()
149+
model = handleUpdate(model, &events.LogEntriesUpdateMsg{})
150+
151+
rendered := model.View()
152+
assert.Contains(t, rendered, termIncluded)
153+
})
137154
}

internal/app/statefiltering.go

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -56,15 +56,8 @@ func (s StateFilteringModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
5656
case events.ErrorOccuredMsg:
5757
return s.handleErrorOccuredMsg(msg)
5858
case tea.KeyMsg:
59-
switch {
60-
case key.Matches(msg, s.keys.Back):
61-
return s.previousState.refresh()
62-
case key.Matches(msg, s.keys.Open):
63-
return s.handleEnterKeyClickedMsg()
64-
}
65-
if cmd := s.handleKeyMsg(msg); cmd != nil {
66-
// Intercept table update.
67-
return s, cmd
59+
if mdl, cmd := s.handleKeyMsg(msg); mdl != nil {
60+
return mdl, cmd
6861
}
6962
default:
7063
s.table, cmdBatch = batched(s.table.Update(msg))(cmdBatch)
@@ -75,17 +68,20 @@ func (s StateFilteringModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
7568
return s, tea.Batch(cmdBatch...)
7669
}
7770

78-
func (s StateFilteringModel) handleKeyMsg(msg tea.KeyMsg) tea.Cmd {
79-
if len(msg.Runes) == 1 {
80-
return nil
71+
func (s StateFilteringModel) handleKeyMsg(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
72+
switch {
73+
case key.Matches(msg, s.keys.Back):
74+
return s.previousState.refresh()
75+
case key.Matches(msg, s.keys.Open):
76+
return s.handleEnterKeyClickedMsg()
77+
default:
78+
return nil, nil
8179
}
82-
83-
return s.Application.handleKeyMsg(msg)
8480
}
8581

8682
func (s StateFilteringModel) handleEnterKeyClickedMsg() (tea.Model, tea.Cmd) {
8783
if s.textInput.Value() == "" {
88-
return s, events.BackKeyClicked
84+
return s, events.EscKeyClicked
8985
}
9086

9187
return initializeModel(newStateFiltered(

internal/app/statefiltering_test.go

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,61 @@ func TestStateFiltering(t *testing.T) {
9999
_, ok := model.(app.StateFilteringModel)
100100
assert.Truef(t, ok, "%s", model)
101101
})
102+
103+
t.Run("runes", func(t *testing.T) {
104+
model := setup()
105+
106+
const content = "hello world"
107+
108+
for _, r := range content {
109+
model = handleUpdate(model, tea.KeyMsg{
110+
Type: tea.KeyRunes,
111+
Runes: []rune{r},
112+
})
113+
}
114+
115+
assert.Contains(t, model.View(), content)
116+
})
117+
118+
t.Run("arrow_right", func(t *testing.T) {
119+
model := setup()
120+
121+
model = handleUpdate(model, events.ArrowRightKeyClicked())
122+
123+
const content = "hello word"
124+
125+
// 1. Input "hello word".
126+
// 2. Press "Left" 2 times: "hello wo|rd"
127+
// 3. Press "Right" 1 time: "hello wor|d".
128+
// 4. Input "r".
129+
// 5. Expect to see "hello world".
130+
for _, r := range content {
131+
model = handleUpdate(model, tea.KeyMsg{
132+
Type: tea.KeyRunes,
133+
Runes: []rune{r},
134+
})
135+
}
136+
137+
model = handleUpdate(model, tea.KeyMsg{Type: tea.KeyLeft})
138+
model = handleUpdate(model, tea.KeyMsg{Type: tea.KeyLeft})
139+
model = handleUpdate(model, tea.KeyMsg{Type: tea.KeyRight})
140+
141+
model = handleUpdate(model, tea.KeyMsg{
142+
Type: tea.KeyRunes,
143+
Runes: []rune{'l'},
144+
})
145+
146+
assert.Contains(t, model.View(), "hello world")
147+
})
148+
149+
t.Run("unknown_message", func(t *testing.T) {
150+
model := setup()
151+
152+
model = handleUpdate(model, nil)
153+
154+
_, ok := model.(app.StateFilteringModel)
155+
assert.Truef(t, ok, "%s", model)
156+
})
102157
}
103158

104159
func TestStateFilteringReset(t *testing.T) {

0 commit comments

Comments
 (0)