Add extracted tools: CitrineOS, OpenOCPP, ShapeShifter

- CitrineOS core extracted (CSMS OCPP 2.0.1)
- OpenOCPP extracted (firmware OCPP 1.6J/2.0.1)
- ShapeShifter library installed (pip install -e)
- ShapeShifter specification extracted
- EVerest extracted

TODO updated with progress
This commit is contained in:
Eric F
2026-06-08 00:38:27 -04:00
parent 468cfeaa50
commit d398a6ced2
7326 changed files with 1177561 additions and 7 deletions

View File

@@ -0,0 +1,647 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2026 Pionix GmbH and Contributors to EVerest
#include <everest/util/vector/fixed_vector.hpp>
#include <gtest/gtest.h>
#include <memory>
#include <string>
using namespace everest::lib::util;
TEST(FixedVectorTest, BasicInt) {
fixed_vector<int, 10> vec;
EXPECT_TRUE(vec.empty());
EXPECT_EQ(vec.size(), 0);
vec.push_back(1);
vec.push_back(2);
vec.push_back(3);
EXPECT_FALSE(vec.empty());
EXPECT_EQ(vec.size(), 3);
EXPECT_EQ(vec[0], 1);
EXPECT_EQ(vec[1], 2);
EXPECT_EQ(vec[2], 3);
EXPECT_EQ(vec.at(1), 2);
int count = 1;
for (const auto& val : vec) {
EXPECT_EQ(val, count++);
}
vec.clear();
EXPECT_TRUE(vec.empty());
EXPECT_EQ(vec.size(), 0);
}
TEST(FixedVectorTest, StringAndMove) {
fixed_vector<std::string, 5> vec;
vec.push_back("hello");
std::string s = "world";
vec.push_back(std::move(s));
EXPECT_EQ(vec.size(), 2);
EXPECT_EQ(vec[0], "hello");
EXPECT_EQ(vec[1], "world");
// Note: The state of a moved-from string is valid but unspecified.
// In many implementations it is empty, but we shouldn't rely on it.
// EXPECT_TRUE(s.empty());
vec.emplace_back(5, 'c');
EXPECT_EQ(vec.size(), 3);
EXPECT_EQ(vec[2], "ccccc");
}
TEST(FixedVectorTest, Capacity) {
fixed_vector<int, 3> vec;
vec.push_back(1);
vec.push_back(2);
vec.push_back(3);
EXPECT_EQ(vec.size(), 3);
EXPECT_THROW(vec.push_back(4), std::length_error);
EXPECT_THROW(vec.emplace_back(5), std::length_error);
}
TEST(FixedVectorTest, AtThrows) {
fixed_vector<int, 5> vec;
vec.push_back(1);
EXPECT_THROW(vec.at(1), std::out_of_range);
const auto& cvec = vec;
EXPECT_THROW(cvec.at(1), std::out_of_range);
}
TEST(FixedVectorTest, Erase) {
fixed_vector<int, 10> vec;
for (int i = 0; i < 10; ++i) {
vec.push_back(i);
}
// erase first
auto it = vec.erase(vec.begin());
EXPECT_EQ(*it, 1);
EXPECT_EQ(vec.size(), 9);
EXPECT_EQ(vec[0], 1);
EXPECT_EQ(vec[8], 9);
// erase last
it = vec.erase(vec.end() - 1);
EXPECT_EQ(it, vec.end());
EXPECT_EQ(vec.size(), 8);
EXPECT_EQ(vec[7], 8);
// erase middle
it = vec.erase(vec.begin() + 3); // erase '4' from {1,2,3,4,5,6,7,8}
EXPECT_EQ(*it, 5);
EXPECT_EQ(vec.size(), 7);
EXPECT_EQ(vec[0], 1);
EXPECT_EQ(vec[1], 2);
EXPECT_EQ(vec[2], 3);
EXPECT_EQ(vec[3], 5);
}
TEST(FixedVectorTest, EraseRange) {
fixed_vector<int, 10> vec;
for (int i = 0; i < 10; ++i) {
vec.push_back(i);
}
// erase range in the middle
auto it = vec.erase(vec.begin() + 2, vec.begin() + 5); // erase 2, 3, 4
EXPECT_EQ(*it, 5);
EXPECT_EQ(vec.size(), 7);
EXPECT_EQ(vec[0], 0);
EXPECT_EQ(vec[1], 1);
EXPECT_EQ(vec[2], 5);
EXPECT_EQ(vec[3], 6);
EXPECT_EQ(vec[6], 9);
}
TEST(FixedVectorTest, MoveOnlyType) {
fixed_vector<std::unique_ptr<int>, 5> vec;
vec.emplace_back(std::make_unique<int>(1));
vec.push_back(std::make_unique<int>(2));
EXPECT_EQ(vec.size(), 2);
EXPECT_EQ(*vec[0], 1);
EXPECT_EQ(*vec[1], 2);
vec.erase(vec.begin());
EXPECT_EQ(vec.size(), 1);
EXPECT_EQ(*vec[0], 2);
}
struct DestructorCheck {
static int destructor_calls;
DestructorCheck() = default;
~DestructorCheck() {
destructor_calls++;
}
};
int DestructorCheck::destructor_calls = 0;
TEST(FixedVectorTest, DestructorCalledOnClear) {
DestructorCheck::destructor_calls = 0;
fixed_vector<DestructorCheck, 5> vec;
vec.emplace_back();
vec.emplace_back();
vec.emplace_back();
EXPECT_EQ(DestructorCheck::destructor_calls, 0);
vec.clear();
EXPECT_EQ(DestructorCheck::destructor_calls, 3);
vec.clear();
EXPECT_EQ(DestructorCheck::destructor_calls, 3);
}
TEST(FixedVectorTest, DestructorCalledOnErase) {
DestructorCheck::destructor_calls = 0;
fixed_vector<DestructorCheck, 5> vec;
vec.emplace_back();
vec.emplace_back();
vec.emplace_back();
EXPECT_EQ(DestructorCheck::destructor_calls, 0);
vec.erase(vec.begin());
EXPECT_EQ(DestructorCheck::destructor_calls, 1);
vec.erase(vec.begin(), vec.end());
EXPECT_EQ(DestructorCheck::destructor_calls, 3);
}
TEST(FixedVectorTest, DestructorCalledOnDestruction) {
DestructorCheck::destructor_calls = 0;
{
fixed_vector<DestructorCheck, 5> vec;
vec.emplace_back();
vec.emplace_back();
EXPECT_EQ(DestructorCheck::destructor_calls, 0);
}
EXPECT_EQ(DestructorCheck::destructor_calls, 2);
}
TEST(FixedVectorTest, CopyConstructor) {
fixed_vector<int, 5> original;
original.push_back(1);
original.push_back(2);
fixed_vector<int, 5> copy = original;
EXPECT_EQ(copy.size(), 2);
EXPECT_EQ(copy[0], 1);
EXPECT_EQ(copy[1], 2);
// Ensure original is untouched
EXPECT_EQ(original.size(), 2);
EXPECT_EQ(original[0], 1);
}
TEST(FixedVectorTest, CopyAssignment) {
fixed_vector<int, 5> original;
original.push_back(1);
original.push_back(2);
fixed_vector<int, 5> copy;
copy.push_back(99);
copy = original;
EXPECT_EQ(copy.size(), 2);
EXPECT_EQ(copy[0], 1);
EXPECT_EQ(copy[1], 2);
// Ensure original is untouched
EXPECT_EQ(original.size(), 2);
}
TEST(FixedVectorTest, CopyAssignmentEdgeCases) {
// Case 1: Destination is larger than source
fixed_vector<DestructorCheck, 5> dest1;
dest1.emplace_back();
dest1.emplace_back();
dest1.emplace_back();
fixed_vector<DestructorCheck, 5> source1;
source1.emplace_back();
source1.emplace_back();
DestructorCheck::destructor_calls = 0;
dest1 = source1;
EXPECT_EQ(dest1.size(), 2);
EXPECT_EQ(DestructorCheck::destructor_calls, 1); // One surplus element should have been destroyed
// Case 2: Destination is smaller than source
fixed_vector<int, 5> dest2;
dest2.push_back(1);
fixed_vector<int, 5> source2;
source2.push_back(10);
source2.push_back(20);
dest2 = source2;
EXPECT_EQ(dest2.size(), 2);
EXPECT_EQ(dest2[0], 10);
EXPECT_EQ(dest2[1], 20);
// Case 3: Sizes are equal
fixed_vector<int, 5> dest3;
dest3.push_back(1);
dest3.push_back(2);
fixed_vector<int, 5> source3;
source3.push_back(10);
source3.push_back(20);
dest3 = source3;
EXPECT_EQ(dest3.size(), 2);
EXPECT_EQ(dest3[0], 10);
EXPECT_EQ(dest3[1], 20);
// Case 4: Self-assignment
fixed_vector<int, 5> self_assign;
self_assign.push_back(123);
self_assign = self_assign;
EXPECT_EQ(self_assign.size(), 1);
EXPECT_EQ(self_assign[0], 123);
}
TEST(FixedVectorTest, MoveConstructor) {
fixed_vector<std::string, 5> original;
original.push_back("a");
original.push_back("b");
fixed_vector<std::string, 5> moved = std::move(original);
EXPECT_EQ(moved.size(), 2);
EXPECT_EQ(moved[0], "a");
EXPECT_TRUE(original.empty());
}
TEST(FixedVectorTest, MoveAssignment) {
fixed_vector<std::string, 5> original;
original.push_back("a");
original.push_back("b");
fixed_vector<std::string, 5> moved;
moved.push_back("c");
moved = std::move(original);
EXPECT_EQ(moved.size(), 2);
EXPECT_EQ(moved[0], "a");
EXPECT_TRUE(original.empty());
}
TEST(FixedVectorTest, ZeroCapacity) {
fixed_vector<int, 0> vec;
EXPECT_TRUE(vec.empty());
EXPECT_EQ(vec.size(), 0);
EXPECT_EQ(vec.capacity(), 0);
EXPECT_THROW(vec.push_back(1), std::length_error);
}
TEST(FixedVectorTest, FrontAndBack) {
fixed_vector<int, 3> vec;
vec.push_back(10);
vec.push_back(20);
EXPECT_EQ(vec.front(), 10);
EXPECT_EQ(vec.back(), 20);
vec.front() = 11;
EXPECT_EQ(vec[0], 11);
const auto& cvec = vec;
EXPECT_EQ(cvec.front(), 11);
EXPECT_EQ(cvec.back(), 20);
}
TEST(FixedVectorTest, ReverseIteration) {
fixed_vector<int, 3> vec;
vec.push_back(1);
vec.push_back(2);
vec.push_back(3);
int expected = 3;
for (auto it = vec.rbegin(); it != vec.rend(); ++it) {
EXPECT_EQ(*it, expected--);
}
const auto& cvec = vec;
expected = 3;
for (auto it = cvec.rbegin(); it != cvec.rend(); ++it) {
EXPECT_EQ(*it, expected--);
}
}
TEST(FixedVectorTest, EraseEdgeCases) {
fixed_vector<int, 5> vec;
vec.push_back(1);
vec.push_back(2);
vec.push_back(3);
vec.push_back(4);
// Erase empty range
auto it = vec.erase(vec.begin() + 1, vec.begin() + 1);
EXPECT_EQ(vec.size(), 4);
EXPECT_EQ(*it, 2);
// Erase to the end
it = vec.erase(vec.begin() + 2, vec.end());
EXPECT_EQ(vec.size(), 2);
EXPECT_EQ(it, vec.end());
EXPECT_EQ(vec[0], 1);
EXPECT_EQ(vec[1], 2);
// Erase everything
it = vec.erase(vec.begin(), vec.end());
EXPECT_TRUE(vec.empty());
EXPECT_EQ(it, vec.end());
}
TEST(FixedVectorTest, TryEmplaceBack) {
fixed_vector<int, 3> vec;
auto* elem1 = vec.try_emplace_back(10);
ASSERT_NE(elem1, nullptr);
EXPECT_EQ(*elem1, 10);
EXPECT_EQ(vec.size(), 1);
EXPECT_EQ(vec[0], 10);
vec.try_emplace_back(20);
vec.try_emplace_back(30);
EXPECT_EQ(vec.size(), 3);
// Vector is full
auto* elem4 = vec.try_emplace_back(40);
EXPECT_EQ(elem4, nullptr);
EXPECT_EQ(vec.size(), 3);
}
TEST(FixedVectorTest, PopBack) {
fixed_vector<int, 5> vec;
vec.push_back(1);
vec.push_back(2);
vec.push_back(3);
EXPECT_EQ(vec.size(), 3);
EXPECT_EQ(vec.back(), 3);
vec.pop_back();
EXPECT_EQ(vec.size(), 2);
EXPECT_EQ(vec.back(), 2);
vec.pop_back();
EXPECT_EQ(vec.size(), 1);
EXPECT_EQ(vec.back(), 1);
vec.pop_back();
EXPECT_TRUE(vec.empty());
EXPECT_EQ(vec.size(), 0);
// Popping from an empty vector should be a no-op
vec.pop_back();
EXPECT_TRUE(vec.empty());
EXPECT_EQ(vec.size(), 0);
// Test with DestructorCheck
DestructorCheck::destructor_calls = 0;
fixed_vector<DestructorCheck, 5> vec_dc;
vec_dc.emplace_back();
vec_dc.emplace_back();
vec_dc.emplace_back();
EXPECT_EQ(DestructorCheck::destructor_calls, 0);
vec_dc.pop_back();
EXPECT_EQ(DestructorCheck::destructor_calls, 1);
vec_dc.pop_back();
EXPECT_EQ(DestructorCheck::destructor_calls, 2);
vec_dc.pop_back();
EXPECT_EQ(DestructorCheck::destructor_calls, 3);
EXPECT_TRUE(vec_dc.empty());
}
TEST(FixedVectorTest, CapacityAndMaxSize) {
fixed_vector<int, 5> vec;
EXPECT_EQ(vec.capacity(), 5);
EXPECT_EQ(vec.max_size(), 5);
const fixed_vector<int, 0> zero_vec;
EXPECT_EQ(zero_vec.capacity(), 0);
EXPECT_EQ(zero_vec.max_size(), 0);
}
TEST(FixedVectorTest, ConstIteratorMethods) {
fixed_vector<int, 5> vec;
vec.push_back(1);
vec.push_back(2);
vec.push_back(3);
const auto& cvec = vec;
// Test cbegin() and cend()
int expected_val = 1;
for (auto it = cvec.cbegin(); it != cvec.cend(); ++it) {
EXPECT_EQ(*it, expected_val++);
}
EXPECT_EQ(expected_val, 4); // Should have iterated 1, 2, 3
// Test crbegin() and crend()
expected_val = 3;
for (auto it = cvec.crbegin(); it != cvec.crend(); ++it) {
EXPECT_EQ(*it, expected_val--);
}
EXPECT_EQ(expected_val, 0); // Should have iterated 3, 2, 1
// Test on empty vector
fixed_vector<int, 5> empty_vec;
const auto& cempty_vec = empty_vec;
EXPECT_EQ(cempty_vec.cbegin(), cempty_vec.cend());
EXPECT_EQ(cempty_vec.crbegin(), cempty_vec.crend());
}
TEST(FixedVectorTest, EraseInvalidRange) {
fixed_vector<int, 5> vec;
vec.push_back(1);
vec.push_back(2);
vec.push_back(3);
vec.push_back(4);
// Test with first > last, which should do nothing
auto original_size = vec.size();
auto it = vec.erase(vec.begin() + 2, vec.begin() + 1);
// Verify nothing happened
EXPECT_EQ(vec.size(), original_size);
EXPECT_EQ(vec[0], 1);
EXPECT_EQ(vec[1], 2);
EXPECT_EQ(vec[2], 3);
EXPECT_EQ(vec[3], 4);
// The returned iterator should be the 'first' iterator passed in
EXPECT_EQ(it, vec.begin() + 2);
EXPECT_EQ(*it, 3);
}
TEST(FixedVectorTest, ComparisonOperators) {
fixed_vector<int, 5> vec1;
vec1.push_back(1);
vec1.push_back(2);
fixed_vector<int, 5> vec2;
vec2.push_back(1);
vec2.push_back(2);
fixed_vector<int, 5> vec3;
vec3.push_back(1);
vec3.push_back(99);
fixed_vector<int, 5> vec4;
vec4.push_back(1);
fixed_vector<int, 5> empty1;
fixed_vector<int, 5> empty2;
EXPECT_TRUE(vec1 == vec2);
EXPECT_FALSE(vec1 != vec2);
EXPECT_FALSE(vec1 == vec3);
EXPECT_TRUE(vec1 != vec3);
EXPECT_FALSE(vec1 == vec4);
EXPECT_TRUE(vec1 != vec4);
EXPECT_TRUE(empty1 == empty2);
EXPECT_FALSE(empty1 != empty2);
EXPECT_FALSE(vec1 == empty1);
EXPECT_TRUE(vec1 != empty1);
}
// Verify that fixed_vector enforces nothrow move requirements at compile time.
// Types with throwing move constructors/assignments are rejected by static_assert.
struct NothrowMovable {
NothrowMovable() = default;
NothrowMovable(NothrowMovable&&) noexcept = default;
NothrowMovable& operator=(NothrowMovable&&) noexcept = default;
NothrowMovable(const NothrowMovable&) = default;
NothrowMovable& operator=(const NothrowMovable&) = default;
};
TEST(FixedVectorTest, NothrowMoveConstraint) {
// Verify that fixed_vector works with nothrow-movable types
fixed_vector<NothrowMovable, 5> vec;
vec.emplace_back();
EXPECT_EQ(vec.size(), 1);
// Move construction should be noexcept
static_assert(std::is_nothrow_move_constructible_v<fixed_vector<NothrowMovable, 5>>);
static_assert(std::is_nothrow_move_assignable_v<fixed_vector<NothrowMovable, 5>>);
static_assert(std::is_nothrow_move_constructible_v<fixed_vector<int, 5>>);
static_assert(std::is_nothrow_move_assignable_v<fixed_vector<int, 5>>);
static_assert(std::is_nothrow_move_constructible_v<fixed_vector<std::string, 5>>);
static_assert(std::is_nothrow_move_assignable_v<fixed_vector<std::string, 5>>);
}
// Types with throwing move operations — used only in compile-time rejection checks below.
struct ThrowingMoveConstructor {
ThrowingMoveConstructor() = default;
ThrowingMoveConstructor(ThrowingMoveConstructor&&) noexcept(false) {
}
ThrowingMoveConstructor& operator=(ThrowingMoveConstructor&&) noexcept = default;
};
struct ThrowingMoveAssignment {
ThrowingMoveAssignment() = default;
ThrowingMoveAssignment(ThrowingMoveAssignment&&) noexcept = default;
ThrowingMoveAssignment& operator=(ThrowingMoveAssignment&&) noexcept(false) {
return *this;
}
};
struct ThrowingBothMoveOps {
ThrowingBothMoveOps() = default;
ThrowingBothMoveOps(ThrowingBothMoveOps&&) noexcept(false) {
}
ThrowingBothMoveOps& operator=(ThrowingBothMoveOps&&) noexcept(false) {
return *this;
}
};
// Verify at compile time that fixed_vector rejects types whose move operations can throw.
// The static_asserts inside fixed_vector prevent instantiation of these types.
// We verify this indirectly: if fixed_vector's constraint is working, these types must not
// satisfy the nothrow move requirements.
TEST(FixedVectorTest, ThrowingMoveTypesAreRejected) {
// Confirm the types themselves have throwing move operations
static_assert(!std::is_nothrow_move_constructible_v<ThrowingMoveConstructor>,
"ThrowingMoveConstructor should not be nothrow move constructible");
static_assert(!std::is_nothrow_move_constructible_v<ThrowingBothMoveOps>,
"ThrowingBothMoveOps should not be nothrow move constructible");
static_assert(!std::is_nothrow_move_assignable_v<ThrowingMoveAssignment>,
"ThrowingMoveAssignment should not be nothrow move assignable");
static_assert(!std::is_nothrow_move_assignable_v<ThrowingBothMoveOps>,
"ThrowingBothMoveOps should not be nothrow move assignable");
// fixed_vector<ThrowingMoveConstructor, 5> would fail to compile due to static_assert.
// fixed_vector<ThrowingMoveAssignment, 5> would fail to compile due to static_assert.
// fixed_vector<ThrowingBothMoveOps, 5> would fail to compile due to static_assert.
//
// These cannot be tested at runtime since instantiation itself is a compile error.
// The static_asserts above confirm the trait checks that fixed_vector relies on.
}
TEST(FixedVectorTest, InitializerListConstructor) {
// Basic construction
fixed_vector<int, 5> vec1 = {1, 2, 3};
EXPECT_EQ(vec1.size(), 3);
EXPECT_EQ(vec1[0], 1);
EXPECT_EQ(vec1[1], 2);
EXPECT_EQ(vec1[2], 3);
// Empty list
fixed_vector<int, 5> vec2 = {};
EXPECT_TRUE(vec2.empty());
EXPECT_EQ(vec2.size(), 0);
// Full capacity
fixed_vector<int, 3> vec3 = {10, 20, 30};
EXPECT_EQ(vec3.size(), 3);
EXPECT_EQ(vec3[2], 30);
// Exceeding capacity - use a lambda to avoid comma issues with the macro
EXPECT_THROW(([] { fixed_vector<int, 2> vec4 = {1, 2, 3}; }()), std::length_error);
// With strings
fixed_vector<std::string, 4> vec5 = {"hello", "world"};
EXPECT_EQ(vec5.size(), 2);
EXPECT_EQ(vec5[0], "hello");
EXPECT_EQ(vec5[1], "world");
}
TEST(FixedVectorTest, StdVectorConstructor) {
// Test case 1: Construct from an empty std::vector
std::vector<int> empty_std_vec = {};
fixed_vector<int, 5> vec_from_empty(empty_std_vec);
EXPECT_TRUE(vec_from_empty.empty());
EXPECT_EQ(vec_from_empty.size(), 0);
// Test case 2: Construct from a std::vector with elements (within capacity)
std::vector<int> small_std_vec = {1, 2, 3};
fixed_vector<int, 5> vec_from_small(small_std_vec);
EXPECT_EQ(vec_from_small.size(), 3);
EXPECT_EQ(vec_from_small[0], 1);
EXPECT_EQ(vec_from_small[1], 2);
EXPECT_EQ(vec_from_small[2], 3);
// Test case 3: Construct from a std::vector with elements (exactly capacity)
std::vector<int> full_std_vec = {10, 20, 30, 40, 50};
fixed_vector<int, 5> vec_from_full(full_std_vec);
EXPECT_EQ(vec_from_full.size(), 5);
EXPECT_EQ(vec_from_full[0], 10);
EXPECT_EQ(vec_from_full[4], 50);
// Test case 4: Construct from a std::vector with elements exceeding capacity
std::vector<int> large_std_vec = {1, 2, 3, 4, 5, 6};
EXPECT_THROW(([large_std_vec] { fixed_vector<int, 5> vec_from_large(large_std_vec); }()), std::length_error);
// Test case 5: Construct with std::string elements
std::vector<std::string> string_std_vec = {"apple", "banana"};
fixed_vector<std::string, 3> vec_from_strings(string_std_vec);
EXPECT_EQ(vec_from_strings.size(), 2);
EXPECT_EQ(vec_from_strings[0], "apple");
EXPECT_EQ(vec_from_strings[1], "banana");
}