1 /*
2     RawSpeed - RAW file decoder.
3 
4     Copyright (C) 2017 Roman Lebedev
5 
6     This library is free software; you can redistribute it and/or
7     modify it under the terms of the GNU Lesser General Public
8     License as published by the Free Software Foundation; either
9     version 2 of the License, or (at your option) any later version.
10 
11     This library is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14     Lesser General Public License for more details.
15 
16     You should have received a copy of the GNU Lesser General Public
17     License along with this library; if not, write to the Free Software
18     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20 
21 #include "EndiannessTest.h"
22 #include "io/Endianness.h" // for getHostEndianness, Endianness, getByteSwa...
23 #include <cstring>         // for memcpy, memcmp
24 #include <gtest/gtest.h>   // for ParamIteratorInterface, Message, TestPart...
25 #include <iomanip>         // for setfill, setw, _Setw, _Setfill
26 #include <iostream>        // for hex, endl, ostream
27 
28 using rawspeed::Endianness;
29 using rawspeed::getBE;
30 using rawspeed::getByteSwapped;
31 using rawspeed::getHostEndianness;
32 using rawspeed::getHostEndiannessRuntime;
33 using rawspeed::getLE;
34 using rawspeed::getU16BE;
35 using rawspeed::getU16LE;
36 using rawspeed::getU32BE;
37 using rawspeed::getU32LE;
38 using std::setfill;
39 using std::setw;
40 
41 namespace rawspeed_test {
42 
TEST(EndiannessTest,getHostEndiannessTests)43 TEST(EndiannessTest, getHostEndiannessTests) {
44 #if defined(__BYTE_ORDER__)
45   ASSERT_EQ(getHostEndiannessRuntime(), getHostEndianness());
46 #endif
47 }
48 
49 /*
50 #!/bin/bash
51 d=16 # squared, how many samples
52 # B=2 # sizeof, bytes
53 b=x # print format
54 p="0x" # print prefix
55 function proc {
56   echo "$1" | od -A n --endian="$2" -t $3$B -N $B -w$B | tr -d ''
57 }
58 function pp {
59   v=$(proc "$1" "$2" "$b")
60   echo $p$v
61 }
62 for i in $(seq $d)
63 do
64   for j in $(seq $d);
65   do
66     v=$(dd if=/dev/urandom bs=$B conv=sparse count=1 status=none)
67     x=$(pp "$v" little);
68     y=$(pp "$v" big);
69     echo "{$x, $y},";
70   done;
71 done;
72 */
73 
74 #define setupHex setfill('0') << setw(2 * sizeof(T)) << std::hex
75 
76 template <typename T>
operator <<(::std::ostream & os,const intPair<T> & p)77 ::std::ostream& operator<<(::std::ostream& os, const intPair<T>& p) {
78   ::testing::Message msg;
79   msg << "(0x" << setupHex << p.first << ", 0x" << setupHex << p.second << ")";
80 
81   return os << msg;
82 }
83 
84 // no polymorphic lambda till c++14
85 struct HexEquals {
86   template <typename T>
operator ()rawspeed_test::HexEquals87   ::testing::AssertionResult operator()(const char* darg1, const char* darg2,
88                                         const T& arg1, const T& arg2) {
89     if (memcmp(&arg1, &arg2, sizeof(T)) == 0)
90       return ::testing::AssertionSuccess();
91 
92     ::testing::Message msg;
93     msg << "      Expected: " << darg1 << std::endl;
94     msg << "      Which is: " << setupHex << arg1 << std::endl;
95     msg << "To be equal to: " << darg2 << std::endl;
96     msg << "      Which is: " << setupHex << arg2;
97 
98     return ::testing::AssertionFailure() << msg;
99   }
100 };
101 
102 #undef setupHex
103 
104 template <class T1, class T2>
105 class AbstractGetByteSwappedTest : public ::testing::TestWithParam<T1> {
106 protected:
107   AbstractGetByteSwappedTest() = default;
SetUp()108   virtual void SetUp() {
109     auto p = this->GetParam();
110     auto v = std::get<0>(p);
111 
112     // swap them around? the test is symmetrical
113     if (std::get<1>(p)) {
114       memcpy(&in, &(v.first), sizeof(T2));
115       memcpy(&expected, &(v.second), sizeof(T2));
116     } else {
117       memcpy(&in, &(v.second), sizeof(T2));
118       memcpy(&expected, &(v.first), sizeof(T2));
119     }
120   }
getByteSwappedT(const void * data,bool bswap)121   T2 getByteSwappedT(const void* data, bool bswap) {
122     return getByteSwapped<T2>(data, bswap);
123   }
getBEt(const void * data)124   T2 getBEt(const void* data) { return getBE<T2>(data); }
getLEt(const void * data)125   T2 getLEt(const void* data) { return getLE<T2>(data); }
126 
127   T2 in;       // input
128   T2 expected; // expected output
129 };
130 
131 /*
132 B=2 # sizeof, bytes
133 */
134 class ushort16Test
135     : public AbstractGetByteSwappedTest<ushort16TType, uint16_t> {};
136 INSTANTIATE_TEST_CASE_P(ushort16Test, ushort16Test,
137                         ::testing::Combine(::testing::ValuesIn(ushort16Values),
138                                            ::testing::Bool()));
TEST_P(ushort16Test,swap)139 TEST_P(ushort16Test, swap) {
140   ASSERT_PRED_FORMAT2(HexEquals{}, getByteSwapped(in), expected);
141 }
TEST_P(ushort16Test,NOP)142 TEST_P(ushort16Test, NOP) {
143   ASSERT_PRED_FORMAT2(HexEquals{}, getByteSwappedT(&in, false), in);
144 }
TEST_P(ushort16Test,typedSwap)145 TEST_P(ushort16Test, typedSwap) {
146   ASSERT_PRED_FORMAT2(HexEquals{}, getByteSwappedT(&in, true), expected);
147 }
TEST_P(ushort16Test,get)148 TEST_P(ushort16Test, get) {
149   if (getHostEndianness() == Endianness::little) {
150     ASSERT_PRED_FORMAT2(HexEquals{}, getBEt(&in), expected);
151   } else if (getHostEndianness() == Endianness::big) {
152     ASSERT_PRED_FORMAT2(HexEquals{}, getLEt(&in), expected);
153   }
154 }
TEST_P(ushort16Test,getNOP)155 TEST_P(ushort16Test, getNOP) {
156   if (getHostEndianness() == Endianness::little) {
157     ASSERT_PRED_FORMAT2(HexEquals{}, getLEt(&in), in);
158   } else if (getHostEndianness() == Endianness::big) {
159     ASSERT_PRED_FORMAT2(HexEquals{}, getBEt(&in), in);
160   }
161 }
162 
TEST_P(ushort16Test,getU16)163 TEST_P(ushort16Test, getU16) {
164   if (getHostEndianness() == Endianness::little) {
165     ASSERT_PRED_FORMAT2(HexEquals{}, getU16BE(&in), expected);
166   } else if (getHostEndianness() == Endianness::big) {
167     ASSERT_PRED_FORMAT2(HexEquals{}, getU16LE(&in), expected);
168   }
169 }
TEST_P(ushort16Test,getU16NOP)170 TEST_P(ushort16Test, getU16NOP) {
171   if (getHostEndianness() == Endianness::little) {
172     ASSERT_PRED_FORMAT2(HexEquals{}, getU16LE(&in), in);
173   } else if (getHostEndianness() == Endianness::big) {
174     ASSERT_PRED_FORMAT2(HexEquals{}, getU16BE(&in), in);
175   }
176 }
177 
178 class short16Test : public AbstractGetByteSwappedTest<ushort16TType, int16_t> {
179 };
180 INSTANTIATE_TEST_CASE_P(short16Test, short16Test,
181                         ::testing::Combine(::testing::ValuesIn(ushort16Values),
182                                            ::testing::Bool()));
TEST_P(short16Test,swap)183 TEST_P(short16Test, swap) {
184   ASSERT_PRED_FORMAT2(HexEquals{}, getByteSwapped(in), expected);
185 }
TEST_P(short16Test,NOP)186 TEST_P(short16Test, NOP) {
187   ASSERT_PRED_FORMAT2(HexEquals{}, getByteSwappedT(&in, false), in);
188 }
TEST_P(short16Test,typedSwap)189 TEST_P(short16Test, typedSwap) {
190   ASSERT_PRED_FORMAT2(HexEquals{}, getByteSwappedT(&in, true), expected);
191 }
TEST_P(short16Test,get)192 TEST_P(short16Test, get) {
193   if (getHostEndianness() == Endianness::little) {
194     ASSERT_PRED_FORMAT2(HexEquals{}, getBEt(&in), expected);
195   } else if (getHostEndianness() == Endianness::big) {
196     ASSERT_PRED_FORMAT2(HexEquals{}, getLEt(&in), expected);
197   }
198 }
TEST_P(short16Test,getNOP)199 TEST_P(short16Test, getNOP) {
200   if (getHostEndianness() == Endianness::little) {
201     ASSERT_PRED_FORMAT2(HexEquals{}, getLEt(&in), in);
202   } else if (getHostEndianness() == Endianness::big) {
203     ASSERT_PRED_FORMAT2(HexEquals{}, getBEt(&in), in);
204   }
205 }
206 
207 /*
208 B=4 # sizeof, bytes
209 */
210 class uint32Test : public AbstractGetByteSwappedTest<uint32TType, uint32_t> {};
211 INSTANTIATE_TEST_CASE_P(uint32Test, uint32Test,
212                         ::testing::Combine(::testing::ValuesIn(uint32Values),
213                                            ::testing::Bool()));
TEST_P(uint32Test,swap)214 TEST_P(uint32Test, swap) {
215   ASSERT_PRED_FORMAT2(HexEquals{}, getByteSwapped(in), expected);
216 }
TEST_P(uint32Test,NOP)217 TEST_P(uint32Test, NOP) {
218   ASSERT_PRED_FORMAT2(HexEquals{}, getByteSwappedT(&in, false), in);
219 }
TEST_P(uint32Test,typedSwap)220 TEST_P(uint32Test, typedSwap) {
221   ASSERT_PRED_FORMAT2(HexEquals{}, getByteSwappedT(&in, true), expected);
222 }
TEST_P(uint32Test,get)223 TEST_P(uint32Test, get) {
224   if (getHostEndianness() == Endianness::little) {
225     ASSERT_PRED_FORMAT2(HexEquals{}, getBEt(&in), expected);
226   } else if (getHostEndianness() == Endianness::big) {
227     ASSERT_PRED_FORMAT2(HexEquals{}, getLEt(&in), expected);
228   }
229 }
TEST_P(uint32Test,getNOP)230 TEST_P(uint32Test, getNOP) {
231   if (getHostEndianness() == Endianness::little) {
232     ASSERT_PRED_FORMAT2(HexEquals{}, getLEt(&in), in);
233   } else if (getHostEndianness() == Endianness::big) {
234     ASSERT_PRED_FORMAT2(HexEquals{}, getBEt(&in), in);
235   }
236 }
237 
TEST_P(uint32Test,getU32)238 TEST_P(uint32Test, getU32) {
239   if (getHostEndianness() == Endianness::little) {
240     ASSERT_PRED_FORMAT2(HexEquals{}, getU32BE(&in), expected);
241   } else if (getHostEndianness() == Endianness::big) {
242     ASSERT_PRED_FORMAT2(HexEquals{}, getU32LE(&in), expected);
243   }
244 }
TEST_P(uint32Test,getU32NOP)245 TEST_P(uint32Test, getU32NOP) {
246   if (getHostEndianness() == Endianness::little) {
247     ASSERT_PRED_FORMAT2(HexEquals{}, getU32LE(&in), in);
248   } else if (getHostEndianness() == Endianness::big) {
249     ASSERT_PRED_FORMAT2(HexEquals{}, getU32BE(&in), in);
250   }
251 }
252 
253 class int32Test : public AbstractGetByteSwappedTest<uint32TType, int32_t> {};
254 INSTANTIATE_TEST_CASE_P(int32Test, int32Test,
255                         ::testing::Combine(::testing::ValuesIn(uint32Values),
256                                            ::testing::Bool()));
TEST_P(int32Test,swap)257 TEST_P(int32Test, swap) {
258   ASSERT_PRED_FORMAT2(HexEquals{}, getByteSwapped(in), expected);
259 }
TEST_P(int32Test,NOP)260 TEST_P(int32Test, NOP) {
261   ASSERT_PRED_FORMAT2(HexEquals{}, getByteSwappedT(&in, false), in);
262 }
TEST_P(int32Test,typedSwap)263 TEST_P(int32Test, typedSwap) {
264   ASSERT_PRED_FORMAT2(HexEquals{}, getByteSwappedT(&in, true), expected);
265 }
TEST_P(int32Test,get)266 TEST_P(int32Test, get) {
267   if (getHostEndianness() == Endianness::little) {
268     ASSERT_PRED_FORMAT2(HexEquals{}, getBEt(&in), expected);
269   } else if (getHostEndianness() == Endianness::big) {
270     ASSERT_PRED_FORMAT2(HexEquals{}, getLEt(&in), expected);
271   }
272 }
TEST_P(int32Test,getNOP)273 TEST_P(int32Test, getNOP) {
274   if (getHostEndianness() == Endianness::little) {
275     ASSERT_PRED_FORMAT2(HexEquals{}, getLEt(&in), in);
276   } else if (getHostEndianness() == Endianness::big) {
277     ASSERT_PRED_FORMAT2(HexEquals{}, getBEt(&in), in);
278   }
279 }
280 
281 /*
282 B=8 # sizeof, bytes
283 */
284 class uint64Test : public AbstractGetByteSwappedTest<uint64TType, uint64_t> {};
285 INSTANTIATE_TEST_CASE_P(uint64Test, uint64Test,
286                         ::testing::Combine(::testing::ValuesIn(uint64Values),
287                                            ::testing::Bool()));
TEST_P(uint64Test,swap)288 TEST_P(uint64Test, swap) {
289   ASSERT_PRED_FORMAT2(HexEquals{}, getByteSwapped(in), expected);
290 }
TEST_P(uint64Test,NOP)291 TEST_P(uint64Test, NOP) {
292   ASSERT_PRED_FORMAT2(HexEquals{}, getByteSwappedT(&in, false), in);
293 }
TEST_P(uint64Test,typedSwap)294 TEST_P(uint64Test, typedSwap) {
295   ASSERT_PRED_FORMAT2(HexEquals{}, getByteSwappedT(&in, true), expected);
296 }
TEST_P(uint64Test,get)297 TEST_P(uint64Test, get) {
298   if (getHostEndianness() == Endianness::little) {
299     ASSERT_PRED_FORMAT2(HexEquals{}, getBEt(&in), expected);
300   } else if (getHostEndianness() == Endianness::big) {
301     ASSERT_PRED_FORMAT2(HexEquals{}, getLEt(&in), expected);
302   }
303 }
TEST_P(uint64Test,getNOP)304 TEST_P(uint64Test, getNOP) {
305   if (getHostEndianness() == Endianness::little) {
306     ASSERT_PRED_FORMAT2(HexEquals{}, getLEt(&in), in);
307   } else if (getHostEndianness() == Endianness::big) {
308     ASSERT_PRED_FORMAT2(HexEquals{}, getBEt(&in), in);
309   }
310 }
311 
312 class floatTest : public AbstractGetByteSwappedTest<uint32TType, float> {};
313 INSTANTIATE_TEST_CASE_P(floatTest, floatTest,
314                         ::testing::Combine(::testing::ValuesIn(uint32Values),
315                                            ::testing::Bool()));
TEST_P(floatTest,swap)316 TEST_P(floatTest, swap) {
317   ASSERT_PRED_FORMAT2(HexEquals{}, getByteSwapped(in), expected);
318 }
TEST_P(floatTest,NOP)319 TEST_P(floatTest, NOP) {
320   ASSERT_PRED_FORMAT2(HexEquals{}, getByteSwappedT(&in, false), in);
321 }
TEST_P(floatTest,typedSwap)322 TEST_P(floatTest, typedSwap) {
323   ASSERT_PRED_FORMAT2(HexEquals{}, getByteSwappedT(&in, true), expected);
324 }
TEST_P(floatTest,get)325 TEST_P(floatTest, get) {
326   if (getHostEndianness() == Endianness::little) {
327     ASSERT_PRED_FORMAT2(HexEquals{}, getBEt(&in), expected);
328   } else if (getHostEndianness() == Endianness::big) {
329     ASSERT_PRED_FORMAT2(HexEquals{}, getLEt(&in), expected);
330   }
331 }
TEST_P(floatTest,getNOP)332 TEST_P(floatTest, getNOP) {
333   if (getHostEndianness() == Endianness::little) {
334     ASSERT_PRED_FORMAT2(HexEquals{}, getLEt(&in), in);
335   } else if (getHostEndianness() == Endianness::big) {
336     ASSERT_PRED_FORMAT2(HexEquals{}, getBEt(&in), in);
337   }
338 }
339 
340 class doubleTest : public AbstractGetByteSwappedTest<uint64TType, double> {};
341 INSTANTIATE_TEST_CASE_P(doubleTest, doubleTest,
342                         ::testing::Combine(::testing::ValuesIn(uint64Values),
343                                            ::testing::Bool()));
TEST_P(doubleTest,swap)344 TEST_P(doubleTest, swap) {
345   ASSERT_PRED_FORMAT2(HexEquals{}, getByteSwapped(in), expected);
346 }
TEST_P(doubleTest,NOP)347 TEST_P(doubleTest, NOP) {
348   ASSERT_PRED_FORMAT2(HexEquals{}, getByteSwappedT(&in, false), in);
349 }
TEST_P(doubleTest,typedSwap)350 TEST_P(doubleTest, typedSwap) {
351   ASSERT_PRED_FORMAT2(HexEquals{}, getByteSwappedT(&in, true), expected);
352 }
TEST_P(doubleTest,get)353 TEST_P(doubleTest, get) {
354   if (getHostEndianness() == Endianness::little) {
355     ASSERT_PRED_FORMAT2(HexEquals{}, getBEt(&in), expected);
356   } else if (getHostEndianness() == Endianness::big) {
357     ASSERT_PRED_FORMAT2(HexEquals{}, getLEt(&in), expected);
358   }
359 }
TEST_P(doubleTest,getNOP)360 TEST_P(doubleTest, getNOP) {
361   if (getHostEndianness() == Endianness::little) {
362     ASSERT_PRED_FORMAT2(HexEquals{}, getLEt(&in), in);
363   } else if (getHostEndianness() == Endianness::big) {
364     ASSERT_PRED_FORMAT2(HexEquals{}, getBEt(&in), in);
365   }
366 }
367 
368 } // namespace rawspeed_test
369