lua

A copy of the Lua development repository
Log | Files | Refs | README

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