1// Copyright 2016 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package tar
6
7import (
8	"math"
9	"strings"
10	"testing"
11	"time"
12)
13
14func TestFitsInBase256(t *testing.T) {
15	vectors := []struct {
16		in    int64
17		width int
18		ok    bool
19	}{
20		{+1, 8, true},
21		{0, 8, true},
22		{-1, 8, true},
23		{1 << 56, 8, false},
24		{(1 << 56) - 1, 8, true},
25		{-1 << 56, 8, true},
26		{(-1 << 56) - 1, 8, false},
27		{121654, 8, true},
28		{-9849849, 8, true},
29		{math.MaxInt64, 9, true},
30		{0, 9, true},
31		{math.MinInt64, 9, true},
32		{math.MaxInt64, 12, true},
33		{0, 12, true},
34		{math.MinInt64, 12, true},
35	}
36
37	for _, v := range vectors {
38		ok := fitsInBase256(v.width, v.in)
39		if ok != v.ok {
40			t.Errorf("fitsInBase256(%d, %d): got %v, want %v", v.in, v.width, ok, v.ok)
41		}
42	}
43}
44
45func TestParseNumeric(t *testing.T) {
46	vectors := []struct {
47		in   string
48		want int64
49		ok   bool
50	}{
51		// Test base-256 (binary) encoded values.
52		{"", 0, true},
53		{"\x80", 0, true},
54		{"\x80\x00", 0, true},
55		{"\x80\x00\x00", 0, true},
56		{"\xbf", (1 << 6) - 1, true},
57		{"\xbf\xff", (1 << 14) - 1, true},
58		{"\xbf\xff\xff", (1 << 22) - 1, true},
59		{"\xff", -1, true},
60		{"\xff\xff", -1, true},
61		{"\xff\xff\xff", -1, true},
62		{"\xc0", -1 * (1 << 6), true},
63		{"\xc0\x00", -1 * (1 << 14), true},
64		{"\xc0\x00\x00", -1 * (1 << 22), true},
65		{"\x87\x76\xa2\x22\xeb\x8a\x72\x61", 537795476381659745, true},
66		{"\x80\x00\x00\x00\x07\x76\xa2\x22\xeb\x8a\x72\x61", 537795476381659745, true},
67		{"\xf7\x76\xa2\x22\xeb\x8a\x72\x61", -615126028225187231, true},
68		{"\xff\xff\xff\xff\xf7\x76\xa2\x22\xeb\x8a\x72\x61", -615126028225187231, true},
69		{"\x80\x7f\xff\xff\xff\xff\xff\xff\xff", math.MaxInt64, true},
70		{"\x80\x80\x00\x00\x00\x00\x00\x00\x00", 0, false},
71		{"\xff\x80\x00\x00\x00\x00\x00\x00\x00", math.MinInt64, true},
72		{"\xff\x7f\xff\xff\xff\xff\xff\xff\xff", 0, false},
73		{"\xf5\xec\xd1\xc7\x7e\x5f\x26\x48\x81\x9f\x8f\x9b", 0, false},
74
75		// Test base-8 (octal) encoded values.
76		{"0000000\x00", 0, true},
77		{" \x0000000\x00", 0, true},
78		{" \x0000003\x00", 3, true},
79		{"00000000227\x00", 0227, true},
80		{"032033\x00 ", 032033, true},
81		{"320330\x00 ", 0320330, true},
82		{"0000660\x00 ", 0660, true},
83		{"\x00 0000660\x00 ", 0660, true},
84		{"0123456789abcdef", 0, false},
85		{"0123456789\x00abcdef", 0, false},
86		{"01234567\x0089abcdef", 342391, true},
87		{"0123\x7e\x5f\x264123", 0, false},
88	}
89
90	for _, v := range vectors {
91		var p parser
92		got := p.parseNumeric([]byte(v.in))
93		ok := (p.err == nil)
94		if ok != v.ok {
95			if v.ok {
96				t.Errorf("parseNumeric(%q): got parsing failure, want success", v.in)
97			} else {
98				t.Errorf("parseNumeric(%q): got parsing success, want failure", v.in)
99			}
100		}
101		if ok && got != v.want {
102			t.Errorf("parseNumeric(%q): got %d, want %d", v.in, got, v.want)
103		}
104	}
105}
106
107func TestFormatNumeric(t *testing.T) {
108	vectors := []struct {
109		in   int64
110		want string
111		ok   bool
112	}{
113		// Test base-8 (octal) encoded values.
114		{0, "0\x00", true},
115		{7, "7\x00", true},
116		{8, "\x80\x08", true},
117		{077, "77\x00", true},
118		{0100, "\x80\x00\x40", true},
119		{0, "0000000\x00", true},
120		{0123, "0000123\x00", true},
121		{07654321, "7654321\x00", true},
122		{07777777, "7777777\x00", true},
123		{010000000, "\x80\x00\x00\x00\x00\x20\x00\x00", true},
124		{0, "00000000000\x00", true},
125		{000001234567, "00001234567\x00", true},
126		{076543210321, "76543210321\x00", true},
127		{012345670123, "12345670123\x00", true},
128		{077777777777, "77777777777\x00", true},
129		{0100000000000, "\x80\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00", true},
130		{math.MaxInt64, "777777777777777777777\x00", true},
131
132		// Test base-256 (binary) encoded values.
133		{-1, "\xff", true},
134		{-1, "\xff\xff", true},
135		{-1, "\xff\xff\xff", true},
136		{(1 << 0), "0", false},
137		{(1 << 8) - 1, "\x80\xff", true},
138		{(1 << 8), "0\x00", false},
139		{(1 << 16) - 1, "\x80\xff\xff", true},
140		{(1 << 16), "00\x00", false},
141		{-1 * (1 << 0), "\xff", true},
142		{-1*(1<<0) - 1, "0", false},
143		{-1 * (1 << 8), "\xff\x00", true},
144		{-1*(1<<8) - 1, "0\x00", false},
145		{-1 * (1 << 16), "\xff\x00\x00", true},
146		{-1*(1<<16) - 1, "00\x00", false},
147		{537795476381659745, "0000000\x00", false},
148		{537795476381659745, "\x80\x00\x00\x00\x07\x76\xa2\x22\xeb\x8a\x72\x61", true},
149		{-615126028225187231, "0000000\x00", false},
150		{-615126028225187231, "\xff\xff\xff\xff\xf7\x76\xa2\x22\xeb\x8a\x72\x61", true},
151		{math.MaxInt64, "0000000\x00", false},
152		{math.MaxInt64, "\x80\x00\x00\x00\x7f\xff\xff\xff\xff\xff\xff\xff", true},
153		{math.MinInt64, "0000000\x00", false},
154		{math.MinInt64, "\xff\xff\xff\xff\x80\x00\x00\x00\x00\x00\x00\x00", true},
155		{math.MaxInt64, "\x80\x7f\xff\xff\xff\xff\xff\xff\xff", true},
156		{math.MinInt64, "\xff\x80\x00\x00\x00\x00\x00\x00\x00", true},
157	}
158
159	for _, v := range vectors {
160		var f formatter
161		got := make([]byte, len(v.want))
162		f.formatNumeric(got, v.in)
163		ok := (f.err == nil)
164		if ok != v.ok {
165			if v.ok {
166				t.Errorf("formatNumeric(%d): got formatting failure, want success", v.in)
167			} else {
168				t.Errorf("formatNumeric(%d): got formatting success, want failure", v.in)
169			}
170		}
171		if string(got) != v.want {
172			t.Errorf("formatNumeric(%d): got %q, want %q", v.in, got, v.want)
173		}
174	}
175}
176
177func TestFitsInOctal(t *testing.T) {
178	vectors := []struct {
179		input int64
180		width int
181		ok    bool
182	}{
183		{-1, 1, false},
184		{-1, 2, false},
185		{-1, 3, false},
186		{0, 1, true},
187		{0 + 1, 1, false},
188		{0, 2, true},
189		{07, 2, true},
190		{07 + 1, 2, false},
191		{0, 4, true},
192		{0777, 4, true},
193		{0777 + 1, 4, false},
194		{0, 8, true},
195		{07777777, 8, true},
196		{07777777 + 1, 8, false},
197		{0, 12, true},
198		{077777777777, 12, true},
199		{077777777777 + 1, 12, false},
200		{math.MaxInt64, 22, true},
201		{012345670123, 12, true},
202		{01564164, 12, true},
203		{-012345670123, 12, false},
204		{-01564164, 12, false},
205		{-1564164, 30, false},
206	}
207
208	for _, v := range vectors {
209		ok := fitsInOctal(v.width, v.input)
210		if ok != v.ok {
211			t.Errorf("checkOctal(%d, %d): got %v, want %v", v.input, v.width, ok, v.ok)
212		}
213	}
214}
215
216func TestParsePAXTime(t *testing.T) {
217	vectors := []struct {
218		in   string
219		want time.Time
220		ok   bool
221	}{
222		{"1350244992.023960108", time.Unix(1350244992, 23960108), true},
223		{"1350244992.02396010", time.Unix(1350244992, 23960100), true},
224		{"1350244992.0239601089", time.Unix(1350244992, 23960108), true},
225		{"1350244992.3", time.Unix(1350244992, 300000000), true},
226		{"1350244992", time.Unix(1350244992, 0), true},
227		{"-1.000000001", time.Unix(-1, -1e0+0e0), true},
228		{"-1.000001", time.Unix(-1, -1e3+0e0), true},
229		{"-1.001000", time.Unix(-1, -1e6+0e0), true},
230		{"-1", time.Unix(-1, -0e0+0e0), true},
231		{"-1.999000", time.Unix(-1, -1e9+1e6), true},
232		{"-1.999999", time.Unix(-1, -1e9+1e3), true},
233		{"-1.999999999", time.Unix(-1, -1e9+1e0), true},
234		{"0.000000001", time.Unix(0, 1e0+0e0), true},
235		{"0.000001", time.Unix(0, 1e3+0e0), true},
236		{"0.001000", time.Unix(0, 1e6+0e0), true},
237		{"0", time.Unix(0, 0e0), true},
238		{"0.999000", time.Unix(0, 1e9-1e6), true},
239		{"0.999999", time.Unix(0, 1e9-1e3), true},
240		{"0.999999999", time.Unix(0, 1e9-1e0), true},
241		{"1.000000001", time.Unix(+1, +1e0-0e0), true},
242		{"1.000001", time.Unix(+1, +1e3-0e0), true},
243		{"1.001000", time.Unix(+1, +1e6-0e0), true},
244		{"1", time.Unix(+1, +0e0-0e0), true},
245		{"1.999000", time.Unix(+1, +1e9-1e6), true},
246		{"1.999999", time.Unix(+1, +1e9-1e3), true},
247		{"1.999999999", time.Unix(+1, +1e9-1e0), true},
248		{"-1350244992.023960108", time.Unix(-1350244992, -23960108), true},
249		{"-1350244992.02396010", time.Unix(-1350244992, -23960100), true},
250		{"-1350244992.0239601089", time.Unix(-1350244992, -23960108), true},
251		{"-1350244992.3", time.Unix(-1350244992, -300000000), true},
252		{"-1350244992", time.Unix(-1350244992, 0), true},
253		{"", time.Time{}, false},
254		{"0", time.Unix(0, 0), true},
255		{"1.", time.Unix(1, 0), true},
256		{"0.0", time.Unix(0, 0), true},
257		{".5", time.Time{}, false},
258		{"-1.3", time.Unix(-1, -3e8), true},
259		{"-1.0", time.Unix(-1, -0e0), true},
260		{"-0.0", time.Unix(-0, -0e0), true},
261		{"-0.1", time.Unix(-0, -1e8), true},
262		{"-0.01", time.Unix(-0, -1e7), true},
263		{"-0.99", time.Unix(-0, -99e7), true},
264		{"-0.98", time.Unix(-0, -98e7), true},
265		{"-1.1", time.Unix(-1, -1e8), true},
266		{"-1.01", time.Unix(-1, -1e7), true},
267		{"-2.99", time.Unix(-2, -99e7), true},
268		{"-5.98", time.Unix(-5, -98e7), true},
269		{"-", time.Time{}, false},
270		{"+", time.Time{}, false},
271		{"-1.-1", time.Time{}, false},
272		{"99999999999999999999999999999999999999999999999", time.Time{}, false},
273		{"0.123456789abcdef", time.Time{}, false},
274		{"foo", time.Time{}, false},
275		{"\x00", time.Time{}, false},
276		{"����������.����������", time.Time{}, false}, // Unicode numbers (U+1D7EC to U+1D7F5)
277		{"98765﹒43210", time.Time{}, false}, // Unicode period (U+FE52)
278	}
279
280	for _, v := range vectors {
281		ts, err := parsePAXTime(v.in)
282		ok := (err == nil)
283		if v.ok != ok {
284			if v.ok {
285				t.Errorf("parsePAXTime(%q): got parsing failure, want success", v.in)
286			} else {
287				t.Errorf("parsePAXTime(%q): got parsing success, want failure", v.in)
288			}
289		}
290		if ok && !ts.Equal(v.want) {
291			t.Errorf("parsePAXTime(%q): got (%ds %dns), want (%ds %dns)",
292				v.in, ts.Unix(), ts.Nanosecond(), v.want.Unix(), v.want.Nanosecond())
293		}
294	}
295}
296
297func TestFormatPAXTime(t *testing.T) {
298	vectors := []struct {
299		sec, nsec int64
300		want      string
301	}{
302		{1350244992, 0, "1350244992"},
303		{1350244992, 300000000, "1350244992.3"},
304		{1350244992, 23960100, "1350244992.0239601"},
305		{1350244992, 23960108, "1350244992.023960108"},
306		{+1, +1E9 - 1E0, "1.999999999"},
307		{+1, +1E9 - 1E3, "1.999999"},
308		{+1, +1E9 - 1E6, "1.999"},
309		{+1, +0E0 - 0E0, "1"},
310		{+1, +1E6 - 0E0, "1.001"},
311		{+1, +1E3 - 0E0, "1.000001"},
312		{+1, +1E0 - 0E0, "1.000000001"},
313		{0, 1E9 - 1E0, "0.999999999"},
314		{0, 1E9 - 1E3, "0.999999"},
315		{0, 1E9 - 1E6, "0.999"},
316		{0, 0E0, "0"},
317		{0, 1E6 + 0E0, "0.001"},
318		{0, 1E3 + 0E0, "0.000001"},
319		{0, 1E0 + 0E0, "0.000000001"},
320		{-1, -1E9 + 1E0, "-1.999999999"},
321		{-1, -1E9 + 1E3, "-1.999999"},
322		{-1, -1E9 + 1E6, "-1.999"},
323		{-1, -0E0 + 0E0, "-1"},
324		{-1, -1E6 + 0E0, "-1.001"},
325		{-1, -1E3 + 0E0, "-1.000001"},
326		{-1, -1E0 + 0E0, "-1.000000001"},
327		{-1350244992, 0, "-1350244992"},
328		{-1350244992, -300000000, "-1350244992.3"},
329		{-1350244992, -23960100, "-1350244992.0239601"},
330		{-1350244992, -23960108, "-1350244992.023960108"},
331	}
332
333	for _, v := range vectors {
334		got := formatPAXTime(time.Unix(v.sec, v.nsec))
335		if got != v.want {
336			t.Errorf("formatPAXTime(%ds, %dns): got %q, want %q",
337				v.sec, v.nsec, got, v.want)
338		}
339	}
340}
341
342func TestParsePAXRecord(t *testing.T) {
343	medName := strings.Repeat("CD", 50)
344	longName := strings.Repeat("AB", 100)
345
346	vectors := []struct {
347		in      string
348		wantRes string
349		wantKey string
350		wantVal string
351		ok      bool
352	}{
353		{"6 k=v\n\n", "\n", "k", "v", true},
354		{"19 path=/etc/hosts\n", "", "path", "/etc/hosts", true},
355		{"210 path=" + longName + "\nabc", "abc", "path", longName, true},
356		{"110 path=" + medName + "\n", "", "path", medName, true},
357		{"9 foo=ba\n", "", "foo", "ba", true},
358		{"11 foo=bar\n\x00", "\x00", "foo", "bar", true},
359		{"18 foo=b=\nar=\n==\x00\n", "", "foo", "b=\nar=\n==\x00", true},
360		{"27 foo=hello9 foo=ba\nworld\n", "", "foo", "hello9 foo=ba\nworld", true},
361		{"27 ☺☻☹=日a本b語ç\nmeow mix", "meow mix", "☺☻☹", "日a本b語ç", true},
362		{"17 \x00hello=\x00world\n", "17 \x00hello=\x00world\n", "", "", false},
363		{"1 k=1\n", "1 k=1\n", "", "", false},
364		{"6 k~1\n", "6 k~1\n", "", "", false},
365		{"6_k=1\n", "6_k=1\n", "", "", false},
366		{"6 k=1 ", "6 k=1 ", "", "", false},
367		{"632 k=1\n", "632 k=1\n", "", "", false},
368		{"16 longkeyname=hahaha\n", "16 longkeyname=hahaha\n", "", "", false},
369		{"3 somelongkey=\n", "3 somelongkey=\n", "", "", false},
370		{"50 tooshort=\n", "50 tooshort=\n", "", "", false},
371	}
372
373	for _, v := range vectors {
374		key, val, res, err := parsePAXRecord(v.in)
375		ok := (err == nil)
376		if ok != v.ok {
377			if v.ok {
378				t.Errorf("parsePAXRecord(%q): got parsing failure, want success", v.in)
379			} else {
380				t.Errorf("parsePAXRecord(%q): got parsing success, want failure", v.in)
381			}
382		}
383		if v.ok && (key != v.wantKey || val != v.wantVal) {
384			t.Errorf("parsePAXRecord(%q): got (%q: %q), want (%q: %q)",
385				v.in, key, val, v.wantKey, v.wantVal)
386		}
387		if res != v.wantRes {
388			t.Errorf("parsePAXRecord(%q): got residual %q, want residual %q",
389				v.in, res, v.wantRes)
390		}
391	}
392}
393
394func TestFormatPAXRecord(t *testing.T) {
395	medName := strings.Repeat("CD", 50)
396	longName := strings.Repeat("AB", 100)
397
398	vectors := []struct {
399		inKey string
400		inVal string
401		want  string
402		ok    bool
403	}{
404		{"k", "v", "6 k=v\n", true},
405		{"path", "/etc/hosts", "19 path=/etc/hosts\n", true},
406		{"path", longName, "210 path=" + longName + "\n", true},
407		{"path", medName, "110 path=" + medName + "\n", true},
408		{"foo", "ba", "9 foo=ba\n", true},
409		{"foo", "bar", "11 foo=bar\n", true},
410		{"foo", "b=\nar=\n==\x00", "18 foo=b=\nar=\n==\x00\n", true},
411		{"foo", "hello9 foo=ba\nworld", "27 foo=hello9 foo=ba\nworld\n", true},
412		{"☺☻☹", "日a本b語ç", "27 ☺☻☹=日a本b語ç\n", true},
413		{"xhello", "\x00world", "17 xhello=\x00world\n", true},
414		{"path", "null\x00", "", false},
415		{"null\x00", "value", "", false},
416		{paxSchilyXattr + "key", "null\x00", "26 SCHILY.xattr.key=null\x00\n", true},
417	}
418
419	for _, v := range vectors {
420		got, err := formatPAXRecord(v.inKey, v.inVal)
421		ok := (err == nil)
422		if ok != v.ok {
423			if v.ok {
424				t.Errorf("formatPAXRecord(%q, %q): got format failure, want success", v.inKey, v.inVal)
425			} else {
426				t.Errorf("formatPAXRecord(%q, %q): got format success, want failure", v.inKey, v.inVal)
427			}
428		}
429		if got != v.want {
430			t.Errorf("formatPAXRecord(%q, %q): got %q, want %q",
431				v.inKey, v.inVal, got, v.want)
432		}
433	}
434}
435