Skip to content

Commit

Permalink
test: Add basic test for VaList
Browse files Browse the repository at this point in the history
  • Loading branch information
dlrobertson committed Nov 26, 2018
1 parent 0814087 commit e9e084f
Show file tree
Hide file tree
Showing 3 changed files with 243 additions and 0 deletions.
6 changes: 6 additions & 0 deletions src/test/run-make-fulldeps/c-link-to-rust-va-list-fn/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
-include ../tools.mk

all:
$(RUSTC) checkrust.rs
$(CC) test.c $(call STATICLIB,checkrust) $(call OUT_EXE,test) $(EXTRACFLAGS)
$(call RUN,test)
142 changes: 142 additions & 0 deletions src/test/run-make-fulldeps/c-link-to-rust-va-list-fn/checkrust.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![crate_type = "staticlib"]
#![feature(c_variadic)]
#![feature(libc)]

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;

#[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;
}
}
}
return 0;
}

#[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)
}

#[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;
}
}
}

ap.copy(|ap| {
compare_answers(&slice[skip_n..], ap)
})
}
95 changes: 95 additions & 0 deletions src/test/run-make-fulldeps/c-link-to-rust-va-list-fn/test.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#include <stdarg.h>
#include <assert.h>
#include <stdint.h>
#include <stdlib.h>

typedef enum {
TAG_DOUBLE,
TAG_LONG,
TAG_LONGLONG,
TAG_INT,
TAG_BYTE,
TAG_CSTR,
TAG_SKIP,
} tag;

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, ...) {
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_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);

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);

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);

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);
return 0;
}

0 comments on commit e9e084f

Please sign in to comment.