diff options
| author | Marcel Braun <marcel.braun@ost.ch> | 2026-04-02 08:48:00 +0200 |
|---|---|---|
| committer | Marcel Braun <marcel.braun@ost.ch> | 2026-04-02 08:48:00 +0200 |
| commit | 0c01a95325b26151ff3c9a70142f5dc83ff7d53f (patch) | |
| tree | 9bf034f544ae773b653554a54edfce232f835754 | |
| parent | 022d3e872de9c5a6a52c67f74af13706552330c0 (diff) | |
| parent | 3eb680cf5bcef626505cac82820996d8db4170d7 (diff) | |
| download | teachos-0c01a95325b26151ff3c9a70142f5dc83ff7d53f.tar.xz teachos-0c01a95325b26151ff3c9a70142f5dc83ff7d53f.zip | |
Merge branch 'fmorgner/develop-SA-FS26/kernel-bht' into 'develop-BA-FS26'
Add experimental support for kernel tests
See merge request teachos/kernel!20
32 files changed, 1298 insertions, 57 deletions
@@ -9,11 +9,12 @@ Documentation: --- If: - PathMatch: + PathMatch: - "libs/.*/tests/.*\\.cpp" + - "kernel/.*\\.tests.cpp" Diagnostics: ClangTidy: - Remove: '*' + Remove: "*" CompileFlags: Add: - - -Wno-c2y-extensions
\ No newline at end of file + - -Wno-c2y-extensions diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 0b933c4..661ce63 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -28,7 +28,7 @@ bht: - cmake --build --preset bht-dbg - ctest --preset bht-dbg - lcov --config-file .lcovrc --capture --directory $(pwd) --output-file coverage.info - - lcov --config-file .lcovrc --list coverage.info + - lcov --list coverage.info - genhtml --prefix $(pwd) --output-directory coverage coverage.info - gcovr --root . --cobertura-pretty --output coverage/cobertura-coverage.xml after_script: @@ -1,5 +1,7 @@ exclude = /usr/include/* exclude = build/bht/_deps/* exclude = tests/* +exclude = **.tests.cpp +exclude = kapi/include/kapi/* ignore_errors = unused,empty,inconsistent
\ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 6cc8a2f..002ab0c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -89,15 +89,10 @@ if(Doxygen_FOUND AND TEACHOS_GENERATE_DOCS) endif() #[============================================================================[ -# Global Targets +# Build Host Testing #]============================================================================] -if(CMAKE_CROSSCOMPILING) - add_subdirectory("arch/${CMAKE_SYSTEM_PROCESSOR}") - add_subdirectory("kernel") - add_subdirectory("kapi") - add_subdirectory("libs") -else() +if(NOT CMAKE_CROSSCOMPILING) include("EnableCoverage") enable_testing() @@ -110,6 +105,16 @@ else() CXX_CLANG_TIDY "" ) endif() +endif() - add_subdirectory("libs") +#[============================================================================[ +# Global Targets +#]============================================================================] + +if(CMAKE_CROSSCOMPILING) + add_subdirectory("arch/${CMAKE_SYSTEM_PROCESSOR}") endif() + +add_subdirectory("kapi") +add_subdirectory("kernel") +add_subdirectory("libs") diff --git a/kapi/include/kapi/cio.hpp b/kapi/include/kapi/cio.hpp index 48f3000..71b5b02 100644 --- a/kapi/include/kapi/cio.hpp +++ b/kapi/include/kapi/cio.hpp @@ -25,6 +25,11 @@ namespace kapi::cio //! @return The previously active output device. auto set_output_device(output_device & device) -> std::optional<output_device *>; + //! @qualifier kernel-defined + //! Write a string to the given output stream. + //! + //! @param stream The output stream to write to. + //! @param text The text to write to the stream. auto write(output_stream stream, std::string_view text) -> void; } // namespace kapi::cio diff --git a/kernel/CMakeLists.txt b/kernel/CMakeLists.txt index cb3d8a5..1b71a5f 100644 --- a/kernel/CMakeLists.txt +++ b/kernel/CMakeLists.txt @@ -1,4 +1,4 @@ -add_executable("kernel" +add_library("kernel_objs" OBJECT # Platform-independent KAPI implementation "kapi/boot_modules.cpp" "kapi/cio.cpp" @@ -12,10 +12,8 @@ add_executable("kernel" "kstd/print.cpp" # Kernel Implementation - "src/main.cpp" "src/memory/bitmap_allocator.cpp" "src/memory/block_list_allocator.cpp" - "src/memory/operators.cpp" "src/memory.cpp" "src/devices/block_device.cpp" "src/devices/block_device_utils.cpp" @@ -40,38 +38,101 @@ add_executable("kernel" "src/filesystem/vfs.cpp" ) -target_include_directories("kernel" PRIVATE +target_include_directories("kernel_objs" PUBLIC "include" ) -target_link_libraries("kernel" PRIVATE - "os::arch" +target_link_libraries("kernel_objs" PUBLIC "os::kapi" ) -target_link_options("kernel" PRIVATE - "-T${KERNEL_LINKER_SCRIPT}" - "-no-pie" - "-nostdlib" -) - -set_property(TARGET "kernel" - APPEND - PROPERTY LINK_DEPENDS - "${KERNEL_LINKER_SCRIPT}" -) - file(GLOB_RECURSE KERNEL_HEADERS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "include/**.hpp") -target_sources("kernel" PUBLIC +target_sources("kernel_objs" PUBLIC FILE_SET HEADERS BASE_DIRS "include" FILES ${KERNEL_HEADERS} ) -target_disassemble("kernel") -target_extract_debug_symbols("kernel") -target_strip("kernel") +add_library("os::kernel" ALIAS "kernel_objs") + +if(CMAKE_CROSSCOMPILING) + add_executable("kernel" + "src/main.cpp" + "src/memory/operators.cpp" + ) + + target_link_libraries("kernel" PRIVATE + "os::arch" + "os::kernel" + ) + + target_link_options("kernel" PRIVATE + "-T${KERNEL_LINKER_SCRIPT}" + "-no-pie" + "-nostdlib" + ) + + set_property(TARGET "kernel" + APPEND + PROPERTY LINK_DEPENDS + "${KERNEL_LINKER_SCRIPT}" + ) + + target_disassemble("kernel") + target_extract_debug_symbols("kernel") + target_strip("kernel") + + target_generate_bootable_iso("kernel") +else() + enable_coverage("kernel_objs") + + add_library("kernel_test_support" OBJECT + "src/test_support/kapi/cpu.cpp" + "src/test_support/kapi/cio.cpp" + "src/test_support/kapi/interrupts.cpp" + "src/test_support/kapi/memory.cpp" + "src/test_support/log_buffer.cpp" + "src/test_support/page_mapper.cpp" + "src/test_support/simulated_memory.cpp" + "src/test_support/state_reset_listener.cpp" + ) + add_library("os::kernel_test_support" ALIAS "kernel_test_support") + + target_link_libraries("kernel_test_support" PUBLIC + "os::kernel" + "Catch2::Catch2WithMain" + ) + + add_executable("kernel_tests" + # KAPI Shim Tests + "kapi/cpu.tests.cpp" + "kapi/system.tests.cpp" + + # KSTD Shim Tests + "kstd/print.tests.cpp" + + # Memory Subsystem Tests + "src/memory/bitmap_allocator.tests.cpp" + "src/memory/block_list_allocator.tests.cpp" + + # Storage Subsystem Tests + "src/devices/storage/ram_disk/device.tests.cpp" + ) + add_executable("os::kernel_tests" ALIAS "kernel_tests") + + target_link_libraries("kernel_tests" PRIVATE + "os::kernel" + "os::kernel_test_support" + ) + + set_target_properties("kernel_tests" PROPERTIES + C_CLANG_TIDY "" + CXX_CLANG_TIDY "" + ) + + enable_coverage("kernel_tests") + catch_discover_tests("os::kernel_tests") +endif() -target_generate_bootable_iso("kernel") diff --git a/kernel/include/kernel/test_support/bump_frame_allocator.hpp b/kernel/include/kernel/test_support/bump_frame_allocator.hpp new file mode 100644 index 0000000..5203565 --- /dev/null +++ b/kernel/include/kernel/test_support/bump_frame_allocator.hpp @@ -0,0 +1,32 @@ +#ifndef TEACHOS_KERNEL_TEST_SUPPORT_BUMP_FRAME_ALLOCATOR_HPP +#define TEACHOS_KERNEL_TEST_SUPPORT_BUMP_FRAME_ALLOCATOR_HPP + +#include "kapi/memory.hpp" + +#include <cstddef> +#include <optional> +#include <utility> + +namespace kernel::tests +{ + + struct bump_frame_allocator : kapi::memory::frame_allocator + { + auto mark_used(kapi::memory::frame) -> void override {} + + auto allocate_many(std::size_t count) noexcept + -> std::optional<std::pair<kapi::memory::frame, std::size_t>> override + { + auto start = next_free_frame; + next_free_frame += count; + return std::pair{kapi::memory::frame{start}, count}; + } + + auto release_many(std::pair<kapi::memory::frame, std::size_t>) -> void override {} + + std::size_t next_free_frame{}; + }; + +} // namespace kernel::tests + +#endif
\ No newline at end of file diff --git a/kernel/include/kernel/test_support/cpu.hpp b/kernel/include/kernel/test_support/cpu.hpp new file mode 100644 index 0000000..5445473 --- /dev/null +++ b/kernel/include/kernel/test_support/cpu.hpp @@ -0,0 +1,18 @@ +#ifndef TEACHOS_KERNEL_TEST_SUPPORT_CPU_HPP +#define TEACHOS_KERNEL_TEST_SUPPORT_CPU_HPP + +#include <stdexcept> + +namespace kernel::tests::cpu +{ + + struct halt : std::runtime_error + { + halt() + : std::runtime_error{"CPU halt requested!"} + {} + }; + +} // namespace kernel::tests::cpu + +#endif
\ No newline at end of file diff --git a/kernel/include/kernel/test_support/log_buffer.hpp b/kernel/include/kernel/test_support/log_buffer.hpp new file mode 100644 index 0000000..581b32f --- /dev/null +++ b/kernel/include/kernel/test_support/log_buffer.hpp @@ -0,0 +1,32 @@ +#ifndef KERNEL_TEST_SUPPORT_LOG_BUFFER_HPP +#define KERNEL_TEST_SUPPORT_LOG_BUFFER_HPP + +#include <string> +#include <vector> + +namespace kernel::tests::log_buffer +{ + + //! Append a message to the testing log buffer. + //! + //! @param message The message to append. + auto append(std::string const & message) -> void; + + //! Clear the testing log buffer. + auto clear() -> void; + + //! Get the testing log buffer as a single string. + //! + //! @return The testing log buffer as a single string. + auto flat_messages() -> std::string; + + //! Get the testing log buffer. + //! + //! @note Messages may be split across multiple entries if they are longer than the internal kernel print buffer size. + //! + //! @return The testing log buffer. + auto messages() -> std::vector<std::string> const &; + +} // namespace kernel::tests::log_buffer + +#endif
\ No newline at end of file diff --git a/kernel/include/kernel/test_support/memory.hpp b/kernel/include/kernel/test_support/memory.hpp new file mode 100644 index 0000000..c6b7449 --- /dev/null +++ b/kernel/include/kernel/test_support/memory.hpp @@ -0,0 +1,11 @@ +#ifndef TEACHOS_KERNEL_TEST_SUPPORT_MEMORY_HPP +#define TEACHOS_KERNEL_TEST_SUPPORT_MEMORY_HPP + +#include "kapi/memory.hpp" + +namespace kernel::tests::memory +{ + auto heap_base() -> kapi::memory::linear_address; +} + +#endif
\ No newline at end of file diff --git a/kernel/include/kernel/test_support/page_mapper.hpp b/kernel/include/kernel/test_support/page_mapper.hpp new file mode 100644 index 0000000..a40aa2e --- /dev/null +++ b/kernel/include/kernel/test_support/page_mapper.hpp @@ -0,0 +1,33 @@ +#ifndef TEACHOS_KERNEL_TEST_SUPPORT_PAGE_MAPPER_HPP +#define TEACHOS_KERNEL_TEST_SUPPORT_PAGE_MAPPER_HPP + +#include "kapi/memory.hpp" + +#include "kernel/test_support/simulated_memory.hpp" + +#include <kstd/units> + +#include <cstddef> +#include <cstdint> +#include <unordered_map> + +namespace kernel::tests +{ + + struct page_mapper : kapi::memory::page_mapper + { + explicit page_mapper(kstd::units::bytes memory_size); + + auto map(kapi::memory::page page, kapi::memory::frame frame, flags) -> std::byte * override; + + auto unmap(kapi::memory::page page) -> void override; + + auto try_unmap(kapi::memory::page page) noexcept -> bool override; + + kernel::tests::simulated_memory memory; + std::unordered_map<std::uint64_t, kapi::memory::frame> page_mappings; + }; + +} // namespace kernel::tests + +#endif
\ No newline at end of file diff --git a/kernel/include/kernel/test_support/simulated_memory.hpp b/kernel/include/kernel/test_support/simulated_memory.hpp new file mode 100644 index 0000000..9a391d8 --- /dev/null +++ b/kernel/include/kernel/test_support/simulated_memory.hpp @@ -0,0 +1,36 @@ +#ifndef TEACHOS_KERNEL_TEST_SUPPORT_SIMULATED_MEMORY_HPP +#define TEACHOS_KERNEL_TEST_SUPPORT_SIMULATED_MEMORY_HPP + +#include "kapi/memory.hpp" + +#include <kstd/units> + +#include <cstddef> + +namespace kernel::tests +{ + + struct simulated_memory + { + explicit simulated_memory(kstd::units::bytes size); + + ~simulated_memory(); + + auto clear() -> void; + + [[nodiscard]] auto ram_base() noexcept -> std::byte *; + [[nodiscard]] auto ram_base() const noexcept -> std::byte const *; + [[nodiscard]] auto heap_base() const noexcept -> kapi::memory::linear_address; + [[nodiscard]] auto heap_size() const noexcept -> kstd::units::bytes; + [[nodiscard]] auto memory_descriptor() const noexcept -> int; + + private: + int m_memory_descriptor{}; + kstd::units::bytes m_size{0}; + std::byte * m_physical_base{nullptr}; + std::byte * m_virtual_base{nullptr}; + }; + +} // namespace kernel::tests + +#endif
\ No newline at end of file diff --git a/kernel/kapi/cpu.tests.cpp b/kernel/kapi/cpu.tests.cpp new file mode 100644 index 0000000..85b20fd --- /dev/null +++ b/kernel/kapi/cpu.tests.cpp @@ -0,0 +1,19 @@ +#include "kapi/cpu.hpp" + +#include "kernel/test_support/cpu.hpp" + +#include <catch2/catch_test_macros.hpp> + +SCENARIO("Kernel testing kapi::cpu shims", "[support]") +{ + GIVEN("the test support infrastructure is initialized") + { + WHEN("a CPU halt is requested") + { + THEN("the correct exception is thrown") + { + REQUIRE_THROWS_AS(kapi::cpu::halt(), kernel::tests::cpu::halt); + } + } + } +}
\ No newline at end of file diff --git a/kernel/kapi/memory.cpp b/kernel/kapi/memory.cpp index 2803d76..06a3165 100644 --- a/kernel/kapi/memory.cpp +++ b/kernel/kapi/memory.cpp @@ -125,14 +125,18 @@ namespace kapi::memory } auto const flags = page_mapper::flags::writable | page_mapper::flags::supervisor_only | page_mapper::flags::global; + auto bitmap_ptr = static_cast<std::uint64_t *>(nullptr); std::ranges::for_each(std::views::iota(0uz, bitmap_pages), [&](auto index) { auto page = page::containing(pmm_metadata_base + index * page::size); auto frame = memory::frame(bitmap_frames->first.number() + index); - active_page_mapper->map(page, frame, flags); + auto mapped = active_page_mapper->map(page, frame, flags); + if (!bitmap_ptr) + { + bitmap_ptr = reinterpret_cast<std::uint64_t *>(mapped); + } }); - auto bitmap_ptr = static_cast<std::uint64_t *>(pmm_metadata_base); auto bitmap = std::span{bitmap_ptr, (bitmap_bytes + kstd::type_size<std::uint64_t> - 1_B) / kstd::type_size<std::uint64_t>}; diff --git a/kernel/kapi/system.tests.cpp b/kernel/kapi/system.tests.cpp new file mode 100644 index 0000000..ee31c51 --- /dev/null +++ b/kernel/kapi/system.tests.cpp @@ -0,0 +1,30 @@ +#include "kapi/system.hpp" + +#include "kernel/test_support/cpu.hpp" +#include "kernel/test_support/log_buffer.hpp" + +#include <kstd/print> + +#include <catch2/catch_test_macros.hpp> + +SCENARIO("Kernel testing kapi::system shims", "[support]") +{ + GIVEN("the test support infrastructure is initialized") + { + WHEN("a the system panics") + { + kernel::tests::log_buffer::clear(); + + THEN("the correct exception is thrown") + { + REQUIRE_THROWS_AS(kapi::system::panic("[kernel:tests] Test Panic"), kernel::tests::cpu::halt); + } + + THEN("the message is appended to the log buffer") + { + CHECK_THROWS(kapi::system::panic("[kernel:tests] Test Panic")); + REQUIRE(kernel::tests::log_buffer::flat_messages().contains("[kernel:tests] Test Panic")); + } + } + } +}
\ No newline at end of file diff --git a/kernel/kstd/print.tests.cpp b/kernel/kstd/print.tests.cpp new file mode 100644 index 0000000..f8e600f --- /dev/null +++ b/kernel/kstd/print.tests.cpp @@ -0,0 +1,23 @@ +#include "kstd/print" + +#include "kernel/test_support/log_buffer.hpp" + +#include <catch2/catch_test_macros.hpp> + +SCENARIO("Kernel testing kstd shims", "[support]") +{ + GIVEN("the test support infrastructure is initialized") + { + WHEN("a regular print is issued") + { + kernel::tests::log_buffer::clear(); + + kstd::println("[kernel:tests] Test Print"); + + THEN("the message is appended to the log buffer") + { + REQUIRE(kernel::tests::log_buffer::flat_messages().contains("[kernel:tests] Test Print")); + } + } + } +}
\ No newline at end of file diff --git a/kernel/src/devices/storage/ram_disk/device.tests.cpp b/kernel/src/devices/storage/ram_disk/device.tests.cpp new file mode 100644 index 0000000..eacdb04 --- /dev/null +++ b/kernel/src/devices/storage/ram_disk/device.tests.cpp @@ -0,0 +1,117 @@ +#include "kernel/devices/storage/ram_disk/device.hpp" + +#include "kapi/boot_module/boot_module.hpp" +#include "kapi/memory.hpp" + +#include "catch2/matchers/catch_matchers.hpp" +#include "catch2/matchers/catch_matchers_range_equals.hpp" + +#include <catch2/catch_test_macros.hpp> + +#include <cstddef> +#include <ranges> +#include <stdexcept> +#include <vector> + +SCENARIO("RAM Disk Device Construction and Initialization", "[ram_disk_device]") +{ + GIVEN("an empty boot module") + { + kapi::boot_modules::boot_module boot_module{}; + boot_module.start_address = kapi::memory::linear_address{nullptr}; + boot_module.size = 0; + + WHEN("constructing the device") + { + kernel::devices::storage::ram_disk::device device{boot_module, 0, 0}; + + THEN("init return false") + { + REQUIRE_FALSE(device.init()); + } + } + } + + GIVEN("a boot module with a valid start address and size") + { + kapi::boot_modules::boot_module boot_module{}; + boot_module.start_address = kapi::memory::linear_address{reinterpret_cast<std::byte *>(0x1000)}; + boot_module.size = 512; + + WHEN("constructing the device") + { + kernel::devices::storage::ram_disk::device device{boot_module, 0, 0}; + + THEN("init return true") + { + REQUIRE(device.init()); + } + } + } +} + +SCENARIO("RAM Disk Device Read and Write", "[ram_disk_device]") +{ + GIVEN("a device initialized with a valid boot module") + { + auto storage = std::vector{4096, std::byte{0xff}}; + auto module = + kapi::boot_modules::boot_module{"test_module", kapi::memory::linear_address{storage.data()}, storage.size()}; + auto device = kernel::devices::storage::ram_disk::device{module, 0, 0}; + REQUIRE(device.init()); + + WHEN("reading a full block from the device") + { + auto buffer = std::vector<std::byte>(device.block_size()); + device.read_block(0, buffer.data()); + + THEN("the buffer is filled with the module data") + { + REQUIRE_THAT(buffer, Catch::Matchers::RangeEquals(std::views::take(storage, device.block_size()))); + } + } + + WHEN("reading from a block index beyond the module size") + { + auto buffer = std::vector<std::byte>(device.block_size()); + device.read_block(10, buffer.data()); + + THEN("the buffer is filled with zeros") + { + REQUIRE_THAT(buffer, Catch::Matchers::RangeEquals(std::vector<std::byte>(device.block_size(), std::byte{0}))); + } + } + + WHEN("reading into a null buffer") + { + REQUIRE_THROWS_AS(device.read_block(0, nullptr), std::runtime_error); + } + + WHEN("writing to a full block") + { + auto buffer = std::vector<std::byte>(device.block_size(), std::byte{0x01}); + device.write_block(0, buffer.data()); + + THEN("the module data is updated") + { + REQUIRE_THAT(std::views::take(storage, device.block_size()), Catch::Matchers::RangeEquals(buffer)); + } + } + + WHEN("writing to a block index beyond the module size") + { + auto buffer = std::vector<std::byte>(device.block_size(), std::byte{0x01}); + device.write_block(10, buffer.data()); + + THEN("the module data is not updated") + { + REQUIRE_THAT(storage, Catch::Matchers::RangeEquals(std::vector{4096, std::byte{0xff}})); + } + } + + WHEN("writing from a null buffer") + { + REQUIRE_THROWS_AS(device.write_block(0, nullptr), std::runtime_error); + } + } +}
\ No newline at end of file diff --git a/kernel/src/memory/bitmap_allocator.cpp b/kernel/src/memory/bitmap_allocator.cpp index c010f77..caaf5a4 100644 --- a/kernel/src/memory/bitmap_allocator.cpp +++ b/kernel/src/memory/bitmap_allocator.cpp @@ -6,6 +6,7 @@ #include <cstddef> #include <cstdint> #include <optional> +#include <ranges> #include <span> #include <utility> @@ -17,7 +18,9 @@ namespace kernel::memory , m_frame_count{frame_count} , m_last_index{} { - std::ranges::fill(m_bitmap, ~0uz); + constexpr auto bits_per_word = 64uz; + auto to_fill = (frame_count + bits_per_word - 1) / bits_per_word; + std::ranges::fill(std::views::take(m_bitmap, to_fill), ~0uz); } auto bitmap_frame_allocator::allocate_many(std::size_t count) noexcept @@ -78,22 +81,25 @@ namespace kernel::memory auto bitmap_frame_allocator::test(std::size_t index) const noexcept -> bool { - auto entry_entry = index / 64; - auto entry_offset = index % 64; + constexpr auto bits_per_word = 64uz; + auto entry_entry = index / bits_per_word; + auto entry_offset = index % bits_per_word; return (m_bitmap[entry_entry] & (1uz << entry_offset)); } auto bitmap_frame_allocator::set(std::size_t index) noexcept -> void { - auto entry_entry = index / 64; - auto entry_offset = index % 64; + constexpr auto bits_per_word = 64uz; + auto entry_entry = index / bits_per_word; + auto entry_offset = index % bits_per_word; m_bitmap[entry_entry] |= (1uz << entry_offset); } auto bitmap_frame_allocator::clear(std::size_t index) noexcept -> void { - auto entry_entry = index / 64; - auto entry_offset = index % 64; + constexpr auto bits_per_word = 64uz; + auto entry_entry = index / bits_per_word; + auto entry_offset = index % bits_per_word; m_bitmap[entry_entry] &= ~(1uz << entry_offset); } diff --git a/kernel/src/memory/bitmap_allocator.tests.cpp b/kernel/src/memory/bitmap_allocator.tests.cpp new file mode 100644 index 0000000..56ec0a4 --- /dev/null +++ b/kernel/src/memory/bitmap_allocator.tests.cpp @@ -0,0 +1,289 @@ +#include "kernel/memory/bitmap_allocator.hpp" + +#include "kapi/memory.hpp" + +#include "catch2/matchers/catch_matchers.hpp" +#include "catch2/matchers/catch_matchers_range_equals.hpp" + +#include <catch2/catch_test_macros.hpp> + +#include <cstdint> +#include <limits> +#include <ranges> +#include <span> +#include <vector> + +constexpr auto all_bits_set = std::numeric_limits<std::uint64_t>::max(); +constexpr auto available_frames = 1024uz; + +SCENARIO("Bitmap allocator construction and initialization", "[memory][bitmap_allocator]") +{ + GIVEN("A storage region") + { + auto storage = std::vector(available_frames / 64, 0uz); + + WHEN("constructing the allocator with 0 frames") + { + auto allocator = kernel::memory::bitmap_frame_allocator{std::span(storage), 0}; + + THEN("the storage region is not modified") + { + REQUIRE_THAT(storage, Catch::Matchers::RangeEquals(std::vector(16, 0uz))); + } + } + + WHEN("constructing with 1 frame") + { + auto allocator = kernel::memory::bitmap_frame_allocator{std::span(storage), 1}; + + THEN("the first word of the storage region is set to all ones") + { + REQUIRE_THAT(std::views::take(storage, 1), Catch::Matchers::RangeEquals(std::vector(1, all_bits_set))); + } + + THEN("the rest of the storage region is not modified") + { + REQUIRE_THAT(std::views::drop(storage, 1), Catch::Matchers::RangeEquals(std::vector(15, 0uz))); + } + } + + WHEN("constructing with 64 frames") + { + auto allocator = kernel::memory::bitmap_frame_allocator{std::span(storage), 64}; + + THEN("the first word of the storage region is set to all ones") + { + REQUIRE_THAT(std::views::take(storage, 1), Catch::Matchers::RangeEquals(std::vector(1, all_bits_set))); + } + + THEN("the rest of the storage region is not modified") + { + REQUIRE_THAT(std::views::drop(storage, 1), Catch::Matchers::RangeEquals(std::vector(15, 0uz))); + } + } + + WHEN("constructing with all available frames") + { + auto allocator = kernel::memory::bitmap_frame_allocator{std::span(storage), available_frames}; + + THEN("the storage region is filled with all ones") + { + REQUIRE_THAT(storage, Catch::Matchers::RangeEquals(std::vector(16, all_bits_set))); + } + } + + WHEN("constructing with half the available frames") + { + auto allocator = kernel::memory::bitmap_frame_allocator{std::span(storage), available_frames / 2}; + + THEN("the first half of the storage region is filled with all ones") + { |
