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