Refactor and improve test coverage
This commit is contained in:
parent
7729646093
commit
c86f080bc7
228
main.go
228
main.go
@ -14,10 +14,9 @@ import (
|
|||||||
"github.com/charmbracelet/bubbles/progress"
|
"github.com/charmbracelet/bubbles/progress"
|
||||||
"github.com/charmbracelet/bubbles/textinput"
|
"github.com/charmbracelet/bubbles/textinput"
|
||||||
tea "github.com/charmbracelet/bubbletea"
|
tea "github.com/charmbracelet/bubbletea"
|
||||||
|
"github.com/charmbracelet/huh"
|
||||||
"github.com/charmbracelet/lipgloss"
|
"github.com/charmbracelet/lipgloss"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
|
|
||||||
"github.com/charmbracelet/huh"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type screen int
|
type screen int
|
||||||
@ -34,12 +33,19 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type model struct {
|
type model struct {
|
||||||
|
// View state
|
||||||
form *huh.Form
|
form *huh.Form
|
||||||
progressBar progress.Model
|
progressBar progress.Model
|
||||||
state string
|
state string
|
||||||
intervalNum int
|
intervalNum int
|
||||||
remaining time.Duration
|
|
||||||
currentScreen screen
|
currentScreen screen
|
||||||
|
isFocus bool
|
||||||
|
fullscreen bool
|
||||||
|
width int
|
||||||
|
height int
|
||||||
|
|
||||||
|
// Timer state
|
||||||
|
remaining time.Duration
|
||||||
intervals int
|
intervals int
|
||||||
breakTime time.Duration
|
breakTime time.Duration
|
||||||
focusTime time.Duration
|
focusTime time.Duration
|
||||||
@ -47,15 +53,28 @@ type model struct {
|
|||||||
onFocusStart []string
|
onFocusStart []string
|
||||||
onFocusEnd []string
|
onFocusEnd []string
|
||||||
onIntervalEnd []string
|
onIntervalEnd []string
|
||||||
isFocus bool
|
|
||||||
fullscreen bool
|
|
||||||
width int
|
|
||||||
height int
|
|
||||||
err error
|
err error
|
||||||
shellrunner *tortoise.ShellRunner
|
shellrunner *tortoise.ShellRunner
|
||||||
}
|
}
|
||||||
|
|
||||||
func initialModel(fullscreen bool, colorLeft string, colorRight string, defaultFocusTime, defaultBreakTime, defaultIntervals *string) model {
|
// Message that signals to start the timer
|
||||||
|
type startTimerMsg struct{}
|
||||||
|
|
||||||
|
// Command that triggers start message
|
||||||
|
func startTimer() tea.Msg {
|
||||||
|
return startTimerMsg{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Message that signals to get values from the form
|
||||||
|
type formSubmitMsg struct{}
|
||||||
|
|
||||||
|
// Command that triggers form submit message
|
||||||
|
func formSubmit() tea.Msg {
|
||||||
|
return formSubmitMsg{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create input form with default values if provided
|
||||||
|
func createInputForm(defaultFocusTime, defaultBreakTime, defaultIntervals *string) *huh.Form {
|
||||||
// Ceate validation functions for input
|
// Ceate validation functions for input
|
||||||
validateDuration := func(text string) error {
|
validateDuration := func(text string) error {
|
||||||
_, err := parseDuration(text)
|
_, err := parseDuration(text)
|
||||||
@ -70,10 +89,6 @@ func initialModel(fullscreen bool, colorLeft string, colorRight string, defaultF
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if colorLeft == "" || colorRight == "" {
|
|
||||||
slog.Panicf("Color flags can't be empty")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create form fields
|
// Create form fields
|
||||||
focusTime := huh.NewInput().
|
focusTime := huh.NewInput().
|
||||||
Key(FORM_FOCUS).
|
Key(FORM_FOCUS).
|
||||||
@ -108,8 +123,19 @@ func initialModel(fullscreen bool, colorLeft string, colorRight string, defaultF
|
|||||||
intervals = intervals.Value(defaultIntervals)
|
intervals = intervals.Value(defaultIntervals)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
f := huh.NewForm(huh.NewGroup(focusTime, breakTime, intervals)).WithShowErrors(true)
|
||||||
|
f.SubmitCmd = formSubmit
|
||||||
|
|
||||||
|
return f
|
||||||
|
}
|
||||||
|
|
||||||
|
func newModelBasic(fullscreen bool, colorLeft, colorRight string) model {
|
||||||
|
if colorLeft == "" || colorRight == "" {
|
||||||
|
slog.Panicf("Color flags can't be empty")
|
||||||
|
}
|
||||||
|
|
||||||
return model{
|
return model{
|
||||||
form: huh.NewForm(huh.NewGroup(focusTime, breakTime, intervals)).WithShowErrors(true),
|
form: nil,
|
||||||
progressBar: progress.New(progress.WithScaledGradient(colorLeft, colorRight)),
|
progressBar: progress.New(progress.WithScaledGradient(colorLeft, colorRight)),
|
||||||
state: "stopped",
|
state: "stopped",
|
||||||
intervalNum: 1,
|
intervalNum: 1,
|
||||||
@ -121,11 +147,51 @@ func initialModel(fullscreen bool, colorLeft string, colorRight string, defaultF
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func newModel(fullscreen bool, colorLeft, colorRight string, focusTime, breakTime time.Duration, intervals int, onFocusStart, onFocusEnd, onIntervalEnd []string) model {
|
||||||
|
m := newModelBasic(fullscreen, colorLeft, colorRight)
|
||||||
|
|
||||||
|
if focusTime != 0 && breakTime != 0 && intervals != 0 {
|
||||||
|
// All values provided, initialize timer
|
||||||
|
m.focusTime = focusTime
|
||||||
|
m.breakTime = breakTime
|
||||||
|
m.intervals = intervals
|
||||||
|
m.currentScreen = TIMER_SCREEN
|
||||||
|
} else {
|
||||||
|
// Prompt for input
|
||||||
|
var defaultFocusTime, defaultBreakTime, defaultIntervals *string
|
||||||
|
|
||||||
|
if value := focusTime.String(); value != "0s" {
|
||||||
|
defaultFocusTime = &value
|
||||||
|
}
|
||||||
|
|
||||||
|
if value := breakTime.String(); value != "0s" {
|
||||||
|
defaultBreakTime = &value
|
||||||
|
}
|
||||||
|
|
||||||
|
if intervals != 0 {
|
||||||
|
intervalsString := strconv.Itoa(intervals)
|
||||||
|
defaultIntervals = &intervalsString
|
||||||
|
}
|
||||||
|
|
||||||
|
m.form = createInputForm(defaultFocusTime, defaultBreakTime, defaultIntervals)
|
||||||
|
m.currentScreen = INPUT_SCREEN
|
||||||
|
}
|
||||||
|
|
||||||
|
// Collect command flags
|
||||||
|
m.onFocusStart = onFocusStart
|
||||||
|
m.onFocusEnd = onFocusEnd
|
||||||
|
m.onIntervalEnd = onIntervalEnd
|
||||||
|
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
|
||||||
func (m model) Init() tea.Cmd {
|
func (m model) Init() tea.Cmd {
|
||||||
// Handle Ctrl+C for graceful exit
|
// Handle Ctrl+C for graceful exit
|
||||||
c := make(chan os.Signal, 1)
|
c := make(chan os.Signal, 1)
|
||||||
signal.Notify(c, os.Interrupt)
|
signal.Notify(c, os.Interrupt)
|
||||||
|
|
||||||
|
cmds := []tea.Cmd{tea.WindowSize(), textinput.Blink}
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
<-c
|
<-c
|
||||||
|
|
||||||
@ -135,10 +201,20 @@ func (m model) Init() tea.Cmd {
|
|||||||
os.Exit(0)
|
os.Exit(0)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
m.form.Init()
|
if m.form != nil {
|
||||||
m.shellrunner.Start()
|
// Start input form if it exists
|
||||||
|
cmds = append(cmds, m.form.Init())
|
||||||
|
} else {
|
||||||
|
// Start timer if no form
|
||||||
|
cmds = append(cmds, startTimer)
|
||||||
|
}
|
||||||
|
|
||||||
return tea.Batch(tea.WindowSize(), textinput.Blink)
|
// Start shell runner if there are any commands to run
|
||||||
|
if len(m.onFocusStart) > 0 || len(m.onFocusEnd) > 0 || len(m.onIntervalEnd) > 0 {
|
||||||
|
m.shellrunner.Start()
|
||||||
|
}
|
||||||
|
|
||||||
|
return tea.Batch(cmds...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// totalTime returns the total time for the current period (focus or break)
|
// totalTime returns the total time for the current period (focus or break)
|
||||||
@ -154,52 +230,13 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|||||||
cmds := []tea.Cmd{}
|
cmds := []tea.Cmd{}
|
||||||
|
|
||||||
// Handle input screen
|
// Handle input screen
|
||||||
if m.currentScreen == INPUT_SCREEN {
|
if m.currentScreen == INPUT_SCREEN && m.form != nil {
|
||||||
form, cmd := m.form.Update(msg)
|
form, cmd := m.form.Update(msg)
|
||||||
if f, ok := form.(*huh.Form); ok {
|
if f, ok := form.(*huh.Form); ok {
|
||||||
m.form = f
|
m.form = f
|
||||||
}
|
}
|
||||||
|
|
||||||
cmds = append(cmds, cmd)
|
cmds = append(cmds, cmd)
|
||||||
|
|
||||||
if m.form.State == huh.StateCompleted {
|
|
||||||
// Kick off the timer
|
|
||||||
focusTime, err := parseDuration(m.form.GetString(FORM_FOCUS))
|
|
||||||
if err != nil {
|
|
||||||
m.err = fmt.Errorf("error parsing focus time duration: %w", err)
|
|
||||||
slog.Fatalf("Error parsing focus time: %v", err)
|
|
||||||
|
|
||||||
return m, tea.Quit
|
|
||||||
}
|
|
||||||
|
|
||||||
breakTime, err := parseDuration(m.form.GetString(FORM_BREAK))
|
|
||||||
if err != nil {
|
|
||||||
m.err = fmt.Errorf("error parsing break time duration: %w", err)
|
|
||||||
slog.Fatalf("Error parsing break time: %v", err)
|
|
||||||
|
|
||||||
return m, tea.Quit
|
|
||||||
}
|
|
||||||
|
|
||||||
m.intervals, err = strconv.Atoi(m.form.GetString(FORM_INTERVALS))
|
|
||||||
if err != nil {
|
|
||||||
m.err = fmt.Errorf("error parsing interval: %w", err)
|
|
||||||
slog.Fatalf("Error parsing interval: %v", err)
|
|
||||||
|
|
||||||
return m, tea.Quit
|
|
||||||
}
|
|
||||||
|
|
||||||
m.focusTime = focusTime
|
|
||||||
m.breakTime = breakTime
|
|
||||||
m.remaining = focusTime
|
|
||||||
m.state = "Focus"
|
|
||||||
m.currentScreen = TIMER_SCREEN
|
|
||||||
m.startTime = time.Now()
|
|
||||||
|
|
||||||
// Run onFocusStart commands
|
|
||||||
m.startCommands(m.onFocusStart)
|
|
||||||
|
|
||||||
return m, tick()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle any uncaptured input screen updates
|
// Handle any uncaptured input screen updates
|
||||||
@ -217,9 +254,52 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case formSubmitMsg:
|
||||||
|
// Get values from the form and send start timer command
|
||||||
|
var err error
|
||||||
|
|
||||||
|
m.focusTime, err = parseDuration(m.form.GetString(FORM_FOCUS))
|
||||||
|
if err != nil {
|
||||||
|
m.err = fmt.Errorf("error parsing focus time duration: %w", err)
|
||||||
|
slog.Fatalf("Error parsing focus time: %v", err)
|
||||||
|
|
||||||
|
return m, tea.Quit
|
||||||
|
}
|
||||||
|
|
||||||
|
m.breakTime, err = parseDuration(m.form.GetString(FORM_BREAK))
|
||||||
|
if err != nil {
|
||||||
|
m.err = fmt.Errorf("error parsing break time duration: %w", err)
|
||||||
|
slog.Fatalf("Error parsing break time: %v", err)
|
||||||
|
|
||||||
|
return m, tea.Quit
|
||||||
|
}
|
||||||
|
|
||||||
|
m.intervals, err = strconv.Atoi(m.form.GetString(FORM_INTERVALS))
|
||||||
|
if err != nil {
|
||||||
|
m.err = fmt.Errorf("error parsing interval: %w", err)
|
||||||
|
slog.Fatalf("Error parsing interval: %v", err)
|
||||||
|
|
||||||
|
return m, tea.Quit
|
||||||
|
}
|
||||||
|
|
||||||
|
return m, startTimer
|
||||||
|
|
||||||
|
case startTimerMsg:
|
||||||
|
// Start the timer
|
||||||
|
m.currentScreen = TIMER_SCREEN
|
||||||
|
// TODO: Could maybe set startTime to 0 and then send a tick command to start the timer
|
||||||
|
// since much of this is duplicate of below
|
||||||
|
m.startTime = time.Now()
|
||||||
|
m.remaining = m.focusTime
|
||||||
|
m.state = "Focus"
|
||||||
|
m.startCommands(m.onFocusStart)
|
||||||
|
|
||||||
|
return m, tick()
|
||||||
|
|
||||||
case timeMsg:
|
case timeMsg:
|
||||||
// Handle timer update for each second
|
// Handle timer update for each second
|
||||||
m.remaining = m.totalTime() - time.Since(m.startTime)
|
m.remaining = m.totalTime() - time.Since(m.startTime)
|
||||||
|
// Check if we've reached a new period
|
||||||
if m.remaining < 0 {
|
if m.remaining < 0 {
|
||||||
if m.isFocus {
|
if m.isFocus {
|
||||||
// Focus period ends, switch to break
|
// Focus period ends, switch to break
|
||||||
@ -257,6 +337,7 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|||||||
m.height = msg.Height
|
m.height = msg.Height
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get errors from shellrunner
|
||||||
for {
|
for {
|
||||||
result := m.shellrunner.GetResults()
|
result := m.shellrunner.GetResults()
|
||||||
if result == nil {
|
if result == nil {
|
||||||
@ -304,6 +385,10 @@ func (m model) View() string {
|
|||||||
|
|
||||||
// View for input screen
|
// View for input screen
|
||||||
func (m model) inputScreenView() string {
|
func (m model) inputScreenView() string {
|
||||||
|
if m.form == nil {
|
||||||
|
return "Loading..."
|
||||||
|
}
|
||||||
|
|
||||||
var builder strings.Builder
|
var builder strings.Builder
|
||||||
|
|
||||||
builder.WriteString("Enter your Pomodoro settings:\n\n")
|
builder.WriteString("Enter your Pomodoro settings:\n\n")
|
||||||
@ -415,34 +500,17 @@ func main() {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set focus, break, and interval values if provided
|
m := newModel(
|
||||||
var defaultFocusTime, defaultBreakTime, defaultIntervals *string
|
|
||||||
|
|
||||||
if focusTime := c.Duration("focus").String(); focusTime != "0s" {
|
|
||||||
defaultFocusTime = &focusTime
|
|
||||||
}
|
|
||||||
if breakTime := c.Duration("break").String(); breakTime != "0s" {
|
|
||||||
defaultBreakTime = &breakTime
|
|
||||||
}
|
|
||||||
if intervals := c.Int("intervals"); intervals != 0 {
|
|
||||||
intervalsString := strconv.Itoa(intervals)
|
|
||||||
defaultIntervals = &intervalsString
|
|
||||||
}
|
|
||||||
|
|
||||||
m := initialModel(
|
|
||||||
c.Bool("fullscreen"),
|
c.Bool("fullscreen"),
|
||||||
c.String("color-left"),
|
c.String("color-left"),
|
||||||
c.String("color-right"),
|
c.String("color-right"),
|
||||||
defaultFocusTime,
|
c.Duration("focus"),
|
||||||
defaultBreakTime,
|
c.Duration("break"),
|
||||||
defaultIntervals,
|
c.Int("intervals"),
|
||||||
|
c.StringSlice("on-focus-start"),
|
||||||
|
c.StringSlice("on-focus-end"),
|
||||||
|
c.StringSlice("on-interval-end"),
|
||||||
)
|
)
|
||||||
|
|
||||||
// Collect command flags
|
|
||||||
m.onFocusStart = c.StringSlice("on-focus-start")
|
|
||||||
m.onFocusEnd = c.StringSlice("on-focus-end")
|
|
||||||
m.onIntervalEnd = c.StringSlice("on-interval-end")
|
|
||||||
|
|
||||||
// Start tea program
|
// Start tea program
|
||||||
|
|
||||||
options := []tea.ProgramOption{}
|
options := []tea.ProgramOption{}
|
||||||
|
116
main_test.go
116
main_test.go
@ -1,6 +1,10 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -60,23 +64,45 @@ func TestParseDuration(t *testing.T) {
|
|||||||
|
|
||||||
// TestRunCommands tests the runCommands function
|
// TestRunCommands tests the runCommands function
|
||||||
func TestRunCommands(t *testing.T) {
|
func TestRunCommands(t *testing.T) {
|
||||||
m := initialModel(false, "#ffdd57", "#57ddff", nil, nil, nil)
|
m := newModelBasic(false, "#ffdd57", "#57ddff")
|
||||||
|
m.onFocusStart = []string{"echo Focus Start"}
|
||||||
|
|
||||||
m.Init()
|
m.Init()
|
||||||
|
m.startCommands(m.onFocusStart)
|
||||||
m.startCommands([]string{"echo Hello, World!"})
|
|
||||||
|
|
||||||
m.shellrunner.Stop()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func sendKeys(m model, keys ...tea.KeyType) (model, tea.Cmd) {
|
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 updatedModel tea.Model
|
||||||
|
|
||||||
var cmd tea.Cmd
|
var cmd tea.Cmd
|
||||||
|
|
||||||
for _, key := range keys {
|
for _, key := range keyMsgs(keys...) {
|
||||||
updatedModel, cmd = m.Update(tea.KeyMsg{Type: key})
|
updatedModel, cmd = m.Update(key)
|
||||||
m = updatedModel.(model)
|
m = updatedModel.(model)
|
||||||
m.form.UpdateFieldPositions()
|
|
||||||
|
if cmd != nil {
|
||||||
|
updatedModel, cmd = m.Update(cmd())
|
||||||
|
m = updatedModel.(model)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return m, cmd
|
return m, cmd
|
||||||
@ -84,44 +110,70 @@ func sendKeys(m model, keys ...tea.KeyType) (model, tea.Cmd) {
|
|||||||
|
|
||||||
// TestInputView tests the Update method of the model for the input view
|
// TestInputView tests the Update method of the model for the input view
|
||||||
func TestInputView(t *testing.T) {
|
func TestInputView(t *testing.T) {
|
||||||
focusInput := "10m"
|
m := newModel(false, "#ffdd57", "#57ddff", 0, 0, 0, []string{}, []string{}, []string{})
|
||||||
breakInput := "5m"
|
|
||||||
intervalInput := "1"
|
|
||||||
|
|
||||||
m := initialModel(false, "#ffdd57", "#57ddff", &focusInput, &breakInput, &intervalInput)
|
var updatedModel tea.Model
|
||||||
m.View()
|
|
||||||
|
|
||||||
assertEqual(t, m.currentScreen, INPUT_SCREEN, "Expected currentScreen to be inputScreen")
|
|
||||||
|
|
||||||
var resultCmd tea.Cmd
|
var resultCmd tea.Cmd
|
||||||
m, resultCmd = sendKeys(m, tea.KeyTab, tea.KeyTab, tea.KeyTab, tea.KeyEnter)
|
|
||||||
|
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")
|
assertNotEqual(t, resultCmd, nil, "Expected resultCmd to be not nil")
|
||||||
|
|
||||||
/*
|
// Apply final next result
|
||||||
* assertEqual(t, m.form.State, huh.StateCompleted, fmt.Sprintf("Expected form state to be completed: %s", m.form.View()))
|
updatedModel, resultCmd = m.Update(resultCmd())
|
||||||
* assertEqual(t, m.currentScreen, TIMER_SCREEN, "Expected currentScreen to be timerScreen")
|
m = updatedModel.(model)
|
||||||
* assertEqual(t, m.remaining.Round(time.Second), 10*time.Minute, "Expected remaining to be 10 minutes")
|
|
||||||
*/
|
// 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")
|
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) {
|
func TestTimerView(t *testing.T) {
|
||||||
m := initialModel(false, "#ffdd57", "#57ddff", nil, nil, nil)
|
m := newModel(false, "#ffdd57", "#57ddff", 10*time.Minute, 10*time.Minute, 2, []string{}, []string{}, []string{})
|
||||||
m.View()
|
|
||||||
|
|
||||||
m.focusTime = 10 * time.Minute
|
var updatedModel tea.Model
|
||||||
m.breakTime = 10 * time.Minute
|
|
||||||
m.intervals = 2
|
// Init model with timer values
|
||||||
m.state = "Focus"
|
updatedModel, _ = m.Update(m.Init())
|
||||||
m.currentScreen = TIMER_SCREEN
|
m = updatedModel.(model)
|
||||||
m.startTime = time.Now()
|
|
||||||
|
// Start timer (batch result from above doesn't apply here)
|
||||||
|
updatedModel, _ = m.Update(startTimer())
|
||||||
|
m = updatedModel.(model)
|
||||||
|
|
||||||
// Test timer view
|
// Test timer view
|
||||||
m.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))
|
oneSec := timeMsg(time.Now().Add(1 * time.Second))
|
||||||
updatedModel, _ := m.Update(oneSec)
|
updatedModel, _ = m.Update(oneSec)
|
||||||
m = updatedModel.(model)
|
m = updatedModel.(model)
|
||||||
|
|
||||||
assertEqual(t, m.state, "Focus", "Expected state to be 'Focus'")
|
assertEqual(t, m.state, "Focus", "Expected state to be 'Focus'")
|
||||||
|
Loading…
Reference in New Issue
Block a user