196 lines
5.4 KiB
Go
196 lines
5.4 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"reflect"
|
|
"runtime"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
tea "github.com/charmbracelet/bubbletea"
|
|
)
|
|
|
|
type compareFunc[T comparable] func(T, T) bool
|
|
|
|
func assertFunc[T comparable](t *testing.T, compare compareFunc[T], actual, expected T, msg string) {
|
|
t.Helper()
|
|
|
|
if !compare(actual, expected) {
|
|
t.Errorf("%s: expected %v, got %v", msg, expected, actual)
|
|
}
|
|
}
|
|
|
|
// assertEqual checks if two values are equal and reports an error if they are not.
|
|
func assertEqual(t *testing.T, actual, expected interface{}, msg string) {
|
|
t.Helper()
|
|
|
|
if actual != expected {
|
|
t.Errorf("%s: expected %v, got %v", msg, expected, actual)
|
|
}
|
|
}
|
|
|
|
// assertNotEqual checks if two values are not equal and reports an error if they are.
|
|
func assertNotEqual(t *testing.T, actual, expected interface{}, msg string) {
|
|
t.Helper()
|
|
|
|
if actual == expected {
|
|
t.Errorf("%s: expected %v to be different from %v", msg, actual, expected)
|
|
}
|
|
}
|
|
|
|
// TestParseDuration tests the parseDuration function
|
|
func TestParseDuration(t *testing.T) {
|
|
tests := []struct {
|
|
input string
|
|
expected time.Duration
|
|
hasError bool
|
|
}{
|
|
{"10", 10 * time.Minute, false},
|
|
{"1h", 1 * time.Hour, false},
|
|
{"invalid", 0, true},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
result, err := parseDuration(test.input)
|
|
if test.hasError {
|
|
assertNotEqual(t, err, nil, "Expected an error for input "+test.input)
|
|
} else {
|
|
assertEqual(t, err, nil, "Did not expect an error for input "+test.input)
|
|
assertEqual(t, result, test.expected, "Expected duration for input "+test.input)
|
|
}
|
|
}
|
|
}
|
|
|
|
// TestRunCommands tests the runCommands function
|
|
func TestRunCommands(t *testing.T) {
|
|
m := newModelBasic(false, "#ffdd57", "#57ddff")
|
|
m.onFocusStart = []string{"echo Focus Start"}
|
|
|
|
m.Init()
|
|
m.startCommands(m.onFocusStart)
|
|
}
|
|
|
|
func keyMsgs(keys ...interface{}) []tea.Msg {
|
|
keyMessages := []tea.Msg{}
|
|
|
|
for _, key := range keys {
|
|
switch keyType := key.(type) {
|
|
case tea.KeyType:
|
|
keyMessages = append(keyMessages, tea.KeyMsg{Type: keyType})
|
|
case string:
|
|
for _, r := range key.(string) {
|
|
keyMessages = append(keyMessages, tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune{r}})
|
|
}
|
|
default:
|
|
panic(fmt.Sprintf("Unknown key type: %v", key))
|
|
}
|
|
}
|
|
|
|
return keyMessages
|
|
}
|
|
|
|
func sendKeys(m model, keys ...interface{}) (model, tea.Cmd) {
|
|
var updatedModel tea.Model
|
|
|
|
var cmd tea.Cmd
|
|
|
|
for _, key := range keyMsgs(keys...) {
|
|
updatedModel, cmd = m.Update(key)
|
|
m = updatedModel.(model)
|
|
|
|
if cmd != nil {
|
|
updatedModel, cmd = m.Update(cmd())
|
|
m = updatedModel.(model)
|
|
}
|
|
}
|
|
|
|
return m, cmd
|
|
}
|
|
|
|
// TestInputView tests the Update method of the model for the input view
|
|
func TestInputView(t *testing.T) {
|
|
m := newModel(false, "#ffdd57", "#57ddff", 0, 0, 0, []string{}, []string{}, []string{})
|
|
|
|
var updatedModel tea.Model
|
|
|
|
var resultCmd tea.Cmd
|
|
|
|
updatedModel, _ = m.Update(m.Init())
|
|
m = updatedModel.(model)
|
|
|
|
// Verify we're on the input screen
|
|
assertEqual(t, m.currentScreen, INPUT_SCREEN, "Expected currentScreen to be inputScreen")
|
|
assertFunc(t, strings.Contains, m.View(), "Break time", "Expected view to contain 'enter next'")
|
|
|
|
// Fill the form
|
|
m, resultCmd = sendKeys(m, "10m", tea.KeyEnter, "10m", tea.KeyEnter, "2", tea.KeyEnter)
|
|
assertNotEqual(t, resultCmd, nil, "Expected resultCmd to be not nil")
|
|
|
|
// Apply final next result
|
|
updatedModel, resultCmd = m.Update(resultCmd())
|
|
m = updatedModel.(model)
|
|
|
|
// Make sure the next command is to submit the form
|
|
assertNotEqual(t, resultCmd, nil, "Expected resultCmd to be not nil")
|
|
assertEqual(
|
|
t,
|
|
reflect.ValueOf(resultCmd).Pointer(),
|
|
reflect.ValueOf(formSubmit).Pointer(),
|
|
fmt.Sprintf("Expected resultCmd to be formSubmit, found %v", runtime.FuncForPC(reflect.ValueOf(resultCmd).Pointer()).Name()),
|
|
)
|
|
|
|
// Apply submit form command
|
|
updatedModel, resultCmd = m.Update(resultCmd())
|
|
m = updatedModel.(model)
|
|
|
|
assertEqual(t, m.err, nil, "Expected no error")
|
|
assertNotEqual(t, resultCmd, nil, "Expected resultCmd to be not nil")
|
|
assertEqual(
|
|
t,
|
|
reflect.ValueOf(resultCmd).Pointer(),
|
|
reflect.ValueOf(startTimer).Pointer(),
|
|
fmt.Sprintf("Expected resultCmd to be startTimer, found %v", runtime.FuncForPC(reflect.ValueOf(resultCmd).Pointer()).Name()),
|
|
)
|
|
}
|
|
|
|
func TestTimerView(t *testing.T) {
|
|
m := newModel(false, "#ffdd57", "#57ddff", 10*time.Minute, 10*time.Minute, 2, []string{}, []string{}, []string{})
|
|
|
|
var updatedModel tea.Model
|
|
|
|
// Init model with timer values
|
|
updatedModel, _ = m.Update(m.Init())
|
|
m = updatedModel.(model)
|
|
|
|
// Start timer (batch result from above doesn't apply here)
|
|
updatedModel, _ = m.Update(startTimer())
|
|
m = updatedModel.(model)
|
|
|
|
// Test timer view
|
|
assertEqual(t, m.currentScreen, TIMER_SCREEN, "Expected currentScreen to be timerScreen")
|
|
assertFunc(t, strings.Contains, m.View(), "Focus", "Expected view to contain 'Focus'")
|
|
assertEqual(t, m.state, "Focus", "Expected state to be 'Focus'")
|
|
|
|
oneSec := timeMsg(time.Now().Add(1 * time.Second))
|
|
updatedModel, _ = m.Update(oneSec)
|
|
m = updatedModel.(model)
|
|
|
|
assertEqual(t, m.state, "Focus", "Expected state to be 'Focus'")
|
|
|
|
// Test switch to break time
|
|
m.startTime = m.startTime.Add(-10 * time.Minute)
|
|
updatedModel, _ = m.Update(oneSec)
|
|
m = updatedModel.(model)
|
|
|
|
assertEqual(t, m.state, "Break", "Expected state to be 'Break'")
|
|
|
|
// Switch back to focus time
|
|
m.startTime = m.startTime.Add(-10 * time.Minute)
|
|
updatedModel, _ = m.Update(oneSec)
|
|
m = updatedModel.(model)
|
|
|
|
assertEqual(t, m.state, "Focus", "Expected state to be 'Focus'")
|
|
t.Logf("Incorrect state %+v", m)
|
|
}
|