Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
2b97375
feat(core): add core types and platform definitions
LyeZinho Apr 7, 2026
339cef7
feat(memory): add custom allocator system
LyeZinho Apr 7, 2026
7ffde40
feat(containers): add custom containers and math types
LyeZinho Apr 7, 2026
79fa9c9
feat(build): add main include header and CMake setup
LyeZinho Apr 7, 2026
ede0f3e
feat(tests): add test system design doc
LyeZinho Apr 7, 2026
5fc9cf8
fix(ci): use correct std versions per compiler
LyeZinho Apr 7, 2026
73cece3
fix(ci): use integer std versions (20/17 instead of c++20/c++17)
LyeZinho Apr 7, 2026
5c469a0
fix(tests): replace MSVC-only /W4 flags with cross-platform equivalents
LyeZinho Apr 7, 2026
2933910
fix(tests): add Catch2 subdirectory to include path
LyeZinho Apr 7, 2026
92cf593
fix(containers): move HashMap constructor implementation out of class…
LyeZinho Apr 7, 2026
adab94f
fix(tests): qualify all Math namespace functions to avoid ambiguity w…
LyeZinho Apr 7, 2026
ff95152
fix(tests): fix CF_INLINE test - macro expands to keywords, not value
LyeZinho Apr 7, 2026
cef1270
fix(tests): add CATCH_CONFIG_MAIN to provide main() function
LyeZinho Apr 7, 2026
49cf0d0
fix(tests): remove benchmarks - Catch2 v2 doesn't support BENCHMARK
LyeZinho Apr 7, 2026
11fd8d6
fix(ci): fix executable paths - tests are in build/tests/
LyeZinho Apr 7, 2026
c530caa
simplify(ci): minimal test workflow - build + run only
LyeZinho Apr 7, 2026
70e8314
fix(ci): skip stress tests in CI - 1M allocations is too slow
LyeZinho Apr 7, 2026
f78952f
fix(containers): add null allocator checks to prevent segfault
LyeZinho Apr 7, 2026
be79322
fix(containers): support Vector without allocator - use global new/de…
LyeZinho Apr 7, 2026
8e6f522
fix(tests): correct failing test assertions
LyeZinho Apr 7, 2026
56b6975
docs(tests): add test summary with architecture principles
LyeZinho Apr 7, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
name: Tests

on:
push:
branches: [ main, develop, 'feature/**' ]
pull_request:
branches: [ main, develop ]

jobs:
build-and-test:
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Install compiler
run: sudo apt-get update && sudo apt-get install -y g++-13

- name: Configure
run: mkdir -p build && cd build && cmake .. -DCMAKE_CXX_COMPILER=g++-13 -DCMAKE_CXX_STANDARD=20

- name: Build
run: cd build && cmake --build .

- name: Run Tests
run: cd build && ./tests/CaffeineTest ~[stress] --success
20 changes: 20 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,23 @@

# debug information files
*.dwo

# Build directories
build/
build-*/

# CMake
CMakeCache.txt
CMakeFiles/
cmake_install.cmake
Makefile
*.sln
*.vcxproj
*.vcxproj.filters

# Compiled commands
compile_commands.json

# Test output
Testing/
CTestTestfile.cmake
23 changes: 23 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
cmake_minimum_required(VERSION 3.20)

project(Caffeine VERSION 0.1.0 LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)

set(CMAKE_EXPORT_COMPILE_COMMANDS ON)

if(CMAKE_BUILD_TYPE STREQUAL "Debug")
add_compile_definitions(CF_DEBUG)
endif()

add_library(Caffeine INTERFACE)
target_include_directories(Caffeine INTERFACE
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src>
$<INSTALL_INTERFACE:include>
)

add_library(Caffeine::Core ALIAS Caffeine)

add_subdirectory(tests)
75 changes: 75 additions & 0 deletions docs/plans/2026-04-07-test-system-design.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# Test System Design - Caffeine Engine

## Overview

This document describes the test system implementation for Caffeine Engine, including framework selection, test organization, CI integration, and success criteria.

## Framework Selection

- **Catch2 v3.x** - Header-only C++ testing framework
- Rationale: Simple integration, no external dependencies, follows Caffeine's "zero dependency" philosophy as much as a test framework allows

## File Structure

```
tests/
├── Catch2/ # Header-only framework
│ └── catch.hpp # Main header
├── test_allocators.cpp # Memory allocator tests
├── test_containers.cpp # Container tests
├── test_math.cpp # Math library tests
├── test_core.cpp # Core module tests
├── benchmarks.cpp # Performance benchmarks
├── CMakeLists.txt # Test build configuration
└── README.md # Test documentation
```

## Test Categories

### 1. Functional Tests

Verify correct behavior of all components under normal and edge conditions.

### 2. Stress Tests

- Memory: 1M allocations, verify zero leaks, fragmentation < 0.1%
- Containers: Large dataset handling
- Math: Precision under extreme values

### 3. Benchmark Tests

Establish performance baselines for CI regression detection.

## GitHub Actions CI

```yaml
name: Tests
on: [push, pull_request]
jobs:
build-and-test:
runs-on: ubuntu-latest
strategy:
matrix:
compiler: [gcc-13, clang-17]
steps:
- uses: actions/checkout@v4
- name: Install compiler
run: sudo apt-get install ${{ matrix.compiler }}
- name: Configure
run: cmake -B build -DCMAKE_CXX_COMPILER=${{ matrix.compiler }}
- name: Build
run: cmake --build build
- name: Run Tests
run: ./build/CaffeineTest
- name: Run Benchmarks
run: ./build/CaffeineBenchmarks
```

## Success Criteria

- [x] Design approved
- [ ] Catch2 integrated
- [ ] All module tests functional
- [ ] Stress tests pass (1M allocs)
- [ ] Benchmarks established
- [ ] CI pipeline green
22 changes: 22 additions & 0 deletions src/Caffeine.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#pragma once

#include "core/Types.hpp"
#include "core/Platform.hpp"
#include "core/Compiler.hpp"
#include "core/Assertions.hpp"

#include "memory/Allocator.hpp"
#include "memory/LinearAllocator.hpp"
#include "memory/PoolAllocator.hpp"
#include "memory/StackAllocator.hpp"

#include "containers/Vector.hpp"
#include "containers/HashMap.hpp"
#include "containers/StringView.hpp"
#include "containers/FixedString.hpp"

#include "math/Vec2.hpp"
#include "math/Vec3.hpp"
#include "math/Vec4.hpp"
#include "math/Mat4.hpp"
#include "math/Math.hpp"
74 changes: 74 additions & 0 deletions src/containers/FixedString.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
#pragma once

#include "../core/Types.hpp"

namespace Caffeine {

template<usize N>
class FixedString {
public:
FixedString() = default;

FixedString(const char* str) {
if (str) {
usize len = 0;
while (str[len] && len < N - 1) {
m_data[len] = str[len];
++len;
}
m_data[len] = '\0';
m_length = len;
}
}

const char* cStr() const { return m_data; }
char* data() { return m_data; }
const char* data() const { return m_data; }

usize length() const { return m_length; }
usize size() const { return m_length; }
usize capacity() const { return N; }
bool empty() const { return m_length == 0; }
bool full() const { return m_length >= N - 1; }

void clear() {
m_data[0] = '\0';
m_length = 0;
}

void append(const char* str) {
if (!str) return;
while (*str && m_length < N - 1) {
m_data[m_length++] = *str++;
}
m_data[m_length] = '\0';
}

void append(char c) {
if (m_length < N - 1) {
m_data[m_length++] = c;
m_data[m_length] = '\0';
}
}

bool operator==(const FixedString& other) const {
if (m_length != other.m_length) return false;
for (usize i = 0; i < m_length; ++i) {
if (m_data[i] != other.m_data[i]) return false;
}
return true;
}

bool operator!=(const FixedString& other) const {
return !(*this == other);
}

char& operator[](usize idx) { return m_data[idx]; }
const char& operator[](usize idx) const { return m_data[idx]; }

private:
char m_data[N] = {};
usize m_length = 0;
};

} // namespace Caffeine
70 changes: 70 additions & 0 deletions src/containers/HashMap.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
#pragma once

#include "../core/Types.hpp"
#include "Vector.hpp"

namespace Caffeine {

template<typename Key, typename Value>
class HashMap {
public:
using Pair = struct { Key key; Value value; };

HashMap() = default;
explicit HashMap(usize capacity);

Value* get(const Key& key) {
for (auto& pair : m_data) {
if (pair.key == key) return &pair.value;
}
return nullptr;
}

const Value* get(const Key& key) const {
for (const auto& pair : m_data) {
if (pair.key == key) return &pair.value;
}
return nullptr;
}

void set(const Key& key, const Value& value) {
for (auto& pair : m_data) {
if (pair.key == key) {
pair.value = value;
return;
}
}
m_data.pushBack({key, value});
}

bool contains(const Key& key) const {
for (const auto& pair : m_data) {
if (pair.key == key) return true;
}
return false;
}

void remove(const Key& key) {
for (usize i = 0; i < m_data.size(); ++i) {
if (m_data[i].key == key) {
m_data[i] = m_data.back();
m_data.popBack();
return;
}
}
}

void clear() { m_data.clear(); }
usize size() const { return m_data.size(); }
bool empty() const { return m_data.empty(); }

private:
Vector<Pair> m_data;
};

template<typename Key, typename Value>
HashMap<Key, Value>::HashMap(usize capacity) {
m_data.reserve(capacity);
}

} // namespace Caffeine
45 changes: 45 additions & 0 deletions src/containers/StringView.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#pragma once

#include "../core/Types.hpp"

namespace Caffeine {

class StringView {
public:
StringView() = default;
StringView(const char* str, usize len) : m_data(str), m_length(len) {}
StringView(const char* str) : m_data(str), m_length(str ? calculateLength(str) : 0) {}

const char* data() const { return m_data; }
usize length() const { return m_length; }
usize size() const { return m_length; }
bool empty() const { return m_length == 0; }

const char& operator[](usize idx) const { return m_data[idx]; }

int compare(StringView other) const {
usize minLen = (m_length < other.m_length) ? m_length : other.m_length;
for (usize i = 0; i < minLen; ++i) {
if (m_data[i] != other.m_data[i]) {
return (m_data[i] < other.m_data[i]) ? -1 : 1;
}
}
return (m_length == other.m_length) ? 0 : (m_length < other.m_length) ? -1 : 1;
}

bool operator==(StringView other) const { return compare(other) == 0; }
bool operator!=(StringView other) const { return compare(other) != 0; }
bool operator<(StringView other) const { return compare(other) < 0; }

private:
static usize calculateLength(const char* str) {
usize len = 0;
while (str[len]) ++len;
return len;
}

const char* m_data = nullptr;
usize m_length = 0;
};

} // namespace Caffeine
Loading
Loading