Start CMake modernization scaffold

This commit is contained in:
2026-05-31 23:40:43 +02:00
parent ee027984b7
commit c38ff8209b
36 changed files with 2118 additions and 1556 deletions

23
tests/CMakeLists.txt Normal file
View File

@@ -0,0 +1,23 @@
add_library(pp_test_harness INTERFACE)
target_include_directories(pp_test_harness INTERFACE
"${CMAKE_CURRENT_SOURCE_DIR}")
target_link_libraries(pp_test_harness INTERFACE
pp_project_options
pp_project_warnings)
add_executable(pp_foundation_tests
foundation/binary_stream_tests.cpp)
target_link_libraries(pp_foundation_tests PRIVATE
pp_foundation
pp_test_harness)
add_test(NAME pp_foundation_tests COMMAND pp_foundation_tests)
set_tests_properties(pp_foundation_tests PROPERTIES
LABELS "foundation;desktop-fast")
if(TARGET pano_cli)
add_test(NAME pano_cli_create_document_smoke
COMMAND pano_cli create-document --width 64 --height 32 --layers 2)
set_tests_properties(pano_cli_create_document_smoke PROPERTIES
LABELS "integration;desktop-fast")
endif()

View File

@@ -0,0 +1,100 @@
#include "foundation/binary_stream.h"
#include "test_harness.h"
#include <array>
#include <cstddef>
#include <cstdint>
#include <vector>
using pp::foundation::ByteReader;
using pp::foundation::ByteWriter;
namespace {
void round_trips_little_endian_values(pp::tests::Harness& h)
{
std::vector<std::byte> bytes;
ByteWriter writer(bytes);
PP_EXPECT(h, writer.write_u8(0x12U).ok());
PP_EXPECT(h, writer.write_u16_le(0x3456U).ok());
PP_EXPECT(h, writer.write_u32_le(0x789abcdeU).ok());
PP_EXPECT(h, writer.size() == 7U);
ByteReader reader(bytes);
const auto u8 = reader.read_u8();
const auto u16 = reader.read_u16_le();
const auto u32 = reader.read_u32_le();
PP_EXPECT(h, u8.ok());
PP_EXPECT(h, u8.value() == 0x12U);
PP_EXPECT(h, u16.ok());
PP_EXPECT(h, u16.value() == 0x3456U);
PP_EXPECT(h, u32.ok());
PP_EXPECT(h, u32.value() == 0x789abcdeU);
PP_EXPECT(h, reader.empty());
}
void rejects_overread_without_moving_cursor(pp::tests::Harness& h)
{
const std::array bytes {
std::byte { 0x01 },
std::byte { 0x02 },
std::byte { 0x03 },
};
ByteReader reader(bytes);
PP_EXPECT(h, reader.seek(2).ok());
const auto before = reader.position();
const auto value = reader.read_u32_le();
PP_EXPECT(h, !value.ok());
PP_EXPECT(h, reader.position() == before);
PP_EXPECT(h, reader.remaining() == 1U);
}
void rejects_out_of_range_seek(pp::tests::Harness& h)
{
const std::array bytes {
std::byte { 0x01 },
std::byte { 0x02 },
};
ByteReader reader(bytes);
PP_EXPECT(h, !reader.seek(3).ok());
PP_EXPECT(h, reader.position() == 0U);
PP_EXPECT(h, reader.seek(2).ok());
PP_EXPECT(h, reader.empty());
}
void boundary_reads_are_consistent(pp::tests::Harness& h)
{
std::array<std::byte, 16> bytes {};
for (std::size_t i = 0; i < bytes.size(); ++i) {
bytes[i] = static_cast<std::byte>(i);
}
for (std::size_t length = 0; length <= bytes.size(); ++length) {
ByteReader reader(std::span<const std::byte>(bytes.data(), length));
const auto exact = reader.read_bytes(length);
PP_EXPECT(h, exact.ok());
PP_EXPECT(h, exact.value().size() == length);
PP_EXPECT(h, reader.empty());
const auto too_much = reader.read_u8();
PP_EXPECT(h, !too_much.ok());
PP_EXPECT(h, reader.position() == length);
}
}
}
int main()
{
pp::tests::Harness harness;
harness.run("round_trips_little_endian_values", round_trips_little_endian_values);
harness.run("rejects_overread_without_moving_cursor", rejects_overread_without_moving_cursor);
harness.run("rejects_out_of_range_seek", rejects_out_of_range_seek);
harness.run("boundary_reads_are_consistent", boundary_reads_are_consistent);
return harness.finish();
}

50
tests/test_harness.h Normal file
View File

@@ -0,0 +1,50 @@
#pragma once
#include <cstdlib>
#include <iostream>
#include <string_view>
namespace pp::tests {
class Harness {
public:
void expect(bool condition, std::string_view expression, std::string_view file, int line)
{
++assertions_;
if (!condition) {
++failures_;
std::cerr << file << ":" << line << ": expectation failed: " << expression << "\n";
}
}
template <typename Callback>
void run(std::string_view name, Callback callback)
{
const auto failures_before = failures_;
callback(*this);
++tests_;
if (failures_ == failures_before) {
std::cout << "[pass] " << name << "\n";
} else {
std::cout << "[fail] " << name << "\n";
}
}
[[nodiscard]] int finish() const
{
std::cout << "{\"tests\":" << tests_
<< ",\"assertions\":" << assertions_
<< ",\"failures\":" << failures_ << "}\n";
return failures_ == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
}
private:
int tests_ = 0;
int assertions_ = 0;
int failures_ = 0;
};
}
#define PP_EXPECT(harness, expression) \
(harness).expect(static_cast<bool>(expression), #expression, __FILE__, __LINE__)