commit 58d0d37b6e8c4bb4a0bdf1639a8e94507dd357f2 Author: jimi Date: Sat Mar 5 07:44:35 2016 -0600 Initial commit... fails to roll back hour when required by negative minutes diff --git a/README.md b/README.md new file mode 100644 index 0000000..a034f0c --- /dev/null +++ b/README.md @@ -0,0 +1,23 @@ +# Clock + +Implement a clock that handles times without dates. + +Create a clock that is independent of date. + +You should be able to add and subtract minutes to it. + +Two clocks that represent the same time should be equal to each other. + +To run the tests simply run the command `go test` in the exercise directory. + +If the test suite contains benchmarks, you can run these with the `-bench` +flag: + + go test -bench . + +For more detailed info about the Go track see the [help +page](http://exercism.io/languages/go). + +## Source + +Pairing session with Erin Drummond [view source](https://twitter.com/ebdrummond) diff --git a/cases_test.go b/cases_test.go new file mode 100644 index 0000000..287e7fe --- /dev/null +++ b/cases_test.go @@ -0,0 +1,78 @@ +package clock + +// Source: exercism/x-common +// Commit: 269f498 Merge pull request #48 from soniakeys/custom-set-json + +// Test creating a new clock with an initial time. +var timeTests = []struct { + h, m int + want string +}{ + {8, 0, "08:00"}, // on the hour + {9, 0, "09:00"}, // on the hour + {11, 9, "11:09"}, // past the hour + {11, 19, "11:19"}, // past the hour + {24, 0, "00:00"}, // midnight is zero hours + {25, 0, "01:00"}, // hour rolls over + {1, 60, "02:00"}, // sixty minutes is next hour + {0, 160, "02:40"}, // minutes roll over + {25, 160, "03:40"}, // hour and minutes roll over + {-1, 15, "23:15"}, // negative hour + {-25, 0, "23:00"}, // negative hour rolls over + {1, -40, "00:20"}, // negative minutes + {1, -160, "22:20"}, // negative minutes roll over + {-25, -160, "20:20"}, // negative hour and minutes both roll over +} + +// Test adding and subtracting minutes. +var addTests = []struct { + h, m, a int + want string +}{ + {10, 0, 3, "10:03"}, // add minutes + {0, 45, 40, "01:25"}, // add to next hour + {10, 0, 61, "11:01"}, // add more than one hour + {23, 59, 2, "00:01"}, // add across midnight + {5, 32, 1500, "06:32"}, // add more than one day (1500 min = 25 hrs) + {0, 45, 160, "03:25"}, // add more than two hours with carry + {10, 3, -3, "10:00"}, // subtract minutes + {10, 3, -30, "09:33"}, // subtract to previous hour + {10, 3, -70, "08:53"}, // subtract more than an hour + {0, 3, -4, "23:59"}, // subtract across midnight + {0, 0, -160, "21:20"}, // subtract more than two hours + {5, 32, -1500, "04:32"}, // subtract more than one day (1500 min = 25 hrs) + {6, 15, -160, "03:35"}, // subtract more than two hours with borrow +} + +// Construct two separate clocks, set times, test if they are equal. +type hm struct{ h, m int } + +var eqTests = []struct { + c1, c2 hm + want bool +}{ + // clocks with same time + { + hm{15, 37}, + hm{15, 37}, + true, + }, + // clocks a minute apart + { + hm{15, 36}, + hm{15, 37}, + false, + }, + // clocks an hour apart + { + hm{14, 37}, + hm{15, 37}, + false, + }, + // clocks set 24 hours apart + { + hm{10, 37}, + hm{34, 37}, + true, + }, +} diff --git a/clock.go b/clock.go new file mode 100644 index 0000000..ec7cb27 --- /dev/null +++ b/clock.go @@ -0,0 +1,41 @@ +package clock + +import "fmt" + +const ( + testVersion = 3 + minutesPerHour = 60 + hoursPerDay = 24 +) + +type Clock struct { + hour int + minutes int +} + +func New(hour, minute int) Clock { + h, m := adjustTime(hour, minute) + return Clock{h, m} +} + +func (c Clock) String() string { + return fmt.Sprintf("%02d:%02d", c.hour, c.minutes) +} + +func (c Clock) Add(minutes int) Clock { + min := c.minutes + minutes + c.hour, c.minutes = adjustTime(c.hour, min) + return c +} + +func adjustTime(h, m int) (int, int) { + h = (h + (m / minutesPerHour)) % hoursPerDay + if h < 0 { + h += hoursPerDay + } + m = m % minutesPerHour + if m < 0 { + m += minutesPerHour + } + return h, m +} diff --git a/clock_test.go b/clock_test.go new file mode 100644 index 0000000..de96a69 --- /dev/null +++ b/clock_test.go @@ -0,0 +1,83 @@ +package clock + +import ( + "reflect" + "testing" +) + +// Clock type API: +// +// New(hour, minute int) Clock // a "constructor" +// (Clock) String() string // a "stringer" +// (Clock) Add(minutes int) Clock +// +// The Add method should also handle subtraction by accepting negative values. +// To satisfy the readme requirement about clocks being equal, values of +// your Clock type need to work with the == operator. +// +// It might help to study the time.Time type in the standard library +// (https://golang.org/pkg/time/#Time) as a model. See how constructors there +// (Date and Now) return Time values rather than pointers. Note also how +// most time.Time methods have value receivers rather than pointer receivers. +// For more background on this read +// https://github.com/golang/go/wiki/CodeReviewComments#receiver-type. + +const targetTestVersion = 3 + +func TestCreateClock(t *testing.T) { + if testVersion != targetTestVersion { + t.Fatalf("Found testVersion = %v, want %v", testVersion, targetTestVersion) + } + for _, n := range timeTests { + if got := New(n.h, n.m); got.String() != n.want { + t.Fatalf("New(%d, %d) = %q, want %q", n.h, n.m, got, n.want) + } + } + t.Log(len(timeTests), "test cases") +} + +func TestAddMinutes(t *testing.T) { + for _, a := range addTests { + if got := New(a.h, a.m).Add(a.a); got.String() != a.want { + t.Fatalf("New(%d, %d).Add(%d) = %q, want %q", + a.h, a.m, a.a, got, a.want) + } + } + t.Log(len(addTests), "test cases") +} + +func TestCompareClocks(t *testing.T) { + for _, e := range eqTests { + clock1 := New(e.c1.h, e.c1.m) + clock2 := New(e.c2.h, e.c2.m) + got := clock1 == clock2 + if got != e.want { + t.Log("Clock1:", clock1) + t.Log("Clock2:", clock2) + t.Logf("Clock1 == Clock2 is %t, want %t", got, e.want) + if reflect.DeepEqual(clock1, clock2) { + t.Log("(Hint: see comments in clock_test.go.)") + } + t.FailNow() + } + } + t.Log(len(eqTests), "test cases") +} + +func BenchmarkAddMinutes(b *testing.B) { + c := New(12, 0) + b.ResetTimer() + for i := 0; i < b.N; i++ { + for _, a := range addTests { + c.Add(a.a) + } + } +} + +func BenchmarkCreateClocks(b *testing.B) { + for i := 0; i < b.N; i++ { + for _, n := range timeTests { + New(n.h, n.m) + } + } +}