use bitflags::bitflags;
bitflags! {
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Default)]
pub struct FlowFlags: u8 {
const CALL = crate::FLOW_CALL;
const RET = crate::FLOW_RET;
const JUMP = crate::FLOW_JUMP;
const INDIRECT = crate::FLOW_INDIRECT;
const STOPS = crate::FLOW_STOPS;
}
}
bitflags! {
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Default)]
pub struct OperandAccess: u8 {
const READ = 1;
const WRITTEN = 2;
}
}
#[cfg(test)]
mod tests {
use assert2::assert;
use proptest::prelude::*;
use rstest::rstest;
use super::*;
#[rstest]
#[case::call(FlowFlags::CALL, crate::FLOW_CALL)]
#[case::ret(FlowFlags::RET, crate::FLOW_RET)]
#[case::jump(FlowFlags::JUMP, crate::FLOW_JUMP)]
#[case::indirect(FlowFlags::INDIRECT, crate::FLOW_INDIRECT)]
#[case::stops(FlowFlags::STOPS, crate::FLOW_STOPS)]
fn flags_pin_the_generated_facade_values(#[case] flag: FlowFlags, #[case] raw: u8) {
assert!(flag.bits() == raw);
}
#[rstest]
#[case::read(OperandAccess::READ, 1)]
#[case::written(OperandAccess::WRITTEN, 2)]
fn operand_access_flags_pin_the_raw_values(#[case] flag: OperandAccess, #[case] raw: u8) {
assert!(flag.bits() == raw);
}
proptest! {
#[test]
fn flow_flags_from_bits_retain_round_trips_every_byte(raw: u8) {
prop_assert_eq!(FlowFlags::from_bits_retain(raw).bits(), raw);
}
#[test]
fn flow_flags_union_and_intersection_are_raw_bitwise_ops(a: u8, b: u8) {
let (fa, fb) = (FlowFlags::from_bits_retain(a), FlowFlags::from_bits_retain(b));
prop_assert_eq!((fa | fb).bits(), a | b);
prop_assert_eq!((fa & fb).bits(), a & b);
}
#[test]
fn operand_access_from_bits_retain_round_trips_every_byte(raw: u8) {
prop_assert_eq!(OperandAccess::from_bits_retain(raw).bits(), raw);
}
#[test]
fn operand_access_union_and_intersection_are_raw_bitwise_ops(a: u8, b: u8) {
let (fa, fb) = (OperandAccess::from_bits_retain(a), OperandAccess::from_bits_retain(b));
prop_assert_eq!((fa | fb).bits(), a | b);
prop_assert_eq!((fa & fb).bits(), a & b);
}
}
}