blob: 013e911ba59e300912d046ef21f5a715780cacb2 [file] [log] [blame]
#include "aos/util/bitpacking.h"
#include <stdint.h>
#include "gtest/gtest.h"
namespace aos {
namespace testing {
// Tests MaskOnes with small arguments.
TEST(MaskOnesTest, Small) {
EXPECT_EQ(0u, MaskOnes<uint8_t>(0));
EXPECT_EQ(0u, MaskOnes<uint64_t>(0));
EXPECT_EQ(1u, MaskOnes<uint8_t>(1));
EXPECT_EQ(1u, MaskOnes<uint64_t>(1));
}
// Tests MaskOnes with large arguments.
TEST(MaskOnesTest, Large) {
EXPECT_EQ(0xFFu, MaskOnes<uint8_t>(8));
EXPECT_EQ(0x7Fu, MaskOnes<uint8_t>(7));
EXPECT_EQ(0xFFu, MaskOnes<uint64_t>(8));
EXPECT_EQ(UINT64_C(0xFFFFFFFFFFFFFFFF), MaskOnes<uint64_t>(64));
EXPECT_EQ(UINT64_C(0x7FFFFFFFFFFFFFFF), MaskOnes<uint64_t>(63));
}
// Tests some simple non-edge-case use cases for PackBits.
TEST(PackBitsTest, Basic) {
{
std::array<char, 3> buffer{};
PackBits<uint8_t, 8, 0>(0, buffer);
EXPECT_EQ((std::array<char, 3>{}), buffer);
PackBits<uint8_t, 8, 0>(9, buffer);
EXPECT_EQ((std::array<char, 3>{{9, 0, 0}}), buffer);
PackBits<uint8_t, 8, 8>(7, buffer);
EXPECT_EQ((std::array<char, 3>{{9, 7, 0}}), buffer);
PackBits<uint8_t, 8, 16>(1, buffer);
EXPECT_EQ((std::array<char, 3>{{9, 7, 1}}), buffer);
}
{
std::array<char, 3> buffer{};
PackBits<uint16_t, 16, 0>(0xdead, buffer);
EXPECT_EQ((std::array<char, 3>{
{static_cast<char>(0xad), static_cast<char>(0xde), 0}}),
buffer);
}
{
std::array<char, 3> buffer{};
PackBits<uint8_t, 4, 0>(0xd7, buffer);
EXPECT_EQ((std::array<char, 3>{{0x7, 0, 0}}), buffer);
}
{
std::array<char, 3> buffer{};
PackBits<uint8_t, 4, 4>(0xd7, buffer);
EXPECT_EQ((std::array<char, 3>{{0x70, 0, 0}}), buffer);
}
}
// Verifies that PackBits puts bits in an order consistent with increasing
// offsets.
TEST(PackBitsTest, Consistency) {
{
std::array<char, 3> buffer1{};
PackBits<uint8_t, 8, 0>(0x80, buffer1);
std::array<char, 3> buffer2{};
PackBits<uint8_t, 1, 7>(0x1, buffer2);
EXPECT_EQ(buffer1, buffer2);
}
{
std::array<char, 1> buffer1{{static_cast<char>(0xFF)}};
PackBits<uint8_t, 8, 0>(0x7F, buffer1);
std::array<char, 1> buffer2{{static_cast<char>(0xFF)}};
PackBits<uint8_t, 1, 7>(0x0, buffer2);
EXPECT_EQ(buffer1, buffer2);
}
{
std::array<char, 1> buffer1{};
PackBits<uint8_t, 3, 5>(0x7, buffer1);
std::array<char, 1> buffer2{};
PackBits<uint8_t, 5, 3>(0x3C, buffer2);
EXPECT_EQ(buffer1, buffer2);
}
{
std::array<char, 1> buffer1{{static_cast<char>(0xFF)}};
PackBits<uint8_t, 3, 5>(0x0, buffer1);
std::array<char, 1> buffer2{{static_cast<char>(0xFF)}};
PackBits<uint8_t, 5, 3>(0x03, buffer2);
EXPECT_EQ(buffer1, buffer2);
}
}
// Tests some simple non-edge-case use cases for UnpackBits.
TEST(UnpackBitsTest, Basic) {
{
std::array<char, 3> buffer{};
EXPECT_EQ(0u, (UnpackBits<uint8_t, 8, 0>(buffer)));
buffer = {{9, 0, 0}};
EXPECT_EQ(9u, (UnpackBits<uint8_t, 8, 0>(buffer)));
buffer = {{9, 7, 0}};
EXPECT_EQ(9u, (UnpackBits<uint8_t, 8, 0>(buffer)));
EXPECT_EQ(7u, (UnpackBits<uint8_t, 8, 8>(buffer)));
buffer = {{9, 7, 1}};
EXPECT_EQ(9u, (UnpackBits<uint8_t, 8, 0>(buffer)));
EXPECT_EQ(7u, (UnpackBits<uint8_t, 8, 8>(buffer)));
EXPECT_EQ(1u, (UnpackBits<uint8_t, 8, 16>(buffer)));
}
{
const std::array<char, 3> buffer = {
{static_cast<char>(0xad), static_cast<char>(0xde), 0}};
EXPECT_EQ(0xdead, (UnpackBits<uint16_t, 16, 0>(buffer)));
}
{
const std::array<char, 3> buffer = {{static_cast<char>(0xF7), 0, 0}};
EXPECT_EQ(7u, (UnpackBits<uint8_t, 4, 0>(buffer)));
}
{
const std::array<char, 3> buffer = {{static_cast<char>(0x7F), 0, 0}};
EXPECT_EQ(7u, (UnpackBits<uint8_t, 4, 4>(buffer)));
}
}
// Tests PackBits split across multiple bytes.
TEST(PackBitsTest, AcrossBytes) {
{
std::array<char, 2> buffer{};
PackBits<uint8_t, 8, 7>(0xFF, buffer);
EXPECT_EQ((std::array<char, 2>{
{static_cast<char>(0x80), static_cast<char>(0x7F)}}),
buffer);
}
{
std::array<char, 2> buffer{};
PackBits<uint8_t, 8, 6>(0xFF, buffer);
EXPECT_EQ((std::array<char, 2>{
{static_cast<char>(0xC0), static_cast<char>(0x3F)}}),
buffer);
}
{
std::array<char, 2> buffer{};
PackBits<uint8_t, 8, 5>(0xFF, buffer);
EXPECT_EQ((std::array<char, 2>{
{static_cast<char>(0xE0), static_cast<char>(0x1F)}}),
buffer);
}
{
std::array<char, 2> buffer{};
PackBits<uint8_t, 8, 4>(0xFF, buffer);
EXPECT_EQ((std::array<char, 2>{
{static_cast<char>(0xF0), static_cast<char>(0x0F)}}),
buffer);
}
{
std::array<char, 2> buffer{};
PackBits<uint8_t, 8, 3>(0xFF, buffer);
EXPECT_EQ((std::array<char, 2>{
{static_cast<char>(0xF8), static_cast<char>(0x07)}}),
buffer);
}
{
std::array<char, 2> buffer{};
PackBits<uint8_t, 8, 2>(0xFF, buffer);
EXPECT_EQ((std::array<char, 2>{
{static_cast<char>(0xFC), static_cast<char>(0x03)}}),
buffer);
}
{
std::array<char, 2> buffer{};
PackBits<uint8_t, 8, 1>(0xFF, buffer);
EXPECT_EQ((std::array<char, 2>{
{static_cast<char>(0xFE), static_cast<char>(0x01)}}),
buffer);
}
}
// Tests UnpackBits split across multiple bytes.
TEST(UnpackBitsTest, AcrossBytes) {
{
const std::array<char, 2> buffer = {
{static_cast<char>(0x80), static_cast<char>(0x7F)}};
EXPECT_EQ(0xFFu, (UnpackBits<uint8_t, 8, 7>(buffer)));
}
{
const std::array<char, 2> buffer = {
{static_cast<char>(0xC0), static_cast<char>(0x3F)}};
EXPECT_EQ(0xFFu, (UnpackBits<uint8_t, 8, 6>(buffer)));
}
{
const std::array<char, 2> buffer = {
{static_cast<char>(0xE0), static_cast<char>(0x1F)}};
EXPECT_EQ(0xFFu, (UnpackBits<uint8_t, 8, 5>(buffer)));
}
{
const std::array<char, 2> buffer = {
{static_cast<char>(0xF0), static_cast<char>(0x0F)}};
EXPECT_EQ(0xFFu, (UnpackBits<uint8_t, 8, 4>(buffer)));
}
{
const std::array<char, 2> buffer = {
{static_cast<char>(0xF8), static_cast<char>(0x07)}};
EXPECT_EQ(0xFFu, (UnpackBits<uint8_t, 8, 3>(buffer)));
}
{
const std::array<char, 2> buffer = {
{static_cast<char>(0xFC), static_cast<char>(0x03)}};
EXPECT_EQ(0xFFu, (UnpackBits<uint8_t, 8, 2>(buffer)));
}
{
const std::array<char, 2> buffer = {
{static_cast<char>(0xFE), static_cast<char>(0x01)}};
EXPECT_EQ(0xFFu, (UnpackBits<uint8_t, 8, 1>(buffer)));
}
}
// Verifies that PackBits avoids touching adjacent bits.
TEST(PackBitsTest, AdjacentBits) {
{
std::array<char, 2> buffer{
{static_cast<char>(0xFF), static_cast<char>(0xFF)}};
PackBits<uint8_t, 1, 0>(0, buffer);
EXPECT_EQ((std::array<char, 2>{
{static_cast<char>(0xFE), static_cast<char>(0xFF)}}),
buffer);
}
{
std::array<char, 2> buffer{
{static_cast<char>(0xFF), static_cast<char>(0xFF)}};
PackBits<uint8_t, 7, 0>(0, buffer);
EXPECT_EQ((std::array<char, 2>{
{static_cast<char>(0x80), static_cast<char>(0xFF)}}),
buffer);
}
{
std::array<char, 2> buffer{
{static_cast<char>(0xFF), static_cast<char>(0xFF)}};
PackBits<uint8_t, 8, 0>(0, buffer);
EXPECT_EQ((std::array<char, 2>{
{static_cast<char>(0x00), static_cast<char>(0xFF)}}),
buffer);
}
{
std::array<char, 2> buffer{
{static_cast<char>(0xFF), static_cast<char>(0xFF)}};
PackBits<uint16_t, 9, 0>(0, buffer);
EXPECT_EQ((std::array<char, 2>{
{static_cast<char>(0x00), static_cast<char>(0xFE)}}),
buffer);
}
{
std::array<char, 2> buffer{
{static_cast<char>(0xFF), static_cast<char>(0xFF)}};
PackBits<uint16_t, 14, 0>(0, buffer);
EXPECT_EQ((std::array<char, 2>{
{static_cast<char>(0x00), static_cast<char>(0xC0)}}),
buffer);
}
{
std::array<char, 2> buffer{
{static_cast<char>(0xFF), static_cast<char>(0xFF)}};
PackBits<uint16_t, 15, 0>(0, buffer);
EXPECT_EQ((std::array<char, 2>{
{static_cast<char>(0x00), static_cast<char>(0x80)}}),
buffer);
}
{
std::array<char, 2> buffer{
{static_cast<char>(0xFF), static_cast<char>(0xFF)}};
PackBits<uint16_t, 15, 1>(0, buffer);
EXPECT_EQ((std::array<char, 2>{
{static_cast<char>(0x01), static_cast<char>(0x00)}}),
buffer);
}
{
std::array<char, 2> buffer{
{static_cast<char>(0xFF), static_cast<char>(0xFF)}};
PackBits<uint16_t, 6, 8>(0, buffer);
EXPECT_EQ((std::array<char, 2>{
{static_cast<char>(0xFF), static_cast<char>(0xC0)}}),
buffer);
}
{
std::array<char, 4> buffer{
{static_cast<char>(0xFF), static_cast<char>(0xFF),
static_cast<char>(0xFF), static_cast<char>(0xFF)}};
PackBits<uint16_t, 6, 24>(0, buffer);
EXPECT_EQ((std::array<char, 4>{
{static_cast<char>(0xFF), static_cast<char>(0xFF),
static_cast<char>(0xFF), static_cast<char>(0xC0)}}),
buffer);
}
}
// Tests FloatToIntLinear with values near or outside of its boundaries.
TEST(FloatToIntLinearTest, OutOfBounds) {
EXPECT_EQ(0u, (FloatToIntLinear<1>(0.0f, 1.0f, 0.0f)));
EXPECT_EQ(0u, (FloatToIntLinear<1>(0.0f, 1.0f, -0.1f)));
EXPECT_EQ(0u, (FloatToIntLinear<1>(0.0f, 1.0f, -1.0f)));
EXPECT_EQ(1u, (FloatToIntLinear<1>(0.0f, 1.0f, 1.0f)));
EXPECT_EQ(1u, (FloatToIntLinear<1>(0.0f, 1.0f, 1.1f)));
EXPECT_EQ(1u, (FloatToIntLinear<1>(0.0f, 1.0f, 2.0f)));
EXPECT_EQ(0u, (FloatToIntLinear<1>(0.0f, 4.0f, 0.0f)));
EXPECT_EQ(1u, (FloatToIntLinear<1>(0.0f, 4.0f, 4.0f)));
EXPECT_EQ(1u, (FloatToIntLinear<1>(0.0f, 4.0f, 10.0f)));
EXPECT_EQ(0u, (FloatToIntLinear<3>(0.0f, 4.0f, 0.0f)));
EXPECT_EQ(0u, (FloatToIntLinear<3>(0.0f, 4.0f, -100.0f)));
EXPECT_EQ(7u, (FloatToIntLinear<3>(0.0f, 4.0f, 4.0f)));
EXPECT_EQ(7u, (FloatToIntLinear<3>(0.0f, 4.0f, 4.01f)));
EXPECT_EQ(0u, (FloatToIntLinear<3>(-3.0f, 5.0f, -3.0f)));
EXPECT_EQ(0u, (FloatToIntLinear<3>(-3.0f, 5.0f, -3.1f)));
EXPECT_EQ(7u, (FloatToIntLinear<3>(-3.0f, 5.0f, 5.0f)));
EXPECT_EQ(7u, (FloatToIntLinear<3>(-3.0f, 5.0f, 5.1f)));
}
// Tests that FloatToIntLinear rounds correctly at the boundaries between output
// values.
TEST(FloatToIntLinearTest, Rounding) {
EXPECT_EQ(0u, (FloatToIntLinear<1>(0.0f, 1.0f, 0.49f)));
EXPECT_EQ(1u, (FloatToIntLinear<1>(0.0f, 1.0f, 0.51f)));
EXPECT_EQ(1u, (FloatToIntLinear<1>(-1.0f, 0.0f, -0.49f)));
EXPECT_EQ(0u, (FloatToIntLinear<1>(-1.0f, 0.0f, -0.51f)));
EXPECT_EQ(1u, (FloatToIntLinear<1>(-1.0f, 1.0f, 0.01f)));
EXPECT_EQ(0u, (FloatToIntLinear<1>(-1.0f, 1.0f, -0.01f)));
EXPECT_EQ(0u, (FloatToIntLinear<3>(0.0f, 1.0f, 0.124f)));
EXPECT_EQ(1u, (FloatToIntLinear<3>(0.0f, 1.0f, 0.126f)));
EXPECT_EQ(1u, (FloatToIntLinear<3>(0.0f, 1.0f, 0.249f)));
EXPECT_EQ(2u, (FloatToIntLinear<3>(0.0f, 1.0f, 0.251f)));
EXPECT_EQ(2u, (FloatToIntLinear<3>(0.0f, 1.0f, 0.374f)));
EXPECT_EQ(3u, (FloatToIntLinear<3>(0.0f, 1.0f, 0.376f)));
EXPECT_EQ(3u, (FloatToIntLinear<3>(0.0f, 1.0f, 0.499f)));
EXPECT_EQ(4u, (FloatToIntLinear<3>(0.0f, 1.0f, 0.501f)));
EXPECT_EQ(4u, (FloatToIntLinear<3>(0.0f, 1.0f, 0.624f)));
EXPECT_EQ(5u, (FloatToIntLinear<3>(0.0f, 1.0f, 0.626f)));
EXPECT_EQ(5u, (FloatToIntLinear<3>(0.0f, 1.0f, 0.749f)));
EXPECT_EQ(6u, (FloatToIntLinear<3>(0.0f, 1.0f, 0.751f)));
EXPECT_EQ(6u, (FloatToIntLinear<3>(0.0f, 1.0f, 0.874f)));
EXPECT_EQ(7u, (FloatToIntLinear<3>(0.0f, 1.0f, 0.876f)));
}
// Tests IntToFloatLinear with values near or outside of its boundaries.
TEST(IntToFloatLinearTest, OutOfBounds) {
EXPECT_EQ(0.25f, (IntToFloatLinear<1>(0.0f, 1.0f, 0)));
EXPECT_EQ(0.75f, (IntToFloatLinear<1>(0.0f, 1.0f, 1)));
EXPECT_EQ(0.75f, (IntToFloatLinear<1>(0.0f, 1.0f, 2)));
EXPECT_EQ(0.75f, (IntToFloatLinear<1>(0.0f, 1.0f, 3)));
EXPECT_EQ(1.0f, (IntToFloatLinear<1>(0.0f, 4.0f, 0)));
EXPECT_EQ(3.0f, (IntToFloatLinear<1>(0.0f, 4.0f, 1)));
EXPECT_EQ(0.0625f, (IntToFloatLinear<3>(0.0f, 1.0f, 0)));
EXPECT_EQ(0.9375f, (IntToFloatLinear<3>(0.0f, 1.0f, 7)));
EXPECT_EQ(0.9375f, (IntToFloatLinear<3>(0.0f, 1.0f, 8)));
}
// Tests IntToFloatLinear with some specific values which are easy to calculate
// by hand.
TEST(IntToFloatLinearTest, Values) {
EXPECT_EQ(0.125f, (IntToFloatLinear<2>(0.0f, 1.0f, 0)));
EXPECT_EQ(0.375f, (IntToFloatLinear<2>(0.0f, 1.0f, 1)));
EXPECT_EQ(0.625f, (IntToFloatLinear<2>(0.0f, 1.0f, 2)));
EXPECT_EQ(0.875f, (IntToFloatLinear<2>(0.0f, 1.0f, 3)));
EXPECT_EQ(0.0625f, (IntToFloatLinear<3>(0.0f, 1.0f, 0)));
EXPECT_EQ(0.1875f, (IntToFloatLinear<3>(0.0f, 1.0f, 1)));
EXPECT_EQ(0.3125f, (IntToFloatLinear<3>(0.0f, 1.0f, 2)));
EXPECT_EQ(0.4375f, (IntToFloatLinear<3>(0.0f, 1.0f, 3)));
EXPECT_EQ(0.5625f, (IntToFloatLinear<3>(0.0f, 1.0f, 4)));
EXPECT_EQ(0.6875f, (IntToFloatLinear<3>(0.0f, 1.0f, 5)));
EXPECT_EQ(0.8125f, (IntToFloatLinear<3>(0.0f, 1.0f, 6)));
EXPECT_EQ(0.9375f, (IntToFloatLinear<3>(0.0f, 1.0f, 7)));
EXPECT_EQ(-0.875f, (IntToFloatLinear<2>(-1.0f, 0.0f, 0)));
EXPECT_EQ(-0.625f, (IntToFloatLinear<2>(-1.0f, 0.0f, 1)));
EXPECT_EQ(-0.375f, (IntToFloatLinear<2>(-1.0f, 0.0f, 2)));
EXPECT_EQ(-0.125f, (IntToFloatLinear<2>(-1.0f, 0.0f, 3)));
EXPECT_EQ(-0.75f, (IntToFloatLinear<2>(-1.0f, 1.0f, 0)));
EXPECT_EQ(-0.25f, (IntToFloatLinear<2>(-1.0f, 1.0f, 1)));
EXPECT_EQ(0.25f, (IntToFloatLinear<2>(-1.0f, 1.0f, 2)));
EXPECT_EQ(0.75f, (IntToFloatLinear<2>(-1.0f, 1.0f, 3)));
}
} // namespace testing
} // namespace aos