package main import ( "bytes" "reflect" "testing" "time" ) const write = "write" const sleep = "sleep" type SpyCountdownOperations struct { Calls []string } func (s *SpyCountdownOperations) Sleep() { s.Calls = append(s.Calls, sleep) } func (s *SpyCountdownOperations) Write(p []byte) (n int, err error) { s.Calls = append(s.Calls, write) return } func TestCountdownRuns(t *testing.T) { t.Run("Prints 3 to Go!", func(t *testing.T) { count := 3 buffer := &bytes.Buffer{} sleeper := &SpyCountdownOperations{} Countdown(buffer, sleeper, count) got := buffer.String() // ` backtick allows strings with preserved newlines. want := `3 2 1 Go! ` if got != want { t.Errorf("got %q want %q", got, want) } if len(sleeper.Calls) != 3 { t.Errorf("Not enough calls to sleeper, want 3 got %q", sleeper.Calls) } }) t.Run("Prints 4 to Go!", func(t *testing.T) { count := 4 buffer := &bytes.Buffer{} sleeper := &SpyCountdownOperations{} Countdown(buffer, sleeper, count) got := buffer.String() // ` backtick allows strings with preserved newlines. want := `4 3 2 1 Go! ` if got != want { t.Errorf("got %q want %q", got, want) } if len(sleeper.Calls) != 4 { t.Errorf("Not enough calls to sleeper, want 3 got %q", sleeper.Calls) } }) t.Run("sleep before every print", func(t *testing.T) { count := 3 sleeper := &SpyCountdownOperations{} Countdown(sleeper, sleeper, count) want := []string{ write, sleep, write, sleep, write, sleep, write, } if !reflect.DeepEqual(want, sleeper.Calls) { t.Errorf("wanted calls %v got %v", want, sleeper.Calls) } }) } type SpyTimeSleeper struct { durationSlept time.Duration } func (s *SpyTimeSleeper) Sleep(duration time.Duration) { s.durationSlept = duration } func TestConfigurableSleeper(t *testing.T) { sleepTime := 5 * time.Second spyTime := &SpyTimeSleeper{} sleeper := ConfigurableSleeper{sleepTime, spyTime.Sleep} sleeper.Sleep() if spyTime.durationSlept != sleepTime { t.Errorf("should have slept for %v but slept for %v", spyTime.durationSlept, sleepTime) } }