tests: Simplify VaList run-make test
The va_list tests were too complex and were causing some spurious test failures on Windows
This commit is contained in:
parent
d48ab693d1
commit
28ca35fd13
2 changed files with 62 additions and 179 deletions
|
@ -16,127 +16,65 @@ extern crate libc;
|
|||
|
||||
use libc::{c_char, c_double, c_int, c_long, c_longlong};
|
||||
use std::ffi::VaList;
|
||||
use std::slice;
|
||||
use std::ffi::CStr;
|
||||
use std::ffi::{CString, CStr};
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub enum AnswerType {
|
||||
Double,
|
||||
Long,
|
||||
LongLong,
|
||||
Int,
|
||||
Byte,
|
||||
CStr,
|
||||
Skip,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub union AnswerData {
|
||||
pub double: c_double,
|
||||
pub long: c_long,
|
||||
pub longlong: c_longlong,
|
||||
pub int: c_int,
|
||||
pub byte: c_char,
|
||||
pub cstr: *const c_char,
|
||||
pub skip_ty: AnswerType,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct Answer {
|
||||
tag: AnswerType,
|
||||
data: AnswerData,
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe fn compare_answers(answers: &[Answer], mut ap: VaList) -> usize {
|
||||
for (i, answer) in answers.iter().enumerate() {
|
||||
match answer {
|
||||
Answer { tag: AnswerType::Double, data: AnswerData { double: d } } => {
|
||||
let tmp = ap.arg::<c_double>();
|
||||
if d.floor() != tmp.floor() {
|
||||
println!("Double: {} != {}", d, tmp);
|
||||
return i + 1;
|
||||
}
|
||||
}
|
||||
Answer { tag: AnswerType::Long, data: AnswerData { long: l } } => {
|
||||
let tmp = ap.arg::<c_long>();
|
||||
if *l != tmp {
|
||||
println!("Long: {} != {}", l, tmp);
|
||||
return i + 1;
|
||||
}
|
||||
}
|
||||
Answer { tag: AnswerType::LongLong, data: AnswerData { longlong: l } } => {
|
||||
let tmp = ap.arg::<c_longlong>();
|
||||
if *l != tmp {
|
||||
println!("Long Long: {} != {}", l, tmp);
|
||||
return i + 1;
|
||||
}
|
||||
}
|
||||
Answer { tag: AnswerType::Int, data: AnswerData { int: n } } => {
|
||||
let tmp = ap.arg::<c_int>();
|
||||
if *n != tmp {
|
||||
println!("Int: {} != {}", n, tmp);
|
||||
return i + 1;
|
||||
}
|
||||
}
|
||||
Answer { tag: AnswerType::Byte, data: AnswerData { byte: b } } => {
|
||||
let tmp = ap.arg::<c_char>();
|
||||
if *b != tmp {
|
||||
println!("Byte: {} != {}", b, tmp);
|
||||
return i + 1;
|
||||
}
|
||||
}
|
||||
Answer { tag: AnswerType::CStr, data: AnswerData { cstr: c0 } } => {
|
||||
let c1 = ap.arg::<*const c_char>();
|
||||
let cstr0 = CStr::from_ptr(*c0);
|
||||
let cstr1 = CStr::from_ptr(c1);
|
||||
if cstr0 != cstr1 {
|
||||
println!("C String: {:?} != {:?}", cstr0, cstr1);
|
||||
return i + 1;
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
println!("Unknown type!");
|
||||
return i + 1;
|
||||
}
|
||||
macro_rules! continue_if {
|
||||
($cond:expr) => {
|
||||
if !($cond) {
|
||||
return 0xff;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsafe fn compare_c_str(ptr: *const c_char, val: &str) -> bool {
|
||||
let cstr0 = CStr::from_ptr(ptr);
|
||||
let cstr1 = CString::new(val).unwrap();
|
||||
&*cstr1 == cstr0
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn check_rust(argc: usize, answers: *const Answer, ap: VaList) -> usize {
|
||||
let slice = slice::from_raw_parts(answers, argc);
|
||||
compare_answers(slice, ap)
|
||||
pub unsafe extern "C" fn check_list_0(mut ap: VaList) -> usize {
|
||||
continue_if!(ap.arg::<c_longlong>() == 1);
|
||||
continue_if!(ap.arg::<c_int>() == 2);
|
||||
continue_if!(ap.arg::<c_longlong>() == 3);
|
||||
0
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn check_rust_copy(argc: usize, answers: *const Answer,
|
||||
mut ap: VaList) -> usize {
|
||||
let slice = slice::from_raw_parts(answers, argc);
|
||||
let mut skip_n = 0;
|
||||
for (i, answer) in slice.iter().enumerate() {
|
||||
match answer {
|
||||
Answer { tag: AnswerType::Skip, data: AnswerData { skip_ty } } => {
|
||||
match skip_ty {
|
||||
AnswerType::Double => { ap.arg::<c_double>(); }
|
||||
AnswerType::Long => { ap.arg::<c_long>(); }
|
||||
AnswerType::LongLong => { ap.arg::<c_longlong>(); }
|
||||
AnswerType::Int => { ap.arg::<c_int>(); }
|
||||
AnswerType::Byte => { ap.arg::<c_char>(); }
|
||||
AnswerType::CStr => { ap.arg::<*const c_char>(); }
|
||||
_ => { return i; }
|
||||
};
|
||||
}
|
||||
_ => {
|
||||
skip_n = i;
|
||||
break;
|
||||
}
|
||||
pub unsafe extern "C" fn check_list_1(mut ap: VaList) -> usize {
|
||||
continue_if!(ap.arg::<c_int>() == -1);
|
||||
continue_if!(ap.arg::<c_char>() == 'A' as c_char);
|
||||
continue_if!(ap.arg::<c_char>() == '4' as c_char);
|
||||
continue_if!(ap.arg::<c_char>() == ';' as c_char);
|
||||
continue_if!(ap.arg::<c_int>() == 0x32);
|
||||
continue_if!(ap.arg::<c_int>() == 0x10000001);
|
||||
continue_if!(compare_c_str(ap.arg::<*const c_char>(), "Valid!"));
|
||||
0
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn check_list_2(mut ap: VaList) -> usize {
|
||||
continue_if!(ap.arg::<c_double>().floor() == 3.14f64.floor());
|
||||
continue_if!(ap.arg::<c_long>() == 12);
|
||||
continue_if!(ap.arg::<c_char>() == 'a' as c_char);
|
||||
continue_if!(ap.arg::<c_double>().floor() == 6.18f64.floor());
|
||||
continue_if!(compare_c_str(ap.arg::<*const c_char>(), "Hello"));
|
||||
continue_if!(ap.arg::<c_int>() == 42);
|
||||
continue_if!(compare_c_str(ap.arg::<*const c_char>(), "World"));
|
||||
0
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn check_list_copy_0(mut ap: VaList) -> usize {
|
||||
continue_if!(ap.arg::<c_double>().floor() == 6.28f64.floor());
|
||||
continue_if!(ap.arg::<c_int>() == 16);
|
||||
continue_if!(ap.arg::<c_char>() == 'A' as c_char);
|
||||
continue_if!(compare_c_str(ap.arg::<*const c_char>(), "Skip Me!"));
|
||||
ap.copy(|mut ap| {
|
||||
if compare_c_str(ap.arg::<*const c_char>(), "Correct") {
|
||||
0
|
||||
} else {
|
||||
0xff
|
||||
}
|
||||
}
|
||||
|
||||
ap.copy(|ap| {
|
||||
compare_answers(&slice[skip_n..], ap)
|
||||
})
|
||||
}
|
||||
|
|
|
@ -12,84 +12,29 @@
|
|||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
typedef enum {
|
||||
TAG_DOUBLE,
|
||||
TAG_LONG,
|
||||
TAG_LONGLONG,
|
||||
TAG_INT,
|
||||
TAG_BYTE,
|
||||
TAG_CSTR,
|
||||
TAG_SKIP,
|
||||
} tag;
|
||||
extern size_t check_list_0(va_list ap);
|
||||
extern size_t check_list_1(va_list ap);
|
||||
extern size_t check_list_2(va_list ap);
|
||||
extern size_t check_list_copy_0(va_list ap);
|
||||
|
||||
typedef struct {
|
||||
tag answer_type;
|
||||
union {
|
||||
double double_precision;
|
||||
long num_long;
|
||||
long long num_longlong;
|
||||
int num_int;
|
||||
int8_t byte;
|
||||
char* cstr;
|
||||
tag skip_ty;
|
||||
} answer_data;
|
||||
} answer;
|
||||
|
||||
#define MK_DOUBLE(n) \
|
||||
{ TAG_DOUBLE, { .double_precision = n } }
|
||||
#define MK_LONG(n) \
|
||||
{ TAG_LONG, { .num_long = n } }
|
||||
#define MK_LONGLONG(n) \
|
||||
{ TAG_LONGLONG, { .num_longlong = n } }
|
||||
#define MK_INT(n) \
|
||||
{ TAG_INT, { .num_int = n } }
|
||||
#define MK_BYTE(b) \
|
||||
{ TAG_BYTE, { .byte = b } }
|
||||
#define MK_CSTR(s) \
|
||||
{ TAG_CSTR, { .cstr = s } }
|
||||
#define MK_SKIP(ty) \
|
||||
{ TAG_SKIP, { .skip_ty = TAG_ ## ty } }
|
||||
|
||||
extern size_t check_rust(size_t argc, const answer* answers, va_list ap);
|
||||
extern size_t check_rust_copy(size_t argc, const answer* answers, va_list ap);
|
||||
|
||||
size_t test_check_rust(size_t argc, const answer* answers, ...) {
|
||||
int test_rust(size_t (*fn)(va_list), ...) {
|
||||
size_t ret = 0;
|
||||
va_list ap;
|
||||
va_start(ap, answers);
|
||||
ret = check_rust(argc, answers, ap);
|
||||
va_end(ap);
|
||||
return ret;
|
||||
}
|
||||
|
||||
size_t test_check_rust_copy(size_t argc, const answer* answers, ...) {
|
||||
size_t ret = 0;
|
||||
va_list ap;
|
||||
va_start(ap, answers);
|
||||
ret = check_rust_copy(argc, answers, ap);
|
||||
va_start(ap, fn);
|
||||
ret = fn(ap);
|
||||
va_end(ap);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
answer test_alignment0[] = {MK_LONGLONG(0x01LL), MK_INT(0x02), MK_LONGLONG(0x03LL)};
|
||||
assert(test_check_rust(3, test_alignment0, 0x01LL, 0x02, 0x03LL) == 0);
|
||||
assert(test_rust(check_list_0, 0x01LL, 0x02, 0x03LL) == 0);
|
||||
|
||||
answer test_alignment1[] = {MK_INT(-1), MK_BYTE('A'), MK_BYTE('4'), MK_BYTE(';'),
|
||||
MK_INT(0x32), MK_INT(0x10000001), MK_CSTR("Valid!")};
|
||||
assert(test_check_rust(7, test_alignment1, -1, 'A', '4', ';', 0x32, 0x10000001,
|
||||
"Valid!") == 0);
|
||||
assert(test_rust(check_list_1, -1, 'A', '4', ';', 0x32, 0x10000001, "Valid!") == 0);
|
||||
|
||||
answer basic_answers[] = {MK_DOUBLE(3.14), MK_LONG(12l), MK_BYTE('a'),
|
||||
MK_DOUBLE(6.28), MK_CSTR("Hello"), MK_INT(42),
|
||||
MK_CSTR("World")};
|
||||
assert(test_check_rust(7, basic_answers, 3.14, 12l, 'a', 6.28, "Hello",
|
||||
42, "World") == 0);
|
||||
assert(test_rust(check_list_2, 3.14, 12l, 'a', 6.28, "Hello", 42, "World") == 0);
|
||||
|
||||
answer copy_answers[] = { MK_SKIP(DOUBLE), MK_SKIP(INT), MK_SKIP(BYTE), MK_SKIP(CSTR),
|
||||
MK_CSTR("Correctly skipped and copied list") };
|
||||
assert(test_check_rust_copy(5, copy_answers, 6.28, 16, 'A', "Skip Me!",
|
||||
"Correctly skipped and copied list") == 0);
|
||||
assert(test_rust(check_list_copy_0, 6.28, 16, 'A', "Skip Me!", "Correct") == 0);
|
||||
return 0;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue