#![cfg(kani)]
use crate::verification::Contract;
use crate::verification::contracts::{BoolValid, I32Positive, StringNonEmpty};
#[kani::proof]
fn verify_string_non_empty_contract() {
let inputs = [
String::from("a"),
String::from("hello"),
String::from("test string"),
String::from("x".repeat(50)),
];
for input in inputs.iter() {
kani::assume(StringNonEmpty::requires(input));
assert!(!input.is_empty());
assert!(input.len() > 0);
let output = input.clone();
assert!(StringNonEmpty::ensures(input, &output));
assert!(!output.is_empty());
}
}
#[kani::proof]
fn verify_i32_positive_contract() {
let input: i32 = kani::any();
kani::assume(I32Positive::requires(&input));
assert!(input > 0);
let output = input;
assert!(I32Positive::ensures(&input, &output));
assert!(output > 0);
}
#[kani::proof]
fn verify_bool_valid_contract() {
let input: bool = kani::any();
assert!(BoolValid::requires(&input));
let output = !input; assert!(BoolValid::ensures(&input, &output));
}
struct NonEmptyString;
impl Contract for NonEmptyString {
type Input = String;
type Output = String;
fn requires(input: &String) -> bool {
!input.is_empty()
}
fn ensures(_input: &String, output: &String) -> bool {
!output.is_empty()
}
}
struct ValidEmail;
impl Contract for ValidEmail {
type Input = String;
type Output = String;
fn requires(input: &String) -> bool {
input.contains('@') && input.len() > 2
}
fn ensures(_input: &String, output: &String) -> bool {
output.contains('@')
}
}
struct PositiveNumber;
impl Contract for PositiveNumber {
type Input = i32;
type Output = i32;
fn requires(input: &i32) -> bool {
*input > 0
}
fn ensures(_input: &i32, output: &i32) -> bool {
*output > 0
}
}
#[kani::proof]
fn verify_non_empty_string_contract() {
let input = String::from("test");
kani::assume(NonEmptyString::requires(&input));
assert!(!input.is_empty());
}
#[kani::proof]
fn verify_email_requires_at_symbol() {
let input = String::from("user@example.com");
kani::assume(ValidEmail::requires(&input));
assert!(input.contains('@'));
assert!(input.len() > 2);
}
#[kani::proof]
fn verify_positive_number_contract() {
let input: i32 = kani::any();
kani::assume(PositiveNumber::requires(&input));
assert!(input > 0);
}
#[kani::proof]
fn verify_contract_composition_preconditions() {
let email = String::from("user@example.com");
kani::assume(ValidEmail::ensures(&email, &email));
assert!(email.contains('@'));
assert!(NonEmptyString::requires(&email));
}
#[kani::proof]
fn verify_proof_zero_sized() {
use crate::contracts::{Established, Is};
let proof: Established<Is<String>> = Established::assert();
assert_eq!(std::mem::size_of_val(&proof), 0);
let proof_i32: Established<Is<i32>> = Established::assert();
assert_eq!(std::mem::size_of_val(&proof_i32), 0);
}
#[kani::proof]
fn verify_conjunction_projects() {
use crate::contracts::{Established, Is, both, fst, snd};
let p: Established<Is<String>> = Established::assert();
let q: Established<Is<i32>> = Established::assert();
let pq = both(p, q);
let _p2: Established<Is<String>> = fst(pq);
let _q2: Established<Is<i32>> = snd(pq);
}
#[kani::proof]
fn verify_reflexive_implies() {
use crate::contracts::{Established, Is};
let proof: Established<Is<String>> = Established::assert();
let same: Established<Is<String>> = proof.weaken();
assert_eq!(std::mem::size_of_val(&same), 0);
}
#[kani::proof]
fn verify_true_axiom() {
use crate::tool::True;
let _proof1 = True::axiom();
let _proof2 = True::axiom();
let _proof3 = True::axiom();
let proof = True::axiom();
assert_eq!(std::mem::size_of_val(&proof), 0);
}
#[kani::proof]
fn verify_invariant_zero_sized() {
use crate::contracts::{Established, InVariant};
enum State {
Active,
Inactive,
}
struct ActiveVariant;
let proof: Established<InVariant<State, ActiveVariant>> = Established::assert();
assert_eq!(std::mem::size_of_val(&proof), 0);
}
#[kani::proof]
fn verify_conjunction_associative() {
use crate::contracts::{And, Established, Is, both};
struct P;
struct Q;
struct R;
impl crate::contracts::Prop for P {}
impl crate::contracts::Prop for Q {}
impl crate::contracts::Prop for R {}
let p: Established<P> = Established::assert();
let q: Established<Q> = Established::assert();
let r: Established<R> = Established::assert();
let pq = both(p, q);
let _pqr: Established<And<And<P, Q>, R>> = both(pq, r);
}
#[kani::proof]
fn verify_tool_requires_precondition() {
use crate::contracts::{Established, Prop};
use crate::tool::True;
struct Validated;
impl Prop for Validated {}
fn mock_tool(_input: String, _pre: Established<Validated>) -> (String, Established<True>) {
("output".to_string(), True::axiom())
}
let proof: Established<Validated> = Established::assert();
let (_result, _post) = mock_tool("input".to_string(), proof);
}
#[kani::proof]
fn verify_true_always_available() {
use crate::tool::True;
let _proof1 = True::axiom();
let _proof2 = True::axiom();
fn unconstrained_tool(_input: String, _pre: crate::contracts::Established<True>) -> String {
"result".to_string()
}
let _result = unconstrained_tool("input".to_string(), True::axiom());
}
#[kani::proof]
fn verify_tool_chain_composition() {
use crate::contracts::{Established, Implies, Prop};
use crate::tool::True;
struct InputValid;
struct OutputTransformed;
impl Prop for InputValid {}
impl Prop for OutputTransformed {}
impl Implies<OutputTransformed> for InputValid {}
fn validate(_input: String, _pre: Established<True>) -> (String, Established<InputValid>) {
("validated".to_string(), Established::assert())
}
fn transform(
_input: String,
_pre: Established<OutputTransformed>,
) -> (String, Established<True>) {
("transformed".to_string(), True::axiom())
}
let (_validated, proof1) = validate("input".to_string(), True::axiom());
let proof2: Established<OutputTransformed> = proof1.weaken(); let (_result, _proof_final) = transform("validated".to_string(), proof2);
}
#[kani::proof]
fn verify_parallel_composition() {
use crate::contracts::{And, Established, Prop, both, fst, snd};
use crate::tool::True;
struct EmailValidated;
struct PhoneValidated;
impl Prop for EmailValidated {}
impl Prop for PhoneValidated {}
fn validate_email(
_email: String,
_pre: Established<True>,
) -> (String, Established<EmailValidated>) {
("email@example.com".to_string(), Established::assert())
}
fn validate_phone(
_phone: String,
_pre: Established<True>,
) -> (String, Established<PhoneValidated>) {
("+1234567890".to_string(), Established::assert())
}
let pre1 = True::axiom();
let pre2 = True::axiom();
let combined_pre = both(pre1, pre2);
let p1 = fst(combined_pre);
let p2 = snd(combined_pre);
let (_email, email_proof) = validate_email("test@example.com".to_string(), p1);
let (_phone, phone_proof) = validate_phone("1234567890".to_string(), p2);
let _combined_post: Established<And<EmailValidated, PhoneValidated>> =
both(email_proof, phone_proof);
}
#[kani::proof]
fn verify_refinement_soundness() {
use crate::contracts::{Established, Implies, Is, Refines, downcast};
struct NonEmptyString(String);
impl Refines<String> for NonEmptyString {}
impl Implies<Is<String>> for Is<NonEmptyString> {}
let refined_proof: Established<Is<NonEmptyString>> = Established::assert();
let _base_proof: Established<Is<String>> = downcast(refined_proof);
}
#[kani::proof]
fn verify_conjunction_soundness() {
use crate::contracts::{And, Established, Prop, both, fst, snd};
struct P;
struct Q;
impl Prop for P {}
impl Prop for Q {}
let p: Established<P> = Established::assert();
let q: Established<Q> = Established::assert();
let pq: Established<And<P, Q>> = both(p, q);
let _p_again: Established<P> = fst(pq);
let _q_again: Established<Q> = snd(pq);
}
#[kani::proof]
fn verify_invariant_state_machine() {
use crate::contracts::{Established, InVariant};
enum State {
Draft,
Approved,
}
struct DraftVariant;
struct ApprovedVariant;
fn edit_draft(_state: State, _proof: Established<InVariant<State, DraftVariant>>) {
}
fn approve(
_state: State,
_draft: Established<InVariant<State, DraftVariant>>,
) -> Established<InVariant<State, ApprovedVariant>> {
Established::assert()
}
let draft_proof: Established<InVariant<State, DraftVariant>> = Established::assert();
edit_draft(State::Draft, draft_proof);
let approved_proof = approve(State::Draft, draft_proof);
let _final_state = (State::Approved, approved_proof);
}