use super::bins::Matcher;
use super::coverpoint::{CovEvent, Coverage, Coverpoint};
use super::decl::{
ArrayKind, BinDecl, BinKind, Bound, CoverpointDecl, RangeItem, RepeatRange, TransItem,
TransRep, TransSet,
};
use super::intset::IntSet;
use super::options::{Options, TypeOptions};
use super::trans::{Rep, TransElem, alt_to_seq, remove_window};
use super::value::{CovError, Eval, Expr, KernelId, NoKernels, TypeInfo, Val};
fn r(lo: i128, hi: i128) -> RangeItem {
RangeItem::Range(Bound::Expr(Expr::int(lo)), Bound::Expr(Expr::int(hi)))
}
fn s(v: i128) -> RangeItem {
RangeItem::Single(Expr::int(v))
}
fn seq(vs: &[i128]) -> TransSet {
vs.iter().map(|&v| TransItem::new(vec![s(v)])).collect()
}
fn it(values: Vec<RangeItem>) -> TransItem {
TransItem::new(values)
}
fn consec(v: i128, lo: i128, hi: i128) -> TransItem {
it(vec![s(v)]).rep(TransRep::Consecutive(RepeatRange::between(lo, hi)))
}
fn goto(v: i128, lo: i128, hi: i128) -> TransItem {
it(vec![s(v)]).rep(TransRep::Goto(RepeatRange::between(lo, hi)))
}
fn nonconsec(v: i128, lo: i128, hi: i128) -> TransItem {
it(vec![s(v)]).rep(TransRep::NonConsecutive(RepeatRange::between(lo, hi)))
}
fn tb(name: &str, sets: Vec<TransSet>) -> BinDecl {
BinDecl::trans(name, sets)
}
fn decl(ty: TypeInfo, bins: Vec<BinDecl>) -> CoverpointDecl {
let mut d = CoverpointDecl::new("cp", ty, Expr::Kernel(0));
d.bins = bins;
d
}
fn try_build(d: &CoverpointDecl) -> Result<(Coverpoint, Vec<String>), CovError> {
Coverpoint::new(
d,
&Options::default(),
&TypeOptions::default(),
&mut NoKernels,
&[],
)
}
fn build(d: &CoverpointDecl) -> Coverpoint {
try_build(d).expect("coverpoint builds").0
}
fn build_err(d: &CoverpointDecl) -> CovError {
try_build(d).expect_err("coverpoint must be rejected")
}
fn hit(cp: &mut Coverpoint, v: i128) -> Vec<CovEvent> {
cp.sample_value(&Val::Int(v), &mut NoKernels, &[]).unwrap()
}
fn feed(cp: &mut Coverpoint, vs: &[i128]) -> Vec<CovEvent> {
vs.iter().flat_map(|&v| hit(cp, v)).collect()
}
fn trace(cp: &mut Coverpoint, vs: &[i128]) -> Vec<(usize, Vec<String>)> {
let mut out = Vec::new();
for (i, &v) in vs.iter().enumerate() {
let before: Vec<u64> = cp.bins.iter().map(|b| b.hits).collect();
hit(cp, v);
let inc: Vec<String> = cp
.bins
.iter()
.zip(before)
.filter(|(b, h)| b.hits > *h)
.map(|(b, _)| b.name.clone())
.collect();
if !inc.is_empty() {
out.push((i + 1, inc));
}
}
out
}
fn names(cp: &Coverpoint) -> Vec<&str> {
cp.bins.iter().map(|b| b.name.as_str()).collect()
}
fn pat(bits: u128, care: u128) -> RangeItem {
RangeItem::Single(Expr::Const(Val::Pat { bits, care }))
}
#[test]
fn simple_transition_counts_each_complete_sequence() {
let d = decl(TypeInfo::unsigned(4), vec![tb("t", vec![seq(&[1, 2, 3])])]);
let mut cp = build(&d);
feed(&mut cp, &[1, 2, 3]);
assert_eq!(cp.hits("t"), Some(1));
feed(&mut cp, &[1, 2, 1, 2, 3]);
assert_eq!(cp.hits("t"), Some(2));
feed(&mut cp, &[1, 2, 2, 3, 9, 1, 3]);
assert_eq!(cp.hits("t"), Some(2));
}
#[test]
fn a_transition_needs_two_samples_and_the_first_is_only_a_start() {
let d = decl(TypeInfo::unsigned(4), vec![tb("t", vec![seq(&[1, 2])])]);
let mut cp = build(&d);
feed(&mut cp, &[2]);
feed(&mut cp, &[1]);
assert_eq!(cp.hits("t"), Some(0));
feed(&mut cp, &[2]);
assert_eq!(cp.hits("t"), Some(1));
}
#[test]
fn range_lists_expand_to_every_pair() {
let d = decl(
TypeInfo::unsigned(4),
vec![tb(
"t",
vec![vec![it(vec![s(1), s(5)]), it(vec![s(6), s(7)])]],
)],
);
for (a, b, want) in [
(1, 6, 1),
(1, 7, 1),
(5, 6, 1),
(5, 7, 1),
(1, 5, 0),
(6, 1, 0),
(7, 7, 0),
] {
let mut cp = build(&d);
feed(&mut cp, &[a, b]);
assert_eq!(cp.hits("t"), Some(want), "{a}=>{b}");
}
}
#[test]
fn trans_list_is_a_union_of_sets() {
let d = decl(
TypeInfo::unsigned(4),
vec![tb(
"sa",
vec![
seq(&[4, 5, 6]),
vec![it(vec![r(7, 9), s(10)]), it(vec![s(11), s(12)])],
],
)],
);
let mut cp = build(&d);
feed(&mut cp, &[4, 5, 6]);
assert_eq!(cp.hits("sa"), Some(1));
feed(&mut cp, &[9, 12]);
assert_eq!(cp.hits("sa"), Some(2));
feed(&mut cp, &[10, 11]);
assert_eq!(cp.hits("sa"), Some(3));
feed(&mut cp, &[3, 11]);
assert_eq!(cp.hits("sa"), Some(3));
}
#[test]
fn consecutive_repetition_is_the_same_as_writing_the_value_out() {
let d = decl(
TypeInfo::unsigned(4),
vec![tb("t", vec![vec![consec(3, 5, 5)]])],
);
let mut cp = build(&d);
feed(&mut cp, &[3, 3, 3, 3]);
assert_eq!(cp.hits("t"), Some(0));
feed(&mut cp, &[3]);
assert_eq!(cp.hits("t"), Some(1));
feed(&mut cp, &[3, 3]);
assert_eq!(cp.hits("t"), Some(3));
feed(&mut cp, &[4, 3, 3, 3, 3]);
assert_eq!(cp.hits("t"), Some(3));
}
#[test]
fn consecutive_repetition_range_counts_once_per_sample() {
let d = decl(
TypeInfo::unsigned(4),
vec![tb("t", vec![vec![consec(3, 3, 5)]])],
);
let mut cp = build(&d);
let tr = trace(&mut cp, &[3, 3, 3, 3, 3, 3]);
let at: Vec<usize> = tr.iter().map(|(i, _)| *i).collect();
assert_eq!(at, [3, 4, 5, 6]);
assert_eq!(cp.hits("t"), Some(4));
}
#[test]
fn repetition_inside_a_longer_sequence() {
let d = decl(
TypeInfo::unsigned(4),
vec![tb(
"t",
vec![vec![it(vec![s(1)]), consec(2, 2, 2), it(vec![s(3)])]],
)],
);
let mut cp = build(&d);
feed(&mut cp, &[1, 2, 3]);
assert_eq!(cp.hits("t"), Some(0));
feed(&mut cp, &[1, 2, 2, 3]);
assert_eq!(cp.hits("t"), Some(1));
feed(&mut cp, &[1, 2, 2, 2, 3]);
assert_eq!(cp.hits("t"), Some(1));
}
#[test]
fn goto_repetition_example_from_the_lrm() {
let d = decl(
TypeInfo::unsigned(4),
vec![tb(
"t",
vec![vec![it(vec![s(1)]), goto(3, 3, 3), it(vec![s(5)])]],
)],
);
let mut cp = build(&d);
feed(&mut cp, &[1, 3, 3, 3, 5]);
assert_eq!(cp.hits("t"), Some(1));
feed(&mut cp, &[1, 7, 3, 7, 3, 8, 3, 5]);
assert_eq!(cp.hits("t"), Some(2));
feed(&mut cp, &[1, 3, 3, 3, 7, 5]);
assert_eq!(cp.hits("t"), Some(2));
feed(&mut cp, &[1, 3, 3, 5]);
assert_eq!(cp.hits("t"), Some(2));
}
#[test]
fn nonconsecutive_repetition_example_from_the_lrm() {
let d = decl(
TypeInfo::unsigned(4),
vec![tb(
"t",
vec![vec![it(vec![s(1)]), nonconsec(3, 2, 2), it(vec![s(6)])]],
)],
);
let mut cp = build(&d);
feed(&mut cp, &[1, 3, 5, 3, 7, 6]);
assert_eq!(cp.hits("t"), Some(1));
feed(&mut cp, &[1, 3, 3, 6]);
assert_eq!(cp.hits("t"), Some(2));
feed(&mut cp, &[1, 3, 3, 3, 6]);
assert_eq!(cp.hits("t"), Some(2));
feed(&mut cp, &[1, 3, 9, 6]);
assert_eq!(cp.hits("t"), Some(2));
}
#[test]
fn trailing_repetition_counts_on_the_occurrence_not_on_every_later_sample() {
for item in [nonconsec(3, 2, 2), goto(3, 2, 2)] {
let d = decl(TypeInfo::unsigned(4), vec![tb("t", vec![vec![item]])]);
let mut cp = build(&d);
let tr = trace(&mut cp, &[1, 3, 5, 3, 7, 8, 9]);
let at: Vec<usize> = tr.iter().map(|(i, _)| *i).collect();
assert_eq!(at, [4]);
}
}
#[test]
fn overlapping_repetition_bins_of_the_lrm_example() {
let d = decl(
TypeInfo::unsigned(4),
vec![
tb("b2", vec![vec![goto(2, 3, 5)]]),
tb("b3", vec![vec![goto(3, 3, 5)]]),
tb("b5", vec![vec![consec(5, 3, 3)]]),
tb(
"b6",
vec![vec![it(vec![s(1)]), goto(3, 4, 6), it(vec![s(1)])]],
),
tb(
"b7",
vec![vec![it(vec![s(1)]), nonconsec(2, 3, 6), it(vec![s(5)])]],
),
],
);
let mut cp = build(&d);
let stream = [1, 4, 3, 2, 3, 3, 2, 2, 3, 2, 3, 1, 5, 5, 5, 5, 5, 5];
let tr = trace(&mut cp, &stream);
let when = |bin: &str| -> Vec<usize> {
tr.iter()
.filter(|(_, bs)| bs.iter().any(|b| b == bin))
.map(|(i, _)| *i)
.collect()
};
assert_eq!(when("b2"), [8, 10]);
assert_eq!(when("b3"), [6, 9, 11]);
assert_eq!(when("b5"), [15, 16, 17, 18]);
assert_eq!(when("b6"), [12]);
assert_eq!(when("b7"), [13]);
}
#[test]
fn default_sequence_example_from_the_lrm() {
let sa = vec![
seq(&[4, 5, 6]),
vec![it(vec![r(7, 9), s(10)]), it(vec![s(11), s(12)])],
];
let d = decl(
TypeInfo::unsigned(4),
vec![
tb("sa", sa.clone()),
tb("sb", sa).array(ArrayKind::Open),
tb("sc", vec![vec![it(vec![s(12)]), goto(3, 1, 1)]]),
BinDecl::default_seq("allother"),
],
);
let mut cp = build(&d);
let tr = trace(&mut cp, &[4, 5, 7, 11, 8, 12, 2, 2, 3]);
let when = |bin: &str| -> Vec<usize> {
tr.iter()
.filter(|(_, bs)| bs.iter().any(|b| b == bin))
.map(|(i, _)| *i)
.collect()
};
assert_eq!(when("allother"), [3, 5]);
assert_eq!(cp.hits("allother"), Some(2));
assert_eq!(when("sa"), [4, 6]);
assert_eq!(when("sb[7=>11]"), [4]);
assert_eq!(when("sb[8=>12]"), [6]);
assert_eq!(when("sc"), [9]);
assert_eq!(cp.hits("sb[4=>5=>6]"), Some(0));
}
#[test]
fn array_of_transition_bins_names_every_sequence() {
let d = decl(
TypeInfo::unsigned(4),
vec![
tb(
"sb",
vec![
seq(&[4, 5, 6]),
vec![it(vec![r(7, 9), s(10)]), it(vec![s(11), s(12)])],
],
)
.array(ArrayKind::Open),
],
);
let cp = build(&d);
assert_eq!(
names(&cp),
[
"sb[4=>5=>6]",
"sb[7=>11]",
"sb[7=>12]",
"sb[8=>11]",
"sb[8=>12]",
"sb[9=>11]",
"sb[9=>12]",
"sb[10=>11]",
"sb[10=>12]",
]
);
let mut cp = cp;
feed(&mut cp, &[10, 12, 10, 12]);
assert_eq!(cp.hits("sb[10=>12]"), Some(2));
assert_eq!(cp.hits("sb[10=>11]"), Some(0));
assert_eq!(
cp.coverage(),
Coverage {
covered: 1,
total: 9
}
);
}
#[test]
fn array_with_bounded_repetition_expands_the_lengths() {
let d = decl(
TypeInfo::unsigned(4),
vec![tb("t", vec![vec![consec(3, 3, 5)]]).array(ArrayKind::Open)],
);
let mut cp = build(&d);
assert_eq!(
names(&cp),
["t[3=>3=>3]", "t[3=>3=>3=>3]", "t[3=>3=>3=>3=>3]"]
);
feed(&mut cp, &[3, 3, 3, 3]);
assert_eq!(cp.hits("t[3=>3=>3]"), Some(2));
assert_eq!(cp.hits("t[3=>3=>3=>3]"), Some(1));
assert_eq!(cp.hits("t[3=>3=>3=>3=>3]"), Some(0));
}
#[test]
fn duplicate_sequences_of_an_array_make_one_bin() {
let d = decl(
TypeInfo::unsigned(4),
vec![tb("t", vec![seq(&[1, 2]), seq(&[1, 2])]).array(ArrayKind::Open)],
);
assert_eq!(names(&build(&d)), ["t[1=>2]"]);
}
#[test]
fn unbounded_transitions_cannot_be_arrays() {
for item in [goto(3, 2, 2), nonconsec(3, 2, 2)] {
let d = decl(
TypeInfo::unsigned(4),
vec![tb("t", vec![vec![it(vec![s(1)]), item]]).array(ArrayKind::Open)],
);
assert!(
matches!(build_err(&d), CovError::TransUnbounded { .. }),
"{:?}",
build_err(&d)
);
}
}
#[test]
fn transition_bins_take_only_the_empty_bracket_form() {
let d = decl(
TypeInfo::unsigned(4),
vec![tb("t", vec![seq(&[1, 2])]).array(ArrayKind::Fixed(Expr::int(2)))],
);
assert!(matches!(build_err(&d), CovError::Unsupported(_)));
}
#[test]
fn default_sequence_cannot_be_an_array() {
let d = decl(
TypeInfo::unsigned(4),
vec![
tb("t", vec![seq(&[1, 2])]),
BinDecl::default_seq("d").array(ArrayKind::Open),
],
);
assert!(matches!(build_err(&d), CovError::Unsupported(_)));
}
#[test]
fn zero_length_transitions_are_rejected() {
for set in [
vec![it(vec![s(0)])],
vec![it(vec![r(0, 1)])],
vec![consec(0, 1, 1)],
vec![it(vec![r(0, 1)]).rep(TransRep::Consecutive(RepeatRange::exactly(1)))],
] {
let d = decl(TypeInfo::unsigned(4), vec![tb("t", vec![set])]);
assert!(
matches!(build_err(&d), CovError::TransZeroLength { .. }),
"{:?}",
build_err(&d)
);
}
let d = decl(
TypeInfo::unsigned(4),
vec![tb("t", vec![vec![consec(0, 2, 2)]])],
);
assert!(try_build(&d).is_ok());
}
#[test]
fn bad_repeat_ranges_are_rejected() {
let reversed = decl(
TypeInfo::unsigned(4),
vec![tb("t", vec![vec![consec(3, 5, 3)]])],
);
assert!(matches!(build_err(&reversed), CovError::TransRepeat { .. }));
let negative = decl(
TypeInfo::unsigned(4),
vec![tb("t", vec![vec![consec(3, -1, 3)]])],
);
assert!(matches!(build_err(&negative), CovError::TransRepeat { .. }));
let zero_goto = decl(
TypeInfo::unsigned(4),
vec![tb("t", vec![vec![it(vec![s(1)]), goto(3, 0, 2)]])],
);
assert!(matches!(
build_err(&zero_goto),
CovError::TransRepeat { .. }
));
}
#[test]
fn real_coverpoints_have_no_transition_bins() {
let d = decl(TypeInfo::real(), vec![tb("t", vec![seq(&[1, 2])])]);
assert!(matches!(build_err(&d), CovError::RealUnsupported { .. }));
}
#[test]
fn wildcard_transition_matches_every_expansion() {
let d = decl(
TypeInfo::unsigned(2),
vec![
tb(
"T0_3",
vec![vec![it(vec![pat(0b00, 0b10)]), it(vec![pat(0b10, 0b10)])]],
)
.wildcard(),
],
);
for (a, b, want) in [
(0, 2, 1),
(0, 3, 1),
(1, 2, 1),
(1, 3, 1),
(2, 0, 0),
(0, 1, 0),
(2, 3, 0),
] {
let mut cp = build(&d);
feed(&mut cp, &[a, b]);
assert_eq!(cp.hits("T0_3"), Some(want), "{a}=>{b}");
}
}
#[test]
fn wildcard_transition_array_names_the_four_sequences() {
let d = decl(
TypeInfo::unsigned(2),
vec![
tb(
"T0_3_array",
vec![vec![it(vec![pat(0b00, 0b10)]), it(vec![pat(0b10, 0b10)])]],
)
.wildcard()
.array(ArrayKind::Open),
],
);
let cp = build(&d);
assert_eq!(
names(&cp),
[
"T0_3_array[0=>2]",
"T0_3_array[0=>3]",
"T0_3_array[1=>2]",
"T0_3_array[1=>3]"
]
);
}
#[test]
fn ignored_transition_removes_the_sequences_containing_it() {
let d = decl(
TypeInfo::unsigned(4),
vec![
tb("t", vec![seq(&[1, 2, 3, 4]), seq(&[5, 6])]),
tb("ign", vec![seq(&[2, 3])]).kind(BinKind::Ignore),
],
);
let mut cp = build(&d);
feed(&mut cp, &[1, 2, 3, 4]);
assert_eq!(cp.hits("t"), Some(0));
feed(&mut cp, &[5, 6]);
assert_eq!(cp.hits("t"), Some(1));
}
#[test]
fn ignored_transition_removes_only_the_overlapping_part_of_a_set() {
let d = decl(
TypeInfo::unsigned(4),
vec![
tb("t", vec![vec![it(vec![s(1), s(2)]), it(vec![s(3)])]]),
tb("ign", vec![seq(&[1, 3])]).kind(BinKind::Ignore),
],
);
let mut cp = build(&d);
feed(&mut cp, &[1, 3]);
assert_eq!(cp.hits("t"), Some(0));
feed(&mut cp, &[2, 3]);
assert_eq!(cp.hits("t"), Some(1));
}
#[test]
fn bin_whose_sequences_are_all_ignored_is_empty_and_uncounted() {
let d = decl(
TypeInfo::unsigned(4),
vec![
tb("gone", vec![seq(&[2, 3])]),
tb("kept", vec![seq(&[5, 6])]),
tb("ign", vec![seq(&[2, 3])]).kind(BinKind::Ignore),
],
);
let mut cp = build(&d);
assert!(cp.bins[0].empty);
assert_eq!(
cp.coverage(),
Coverage {
covered: 0,
total: 1
}
);
feed(&mut cp, &[5, 6]);
assert_eq!(
cp.coverage(),
Coverage {
covered: 1,
total: 1
}
);
}
#[test]
fn ignored_value_does_not_affect_a_transition_through_it() {
let d = decl(
TypeInfo::unsigned(4),
vec![
tb("t", vec![seq(&[7, 8])]),
BinDecl::ranges("v", vec![s(0)]),
BinDecl::ranges("ignv", vec![s(7)]).kind(BinKind::Ignore),
],
);
let mut cp = build(&d);
feed(&mut cp, &[7, 8]);
assert_eq!(cp.hits("t"), Some(1));
}
#[test]
fn illegal_transition_is_an_error_and_removes_the_sequence() {
let d = decl(
TypeInfo::unsigned(4),
vec![
tb("t", vec![seq(&[4, 5, 6]), seq(&[1, 2])]),
tb("bad", vec![seq(&[4, 5, 6])]).kind(BinKind::Illegal),
],
);
let mut cp = build(&d);
let ev = feed(&mut cp, &[4, 5, 6]);
assert_eq!(
ev,
[CovEvent::IllegalBin {
coverpoint: "cp".to_string(),
bin: "bad".to_string(),
value: "4=>5=>6".to_string()
}]
);
assert_eq!(cp.hits("bad"), Some(1));
assert_eq!(cp.hits("t"), Some(0));
feed(&mut cp, &[1, 2]);
assert_eq!(cp.hits("t"), Some(1));
}
#[test]
fn unbounded_ignored_or_illegal_transitions_are_rejected() {
for kind in [BinKind::Ignore, BinKind::Illegal] {
let d = decl(
TypeInfo::unsigned(4),
vec![
tb("t", vec![seq(&[1, 2])]),
tb("x", vec![vec![it(vec![s(1)]), goto(3, 1, 2)]]).kind(kind),
],
);
assert!(
matches!(build_err(&d), CovError::TransUnbounded { .. }),
"{kind:?}"
);
}
}
#[test]
fn unbounded_covered_bin_with_removals_is_a_named_error() {
let d = decl(
TypeInfo::unsigned(4),
vec![
tb("t", vec![vec![it(vec![s(1)]), goto(3, 1, 2)]]),
tb("ign", vec![seq(&[2, 3])]).kind(BinKind::Ignore),
],
);
assert!(matches!(build_err(&d), CovError::TransUnbounded { .. }));
}
#[test]
fn illegal_default_sequence_reports_unexpected_transitions() {
let d = decl(
TypeInfo::unsigned(4),
vec![
tb("ok", vec![seq(&[1, 2])]),
BinDecl::default_seq("bad").kind(BinKind::Illegal),
],
);
let mut cp = build(&d);
assert!(feed(&mut cp, &[1, 2]).is_empty());
let ev = feed(&mut cp, &[7]);
assert_eq!(ev.len(), 1);
assert_eq!(cp.hits("bad"), Some(1));
}
#[test]
fn ignored_transition_counts_as_taken_for_default_sequence() {
let d = decl(
TypeInfo::unsigned(4),
vec![
tb("t", vec![seq(&[1, 2])]),
tb("ign", vec![seq(&[5, 6])]).kind(BinKind::Ignore),
BinDecl::default_seq("other"),
],
);
let mut cp = build(&d);
feed(&mut cp, &[5, 6]);
assert_eq!(cp.hits("other"), Some(0));
feed(&mut cp, &[9]);
assert_eq!(cp.hits("other"), Some(1));
}
#[test]
fn unknown_sample_breaks_pending_sequences() {
let d = decl(TypeInfo::unsigned(4), vec![tb("t", vec![seq(&[1, 2])])]);
let mut cp = build(&d);
hit(&mut cp, 1);
cp.sample_value(&Val::Unknown, &mut NoKernels, &[]).unwrap();
hit(&mut cp, 2);
assert_eq!(cp.hits("t"), Some(0));
hit(&mut cp, 1);
hit(&mut cp, 2);
assert_eq!(cp.hits("t"), Some(1));
}
#[test]
fn default_sequence_does_not_fire_on_the_first_sample_or_after_unknown() {
let d = decl(
TypeInfo::unsigned(4),
vec![tb("t", vec![seq(&[1, 2])]), BinDecl::default_seq("o")],
);
let mut cp = build(&d);
hit(&mut cp, 9);
assert_eq!(cp.hits("o"), Some(0));
hit(&mut cp, 9);
assert_eq!(cp.hits("o"), Some(1));
cp.sample_value(&Val::Unknown, &mut NoKernels, &[]).unwrap();
hit(&mut cp, 9);
assert_eq!(cp.hits("o"), Some(1));
}
#[test]
fn default_sequence_is_excluded_from_coverage() {
let d = decl(
TypeInfo::unsigned(4),
vec![
tb("t1", vec![seq(&[1, 2])]),
tb("t2", vec![seq(&[3, 4])]),
BinDecl::default_seq("o"),
],
);
let mut cp = build(&d);
feed(&mut cp, &[1, 2, 9, 9]);
assert_eq!(
cp.coverage(),
Coverage {
covered: 1,
total: 2
}
);
}
#[test]
fn transition_only_coverpoint_gets_no_auto_bins() {
let d = decl(TypeInfo::unsigned(4), vec![tb("t", vec![seq(&[1, 2])])]);
assert_eq!(names(&build(&d)), ["t"]);
}
#[test]
fn transition_and_value_bins_coexist() {
let d = decl(
TypeInfo::unsigned(4),
vec![
BinDecl::ranges("v", vec![r(0, 3)]),
tb("t", vec![seq(&[1, 2])]),
],
);
let mut cp = build(&d);
feed(&mut cp, &[1, 2]);
assert_eq!(cp.hits("v"), Some(2));
assert_eq!(cp.hits("t"), Some(1));
}
#[test]
fn bin_iff_gates_the_count_but_not_the_attempt() {
struct Ev {
en: i128,
}
impl Eval for Ev {
fn eval(&mut self, id: KernelId, args: &[Val]) -> Result<Val, CovError> {
match id {
0 => Ok(args[0].clone()),
_ => Ok(Val::Int(self.en)),
}
}
}
let d = decl(
TypeInfo::unsigned(4),
vec![tb("t", vec![seq(&[1, 2])]).iff(Expr::Kernel(1))],
);
let (mut cp, _) = Coverpoint::new(
&d,
&Options::default(),
&TypeOptions::default(),
&mut NoKernels,
&[],
)
.unwrap();
let mut ev = Ev { en: 1 };
cp.sample(&mut ev, &[Val::Int(1)]).unwrap();
ev.en = 0;
cp.sample(&mut ev, &[Val::Int(2)]).unwrap();
assert_eq!(cp.hits("t"), Some(0));
ev.en = 1;
cp.sample(&mut ev, &[Val::Int(1)]).unwrap();
cp.sample(&mut ev, &[Val::Int(2)]).unwrap();
assert_eq!(cp.hits("t"), Some(1));
}
#[test]
fn coverpoint_iff_false_skips_the_sample_entirely() {
struct Ev;
impl Eval for Ev {
fn eval(&mut self, id: KernelId, args: &[Val]) -> Result<Val, CovError> {
Ok(args[id as usize].clone())
}
}
let mut d = decl(TypeInfo::unsigned(4), vec![tb("t", vec![seq(&[1, 2])])]);
d.iff = Some(Expr::Kernel(1));
let (mut cp, _) = Coverpoint::new(
&d,
&Options::default(),
&TypeOptions::default(),
&mut NoKernels,
&[],
)
.unwrap();
cp.sample(&mut Ev, &[Val::Int(1), Val::Int(1)]).unwrap();
cp.sample(&mut Ev, &[Val::Int(9), Val::Int(0)]).unwrap();
cp.sample(&mut Ev, &[Val::Int(2), Val::Int(1)]).unwrap();
assert_eq!(cp.hits("t"), Some(1));
}
#[test]
fn signed_coverpoint_transitions_use_the_value_not_the_bits() {
let d = decl(TypeInfo::signed(4), vec![tb("t", vec![seq(&[-1, 3])])]);
let mut cp = build(&d);
feed(&mut cp, &[-1, 3]);
assert_eq!(cp.hits("t"), Some(1));
}
#[test]
fn reset_clears_pending_sequences() {
let d = decl(TypeInfo::unsigned(4), vec![tb("t", vec![seq(&[1, 2])])]);
let mut cp = build(&d);
hit(&mut cp, 1);
cp.reset();
hit(&mut cp, 2);
assert_eq!(cp.hits("t"), Some(0));
}
#[test]
fn empty_value_set_makes_the_bin_empty() {
let d = decl(
TypeInfo::unsigned(2),
vec![
tb("dead", vec![seq(&[1, 9])]),
tb("live", vec![seq(&[1, 2])]),
],
);
let (cp, warns) = try_build(&d).unwrap();
assert!(cp.bins[0].empty);
assert!(!warns.is_empty());
assert_eq!(cp.coverage().total, 1);
}
#[test]
fn remove_window_splits_a_set_sequence() {
let set = |v: &[i128]| IntSet::from_intervals(v.iter().map(|&x| (x, x)));
let alt = vec![set(&[1, 2]), set(&[3])];
let ign = vec![set(&[1]), set(&[3])];
let out = remove_window(&alt, &ign);
assert_eq!(out, vec![vec![set(&[2]), set(&[3])]]);
let ign = vec![set(&[7]), set(&[8])];
assert_eq!(remove_window(&alt, &ign), vec![alt.clone()]);
let ign = vec![set(&[1]), set(&[3]), set(&[4])];
assert_eq!(remove_window(&alt, &ign), vec![alt.clone()]);
let long = vec![set(&[1]), set(&[2]), set(&[3]), set(&[4])];
assert!(remove_window(&long, &vec![set(&[2]), set(&[3])]).is_empty());
}
#[test]
fn alt_to_seq_makes_once_elements() {
let set = IntSet::from_intervals([(1, 1)]);
let q = alt_to_seq(vec![set.clone(), set.clone()]);
assert_eq!(q.len(), 2);
assert!(q.iter().all(|e: &TransElem| e.rep == Rep::Once));
}
#[test]
fn matcher_kind_is_exposed_to_the_coverpoint() {
let d = decl(
TypeInfo::unsigned(4),
vec![tb("t", vec![seq(&[1, 2])]), BinDecl::default_seq("o")],
);
let cp = build(&d);
assert!(matches!(cp.bins[0].matcher, Matcher::Trans(_)));
assert!(matches!(cp.bins[1].matcher, Matcher::DefaultSeq));
assert!(cp.bins[1].is_default_seq());
assert!(!cp.bins[1].is_default());
}