| 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 num := 20000000 | |
| 150 if testing.Short() { | |
| 151 num = 100000 | |
| 152 } | |
| 153 num += len(cases) | |
| 154 randomCases := make(testCaseSlice, num) | |
| 155 | |
| 156 rcSub := randomCases[copy(randomCases, cases):] | |
| 157 r := rand.New(rand.NewSource(*seed)) | |
| 158 for i := range rcSub { | |
| 159 v := int64(uint64(r.Uint32())<<32 | uint64(r.Uint32())) | |
| 160 rcSub[i].val = v | |
| 161 buf := make([]byte, MaxFunnyBaseLen64) | |
| 162 rcSub[i].expect = buf[:Put(buf, v)] | |
| 163 } | |
| 164 | |
| 165 sort.Sort(randomCases) | |
| 166 | |
| 167 shouldBeLessThanOrEqual := func(actual interface{}, expected ...interfac
e{}) string { | |
| 168 a, b := actual.([]byte), expected[0].([]byte) | |
| 169 if bytes.Compare(a, b) <= 0 { | |
| 170 return fmt.Sprintf("Expected A <= B (but it wasn't)!\nA:
[% x]\nB: [% x]", a, b) | |
| 171 } | |
| 172 return "" | |
| 173 } | |
| 174 | |
| 175 Convey("TestSort", t, func() { | |
| 176 prev := randomCases[0] | |
| 177 for _, c := range randomCases[1:] { | |
| 178 // Actually asserting with the So for every entry in the
sorted array will | |
| 179 // produce 100000 green checkmarks on a sucessful test,
which is a bit | |
| 180 // much :). | |
| 181 if bytes.Compare(c.expect, prev.expect) < 0 { | |
| 182 So(c.expect, shouldBeLessThanOrEqual, prev.expec
t) | |
| 183 break | |
| 184 } | |
| 185 prev = c | |
| 186 } | |
| 187 | |
| 188 // This silly assertion is done so that this test has a green ch
eck next to | |
| 189 // it in the event that it passes. Otherwise convey thinks we sk
ipped the | |
| 190 // test, which isn't correct. | |
| 191 So(true, ShouldBeTrue) | |
| 192 }) | |
| 193 } | |
| 194 | |
| 195 type fakeWriter struct{ count int } | |
| 196 | |
| 197 func (f *fakeWriter) WriteByte(byte) error { | |
| 198 if f.count == 0 { | |
| 199 return fmt.Errorf("nope") | |
| 200 } | |
| 201 f.count-- | |
| 202 return nil | |
| 203 } | |
| 204 | |
| 205 func TestErrors(t *testing.T) { | |
| 206 smallerInt64 := []byte{b01000000, b01111111, b11111111, b11111111, b1111
1111, 0xff, 0xff, 0xff, b11111110} | |
| 207 | |
| 208 prettyBigUint64 := []byte{b10111111, b10000000, 0, 0, 0, 0, 0, 0, 0} | |
| 209 prettyBigUint64Val := uint64(math.MaxInt64 + 1) | |
| 210 | |
| 211 reallyBigUint64 := []byte{b10111111, b11111111, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff} | |
| 212 reallyBigUint64Val := uint64(math.MaxUint64) | |
| 213 tests := []struct { | |
| 214 name string | |
| 215 buf []byte | |
| 216 | |
| 217 v int64 | |
| 218 n int | |
| 219 err error | |
| 220 | |
| 221 uv uint64 | |
| 222 un int | |
| 223 uerr error | |
| 224 }{ | |
| 225 { | |
| 226 name: "Too big!!", | |
| 227 buf: []byte{b11000000}, // 65 bits!? | |
| 228 n: -1, | |
| 229 un: -1, | |
| 230 err: ErrOverflow, | |
| 231 uerr: ErrOverflow, | |
| 232 }, { | |
| 233 name: "Nil buffer", | |
| 234 err: io.EOF, | |
| 235 uerr: io.EOF, | |
| 236 }, { | |
| 237 name: "Empty buffer", | |
| 238 buf: []byte{}, | |
| 239 err: io.EOF, | |
| 240 uerr: io.EOF, | |
| 241 }, { | |
| 242 name: "Small buffer", | |
| 243 buf: cases[len(cases)-1].expect[:4], | |
| 244 err: io.EOF, | |
| 245 uerr: io.EOF, | |
| 246 }, { | |
| 247 name: "Reading a negative number with *Uint", | |
| 248 buf: cases[0].expect, | |
| 249 v: cases[0].val, | |
| 250 n: len(cases[0].expect), | |
| 251 | |
| 252 un: -2, | |
| 253 uerr: ErrUnderflow, | |
| 254 }, { | |
| 255 name: "Reading a number smaller than min int64", | |
| 256 buf: smallerInt64, | |
| 257 n: -2, | |
| 258 err: ErrUnderflow, | |
| 259 | |
| 260 un: -2, | |
| 261 uerr: ErrUnderflow, | |
| 262 }, { | |
| 263 name: "Reading a number bigger than int64", | |
| 264 buf: prettyBigUint64, | |
| 265 n: -1, | |
| 266 err: ErrOverflow, | |
| 267 | |
| 268 uv: prettyBigUint64Val, | |
| 269 un: len(prettyBigUint64), | |
| 270 }, { | |
| 271 name: "Reading MaxUint64", | |
| 272 buf: reallyBigUint64, | |
| 273 n: -1, | |
| 274 err: ErrOverflow, | |
| 275 | |
| 276 uv: reallyBigUint64Val, | |
| 277 un: len(reallyBigUint64), | |
| 278 }, | |
| 279 } | |
| 280 | |
| 281 Convey("Error conditions", t, func() { | |
| 282 for _, t := range tests { | |
| 283 Convey(t.name, func() { | |
| 284 Convey("Get", func() { | |
| 285 v, n := Get(t.buf) | |
| 286 So(v, ShouldEqual, t.v) | |
| 287 So(n, ShouldEqual, t.n) | |
| 288 }) | |
| 289 Convey("GetUint", func() { | |
| 290 uv, un := GetUint(t.buf) | |
| 291 So(uv, ShouldEqual, t.uv) | |
| 292 So(un, ShouldEqual, t.un) | |
| 293 }) | |
| 294 Convey("Read", func() { | |
| 295 v, err := Read(bytes.NewBuffer(t.buf)) | |
| 296 So(err, ShouldEqual, t.err) | |
| 297 So(v, ShouldEqual, t.v) | |
| 298 }) | |
| 299 Convey("ReadUint", func() { | |
| 300 uv, err := ReadUint(bytes.NewBuffer(t.bu
f)) | |
| 301 So(err, ShouldEqual, t.uerr) | |
| 302 So(uv, ShouldEqual, t.uv) | |
| 303 }) | |
| 304 }) | |
| 305 } | |
| 306 Convey("Panics", func() { | |
| 307 Convey("Put", func() { | |
| 308 buf := make([]byte, MaxFunnyBaseLen64) | |
| 309 buf = buf[:4] // enough capacity, but not enough
length! | |
| 310 So(func() { Put(buf, cases[0].val) }, ShouldPani
c) | |
| 311 }) | |
| 312 Convey("PutUint", func() { | |
| 313 buf := make([]byte, MaxFunnyBaseLen64) | |
| 314 buf = buf[:4] // enough capacity, but not enough
length! | |
| 315 So(func() { PutUint(buf, reallyBigUint64Val) },
ShouldPanic) | |
| 316 }) | |
| 317 }) | |
| 318 Convey("Write Errors", func() { | |
| 319 // Test each error return location in writeSignMag | |
| 320 for count := 0; count < 3; count++ { | |
| 321 fw := &fakeWriter{count} | |
| 322 err := Write(fw, -10000) | |
| 323 So(err.Error(), ShouldContainSubstring, "nope") | |
| 324 So(fw.count, ShouldEqual, 0) | |
| 325 } | |
| 326 }) | |
| 327 }) | |
| 328 } | |
| OLD | NEW |