Home | History | Annotate | Download | only in test
      1 #!/usr/bin/python
      2 #
      3 # Copyright 2016 The Android Open Source Project
      4 #
      5 # Licensed under the Apache License, Version 2.0 (the "License");
      6 # you may not use this file except in compliance with the License.
      7 # You may obtain a copy of the License at
      8 #
      9 # http://www.apache.org/licenses/LICENSE-2.0
     10 #
     11 # Unless required by applicable law or agreed to in writing, software
     12 # distributed under the License is distributed on an "AS IS" BASIS,
     13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14 # See the License for the specific language governing permissions and
     15 # limitations under the License.
     16 
     17 import unittest
     18 
     19 import cstruct
     20 
     21 
     22 # These aren't constants, they're classes. So, pylint: disable=invalid-name
     23 TestStructA = cstruct.Struct("TestStructA", "=BI", "byte1 int2")
     24 TestStructB = cstruct.Struct("TestStructB", "=BI", "byte1 int2")
     25 
     26 
     27 class CstructTest(unittest.TestCase):
     28 
     29   def CheckEquals(self, a, b):
     30     self.assertEquals(a, b)
     31     self.assertEquals(b, a)
     32     assert a == b
     33     assert b == a
     34     assert not (a != b)  # pylint: disable=g-comparison-negation,superfluous-parens
     35     assert not (b != a)  # pylint: disable=g-comparison-negation,superfluous-parens
     36 
     37   def CheckNotEquals(self, a, b):
     38     self.assertNotEquals(a, b)
     39     self.assertNotEquals(b, a)
     40     assert a != b
     41     assert b != a
     42     assert not (a == b)  # pylint: disable=g-comparison-negation,superfluous-parens
     43     assert not (b == a)  # pylint: disable=g-comparison-negation,superfluous-parens
     44 
     45   def testEqAndNe(self):
     46     a1 = TestStructA((1, 2))
     47     a2 = TestStructA((2, 3))
     48     a3 = TestStructA((1, 2))
     49     b = TestStructB((1, 2))
     50     self.CheckNotEquals(a1, b)
     51     self.CheckNotEquals(a2, b)
     52     self.CheckNotEquals(a1, a2)
     53     self.CheckNotEquals(a2, a3)
     54     for i in [a1, a2, a3, b]:
     55       self.CheckEquals(i, i)
     56     self.CheckEquals(a1, a3)
     57 
     58   def testNestedStructs(self):
     59     Nested = cstruct.Struct("Nested", "!HSSi",
     60                             "word1 nest2 nest3 int4",
     61                             [TestStructA, TestStructB])
     62     DoubleNested = cstruct.Struct("DoubleNested", "SSB",
     63                                   "nest1 nest2 byte3",
     64                                   [TestStructA, Nested])
     65     d = DoubleNested((TestStructA((1, 2)),
     66                       Nested((5, TestStructA((3, 4)), TestStructB((7, 8)), 9)),
     67                       6))
     68 
     69     expectedlen = (len(TestStructA) +
     70                    2 + len(TestStructA) + len(TestStructB) + 4 +
     71                    1)
     72     self.assertEquals(expectedlen, len(DoubleNested))
     73 
     74     self.assertEquals(7, d.nest2.nest3.byte1)
     75 
     76     d.byte3 = 252
     77     d.nest2.word1 = 33214
     78     n = d.nest2
     79     n.int4 = -55
     80     t = n.nest3
     81     t.int2 = 33627591
     82 
     83     self.assertEquals(33627591, d.nest2.nest3.int2)
     84 
     85     expected = (
     86         "DoubleNested(nest1=TestStructA(byte1=1, int2=2),"
     87         " nest2=Nested(word1=33214, nest2=TestStructA(byte1=3, int2=4),"
     88         " nest3=TestStructB(byte1=7, int2=33627591), int4=-55), byte3=252)")
     89     self.assertEquals(expected, str(d))
     90     expected = ("01" "02000000"
     91                 "81be" "03" "04000000"
     92                 "07" "c71d0102" "ffffffc9" "fc").decode("hex")
     93     self.assertEquals(expected, d.Pack())
     94     unpacked = DoubleNested(expected)
     95     self.CheckEquals(unpacked, d)
     96 
     97   def testNullTerminatedStrings(self):
     98     TestStruct = cstruct.Struct("TestStruct", "B16si16AH",
     99                                 "byte1 string2 int3 ascii4 word5")
    100     nullstr = "hello" + (16 - len("hello")) * "\x00"
    101 
    102     t = TestStruct((2, nullstr, 12345, nullstr, 33210))
    103     expected = ("TestStruct(byte1=2, string2=68656c6c6f0000000000000000000000,"
    104                 " int3=12345, ascii4=hello, word5=33210)")
    105     self.assertEquals(expected, str(t))
    106 
    107     embeddednull = "hello\x00visible123"
    108     t = TestStruct((2, embeddednull, 12345, embeddednull, 33210))
    109     expected = ("TestStruct(byte1=2, string2=68656c6c6f0076697369626c65313233,"
    110                 " int3=12345, ascii4=hello\x00visible123, word5=33210)")
    111     self.assertEquals(expected, str(t))
    112 
    113   def testZeroInitialization(self):
    114     TestStruct = cstruct.Struct("TestStruct", "B16si16AH",
    115                                 "byte1 string2 int3 ascii4 word5")
    116     t = TestStruct()
    117     self.assertEquals(0, t.byte1)
    118     self.assertEquals("\x00" * 16, t.string2)
    119     self.assertEquals(0, t.int3)
    120     self.assertEquals("\x00" * 16, t.ascii4)
    121     self.assertEquals(0, t.word5)
    122     self.assertEquals("\x00" * len(TestStruct), t.Pack())
    123 
    124   def testKeywordInitialization(self):
    125     TestStruct = cstruct.Struct("TestStruct", "=B16sIH",
    126                                 "byte1 string2 int3 word4")
    127     text = "hello world! ^_^"
    128     text_bytes = text.encode("hex")
    129 
    130     # Populate all fields
    131     t1 = TestStruct(byte1=1, string2=text, int3=0xFEDCBA98, word4=0x1234)
    132     expected = ("01" + text_bytes + "98BADCFE" "3412").decode("hex")
    133     self.assertEquals(expected, t1.Pack())
    134 
    135     # Partially populated
    136     t1 = TestStruct(string2=text, word4=0x1234)
    137     expected = ("00" + text_bytes + "00000000" "3412").decode("hex")
    138     self.assertEquals(expected, t1.Pack())
    139 
    140   def testCstructOffset(self):
    141     TestStruct = cstruct.Struct("TestStruct", "B16si16AH",
    142                                 "byte1 string2 int3 ascii4 word5")
    143     nullstr = "hello" + (16 - len("hello")) * "\x00"
    144     t = TestStruct((2, nullstr, 12345, nullstr, 33210))
    145     self.assertEquals(0, t.offset("byte1"))
    146     self.assertEquals(1, t.offset("string2"))  # sizeof(byte)
    147     self.assertEquals(17, t.offset("int3"))    # sizeof(byte) + 16*sizeof(char)
    148     # The integer is automatically padded by the struct module
    149     # to match native alignment.
    150     # offset = sizeof(byte) + 16*sizeof(char) + padding + sizeof(int)
    151     self.assertEquals(24, t.offset("ascii4"))
    152     self.assertEquals(40, t.offset("word5"))
    153     self.assertRaises(KeyError, t.offset, "random")
    154 
    155     # TODO: Add support for nested struct offset
    156     Nested = cstruct.Struct("Nested", "!HSSi", "word1 nest2 nest3 int4",
    157                             [TestStructA, TestStructB])
    158     DoubleNested = cstruct.Struct("DoubleNested", "SSB", "nest1 nest2 byte3",
    159                                   [TestStructA, Nested])
    160     d = DoubleNested((TestStructA((1, 2)), Nested((5, TestStructA((3, 4)),
    161                                                    TestStructB((7, 8)), 9)), 6))
    162     self.assertEqual(0, d.offset("nest1"))
    163     self.assertEqual(len(TestStructA), d.offset("nest2"))
    164     self.assertEqual(len(TestStructA) + len(Nested), d.offset("byte3"))
    165     self.assertRaises(KeyError, t.offset, "word1")
    166 
    167   def testDefinitionFieldMismatch(self):
    168     cstruct.Struct("TestA", "=BI", "byte1 int2")
    169     cstruct.Struct("TestA", "=BxxxxxIx", "byte1 int2")
    170     with self.assertRaises(ValueError):
    171       cstruct.Struct("TestA", "=B", "byte1 int2")
    172     with self.assertRaises(ValueError):
    173       cstruct.Struct("TestA", "=BI", "byte1")
    174 
    175     Nested = cstruct.Struct("Nested", "!II", "int1 int2")
    176     cstruct.Struct("TestB", "=BSI", "byte1 nest2 int3", [Nested])
    177     cstruct.Struct("TestB", "=BxSxIx", "byte1 nest2 int3", [Nested])
    178     with self.assertRaises(ValueError):
    179       cstruct.Struct("TestB", "=BSI", "byte1 int3", [Nested])
    180     with self.assertRaises(ValueError):
    181       cstruct.Struct("TestB", "=BSI", "byte1 nest2", [Nested])
    182 
    183     cstruct.Struct("TestC", "=BSSI", "byte1 nest2 nest3 int4", [Nested, Nested])
    184     with self.assertRaises(ValueError):
    185       cstruct.Struct("TestC", "=BSSI", "byte1 nest2 int4", [Nested, Nested])
    186 
    187 
    188 if __name__ == "__main__":
    189   unittest.main()
    190