Keep the colleague's microbu-esp32c5 tree in this repository

obu-firmware builds against vanetza-idf from microbu-esp32c5/external, but
that tree was gitignored, so a clone of this repository could not build the
firmware it ships. It is now committed here as ordinary files in its own
folder, microbu-esp32c5/: the colleague's commit cf4b99f plus the V2X2MAP
bridge's signature verification (--trust) used on the bench. Nothing is
fetched from or pushed to the colleague's repository; this repository and
its remotes carry everything. The folder's own .gitignore keeps build output,
downloaded components and private key material out, as it did there; the
committed file set is identical to that repository's tracked files.

The ESP32-C5 is still flashed from obu-firmware/, which only takes
vanetza-idf from microbu-esp32c5/, so the two stay separate folders.
FLASHING.md says how to take a newer version of the colleague's tree (copy
it over the folder, rebuild, test, commit).
This commit is contained in:
Ashin Walpola
2026-09-23 17:46:40 +02:00
parent 2f60623e18
commit 0e9525162d
9881 changed files with 1582523 additions and 17 deletions
@@ -0,0 +1,15 @@
include(UseGTest)
configure_gtest_directory(LINK_LIBRARIES common)
add_gtest(BitNumber bit_number.cpp)
add_gtest(ByteBuffer byte_buffer.cpp)
add_gtest(ByteBufferSink byte_buffer_sink.cpp)
add_gtest(ByteBufferSource byte_buffer_source.cpp)
add_gtest(ByteOrder byte_order.cpp)
add_gtest(ByteView byte_view.cpp)
add_gtest(Hook hook.cpp)
add_gtest(LruCache lru_cache.cpp)
add_gtest(ObjectContainer object_container.cpp)
add_gtest(ManualRuntime manual_runtime.cpp)
add_gtest(UnitInterval unit_interval.cpp)
@@ -0,0 +1,48 @@
#include <gtest/gtest.h>
#include <vanetza/common/bit_number.hpp>
#include <cstdint>
using namespace vanetza;
TEST(BitNumber, ctor) {
BitNumber<uint32_t, 20> a;
EXPECT_EQ(a.raw(), 0);
BitNumber<uint32_t, 20> b(0x0fffff);
EXPECT_EQ(b.raw(), 0x0fffff);
}
TEST(BitNumber, mask) {
BitNumber<uint32_t, 20> a(0xf01234);
EXPECT_EQ(a.raw(), 0x1234);
BitNumber<uint32_t, 1> b(4);
EXPECT_EQ(b.raw(), 0);
b = 1;
EXPECT_EQ(b.raw(), 1);
}
TEST(BitNumber, equality) {
BitNumber<int8_t, 3> a;
BitNumber<int8_t, 3> b(0);
EXPECT_EQ(a, b);
a = 3;
EXPECT_NE(a, b);
}
TEST(BitNumber, less) {
BitNumber<uint16_t, 4> a(3);
BitNumber<uint16_t, 4> b(4);
EXPECT_LT(a, b);
EXPECT_LE(a, b);
EXPECT_GT(b, a);
a = 4;
EXPECT_LE(a, b);
EXPECT_GE(a, b);
b = 17; // 17 is masked to 1
EXPECT_LE(b, a);
}
@@ -0,0 +1,35 @@
#include <gtest/gtest.h>
#include <vanetza/common/byte_buffer.hpp>
#include <cstring>
using namespace vanetza;
struct A
{
char b[10];
};
TEST(ByteBuffer, buffer_cast) {
ByteBuffer buf = { 'A', ' ', 't', 'e', 's', 't', ' ', 'b', 'u', 'f', 'f', 'e', 'r' };
ASSERT_GE(buf.size(), sizeof(A));
A* a = buffer_cast<A>(buf);
ASSERT_NE(nullptr, a);
EXPECT_EQ(a->b[0], 'A');
EXPECT_EQ(a->b[4], 's');
EXPECT_EQ(a->b[9], 'f');
}
TEST(ByteBuffer, buffer_copy) {
A a;
strcpy(a.b, "123456789");
auto copy = buffer_copy(a);
ASSERT_EQ(copy.size(), 10);
EXPECT_EQ(copy[0], '1');
EXPECT_EQ(copy[3], '4');
EXPECT_EQ(copy[8], '9');
EXPECT_EQ(copy[9], '\0');
a.b[0] = 'X';
EXPECT_EQ(copy[0], '1');
}
@@ -0,0 +1,29 @@
#include <gtest/gtest.h>
#include <vanetza/common/byte_buffer_sink.hpp>
#include <boost/iostreams/stream_buffer.hpp>
#include <ostream>
#include <string>
using namespace vanetza;
TEST(ByteBufferSink, write) {
ByteBuffer buf;
byte_buffer_sink sink(buf);
boost::iostreams::stream_buffer<byte_buffer_sink> stream(sink);
ASSERT_TRUE(buf.empty());
std::ostream os(&stream);
ASSERT_TRUE(os.good());
const std::string data("Hello World!");
os << data;
os.flush();
EXPECT_EQ(buf.size(), 12);
for (unsigned i = 0; i < buf.size(); ++i) {
EXPECT_EQ(buf[i], data[i]);
}
EXPECT_TRUE(os.good());
}
@@ -0,0 +1,29 @@
#include <gtest/gtest.h>
#include <vanetza/common/byte_buffer_source.hpp>
#include <boost/iostreams/stream_buffer.hpp>
#include <istream>
using namespace vanetza;
TEST(ByteBufferSource, read) {
const ByteBuffer buf = { 0x01, 0x11, 0x12, 0x22, 0x23, 0x33, 0x34, 0x44 };
byte_buffer_source source(buf);
boost::iostreams::stream_buffer<byte_buffer_source> stream(source);
std::istream is(&stream);
ASSERT_TRUE(is.good());
char read = '\0';
unsigned read_bytes = 0;
for (uint8_t byte : buf) {
is >> read;
EXPECT_NE(byte, '\0');
EXPECT_EQ(byte, read);
++read_bytes;
}
EXPECT_EQ(read_bytes, 8);
is >> read;
EXPECT_TRUE(is.eof());
}
@@ -0,0 +1,48 @@
#include <gtest/gtest.h>
#include <vanetza/common/byte_order.hpp>
#include <sstream>
using namespace vanetza;
using le_type = EndianType<uint32_t, ByteOrder::LittleEndian>;
using be_type = EndianType<uint32_t, ByteOrder::BigEndian>;
TEST(ByteOrder, equality)
{
EndianType<int, ByteOrder::BigEndian> a(3);
EndianType<int, ByteOrder::BigEndian> b(3);
EXPECT_EQ(a, b);
a = host_cast(static_cast<int>(4));
EXPECT_NE(a, b);
}
TEST(ByteOrder, access)
{
le_type a = host_cast<uint32_t>(0x12345678);
be_type b = host_cast<uint32_t>(0x12345678);
EXPECT_NE(a.get(), b.get());
EXPECT_EQ(a.net(), b.net());
EXPECT_EQ(a.host(), b.host());
}
TEST(ByteOrder, less)
{
uint8be_t a { 3 };
uint8be_t b { 5 };
uint8be_t c { 5 };
EXPECT_TRUE(a < b);
EXPECT_FALSE(b < c);
EXPECT_FALSE(b < a);
}
TEST(ByteOrder, hash)
{
le_type a = host_cast<uint32_t>(0x12345678);
be_type b = host_cast<uint32_t>(0x12345678);
be_type c = host_cast<uint32_t>(0x78563412);
EXPECT_EQ(std::hash<le_type>()(a), std::hash<le_type>()(a));
EXPECT_EQ(std::hash<be_type>()(b), std::hash<be_type>()(b));
EXPECT_NE(std::hash<be_type>()(b), std::hash<be_type>()(c));
}
@@ -0,0 +1,28 @@
#include <gtest/gtest.h>
#include <vanetza/common/byte_view.hpp>
#include <vanetza/common/byte_buffer_convertible.hpp>
using namespace vanetza;
TEST(ByteView, range_buffer) {
ByteBuffer buffer = {1, 2, 3, 4, 5, 6, 7, 8};
byte_view_range view = create_byte_view(buffer);
ASSERT_EQ(buffer.size(), view.size());
EXPECT_EQ(1, *view.begin());
EXPECT_EQ(3, view[2]);
}
TEST(ByteView, range_convertible) {
byte_view_range view = create_byte_view(ByteBuffer());
{
std::string buffer = "temporary data";
ByteBufferConvertible convertible { std::move(buffer) };
// view should now own a byte buffer copy of original string
view = create_byte_view(convertible);
}
ASSERT_EQ(14, view.size());
EXPECT_EQ('t', view[0]);
EXPECT_EQ('y', view[8]);
EXPECT_EQ('d', view[10]);
}
@@ -0,0 +1,57 @@
#include <gtest/gtest.h>
#include <vanetza/common/hook.hpp>
#include <string>
#include <vector>
using namespace vanetza;
TEST(Hook, variants) {
Hook<int> hook_int;
hook_int(28); // rvalue call
int x = 29;
hook_int(x); // lvalue (exact type)
int& y = x;
hook_int(y); // lvalue (compatible type)
Hook<double, float> hook_fp;
hook_fp(23.0, -42.0f);
Hook<const std::string&, std::vector<int>> hook_objects;
hook_objects("foo", {3, 2});
Hook<std::string&&> hook_rvalue_ref;
hook_rvalue_ref("bar");
}
TEST(Hook, invocation) {
Hook<double, float> hook;
double d = 3.0;
float f = 5.3f;
// empty hook does nothing
hook(0.0, 1.0f);
EXPECT_EQ(3.0, d);
EXPECT_EQ(5.3f, f);
// set hook and test it's magic
hook = [&d, &f](double _d, float _f) { d = _d; f = _f; };
hook(23.1, -384.34f);
EXPECT_EQ(23.1, d);
EXPECT_EQ(-384.34f, f);
// reset hook and it should do nothing again
hook.reset();
hook(0.0, 3.33f);
EXPECT_EQ(23.1, d);
EXPECT_EQ(-384.34f, f);
}
TEST(HookRegistry, registration) {
Hook<double> hook;
HookRegistry<double> registry(hook);
double d = 42.0;
registry = [&d](double _d) { d = _d; };
hook(21.0);
EXPECT_EQ(21.0, d);
}
@@ -0,0 +1,82 @@
#include <gtest/gtest.h>
#include <vanetza/common/lru_cache.hpp>
using namespace vanetza;
class LruCacheTest : public ::testing::Test
{
protected:
void SetUp() override
{
generator_calls = 0;
last_key = 0;
}
std::function<int(int)> generator()
{
return [this](int key) {
++generator_calls;
last_key = key;
return ~key;
};
}
unsigned generator_calls;
int last_key;
};
TEST_F(LruCacheTest, caching)
{
LruCache<int, int> cache(generator(), 5);
// generate one new entry
EXPECT_EQ(~8, cache[8]);
EXPECT_EQ(1, generator_calls);
// refer to cached entry
EXPECT_EQ(~8, cache[8]);
EXPECT_EQ(1, generator_calls);
// further entry
EXPECT_EQ(~4, cache[4]);
EXPECT_EQ(2, generator_calls);
// first entry is still there
EXPECT_EQ(~8, cache[8]);
EXPECT_EQ(2, generator_calls);
}
TEST_F(LruCacheTest, modify)
{
LruCache<int, int> cache(generator(), 5);
// modify new cache entry
cache[8] = 23;
EXPECT_EQ(23, cache[8]);
// modify existing entry
cache[8] = 42;
EXPECT_EQ(42, cache[8]);
EXPECT_EQ(1, generator_calls);
}
TEST_F(LruCacheTest, drop_lru)
{
LruCache<int, int> cache(generator(), 3);
cache[1];
cache[2];
cache[3];
EXPECT_EQ(3, generator_calls);
EXPECT_EQ(~2, cache[2]); // LRU: 1, 3, 2
cache[4]; // drop 1, LRU: 3, 2, 4
cache[1]; // re-create entry, LRU: 2, 4, 1
EXPECT_EQ(5, generator_calls);
EXPECT_EQ(~2, cache[2]);
EXPECT_EQ(~4, cache[4]);
EXPECT_EQ(~1, cache[1]);
EXPECT_EQ(5, generator_calls);
}
@@ -0,0 +1,199 @@
#include <gtest/gtest.h>
#include <vanetza/common/manual_runtime.hpp>
#include <chrono>
#include <functional>
#include <string>
#include <vector>
using namespace vanetza;
using std::chrono::hours;
using std::chrono::minutes;
using std::chrono::seconds;
TEST(ManualRuntime, default_construction)
{
ManualRuntime r;
EXPECT_EQ(std::chrono::milliseconds(0), r.now().time_since_epoch());
}
TEST(ManualRuntime, time_progress_absolute)
{
ManualRuntime r;
const Clock::time_point t1 { hours(27) };
r.trigger(t1);
EXPECT_EQ(t1, r.now());
const Clock::time_point t2 { hours(28) };
r.trigger(t2);
EXPECT_EQ(t2, r.now());
}
TEST(ManualRuntime, time_progress_relative)
{
ManualRuntime r;
r.trigger(hours(3));
EXPECT_EQ(Clock::time_point { hours(3) }, r.now());
r.trigger(hours(2));
EXPECT_EQ(Clock::time_point { hours(5) }, r.now());
}
TEST(ManualRuntime, sorting)
{
ManualRuntime r;
r.trigger(hours(3));
EXPECT_EQ(Clock::time_point::max(), r.next());
auto cb = [](Clock::time_point) {};
const auto tp1 = Clock::time_point { hours(2) };
static_cast<Runtime*>(&r)->schedule(tp1, cb);
EXPECT_EQ(tp1, r.next());
r.schedule(Clock::time_point { hours(3) }, cb);
EXPECT_EQ(tp1, r.next());
const auto tp2 = Clock::time_point { hours(1) };
r.schedule(tp2, cb);
EXPECT_EQ(tp2, r.next());
r.schedule(minutes(30), cb);
EXPECT_EQ(tp2, r.next());
}
TEST(ManualRuntime, scheduling)
{
ManualRuntime r;
r.trigger(hours(5));
namespace ph = std::placeholders;
std::string seq;
std::vector<Clock::time_point> deadlines;
auto cb = [&seq, &deadlines](const char* str, Clock::time_point deadline) {
deadlines.push_back(deadline);
seq.append(str);
};
r.schedule(hours(10), std::bind<void>(cb, "1", ph::_1));
r.schedule(hours(11), std::bind<void>(cb, "2", ph::_1));
r.schedule(hours(11), std::bind<void>(cb, "2", ph::_1));
r.schedule(hours(5), std::bind<void>(cb, "3", ph::_1));
r.trigger(hours(4));
EXPECT_EQ("", seq);
r.trigger(hours(1));
EXPECT_EQ("3", seq);
r.trigger(hours(5));
EXPECT_EQ("31", seq);
// schedule expired callback (immediate invocation at next trigger)
r.schedule(Clock::time_point { hours(2) }, std::bind<void>(cb, "4", ph::_1));
r.trigger(hours(0));
EXPECT_EQ("314", seq);
r.trigger(hours(5));
EXPECT_EQ("31422", seq);
r.trigger(Clock::time_point::max());
EXPECT_EQ("31422", seq);
const std::vector<Clock::time_point> expected_deadlines = {
Clock::time_point { hours(10) },
Clock::time_point { hours(15) },
Clock::time_point { hours(2) },
Clock::time_point { hours(16) },
Clock::time_point { hours(16) },
};
EXPECT_EQ(expected_deadlines, deadlines);
}
TEST(ManualRuntime, reset)
{
ManualRuntime r;
unsigned calls = 0;
auto cb = [&calls](Clock::time_point) { ++calls; };
r.trigger(hours(23));
for (unsigned i = 10; i < 100; ++i) {
r.schedule(seconds(i), cb);
}
r.trigger(seconds(9));
EXPECT_EQ(0, calls);
r.trigger(seconds(2));
EXPECT_EQ(2, calls);
EXPECT_EQ(Clock::time_point { hours(23) + seconds(11) }, r.now());
r.reset(Clock::time_point { hours(10) });
EXPECT_EQ(Clock::time_point { hours(10) }, r.now());
EXPECT_EQ(90, calls);
r.trigger(Clock::duration::max());
EXPECT_EQ(90, calls);
}
TEST(ManualRuntime, cancel)
{
ManualRuntime r;
std::vector<char> calls;
auto cb = [&calls](char c, Clock::time_point) { calls.push_back(c); };
// some dummy scopes
const int foo = 1;
const int bar = 2;
const int doe = 3;
namespace ph = std::placeholders;
r.schedule(minutes(3), std::bind<void>(cb, 'a', ph::_1));
r.schedule(minutes(4), std::bind<void>(cb, 'b', ph::_1), &foo);
r.schedule(minutes(5), std::bind<void>(cb, 'c', ph::_1));
r.schedule(minutes(3), std::bind<void>(cb, 'd', ph::_1), &bar);
r.schedule(minutes(4), std::bind<void>(cb, 'e', ph::_1));
r.schedule(minutes(5), std::bind<void>(cb, 'f', ph::_1), &foo);
r.schedule(minutes(6), std::bind<void>(cb, 'g', ph::_1), &doe);
r.schedule(minutes(7), std::bind<void>(cb, 'h', ph::_1), nullptr);
// cancel single callback
r.cancel(&bar);
r.trigger(minutes(8));
EXPECT_EQ((std::vector<char> {'a', 'b', 'e', 'c', 'f', 'g', 'h'}), calls);
// cancel several callbacks
calls.clear();
r.schedule(minutes(1), std::bind<void>(cb, 'a', ph::_1), &foo);
r.schedule(minutes(1), std::bind<void>(cb, 'b', ph::_1), &bar);
r.schedule(minutes(1), std::bind<void>(cb, 'c', ph::_1), &bar);
r.schedule(minutes(1), std::bind<void>(cb, 'd', ph::_1), &foo);
r.cancel(&foo);
r.trigger(minutes(1));
EXPECT_EQ((std::vector<char> {'b', 'c'}), calls);
}
TEST(ManualRuntime, scope)
{
ManualRuntime r;
std::vector<char> calls;
auto cb = [&calls](char c, Clock::time_point) { calls.push_back(c); };
int scope1, scope2;
namespace ph = std::placeholders;
r.schedule(minutes(3), std::bind<void>(cb, 'a', ph::_1), &scope1);
r.schedule(minutes(1), std::bind<void>(cb, 'b', ph::_1), &scope2);
r.schedule(minutes(2), std::bind<void>(cb, 'c', ph::_1));
r.schedule(minutes(5), std::bind<void>(cb, 'd', ph::_1), &scope1);
r.schedule(minutes(4), std::bind<void>(cb, 'e', ph::_1), &scope2);
r.schedule(minutes(6), std::bind<void>(cb, 'f', ph::_1), "");
// cancel scope 1 and trigger all callbacks within 3 minutes
r.cancel(&scope1);
r.trigger(minutes(3));
EXPECT_EQ((std::vector<char> {'b', 'c'}), calls);
calls.clear();
// canceling nullptr scope has no effect
r.cancel(nullptr);
r.trigger(minutes(10));
EXPECT_EQ((std::vector<char> {'e', 'f'}), calls);
}
@@ -0,0 +1,117 @@
#include <gtest/gtest.h>
#include <vanetza/common/object_container.hpp>
using namespace vanetza;
struct ObjectA
{
int a = 1;
};
struct ObjectB
{
int b = 2;
};
struct ObjectC
{
int c = 3;
};
template<typename T>
std::unique_ptr<T> create_unique()
{
return std::unique_ptr<T> { new T() };
}
TEST(ObjectContainer, size)
{
ObjectContainer c;
EXPECT_EQ(0, c.size());
c.insert(create_unique<ObjectA>());
EXPECT_EQ(1, c.size());
c.insert(create_unique<ObjectA>());
EXPECT_EQ(1, c.size());
c.insert(create_unique<ObjectB>());
EXPECT_EQ(2, c.size());
c.clear();
EXPECT_EQ(0, c.size());
}
TEST(ObjectContainer, insert)
{
ObjectContainer c;
EXPECT_TRUE(c.insert(create_unique<ObjectA>()));
EXPECT_FALSE(c.insert(create_unique<ObjectA>()));
EXPECT_TRUE(c.insert(create_unique<ObjectB>()));
}
TEST(ObjectContainer, find)
{
ObjectContainer c;
EXPECT_EQ(nullptr, c.find<ObjectA>());
auto a = create_unique<ObjectA>();
ObjectA* pa = a.get();
auto b = create_unique<ObjectB>();
ObjectB* pb = b.get();
c.insert(std::move(a));
c.insert(std::move(b));
EXPECT_EQ(pa, c.find<ObjectA>());
EXPECT_EQ(pb, c.find<ObjectB>());
}
TEST(ObjectContainer, erase)
{
ObjectContainer c;
c.insert(create_unique<ObjectA>());
ASSERT_EQ(1, c.size());
c.erase<ObjectB>();
EXPECT_EQ(1, c.size());
c.erase<ObjectA>();
EXPECT_EQ(0, c.size());
c.insert(create_unique<ObjectA>());
c.insert(create_unique<ObjectB>());
c.insert(create_unique<ObjectC>());
c.erase<ObjectB>();
EXPECT_EQ(2, c.size());
EXPECT_NE(nullptr, c.find<ObjectA>());
EXPECT_EQ(nullptr, c.find<ObjectB>());
EXPECT_NE(nullptr, c.find<ObjectC>());
}
TEST(ObjectContainer, move)
{
ObjectContainer c1;
c1.insert(create_unique<ObjectA>());
c1.insert(create_unique<ObjectB>());
c1.insert(create_unique<ObjectC>());
ASSERT_EQ(3, c1.size());
auto* pa = c1.find<ObjectA>();
auto* pb = c1.find<ObjectB>();
auto* pc = c1.find<ObjectC>();
ObjectContainer c2 = std::move(c1);
EXPECT_EQ(0, c1.size());
EXPECT_EQ(3, c2.size());
EXPECT_EQ(pa, c2.find<ObjectA>());
EXPECT_EQ(pb, c2.find<ObjectB>());
EXPECT_EQ(pc, c2.find<ObjectC>());
}
TEST(ObjectContainer, get)
{
ObjectContainer c;
EXPECT_EQ(nullptr, c.find<ObjectA>());
ObjectA& a = c.get<ObjectA>();
EXPECT_EQ(1, a.a);
}
@@ -0,0 +1,168 @@
#include <gtest/gtest.h>
#include <vanetza/common/unit_interval.hpp>
using namespace vanetza;
namespace vanetza {
void PrintTo(const UnitInterval& cl, std::ostream* os) { *os << cl.value(); }
}
TEST(UnitInterval, construction)
{
UnitInterval v1;
EXPECT_DOUBLE_EQ(0.0, v1.value());
UnitInterval v2(0.42);
EXPECT_DOUBLE_EQ(0.42, v2.value());
UnitInterval v3 = v2;
EXPECT_DOUBLE_EQ(0.42, v3.value());
v3 = v1;
EXPECT_DOUBLE_EQ(0.0, v3.value());
}
TEST(UnitInterval, partially_ordered)
{
// only test < and == (other operators are provided by Boost)
EXPECT_LT(UnitInterval(0.3), UnitInterval(0.4));
EXPECT_EQ(UnitInterval(0.5), UnitInterval(0.5));
// stress equality comparison
UnitInterval v1 { 0.0000001 };
UnitInterval v2 { 0.00000005 };
EXPECT_EQ(v1 * 1000000, v2 * 2000000);
EXPECT_NE(UnitInterval(0.000000001), UnitInterval(0.0000000011));
}
TEST(UnitInterval, range)
{
UnitInterval v1 { 3.14 };
EXPECT_EQ(UnitInterval(1.0), v1);
UnitInterval v2 { -42.0 };
EXPECT_EQ(UnitInterval(0.0), v2);
}
TEST(UnitInterval, arithmetic_interval)
{
// only test +=, -=, *=, /= (symmetric operators by Boost)
UnitInterval a1(0.45);
a1 += UnitInterval(0.53);
EXPECT_EQ(UnitInterval(0.98), a1);
UnitInterval a2(0.45);
a2 += UnitInterval(0.6);
EXPECT_EQ(UnitInterval(1.0), a2);
UnitInterval s1(0.45);
s1 -= UnitInterval(0.35);
EXPECT_EQ(UnitInterval(0.1), s1);
UnitInterval s2(0.3);
s2 -= UnitInterval(0.4);
EXPECT_EQ(UnitInterval(0.0), s2);
UnitInterval m1(0.2);
m1 *= UnitInterval(0.5);
EXPECT_EQ(UnitInterval(0.1), m1);
UnitInterval m2(0.4);
m2 *= UnitInterval(0.0);
EXPECT_EQ(UnitInterval(0.0), m2);
UnitInterval m3(1.0);
m3 *= UnitInterval(1.0);
EXPECT_EQ(UnitInterval(1.0), m3);
UnitInterval d1(0.6);
d1 /= UnitInterval(0.8);
EXPECT_EQ(UnitInterval(0.75), d1);
UnitInterval d2(0.5);
d2 /= UnitInterval(0.1);
EXPECT_EQ(UnitInterval(1.0), d2);
}
TEST(UnitInterval, arithmetic_double)
{
// only test +=, -=, *=, /= (symmetric operators by Boost)
UnitInterval a1(0.45);
a1 += 0.53;
EXPECT_EQ(UnitInterval(0.98), a1);
UnitInterval a2(0.45);
a2 += 0.6;
EXPECT_EQ(UnitInterval(1.0), a2);
UnitInterval a3(0.45);
a3 += -0.7;
EXPECT_EQ(UnitInterval(0.0), a3);
UnitInterval s1(0.45);
s1 -= 0.35;
EXPECT_EQ(UnitInterval(0.1), s1);
UnitInterval s2(0.3);
s2 -= 0.4;
EXPECT_EQ(UnitInterval(0.0), s2);
UnitInterval s3(0.3);
s3 -= -0.8;
EXPECT_EQ(UnitInterval(1.0), s3);
UnitInterval m1(0.2);
m1 *= 0.5;
EXPECT_EQ(UnitInterval(0.1), m1);
UnitInterval m2(0.4);
m2 *= 0.0;
EXPECT_EQ(UnitInterval(0.0), m2);
UnitInterval m3(1.0);
m3 *= 1.2;
EXPECT_EQ(UnitInterval(1.0), m3);
UnitInterval m4(0.3);
m4 *= -0.1;
EXPECT_EQ(UnitInterval(0.0), m4);
UnitInterval d1(0.6);
d1 /= 0.8;
EXPECT_EQ(UnitInterval(0.75), d1);
UnitInterval d2(0.5);
d2 /= 0.1;
EXPECT_EQ(UnitInterval(1.0), d2);
UnitInterval d3(0.2);
d3 /= 2.0;
EXPECT_EQ(UnitInterval(0.1), d3);
UnitInterval d4(0.5);
d4 /= -0.4;
EXPECT_EQ(UnitInterval(0.0), d4);
}
TEST(UnitInterval, complement)
{
EXPECT_EQ(UnitInterval(0.0), UnitInterval(1.0).complement());
EXPECT_EQ(UnitInterval(1.0), UnitInterval(0.0).complement());
EXPECT_EQ(UnitInterval(1.0), UnitInterval(0.67) + UnitInterval(0.67).complement());
}
TEST(UnitInterval, mean)
{
EXPECT_EQ(UnitInterval(0.3), mean(UnitInterval(0.1), UnitInterval(0.5)));
EXPECT_EQ(UnitInterval(0.0), mean(UnitInterval(0.0), UnitInterval(0.0)));
EXPECT_EQ(UnitInterval(0.75), mean(UnitInterval(1.0), UnitInterval(0.5)));
}
TEST(UnitInterval, mean_range)
{
UnitInterval a[3] = { UnitInterval (0.4), UnitInterval(0.2), UnitInterval(0.9) };
EXPECT_EQ(UnitInterval(0.0), mean(a, a));
EXPECT_EQ(UnitInterval(0.2), mean(a + 1, a + 2));
EXPECT_EQ(UnitInterval(0.3), mean(a, a + 2 ));
EXPECT_EQ(UnitInterval(0.5), mean(a, a + 3));
}