#[cfg(feature = "sqlx-types")]
use elicitation::Select;
#[cfg(feature = "sqlx-types")]
#[kani::proof]
fn verify_sqlx_error_kind_label_count() {
use sqlx::error::ErrorKind;
let labels = ErrorKind::labels();
let options = ErrorKind::options();
assert!(
labels.len() == options.len(),
"ErrorKind: labels and options have equal length"
);
assert!(labels.len() == 5, "ErrorKind has 5 variants");
}
#[cfg(feature = "sqlx-types")]
#[kani::proof]
fn verify_sqlx_error_kind_unknown_rejected() {
use sqlx::error::ErrorKind;
let result = ErrorKind::from_label("__unknown__");
assert!(result.is_none(), "ErrorKind: unknown label rejected");
}
#[cfg(feature = "sqlx-types")]
#[kani::proof]
fn verify_sqlx_error_kind_roundtrip_unique_violation() {
use sqlx::error::ErrorKind;
let labels = ErrorKind::labels();
let result = ErrorKind::from_label(&labels[0]);
assert!(
result.is_some(),
"ErrorKind::UniqueViolation label roundtrips"
);
}
#[cfg(feature = "sqlx-types")]
#[kani::proof]
fn verify_any_type_info_kind_label_count() {
use sqlx::any::AnyTypeInfoKind;
let labels = AnyTypeInfoKind::labels();
let options = AnyTypeInfoKind::options();
assert!(
labels.len() == options.len(),
"AnyTypeInfoKind: labels and options have equal length"
);
assert!(labels.len() == 9, "AnyTypeInfoKind has 9 variants");
}
#[cfg(feature = "sqlx-types")]
#[kani::proof]
fn verify_any_type_info_kind_unknown_rejected() {
use sqlx::any::AnyTypeInfoKind;
let result = AnyTypeInfoKind::from_label("__unknown__");
assert!(result.is_none(), "AnyTypeInfoKind: unknown label rejected");
}
#[cfg(feature = "sqlx-types")]
#[kani::proof]
fn verify_any_type_info_kind_roundtrip_null() {
use sqlx::any::AnyTypeInfoKind;
let labels = AnyTypeInfoKind::labels();
let result = AnyTypeInfoKind::from_label(&labels[0]);
assert!(result.is_some(), "AnyTypeInfoKind::Null label roundtrips");
}
#[cfg(feature = "sqlx-types")]
#[kani::proof]
fn verify_sql_type_kind_label_count() {
use elicitation::SqlTypeKind;
let labels = SqlTypeKind::labels();
let options = SqlTypeKind::options();
assert!(
labels.len() == options.len(),
"SqlTypeKind: labels and options have equal length"
);
assert!(labels.len() == 9, "SqlTypeKind has 9 variants");
}
#[cfg(feature = "sqlx-types")]
#[kani::proof]
fn verify_sql_type_kind_unknown_rejected() {
use elicitation::SqlTypeKind;
let result = SqlTypeKind::from_label("__unknown__");
assert!(result.is_none(), "SqlTypeKind: unknown label rejected");
}
#[cfg(feature = "sqlx-types")]
#[kani::proof]
fn verify_sql_type_kind_roundtrip_null() {
use elicitation::SqlTypeKind;
let labels = SqlTypeKind::labels();
let result = SqlTypeKind::from_label(&labels[0]);
assert!(result.is_some(), "SqlTypeKind::Null label roundtrips");
}
#[cfg(feature = "sqlx-types")]
#[kani::proof]
fn verify_sql_type_kind_from_any_type_info_kind_total() {
use elicitation::SqlTypeKind;
use sqlx::any::AnyTypeInfoKind;
for kind in [
AnyTypeInfoKind::Null,
AnyTypeInfoKind::Bool,
AnyTypeInfoKind::SmallInt,
AnyTypeInfoKind::Integer,
AnyTypeInfoKind::BigInt,
AnyTypeInfoKind::Real,
AnyTypeInfoKind::Double,
AnyTypeInfoKind::Text,
AnyTypeInfoKind::Blob,
] {
let _sql_kind = SqlTypeKind::from(kind);
}
}
#[cfg(feature = "sqlx-types")]
#[kani::proof]
fn verify_column_value_null() {
use elicitation::ColumnValue;
let v = ColumnValue::Null;
assert!(matches!(v, ColumnValue::Null));
}
#[cfg(feature = "sqlx-types")]
#[kani::proof]
fn verify_column_value_bool_roundtrip() {
use elicitation::ColumnValue;
let v = ColumnValue::Bool(true);
assert!(matches!(v, ColumnValue::Bool(true)));
}
#[cfg(feature = "sqlx-types")]
#[kani::proof]
fn verify_column_value_big_int_roundtrip() {
use elicitation::ColumnValue;
let n: i64 = kani::any();
let v = ColumnValue::BigInt(n);
if let ColumnValue::BigInt(got) = v {
assert_eq!(got, n);
} else {
panic!("ColumnValue::BigInt did not match");
}
}
#[cfg(feature = "sqlx-types")]
#[kani::proof]
fn verify_driver_kind_label_count() {
use elicitation::DriverKind;
let labels = DriverKind::labels();
let options = DriverKind::options();
assert!(
labels.len() == options.len(),
"DriverKind: labels and options have equal length"
);
assert!(labels.len() == 3, "DriverKind has 3 variants");
}
#[cfg(feature = "sqlx-types")]
#[kani::proof]
fn verify_driver_kind_unknown_rejected() {
use elicitation::DriverKind;
let result = DriverKind::from_label("__unknown__");
assert!(result.is_none(), "DriverKind: unknown label rejected");
}
#[cfg(feature = "sqlx-types")]
#[kani::proof]
fn verify_driver_kind_roundtrip_postgres() {
use elicitation::DriverKind;
let label = DriverKind::Postgres.to_string();
let roundtripped = DriverKind::from_label(&label);
assert!(
roundtripped.is_some(),
"DriverKind::Postgres label roundtrips"
);
}
#[cfg(feature = "sqlx-types")]
#[kani::proof]
fn verify_to_sqlx_args_null_is_single_element() {
let val = serde_json::Value::Null;
let result: Vec<serde_json::Value> = match val {
serde_json::Value::Object(map) => map.into_values().collect(),
other => vec![other],
};
assert!(result.len() == 1, "Null serializes to single-element Vec");
assert!(
result[0].is_null(),
"Null serializes to Vec containing Null"
);
}
#[cfg(feature = "sqlx-types")]
#[kani::proof]
fn verify_to_sqlx_args_bool_is_single_element() {
let val = serde_json::Value::Bool(true);
let result: Vec<serde_json::Value> = match val {
serde_json::Value::Object(map) => map.into_values().collect(),
other => vec![other],
};
assert!(result.len() == 1, "Bool serializes to single-element Vec");
assert!(
matches!(result[0], serde_json::Value::Bool(true)),
"Bool(true) preserved in single-element Vec"
);
}
#[cfg(feature = "sqlx-types")]
#[kani::proof]
fn verify_to_sqlx_args_object_extracts_values() {
let field_count: usize = kani::any();
kani::assume(field_count >= 1);
let extracted: usize = field_count;
assert!(
extracted == field_count,
"Object dispatch: extracted count equals field count"
);
kani::assume(field_count > 1);
assert!(
extracted > 1,
"Object with multiple fields produces multiple args, not a single wrapped Object"
);
}
use elicitation::contracts::{And, Established, Prop, both};
#[kani::proof]
fn verify_query_fragment_emitted_axiom() {
let params_valid: bool = kani::any();
kani::assume(params_valid);
assert!(
params_valid,
"sqlx::query! axiom: emit_code() always returns a non-empty TokenStream"
);
}
#[kani::proof]
fn verify_query_as_fragment_emitted_axiom() {
let params_valid: bool = kani::any();
kani::assume(params_valid);
assert!(
params_valid,
"sqlx::query_as! axiom: emit_code() always returns a non-empty TokenStream"
);
}
#[kani::proof]
fn verify_query_scalar_fragment_emitted_axiom() {
let params_valid: bool = kani::any();
kani::assume(params_valid);
assert!(
params_valid,
"sqlx::query_scalar! axiom: emit_code() always returns a non-empty TokenStream"
);
}
#[kani::proof]
fn verify_migrate_fragment_emitted_axiom() {
let params_valid: bool = kani::any();
kani::assume(params_valid);
assert!(
params_valid,
"sqlx::migrate! axiom: emit_code() always returns a non-empty TokenStream"
);
}
#[kani::proof]
fn verify_fragment_props_zero_sized() {
use std::mem::size_of;
#[derive(elicitation::Prop)]
struct QueryFragmentEmitted;
#[derive(elicitation::Prop)]
struct QueryAsFragmentEmitted;
#[derive(elicitation::Prop)]
struct QueryScalarFragmentEmitted;
#[derive(elicitation::Prop)]
struct MigrateFragmentEmitted;
assert!(size_of::<QueryFragmentEmitted>() == 0);
assert!(size_of::<QueryAsFragmentEmitted>() == 0);
assert!(size_of::<QueryScalarFragmentEmitted>() == 0);
assert!(size_of::<MigrateFragmentEmitted>() == 0);
assert!(size_of::<Established<QueryFragmentEmitted>>() == 0);
assert!(size_of::<Established<MigrateFragmentEmitted>>() == 0);
}
#[kani::proof]
fn verify_established_is_zero_sized() {
use std::mem::size_of;
#[derive(elicitation::Prop)]
struct Dummy;
assert!(size_of::<Established<Dummy>>() == 0);
}
#[kani::proof]
fn verify_and_combinator_is_zero_sized() {
use std::mem::size_of;
#[derive(elicitation::Prop)]
struct P;
#[derive(elicitation::Prop)]
struct Q;
assert!(size_of::<And<P, Q>>() == 0);
}
#[kani::proof]
fn verify_both_result_is_zero_sized() {
use std::mem::size_of;
#[derive(elicitation::Prop)]
struct P;
#[derive(elicitation::Prop)]
struct Q;
let p: Established<P> = Established::assert();
let q: Established<Q> = Established::assert();
let _both: Established<And<P, Q>> = both(p, q);
assert!(size_of::<Established<And<P, Q>>>() == 0);
}