Unit Test Examples
The OULY unit tests serve as comprehensive examples of proper API usage and best practices.
Allocator Examples
Linear Allocator Usage
The linear allocator tests demonstrate sequential allocation patterns:
// From unit_tests/allocators/test_linear_allocator.cpp
TEST_CASE("linear_allocator basic usage", "[allocators]") {
ouly::linear_allocator<> allocator(1024);
// Sequential allocations
void* ptr1 = allocator.allocate(256);
void* ptr2 = allocator.allocate(128);
REQUIRE(ptr1 != nullptr);
REQUIRE(ptr2 != nullptr);
REQUIRE(allocator.used() == 384);
// LIFO deallocation
allocator.deallocate(ptr2, 128);
allocator.deallocate(ptr1, 256);
REQUIRE(allocator.used() == 0);
}
Pool Allocator Examples
Pool allocators for fixed-size object allocation:
TEST_CASE("pool_allocator object management", "[allocators]") {
struct TestObject {
int value;
float data;
};
ouly::pool_allocator<> pool(sizeof(TestObject), 100);
std::vector<TestObject*> objects;
// Allocate multiple objects
for (int i = 0; i < 50; ++i) {
auto* obj = static_cast<TestObject*>(
pool.allocate(sizeof(TestObject))
);
new(obj) TestObject{i, static_cast<float>(i * 2)};
objects.push_back(obj);
}
// Cleanup
for (auto* obj : objects) {
obj->~TestObject();
pool.deallocate(obj, sizeof(TestObject));
}
}
Container Examples
Small Vector Usage
Stack-optimized vector examples:
// From unit_tests/containers/test_small_vector.cpp
TEST_CASE("small_vector stack optimization", "[containers]") {
ouly::small_vector<int, 8> vec;
// These use stack storage
for (int i = 0; i < 8; ++i) {
vec.push_back(i);
}
REQUIRE(!vec.is_heap_allocated());
// This triggers heap allocation
vec.push_back(8);
REQUIRE(vec.is_heap_allocated());
}
SoA Vector Examples
Structure of Arrays container usage:
TEST_CASE("soavector aggregate expansion", "[containers]") {
struct Particle {
float x, y, z;
int life;
};
ouly::soavector<Particle> particles;
// Add particles
particles.emplace_back(1.0f, 2.0f, 3.0f, 100);
particles.emplace_back(4.0f, 5.0f, 6.0f, 50);
// Access individual arrays for SIMD operations
auto& x_coords = particles.get<0>();
auto& y_coords = particles.get<1>();
auto& lifetimes = particles.get<3>();
// Vectorized update
for (size_t i = 0; i < particles.size(); ++i) {
x_coords[i] += 1.0f;
lifetimes[i] -= 1;
}
}
ECS Examples
Entity and Component Management
// From unit_tests/ecs/test_registry.cpp
TEST_CASE("ecs basic entity management", "[ecs]") {
ouly::ecs::registry<> registry;
ouly::ecs::components<Position> positions;
ouly::ecs::components<Velocity> velocities;
// Create entities
auto entity1 = registry.emplace();
auto entity2 = registry.emplace();
// Add components
positions.emplace_at(entity1, 10.0f, 20.0f, 0.0f);
velocities.emplace_at(entity1, 1.0f, 0.0f, 0.0f);
positions.emplace_at(entity2, 5.0f, 15.0f, 0.0f);
// entity2 has no velocity component
// System processing
positions.for_each(velocities, [](auto entity, auto& pos, auto& vel) {
pos.x += vel.dx;
pos.y += vel.dy;
pos.z += vel.dz;
});
}
Component Storage Configuration
TEST_CASE("ecs storage strategies", "[ecs]") {
// Dense storage (default)
ouly::ecs::components<Position> dense_positions;
// Sparse storage for rarely used components
using SparseConfig = ouly::cfg::use_sparse<>;
ouly::ecs::components<SpecialAbility, ouly::ecs::entity<>, SparseConfig> abilities;
// Direct mapping for frequently accessed components
using DirectConfig = ouly::cfg::use_direct_mapping<>;
ouly::ecs::components<Transform, ouly::ecs::entity<>, DirectConfig> transforms;
}
Scheduler Examples
Basic Task Execution
// From unit_tests/scheduler/test_scheduler.cpp
TEST_CASE("scheduler basic task execution", "[scheduler]") {
ouly::scheduler scheduler(2);
// Create workgroup BEFORE begin_execution
auto workgroup = scheduler.create_workgroup();
// Begin execution
scheduler.begin_execution();
// Submit tasks
auto future1 = scheduler.submit(workgroup, []() { return 42; });
auto future2 = scheduler.submit(workgroup, []() { return 24; });
// Wait for results
REQUIRE(future1.get() == 42);
REQUIRE(future2.get() == 24);
// Cleanup
scheduler.end_execution();
scheduler.shutdown();
}
Parallel Algorithms
TEST_CASE("scheduler parallel processing", "[scheduler]") {
ouly::scheduler scheduler(4);
auto workgroup = scheduler.create_workgroup();
scheduler.begin_execution();
std::vector<int> data(1000);
std::iota(data.begin(), data.end(), 1);
// Parallel processing using task context
scheduler.submit(workgroup, [&](auto& ctx) {
// Split work across available workers
size_t chunk_size = data.size() / 4;
std::vector<std::future<void>> futures;
for (size_t i = 0; i < 4; ++i) {
size_t start = i * chunk_size;
size_t end = (i == 3) ? data.size() : start + chunk_size;
auto future = ouly::async(ctx, ctx.current_workgroup(),
[&data, start, end]() {
for (size_t j = start; j < end; ++j) {
data[j] *= 2; // Double each element
}
});
futures.push_back(std::move(future));
}
// Wait for all chunks to complete
for (auto& f : futures) {
f.wait();
}
}).wait();
scheduler.end_execution();
scheduler.shutdown();
}
Serialization Examples
Binary Serialization
// From unit_tests/serializers/test_binary_serializer.cpp
TEST_CASE("binary serialization basic types", "[serializers]") {
struct TestData {
int id;
std::string name;
std::vector<float> values;
};
TestData original{42, "test", {1.0f, 2.0f, 3.0f}};
// Serialize
ouly::binary_stream stream;
ouly::write<std::endian::little>(stream, original);
// Deserialize
ouly::binary_stream input(stream.data(), stream.size());
TestData loaded;
ouly::read<std::endian::little>(input, loaded);
// Verify
REQUIRE(loaded.id == original.id);
REQUIRE(loaded.name == original.name);
REQUIRE(loaded.values == original.values);
}
YAML Serialization
TEST_CASE("yaml serialization configuration", "[serializers]") {
struct Config {
std::string app_name;
int version;
std::vector<std::string> modules;
std::map<std::string, int> settings;
};
Config original;
original.app_name = "TestApp";
original.version = 1;
original.modules = {"core", "graphics", "audio"};
original.settings["max_fps"] = 60;
original.settings["resolution_x"] = 1920;
// Serialize to YAML
std::string yaml = ouly::yml::to_string(original);
// Deserialize from YAML
Config loaded;
ouly::yml::from_string(loaded, yaml);
// Verify
REQUIRE(loaded.app_name == original.app_name);
REQUIRE(loaded.modules == original.modules);
REQUIRE(loaded.settings == original.settings);
}
Running Specific Examples
To run and study specific examples:
# Build with tests
cmake --preset=macos-default
cmake --build build/macos-default
# Run specific test categories
cd build/macos-default
# All allocator examples
ctest -R allocator -V
# All container examples
ctest -R container -V
# All ECS examples
ctest -R ecs -V
# All scheduler examples
ctest -R scheduler -V
# All serialization examples
ctest -R serializer -V
The -V flag provides verbose output showing the test execution details.