tpack.lua (10643B)
1 -- $Id: testes/tpack.lua $ 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 local 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 do 139 local maxsize = (packsize("j") <= packsize("T")) and 140 math.maxinteger or (1 << (packsize("T") * 8)) 141 assert (packsize(string.format("c%d", maxsize - 9)) == maxsize - 9) 142 checkerror("too large", packsize, string.format("c%dc10", maxsize - 9)) 143 checkerror("too long", pack, string.format("xxxxxxxxxx c%d", maxsize - 9)) 144 end 145 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 c1", "", "X") == string.rep("\0", 88) .. "X") 233 assert(pack("c188 c2", "ab", "X\1") == 234 "ab" .. string.rep("\0", 188 - 2) .. "X\1") 235 local a, b, c = unpack("!4 z c3", "abcdefghi\0xyz") 236 assert(a == "abcdefghi" and b == "xyz" and c == 14) 237 checkerror("longer than", pack, "c3", "1234") 238 end 239 240 241 -- testing multiple types and sequence 242 do 243 local x = pack("<b h b f d f n i", 1, 2, 3, 4, 5, 6, 7, 8) 244 assert(#x == packsize("<b h b f d f n i")) 245 local a, b, c, d, e, f, g, h = unpack("<b h b f d f n i", x) 246 assert(a == 1 and b == 2 and c == 3 and d == 4 and e == 5 and f == 6 and 247 g == 7 and h == 8) 248 end 249 250 print "testing alignment" 251 do 252 assert(pack(" < i1 i2 ", 2, 3) == "\2\3\0") -- no alignment by default 253 local x = pack(">!8 b Xh i4 i8 c1 Xi8", -12, 100, 200, "\xEC") 254 assert(#x == packsize(">!8 b Xh i4 i8 c1 Xi8")) 255 assert(x == "\xf4" .. "\0\0\0" .. 256 "\0\0\0\100" .. 257 "\0\0\0\0\0\0\0\xC8" .. 258 "\xEC" .. "\0\0\0\0\0\0\0") 259 local a, b, c, d, pos = unpack(">!8 c1 Xh i4 i8 b Xi8 XI XH", x) 260 assert(a == "\xF4" and b == 100 and c == 200 and d == -20 and (pos - 1) == #x) 261 262 x = pack(">!4 c3 c4 c2 z i4 c5 c2 Xi4", 263 "abc", "abcd", "xz", "hello", 5, "world", "xy") 264 assert(x == "abcabcdxzhello\0\0\0\0\0\5worldxy\0") 265 local a, b, c, d, e, f, g, pos = unpack(">!4 c3 c4 c2 z i4 c5 c2 Xh Xi4", x) 266 assert(a == "abc" and b == "abcd" and c == "xz" and d == "hello" and 267 e == 5 and f == "world" and g == "xy" and (pos - 1) % 4 == 0) 268 269 x = pack(" b b Xd b Xb x", 1, 2, 3) 270 assert(packsize(" b b Xd b Xb x") == 4) 271 assert(x == "\1\2\3\0") 272 a, b, c, pos = unpack("bbXdb", x) 273 assert(a == 1 and b == 2 and c == 3 and pos == #x) 274 275 -- only alignment 276 assert(packsize("!8 xXi8") == 8) 277 local pos = unpack("!8 xXi8", "0123456701234567"); assert(pos == 9) 278 assert(packsize("!8 xXi2") == 2) 279 local pos = unpack("!8 xXi2", "0123456701234567"); assert(pos == 3) 280 assert(packsize("!2 xXi2") == 2) 281 local pos = unpack("!2 xXi2", "0123456701234567"); assert(pos == 3) 282 assert(packsize("!2 xXi8") == 2) 283 local pos = unpack("!2 xXi8", "0123456701234567"); assert(pos == 3) 284 assert(packsize("!16 xXi16") == 16) 285 local pos = unpack("!16 xXi16", "0123456701234567"); assert(pos == 17) 286 287 checkerror("invalid next option", pack, "X") 288 checkerror("invalid next option", unpack, "XXi", "") 289 checkerror("invalid next option", unpack, "X i", "") 290 checkerror("invalid next option", pack, "Xc1") 291 end 292 293 do -- testing initial position 294 local x = pack("i4i4i4i4", 1, 2, 3, 4) 295 for pos = 1, 16, 4 do 296 local i, p = unpack("i4", x, pos) 297 assert(i == pos//4 + 1 and p == pos + 4) 298 end 299 300 -- with alignment 301 for pos = 0, 12 do -- will always round position to power of 2 302 local i, p = unpack("!4 i4", x, pos + 1) 303 assert(i == (pos + 3)//4 + 1 and p == i*4 + 1) 304 end 305 306 -- negative indices 307 local i, p = unpack("!4 i4", x, -4) 308 assert(i == 4 and p == 17) 309 local i, p = unpack("!4 i4", x, -7) 310 assert(i == 4 and p == 17) 311 local i, p = unpack("!4 i4", x, -#x) 312 assert(i == 1 and p == 5) 313 314 -- limits 315 for i = 1, #x + 1 do 316 assert(unpack("c0", x, i) == "") 317 end 318 checkerror("out of string", unpack, "c0", x, #x + 2) 319 320 end 321 322 print "OK" 323