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