forked from fxtlabs/date
-
Notifications
You must be signed in to change notification settings - Fork 23
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1 from avalchev94/master
Added interface implementations for Clock - good work, thanks :)
- Loading branch information
Showing
4 changed files
with
306 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
package clock | ||
|
||
import ( | ||
"errors" | ||
) | ||
|
||
// MarshalBinary implements the encoding.BinaryMarshaler interface. | ||
func (c Clock) MarshalBinary() ([]byte, error) { | ||
enc := []byte{ | ||
byte(c >> 24), | ||
byte(c >> 16), | ||
byte(c >> 8), | ||
byte(c), | ||
} | ||
return enc, nil | ||
} | ||
|
||
// UnmarshalBinary implements the encoding.BinaryUnmarshaler interface. | ||
func (c *Clock) UnmarshalBinary(data []byte) error { | ||
if len(data) == 0 { | ||
return errors.New("Clock.UnmarshalBinary: no data") | ||
} | ||
if len(data) != 4 { | ||
return errors.New("Clock.UnmarshalBinary: invalid length") | ||
} | ||
|
||
*c = Clock(data[3]) | Clock(data[2])<<8 | Clock(data[1])<<16 | Clock(data[0])<<24 | ||
return nil | ||
} | ||
|
||
// MarshalText implements the encoding.TextMarshaler interface. | ||
func (c Clock) MarshalText() ([]byte, error) { | ||
return []byte(c.String()), nil | ||
} | ||
|
||
// UnmarshalText implements the encoding.TextUnmarshaler interface. | ||
func (c *Clock) UnmarshalText(data []byte) (err error) { | ||
clock, err := Parse(string(data)) | ||
if err == nil { | ||
*c = clock | ||
} | ||
return err | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,149 @@ | ||
package clock | ||
|
||
import ( | ||
"bytes" | ||
"encoding/gob" | ||
"encoding/json" | ||
"strings" | ||
"testing" | ||
) | ||
|
||
func TestGobEncoding(t *testing.T) { | ||
var b bytes.Buffer | ||
encoder := gob.NewEncoder(&b) | ||
decoder := gob.NewDecoder(&b) | ||
cases := []Clock{ | ||
New(-1, -1, -1, -1), | ||
New(0, 0, 0, 0), | ||
New(12, 40, 40, 80), | ||
New(13, 55, 0, 20), | ||
New(16, 20, 0, 0), | ||
New(20, 60, 59, 59), | ||
New(24, 0, 0, 0), | ||
New(24, 0, 0, 1), | ||
} | ||
for _, c := range cases { | ||
var clock Clock | ||
err := encoder.Encode(&c) | ||
if err != nil { | ||
t.Errorf("Gob(%v) encode error %v", c, err) | ||
} else { | ||
err = decoder.Decode(&clock) | ||
if err != nil { | ||
t.Errorf("Gob(%v) decode error %v", c, err) | ||
} else if clock != c { | ||
t.Errorf("Gob(%v) decode got %v", c, clock) | ||
} | ||
} | ||
} | ||
} | ||
|
||
func TestJSONMarshalling(t *testing.T) { | ||
cases := []struct { | ||
value Clock | ||
want string | ||
}{ | ||
{New(-1, -1, -1, -1), `"22:58:58.999"`}, | ||
{New(0, 0, 0, 0), `"00:00:00.000"`}, | ||
{New(12, 40, 40, 80), `"12:40:40.080"`}, | ||
{New(13, 55, 0, 20), `"13:55:00.020"`}, | ||
{New(16, 20, 0, 0), `"16:20:00.000"`}, | ||
{New(20, 60, 59, 59), `"21:00:59.059"`}, | ||
{New(24, 0, 0, 0), `"24:00:00.000"`}, | ||
{New(24, 0, 0, 1), `"00:00:00.001"`}, | ||
} | ||
for _, c := range cases { | ||
bb, err := json.Marshal(c.value) | ||
if err != nil { | ||
t.Errorf("JSON(%v) marshal error %v", c, err) | ||
} else if string(bb) != c.want { | ||
t.Errorf("JSON(%v) == %v, want %v", c.value, string(bb), c.want) | ||
} | ||
} | ||
} | ||
|
||
func TestJSONUnmarshalling(t *testing.T) { | ||
cases := []struct { | ||
values []string | ||
want Clock | ||
}{ | ||
{[]string{`"22:58:58.999"`, `"10:58:58.999pm"`}, New(-1, -1, -1, -1)}, | ||
{[]string{`"00:00:00.000"`, `"00:00:00.000AM"`}, New(0, 0, 0, 0)}, | ||
{[]string{`"12:40:40.080"`, `"12:40:40.080PM"`}, New(12, 40, 40, 80)}, | ||
{[]string{`"13:55:00.020"`, `"01:55:00.020PM"`}, New(13, 55, 0, 20)}, | ||
{[]string{`"16:20:00.000"`, `"04:20:00.000pm"`}, New(16, 20, 0, 0)}, | ||
{[]string{`"21:00:59.059"`, `"09:00:59.059PM"`}, New(20, 60, 59, 59)}, | ||
{[]string{`"24:00:00.000"`, `"00:00:00.000am"`}, New(24, 0, 0, 0)}, | ||
{[]string{`"00:00:00.001"`, `"00:00:00.001AM"`}, New(24, 0, 0, 1)}, | ||
} | ||
|
||
for _, c := range cases { | ||
for _, v := range c.values { | ||
var clock Clock | ||
err := json.Unmarshal([]byte(v), &clock) | ||
if err != nil { | ||
t.Errorf("JSON(%v) unmarshal error %v", v, err) | ||
} else if c.want.Mod24() != clock.Mod24() { | ||
t.Errorf("JSON(%v) == %v, want %v", v, clock, c.want) | ||
} | ||
} | ||
} | ||
} | ||
|
||
func TestBinaryMarshalling(t *testing.T) { | ||
cases := []Clock{ | ||
New(-1, -1, -1, -1), | ||
New(0, 0, 0, 0), | ||
New(12, 40, 40, 80), | ||
New(13, 55, 0, 20), | ||
New(16, 20, 0, 0), | ||
New(20, 60, 59, 59), | ||
New(24, 0, 0, 0), | ||
New(24, 0, 0, 1), | ||
} | ||
for _, c := range cases { | ||
bb, err := c.MarshalBinary() | ||
if err != nil { | ||
t.Errorf("Binary(%v) marshal error %v", c, err) | ||
} else { | ||
var clock Clock | ||
err = clock.UnmarshalBinary(bb) | ||
if err != nil { | ||
t.Errorf("Binary(% v) unmarshal error %v", c, err) | ||
} else if clock.Mod24() != c.Mod24() { | ||
t.Errorf("Binary(%v) unmarshal got %v", c, clock) | ||
} | ||
} | ||
} | ||
} | ||
|
||
func TestBinaryUnmarshallingErrors(t *testing.T) { | ||
var c Clock | ||
err1 := c.UnmarshalBinary([]byte{}) | ||
if err1 == nil { | ||
t.Errorf("unmarshal no empty data error") | ||
} | ||
|
||
err2 := c.UnmarshalBinary([]byte("12345")) | ||
if err2 == nil { | ||
t.Errorf("unmarshal no wrong length error") | ||
} | ||
} | ||
|
||
func TestInvalidClockText(t *testing.T) { | ||
cases := []struct { | ||
value string | ||
want string | ||
}{ | ||
{`not-a-clock`, `clock.Clock: cannot parse not-a-clock`}, | ||
{`00:50:100.0`, `clock.Clock: cannot parse 00:50:100.0`}, | ||
{`24:00:00.0pM`, `clock.Clock: cannot parse 24:00:00.0pM: strconv.Atoi: parsing "0pM": invalid syntax`}, | ||
} | ||
for _, c := range cases { | ||
var clock Clock | ||
err := clock.UnmarshalText([]byte(c.value)) | ||
if err == nil || !strings.Contains(err.Error(), c.want) { | ||
t.Errorf("InvalidText(%v) == %v, want %v", c.value, err, c.want) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
package clock | ||
|
||
import ( | ||
"database/sql/driver" | ||
"fmt" | ||
"time" | ||
) | ||
|
||
// Scan parses some value. It implements sql.Scanner, | ||
// https://golang.org/pkg/database/sql/#Scanner | ||
func (c *Clock) Scan(value interface{}) (err error) { | ||
if value == nil { | ||
return nil | ||
} | ||
|
||
return c.scanAny(value) | ||
} | ||
|
||
func (c *Clock) scanAny(value interface{}) (err error) { | ||
err = nil | ||
switch value.(type) { | ||
case int64: | ||
*c = Clock(value.(int64)) | ||
case []byte: | ||
*c, err = Parse(string(value.([]byte))) | ||
case string: | ||
*c, err = Parse(value.(string)) | ||
case time.Time: | ||
*c = NewAt(value.(time.Time)) | ||
default: | ||
err = fmt.Errorf("%T %+v is not a meaningful clock", value, value) | ||
} | ||
return | ||
} | ||
|
||
// Value converts the value to an int64. It implements driver.Valuer, | ||
// https://golang.org/pkg/database/sql/driver/#Valuer | ||
func (c Clock) Value() (driver.Value, error) { | ||
|
||
return int64(c), nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
package clock | ||
|
||
import ( | ||
"database/sql/driver" | ||
"testing" | ||
"time" | ||
) | ||
|
||
func TestClockScan(t *testing.T) { | ||
now := time.Now() | ||
|
||
cases := []struct { | ||
v interface{} | ||
expected Clock | ||
}{ | ||
{int64(New(-1, -1, -1, -1)), New(-1, -1, -1, -1)}, | ||
{int64(New(10, 60, 10, 0)), New(10, 60, 10, 0)}, | ||
{int64(New(24, 10, 0, 10)), New(0, 10, 0, 10)}, | ||
{"12:00:00.400", New(12, 0, 0, 400)}, | ||
{"01:40:50.000pm", New(13, 40, 50, 0)}, | ||
{"4:20:00.000pm", New(16, 20, 0, 0)}, | ||
{[]byte("23:60:60.000"), New(0, 1, 0, 0)}, | ||
{now, NewAt(now)}, | ||
} | ||
|
||
for i, c := range cases { | ||
var clock Clock | ||
e := clock.Scan(c.v) | ||
if e != nil { | ||
t.Errorf("%d: Got %v for %d", i, e, c.expected) | ||
} else if clock.Mod24() != c.expected.Mod24() { | ||
t.Errorf("%d: Got %v, want %d", i, clock, c.expected) | ||
} | ||
|
||
var d driver.Valuer = clock | ||
|
||
q, e := d.Value() | ||
if e != nil { | ||
t.Errorf("%d: Got %v for %d", i, e, c.expected) | ||
} else if Clock(q.(int64)).Mod24() != c.expected.Mod24() { | ||
t.Errorf("%d: Got %v, want %d", i, q, c.expected) | ||
} | ||
} | ||
} | ||
|
||
func TestClockScanWithJunk(t *testing.T) { | ||
cases := []struct { | ||
v interface{} | ||
expected string | ||
}{ | ||
{true, "bool true is not a meaningful clock"}, | ||
{false, "bool false is not a meaningful clock"}, | ||
} | ||
|
||
for i, c := range cases { | ||
var clock Clock | ||
e := clock.Scan(c.v) | ||
if e.Error() != c.expected { | ||
t.Errorf("%d: Got %q, want %q", i, e.Error(), c.expected) | ||
} | ||
} | ||
} | ||
|
||
func TestClockScanWithNil(t *testing.T) { | ||
var r *Clock | ||
e := r.Scan(nil) | ||
if e != nil { | ||
t.Errorf("Got %v", e) | ||
} | ||
if r != nil { | ||
t.Errorf("Got %v", r) | ||
} | ||
} |