diff options
Diffstat (limited to 'testes/tpack.lua')
-rw-r--r-- | testes/tpack.lua | 322 |
1 files changed, 322 insertions, 0 deletions
diff --git a/testes/tpack.lua b/testes/tpack.lua new file mode 100644 index 00000000..96bb4da4 --- /dev/null +++ b/testes/tpack.lua | |||
@@ -0,0 +1,322 @@ | |||
1 | -- $Id: tpack.lua,v 1.13 2016/11/07 13:11:28 roberto Exp $ | ||
2 | -- See Copyright Notice in file all.lua | ||
3 | |||
4 | local pack = string.pack | ||
5 | local packsize = string.packsize | ||
6 | local unpack = string.unpack | ||
7 | |||
8 | print "testing pack/unpack" | ||
9 | |||
10 | -- maximum size for integers | ||
11 | local NB = 16 | ||
12 | |||
13 | local sizeshort = packsize("h") | ||
14 | local sizeint = packsize("i") | ||
15 | local sizelong = packsize("l") | ||
16 | local sizesize_t = packsize("T") | ||
17 | local sizeLI = packsize("j") | ||
18 | local sizefloat = packsize("f") | ||
19 | local sizedouble = packsize("d") | ||
20 | local sizenumber = packsize("n") | ||
21 | local little = (pack("i2", 1) == "\1\0") | ||
22 | local align = packsize("!xXi16") | ||
23 | |||
24 | assert(1 <= sizeshort and sizeshort <= sizeint and sizeint <= sizelong and | ||
25 | sizefloat <= sizedouble) | ||
26 | |||
27 | print("platform:") | ||
28 | print(string.format( | ||
29 | "\tshort %d, int %d, long %d, size_t %d, float %d, double %d,\n\z | ||
30 | \tlua Integer %d, lua Number %d", | ||
31 | sizeshort, sizeint, sizelong, sizesize_t, sizefloat, sizedouble, | ||
32 | sizeLI, sizenumber)) | ||
33 | print("\t" .. (little and "little" or "big") .. " endian") | ||
34 | print("\talignment: " .. align) | ||
35 | |||
36 | |||
37 | -- check errors in arguments | ||
38 | function checkerror (msg, f, ...) | ||
39 | local status, err = pcall(f, ...) | ||
40 | -- print(status, err, msg) | ||
41 | assert(not status and string.find(err, msg)) | ||
42 | end | ||
43 | |||
44 | -- minimum behavior for integer formats | ||
45 | assert(unpack("B", pack("B", 0xff)) == 0xff) | ||
46 | assert(unpack("b", pack("b", 0x7f)) == 0x7f) | ||
47 | assert(unpack("b", pack("b", -0x80)) == -0x80) | ||
48 | |||
49 | assert(unpack("H", pack("H", 0xffff)) == 0xffff) | ||
50 | assert(unpack("h", pack("h", 0x7fff)) == 0x7fff) | ||
51 | assert(unpack("h", pack("h", -0x8000)) == -0x8000) | ||
52 | |||
53 | assert(unpack("L", pack("L", 0xffffffff)) == 0xffffffff) | ||
54 | assert(unpack("l", pack("l", 0x7fffffff)) == 0x7fffffff) | ||
55 | assert(unpack("l", pack("l", -0x80000000)) == -0x80000000) | ||
56 | |||
57 | |||
58 | for i = 1, NB do | ||
59 | -- small numbers with signal extension ("\xFF...") | ||
60 | local s = string.rep("\xff", i) | ||
61 | assert(pack("i" .. i, -1) == s) | ||
62 | assert(packsize("i" .. i) == #s) | ||
63 | assert(unpack("i" .. i, s) == -1) | ||
64 | |||
65 | -- small unsigned number ("\0...\xAA") | ||
66 | s = "\xAA" .. string.rep("\0", i - 1) | ||
67 | assert(pack("<I" .. i, 0xAA) == s) | ||
68 | assert(unpack("<I" .. i, s) == 0xAA) | ||
69 | assert(pack(">I" .. i, 0xAA) == s:reverse()) | ||
70 | assert(unpack(">I" .. i, s:reverse()) == 0xAA) | ||
71 | end | ||
72 | |||
73 | do | ||
74 | local lnum = 0x13121110090807060504030201 | ||
75 | local s = pack("<j", lnum) | ||
76 | assert(unpack("<j", s) == lnum) | ||
77 | assert(unpack("<i" .. sizeLI + 1, s .. "\0") == lnum) | ||
78 | assert(unpack("<i" .. sizeLI + 1, s .. "\0") == lnum) | ||
79 | |||
80 | for i = sizeLI + 1, NB do | ||
81 | local s = pack("<j", -lnum) | ||
82 | assert(unpack("<j", s) == -lnum) | ||
83 | -- strings with (correct) extra bytes | ||
84 | assert(unpack("<i" .. i, s .. ("\xFF"):rep(i - sizeLI)) == -lnum) | ||
85 | assert(unpack(">i" .. i, ("\xFF"):rep(i - sizeLI) .. s:reverse()) == -lnum) | ||
86 | assert(unpack("<I" .. i, s .. ("\0"):rep(i - sizeLI)) == -lnum) | ||
87 | |||
88 | -- overflows | ||
89 | checkerror("does not fit", unpack, "<I" .. i, ("\x00"):rep(i - 1) .. "\1") | ||
90 | checkerror("does not fit", unpack, ">i" .. i, "\1" .. ("\x00"):rep(i - 1)) | ||
91 | end | ||
92 | end | ||
93 | |||
94 | for i = 1, sizeLI do | ||
95 | local lstr = "\1\2\3\4\5\6\7\8\9\10\11\12\13" | ||
96 | local lnum = 0x13121110090807060504030201 | ||
97 | local n = lnum & (~(-1 << (i * 8))) | ||
98 | local s = string.sub(lstr, 1, i) | ||
99 | assert(pack("<i" .. i, n) == s) | ||
100 | assert(pack(">i" .. i, n) == s:reverse()) | ||
101 | assert(unpack(">i" .. i, s:reverse()) == n) | ||
102 | end | ||
103 | |||
104 | -- sign extension | ||
105 | do | ||
106 | local u = 0xf0 | ||
107 | for i = 1, sizeLI - 1 do | ||
108 | assert(unpack("<i"..i, "\xf0"..("\xff"):rep(i - 1)) == -16) | ||
109 | assert(unpack(">I"..i, "\xf0"..("\xff"):rep(i - 1)) == u) | ||
110 | u = u * 256 + 0xff | ||
111 | end | ||
112 | end | ||
113 | |||
114 | -- mixed endianness | ||
115 | do | ||
116 | assert(pack(">i2 <i2", 10, 20) == "\0\10\20\0") | ||
117 | local a, b = unpack("<i2 >i2", "\10\0\0\20") | ||
118 | assert(a == 10 and b == 20) | ||
119 | assert(pack("=i4", 2001) == pack("i4", 2001)) | ||
120 | end | ||
121 | |||
122 | print("testing invalid formats") | ||
123 | |||
124 | checkerror("out of limits", pack, "i0", 0) | ||
125 | checkerror("out of limits", pack, "i" .. NB + 1, 0) | ||
126 | checkerror("out of limits", pack, "!" .. NB + 1, 0) | ||
127 | checkerror("%(17%) out of limits %[1,16%]", pack, "Xi" .. NB + 1) | ||
128 | checkerror("invalid format option 'r'", pack, "i3r", 0) | ||
129 | checkerror("16%-byte integer", unpack, "i16", string.rep('\3', 16)) | ||
130 | checkerror("not power of 2", pack, "!4i3", 0); | ||
131 | checkerror("missing size", pack, "c", "") | ||
132 | checkerror("variable%-length format", packsize, "s") | ||
133 | checkerror("variable%-length format", packsize, "z") | ||
134 | |||
135 | -- overflow in option size (error will be in digit after limit) | ||
136 | checkerror("invalid format", packsize, "c1" .. string.rep("0", 40)) | ||
137 | |||
138 | if packsize("i") == 4 then | ||
139 | -- result would be 2^31 (2^3 repetitions of 2^28 strings) | ||
140 | local s = string.rep("c268435456", 2^3) | ||
141 | checkerror("too large", packsize, s) | ||
142 | -- one less is OK | ||
143 | s = string.rep("c268435456", 2^3 - 1) .. "c268435455" | ||
144 | assert(packsize(s) == 0x7fffffff) | ||
145 | end | ||
146 | |||
147 | -- overflow in packing | ||
148 | for i = 1, sizeLI - 1 do | ||
149 | local umax = (1 << (i * 8)) - 1 | ||
150 | local max = umax >> 1 | ||
151 | local min = ~max | ||
152 | checkerror("overflow", pack, "<I" .. i, -1) | ||
153 | checkerror("overflow", pack, "<I" .. i, min) | ||
154 | checkerror("overflow", pack, ">I" .. i, umax + 1) | ||
155 | |||
156 | checkerror("overflow", pack, ">i" .. i, umax) | ||
157 | checkerror("overflow", pack, ">i" .. i, max + 1) | ||
158 | checkerror("overflow", pack, "<i" .. i, min - 1) | ||
159 | |||
160 | assert(unpack(">i" .. i, pack(">i" .. i, max)) == max) | ||
161 | assert(unpack("<i" .. i, pack("<i" .. i, min)) == min) | ||
162 | assert(unpack(">I" .. i, pack(">I" .. i, umax)) == umax) | ||
163 | end | ||
164 | |||
165 | -- Lua integer size | ||
166 | assert(unpack(">j", pack(">j", math.maxinteger)) == math.maxinteger) | ||
167 | assert(unpack("<j", pack("<j", math.mininteger)) == math.mininteger) | ||
168 | assert(unpack("<J", pack("<j", -1)) == -1) -- maximum unsigned integer | ||
169 | |||
170 | if little then | ||
171 | assert(pack("f", 24) == pack("<f", 24)) | ||
172 | else | ||
173 | assert(pack("f", 24) == pack(">f", 24)) | ||
174 | end | ||
175 | |||
176 | print "testing pack/unpack of floating-point numbers" | ||
177 | |||
178 | for _, n in ipairs{0, -1.1, 1.9, 1/0, -1/0, 1e20, -1e20, 0.1, 2000.7} do | ||
179 | assert(unpack("n", pack("n", n)) == n) | ||
180 | assert(unpack("<n", pack("<n", n)) == n) | ||
181 | assert(unpack(">n", pack(">n", n)) == n) | ||
182 | assert(pack("<f", n) == pack(">f", n):reverse()) | ||
183 | assert(pack(">d", n) == pack("<d", n):reverse()) | ||
184 | end | ||
185 | |||
186 | -- for non-native precisions, test only with "round" numbers | ||
187 | for _, n in ipairs{0, -1.5, 1/0, -1/0, 1e10, -1e9, 0.5, 2000.25} do | ||
188 | assert(unpack("<f", pack("<f", n)) == n) | ||
189 | assert(unpack(">f", pack(">f", n)) == n) | ||
190 | assert(unpack("<d", pack("<d", n)) == n) | ||
191 | assert(unpack(">d", pack(">d", n)) == n) | ||
192 | end | ||
193 | |||
194 | print "testing pack/unpack of strings" | ||
195 | do | ||
196 | local s = string.rep("abc", 1000) | ||
197 | assert(pack("zB", s, 247) == s .. "\0\xF7") | ||
198 | local s1, b = unpack("zB", s .. "\0\xF9") | ||
199 | assert(b == 249 and s1 == s) | ||
200 | s1 = pack("s", s) | ||
201 | assert(unpack("s", s1) == s) | ||
202 | |||
203 | checkerror("does not fit", pack, "s1", s) | ||
204 | |||
205 | checkerror("contains zeros", pack, "z", "alo\0"); | ||
206 | |||
207 | for i = 2, NB do | ||
208 | local s1 = pack("s" .. i, s) | ||
209 | assert(unpack("s" .. i, s1) == s and #s1 == #s + i) | ||
210 | end | ||
211 | end | ||
212 | |||
213 | do | ||
214 | local x = pack("s", "alo") | ||
215 | checkerror("too short", unpack, "s", x:sub(1, -2)) | ||
216 | checkerror("too short", unpack, "c5", "abcd") | ||
217 | checkerror("out of limits", pack, "s100", "alo") | ||
218 | end | ||
219 | |||
220 | do | ||
221 | assert(pack("c0", "") == "") | ||
222 | assert(packsize("c0") == 0) | ||
223 | assert(unpack("c0", "") == "") | ||
224 | assert(pack("<! c3", "abc") == "abc") | ||
225 | assert(packsize("<! c3") == 3) | ||
226 | assert(pack(">!4 c6", "abcdef") == "abcdef") | ||
227 | assert(pack("c3", "123") == "123") | ||
228 | assert(pack("c0", "") == "") | ||
229 | assert(pack("c8", "123456") == "123456\0\0") | ||
230 | assert(pack("c88", "") == string.rep("\0", 88)) | ||
231 | assert(pack("c188", "ab") == "ab" .. string.rep("\0", 188 - 2)) | ||
232 | local a, b, c = unpack("!4 z c3", "abcdefghi\0xyz") | ||
233 | assert(a == "abcdefghi" and b == "xyz" and c == 14) | ||
234 | checkerror("longer than", pack, "c3", "1234") | ||
235 | end | ||
236 | |||
237 | |||
238 | -- testing multiple types and sequence | ||
239 | do | ||
240 | local x = pack("<b h b f d f n i", 1, 2, 3, 4, 5, 6, 7, 8) | ||
241 | assert(#x == packsize("<b h b f d f n i")) | ||
242 | local a, b, c, d, e, f, g, h = unpack("<b h b f d f n i", x) | ||
243 | assert(a == 1 and b == 2 and c == 3 and d == 4 and e == 5 and f == 6 and | ||
244 | g == 7 and h == 8) | ||
245 | end | ||
246 | |||
247 | print "testing alignment" | ||
248 | do | ||
249 | assert(pack(" < i1 i2 ", 2, 3) == "\2\3\0") -- no alignment by default | ||
250 | local x = pack(">!8 b Xh i4 i8 c1 Xi8", -12, 100, 200, "\xEC") | ||
251 | assert(#x == packsize(">!8 b Xh i4 i8 c1 Xi8")) | ||
252 | assert(x == "\xf4" .. "\0\0\0" .. | ||
253 | "\0\0\0\100" .. | ||
254 | "\0\0\0\0\0\0\0\xC8" .. | ||
255 | "\xEC" .. "\0\0\0\0\0\0\0") | ||
256 | local a, b, c, d, pos = unpack(">!8 c1 Xh i4 i8 b Xi8 XI XH", x) | ||
257 | assert(a == "\xF4" and b == 100 and c == 200 and d == -20 and (pos - 1) == #x) | ||
258 | |||
259 | x = pack(">!4 c3 c4 c2 z i4 c5 c2 Xi4", | ||
260 | "abc", "abcd", "xz", "hello", 5, "world", "xy") | ||
261 | assert(x == "abcabcdxzhello\0\0\0\0\0\5worldxy\0") | ||
262 | local a, b, c, d, e, f, g, pos = unpack(">!4 c3 c4 c2 z i4 c5 c2 Xh Xi4", x) | ||
263 | assert(a == "abc" and b == "abcd" and c == "xz" and d == "hello" and | ||
264 | e == 5 and f == "world" and g == "xy" and (pos - 1) % 4 == 0) | ||
265 | |||
266 | x = pack(" b b Xd b Xb x", 1, 2, 3) | ||
267 | assert(packsize(" b b Xd b Xb x") == 4) | ||
268 | assert(x == "\1\2\3\0") | ||
269 | a, b, c, pos = unpack("bbXdb", x) | ||
270 | assert(a == 1 and b == 2 and c == 3 and pos == #x) | ||
271 | |||
272 | -- only alignment | ||
273 | assert(packsize("!8 xXi8") == 8) | ||
274 | local pos = unpack("!8 xXi8", "0123456701234567"); assert(pos == 9) | ||
275 | assert(packsize("!8 xXi2") == 2) | ||
276 | local pos = unpack("!8 xXi2", "0123456701234567"); assert(pos == 3) | ||
277 | assert(packsize("!2 xXi2") == 2) | ||
278 | local pos = unpack("!2 xXi2", "0123456701234567"); assert(pos == 3) | ||
279 | assert(packsize("!2 xXi8") == 2) | ||
280 | local pos = unpack("!2 xXi8", "0123456701234567"); assert(pos == 3) | ||
281 | assert(packsize("!16 xXi16") == 16) | ||
282 | local pos = unpack("!16 xXi16", "0123456701234567"); assert(pos == 17) | ||
283 | |||
284 | checkerror("invalid next option", pack, "X") | ||
285 | checkerror("invalid next option", unpack, "XXi", "") | ||
286 | checkerror("invalid next option", unpack, "X i", "") | ||
287 | checkerror("invalid next option", pack, "Xc1") | ||
288 | end | ||
289 | |||
290 | do -- testing initial position | ||
291 | local x = pack("i4i4i4i4", 1, 2, 3, 4) | ||
292 | for pos = 1, 16, 4 do | ||
293 | local i, p = unpack("i4", x, pos) | ||
294 | assert(i == pos//4 + 1 and p == pos + 4) | ||
295 | end | ||
296 | |||
297 | -- with alignment | ||
298 | for pos = 0, 12 do -- will always round position to power of 2 | ||
299 | local i, p = unpack("!4 i4", x, pos + 1) | ||
300 | assert(i == (pos + 3)//4 + 1 and p == i*4 + 1) | ||
301 | end | ||
302 | |||
303 | -- negative indices | ||
304 | local i, p = unpack("!4 i4", x, -4) | ||
305 | assert(i == 4 and p == 17) | ||
306 | local i, p = unpack("!4 i4", x, -7) | ||
307 | assert(i == 4 and p == 17) | ||
308 | local i, p = unpack("!4 i4", x, -#x) | ||
309 | assert(i == 1 and p == 5) | ||
310 | |||
311 | -- limits | ||
312 | for i = 1, #x + 1 do | ||
313 | assert(unpack("c0", x, i) == "") | ||
314 | end | ||
315 | checkerror("out of string", unpack, "c0", x, 0) | ||
316 | checkerror("out of string", unpack, "c0", x, #x + 2) | ||
317 | checkerror("out of string", unpack, "c0", x, -(#x + 1)) | ||
318 | |||
319 | end | ||
320 | |||
321 | print "OK" | ||
322 | |||