1// Copyright 2013 The go-github AUTHORS. All rights reserved.
2//
3// Use of this source code is governed by a BSD-style
4// license that can be found in the LICENSE file.
5
6package github
7
8import (
9	"encoding/json"
10	"fmt"
11	"testing"
12	"time"
13)
14
15const (
16	emptyTimeStr               = `"0001-01-01T00:00:00Z"`
17	referenceTimeStr           = `"2006-01-02T15:04:05Z"`
18	referenceTimeStrFractional = `"2006-01-02T15:04:05.000Z"` // This format was returned by the Projects API before October 1, 2017.
19	referenceUnixTimeStr       = `1136214245`
20)
21
22var (
23	referenceTime = time.Date(2006, time.January, 02, 15, 04, 05, 0, time.UTC)
24	unixOrigin    = time.Unix(0, 0).In(time.UTC)
25)
26
27func TestTimestamp_Marshal(t *testing.T) {
28	testCases := []struct {
29		desc    string
30		data    Timestamp
31		want    string
32		wantErr bool
33		equal   bool
34	}{
35		{"Reference", Timestamp{referenceTime}, referenceTimeStr, false, true},
36		{"Empty", Timestamp{}, emptyTimeStr, false, true},
37		{"Mismatch", Timestamp{}, referenceTimeStr, false, false},
38	}
39	for _, tc := range testCases {
40		out, err := json.Marshal(tc.data)
41		if gotErr := err != nil; gotErr != tc.wantErr {
42			t.Errorf("%s: gotErr=%v, wantErr=%v, err=%v", tc.desc, gotErr, tc.wantErr, err)
43		}
44		got := string(out)
45		equal := got == tc.want
46		if (got == tc.want) != tc.equal {
47			t.Errorf("%s: got=%s, want=%s, equal=%v, want=%v", tc.desc, got, tc.want, equal, tc.equal)
48		}
49	}
50}
51
52func TestTimestamp_Unmarshal(t *testing.T) {
53	testCases := []struct {
54		desc    string
55		data    string
56		want    Timestamp
57		wantErr bool
58		equal   bool
59	}{
60		{"Reference", referenceTimeStr, Timestamp{referenceTime}, false, true},
61		{"ReferenceUnix", referenceUnixTimeStr, Timestamp{referenceTime}, false, true},
62		{"ReferenceFractional", referenceTimeStrFractional, Timestamp{referenceTime}, false, true},
63		{"Empty", emptyTimeStr, Timestamp{}, false, true},
64		{"UnixStart", `0`, Timestamp{unixOrigin}, false, true},
65		{"Mismatch", referenceTimeStr, Timestamp{}, false, false},
66		{"MismatchUnix", `0`, Timestamp{}, false, false},
67		{"Invalid", `"asdf"`, Timestamp{referenceTime}, true, false},
68	}
69	for _, tc := range testCases {
70		var got Timestamp
71		err := json.Unmarshal([]byte(tc.data), &got)
72		if gotErr := err != nil; gotErr != tc.wantErr {
73			t.Errorf("%s: gotErr=%v, wantErr=%v, err=%v", tc.desc, gotErr, tc.wantErr, err)
74			continue
75		}
76		equal := got.Equal(tc.want)
77		if equal != tc.equal {
78			t.Errorf("%s: got=%#v, want=%#v, equal=%v, want=%v", tc.desc, got, tc.want, equal, tc.equal)
79		}
80	}
81}
82
83func TestTimstamp_MarshalReflexivity(t *testing.T) {
84	testCases := []struct {
85		desc string
86		data Timestamp
87	}{
88		{"Reference", Timestamp{referenceTime}},
89		{"Empty", Timestamp{}},
90	}
91	for _, tc := range testCases {
92		data, err := json.Marshal(tc.data)
93		if err != nil {
94			t.Errorf("%s: Marshal err=%v", tc.desc, err)
95		}
96		var got Timestamp
97		err = json.Unmarshal(data, &got)
98		if err != nil {
99			t.Errorf("%s: Unmarshal err=%v", tc.desc, err)
100		}
101		if !got.Equal(tc.data) {
102			t.Errorf("%s: %+v != %+v", tc.desc, got, data)
103		}
104	}
105}
106
107type WrappedTimestamp struct {
108	A    int
109	Time Timestamp
110}
111
112func TestWrappedTimstamp_Marshal(t *testing.T) {
113	testCases := []struct {
114		desc    string
115		data    WrappedTimestamp
116		want    string
117		wantErr bool
118		equal   bool
119	}{
120		{"Reference", WrappedTimestamp{0, Timestamp{referenceTime}}, fmt.Sprintf(`{"A":0,"Time":%s}`, referenceTimeStr), false, true},
121		{"Empty", WrappedTimestamp{}, fmt.Sprintf(`{"A":0,"Time":%s}`, emptyTimeStr), false, true},
122		{"Mismatch", WrappedTimestamp{}, fmt.Sprintf(`{"A":0,"Time":%s}`, referenceTimeStr), false, false},
123	}
124	for _, tc := range testCases {
125		out, err := json.Marshal(tc.data)
126		if gotErr := err != nil; gotErr != tc.wantErr {
127			t.Errorf("%s: gotErr=%v, wantErr=%v, err=%v", tc.desc, gotErr, tc.wantErr, err)
128		}
129		got := string(out)
130		equal := got == tc.want
131		if equal != tc.equal {
132			t.Errorf("%s: got=%s, want=%s, equal=%v, want=%v", tc.desc, got, tc.want, equal, tc.equal)
133		}
134	}
135}
136
137func TestWrappedTimstamp_Unmarshal(t *testing.T) {
138	testCases := []struct {
139		desc    string
140		data    string
141		want    WrappedTimestamp
142		wantErr bool
143		equal   bool
144	}{
145		{"Reference", referenceTimeStr, WrappedTimestamp{0, Timestamp{referenceTime}}, false, true},
146		{"ReferenceUnix", referenceUnixTimeStr, WrappedTimestamp{0, Timestamp{referenceTime}}, false, true},
147		{"Empty", emptyTimeStr, WrappedTimestamp{0, Timestamp{}}, false, true},
148		{"UnixStart", `0`, WrappedTimestamp{0, Timestamp{unixOrigin}}, false, true},
149		{"Mismatch", referenceTimeStr, WrappedTimestamp{0, Timestamp{}}, false, false},
150		{"MismatchUnix", `0`, WrappedTimestamp{0, Timestamp{}}, false, false},
151		{"Invalid", `"asdf"`, WrappedTimestamp{0, Timestamp{referenceTime}}, true, false},
152	}
153	for _, tc := range testCases {
154		var got Timestamp
155		err := json.Unmarshal([]byte(tc.data), &got)
156		if gotErr := err != nil; gotErr != tc.wantErr {
157			t.Errorf("%s: gotErr=%v, wantErr=%v, err=%v", tc.desc, gotErr, tc.wantErr, err)
158			continue
159		}
160		equal := got.Time.Equal(tc.want.Time.Time)
161		if equal != tc.equal {
162			t.Errorf("%s: got=%#v, want=%#v, equal=%v, want=%v", tc.desc, got, tc.want, equal, tc.equal)
163		}
164	}
165}
166
167func TestWrappedTimstamp_MarshalReflexivity(t *testing.T) {
168	testCases := []struct {
169		desc string
170		data WrappedTimestamp
171	}{
172		{"Reference", WrappedTimestamp{0, Timestamp{referenceTime}}},
173		{"Empty", WrappedTimestamp{0, Timestamp{}}},
174	}
175	for _, tc := range testCases {
176		bytes, err := json.Marshal(tc.data)
177		if err != nil {
178			t.Errorf("%s: Marshal err=%v", tc.desc, err)
179		}
180		var got WrappedTimestamp
181		err = json.Unmarshal(bytes, &got)
182		if err != nil {
183			t.Errorf("%s: Unmarshal err=%v", tc.desc, err)
184		}
185		if !got.Time.Equal(tc.data.Time) {
186			t.Errorf("%s: %+v != %+v", tc.desc, got, tc.data)
187		}
188	}
189}
190