Skip to content

Commit

Permalink
Implement Arbitrary for Range* (#3666)
Browse files Browse the repository at this point in the history
Resolves #3662

cc @zhassan-aws
  • Loading branch information
c410-f3r authored Nov 2, 2024
1 parent 66764b2 commit 149e408
Show file tree
Hide file tree
Showing 2 changed files with 182 additions and 0 deletions.
68 changes: 68 additions & 0 deletions library/kani_core/src/arbitrary.rs
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,74 @@ macro_rules! generate_arbitrary {
pub mod slice {
kani_core::slice_generator!();
}

mod range_structures {
use super::{
Arbitrary,
core_path::{
mem,
ops::{Bound, Range, RangeFrom, RangeInclusive, RangeTo, RangeToInclusive},
},
};

impl<T> Arbitrary for Bound<T>
where
T: Arbitrary,
{
fn any() -> Self {
match u8::any() {
0 => Bound::Included(T::any()),
1 => Bound::Excluded(T::any()),
_ => Bound::Unbounded,
}
}
}

impl<T> Arbitrary for Range<T>
where
T: Arbitrary,
{
fn any() -> Self {
T::any()..T::any()
}
}

impl<T> Arbitrary for RangeFrom<T>
where
T: Arbitrary,
{
fn any() -> Self {
T::any()..
}
}

impl<T> Arbitrary for RangeInclusive<T>
where
T: Arbitrary,
{
fn any() -> Self {
T::any()..=T::any()
}
}

impl<T> Arbitrary for RangeTo<T>
where
T: Arbitrary,
{
fn any() -> Self {
..T::any()
}
}

impl<T> Arbitrary for RangeToInclusive<T>
where
T: Arbitrary,
{
fn any() -> Self {
..=T::any()
}
}
}
};
}

Expand Down
114 changes: 114 additions & 0 deletions tests/kani/Arbitrary/ops.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
// Copyright Kani Contributors
// SPDX-License-Identifier: Apache-2.0 OR MIT
//
// Check that users can generate range structures

extern crate kani;

use std::ops::{Bound, Range, RangeFrom, RangeInclusive, RangeTo, RangeToInclusive};

#[kani::proof]
fn bound() {
let elem: Wrapper<Bound<u8>> = kani::any();
match elem.0 {
Bound::Included(elem) => {
assert!(elem < 100);
}
Bound::Excluded(elem) => {
assert!(elem < 100);
}
Bound::Unbounded => {}
}
}

#[kani::proof]
fn range() {
let elem: Wrapper<Range<u8>> = kani::any();
assert!(elem.0.start < 100);
assert!(elem.0.end < 100);
}

#[kani::proof]
fn range_from() {
let elem: Wrapper<RangeFrom<u8>> = kani::any();
assert!(elem.0.start < 100);
}

#[kani::proof]
fn range_inclusive() {
let elem: Wrapper<RangeInclusive<u8>> = kani::any();
assert!(*elem.0.start() < 100);
assert!(*elem.0.end() < 100);
}

#[kani::proof]
fn range_to() {
let elem: Wrapper<RangeTo<u8>> = kani::any();
assert!(elem.0.end < 100);
}

#[kani::proof]
fn range_to_inclusive() {
let elem: Wrapper<RangeToInclusive<u8>> = kani::any();
assert!(elem.0.end < 100);
}

struct Wrapper<T>(T);

impl kani::Arbitrary for Wrapper<Bound<u8>> {
fn any() -> Self {
let val = kani::any();
match val {
Bound::Included(elem) => {
kani::assume(elem < 100);
}
Bound::Excluded(elem) => {
kani::assume(elem < 100);
}
Bound::Unbounded => {}
}
Self(val)
}
}

impl kani::Arbitrary for Wrapper<Range<u8>> {
fn any() -> Self {
let val = kani::any()..kani::any();
kani::assume(val.start < 100);
kani::assume(val.end < 100);
Self(val)
}
}

impl kani::Arbitrary for Wrapper<RangeFrom<u8>> {
fn any() -> Self {
let val = kani::any()..;
kani::assume(val.start < 100);
Self(val)
}
}

impl kani::Arbitrary for Wrapper<RangeInclusive<u8>> {
fn any() -> Self {
let val = kani::any()..=kani::any();
kani::assume(*val.start() < 100);
kani::assume(*val.end() < 100);
Self(val)
}
}

impl kani::Arbitrary for Wrapper<RangeTo<u8>> {
fn any() -> Self {
let val = ..kani::any();
kani::assume(val.end < 100);
Self(val)
}
}

impl kani::Arbitrary for Wrapper<RangeToInclusive<u8>> {
fn any() -> Self {
let val = ..=kani::any();
kani::assume(val.end < 100);
Self(val)
}
}

0 comments on commit 149e408

Please sign in to comment.