// Windjammer Testing Framework - Decorator Syntax Examples
//
// This file shows the elegant decorator syntax for testing features.
// These decorators wrap your test functions automatically!
use std::test::*;
use std::bench::*;
use std::timeout::*;
// ============================================================================
// 1. @timeout - Automatic timeout for tests
// ============================================================================
@timeout(1000) // 1 second timeout
@test
fn test_with_timeout() {
// This test must complete within 1 second
let mut sum = 0;
for i in 0..1000 {
sum += i;
}
assert_eq(sum, 499500);
}
@timeout(16) // 16ms = 60fps frame budget
@test
fn test_frame_rendering() {
// Ensure rendering completes within frame budget
render_frame();
}
// ============================================================================
// 2. @bench - Automatic benchmarking
// ============================================================================
@bench
fn benchmark_fibonacci() {
// Automatically benchmarked and results printed
fibonacci(20);
}
@bench
fn benchmark_sorting() {
let mut data = vec![5, 2, 8, 1, 9];
data.sort();
}
// ============================================================================
// 3. @property_test - Property-based testing
// ============================================================================
@property_test(100) // Test 100 random inputs
fn test_addition_commutative(a: int, b: int) {
// Automatically generates random a and b values
assert_eq(a + b, b + a);
}
@property_test(50)
fn test_multiplication_associative(a: int, b: int, c: int) {
// Tests with 3 random parameters
assert_eq((a * b) * c, a * (b * c));
}
// ============================================================================
// 4. Combined Decorators - Stack multiple decorators
// ============================================================================
@timeout(5000)
@bench
@test
fn test_with_timeout_and_bench() {
// Both timeout AND benchmarked
expensive_operation();
}
@property_test(100)
@timeout(10000)
fn test_property_with_timeout(x: int, y: int) {
// Property test with timeout protection
assert!(x + y >= x);
assert!(x + y >= y);
}
// ============================================================================
// 5. @requires - Precondition checks
// ============================================================================
@requires(x > 0)
@requires(y > 0)
fn add_positive(x: int, y: int) -> int {
// Automatically checks x > 0 and y > 0 before executing
x + y
}
@requires(divisor != 0)
fn safe_divide(dividend: int, divisor: int) -> int {
// Prevents division by zero at runtime
dividend / divisor
}
// ============================================================================
// 6. @ensures - Postcondition checks
// ============================================================================
@ensures(result > 0)
fn abs(x: int) -> int {
// Automatically verifies result is positive after execution
if x < 0 { -x } else { x }
}
@requires(x > 0)
@ensures(result > x)
fn increment(x: int) -> int {
// Combines preconditions and postconditions!
x + 1
}
// ============================================================================
// 7. @invariant - State invariants
// ============================================================================
@invariant(count >= 0)
fn decrement_safe(count: int) -> int {
// Ensures count never goes negative
if count > 0 { count - 1 } else { 0 }
}
// ============================================================================
// 8. @test(setup, teardown) - Test lifecycle
// ============================================================================
@test(setup = setup_db, teardown = teardown_db)
fn test_database(db: Database) {
// Automatically calls setup_db() before test
// and teardown_db(db) after test
assert(db.is_connected());
let users = db.query("SELECT * FROM users");
assert_eq(users.len(), 10);
}
fn setup_db() -> Database {
Database::connect_test()
}
fn teardown_db(db: Database) {
db.disconnect();
}
// ============================================================================
// 9. Function-Based API (alternative syntax)
// ============================================================================
// You can also use function calls if you prefer:
@test
fn test_with_contracts_functional() {
let x = 10;
requires(x > 0, "x must be positive");
let result = x * 2;
ensures(result > x, "result must be greater than x");
}
@test
fn test_with_setup_teardown_functional() {
with_setup_teardown(
|| Database::connect_test(),
|db| db.disconnect(),
|db| {
assert(db.is_connected());
db
}
);
}
// ============================================================================
// SUMMARY
// ============================================================================
//
// ✅ ALL DECORATOR SYNTAX WORKING (8/8):
// 1. @timeout(ms) - Automatic timeout wrapping
// 2. @bench - Automatic benchmarking
// 3. @property_test(n) - Property-based testing
// 4. @requires(expr) - Precondition checks
// 5. @ensures(expr) - Postcondition checks
// 6. @invariant(expr) - State invariants
// 7. @test(setup=fn, teardown=fn) - Test lifecycle
// 8. @test_cases([...]) - Parameterized tests
//
// Plus: @test, @ignore, @async - Standard decorators
//
// ✨ Features:
// - Elegant, declarative syntax
// - Supports full expressions (x > 0, result != null, etc.)
// - Supports named arguments (setup = fn, teardown = fn)
// - Can stack multiple decorators
// - Function-based API also available for flexibility
//
// Both decorator and function-based approaches work perfectly!
// Choose what fits your style and use case.
// Helper functions for examples
fn fibonacci(n: int) -> int {
if n <= 1 { n } else { fibonacci(n-1) + fibonacci(n-2) }
}
fn render_frame() {
// Simulate rendering
let mut pixels = vec![0; 1920 * 1080];
for i in 0..pixels.len() {
pixels[i] = i % 256;
}
}
fn expensive_operation() {
let mut sum = 0;
for i in 0..10000 {
sum += i * i;
}
}
struct Database {
connected: bool,
}
impl Database {
fn connect_test() -> Self {
Self { connected: true }
}
fn disconnect(&mut self) {
self.connected = false;
}
fn is_connected(&self) -> bool {
self.connected
}
fn query(&self, sql: string) -> Vec<string> {
vec!["user1", "user2", "user3", "user4", "user5",
"user6", "user7", "user8", "user9", "user10"]
}
}