elicitation_kani 0.11.1

Kani model-checking proofs for elicitation contract types
Documentation
//! Kani proofs for jiff datetime generators.
//!
//! These proofs verify the correctness of jiff generator wrapper logic
//! following the "castle on cloud" + symbolic gate pattern.
//!
//! NOTE: jiff's Span arithmetic creates large state spaces, so we use
//! symbolic gate verification (verify decision logic without calling generate).

#![cfg(kani)]
#![cfg(feature = "jiff")]

use elicitation::{Generator, TimestampGenerationMode, TimestampGenerator};
use jiff::Timestamp;

// ============================================================================
// Timestamp Generator Proofs
// ============================================================================

/// Verify UnixEpoch mode produces UNIX_EPOCH.
///
/// This proof can call generate() because it doesn't involve arithmetic.
#[kani::proof]
fn verify_timestamp_generator_unix_epoch() {
    let mode = TimestampGenerationMode::UnixEpoch;
    let reference = Timestamp::UNIX_EPOCH;
    let generator = TimestampGenerator::with_reference(mode, reference);

    let ts = generator.generate();

    assert_eq!(
        ts,
        Timestamp::UNIX_EPOCH,
        "UnixEpoch mode produces UNIX_EPOCH"
    );
}

/// Verify positive offset decision logic.
///
/// Symbolic gate: Verify wrapper's decision logic for positive offsets
/// without calling jiff's Span arithmetic.
#[kani::proof]
fn verify_timestamp_generator_offset_positive_logic() {
    let seconds: i64 = kani::any();

    kani::assume(seconds > 0);
    kani::assume(seconds < 100_000);

    let mode = TimestampGenerationMode::Offset { seconds };

    // Verify the wrapper's decision logic
    match mode {
        TimestampGenerationMode::Now => {
            assert!(false, "Wrong branch");
        }
        TimestampGenerationMode::UnixEpoch => {
            assert!(false, "Wrong branch");
        }
        TimestampGenerationMode::Offset { seconds: s } => {
            // Verify positive offset is stored correctly
            assert!(s > 0, "Positive seconds");
            assert_eq!(s, seconds);

            // The actual generate() would do:
            // let span = Span::new().seconds(seconds);
            // self.reference.checked_add(span).unwrap_or(self.reference)
            // We trust jiff's Span and checked_add work correctly
        }
    }
}

/// Verify negative offset decision logic.
#[kani::proof]
fn verify_timestamp_generator_offset_negative_logic() {
    let seconds: i64 = kani::any();

    kani::assume(seconds < 0);
    kani::assume(seconds > -100_000);

    let mode = TimestampGenerationMode::Offset { seconds };

    match mode {
        TimestampGenerationMode::Offset { seconds: s } => {
            // Verify negative offset is stored correctly
            assert!(s < 0, "Negative seconds");
            assert_eq!(s, seconds);

            // jiff's Span handles negative seconds correctly (subtraction)
            // We trust jiff's implementation
        }
        _ => assert!(false, "Wrong branch"),
    }
}

/// Verify zero offset decision logic.
#[kani::proof]
fn verify_timestamp_generator_offset_zero_logic() {
    let mode = TimestampGenerationMode::Offset { seconds: 0 };

    match mode {
        TimestampGenerationMode::Offset { seconds } => {
            assert_eq!(seconds, 0);

            // With zero seconds, Span::new().seconds(0) is identity
            // checked_add with zero span returns reference unchanged
            // We verify the wrapper uses the correct mode
        }
        _ => assert!(false, "Wrong branch"),
    }
}

/// Verify generator mode is preserved.
#[kani::proof]
fn verify_timestamp_generator_mode_preserved() {
    let mode = TimestampGenerationMode::UnixEpoch;
    let reference = Timestamp::UNIX_EPOCH;
    let generator = TimestampGenerator::with_reference(mode, reference);

    assert_eq!(generator.mode(), mode, "Generator preserves mode");
}

/// Verify generator reference is preserved.
#[kani::proof]
fn verify_timestamp_generator_reference_preserved() {
    let mode = TimestampGenerationMode::UnixEpoch;
    let reference = Timestamp::UNIX_EPOCH;
    let generator = TimestampGenerator::with_reference(mode, reference);

    assert_eq!(
        generator.reference(),
        reference,
        "Generator preserves reference"
    );
}