1// Copyright (c) 2013 Couchbase, Inc. 2 3package collatejson 4 5import "bytes" 6import "strconv" 7import "testing" 8 9var code = make([]byte, 0, 1024) 10var text = make([]byte, 0, 1024) 11 12func TestInteger(t *testing.T) { 13 var samples = [][2]string{ 14 {"7", ">7"}, 15 {"+7", ">7"}, 16 {"+1234567890", ">>>2101234567890"}, 17 {"-10", "--789"}, 18 {"-11", "--788"}, 19 {"-1234567891", "---7898765432108"}, 20 {"-1234567890", "---7898765432109"}, 21 {"-1234567889", "---7898765432110"}, 22 {"0", "0"}, 23 {"+0", "0"}, 24 {"-0", "0"}, 25 } 26 for _, tcase := range samples { 27 sample, ref := tcase[0], tcase[1] 28 out := EncodeInt([]byte(sample), code[:0]) 29 if string(out) != ref { 30 t.Error("error encode failed for:", sample, string(out), ref) 31 } 32 _, out = DecodeInt([]byte(out), text[:0]) 33 if atoi(string(out), t) != atoi(sample, t) { 34 t.Error("error decode failed for:", sample, string(out)) 35 } 36 } 37} 38 39func atoi(text string, t *testing.T) int { 40 if val, err := strconv.Atoi(text); err == nil { 41 return val 42 } 43 t.Errorf("atoi: Unable to convert %v", text) 44 return 0 45} 46 47func atof(text string, t *testing.T) float64 { 48 val, err := strconv.ParseFloat(text, 64) 49 if err == nil { 50 return val 51 } 52 t.Error("atof: Unable to convert", text, err) 53 return 0.0 54} 55 56func TestSmallDecimal(t *testing.T) { 57 var samples = [][2]string{ 58 {"-0.9995", "-0004>"}, 59 {"-0.999", "-000>"}, 60 {"-0.0123", "-9876>"}, 61 {"-0.00123", "-99876>"}, 62 {"-0.0001233", "-9998766>"}, 63 {"-0.000123", "-999876>"}, 64 {"+0.000123", ">000123-"}, 65 {"+0.0001233", ">0001233-"}, 66 {"+0.00123", ">00123-"}, 67 {"+0.0123", ">0123-"}, 68 {"+0.999", ">999-"}, 69 {"+0.9995", ">9995-"}, 70 } 71 for _, tcase := range samples { 72 sample, ref := tcase[0], tcase[1] 73 out := string(EncodeSD([]byte(sample), code[:0])) 74 if out != ref { 75 t.Error("error small decimal encode failed:", sample, out, ref) 76 } 77 out = string(DecodeSD([]byte(out), text[:0])) 78 if atof(out, t) != atof(sample, t) { 79 t.Error("error small decimal decode failed:", sample, out) 80 } 81 } 82} 83 84func TestLargeDecimal(t *testing.T) { 85 var samples = [][2]string{ 86 {"-100.5", "--68994>"}, 87 {"-10.5", "--7894>"}, 88 {"-3.145", "-6854>"}, 89 {"-3.14", "-685>"}, 90 {"-1.01", "-898>"}, 91 {"-1", "-89>"}, 92 {"+1", ">1-"}, 93 {"+1.01", ">101-"}, 94 {"+3.14", ">314-"}, 95 {"+3.145", ">3145-"}, 96 {"+10.5", ">>2105-"}, 97 {"+100.5", ">>31005-"}, 98 } 99 for _, tcase := range samples { 100 sample, ref := tcase[0], tcase[1] 101 out := string(EncodeLD([]byte(sample), code[:0])) 102 if out != ref { 103 t.Error("large decimal encode failed:", sample, out, ref) 104 } 105 out = string(DecodeLD([]byte(out), text[:0])) 106 if atof(out, t) != atof(sample, t) { 107 t.Error("large decimal decode failed:", sample, out) 108 } 109 } 110} 111 112func TestFloat(t *testing.T) { 113 var samples = [][2]string{ 114 {"-10000000000.0", "---7888>"}, 115 {"-1000000000.0", "---7898>"}, 116 {"-1.4", "--885>"}, 117 {"-1.3", "--886>"}, 118 {"-1", "--88>"}, 119 {"-0.123", "-0876>"}, 120 {"-0.0123", "->1876>"}, 121 {"-0.001233", "->28766>"}, 122 {"-0.00123", "->2876>"}, 123 {"0", "0"}, 124 {"+0.00123", ">-7123-"}, 125 {"+0.001233", ">-71233-"}, 126 {"+0.0123", ">-8123-"}, 127 {"+0.123", ">0123-"}, 128 {"+1", ">>11-"}, 129 {"+1.3", ">>113-"}, 130 {"+1.4", ">>114-"}, 131 {"+1000000000.0", ">>>2101-"}, 132 {"+10000000000.0", ">>>2111-"}, 133 } 134 for _, tcase := range samples { 135 sample, ref := tcase[0], tcase[1] 136 f, _ := strconv.ParseFloat(sample, 64) 137 sampleF := strconv.FormatFloat(f, 'e', -1, 64) 138 out := string(EncodeFloat([]byte(sampleF), code[:0])) 139 if out != ref { 140 t.Error("float encode failed:", sample, out, ref) 141 } 142 out = string(DecodeFloat([]byte(out), text[:0])) 143 if atof(out, t) != atof(sample, t) { 144 t.Error("float decode failed:", sample, out) 145 } 146 } 147} 148 149func TestSuffixCoding(t *testing.T) { 150 bs := []byte("hello\x00wo\xffrld\x00") 151 code := suffixEncodeString(bs, code[:0]) 152 code = append(code, Terminator) 153 text, remn, err := suffixDecodeString(code, text[:0]) 154 if err != nil { 155 t.Error(err) 156 } 157 if bytes.Compare(bs, text) != 0 { 158 t.Error("Suffix coding for strings failed") 159 } 160 if len(remn) != 0 { 161 t.Errorf("Suffix coding for strings failed, residue found %q", remn) 162 } 163} 164 165func BenchmarkEncodeInt0(b *testing.B) { 166 bEncodeInt(b, []byte("0")) 167} 168 169func BenchmarkEncodeInt7(b *testing.B) { 170 bEncodeInt(b, []byte("+7")) 171} 172 173func BenchmarkEncodeInt1234567890(b *testing.B) { 174 bEncodeInt(b, []byte("+1234567890")) 175} 176 177func BenchmarkEncodeInt1234567890Neg(b *testing.B) { 178 bEncodeInt(b, []byte("-1234567890")) 179} 180 181func BenchmarkDecodeInt0(b *testing.B) { 182 bDecodeInt(b, []byte("0")) 183} 184 185func BenchmarkDecodeInt7(b *testing.B) { 186 bDecodeInt(b, []byte(">7")) 187} 188 189func BenchmarkDecodeInt1234567890(b *testing.B) { 190 bDecodeInt(b, []byte(">>>2101234567890")) 191} 192 193func BenchmarkDecodeInt1234567891Neg(b *testing.B) { 194 bDecodeInt(b, []byte("---7898765432108")) 195} 196 197func BenchmarkEncodeInt(b *testing.B) { 198 var samples = [][]byte{ 199 []byte("+7"), 200 []byte("+123"), 201 []byte("+1234567890"), 202 []byte("-1234567891"), 203 []byte("-1234567890"), 204 []byte("-1234567889"), 205 []byte("0"), 206 []byte("0"), 207 } 208 ln := len(samples) 209 b.ResetTimer() 210 for i := 0; i < b.N; i++ { 211 EncodeInt([]byte(samples[i%ln]), code[:0]) 212 } 213} 214 215func BenchmarkDecodeInt(b *testing.B) { 216 var samples = [][]byte{ 217 []byte(">7"), 218 []byte(">>3123"), 219 []byte(">>>2101234567890"), 220 []byte("---7898765432108"), 221 []byte("---7898765432109"), 222 []byte("---7898765432110"), 223 []byte("0"), 224 } 225 ln := len(samples) 226 b.ResetTimer() 227 for i := 0; i < b.N; i++ { 228 DecodeInt(samples[i%ln], text[:0]) 229 } 230} 231 232func BenchmarkEncodeFloat10000000000(b *testing.B) { 233 bEncodeFloat(b, "+10000000000") 234} 235 236func BenchmarkEncodeFloat001233(b *testing.B) { 237 bEncodeFloat(b, "+0.001233") 238} 239 240func BenchmarkEncodeFloat001233Neg(b *testing.B) { 241 bEncodeFloat(b, "-0.001233") 242} 243 244func BenchmarkEncodeFloat1Neg(b *testing.B) { 245 bEncodeFloat(b, "-1") 246} 247 248func BenchmarkEncodeFloat10000000000Neg(b *testing.B) { 249 bEncodeFloat(b, "-10000000000") 250} 251 252func BenchmarkDecodeFloat10000000000(b *testing.B) { 253 bDecodeFloat(b, ">>>2111-") 254} 255 256func BenchmarkDecodeFloat001233(b *testing.B) { 257 bDecodeFloat(b, "->28766>") 258} 259 260func BenchmarkDecodeFloat001233Neg(b *testing.B) { 261 bDecodeFloat(b, "->28766>") 262} 263 264func BenchmarkDecodeFloat1Neg(b *testing.B) { 265 bDecodeFloat(b, "--88>") 266} 267 268func BenchmarkDecodeFloat10000000000Neg(b *testing.B) { 269 bDecodeFloat(b, "---7888>") 270} 271 272func BenchmarkEncodeFloat(b *testing.B) { 273 var samples = [][]byte{ 274 []byte("-10000000000.0"), 275 []byte("-1000000000.0"), 276 []byte("-1.4"), 277 []byte("-1.3"), 278 []byte("-1"), 279 []byte("-0.123"), 280 []byte("-0.0123"), 281 []byte("-0.001233"), 282 []byte("-0.00123"), 283 []byte("0"), 284 []byte("+0.00123"), 285 []byte("+0.001233"), 286 []byte("+0.0123"), 287 []byte("+0.123"), 288 []byte("+1"), 289 []byte("+1.3"), 290 []byte("+1.4"), 291 []byte("+1000000000.0"), 292 []byte("+10000000000.0"), 293 } 294 ln := len(samples) 295 for i := 0; i < ln; i++ { 296 f, _ := strconv.ParseFloat(string(samples[i]), 64) 297 samples[i] = []byte(strconv.FormatFloat(f, 'e', -1, 64)) 298 } 299 b.ResetTimer() 300 for i := 0; i < b.N; i++ { 301 EncodeFloat(samples[i%ln], code[:0]) 302 } 303} 304 305func BenchmarkDecodeFloat(b *testing.B) { 306 var samples = [][]byte{ 307 []byte("-10000000000.0"), 308 []byte("-1000000000.0"), 309 []byte("-1.4"), 310 []byte("-1.3"), 311 []byte("-1"), 312 []byte("-0.123"), 313 []byte("-0.0123"), 314 []byte("-0.001233"), 315 []byte("-0.00123"), 316 []byte("0"), 317 []byte("+0.00123"), 318 []byte("+0.001233"), 319 []byte("+0.0123"), 320 []byte("+0.123"), 321 []byte("+1"), 322 []byte("+1.3"), 323 []byte("+1.4"), 324 []byte("+1000000000.0"), 325 []byte("+10000000000.0"), 326 } 327 ln := len(samples) 328 for i := 0; i < ln; i++ { 329 f, _ := strconv.ParseFloat(string(samples[i]), 64) 330 samples[i] = make([]byte, 0) 331 samples[i] = append(samples[i], 332 EncodeFloat( 333 []byte(strconv.FormatFloat(f, 'e', -1, 64)), code[:0])...) 334 } 335 336 b.ResetTimer() 337 for i := 0; i < b.N; i++ { 338 DecodeFloat(samples[i%ln], code[:0]) 339 } 340} 341 342func BenchmarkEncodeSD(b *testing.B) { 343 var samples = [][]byte{ 344 []byte("-0.9995"), 345 []byte("-0.999"), 346 []byte("-0.0123"), 347 []byte("-0.00123"), 348 []byte("-0.0001233"), 349 []byte("-0.000123"), 350 []byte("+0.000123"), 351 []byte("+0.0001233"), 352 []byte("+0.00123"), 353 []byte("+0.0123"), 354 []byte("+0.999"), 355 []byte("+0.9995"), 356 } 357 ln := len(samples) 358 b.ResetTimer() 359 for i := 0; i < b.N; i++ { 360 EncodeSD(samples[i%ln], code[:0]) 361 } 362} 363 364func BenchmarkDecodeSD(b *testing.B) { 365 var samples = [][]byte{ 366 []byte("-0004>"), 367 []byte("-000>"), 368 []byte("-9876>"), 369 []byte("-99876>"), 370 []byte("-9998766>"), 371 []byte("-999876>"), 372 []byte(">000123-"), 373 []byte(">0001233-"), 374 []byte(">00123-"), 375 []byte(">0123-"), 376 []byte(">999-"), 377 []byte(">9995-"), 378 } 379 ln := len(samples) 380 b.ResetTimer() 381 for i := 0; i < b.N; i++ { 382 DecodeSD(samples[i%ln], text[:0]) 383 } 384} 385 386func BenchmarkEncodeLD(b *testing.B) { 387 var samples = [][]byte{ 388 []byte("-100.5"), 389 []byte("-10.5"), 390 []byte("-3.145"), 391 []byte("-3.14"), 392 []byte("-1.01"), 393 []byte("+1.01"), 394 []byte("+3.14"), 395 []byte("+3.145"), 396 []byte("+10.5"), 397 []byte("+100.5"), 398 } 399 ln := len(samples) 400 b.ResetTimer() 401 for i := 0; i < b.N; i++ { 402 EncodeLD(samples[i%ln], code[:0]) 403 } 404} 405 406func BenchmarkDecodeLD(b *testing.B) { 407 var samples = [][]byte{ 408 []byte("--68994>"), 409 []byte("--7894>"), 410 []byte("-6854>"), 411 []byte("-685>"), 412 []byte("-898>"), 413 []byte("-89>"), 414 []byte(">1-"), 415 []byte(">101-"), 416 []byte(">314-"), 417 []byte(">3145-"), 418 []byte(">>2105-"), 419 []byte(">>31005-"), 420 } 421 ln := len(samples) 422 b.ResetTimer() 423 for i := 0; i < b.N; i++ { 424 DecodeLD(samples[i%ln], text[:0]) 425 } 426} 427 428func BenchmarkSuffixEncode(b *testing.B) { 429 bs := []byte("hello\x00wo\xffrld\x00") 430 for i := 0; i < b.N; i++ { 431 suffixEncodeString(bs, code[:0]) 432 } 433} 434 435func BenchmarkSuffixDecode(b *testing.B) { 436 bs := []byte("hello\x00wo\xffrld\x00") 437 code := suffixEncodeString(bs, code[:0]) 438 code = joinBytes(code, []byte{Terminator}) 439 b.ResetTimer() 440 for i := 0; i < b.N; i++ { 441 suffixDecodeString(code, text[:]) 442 } 443} 444 445func bEncodeInt(b *testing.B, in []byte) { 446 for i := 0; i < b.N; i++ { 447 EncodeInt(in, code[:0]) 448 } 449} 450 451func bDecodeInt(b *testing.B, in []byte) { 452 for i := 0; i < b.N; i++ { 453 DecodeInt(in, text[:0]) 454 } 455} 456 457func bEncodeFloat(b *testing.B, in string) { 458 f, _ := strconv.ParseFloat(in, 64) 459 inb := []byte(strconv.FormatFloat(f, 'e', -1, 64)) 460 for i := 0; i < b.N; i++ { 461 EncodeFloat(inb, code[:0]) 462 } 463} 464 465func bDecodeFloat(b *testing.B, in string) { 466 inb := []byte(in) 467 for i := 0; i < b.N; i++ { 468 DecodeFloat(inb, text[:0]) 469 } 470} 471