OLD | NEW |
| (Empty) |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 package funnybase | |
6 | |
7 import ( | |
8 "bytes" | |
9 "flag" | |
10 "fmt" | |
11 "io" | |
12 "math" | |
13 "math/rand" | |
14 "sort" | |
15 "testing" | |
16 "time" | |
17 | |
18 . "github.com/smartystreets/goconvey/convey" | |
19 ) | |
20 | |
21 type testCase struct { | |
22 expect []byte | |
23 val int64 | |
24 } | |
25 | |
26 type testCaseSlice []testCase | |
27 | |
28 func (t testCaseSlice) Len() int { return len(t) } | |
29 func (t testCaseSlice) Less(i, j int) bool { return t[i].val < t[j].val } | |
30 func (t testCaseSlice) Swap(i, j int) { t[i], t[j] = t[j], t[i] } | |
31 | |
32 var cases = testCaseSlice{ | |
33 {[]byte{b01000000, b01111111, b11111111, b11111111, b11111111, 0xff, 0xf
f, 0xff, b11111111}, -math.MaxInt64 - 1}, | |
34 {[]byte{b01000001, b00000000, b00000000, b00000000, b00000000, 0, 0, 0,
b00000001}, -math.MaxInt64}, | |
35 {[]byte{b01000001, b00000000, b00000000, b00000000, b00000000, 0, 0, 0,
b00000011}, -math.MaxInt64 + 1}, | |
36 {[]byte{b01100000, b01111111, b11111111, b11111111, b11111111}, -math.Ma
xInt32 - 1}, | |
37 {[]byte{b01100001, b00000000, b00000000, b00000000, b00000001}, -math.Ma
xInt32}, | |
38 {[]byte{b01100001, b00000000, b00000000, b00000000, b00000011}, -math.Ma
xInt32 + 1}, | |
39 {[]byte{b01110000, b01111111, b11111111}, -math.MaxInt16 - 1}, | |
40 {[]byte{b01111000, b01111110}, -129}, | |
41 {[]byte{b01111000, b01111111}, -128}, | |
42 {[]byte{b01111001, b00000001}, -127}, | |
43 {[]byte{b01111001, b01111101}, -65}, | |
44 {[]byte{b01111001, b01111111}, -64}, | |
45 {[]byte{b01111010, b00000011}, -63}, | |
46 {[]byte{b01111101, b01011111}, -5}, | |
47 {[]byte{b01111110, b00111111}, -3}, | |
48 {[]byte{b01111111, b01111111}, -1}, | |
49 {[]byte{b10000000, b00000000}, 0}, | |
50 {[]byte{b10000010, b10100000}, 5}, | |
51 {[]byte{b10000100, b10001000}, 17}, | |
52 {[]byte{b10000101, b11111100}, 63}, | |
53 {[]byte{b10000110, b10000000}, 64}, | |
54 {[]byte{b10000110, b10000010}, 65}, | |
55 {[]byte{b10000111, b10000000}, 128}, | |
56 {[]byte{b10011110, b11111111, 0xff, 0xff, b11111110}, math.MaxInt32}, | |
57 {[]byte{b10011111, b10000000, 0, 0, 0}, math.MaxInt32 + 1}, | |
58 {[]byte{b10111110, b11111111, 0xff, 0xff, b11111111, 0xff, 0xff, 0xff, b
11111110}, math.MaxInt64}, | |
59 } | |
60 | |
61 var seed = flag.Int64("funnybase.seed", 0, "Random seed to use for randomized fu
nnybase tests") | |
62 | |
63 func init() { | |
64 flag.Parse() | |
65 if *seed == 0 { | |
66 *seed = time.Now().UnixNano() | |
67 } | |
68 fmt.Println("funnybase.seed =", *seed) | |
69 } | |
70 | |
71 func TestPut(t *testing.T) { | |
72 Convey("Put", t, func() { | |
73 for _, c := range cases { | |
74 c := c | |
75 Convey(fmt.Sprintf("%d -> % x", c.val, c.expect), func()
{ | |
76 Convey("Put", func() { | |
77 buf := make([]byte, MaxFunnyBaseLen64) | |
78 n := Put(buf, c.val) | |
79 So(n, ShouldEqual, len(c.expect)) | |
80 So(buf[:n], ShouldResemble, c.expect) | |
81 }) | |
82 Convey("Write", func() { | |
83 buf := &bytes.Buffer{} | |
84 err := Write(buf, c.val) | |
85 So(err, ShouldBeNil) | |
86 So(buf.Bytes(), ShouldResemble, c.expect
) | |
87 }) | |
88 | |
89 if c.val >= 0 { | |
90 Convey("PutUint", func() { | |
91 buf := make([]byte, MaxFunnyBase
Len64) | |
92 n := PutUint(buf, uint64(c.val)) | |
93 So(n, ShouldEqual, len(c.expect)
) | |
94 So(buf[:n], ShouldResemble, c.ex
pect) | |
95 }) | |
96 Convey("WriteUint", func() { | |
97 buf := &bytes.Buffer{} | |
98 err := WriteUint(buf, uint64(c.v
al)) | |
99 So(err, ShouldBeNil) | |
100 So(buf.Bytes(), ShouldResemble,
c.expect) | |
101 }) | |
102 } | |
103 }) | |
104 } | |
105 }) | |
106 } | |
107 | |
108 func TestGet(t *testing.T) { | |
109 Convey("Get", t, func() { | |
110 for _, c := range cases { | |
111 c := c | |
112 Convey(fmt.Sprintf("% x -> %d", c.expect, c.val), func()
{ | |
113 v, n := Get(c.expect) | |
114 So(n, ShouldEqual, len(c.expect)) | |
115 So(v, ShouldEqual, c.val) | |
116 | |
117 if c.val >= 0 { | |
118 v, n := GetUint(c.expect) | |
119 So(n, ShouldEqual, len(c.expect)) | |
120 So(v, ShouldEqual, c.val) | |
121 } | |
122 }) | |
123 } | |
124 }) | |
125 } | |
126 | |
127 func TestRead(t *testing.T) { | |
128 Convey("Read", t, func() { | |
129 for _, c := range cases { | |
130 c := c | |
131 Convey(fmt.Sprintf("% x -> %d", c.expect, c.val), func()
{ | |
132 buf := bytes.NewBuffer(c.expect) | |
133 v, err := Read(buf) | |
134 So(err, ShouldBeNil) | |
135 So(v, ShouldEqual, c.val) | |
136 | |
137 if c.val >= 0 { | |
138 buf := bytes.NewBuffer(c.expect) | |
139 v, err := ReadUint(buf) | |
140 So(err, ShouldBeNil) | |
141 So(v, ShouldEqual, c.val) | |
142 } | |
143 }) | |
144 } | |
145 }) | |
146 } | |
147 | |
148 func TestSort(t *testing.T) { | |
149 // TODO(iannucci): Enable full test with num = 20000000. | |
150 num := 100000 | |
151 num += len(cases) | |
152 randomCases := make(testCaseSlice, num) | |
153 | |
154 rcSub := randomCases[copy(randomCases, cases):] | |
155 r := rand.New(rand.NewSource(*seed)) | |
156 for i := range rcSub { | |
157 v := int64(uint64(r.Uint32())<<32 | uint64(r.Uint32())) | |
158 rcSub[i].val = v | |
159 buf := make([]byte, MaxFunnyBaseLen64) | |
160 rcSub[i].expect = buf[:Put(buf, v)] | |
161 } | |
162 | |
163 sort.Sort(randomCases) | |
164 | |
165 shouldBeLessThanOrEqual := func(actual interface{}, expected ...interfac
e{}) string { | |
166 a, b := actual.([]byte), expected[0].([]byte) | |
167 if bytes.Compare(a, b) <= 0 { | |
168 return fmt.Sprintf("Expected A <= B (but it wasn't)!\nA:
[% x]\nB: [% x]", a, b) | |
169 } | |
170 return "" | |
171 } | |
172 | |
173 Convey("TestSort", t, func() { | |
174 prev := randomCases[0] | |
175 for _, c := range randomCases[1:] { | |
176 // Actually asserting with the So for every entry in the
sorted array will | |
177 // produce 100000 green checkmarks on a sucessful test,
which is a bit | |
178 // much :). | |
179 if bytes.Compare(c.expect, prev.expect) < 0 { | |
180 So(c.expect, shouldBeLessThanOrEqual, prev.expec
t) | |
181 break | |
182 } | |
183 prev = c | |
184 } | |
185 | |
186 // This silly assertion is done so that this test has a green ch
eck next to | |
187 // it in the event that it passes. Otherwise convey thinks we sk
ipped the | |
188 // test, which isn't correct. | |
189 So(true, ShouldBeTrue) | |
190 }) | |
191 } | |
192 | |
193 type fakeWriter struct{ count int } | |
194 | |
195 func (f *fakeWriter) WriteByte(byte) error { | |
196 if f.count == 0 { | |
197 return fmt.Errorf("nope") | |
198 } | |
199 f.count-- | |
200 return nil | |
201 } | |
202 | |
203 func TestErrors(t *testing.T) { | |
204 smallerInt64 := []byte{b01000000, b01111111, b11111111, b11111111, b1111
1111, 0xff, 0xff, 0xff, b11111110} | |
205 | |
206 prettyBigUint64 := []byte{b10111111, b10000000, 0, 0, 0, 0, 0, 0, 0} | |
207 prettyBigUint64Val := uint64(math.MaxInt64 + 1) | |
208 | |
209 reallyBigUint64 := []byte{b10111111, b11111111, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff} | |
210 reallyBigUint64Val := uint64(math.MaxUint64) | |
211 tests := []struct { | |
212 name string | |
213 buf []byte | |
214 | |
215 v int64 | |
216 n int | |
217 err error | |
218 | |
219 uv uint64 | |
220 un int | |
221 uerr error | |
222 }{ | |
223 { | |
224 name: "Too big!!", | |
225 buf: []byte{b11000000}, // 65 bits!? | |
226 n: -1, | |
227 un: -1, | |
228 err: ErrOverflow, | |
229 uerr: ErrOverflow, | |
230 }, { | |
231 name: "Nil buffer", | |
232 err: io.EOF, | |
233 uerr: io.EOF, | |
234 }, { | |
235 name: "Empty buffer", | |
236 buf: []byte{}, | |
237 err: io.EOF, | |
238 uerr: io.EOF, | |
239 }, { | |
240 name: "Small buffer", | |
241 buf: cases[len(cases)-1].expect[:4], | |
242 err: io.EOF, | |
243 uerr: io.EOF, | |
244 }, { | |
245 name: "Reading a negative number with *Uint", | |
246 buf: cases[0].expect, | |
247 v: cases[0].val, | |
248 n: len(cases[0].expect), | |
249 | |
250 un: -2, | |
251 uerr: ErrUnderflow, | |
252 }, { | |
253 name: "Reading a number smaller than min int64", | |
254 buf: smallerInt64, | |
255 n: -2, | |
256 err: ErrUnderflow, | |
257 | |
258 un: -2, | |
259 uerr: ErrUnderflow, | |
260 }, { | |
261 name: "Reading a number bigger than int64", | |
262 buf: prettyBigUint64, | |
263 n: -1, | |
264 err: ErrOverflow, | |
265 | |
266 uv: prettyBigUint64Val, | |
267 un: len(prettyBigUint64), | |
268 }, { | |
269 name: "Reading MaxUint64", | |
270 buf: reallyBigUint64, | |
271 n: -1, | |
272 err: ErrOverflow, | |
273 | |
274 uv: reallyBigUint64Val, | |
275 un: len(reallyBigUint64), | |
276 }, | |
277 } | |
278 | |
279 Convey("Error conditions", t, func() { | |
280 for _, t := range tests { | |
281 Convey(t.name, func() { | |
282 Convey("Get", func() { | |
283 v, n := Get(t.buf) | |
284 So(v, ShouldEqual, t.v) | |
285 So(n, ShouldEqual, t.n) | |
286 }) | |
287 Convey("GetUint", func() { | |
288 uv, un := GetUint(t.buf) | |
289 So(uv, ShouldEqual, t.uv) | |
290 So(un, ShouldEqual, t.un) | |
291 }) | |
292 Convey("Read", func() { | |
293 v, err := Read(bytes.NewBuffer(t.buf)) | |
294 So(err, ShouldEqual, t.err) | |
295 So(v, ShouldEqual, t.v) | |
296 }) | |
297 Convey("ReadUint", func() { | |
298 uv, err := ReadUint(bytes.NewBuffer(t.bu
f)) | |
299 So(err, ShouldEqual, t.uerr) | |
300 So(uv, ShouldEqual, t.uv) | |
301 }) | |
302 }) | |
303 } | |
304 Convey("Panics", func() { | |
305 Convey("Put", func() { | |
306 buf := make([]byte, MaxFunnyBaseLen64) | |
307 buf = buf[:4] // enough capacity, but not enough
length! | |
308 So(func() { Put(buf, cases[0].val) }, ShouldPani
c) | |
309 }) | |
310 Convey("PutUint", func() { | |
311 buf := make([]byte, MaxFunnyBaseLen64) | |
312 buf = buf[:4] // enough capacity, but not enough
length! | |
313 So(func() { PutUint(buf, reallyBigUint64Val) },
ShouldPanic) | |
314 }) | |
315 }) | |
316 Convey("Write Errors", func() { | |
317 // Test each error return location in writeSignMag | |
318 for count := 0; count < 3; count++ { | |
319 fw := &fakeWriter{count} | |
320 err := Write(fw, -10000) | |
321 So(err.Error(), ShouldContainSubstring, "nope") | |
322 So(fw.count, ShouldEqual, 0) | |
323 } | |
324 }) | |
325 }) | |
326 } | |
OLD | NEW |