byte_io_unittest.cc (10154B)
1 /* 2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11 #include "modules/rtp_rtcp/source/byte_io.h" 12 13 #include <cstdint> 14 #include <limits> 15 16 #include "test/gtest.h" 17 18 namespace webrtc { 19 namespace { 20 21 class ByteIoTest : public ::testing::Test { 22 protected: 23 ByteIoTest() = default; 24 ~ByteIoTest() override = default; 25 26 enum { kAlignments = sizeof(uint64_t) - 1 }; 27 28 // Method to create a test value that is not the same when byte reversed. 29 template <typename T> 30 T CreateTestValue(bool negative, uint8_t num_bytes) { 31 // Examples of output: 32 // T = int32_t, negative = false, num_bytes = 4: 0x00010203 33 // T = int32_t, negative = true, num_bytes = 4: 0xFFFEFDFC 34 // T = int32_t, negative = false, num_bytes = 3: 0x000102 35 // * T = int32_t, negative = true, num_bytes = 3: 0xFFFEFD 36 37 T val = 0; 38 for (uint8_t i = 0; i != num_bytes; ++i) { 39 val = (val << 8) + (negative ? (0xFF - i) : (i + 1)); 40 } 41 42 // This loop will create a sign extend mask if num_bytes if necessary. 43 // For the last example (marked * above), the number needs to be sign 44 // extended to be a valid int32_t. The sign extend mask is 0xFF000000. 45 // Comments for each step with this example below. 46 if (std::numeric_limits<T>::is_signed && negative && 47 num_bytes < sizeof(T)) { 48 // Start with mask = 0xFFFFFFFF. 49 T mask = static_cast<T>(-1); 50 // Create a temporary for the lowest byte (0x000000FF). 51 const T neg_byte = static_cast<T>(0xFF); 52 for (int i = 0; i < num_bytes; ++i) { 53 // And the inverse of the temporary and the mask: 54 // 0xFFFFFFFF & 0xFFFFFF00 = 0xFFFFFF00. 55 // 0xFFFFFF00 & 0xFFFF00FF = 0xFFFF0000. 56 // 0xFFFF0000 & 0xFF00FFFF = 0xFF000000. 57 mask &= ~(neg_byte << (i * 8)); 58 } 59 // Add the sign extension mask to the actual value. 60 val |= mask; 61 } 62 return val; 63 } 64 65 // Populate byte buffer with value, in big endian format. 66 template <typename T> 67 void PopulateTestData(uint8_t* data, T value, int num_bytes, bool bigendian) { 68 if (bigendian) { 69 for (int i = 0; i < num_bytes; ++i) { 70 data[i] = (value >> ((num_bytes - i - 1) * 8)) & 0xFF; 71 } 72 } else { 73 for (int i = 0; i < num_bytes; ++i) { 74 data[i] = (value >> (i * 8)) & 0xFF; 75 } 76 } 77 } 78 79 // Test reading big endian numbers. 80 // Template arguments: Type T, read method RM(buffer), B bytes of data. 81 template <typename T, T (*RM)(const uint8_t*), int B> 82 void TestRead(bool big_endian) { 83 // Test both for values that are positive and negative (if signed) 84 for (int neg = 0; neg < 2; ++neg) { 85 bool negative = neg > 0; 86 87 // Write test value to byte buffer, in big endian format. 88 T test_value = CreateTestValue<T>(negative, B); 89 uint8_t bytes[B + kAlignments]; 90 91 // Make one test for each alignment. 92 for (int i = 0; i < kAlignments; ++i) { 93 PopulateTestData(bytes + i, test_value, B, big_endian); 94 95 // Check that test value is retrieved from buffer when used read method. 96 EXPECT_EQ(test_value, RM(bytes + i)); 97 } 98 } 99 } 100 101 // Test writing big endian numbers. 102 // Template arguments: Type T, write method WM(buffer, value), B bytes of data 103 template <typename T, void (*WM)(uint8_t*, T), int B> 104 void TestWrite(bool big_endian) { 105 // Test both for values that are positive and negative (if signed). 106 for (int neg = 0; neg < 2; ++neg) { 107 bool negative = neg > 0; 108 109 // Write test value to byte buffer, in big endian format. 110 T test_value = CreateTestValue<T>(negative, B); 111 uint8_t expected_bytes[B + kAlignments]; 112 uint8_t bytes[B + kAlignments]; 113 114 // Make one test for each alignment. 115 for (int i = 0; i < kAlignments; ++i) { 116 PopulateTestData(expected_bytes + i, test_value, B, big_endian); 117 118 // Zero initialize buffer and let WM populate it. 119 memset(bytes, 0, B + kAlignments); 120 WM(bytes + i, test_value); 121 122 // Check that data produced by WM is big endian as expected. 123 for (int j = 0; j < B; ++j) { 124 EXPECT_EQ(expected_bytes[i + j], bytes[i + j]); 125 } 126 } 127 } 128 } 129 }; 130 131 TEST_F(ByteIoTest, Test16UBitBigEndian) { 132 TestRead<uint16_t, ByteReader<uint16_t>::ReadBigEndian, sizeof(uint16_t)>( 133 true); 134 TestWrite<uint16_t, ByteWriter<uint16_t>::WriteBigEndian, sizeof(uint16_t)>( 135 true); 136 } 137 138 TEST_F(ByteIoTest, Test24UBitBigEndian) { 139 TestRead<uint32_t, ByteReader<uint32_t, 3>::ReadBigEndian, 3>(true); 140 TestWrite<uint32_t, ByteWriter<uint32_t, 3>::WriteBigEndian, 3>(true); 141 } 142 143 TEST_F(ByteIoTest, Test32UBitBigEndian) { 144 TestRead<uint32_t, ByteReader<uint32_t>::ReadBigEndian, sizeof(uint32_t)>( 145 true); 146 TestWrite<uint32_t, ByteWriter<uint32_t>::WriteBigEndian, sizeof(uint32_t)>( 147 true); 148 } 149 150 TEST_F(ByteIoTest, Test64UBitBigEndian) { 151 TestRead<uint64_t, ByteReader<uint64_t>::ReadBigEndian, sizeof(uint64_t)>( 152 true); 153 TestWrite<uint64_t, ByteWriter<uint64_t>::WriteBigEndian, sizeof(uint64_t)>( 154 true); 155 } 156 157 TEST_F(ByteIoTest, Test16SBitBigEndian) { 158 TestRead<int16_t, ByteReader<int16_t>::ReadBigEndian, sizeof(int16_t)>(true); 159 TestWrite<int16_t, ByteWriter<int16_t>::WriteBigEndian, sizeof(int16_t)>( 160 true); 161 } 162 163 TEST_F(ByteIoTest, Test24SBitBigEndian) { 164 TestRead<int32_t, ByteReader<int32_t, 3>::ReadBigEndian, 3>(true); 165 TestWrite<int32_t, ByteWriter<int32_t, 3>::WriteBigEndian, 3>(true); 166 } 167 168 TEST_F(ByteIoTest, Test32SBitBigEndian) { 169 TestRead<int32_t, ByteReader<int32_t>::ReadBigEndian, sizeof(int32_t)>(true); 170 TestWrite<int32_t, ByteWriter<int32_t>::WriteBigEndian, sizeof(int32_t)>( 171 true); 172 } 173 174 TEST_F(ByteIoTest, Test64SBitBigEndian) { 175 TestRead<int64_t, ByteReader<int64_t>::ReadBigEndian, sizeof(int64_t)>(true); 176 TestWrite<int64_t, ByteWriter<int64_t>::WriteBigEndian, sizeof(int64_t)>( 177 true); 178 } 179 180 TEST_F(ByteIoTest, Test16UBitLittleEndian) { 181 TestRead<uint16_t, ByteReader<uint16_t>::ReadLittleEndian, sizeof(uint16_t)>( 182 false); 183 TestWrite<uint16_t, ByteWriter<uint16_t>::WriteLittleEndian, 184 sizeof(uint16_t)>(false); 185 } 186 187 TEST_F(ByteIoTest, Test24UBitLittleEndian) { 188 TestRead<uint32_t, ByteReader<uint32_t, 3>::ReadLittleEndian, 3>(false); 189 TestWrite<uint32_t, ByteWriter<uint32_t, 3>::WriteLittleEndian, 3>(false); 190 } 191 192 TEST_F(ByteIoTest, Test32UBitLittleEndian) { 193 TestRead<uint32_t, ByteReader<uint32_t>::ReadLittleEndian, sizeof(uint32_t)>( 194 false); 195 TestWrite<uint32_t, ByteWriter<uint32_t>::WriteLittleEndian, 196 sizeof(uint32_t)>(false); 197 } 198 199 TEST_F(ByteIoTest, Test64UBitLittleEndian) { 200 TestRead<uint64_t, ByteReader<uint64_t>::ReadLittleEndian, sizeof(uint64_t)>( 201 false); 202 TestWrite<uint64_t, ByteWriter<uint64_t>::WriteLittleEndian, 203 sizeof(uint64_t)>(false); 204 } 205 206 TEST_F(ByteIoTest, Test16SBitLittleEndian) { 207 TestRead<int16_t, ByteReader<int16_t>::ReadLittleEndian, sizeof(int16_t)>( 208 false); 209 TestWrite<int16_t, ByteWriter<int16_t>::WriteLittleEndian, sizeof(int16_t)>( 210 false); 211 } 212 213 TEST_F(ByteIoTest, Test24SBitLittleEndian) { 214 TestRead<int32_t, ByteReader<int32_t, 3>::ReadLittleEndian, 3>(false); 215 TestWrite<int32_t, ByteWriter<int32_t, 3>::WriteLittleEndian, 3>(false); 216 } 217 218 TEST_F(ByteIoTest, Test32SBitLittleEndian) { 219 TestRead<int32_t, ByteReader<int32_t>::ReadLittleEndian, sizeof(int32_t)>( 220 false); 221 TestWrite<int32_t, ByteWriter<int32_t>::WriteLittleEndian, sizeof(int32_t)>( 222 false); 223 } 224 225 TEST_F(ByteIoTest, Test64SBitLittleEndian) { 226 TestRead<int64_t, ByteReader<int64_t>::ReadLittleEndian, sizeof(int64_t)>( 227 false); 228 TestWrite<int64_t, ByteWriter<int64_t>::WriteLittleEndian, sizeof(int64_t)>( 229 false); 230 } 231 232 // Sets up a fixed byte array and converts N bytes from the array into a 233 // uint64_t. Verifies the value with hard-coded reference. 234 TEST(ByteIo, SanityCheckFixedByteArrayUnsignedReadBigEndian) { 235 uint8_t data[8] = {0xFF, 0xEE, 0xDD, 0xCC, 0xBB, 0xAA, 0x99, 0x88}; 236 uint64_t value = ByteReader<uint64_t, 2>::ReadBigEndian(data); 237 EXPECT_EQ(static_cast<uint64_t>(0xFFEE), value); 238 value = ByteReader<uint64_t, 3>::ReadBigEndian(data); 239 EXPECT_EQ(static_cast<uint64_t>(0xFFEEDD), value); 240 value = ByteReader<uint64_t, 4>::ReadBigEndian(data); 241 EXPECT_EQ(static_cast<uint64_t>(0xFFEEDDCC), value); 242 value = ByteReader<uint64_t, 5>::ReadBigEndian(data); 243 EXPECT_EQ(static_cast<uint64_t>(0xFFEEDDCCBB), value); 244 value = ByteReader<uint64_t, 6>::ReadBigEndian(data); 245 EXPECT_EQ(static_cast<uint64_t>(0xFFEEDDCCBBAA), value); 246 value = ByteReader<uint64_t, 7>::ReadBigEndian(data); 247 EXPECT_EQ(static_cast<uint64_t>(0xFFEEDDCCBBAA99), value); 248 value = ByteReader<uint64_t, 8>::ReadBigEndian(data); 249 EXPECT_EQ(static_cast<uint64_t>(0xFFEEDDCCBBAA9988), value); 250 } 251 252 // Same as above, but for little-endian reading. 253 TEST(ByteIo, SanityCheckFixedByteArrayUnsignedReadLittleEndian) { 254 uint8_t data[8] = {0xFF, 0xEE, 0xDD, 0xCC, 0xBB, 0xAA, 0x99, 0x88}; 255 uint64_t value = ByteReader<uint64_t, 2>::ReadLittleEndian(data); 256 EXPECT_EQ(static_cast<uint64_t>(0xEEFF), value); 257 value = ByteReader<uint64_t, 3>::ReadLittleEndian(data); 258 EXPECT_EQ(static_cast<uint64_t>(0xDDEEFF), value); 259 value = ByteReader<uint64_t, 4>::ReadLittleEndian(data); 260 EXPECT_EQ(static_cast<uint64_t>(0xCCDDEEFF), value); 261 value = ByteReader<uint64_t, 5>::ReadLittleEndian(data); 262 EXPECT_EQ(static_cast<uint64_t>(0xBBCCDDEEFF), value); 263 value = ByteReader<uint64_t, 6>::ReadLittleEndian(data); 264 EXPECT_EQ(static_cast<uint64_t>(0xAABBCCDDEEFF), value); 265 value = ByteReader<uint64_t, 7>::ReadLittleEndian(data); 266 EXPECT_EQ(static_cast<uint64_t>(0x99AABBCCDDEEFF), value); 267 value = ByteReader<uint64_t, 8>::ReadLittleEndian(data); 268 EXPECT_EQ(static_cast<uint64_t>(0x8899AABBCCDDEEFF), value); 269 } 270 } // namespace 271 } // namespace webrtc