|  | 
|  | 1 | +import unittest | 
|  | 2 | +from pathlib import Path | 
|  | 3 | + | 
|  | 4 | +from tests.gen.car_example import MessageHeaderEncoder, CarEncoder, BooleanType, Model, EngineEncoder, BoostType | 
|  | 5 | +from tests.gen.car_example import MessageHeaderDecoder, CarDecoder, EngineDecoder | 
|  | 6 | + | 
|  | 7 | + | 
|  | 8 | +class TestCarExample(unittest.TestCase): | 
|  | 9 | + REFERENCE_FILE_ENCODE = Path(__file__).resolve().parent / Path('gen') / 'car_example' / 'car_example_data.sbe' | 
|  | 10 | + | 
|  | 11 | + VEHICLE_CODE = "abcdef".encode(CarDecoder.vehicleCodeCharacterEncoding()) | 
|  | 12 | + MANUFACTURER_CODE = "123".encode(EngineDecoder.manufacturerCodeCharacterEncoding()) | 
|  | 13 | + MANUFACTURER = "Honda".encode(CarDecoder.manufacturerCharacterEncoding()) | 
|  | 14 | + MODEL = "Civic VTi".encode(CarDecoder.modelCharacterEncoding()) | 
|  | 15 | + ACTIVATION_CODE = "abcdef".encode(CarDecoder.activationCodeCharacterEncoding()) | 
|  | 16 | + | 
|  | 17 | + CAR_ENCODER = CarEncoder() | 
|  | 18 | + MESSAGE_HEADER_ENCODER = MessageHeaderEncoder() | 
|  | 19 | + | 
|  | 20 | + CAR_DECODER = CarDecoder() | 
|  | 21 | + MESSAGE_HEADER_DECODER = MessageHeaderDecoder() | 
|  | 22 | + | 
|  | 23 | + def test_encoding(self): | 
|  | 24 | + with open(self.REFERENCE_FILE_ENCODE, 'rb') as f: | 
|  | 25 | + buffer = f.read() | 
|  | 26 | + py_buf = bytearray(4096) | 
|  | 27 | + self._encode(py_buf, self.MESSAGE_HEADER_ENCODER, self.CAR_ENCODER) | 
|  | 28 | + # Encoded message should match | 
|  | 29 | + self.assertEqual(buffer, py_buf[:207]) | 
|  | 30 | + # The empty part of the buffer should be all 0's | 
|  | 31 | + self.assertEqual(bytes(len(py_buf) - len(buffer)), py_buf[len(buffer):]) | 
|  | 32 | + self.assertEqual(207, len(buffer)) | 
|  | 33 | + | 
|  | 34 | + def test_decoding(self): | 
|  | 35 | + self.maxDiff = None | 
|  | 36 | + with open(self.REFERENCE_FILE_ENCODE, 'rb') as f: | 
|  | 37 | + buffer = f.read() | 
|  | 38 | + py_buf = bytearray(4096) | 
|  | 39 | + self._encode(py_buf, self.MESSAGE_HEADER_ENCODER, self.CAR_ENCODER) | 
|  | 40 | + self._decode(py_buf, self.MESSAGE_HEADER_DECODER, self.CAR_DECODER) | 
|  | 41 | + self._decode(buffer, self.MESSAGE_HEADER_DECODER, self.CAR_DECODER) | 
|  | 42 | + | 
|  | 43 | + def _encode(self, buf: bytearray, header: MessageHeaderEncoder, car: CarEncoder): | 
|  | 44 | + offset = 0 | 
|  | 45 | + | 
|  | 46 | + car.wrapAndApplyHeader(buf, offset, header) | 
|  | 47 | + car.serialNumber(1234) | 
|  | 48 | + car.modelYear(2013) | 
|  | 49 | + car.available(BooleanType.T) | 
|  | 50 | + car.code(Model.A) | 
|  | 51 | + car.set_vehicleCode(self.VEHICLE_CODE) | 
|  | 52 | + | 
|  | 53 | + car.someNumbers(0,1) | 
|  | 54 | + car.someNumbers(1,2) | 
|  | 55 | + car.someNumbers(2,3) | 
|  | 56 | + car.someNumbers(3,4) | 
|  | 57 | + | 
|  | 58 | + car.extras() \ | 
|  | 59 | + .clear() \ | 
|  | 60 | + .cruiseControl(True) \ | 
|  | 61 | + .sportsPack(True) \ | 
|  | 62 | + .sunRoof(False) | 
|  | 63 | + | 
|  | 64 | + car.engine() \ | 
|  | 65 | + .capacity(2000) \ | 
|  | 66 | + .numCylinders(4) \ | 
|  | 67 | + .set_manufacturerCode(self.MANUFACTURER_CODE) \ | 
|  | 68 | + .efficiency(35) \ | 
|  | 69 | + .boosterEnabled(BooleanType.T) \ | 
|  | 70 | + .booster() \ | 
|  | 71 | + .boostType(BoostType.NITROUS) \ | 
|  | 72 | + .horsePower(200) | 
|  | 73 | + | 
|  | 74 | + ff = car.fuelFiguresCount(3) | 
|  | 75 | + ff.next().speed(30).mpg(35.9).usageDescription("Urban Cycle".encode(CarEncoder.FuelFiguresEncoder | 
|  | 76 | + .usageDescriptionCharacterEncoding())) | 
|  | 77 | + ff.next().speed(55).mpg(49.0).usageDescription("Combined Cycle".encode(CarEncoder.FuelFiguresEncoder | 
|  | 78 | + .usageDescriptionCharacterEncoding())) | 
|  | 79 | + ff.next().speed(75).mpg(40.0).usageDescription("Highway Cycle".encode(CarEncoder.FuelFiguresEncoder | 
|  | 80 | + .usageDescriptionCharacterEncoding())) | 
|  | 81 | + | 
|  | 82 | + figures = car.performanceFiguresCount(2) | 
|  | 83 | + figures.next().octaneRating(95).accelerationCount(3) \ | 
|  | 84 | + .next().mph(30).seconds(4.0) \ | 
|  | 85 | + .next().mph(60).seconds(7.5) \ | 
|  | 86 | + .next().mph(100).seconds(12.2) | 
|  | 87 | + | 
|  | 88 | + figures.next().octaneRating(99).accelerationCount(3) \ | 
|  | 89 | + .next().mph(30).seconds(3.8) \ | 
|  | 90 | + .next().mph(60).seconds(7.1) \ | 
|  | 91 | + .next().mph(100).seconds(11.8) | 
|  | 92 | + | 
|  | 93 | + car.manufacturer(self.MANUFACTURER).model(self.MODEL).activationCode(self.ACTIVATION_CODE) | 
|  | 94 | + | 
|  | 95 | + return header.encodedLength + car.encodedLength | 
|  | 96 | + | 
|  | 97 | + def _decode(self, buf: bytes, header: MessageHeaderDecoder, car: CarDecoder): | 
|  | 98 | + offset = 0 | 
|  | 99 | + out = "" | 
|  | 100 | + header.wrap(buf, offset) | 
|  | 101 | + template_id = header.templateId() | 
|  | 102 | + if template_id != car.sbeTemplateId: | 
|  | 103 | + raise Exception("Template ID missmatch") | 
|  | 104 | + acting_block_length = header.blockLength() | 
|  | 105 | + acting_block_version = header.version() | 
|  | 106 | + offset += header.encodedLength | 
|  | 107 | + | 
|  | 108 | + car.wrap(buf, offset, acting_block_length, acting_block_version) | 
|  | 109 | + self.assertEqual(1234, car.serialNumber()) | 
|  | 110 | + self.assertEqual(2013, car.modelYear()) | 
|  | 111 | + self.assertEqual(BooleanType.T, car.available()) | 
|  | 112 | + self.assertEqual(Model.A, car.code()) | 
|  | 113 | + self.assertEqual((1, 2, 3, 4), car.getMultiSomeNumbers()) | 
|  | 114 | + self.assertEqual(1, car.someNumbers(0)) | 
|  | 115 | + self.assertEqual(2, car.someNumbers(1)) | 
|  | 116 | + self.assertEqual(3, car.someNumbers(2)) | 
|  | 117 | + self.assertEqual(4, car.someNumbers(3)) | 
|  | 118 | + index_oob = False | 
|  | 119 | + try: | 
|  | 120 | + car.someNumbers(55) | 
|  | 121 | + except IndexError as e: | 
|  | 122 | + index_oob = True | 
|  | 123 | + self.assertEqual(IndexError, type(e)) | 
|  | 124 | + self.assertTrue(index_oob) | 
|  | 125 | + | 
|  | 126 | + self.assertEqual("abcdef", str(car.getMultiVehicleCode(), car.vehicleCodeCharacterEncoding())) | 
|  | 127 | + | 
|  | 128 | + extras = car.extras() | 
|  | 129 | + self.assertTrue(extras.cruiseControl()) | 
|  | 130 | + self.assertTrue(extras.sportsPack()) | 
|  | 131 | + self.assertFalse(extras.sunRoof()) | 
|  | 132 | + | 
|  | 133 | + self.assertEqual("C", car.discountedModel().name) | 
|  | 134 | + | 
|  | 135 | + engine = car.engine() | 
|  | 136 | + self.assertEqual(2000, engine.capacity()) | 
|  | 137 | + self.assertEqual(4, engine.numCylinders()) | 
|  | 138 | + self.assertEqual(9000, engine.maxRpm) | 
|  | 139 | + self.assertEqual("123", str(engine.getMultiManufacturerCode(), EngineDecoder.manufacturerCodeCharacterEncoding())) | 
|  | 140 | + self.assertEqual(35, engine.efficiency()) | 
|  | 141 | + self.assertEqual(BooleanType.T, engine.boosterEnabled()) | 
|  | 142 | + self.assertEqual(BoostType.NITROUS, engine.booster().boostType()) | 
|  | 143 | + self.assertEqual(200, engine.booster().horsePower()) | 
|  | 144 | + | 
|  | 145 | + self.assertEqual("Petrol", str(engine.getFuel(0, len(buf)).tobytes().decode())) | 
|  | 146 | + | 
|  | 147 | + ff = car.fuelFigures() | 
|  | 148 | + ff.next() | 
|  | 149 | + self.assertEqual(30, ff.speed()) | 
|  | 150 | + self.assertAlmostEqual(35.9, ff.mpg(), places=5) | 
|  | 151 | + self.assertEqual("Urban Cycle", ff.usageDescription()) | 
|  | 152 | + ff.next() | 
|  | 153 | + self.assertEqual(55, ff.speed()) | 
|  | 154 | + self.assertAlmostEqual(49.0, ff.mpg(), places=5) | 
|  | 155 | + self.assertEqual("Combined Cycle", ff.usageDescription()) | 
|  | 156 | + ff.next() | 
|  | 157 | + self.assertEqual(75, ff.speed()) | 
|  | 158 | + self.assertAlmostEqual(40.0, ff.mpg(), places=5) | 
|  | 159 | + self.assertEqual("Highway Cycle", ff.usageDescription()) | 
|  | 160 | + | 
|  | 161 | + pf = car.performanceFigures() | 
|  | 162 | + pf.next() | 
|  | 163 | + self.assertEqual(95, pf.octaneRating()) | 
|  | 164 | + pfa = pf.acceleration() | 
|  | 165 | + pfa.next() | 
|  | 166 | + self.assertEqual(30, pfa.mph()) | 
|  | 167 | + self.assertAlmostEqual(4.0, pfa.seconds(), places=5) | 
|  | 168 | + pfa.next() | 
|  | 169 | + self.assertEqual(60, pfa.mph()) | 
|  | 170 | + self.assertAlmostEqual(7.5, pfa.seconds(), places=5) | 
|  | 171 | + pfa.next() | 
|  | 172 | + self.assertEqual(100, pfa.mph()) | 
|  | 173 | + self.assertAlmostEqual(12.2, pfa.seconds(), places=5) | 
|  | 174 | + | 
|  | 175 | + pf.next() | 
|  | 176 | + self.assertEqual(99, pf.octaneRating()) | 
|  | 177 | + pfa = pf.acceleration() | 
|  | 178 | + pfa.next() | 
|  | 179 | + self.assertEqual(30, pfa.mph()) | 
|  | 180 | + self.assertAlmostEqual(3.8, pfa.seconds(), places=5) | 
|  | 181 | + pfa.next() | 
|  | 182 | + self.assertEqual(60, pfa.mph()) | 
|  | 183 | + self.assertAlmostEqual(7.1, pfa.seconds(), places=5) | 
|  | 184 | + pfa.next() | 
|  | 185 | + self.assertEqual(100, pfa.mph()) | 
|  | 186 | + self.assertAlmostEqual(11.8, pfa.seconds(), places=5) | 
|  | 187 | + | 
|  | 188 | + self.assertEqual("Honda", car.manufacturer()) | 
|  | 189 | + self.assertEqual("Civic VTi", car.model()) | 
|  | 190 | + self.assertEqual("abcdef", car.activationCode()) | 
|  | 191 | + self.assertEqual(199, car.encodedLength) | 
|  | 192 | + return out | 
0 commit comments