Testing and Validation

Relevant source files

This page provides a comprehensive guide to the test suite for the slab_allocator crate. It covers the test infrastructure, validation scenarios, test execution procedures, and analysis of different allocation patterns used to ensure the reliability and correctness of the hybrid memory allocation system.

For information about the core allocation architecture being tested, see Core Architecture. For API usage patterns demonstrated in tests, see API Reference.

Test Infrastructure

The test suite is built around two primary test heap configurations that provide controlled environments for validation.

Test Heap Configurations

The testing infrastructure uses statically allocated, page-aligned memory regions to simulate real-world heap conditions:

ConfigurationSizePurpose
TestHeap64KB (16 × 4096 bytes)Small-scale allocation testing
TestBigHeap640KB (64KB × 10)Large allocation and growth testing
flowchart TD
subgraph subGraph1["Test Infrastructure Architecture"]
    A["TestHeap"]
    B["64KB aligned memory"]
    C["TestBigHeap"]
    D["640KB aligned memory"]
    E["new_heap()"]
    F["new_big_heap()"]
    G["Heap::new()"]
    H["Test Execution"]
    subgraph subGraph0["Memory Layout"]
        I["#[repr(align(4096))]"]
        J["heap_space: [u8; SIZE]"]
    end
end

A --> B
A --> I
B --> E
B --> J
C --> D
C --> I
D --> F
D --> J
E --> G
F --> G
G --> H

The test structures use #[repr(align(4096))] to ensure proper page alignment, which is critical for the underlying buddy allocator's operation.

Sources: src/tests.rs(L8 - L16)  src/tests.rs(L18 - L37) 

Test Heap Factory Functions

Two factory functions provide standardized heap initialization:

  • new_heap() - Creates a 64KB heap instance for basic allocation testing
  • new_big_heap() - Creates a 640KB heap instance for large allocation scenarios

These functions handle the unsafe memory region setup and return initialized Heap instances ready for testing.

Sources: src/tests.rs(L18 - L37) 

Test Categories and Validation Scenarios

The test suite validates the allocator through several distinct categories of allocation patterns and edge cases.

Memory Exhaustion Testing

flowchart TD
subgraph subGraph0["OOM Test Flow"]
    A["oom() test"]
    B["Request HEAP_SIZE + 1 bytes"]
    C["Layout::from_size_align()"]
    D["heap.allocate()"]
    E["Verify Error Result"]
    F["Heap: 64KB"]
    G["Request: 64KB + 1"]
    H["Expected: Allocation Failure"]
end

A --> B
B --> C
C --> D
D --> E
F --> G
G --> H

The oom() test validates out-of-memory handling by requesting more memory than the total heap capacity. This ensures the allocator gracefully handles resource exhaustion rather than causing undefined behavior.

Sources: src/tests.rs(L39 - L45) 

Basic Allocation Patterns

The test suite validates fundamental allocation operations through progressively complex scenarios:

Test FunctionAllocation SizeValidation Focus
allocate_double_usize()2 ×usizeBasic allocation success
allocate_and_free_double_usize()2 ×usizeAllocation + deallocation cycle
reallocate_double_usize()2 ×usizeMemory reuse verification
flowchart TD
subgraph subGraph0["Basic Allocation Test Flow"]
    A["Layout Creation"]
    B["size_of::() * 2"]
    C["align_of::()"]
    D["Layout::from_size_align()"]
    E["heap.allocate()"]
    F["Success Verification"]
    G["Memory Write Test"]
    H["0xdeafdeadbeafbabe pattern"]
    I["heap.deallocate()"]
    J["Memory Reuse Check"]
end

A --> B
A --> C
B --> D
C --> D
D --> E
E --> F
F --> G
G --> H
H --> I
I --> J

Sources: src/tests.rs(L47 - L87) 

Multi-Size Allocation Testing

The allocate_multiple_sizes() test validates the allocator's ability to handle concurrent allocations of different sizes and alignments:

  • Size Variations: 2×, 3×, 10× base usize
  • Alignment Variations: Standard alignment and 8× alignment
  • Deallocation Patterns: Non-sequential deallocation order

This test ensures the slab allocator correctly routes different sizes to appropriate slabs and handles fragmentation scenarios.

Sources: src/tests.rs(L89 - L117) 

Large Block Allocation Testing

Two specialized tests validate large allocation handling that exceeds the slab threshold:

flowchart TD
subgraph subGraph0["Large Block Test Strategy"]
    A["allocate_one_4096_block()"]
    B["Single 4KB allocation"]
    C["allocate_multiple_4096_blocks()"]
    D["Multiple 4KB+ allocations"]
    E["512 * usize allocation"]
    F["Mixed size allocations"]
    G["Complex deallocation patterns"]
    H["Buddy allocator routing"]
    I["Memory pattern verification"]
    J["0xdeafdeadbeafbabe write test"]
end

A --> B
B --> E
C --> D
D --> F
D --> G
E --> H
F --> H
G --> H
H --> I
I --> J

These tests specifically target the boundary between slab allocation (≤4096 bytes) and buddy allocation (>4096 bytes), ensuring proper routing and memory management across the threshold.

Sources: src/tests.rs(L119 - L163) 

Test Execution and Validation Patterns

Layout-Based Testing

All tests use Rust's Layout type to specify allocation requirements, ensuring compatibility with the standard allocator interface:

// Example pattern from tests
let layout = Layout::from_size_align(size, alignment).unwrap();
let addr = heap.allocate(layout.clone());

This approach validates that the allocator correctly handles:

  • Size requirements
  • Alignment constraints
  • Error propagation
  • Memory safety

Memory Pattern Verification

Critical tests write specific bit patterns to allocated memory to verify:

  • Successful memory access
  • Proper alignment
  • Data integrity across allocation/deallocation cycles

The pattern 0xdeafdeadbeafbabe is used as a recognizable marker for debugging and validation.

Sources: src/tests.rs(L64)  src/tests.rs(L161) 

Allocation Lifecycle Testing

flowchart TD
subgraph subGraph0["Complete Allocation Lifecycle"]
    A["Allocate"]
    B["Write Pattern"]
    C["Verify Access"]
    D["Deallocate"]
    E["Re-allocate"]
    F["Verify Reuse"]
    G["Layout Creation"]
    H["Error Handling"]
    I["Memory Safety"]
    J["Resource Management"]
end

A --> B
B --> C
C --> D
D --> E
E --> F
G --> A
H --> A
I --> C
J --> D

Tests validate the complete allocation lifecycle to ensure:

  • Proper initialization
  • Safe memory access
  • Correct deallocation
  • Memory reuse efficiency
  • No memory leaks

Sources: src/tests.rs(L71 - L87) 

Running the Test Suite

The test suite runs using Rust's standard testing framework:

cargo test

Target Platform Testing

The CI/CD pipeline executes tests across multiple target platforms:

  • x86_64-unknown-linux-gnu (with full test execution)
  • x86_64-unknown-none (build verification)
  • riscv64gc-unknown-none-elf (build verification)
  • aarch64-unknown-none-softfloat (build verification)

This ensures the allocator works correctly across different embedded and no_std environments.

Sources: Based on repository CI/CD configuration referenced in overview diagrams

Test Coverage Analysis

The test suite provides comprehensive coverage of the allocator's functionality:

ComponentTest Coverage
Heap initialization✓ Factory functions
Small allocations✓ Slab routing tests
Large allocations✓ Buddy allocator tests
Memory exhaustion✓ OOM handling
Fragmentation✓ Multi-size patterns
Alignment✓ Various alignment requirements
Memory reuse✓ Allocation/deallocation cycles

The tests validate both the high-level Heap interface and the underlying allocation strategy switching between slab and buddy allocation based on size thresholds.

Sources: src/tests.rs(L1 - L164)