# Copyright 2013 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. import sys import unittest from mojom.generate import module as mojom from mojom.generate import pack class PackTest(unittest.TestCase): def testOrdinalOrder(self): struct = mojom.Struct('test') struct.AddField('testfield1', mojom.INT32, 2) struct.AddField('testfield2', mojom.INT32, 1) ps = pack.PackedStruct(struct) self.assertEqual(2, len(ps.packed_fields)) self.assertEqual('testfield2', ps.packed_fields[0].field.mojom_name) self.assertEqual('testfield1', ps.packed_fields[1].field.mojom_name) def testZeroFields(self): struct = mojom.Struct('test') ps = pack.PackedStruct(struct) self.assertEqual(0, len(ps.packed_fields)) def testOneField(self): struct = mojom.Struct('test') struct.AddField('testfield1', mojom.INT8) ps = pack.PackedStruct(struct) self.assertEqual(1, len(ps.packed_fields)) def _CheckPackSequence(self, kinds, fields, offsets): """Checks the pack order and offsets of a sequence of mojom.Kinds. Args: kinds: A sequence of mojom.Kinds that specify the fields that are to be created. fields: The expected order of the resulting fields, with the integer "1" first. offsets: The expected order of offsets, with the integer "0" first. """ struct = mojom.Struct('test') index = 1 for kind in kinds: struct.AddField('%d' % index, kind) index += 1 ps = pack.PackedStruct(struct) num_fields = len(ps.packed_fields) self.assertEqual(len(kinds), num_fields) for i in range(num_fields): self.assertEqual('%d' % fields[i], ps.packed_fields[i].field.mojom_name) self.assertEqual(offsets[i], ps.packed_fields[i].offset) def testPaddingPackedInOrder(self): return self._CheckPackSequence((mojom.INT8, mojom.UINT8, mojom.INT32), (1, 2, 3), (0, 1, 4)) def testPaddingPackedOutOfOrder(self): return self._CheckPackSequence((mojom.INT8, mojom.INT32, mojom.UINT8), (1, 3, 2), (0, 1, 4)) def testPaddingPackedOverflow(self): kinds = (mojom.INT8, mojom.INT32, mojom.INT16, mojom.INT8, mojom.INT8) # 2 bytes should be packed together first, followed by short, then by int. fields = (1, 4, 3, 2, 5) offsets = (0, 1, 2, 4, 8) return self._CheckPackSequence(kinds, fields, offsets) def testNullableTypes(self): kinds = (mojom.STRING.MakeNullableKind(), mojom.HANDLE.MakeNullableKind(), mojom.Struct('test_struct').MakeNullableKind(), mojom.DCPIPE.MakeNullableKind(), mojom.Array().MakeNullableKind(), mojom.DPPIPE.MakeNullableKind(), mojom.Array(length=5).MakeNullableKind(), mojom.MSGPIPE.MakeNullableKind(), mojom.Interface('test_interface').MakeNullableKind(), mojom.SHAREDBUFFER.MakeNullableKind(), mojom.InterfaceRequest().MakeNullableKind()) fields = (1, 2, 4, 3, 5, 6, 8, 7, 9, 10, 11) offsets = (0, 8, 12, 16, 24, 32, 36, 40, 48, 56, 60) return self._CheckPackSequence(kinds, fields, offsets) def testAllTypes(self): return self._CheckPackSequence( (mojom.BOOL, mojom.INT8, mojom.STRING, mojom.UINT8, mojom.INT16, mojom.DOUBLE, mojom.UINT16, mojom.INT32, mojom.UINT32, mojom.INT64, mojom.FLOAT, mojom.STRING, mojom.HANDLE, mojom.UINT64, mojom.Struct('test'), mojom.Array(), mojom.STRING.MakeNullableKind()), (1, 2, 4, 5, 7, 3, 6, 8, 9, 10, 11, 13, 12, 14, 15, 16, 17, 18), (0, 1, 2, 4, 6, 8, 16, 24, 28, 32, 40, 44, 48, 56, 64, 72, 80, 88)) def testPaddingPackedOutOfOrderByOrdinal(self): struct = mojom.Struct('test') struct.AddField('testfield1', mojom.INT8) struct.AddField('testfield3', mojom.UINT8, 3) struct.AddField('testfield2', mojom.INT32, 2) ps = pack.PackedStruct(struct) self.assertEqual(3, len(ps.packed_fields)) # Second byte should be packed in behind first, altering order. self.assertEqual('testfield1', ps.packed_fields[0].field.mojom_name) self.assertEqual('testfield3', ps.packed_fields[1].field.mojom_name) self.assertEqual('testfield2', ps.packed_fields[2].field.mojom_name) # Second byte should be packed with first. self.assertEqual(0, ps.packed_fields[0].offset) self.assertEqual(1, ps.packed_fields[1].offset) self.assertEqual(4, ps.packed_fields[2].offset) def testBools(self): struct = mojom.Struct('test') struct.AddField('bit0', mojom.BOOL) struct.AddField('bit1', mojom.BOOL) struct.AddField('int', mojom.INT32) struct.AddField('bit2', mojom.BOOL) struct.AddField('bit3', mojom.BOOL) struct.AddField('bit4', mojom.BOOL) struct.AddField('bit5', mojom.BOOL) struct.AddField('bit6', mojom.BOOL) struct.AddField('bit7', mojom.BOOL) struct.AddField('bit8', mojom.BOOL) ps = pack.PackedStruct(struct) self.assertEqual(10, len(ps.packed_fields)) # First 8 bits packed together. for i in range(8): pf = ps.packed_fields[i] self.assertEqual(0, pf.offset) self.assertEqual("bit%d" % i, pf.field.mojom_name) self.assertEqual(i, pf.bit) # Ninth bit goes into second byte. self.assertEqual("bit8", ps.packed_fields[8].field.mojom_name) self.assertEqual(1, ps.packed_fields[8].offset) self.assertEqual(0, ps.packed_fields[8].bit) # int comes last. self.assertEqual("int", ps.packed_fields[9].field.mojom_name) self.assertEqual(4, ps.packed_fields[9].offset) def testMinVersion(self): """Tests that |min_version| is properly set for packed fields.""" struct = mojom.Struct('test') struct.AddField('field_2', mojom.BOOL, 2) struct.AddField('field_0', mojom.INT32, 0) struct.AddField('field_1', mojom.INT64, 1) ps = pack.PackedStruct(struct) self.assertEqual('field_0', ps.packed_fields[0].field.mojom_name) self.assertEqual('field_2', ps.packed_fields[1].field.mojom_name) self.assertEqual('field_1', ps.packed_fields[2].field.mojom_name) self.assertEqual(0, ps.packed_fields[0].min_version) self.assertEqual(0, ps.packed_fields[1].min_version) self.assertEqual(0, ps.packed_fields[2].min_version) struct.fields[0].attributes = {'MinVersion': 1} ps = pack.PackedStruct(struct) self.assertEqual(0, ps.packed_fields[0].min_version) self.assertEqual(1, ps.packed_fields[1].min_version) self.assertEqual(0, ps.packed_fields[2].min_version) def testGetVersionInfoEmptyStruct(self): """Tests that pack.GetVersionInfo() never returns an empty list, even for empty structs. """ struct = mojom.Struct('test') ps = pack.PackedStruct(struct) versions = pack.GetVersionInfo(ps) self.assertEqual(1, len(versions)) self.assertEqual(0, versions[0].version) self.assertEqual(0, versions[0].num_fields) self.assertEqual(8, versions[0].num_bytes) def testGetVersionInfoComplexOrder(self): """Tests pack.GetVersionInfo() using a struct whose definition order, ordinal order and pack order for fields are all different. """ struct = mojom.Struct('test') struct.AddField( 'field_3', mojom.BOOL, ordinal=3, attributes={'MinVersion': 3}) struct.AddField('field_0', mojom.INT32, ordinal=0) struct.AddField( 'field_1', mojom.INT64, ordinal=1, attributes={'MinVersion': 2}) struct.AddField( 'field_2', mojom.INT64, ordinal=2, attributes={'MinVersion': 3}) ps = pack.PackedStruct(struct) versions = pack.GetVersionInfo(ps) self.assertEqual(3, len(versions)) self.assertEqual(0, versions[0].version) self.assertEqual(1, versions[0].num_fields) self.assertEqual(16, versions[0].num_bytes) self.assertEqual(2, versions[1].version) self.assertEqual(2, versions[1].num_fields) self.assertEqual(24, versions[1].num_bytes) self.assertEqual(3, versions[2].version) self.assertEqual(4, versions[2].num_fields) self.assertEqual(32, versions[2].num_bytes) def testInterfaceAlignment(self): """Tests that interfaces are aligned on 4-byte boundaries, although the size of an interface is 8 bytes. """ kinds = (mojom.INT32, mojom.Interface('test_interface')) fields = (1, 2) offsets = (0, 4) self._CheckPackSequence(kinds, fields, offsets) def testAssociatedInterfaceAlignment(self): """Tests that associated interfaces are aligned on 4-byte boundaries, although the size of an associated interface is 8 bytes. """ kinds = (mojom.INT32, mojom.AssociatedInterface(mojom.Interface('test_interface'))) fields = (1, 2) offsets = (0, 4) self._CheckPackSequence(kinds, fields, offsets)