diff options
| author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2018-07-09 12:33:01 -0300 |
|---|---|---|
| committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2018-07-09 12:33:01 -0300 |
| commit | 7c519dfbd0c68b952f0849e01deaa3750e1f8153 (patch) | |
| tree | dde3ddbba310877db725df37a0d9f2cbe4e2a8f9 /testes/tpack.lua | |
| parent | f59e6a93c0ad38a27a420e51abf8f13d962446b5 (diff) | |
| download | lua-7c519dfbd0c68b952f0849e01deaa3750e1f8153.tar.gz lua-7c519dfbd0c68b952f0849e01deaa3750e1f8153.tar.bz2 lua-7c519dfbd0c68b952f0849e01deaa3750e1f8153.zip | |
Added manual and tests for version 5.4-w2
Diffstat (limited to 'testes/tpack.lua')
| -rw-r--r-- | testes/tpack.lua | 324 |
1 files changed, 324 insertions, 0 deletions
diff --git a/testes/tpack.lua b/testes/tpack.lua new file mode 100644 index 00000000..0e639cc5 --- /dev/null +++ b/testes/tpack.lua | |||
| @@ -0,0 +1,324 @@ | |||
| 1 | -- $Id: tpack.lua,v 1.14 2018/06/04 14:26:32 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 | checkerror("unfinished string", unpack, "zc10000000", "alo") | ||
| 208 | |||
| 209 | for i = 2, NB do | ||
| 210 | local s1 = pack("s" .. i, s) | ||
| 211 | assert(unpack("s" .. i, s1) == s and #s1 == #s + i) | ||
| 212 | end | ||
| 213 | end | ||
| 214 | |||
| 215 | do | ||
| 216 | local x = pack("s", "alo") | ||
| 217 | checkerror("too short", unpack, "s", x:sub(1, -2)) | ||
| 218 | checkerror("too short", unpack, "c5", "abcd") | ||
| 219 | checkerror("out of limits", pack, "s100", "alo") | ||
| 220 | end | ||
| 221 | |||
| 222 | do | ||
| 223 | assert(pack("c0", "") == "") | ||
| 224 | assert(packsize("c0") == 0) | ||
| 225 | assert(unpack("c0", "") == "") | ||
| 226 | assert(pack("<! c3", "abc") == "abc") | ||
| 227 | assert(packsize("<! c3") == 3) | ||
| 228 | assert(pack(">!4 c6", "abcdef") == "abcdef") | ||
| 229 | assert(pack("c3", "123") == "123") | ||
| 230 | assert(pack("c0", "") == "") | ||
| 231 | assert(pack("c8", "123456") == "123456\0\0") | ||
| 232 | assert(pack("c88", "") == string.rep("\0", 88)) | ||
| 233 | assert(pack("c188", "ab") == "ab" .. string.rep("\0", 188 - 2)) | ||
| 234 | local a, b, c = unpack("!4 z c3", "abcdefghi\0xyz") | ||
| 235 | assert(a == "abcdefghi" and b == "xyz" and c == 14) | ||
| 236 | checkerror("longer than", pack, "c3", "1234") | ||
| 237 | end | ||
| 238 | |||
| 239 | |||
| 240 | -- testing multiple types and sequence | ||
| 241 | do | ||
| 242 | local x = pack("<b h b f d f n i", 1, 2, 3, 4, 5, 6, 7, 8) | ||
| 243 | assert(#x == packsize("<b h b f d f n i")) | ||
| 244 | local a, b, c, d, e, f, g, h = unpack("<b h b f d f n i", x) | ||
| 245 | assert(a == 1 and b == 2 and c == 3 and d == 4 and e == 5 and f == 6 and | ||
| 246 | g == 7 and h == 8) | ||
| 247 | end | ||
| 248 | |||
| 249 | print "testing alignment" | ||
| 250 | do | ||
| 251 | assert(pack(" < i1 i2 ", 2, 3) == "\2\3\0") -- no alignment by default | ||
| 252 | local x = pack(">!8 b Xh i4 i8 c1 Xi8", -12, 100, 200, "\xEC") | ||
| 253 | assert(#x == packsize(">!8 b Xh i4 i8 c1 Xi8")) | ||
| 254 | assert(x == "\xf4" .. "\0\0\0" .. | ||
| 255 | "\0\0\0\100" .. | ||
| 256 | "\0\0\0\0\0\0\0\xC8" .. | ||
| 257 | "\xEC" .. "\0\0\0\0\0\0\0") | ||
| 258 | local a, b, c, d, pos = unpack(">!8 c1 Xh i4 i8 b Xi8 XI XH", x) | ||
| 259 | assert(a == "\xF4" and b == 100 and c == 200 and d == -20 and (pos - 1) == #x) | ||
| 260 | |||
| 261 | x = pack(">!4 c3 c4 c2 z i4 c5 c2 Xi4", | ||
| 262 | "abc", "abcd", "xz", "hello", 5, "world", "xy") | ||
| 263 | assert(x == "abcabcdxzhello\0\0\0\0\0\5worldxy\0") | ||
| 264 | local a, b, c, d, e, f, g, pos = unpack(">!4 c3 c4 c2 z i4 c5 c2 Xh Xi4", x) | ||
| 265 | assert(a == "abc" and b == "abcd" and c == "xz" and d == "hello" and | ||
| 266 | e == 5 and f == "world" and g == "xy" and (pos - 1) % 4 == 0) | ||
| 267 | |||
| 268 | x = pack(" b b Xd b Xb x", 1, 2, 3) | ||
| 269 | assert(packsize(" b b Xd b Xb x") == 4) | ||
| 270 | assert(x == "\1\2\3\0") | ||
| 271 | a, b, c, pos = unpack("bbXdb", x) | ||
| 272 | assert(a == 1 and b == 2 and c == 3 and pos == #x) | ||
| 273 | |||
| 274 | -- only alignment | ||
| 275 | assert(packsize("!8 xXi8") == 8) | ||
| 276 | local pos = unpack("!8 xXi8", "0123456701234567"); assert(pos == 9) | ||
| 277 | assert(packsize("!8 xXi2") == 2) | ||
| 278 | local pos = unpack("!8 xXi2", "0123456701234567"); assert(pos == 3) | ||
| 279 | assert(packsize("!2 xXi2") == 2) | ||
| 280 | local pos = unpack("!2 xXi2", "0123456701234567"); assert(pos == 3) | ||
| 281 | assert(packsize("!2 xXi8") == 2) | ||
| 282 | local pos = unpack("!2 xXi8", "0123456701234567"); assert(pos == 3) | ||
| 283 | assert(packsize("!16 xXi16") == 16) | ||
| 284 | local pos = unpack("!16 xXi16", "0123456701234567"); assert(pos == 17) | ||
| 285 | |||
| 286 | checkerror("invalid next option", pack, "X") | ||
| 287 | checkerror("invalid next option", unpack, "XXi", "") | ||
| 288 | checkerror("invalid next option", unpack, "X i", "") | ||
| 289 | checkerror("invalid next option", pack, "Xc1") | ||
| 290 | end | ||
| 291 | |||
| 292 | do -- testing initial position | ||
| 293 | local x = pack("i4i4i4i4", 1, 2, 3, 4) | ||
| 294 | for pos = 1, 16, 4 do | ||
| 295 | local i, p = unpack("i4", x, pos) | ||
| 296 | assert(i == pos//4 + 1 and p == pos + 4) | ||
| 297 | end | ||
| 298 | |||
| 299 | -- with alignment | ||
| 300 | for pos = 0, 12 do -- will always round position to power of 2 | ||
| 301 | local i, p = unpack("!4 i4", x, pos + 1) | ||
| 302 | assert(i == (pos + 3)//4 + 1 and p == i*4 + 1) | ||
| 303 | end | ||
| 304 | |||
| 305 | -- negative indices | ||
| 306 | local i, p = unpack("!4 i4", x, -4) | ||
| 307 | assert(i == 4 and p == 17) | ||
| 308 | local i, p = unpack("!4 i4", x, -7) | ||
| 309 | assert(i == 4 and p == 17) | ||
| 310 | local i, p = unpack("!4 i4", x, -#x) | ||
| 311 | assert(i == 1 and p == 5) | ||
| 312 | |||
| 313 | -- limits | ||
| 314 | for i = 1, #x + 1 do | ||
| 315 | assert(unpack("c0", x, i) == "") | ||
| 316 | end | ||
| 317 | checkerror("out of string", unpack, "c0", x, 0) | ||
| 318 | checkerror("out of string", unpack, "c0", x, #x + 2) | ||
| 319 | checkerror("out of string", unpack, "c0", x, -(#x + 1)) | ||
| 320 | |||
| 321 | end | ||
| 322 | |||
| 323 | print "OK" | ||
| 324 | |||
