mirror of
https://gitee.com/mirrors_PX4/PX4-Autopilot.git
synced 2026-10-20 05:53:34 +08:00
Reorganized directory structure for tests and src
This commit is contained in:
@@ -1,756 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Pavel Kirienko <pavel.kirienko@gmail.com>
|
||||
*/
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <uavcan/internal/marshal/types.hpp>
|
||||
|
||||
using uavcan::Array;
|
||||
using uavcan::ArrayModeDynamic;
|
||||
using uavcan::ArrayModeStatic;
|
||||
using uavcan::IntegerSpec;
|
||||
using uavcan::FloatSpec;
|
||||
using uavcan::SignednessSigned;
|
||||
using uavcan::SignednessUnsigned;
|
||||
using uavcan::CastModeSaturate;
|
||||
using uavcan::CastModeTruncate;
|
||||
|
||||
struct CustomType
|
||||
{
|
||||
typedef uavcan::IntegerSpec<8, uavcan::SignednessSigned, uavcan::CastModeTruncate> A;
|
||||
typedef uavcan::FloatSpec<16, uavcan::CastModeSaturate> B;
|
||||
// Dynamic array of max len 5 --> 3 bits for len, 5 bits for data --> 1 byte max len
|
||||
typedef uavcan::Array<uavcan::IntegerSpec<1, uavcan::SignednessUnsigned, uavcan::CastModeSaturate>,
|
||||
uavcan::ArrayModeDynamic, 5> C;
|
||||
|
||||
enum { MinBitLen = A::MinBitLen + B::MinBitLen + C::MinBitLen };
|
||||
enum { MaxBitLen = A::MaxBitLen + B::MaxBitLen + C::MaxBitLen };
|
||||
|
||||
typename uavcan::StorageType<A>::Type a;
|
||||
typename uavcan::StorageType<B>::Type b;
|
||||
typename uavcan::StorageType<C>::Type c;
|
||||
|
||||
CustomType() : a(), b(), c() { }
|
||||
|
||||
bool operator==(const CustomType& rhs) const { return a == rhs.a && b == rhs.b && c == rhs.c; }
|
||||
|
||||
static int encode(const CustomType& obj, uavcan::ScalarCodec& codec,
|
||||
uavcan::TailArrayOptimizationMode tao_mode = uavcan::TailArrayOptEnabled)
|
||||
{
|
||||
int res = 0;
|
||||
|
||||
res = A::encode(obj.a, codec, uavcan::TailArrayOptDisabled);
|
||||
if (res <= 0)
|
||||
return res;
|
||||
|
||||
res = B::encode(obj.b, codec, uavcan::TailArrayOptDisabled);
|
||||
if (res <= 0)
|
||||
return res;
|
||||
|
||||
res = C::encode(obj.c, codec, tao_mode);
|
||||
if (res <= 0)
|
||||
return res;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int decode(CustomType& obj, uavcan::ScalarCodec& codec,
|
||||
uavcan::TailArrayOptimizationMode tao_mode = uavcan::TailArrayOptEnabled)
|
||||
{
|
||||
int res = 0;
|
||||
|
||||
res = A::decode(obj.a, codec, uavcan::TailArrayOptDisabled);
|
||||
if (res <= 0)
|
||||
return res;
|
||||
|
||||
res = B::decode(obj.b, codec, uavcan::TailArrayOptDisabled);
|
||||
if (res <= 0)
|
||||
return res;
|
||||
|
||||
res = C::decode(obj.c, codec, tao_mode);
|
||||
if (res <= 0)
|
||||
return res;
|
||||
|
||||
return 1;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
TEST(Array, Basic)
|
||||
{
|
||||
typedef Array<IntegerSpec<8, SignednessSigned, CastModeTruncate>, ArrayModeStatic, 4> A1;
|
||||
typedef Array<FloatSpec<16, CastModeSaturate>, ArrayModeStatic, 2> A2;
|
||||
typedef Array<CustomType, ArrayModeStatic, 2> A3;
|
||||
|
||||
A1 a1;
|
||||
A2 a2;
|
||||
A3 a3;
|
||||
|
||||
ASSERT_EQ(1, A3::ValueType::C::RawValueType::BitLen);
|
||||
|
||||
ASSERT_EQ(8 * 4, A1::MaxBitLen);
|
||||
ASSERT_EQ(16 * 2, A2::MaxBitLen);
|
||||
ASSERT_EQ((8 + 16 + 5 + 3) * 2, A3::MaxBitLen);
|
||||
|
||||
/*
|
||||
* Zero initialization check
|
||||
*/
|
||||
ASSERT_FALSE(a1.empty());
|
||||
for (A1::const_iterator it = a1.begin(); it != a1.end(); ++it)
|
||||
ASSERT_EQ(0, *it);
|
||||
|
||||
ASSERT_FALSE(a2.empty());
|
||||
for (A2::const_iterator it = a2.begin(); it != a2.end(); ++it)
|
||||
ASSERT_EQ(0, *it);
|
||||
|
||||
for (A3::const_iterator it = a3.begin(); it != a3.end(); ++it)
|
||||
{
|
||||
ASSERT_EQ(0, it->a);
|
||||
ASSERT_EQ(0, it->b);
|
||||
ASSERT_EQ(0, it->c.size());
|
||||
ASSERT_TRUE(it->c.empty());
|
||||
}
|
||||
|
||||
/*
|
||||
* Modification with known values; array lengths are hard coded.
|
||||
*/
|
||||
for (int i = 0; i < 4; i++)
|
||||
a1.at(i) = i;
|
||||
|
||||
for (int i = 0; i < 2; i++)
|
||||
a2.at(i) = i;
|
||||
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
a3[i].a = i;
|
||||
a3[i].b = i;
|
||||
for (int i2 = 0; i2 < 5; i2++)
|
||||
a3[i].c.push_back(i2 & 1);
|
||||
ASSERT_EQ(5, a3[i].c.size());
|
||||
ASSERT_FALSE(a3[i].c.empty());
|
||||
}
|
||||
|
||||
/*
|
||||
* Representation check
|
||||
* Note that TAO in A3 is not possible because A3::C has less than one byte per item
|
||||
*/
|
||||
uavcan::StaticTransferBuffer<16> buf;
|
||||
uavcan::BitStream bs_wr(buf);
|
||||
uavcan::ScalarCodec sc_wr(bs_wr);
|
||||
|
||||
ASSERT_EQ(1, A1::encode(a1, sc_wr, uavcan::TailArrayOptDisabled));
|
||||
ASSERT_EQ(1, A2::encode(a2, sc_wr, uavcan::TailArrayOptDisabled));
|
||||
ASSERT_EQ(1, A3::encode(a3, sc_wr, uavcan::TailArrayOptEnabled));
|
||||
|
||||
ASSERT_EQ(0, A3::encode(a3, sc_wr, uavcan::TailArrayOptEnabled)); // Out of buffer space
|
||||
|
||||
static const std::string Reference =
|
||||
"00000000 00000001 00000010 00000011 " // A1 (0, 1, 2, 3)
|
||||
"00000000 00000000 00000000 00111100 " // A2 (0, 1)
|
||||
"00000000 00000000 00000000 10101010 " // A3[0] (0, 0, bool[5])
|
||||
"00000001 00000000 00111100 10101010"; // A3[1] (1, 1, bool[5])
|
||||
|
||||
ASSERT_EQ(Reference, bs_wr.toString());
|
||||
|
||||
/*
|
||||
* Read back
|
||||
*/
|
||||
uavcan::BitStream bs_rd(buf);
|
||||
uavcan::ScalarCodec sc_rd(bs_rd);
|
||||
|
||||
A1 a1_;
|
||||
A2 a2_;
|
||||
A3 a3_;
|
||||
|
||||
ASSERT_EQ(1, A1::decode(a1_, sc_rd, uavcan::TailArrayOptDisabled));
|
||||
ASSERT_EQ(1, A2::decode(a2_, sc_rd, uavcan::TailArrayOptDisabled));
|
||||
ASSERT_EQ(1, A3::decode(a3_, sc_rd, uavcan::TailArrayOptEnabled));
|
||||
|
||||
ASSERT_EQ(a1_, a1);
|
||||
ASSERT_EQ(a2_, a2);
|
||||
ASSERT_EQ(a3_, a3);
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
ASSERT_EQ(a1[i], a1_[i]);
|
||||
|
||||
for (int i = 0; i < 2; i++)
|
||||
ASSERT_EQ(a2[i], a2_[i]);
|
||||
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
ASSERT_EQ(a3[i].a, a3_[i].a);
|
||||
ASSERT_EQ(a3[i].b, a3_[i].b);
|
||||
ASSERT_EQ(a3[i].c, a3_[i].c);
|
||||
}
|
||||
|
||||
ASSERT_EQ(0, A3::decode(a3_, sc_rd, uavcan::TailArrayOptEnabled)); // Out of buffer space
|
||||
|
||||
/*
|
||||
* STL compatibility
|
||||
*/
|
||||
std::vector<int> v1;
|
||||
v1.push_back(0);
|
||||
v1.push_back(1);
|
||||
v1.push_back(2);
|
||||
v1.push_back(3);
|
||||
|
||||
ASSERT_TRUE(a1 == v1);
|
||||
ASSERT_FALSE(a1 != v1);
|
||||
ASSERT_TRUE(v1 == a1);
|
||||
ASSERT_FALSE(v1 != a1);
|
||||
ASSERT_FALSE(a1 < v1);
|
||||
|
||||
v1[0] = 9000;
|
||||
ASSERT_FALSE(a1 == v1);
|
||||
ASSERT_TRUE(a1 != v1);
|
||||
ASSERT_TRUE(a1 < v1);
|
||||
|
||||
ASSERT_EQ(0, a1.front());
|
||||
ASSERT_EQ(3, a1.back());
|
||||
|
||||
// Boolean vector
|
||||
std::vector<bool> v2;
|
||||
v2.push_back(false);
|
||||
v2.push_back(true);
|
||||
v2.push_back(false);
|
||||
v2.push_back(true);
|
||||
v2.push_back(false);
|
||||
|
||||
ASSERT_TRUE(a3[0].c == v2);
|
||||
ASSERT_FALSE(a3[0].c == v1);
|
||||
ASSERT_FALSE(a3[0].c != v2);
|
||||
ASSERT_TRUE(a3[0].c != v1);
|
||||
|
||||
v2[0] = true;
|
||||
ASSERT_TRUE(a3[0].c != v2);
|
||||
ASSERT_FALSE(a3[0].c == v2);
|
||||
}
|
||||
|
||||
|
||||
TEST(Array, Dynamic)
|
||||
{
|
||||
typedef Array<IntegerSpec<1, SignednessUnsigned, CastModeSaturate>, ArrayModeDynamic, 5> A;
|
||||
typedef Array<IntegerSpec<8, SignednessSigned, CastModeSaturate>, ArrayModeDynamic, 255> B;
|
||||
|
||||
A a;
|
||||
B b;
|
||||
B b2;
|
||||
|
||||
ASSERT_EQ(3 + 5, A::MaxBitLen);
|
||||
ASSERT_EQ(8 + 255 * 8, B::MaxBitLen);
|
||||
|
||||
ASSERT_TRUE(a.empty());
|
||||
ASSERT_TRUE(b.empty());
|
||||
ASSERT_TRUE(b2.empty());
|
||||
|
||||
{
|
||||
uavcan::StaticTransferBuffer<16> buf;
|
||||
uavcan::BitStream bs_wr(buf);
|
||||
uavcan::ScalarCodec sc_wr(bs_wr);
|
||||
|
||||
ASSERT_EQ(1, A::encode(a, sc_wr, uavcan::TailArrayOptDisabled));
|
||||
ASSERT_EQ(1, B::encode(b, sc_wr, uavcan::TailArrayOptDisabled));
|
||||
ASSERT_EQ(1, B::encode(b2, sc_wr, uavcan::TailArrayOptEnabled));
|
||||
|
||||
ASSERT_EQ("000" "00000 000" "00000", bs_wr.toString()); // Last array was optimized away completely
|
||||
|
||||
uavcan::BitStream bs_rd(buf);
|
||||
uavcan::ScalarCodec sc_rd(bs_rd);
|
||||
|
||||
ASSERT_EQ(1, A::decode(a, sc_rd, uavcan::TailArrayOptDisabled));
|
||||
ASSERT_EQ(1, B::decode(b, sc_rd, uavcan::TailArrayOptDisabled));
|
||||
ASSERT_EQ(1, B::decode(b2, sc_rd, uavcan::TailArrayOptEnabled));
|
||||
|
||||
ASSERT_TRUE(a.empty());
|
||||
ASSERT_TRUE(b.empty());
|
||||
ASSERT_TRUE(b2.empty());
|
||||
}
|
||||
|
||||
a.push_back(true);
|
||||
a.push_back(false);
|
||||
a.push_back(true);
|
||||
a.push_back(false);
|
||||
a.push_back(true);
|
||||
|
||||
b.push_back(42);
|
||||
b.push_back(-42);
|
||||
|
||||
b2.push_back(123);
|
||||
b2.push_back(72);
|
||||
|
||||
{
|
||||
uavcan::StaticTransferBuffer<16> buf;
|
||||
uavcan::BitStream bs_wr(buf);
|
||||
uavcan::ScalarCodec sc_wr(bs_wr);
|
||||
|
||||
ASSERT_EQ(1, A::encode(a, sc_wr, uavcan::TailArrayOptDisabled));
|
||||
ASSERT_EQ(1, B::encode(b, sc_wr, uavcan::TailArrayOptDisabled));
|
||||
ASSERT_EQ(1, B::encode(b2, sc_wr, uavcan::TailArrayOptEnabled)); // No length field
|
||||
|
||||
// A B len B[0] B[1] B2[0] B2[1]
|
||||
ASSERT_EQ("10110101 00000010 00101010 11010110 01111011 01001000", bs_wr.toString());
|
||||
|
||||
uavcan::BitStream bs_rd(buf);
|
||||
uavcan::ScalarCodec sc_rd(bs_rd);
|
||||
|
||||
a.clear();
|
||||
b.clear();
|
||||
b2.clear();
|
||||
ASSERT_TRUE(a.empty());
|
||||
ASSERT_TRUE(b.empty());
|
||||
ASSERT_TRUE(b2.empty());
|
||||
|
||||
ASSERT_EQ(1, A::decode(a, sc_rd, uavcan::TailArrayOptDisabled));
|
||||
ASSERT_EQ(1, B::decode(b, sc_rd, uavcan::TailArrayOptDisabled));
|
||||
ASSERT_EQ(1, B::decode(b2, sc_rd, uavcan::TailArrayOptEnabled));
|
||||
|
||||
ASSERT_EQ(5, a.size());
|
||||
ASSERT_EQ(2, b.size());
|
||||
ASSERT_EQ(2, b2.size());
|
||||
|
||||
ASSERT_TRUE(a[0]);
|
||||
ASSERT_FALSE(a[1]);
|
||||
ASSERT_TRUE(a[2]);
|
||||
ASSERT_FALSE(a[3]);
|
||||
ASSERT_TRUE(a[4]);
|
||||
|
||||
ASSERT_EQ(42, b[0]);
|
||||
ASSERT_EQ(-42, b[1]);
|
||||
|
||||
ASSERT_EQ(123, b2[0]);
|
||||
ASSERT_EQ(72, b2[1]);
|
||||
}
|
||||
|
||||
ASSERT_FALSE(a == b);
|
||||
ASSERT_FALSE(b == a);
|
||||
ASSERT_TRUE(a != b);
|
||||
ASSERT_TRUE(b != a);
|
||||
|
||||
a.resize(0);
|
||||
b.resize(0);
|
||||
ASSERT_TRUE(a.empty());
|
||||
ASSERT_TRUE(b.empty());
|
||||
|
||||
a.resize(5, true);
|
||||
b.resize(255, 72);
|
||||
ASSERT_EQ(5, a.size());
|
||||
ASSERT_EQ(255, b.size());
|
||||
|
||||
for (int i = 0; i < 5; i++)
|
||||
ASSERT_TRUE(a[i]);
|
||||
|
||||
for (int i = 0; i < 255; i++)
|
||||
ASSERT_EQ(72, b[i]);
|
||||
}
|
||||
|
||||
|
||||
template <typename B>
|
||||
struct CustomType2
|
||||
{
|
||||
typedef uavcan::FloatSpec<16, uavcan::CastModeSaturate> A;
|
||||
|
||||
enum { MinBitLen = A::MinBitLen + B::MinBitLen };
|
||||
enum { MaxBitLen = A::MaxBitLen + B::MaxBitLen };
|
||||
|
||||
typename uavcan::StorageType<A>::Type a;
|
||||
typename uavcan::StorageType<B>::Type b;
|
||||
|
||||
CustomType2() : a(), b() { }
|
||||
|
||||
bool operator==(const CustomType2& rhs) const { return a == rhs.a && b == rhs.b; }
|
||||
|
||||
static int encode(const CustomType2& obj, uavcan::ScalarCodec& codec,
|
||||
uavcan::TailArrayOptimizationMode tao_mode = uavcan::TailArrayOptEnabled)
|
||||
{
|
||||
int res = 0;
|
||||
res = A::encode(obj.a, codec, uavcan::TailArrayOptDisabled);
|
||||
if (res <= 0)
|
||||
return res;
|
||||
res = B::encode(obj.b, codec, tao_mode);
|
||||
if (res <= 0)
|
||||
return res;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int decode(CustomType2& obj, uavcan::ScalarCodec& codec,
|
||||
uavcan::TailArrayOptimizationMode tao_mode = uavcan::TailArrayOptEnabled)
|
||||
{
|
||||
int res = 0;
|
||||
res = A::decode(obj.a, codec, uavcan::TailArrayOptDisabled);
|
||||
if (res <= 0)
|
||||
return res;
|
||||
res = B::decode(obj.b, codec, tao_mode);
|
||||
if (res <= 0)
|
||||
return res;
|
||||
return 1;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template <typename T>
|
||||
static std::string runEncodeDecode(const typename uavcan::StorageType<T>::Type& value,
|
||||
const uavcan::TailArrayOptimizationMode tao_mode)
|
||||
{
|
||||
uavcan::StaticTransferBuffer<(T::MaxBitLen + 7) / 8> buf;
|
||||
uavcan::BitStream bs_wr(buf);
|
||||
uavcan::ScalarCodec sc_wr(bs_wr);
|
||||
EXPECT_EQ(1, T::encode(value, sc_wr, tao_mode));
|
||||
|
||||
typename uavcan::StorageType<T>::Type value2 = typename uavcan::StorageType<T>::Type();
|
||||
// Decode multiple times to make sure that the decoded type is being correctly de-initialized
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
uavcan::BitStream bs_rd(buf);
|
||||
uavcan::ScalarCodec sc_rd(bs_rd);
|
||||
EXPECT_EQ(1, T::decode(value2, sc_rd, tao_mode));
|
||||
EXPECT_EQ(value, value2);
|
||||
}
|
||||
return bs_wr.toString();
|
||||
}
|
||||
|
||||
|
||||
TEST(Array, TailArrayOptimization)
|
||||
{
|
||||
typedef Array<IntegerSpec<1, SignednessUnsigned, CastModeSaturate>, ArrayModeDynamic, 5> OneBitArray;
|
||||
typedef Array<IntegerSpec<8, SignednessUnsigned, CastModeSaturate>, ArrayModeDynamic, 255> EightBitArray;
|
||||
typedef CustomType2<Array<OneBitArray, ArrayModeDynamic, 255> > A;
|
||||
typedef CustomType2<Array<EightBitArray, ArrayModeDynamic, 255> > B;
|
||||
typedef CustomType2<EightBitArray> C;
|
||||
|
||||
A a;
|
||||
B b;
|
||||
C c;
|
||||
|
||||
/*
|
||||
* Empty
|
||||
*/
|
||||
// a LSB a MSB b len
|
||||
ASSERT_EQ("00000000 00000000 00000000", runEncodeDecode<A>(a, uavcan::TailArrayOptEnabled));
|
||||
ASSERT_EQ("00000000 00000000 00000000", runEncodeDecode<A>(a, uavcan::TailArrayOptDisabled));
|
||||
|
||||
// a LSB a MSB b len
|
||||
ASSERT_EQ("00000000 00000000 00000000", runEncodeDecode<B>(b, uavcan::TailArrayOptEnabled));
|
||||
ASSERT_EQ("00000000 00000000 00000000", runEncodeDecode<B>(b, uavcan::TailArrayOptDisabled));
|
||||
|
||||
// a LSB a MSB
|
||||
ASSERT_EQ("00000000 00000000", runEncodeDecode<C>(c, uavcan::TailArrayOptEnabled));
|
||||
ASSERT_EQ("00000000 00000000 00000000", runEncodeDecode<C>(c, uavcan::TailArrayOptDisabled));
|
||||
|
||||
/*
|
||||
* A
|
||||
*/
|
||||
a.b.resize(2);
|
||||
a.b[0].push_back(true);
|
||||
a.b[0].push_back(false);
|
||||
// a.b[1] remains empty
|
||||
// a LSB a MSB b len b: len(2), 1, 0, len(0)
|
||||
ASSERT_EQ("00000000 00000000 00000010 01010000", runEncodeDecode<A>(a, uavcan::TailArrayOptEnabled));
|
||||
ASSERT_EQ("00000000 00000000 00000010 01010000", runEncodeDecode<A>(a, uavcan::TailArrayOptDisabled));
|
||||
|
||||
/*
|
||||
* B
|
||||
*/
|
||||
b.b.resize(3);
|
||||
b.b[0].push_back(42);
|
||||
b.b[0].push_back(72);
|
||||
// b.b[1] remains empty
|
||||
b.b[2].push_back(123);
|
||||
b.b[2].push_back(99);
|
||||
// a LSB a MSB b len b[0]len 42 72 b[1]len 123 99 (b[2] len optimized out)
|
||||
ASSERT_EQ("00000000 00000000 00000011 00000010 00101010 01001000 00000000 01111011 01100011",
|
||||
runEncodeDecode<B>(b, uavcan::TailArrayOptEnabled));
|
||||
// Same as above, but b[2] len is present v here v
|
||||
ASSERT_EQ("00000000 00000000 00000011 00000010 00101010 01001000 00000000 00000010 01111011 01100011",
|
||||
runEncodeDecode<B>(b, uavcan::TailArrayOptDisabled));
|
||||
|
||||
/*
|
||||
* C
|
||||
*/
|
||||
c.a = 1;
|
||||
c.b.push_back(1);
|
||||
c.b.push_back(2);
|
||||
c.b.push_back(3);
|
||||
// a LSB a MSB 1 2 3
|
||||
ASSERT_EQ("00000000 00111100 00000001 00000010 00000011",
|
||||
runEncodeDecode<C>(c, uavcan::TailArrayOptEnabled));
|
||||
// a LSB a MSB b len 1 2 3
|
||||
ASSERT_EQ("00000000 00111100 00000011 00000001 00000010 00000011",
|
||||
runEncodeDecode<C>(c, uavcan::TailArrayOptDisabled));
|
||||
}
|
||||
|
||||
|
||||
TEST(Array, TailArrayOptimizationErrors)
|
||||
{
|
||||
typedef Array<IntegerSpec<8, SignednessUnsigned, CastModeSaturate>, ArrayModeDynamic, 5> A;
|
||||
|
||||
A a;
|
||||
ASSERT_TRUE(a.empty());
|
||||
ASSERT_EQ("", runEncodeDecode<A>(a, uavcan::TailArrayOptEnabled));
|
||||
ASSERT_EQ("00000000", runEncodeDecode<A>(a, uavcan::TailArrayOptDisabled));
|
||||
|
||||
// Correct decode/encode
|
||||
a.push_back(1);
|
||||
a.push_back(126);
|
||||
a.push_back(5);
|
||||
ASSERT_FALSE(a.empty());
|
||||
ASSERT_EQ("00000001 01111110 00000101", runEncodeDecode<A>(a, uavcan::TailArrayOptEnabled));
|
||||
ASSERT_EQ("01100000 00101111 11000000 10100000", runEncodeDecode<A>(a, uavcan::TailArrayOptDisabled));
|
||||
|
||||
// Invalid decode - length field is out of range
|
||||
uavcan::StaticTransferBuffer<7> buf;
|
||||
uavcan::BitStream bs_wr(buf);
|
||||
uavcan::ScalarCodec sc_wr(bs_wr);
|
||||
|
||||
ASSERT_EQ(1, sc_wr.encode<3>(uint8_t(6))); // Length - more than 5 items, error
|
||||
ASSERT_EQ(1, sc_wr.encode<8>(uint8_t(42)));
|
||||
ASSERT_EQ(1, sc_wr.encode<8>(uint8_t(72)));
|
||||
ASSERT_EQ(1, sc_wr.encode<8>(uint8_t(126)));
|
||||
ASSERT_EQ(1, sc_wr.encode<8>(uint8_t(1)));
|
||||
ASSERT_EQ(1, sc_wr.encode<8>(uint8_t(2)));
|
||||
ASSERT_EQ(1, sc_wr.encode<8>(uint8_t(3))); // Out of range - only 5 items allowed
|
||||
|
||||
// 197 73 15 192 32 ...
|
||||
ASSERT_EQ("11000101 01001001 00001111 11000000 00100000 01000000 01100000", bs_wr.toString());
|
||||
|
||||
{
|
||||
uavcan::BitStream bs_rd(buf);
|
||||
uavcan::ScalarCodec sc_rd(bs_rd);
|
||||
A a2;
|
||||
a2.push_back(56); // Garbage
|
||||
ASSERT_EQ(1, a2.size());
|
||||
// Will fail - declared length is more than 5 items
|
||||
ASSERT_EQ(-1, A::decode(a2, sc_rd, uavcan::TailArrayOptDisabled));
|
||||
// Must be cleared
|
||||
ASSERT_TRUE(a2.empty());
|
||||
}
|
||||
{
|
||||
uavcan::BitStream bs_rd(buf);
|
||||
uavcan::ScalarCodec sc_rd(bs_rd);
|
||||
A a2;
|
||||
a2.push_back(56); // Garbage
|
||||
ASSERT_EQ(1, a2.size());
|
||||
// Will fail - no length field, but the stream is too long
|
||||
ASSERT_EQ(-1, A::decode(a2, sc_rd, uavcan::TailArrayOptEnabled));
|
||||
// Will contain some garbage
|
||||
ASSERT_EQ(5, a2.size());
|
||||
// Interpreted stream - see the values above
|
||||
ASSERT_EQ(197, a2[0]);
|
||||
ASSERT_EQ(73, a2[1]);
|
||||
ASSERT_EQ(15, a2[2]);
|
||||
ASSERT_EQ(192, a2[3]);
|
||||
ASSERT_EQ(32, a2[4]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(Array, DynamicEncodeDecodeErrors)
|
||||
{
|
||||
typedef CustomType2<Array<Array<IntegerSpec<8, SignednessUnsigned, CastModeSaturate>,
|
||||
ArrayModeDynamic, 255>,
|
||||
ArrayModeDynamic, 255> > A;
|
||||
A a;
|
||||
a.b.resize(2);
|
||||
a.b[0].push_back(55);
|
||||
a.b[0].push_back(66);
|
||||
{
|
||||
uavcan::StaticTransferBuffer<4> buf;
|
||||
uavcan::BitStream bs_wr(buf);
|
||||
uavcan::ScalarCodec sc_wr(bs_wr);
|
||||
ASSERT_EQ(0, A::encode(a, sc_wr, uavcan::TailArrayOptEnabled)); // Not enough buffer space
|
||||
|
||||
uavcan::BitStream bs_rd(buf);
|
||||
uavcan::ScalarCodec sc_rd(bs_rd);
|
||||
ASSERT_EQ(0, A::decode(a, sc_rd, uavcan::TailArrayOptEnabled));
|
||||
}
|
||||
{
|
||||
uavcan::StaticTransferBuffer<4> buf;
|
||||
uavcan::BitStream bs_wr(buf);
|
||||
uavcan::ScalarCodec sc_wr(bs_wr);
|
||||
ASSERT_EQ(0, A::encode(a, sc_wr, uavcan::TailArrayOptDisabled)); // Not enough buffer space
|
||||
|
||||
uavcan::BitStream bs_rd(buf);
|
||||
uavcan::ScalarCodec sc_rd(bs_rd);
|
||||
ASSERT_EQ(0, A::decode(a, sc_rd, uavcan::TailArrayOptDisabled));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(Array, StaticEncodeDecodeErrors)
|
||||
{
|
||||
typedef CustomType2<Array<Array<IntegerSpec<8, SignednessUnsigned, CastModeSaturate>,
|
||||
ArrayModeStatic, 2>,
|
||||
ArrayModeStatic, 2> > A;
|
||||
A a;
|
||||
a.a = 1.0;
|
||||
a.b[0][0] = 0x11;
|
||||
a.b[0][1] = 0x22;
|
||||
a.b[1][0] = 0x33;
|
||||
a.b[1][1] = 0x44;
|
||||
{ // Just enough buffer space - 6 bytes
|
||||
uavcan::StaticTransferBuffer<6> buf;
|
||||
uavcan::BitStream bs_wr(buf);
|
||||
uavcan::ScalarCodec sc_wr(bs_wr);
|
||||
ASSERT_EQ(1, A::encode(a, sc_wr, uavcan::TailArrayOptDisabled));
|
||||
|
||||
ASSERT_EQ("00000000 00111100 00010001 00100010 00110011 01000100", bs_wr.toString());
|
||||
|
||||
uavcan::BitStream bs_rd(buf);
|
||||
uavcan::ScalarCodec sc_rd(bs_rd);
|
||||
ASSERT_EQ(1, A::decode(a, sc_rd, uavcan::TailArrayOptEnabled));
|
||||
}
|
||||
{ // Not enough space
|
||||
uavcan::StaticTransferBuffer<5> buf;
|
||||
uavcan::BitStream bs_wr(buf);
|
||||
uavcan::ScalarCodec sc_wr(bs_wr);
|
||||
ASSERT_EQ(0, A::encode(a, sc_wr, uavcan::TailArrayOptDisabled));
|
||||
|
||||
ASSERT_EQ("00000000 00111100 00010001 00100010 00110011", bs_wr.toString());
|
||||
|
||||
uavcan::BitStream bs_rd(buf);
|
||||
uavcan::ScalarCodec sc_rd(bs_rd);
|
||||
ASSERT_EQ(0, A::decode(a, sc_rd, uavcan::TailArrayOptEnabled));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(Array, Copyability)
|
||||
{
|
||||
typedef Array<IntegerSpec<1, SignednessUnsigned, CastModeSaturate>, ArrayModeDynamic, 5> OneBitArray;
|
||||
typedef Array<IntegerSpec<8, SignednessUnsigned, CastModeSaturate>, ArrayModeDynamic, 255> EightBitArray;
|
||||
typedef Array<OneBitArray, ArrayModeDynamic, 255> A;
|
||||
typedef Array<EightBitArray, ArrayModeDynamic, 255> B;
|
||||
typedef EightBitArray C;
|
||||
|
||||
A a;
|
||||
B b;
|
||||
C c;
|
||||
|
||||
A a2 = a;
|
||||
B b2 = b;
|
||||
C c2 = c;
|
||||
|
||||
ASSERT_TRUE(a == a2);
|
||||
ASSERT_TRUE(b == b2);
|
||||
ASSERT_TRUE(c == c2);
|
||||
|
||||
a.push_back(OneBitArray());
|
||||
b.push_back(EightBitArray());
|
||||
c.push_back(42);
|
||||
|
||||
ASSERT_TRUE(a != a2);
|
||||
ASSERT_TRUE(b != b2);
|
||||
ASSERT_TRUE(c != c2);
|
||||
|
||||
a2 = a;
|
||||
b2 = b;
|
||||
c2 = c;
|
||||
|
||||
ASSERT_TRUE(a2 == a);
|
||||
ASSERT_TRUE(b2 == b);
|
||||
ASSERT_TRUE(c2 == c);
|
||||
}
|
||||
|
||||
|
||||
TEST(Array, Strings)
|
||||
{
|
||||
typedef Array<IntegerSpec<8, SignednessUnsigned, CastModeSaturate>, ArrayModeDynamic, 32> A8;
|
||||
typedef Array<IntegerSpec<7, SignednessUnsigned, CastModeSaturate>, ArrayModeDynamic, 32> A7;
|
||||
|
||||
A8 a8;
|
||||
A8 a8_2;
|
||||
A7 a7;
|
||||
|
||||
ASSERT_TRUE(a8 == a7);
|
||||
// cppcheck-suppress duplicateExpression
|
||||
ASSERT_TRUE(a8 == a8);
|
||||
// cppcheck-suppress duplicateExpression
|
||||
ASSERT_TRUE(a7 == a7);
|
||||
ASSERT_TRUE(a8 == "");
|
||||
ASSERT_TRUE(a7 == "");
|
||||
|
||||
a8 = "Hello world!";
|
||||
a7 = "123";
|
||||
ASSERT_TRUE(a8 == "Hello world!");
|
||||
ASSERT_TRUE(a7 == "123");
|
||||
|
||||
a8 = "Our sun is dying.";
|
||||
a7 = "456";
|
||||
ASSERT_TRUE("Our sun is dying." == a8);
|
||||
ASSERT_TRUE("456" == a7);
|
||||
|
||||
a8 += " 123456";
|
||||
a8 += "-789";
|
||||
ASSERT_TRUE("Our sun is dying. 123456-789" == a8);
|
||||
|
||||
ASSERT_TRUE(a8_2 == "");
|
||||
ASSERT_TRUE(a8_2.empty());
|
||||
ASSERT_TRUE(a8_2 != a8);
|
||||
a8_2 = a8;
|
||||
ASSERT_TRUE(a8_2 == "Our sun is dying. 123456-789");
|
||||
ASSERT_TRUE(a8_2 == a8);
|
||||
|
||||
/*
|
||||
* c_str()
|
||||
*/
|
||||
ASSERT_STREQ("", A8().c_str());
|
||||
ASSERT_STREQ("", A7().c_str());
|
||||
ASSERT_STREQ("Our sun is dying. 123456-789", a8_2.c_str());
|
||||
ASSERT_STREQ("Our sun is dying. 123456-789", a8.c_str());
|
||||
ASSERT_STREQ("456", a7.c_str());
|
||||
}
|
||||
|
||||
|
||||
TEST(Array, FlatStreaming)
|
||||
{
|
||||
typedef Array<IntegerSpec<8, SignednessUnsigned, CastModeSaturate>, ArrayModeDynamic, 32> A8D;
|
||||
typedef Array<FloatSpec<16, CastModeSaturate>, ArrayModeDynamic, 16> AF16D;
|
||||
typedef Array<FloatSpec<16, CastModeSaturate>, ArrayModeStatic, 3> AF16S;
|
||||
|
||||
A8D a1;
|
||||
a1 = "12\n3\x44\xa5\xde\xad\x79";
|
||||
uavcan::YamlStreamer<A8D>::stream(std::cout, a1, 0);
|
||||
std::cout << std::endl;
|
||||
|
||||
A8D a2;
|
||||
a2 = "Hello";
|
||||
uavcan::YamlStreamer<A8D>::stream(std::cout, a2, 0);
|
||||
std::cout << std::endl;
|
||||
|
||||
AF16D af16d1;
|
||||
af16d1.push_back(1.23);
|
||||
af16d1.push_back(4.56);
|
||||
uavcan::YamlStreamer<AF16D>::stream(std::cout, af16d1, 0);
|
||||
std::cout << std::endl;
|
||||
|
||||
AF16D af16d2;
|
||||
uavcan::YamlStreamer<AF16D>::stream(std::cout, af16d2, 0);
|
||||
std::cout << std::endl;
|
||||
|
||||
AF16S af16s;
|
||||
uavcan::YamlStreamer<AF16S>::stream(std::cout, af16s, 0);
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
|
||||
TEST(Array, MultidimensionalStreaming)
|
||||
{
|
||||
typedef Array<FloatSpec<16, CastModeSaturate>, ArrayModeDynamic, 16> Float16Array;
|
||||
typedef Array<Float16Array, ArrayModeDynamic, 8> TwoDimensional;
|
||||
typedef Array<TwoDimensional, ArrayModeDynamic, 4> ThreeDimensional;
|
||||
|
||||
ThreeDimensional threedee;
|
||||
threedee.resize(3);
|
||||
for (int x = 0; x < threedee.size(); x++)
|
||||
{
|
||||
threedee[x].resize(3);
|
||||
for (int y = 0; y < threedee[x].size(); y++)
|
||||
{
|
||||
threedee[x][y].resize(3);
|
||||
for (int z = 0; z < threedee[x][y].size(); z++)
|
||||
threedee[x][y][z] = 1.0 / (x + y + z + 1.0);
|
||||
}
|
||||
}
|
||||
|
||||
uavcan::YamlStreamer<ThreeDimensional>::stream(std::cout, threedee, 0);
|
||||
std::cout << std::endl;
|
||||
}
|
||||
@@ -1,193 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Pavel Kirienko <pavel.kirienko@gmail.com>
|
||||
*/
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <uavcan/internal/marshal/bit_stream.hpp>
|
||||
|
||||
|
||||
TEST(BitStream, ToString)
|
||||
{
|
||||
{
|
||||
uavcan::StaticTransferBuffer<8> buf;
|
||||
uavcan::BitStream bs(buf);
|
||||
ASSERT_EQ("", bs.toString());
|
||||
ASSERT_EQ("", bs.toString());
|
||||
}
|
||||
{
|
||||
const uint8_t data[] = {0xad}; // 10101101
|
||||
uavcan::StaticTransferBuffer<8> buf;
|
||||
uavcan::BitStream bs(buf);
|
||||
ASSERT_EQ(1, bs.write(data, 8)); // all 8
|
||||
ASSERT_EQ("10101101", bs.toString());
|
||||
}
|
||||
{
|
||||
const uint8_t data[] = {0xad, 0xbe}; // 10101101 10111110
|
||||
uavcan::StaticTransferBuffer<8> buf;
|
||||
uavcan::BitStream bs(buf);
|
||||
ASSERT_EQ(1, bs.write(data, 16)); // all 16
|
||||
ASSERT_EQ("10101101 10111110", bs.toString());
|
||||
}
|
||||
{
|
||||
const uint8_t data[] = {0xad, 0xbe, 0xfc}; // 10101101 10111110 11111100
|
||||
uavcan::StaticTransferBuffer<8> buf;
|
||||
uavcan::BitStream bs(buf);
|
||||
ASSERT_EQ(1, bs.write(data, 20)); // 10101101 10111110 1111
|
||||
ASSERT_EQ("10101101 10111110 11110000", bs.toString());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(BitStream, BitOrderSimple)
|
||||
{
|
||||
/*
|
||||
* a = 1010
|
||||
* b = 1011
|
||||
* c = 1100
|
||||
* d = 1101
|
||||
* e = 1110
|
||||
* f = 1111
|
||||
*/
|
||||
uavcan::StaticTransferBuffer<32> buf;
|
||||
{ // Write
|
||||
const uint8_t data[] = {0xad, 0xbe}; // adbe
|
||||
uavcan::BitStream bs(buf);
|
||||
ASSERT_EQ(1, bs.write(data, 12)); // adb0
|
||||
ASSERT_EQ("10101101 10110000", bs.toString()); // adb0
|
||||
}
|
||||
{ // Read
|
||||
uavcan::BitStream bs(buf);
|
||||
ASSERT_EQ("10101101 10110000", bs.toString()); // Same data
|
||||
uint8_t data[] = {0xFF, 0xFF}; // Uninitialized
|
||||
ASSERT_EQ(1, bs.read(data, 12));
|
||||
ASSERT_EQ(0xad, data[0]);
|
||||
ASSERT_EQ(0xb0, data[1]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(BitStream, BitOrderComplex)
|
||||
{
|
||||
static const std::string REFERENCE =
|
||||
"10101101 10111111 11101111 01010110 11011111 01000100 10001101 00010101 10011110 00100110 10101111 00110111 10111100 00000100";
|
||||
|
||||
uavcan::StaticTransferBuffer<32> buf;
|
||||
{ // Write
|
||||
const uint8_t data1[] = {0xad, 0xbe}; // 10101101 10111110
|
||||
const uint8_t data2[] = {0xfc}; // 11111100
|
||||
const uint8_t data3[] = {0xde, 0xad, 0xbe, 0xef}; // 11011110 10101101 10111110 11101111
|
||||
const uint8_t data4[] = {0x12, 0x34, 0x56, 0x78, // 00010010 00110100 01010110 01111000
|
||||
0x9a, 0xbc, 0xde, 0xf0}; // 10011010 10111100 11011110 11110000
|
||||
|
||||
uavcan::BitStream bs(buf);
|
||||
ASSERT_EQ(1, bs.write(data1, 11)); // 10101101 101
|
||||
std::cout << bs.toString() << std::endl;
|
||||
ASSERT_EQ(1, bs.write(data2, 6)); // 11111 1
|
||||
std::cout << bs.toString() << std::endl;
|
||||
ASSERT_EQ(1, bs.write(data3, 25)); // 1101111 01010110 11011111 01
|
||||
std::cout << bs.toString() << std::endl;
|
||||
ASSERT_EQ(1, bs.write(data4, 64)); // all 64, total 42 + 64 = 106
|
||||
std::cout << bs.toString() << std::endl;
|
||||
ASSERT_EQ(1, bs.write(data4, 4)); // 0001
|
||||
std::cout << bs.toString() << std::endl;
|
||||
|
||||
std::cout << "Reference:\n" << REFERENCE << std::endl;
|
||||
|
||||
ASSERT_EQ(REFERENCE, bs.toString());
|
||||
}
|
||||
{ // Read back in the same order
|
||||
uint8_t data[8];
|
||||
std::fill(data, data + sizeof(data), 0xA5); // Filling with garbage
|
||||
uavcan::BitStream bs(buf);
|
||||
ASSERT_EQ(REFERENCE, bs.toString());
|
||||
|
||||
ASSERT_EQ(1, bs.read(data, 11)); // 10101101 10100000
|
||||
ASSERT_EQ(0xad, data[0]);
|
||||
ASSERT_EQ(0xa0, data[1]);
|
||||
|
||||
ASSERT_EQ(1, bs.read(data, 6)); // 11111100
|
||||
ASSERT_EQ(0xfc, data[0]);
|
||||
|
||||
ASSERT_EQ(1, bs.read(data, 25)); // 11011110 10101101 10111110 10000000
|
||||
ASSERT_EQ(0xde, data[0]);
|
||||
ASSERT_EQ(0xad, data[1]);
|
||||
ASSERT_EQ(0xbe, data[2]);
|
||||
ASSERT_EQ(0x80, data[3]);
|
||||
|
||||
ASSERT_EQ(1, bs.read(data, 64)); // Data - see above
|
||||
ASSERT_EQ(0x12, data[0]);
|
||||
ASSERT_EQ(0x34, data[1]);
|
||||
ASSERT_EQ(0x56, data[2]);
|
||||
ASSERT_EQ(0x78, data[3]);
|
||||
ASSERT_EQ(0x9a, data[4]);
|
||||
ASSERT_EQ(0xbc, data[5]);
|
||||
ASSERT_EQ(0xde, data[6]);
|
||||
ASSERT_EQ(0xf0, data[7]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(BitStream, BitByBit)
|
||||
{
|
||||
static const int NUM_BYTES = 1024;
|
||||
uavcan::StaticTransferBuffer<NUM_BYTES> buf;
|
||||
uavcan::BitStream bs_wr(buf);
|
||||
|
||||
std::string binary_string;
|
||||
unsigned int counter = 0;
|
||||
for (int byte = 0; byte < NUM_BYTES; byte++)
|
||||
{
|
||||
for (int bit = 0; bit < 8; bit++, counter++)
|
||||
{
|
||||
const bool value = counter % 3 == 0;
|
||||
binary_string.push_back(value ? '1' : '0');
|
||||
const uint8_t data[] = { value << 7 };
|
||||
ASSERT_EQ(1, bs_wr.write(data, 1));
|
||||
}
|
||||
binary_string.push_back(' ');
|
||||
}
|
||||
binary_string.erase(binary_string.length() - 1, 1);
|
||||
|
||||
/*
|
||||
* Currently we have no free buffer space, so next write() must fail
|
||||
*/
|
||||
const uint8_t dummy_data_wr[] = { 0xFF };
|
||||
ASSERT_EQ(0, bs_wr.write(dummy_data_wr, 1));
|
||||
|
||||
/*
|
||||
* Bitstream content validation
|
||||
*/
|
||||
// std::cout << bs.toString() << std::endl;
|
||||
// std::cout << "Reference:\n" << binary_string << std::endl;
|
||||
ASSERT_EQ(binary_string, bs_wr.toString());
|
||||
|
||||
/*
|
||||
* Read back
|
||||
*/
|
||||
uavcan::BitStream bs_rd(buf);
|
||||
counter = 0;
|
||||
for (int byte = 0; byte < NUM_BYTES; byte++)
|
||||
{
|
||||
for (int bit = 0; bit < 8; bit++, counter++)
|
||||
{
|
||||
const bool value = counter % 3 == 0;
|
||||
uint8_t data[1];
|
||||
ASSERT_EQ(1, bs_rd.read(data, 1));
|
||||
if (value)
|
||||
{
|
||||
ASSERT_EQ(0x80, data[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSERT_EQ(0, data[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Making sure that reading out of buffer range will fail with error
|
||||
*/
|
||||
uint8_t dummy_data_rd[] = { 0xFF };
|
||||
ASSERT_EQ(0, bs_wr.read(dummy_data_rd, 1));
|
||||
ASSERT_EQ(0xFF, dummy_data_rd[0]);
|
||||
}
|
||||
@@ -1,176 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Pavel Kirienko <pavel.kirienko@gmail.com>
|
||||
*/
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <uavcan/internal/marshal/types.hpp>
|
||||
|
||||
|
||||
TEST(FloatSpec, Limits)
|
||||
{
|
||||
using uavcan::FloatSpec;
|
||||
using uavcan::CastModeSaturate;
|
||||
using uavcan::CastModeTruncate;
|
||||
|
||||
typedef FloatSpec<16, CastModeSaturate> F16S;
|
||||
typedef FloatSpec<16, CastModeTruncate> F16T;
|
||||
typedef FloatSpec<32, CastModeSaturate> F32S;
|
||||
typedef FloatSpec<32, CastModeTruncate> F32T;
|
||||
typedef FloatSpec<64, CastModeSaturate> F64S;
|
||||
typedef FloatSpec<64, CastModeTruncate> F64T;
|
||||
|
||||
ASSERT_FALSE(F16S::IsExactRepresentation);
|
||||
ASSERT_FLOAT_EQ(65504.0, F16S::max());
|
||||
ASSERT_FLOAT_EQ(9.77e-04, F16S::epsilon());
|
||||
|
||||
ASSERT_TRUE(F32T::IsExactRepresentation);
|
||||
ASSERT_FLOAT_EQ(std::numeric_limits<float>::max(), F32T::max());
|
||||
ASSERT_FLOAT_EQ(std::numeric_limits<float>::epsilon(), F32T::epsilon());
|
||||
|
||||
ASSERT_TRUE(F64S::IsExactRepresentation);
|
||||
ASSERT_FLOAT_EQ(std::numeric_limits<double>::max(), F64S::max());
|
||||
ASSERT_FLOAT_EQ(std::numeric_limits<double>::epsilon(), F64S::epsilon());
|
||||
}
|
||||
|
||||
TEST(FloatSpec, Basic)
|
||||
{
|
||||
using uavcan::FloatSpec;
|
||||
using uavcan::CastModeSaturate;
|
||||
using uavcan::CastModeTruncate;
|
||||
using uavcan::StorageType;
|
||||
|
||||
typedef FloatSpec<16, CastModeSaturate> F16S;
|
||||
typedef FloatSpec<16, CastModeTruncate> F16T;
|
||||
typedef FloatSpec<32, CastModeSaturate> F32S;
|
||||
typedef FloatSpec<32, CastModeTruncate> F32T;
|
||||
typedef FloatSpec<64, CastModeSaturate> F64S;
|
||||
typedef FloatSpec<64, CastModeTruncate> F64T;
|
||||
|
||||
static const long double Values[] =
|
||||
{
|
||||
0.0,
|
||||
1.0,
|
||||
M_PI,
|
||||
123,
|
||||
-123,
|
||||
99999,
|
||||
-999999,
|
||||
std::numeric_limits<float>::max(),
|
||||
-std::numeric_limits<float>::max(),
|
||||
std::numeric_limits<double>::infinity(),
|
||||
-std::numeric_limits<double>::infinity(),
|
||||
nanl("")
|
||||
};
|
||||
static const int NumValues = sizeof(Values) / sizeof(Values[0]);
|
||||
|
||||
static const long double ValuesF16S[] =
|
||||
{
|
||||
0.0,
|
||||
1.0,
|
||||
3.140625,
|
||||
123,
|
||||
-123,
|
||||
F16S::max(),
|
||||
-F16S::max(),
|
||||
F16S::max(),
|
||||
-F16S::max(),
|
||||
std::numeric_limits<F16S::StorageType>::infinity(),
|
||||
-std::numeric_limits<F16S::StorageType>::infinity(),
|
||||
nanl("")
|
||||
};
|
||||
static const long double ValuesF16T[] =
|
||||
{
|
||||
0.0,
|
||||
1.0,
|
||||
3.140625,
|
||||
123,
|
||||
-123,
|
||||
std::numeric_limits<F16S::StorageType>::infinity(),
|
||||
-std::numeric_limits<F16S::StorageType>::infinity(),
|
||||
std::numeric_limits<F16S::StorageType>::infinity(),
|
||||
-std::numeric_limits<F16S::StorageType>::infinity(),
|
||||
std::numeric_limits<F16S::StorageType>::infinity(),
|
||||
-std::numeric_limits<F16S::StorageType>::infinity(),
|
||||
nanl("")
|
||||
};
|
||||
|
||||
/*
|
||||
* Writing
|
||||
*/
|
||||
uavcan::StaticTransferBuffer<NumValues * (2 + 4 + 8) * 2> buf;
|
||||
uavcan::BitStream bs_wr(buf);
|
||||
uavcan::ScalarCodec sc_wr(bs_wr);
|
||||
|
||||
for (int i = 0; i < NumValues; i++)
|
||||
{
|
||||
ASSERT_EQ(1, F16S::encode(Values[i], sc_wr, uavcan::TailArrayOptDisabled));
|
||||
ASSERT_EQ(1, F16T::encode(Values[i], sc_wr, uavcan::TailArrayOptDisabled));
|
||||
ASSERT_EQ(1, F32S::encode(Values[i], sc_wr, uavcan::TailArrayOptDisabled));
|
||||
ASSERT_EQ(1, F32T::encode(Values[i], sc_wr, uavcan::TailArrayOptDisabled));
|
||||
ASSERT_EQ(1, F64S::encode(Values[i], sc_wr, uavcan::TailArrayOptDisabled));
|
||||
ASSERT_EQ(1, F64T::encode(Values[i], sc_wr, uavcan::TailArrayOptDisabled));
|
||||
}
|
||||
|
||||
ASSERT_EQ(0, F16S::encode(0, sc_wr, uavcan::TailArrayOptDisabled)); // Out of buffer space now
|
||||
|
||||
/*
|
||||
* Reading
|
||||
*/
|
||||
uavcan::BitStream bs_rd(buf);
|
||||
uavcan::ScalarCodec sc_rd(bs_rd);
|
||||
|
||||
#define CHECK(FloatType, expected_value) \
|
||||
do { \
|
||||
StorageType<FloatType>::Type var = StorageType<FloatType>::Type(); \
|
||||
ASSERT_EQ(1, FloatType::decode(var, sc_rd, uavcan::TailArrayOptDisabled)); \
|
||||
if (!isnan(expected_value)) \
|
||||
ASSERT_FLOAT_EQ(expected_value, var); \
|
||||
else \
|
||||
ASSERT_EQ(!!isnan(expected_value), !!isnan(var)); \
|
||||
} while (0)
|
||||
|
||||
for (int i = 0; i < NumValues; i++)
|
||||
{
|
||||
CHECK(F16S, ValuesF16S[i]);
|
||||
CHECK(F16T, ValuesF16T[i]);
|
||||
CHECK(F32S, Values[i]);
|
||||
CHECK(F32T, Values[i]);
|
||||
CHECK(F64S, Values[i]);
|
||||
CHECK(F64T, Values[i]);
|
||||
}
|
||||
|
||||
#undef CHECK
|
||||
}
|
||||
|
||||
TEST(FloatSpec, Float16Representation)
|
||||
{
|
||||
using uavcan::FloatSpec;
|
||||
using uavcan::CastModeSaturate;
|
||||
using uavcan::CastModeTruncate;
|
||||
|
||||
typedef FloatSpec<16, CastModeSaturate> F16S;
|
||||
typedef FloatSpec<16, CastModeTruncate> F16T;
|
||||
|
||||
uavcan::StaticTransferBuffer<2 * 6> buf;
|
||||
uavcan::BitStream bs_wr(buf);
|
||||
uavcan::ScalarCodec sc_wr(bs_wr);
|
||||
|
||||
ASSERT_EQ(1, F16S::encode(0.0, sc_wr, uavcan::TailArrayOptDisabled));
|
||||
ASSERT_EQ(1, F16S::encode(1.0, sc_wr, uavcan::TailArrayOptDisabled));
|
||||
ASSERT_EQ(1, F16S::encode(-2.0, sc_wr, uavcan::TailArrayOptDisabled));
|
||||
ASSERT_EQ(1, F16T::encode(999999, sc_wr, uavcan::TailArrayOptDisabled)); // +inf
|
||||
ASSERT_EQ(1, F16S::encode(-999999, sc_wr, uavcan::TailArrayOptDisabled)); // -max
|
||||
ASSERT_EQ(1, F16S::encode(nan(""), sc_wr, uavcan::TailArrayOptDisabled)); // nan
|
||||
|
||||
ASSERT_EQ(0, F16S::encode(0, sc_wr, uavcan::TailArrayOptDisabled)); // Out of buffer space now
|
||||
|
||||
static const std::string Reference = // Keep in mind that this is LITTLE ENDIAN representation
|
||||
"00000000 00000000 " // 0.0
|
||||
"00000000 00111100 " // 1.0
|
||||
"00000000 11000000 " // -2.0
|
||||
"00000000 01111100 " // +inf
|
||||
"11111111 11111011 " // -max
|
||||
"11111111 01111111"; // nan
|
||||
|
||||
ASSERT_EQ(Reference, bs_wr.toString());
|
||||
}
|
||||
@@ -1,109 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Pavel Kirienko <pavel.kirienko@gmail.com>
|
||||
*/
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <uavcan/internal/marshal/types.hpp>
|
||||
|
||||
|
||||
TEST(IntegerSpec, Limits)
|
||||
{
|
||||
using uavcan::IntegerSpec;
|
||||
using uavcan::SignednessSigned;
|
||||
using uavcan::SignednessUnsigned;
|
||||
using uavcan::CastModeSaturate;
|
||||
using uavcan::CastModeTruncate;
|
||||
|
||||
typedef IntegerSpec<8, SignednessUnsigned, CastModeSaturate> UInt8;
|
||||
typedef IntegerSpec<4, SignednessSigned, CastModeTruncate> SInt4;
|
||||
typedef IntegerSpec<32, SignednessUnsigned, CastModeTruncate> UInt32;
|
||||
typedef IntegerSpec<40, SignednessUnsigned, CastModeSaturate> UInt40;
|
||||
typedef IntegerSpec<64, SignednessUnsigned, CastModeTruncate> UInt64;
|
||||
typedef IntegerSpec<64, SignednessSigned, CastModeSaturate> SInt64;
|
||||
typedef IntegerSpec<63, SignednessUnsigned, CastModeSaturate> UInt63;
|
||||
|
||||
ASSERT_EQ(255, UInt8::max());
|
||||
ASSERT_EQ(0, UInt8::min());
|
||||
|
||||
ASSERT_EQ(7, SInt4::max());
|
||||
ASSERT_EQ(-8, SInt4::min());
|
||||
|
||||
ASSERT_EQ(0xFFFFFFFF, UInt32::max());
|
||||
ASSERT_EQ(0, UInt32::min());
|
||||
|
||||
ASSERT_EQ(0xFFFFFFFFFF, UInt40::max());
|
||||
ASSERT_EQ(0, UInt40::min());
|
||||
|
||||
ASSERT_EQ(0xFFFFFFFFFFFFFFFF, UInt64::max());
|
||||
ASSERT_EQ(0, UInt64::min());
|
||||
|
||||
ASSERT_EQ(0x7FFFFFFFFFFFFFFF, SInt64::max());
|
||||
ASSERT_EQ(-0x8000000000000000, SInt64::min());
|
||||
|
||||
ASSERT_EQ(0x7FFFFFFFFFFFFFFF, UInt63::max());
|
||||
ASSERT_EQ(0, UInt63::min());
|
||||
|
||||
ASSERT_EQ(SInt64::max(), UInt63::max());
|
||||
}
|
||||
|
||||
|
||||
TEST(IntegerSpec, Basic)
|
||||
{
|
||||
using uavcan::IntegerSpec;
|
||||
using uavcan::SignednessSigned;
|
||||
using uavcan::SignednessUnsigned;
|
||||
using uavcan::CastModeSaturate;
|
||||
using uavcan::CastModeTruncate;
|
||||
using uavcan::StorageType;
|
||||
|
||||
uavcan::StaticTransferBuffer<100> buf;
|
||||
uavcan::BitStream bs_wr(buf);
|
||||
uavcan::ScalarCodec sc_wr(bs_wr);
|
||||
|
||||
typedef IntegerSpec<8, SignednessUnsigned, CastModeSaturate> UInt8S;
|
||||
typedef IntegerSpec<4, SignednessSigned, CastModeTruncate> SInt4T;
|
||||
typedef IntegerSpec<32, SignednessUnsigned, CastModeTruncate> UInt32T;
|
||||
typedef IntegerSpec<40, SignednessUnsigned, CastModeSaturate> UInt40S;
|
||||
typedef IntegerSpec<64, SignednessUnsigned, CastModeTruncate> UInt64T;
|
||||
typedef IntegerSpec<58, SignednessSigned, CastModeSaturate> SInt58S;
|
||||
typedef IntegerSpec<63, SignednessUnsigned, CastModeSaturate> UInt63S;
|
||||
typedef IntegerSpec<10, SignednessSigned, CastModeSaturate> SInt10S;
|
||||
typedef IntegerSpec<1, SignednessUnsigned, CastModeSaturate> UInt1S;
|
||||
|
||||
ASSERT_EQ(1, UInt8S::encode(UInt8S::StorageType(123), sc_wr, uavcan::TailArrayOptDisabled));
|
||||
ASSERT_EQ(1, SInt4T::encode(SInt4T::StorageType(-0x44), sc_wr, uavcan::TailArrayOptDisabled));
|
||||
ASSERT_EQ(1, UInt32T::encode(UInt32T::StorageType(0xFFFFFFFF), sc_wr, uavcan::TailArrayOptDisabled));
|
||||
ASSERT_EQ(1, UInt40S::encode(UInt40S::StorageType(0xFFFFFFFFFFFFFFFF), sc_wr, uavcan::TailArrayOptDisabled));
|
||||
ASSERT_EQ(1, UInt64T::encode(UInt64T::StorageType(0xFFFFFFFFFFFFFFFF), sc_wr, uavcan::TailArrayOptDisabled));
|
||||
ASSERT_EQ(1, SInt58S::encode(SInt58S::StorageType(0xFFFFFFFFFFFFFFF), sc_wr, uavcan::TailArrayOptDisabled));
|
||||
ASSERT_EQ(1, UInt63S::encode(UInt63S::StorageType(0xFFFFFFFFFFFFFFFF), sc_wr, uavcan::TailArrayOptDisabled));
|
||||
ASSERT_EQ(1, SInt10S::encode(SInt10S::StorageType(-30000), sc_wr, uavcan::TailArrayOptDisabled));
|
||||
ASSERT_EQ(1, UInt1S::encode(UInt1S::StorageType(42), sc_wr, uavcan::TailArrayOptDisabled));
|
||||
|
||||
std::cout << bs_wr.toString() << std::endl;
|
||||
|
||||
uavcan::BitStream bs_rd(buf);
|
||||
uavcan::ScalarCodec sc_rd(bs_rd);
|
||||
|
||||
#define CHECK(IntType, expected_value) \
|
||||
do { \
|
||||
StorageType<IntType>::Type var = StorageType<IntType>::Type(); \
|
||||
ASSERT_EQ(1, IntType::decode(var, sc_rd, uavcan::TailArrayOptDisabled)); \
|
||||
ASSERT_EQ(expected_value, var); \
|
||||
} while (0)
|
||||
|
||||
CHECK(UInt8S, 123);
|
||||
CHECK(SInt4T, -4);
|
||||
CHECK(UInt32T, 0xFFFFFFFF);
|
||||
CHECK(UInt40S, 0xFFFFFFFFFF);
|
||||
CHECK(UInt64T, 0xFFFFFFFFFFFFFFFF);
|
||||
CHECK(SInt58S, 0x1FFFFFFFFFFFFFF);
|
||||
CHECK(UInt63S, 0x7FFFFFFFFFFFFFFF);
|
||||
CHECK(SInt10S, -512);
|
||||
CHECK(UInt1S, 1);
|
||||
|
||||
#undef CHECK
|
||||
|
||||
StorageType<UInt1S>::Type var;
|
||||
ASSERT_EQ(0, UInt1S::decode(var, sc_rd, uavcan::TailArrayOptDisabled));
|
||||
}
|
||||
@@ -1,96 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Pavel Kirienko <pavel.kirienko@gmail.com>
|
||||
*/
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <uavcan/internal/marshal/scalar_codec.hpp>
|
||||
|
||||
|
||||
TEST(ScalarCodec, Basic)
|
||||
{
|
||||
uavcan::StaticTransferBuffer<38> buf;
|
||||
uavcan::BitStream bs_wr(buf);
|
||||
uavcan::ScalarCodec sc_wr(bs_wr);
|
||||
|
||||
{
|
||||
uint64_t u64 = 0;
|
||||
ASSERT_EQ(0, sc_wr.decode<64>(u64)); // Out of buffer space
|
||||
}
|
||||
|
||||
/*
|
||||
* Encoding some variables
|
||||
*/
|
||||
ASSERT_EQ(1, sc_wr.encode<12>((uint16_t)0xbeda)); // --> 0xeda
|
||||
ASSERT_EQ(1, sc_wr.encode<1>((uint8_t)1));
|
||||
ASSERT_EQ(1, sc_wr.encode<1>((uint16_t)0));
|
||||
ASSERT_EQ(1, sc_wr.encode<4>((uint8_t)8));
|
||||
ASSERT_EQ(1, sc_wr.encode<32>((uint32_t)0xdeadbeef));
|
||||
ASSERT_EQ(1, sc_wr.encode<3>((int8_t)-1));
|
||||
ASSERT_EQ(1, sc_wr.encode<4>((int8_t)-6));
|
||||
ASSERT_EQ(1, sc_wr.encode<20>((int32_t)-123456));
|
||||
ASSERT_EQ(1, sc_wr.encode<64>(std::numeric_limits<int64_t>::min()));
|
||||
ASSERT_EQ(1, sc_wr.encode<64>(std::numeric_limits<int64_t>::max()));
|
||||
ASSERT_EQ(1, sc_wr.encode<15>((int16_t)-1));
|
||||
ASSERT_EQ(1, sc_wr.encode<2>((int16_t)-1));
|
||||
ASSERT_EQ(1, sc_wr.encode<16>(std::numeric_limits<int16_t>::min()));
|
||||
ASSERT_EQ(1, sc_wr.encode<64>(std::numeric_limits<uint64_t>::max())); // Total 302 bit (38 bytes)
|
||||
|
||||
ASSERT_EQ(0, sc_wr.encode<64>(std::numeric_limits<uint64_t>::min())); // Out of buffer space
|
||||
|
||||
/*
|
||||
* Decoding back
|
||||
*/
|
||||
uavcan::BitStream bs_rd(buf);
|
||||
uavcan::ScalarCodec sc_rd(bs_rd);
|
||||
|
||||
uint8_t u8 = 0;
|
||||
int8_t i8 = 0;
|
||||
uint16_t u16 = 0;
|
||||
int16_t i16 = 0;
|
||||
uint32_t u32 = 0;
|
||||
int32_t i32 = 0;
|
||||
uint64_t u64 = 0;
|
||||
int64_t i64 = 0;
|
||||
|
||||
#define CHECK(bitlen, variable, expected_value) \
|
||||
do { \
|
||||
ASSERT_EQ(1, sc_rd.decode<bitlen>(variable)); \
|
||||
ASSERT_EQ(expected_value, variable); \
|
||||
} while (0)
|
||||
|
||||
CHECK(12, u16, 0xeda);
|
||||
CHECK(1, u8, 1);
|
||||
CHECK(1, u16, 0);
|
||||
CHECK(4, u8, 8);
|
||||
CHECK(32, u32, 0xdeadbeef);
|
||||
CHECK(3, i8, -1);
|
||||
CHECK(4, i8, -6);
|
||||
CHECK(20, i32, -123456);
|
||||
CHECK(64, i64, std::numeric_limits<int64_t>::min());
|
||||
CHECK(64, i64, std::numeric_limits<int64_t>::max());
|
||||
CHECK(15, i16, -1);
|
||||
CHECK(2, i8, -1);
|
||||
CHECK(16, i16, std::numeric_limits<int16_t>::min());
|
||||
CHECK(64, u64, std::numeric_limits<uint64_t>::max());
|
||||
|
||||
#undef CHECK
|
||||
|
||||
ASSERT_EQ(0, sc_rd.decode<64>(u64)); // Out of buffer space
|
||||
}
|
||||
|
||||
TEST(ScalarCodec, RepresentationCorrectness)
|
||||
{
|
||||
uavcan::StaticTransferBuffer<4> buf;
|
||||
uavcan::BitStream bs_wr(buf);
|
||||
uavcan::ScalarCodec sc_wr(bs_wr);
|
||||
|
||||
ASSERT_EQ(1, sc_wr.encode<12>((uint16_t)0xbeda)); // --> 0xeda
|
||||
ASSERT_EQ(1, sc_wr.encode<3>((int8_t)-1));
|
||||
ASSERT_EQ(1, sc_wr.encode<4>((int8_t)-5));
|
||||
ASSERT_EQ(1, sc_wr.encode<2>((int16_t)-1));
|
||||
ASSERT_EQ(1, sc_wr.encode<4>((uint8_t)0x88)); // --> 8
|
||||
|
||||
// This representation was carefully crafted and triple checked:
|
||||
static const std::string REFERENCE = "11011010 11101111 01111100 00000000";
|
||||
ASSERT_EQ(REFERENCE, bs_wr.toString());
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Pavel Kirienko <pavel.kirienko@gmail.com>
|
||||
*/
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <uavcan/internal/marshal/types.hpp>
|
||||
|
||||
|
||||
TEST(MarshalTypeUtil, IntegerBitLen)
|
||||
{
|
||||
using uavcan::IntegerBitLen;
|
||||
|
||||
ASSERT_EQ(0, IntegerBitLen<0>::Result);
|
||||
ASSERT_EQ(1, IntegerBitLen<1>::Result);
|
||||
ASSERT_EQ(6, IntegerBitLen<42>::Result);
|
||||
ASSERT_EQ(8, IntegerBitLen<232>::Result);
|
||||
ASSERT_EQ(32, IntegerBitLen<0x81234567>::Result);
|
||||
}
|
||||
|
||||
|
||||
TEST(MarshalTypeUtil, BitLenToByteLen)
|
||||
{
|
||||
using uavcan::BitLenToByteLen;
|
||||
|
||||
ASSERT_EQ(2, BitLenToByteLen<16>::Result);
|
||||
ASSERT_EQ(1, BitLenToByteLen<8>::Result);
|
||||
ASSERT_EQ(1, BitLenToByteLen<7>::Result);
|
||||
ASSERT_EQ(1, BitLenToByteLen<1>::Result);
|
||||
ASSERT_EQ(2, BitLenToByteLen<9>::Result);
|
||||
}
|
||||
Reference in New Issue
Block a user