Skip to content

ctest: add tests for aliases, structs, unions, as well as a test crate. #4543

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ extra_traits = []
members = [
"ctest",
"ctest-next",
"ctest-next-test",
"ctest-test",
"libc-test",
]
Expand Down
24 changes: 24 additions & 0 deletions ctest-next-test/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
[package]
name = "ctest-next-test"
version = "0.1.0"
authors = ["Alex Crichton <[email protected]>"]
publish = false
edition = "2021"

[build-dependencies]
ctest-next = { path = "../ctest-next" }
cc = "1.0"

[dev-dependencies]
ctest-next = { path = "../ctest-next" }

[dependencies]
libc = { path = ".." }

[[bin]]
name = "t1"
test = false

[[bin]]
name = "t2"
test = false
62 changes: 62 additions & 0 deletions ctest-next-test/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
use std::env;

use ctest_next::{generate_test, TestGenerator};

fn main() {
let opt_level = env::var("OPT_LEVEL")
.ok()
.and_then(|s| s.parse().ok())
.unwrap_or(0);

let profile = env::var("PROFILE").unwrap_or_default();
if profile == "release" || opt_level >= 2 {
println!("cargo:rustc-cfg=optimized");
}

// FIXME(ctest): The .c files are ignored right now, I'm not sure if they
// were used or how they were used before.
cc::Build::new()
.include("src")
.warnings(false)
.file("src/t1.c")
.compile("libt1.a");
println!("cargo:rerun-if-changed=src/t1.c");
println!("cargo:rerun-if-changed=src/t1.h");

cc::Build::new()
.warnings(false)
.file("src/t2.c")
.compile("libt2.a");
println!("cargo:rerun-if-changed=src/t2.c");
println!("cargo:rerun-if-changed=src/t2.h");

let mut t1gen = TestGenerator::new();
t1gen
.header("t1.h")
.include("src")
.skip_private(true)
.rename_fn(|f| f.link_name().unwrap_or(f.ident()).to_string().into())
.rename_union_ty(|ty| (ty == "T1Union").then_some(ty.to_string()))
.rename_struct_ty(|ty| (ty == "Transparent").then_some(ty.to_string()))
.volatile_field(|s, f| s.ident() == "V" && f.ident() == "v")
.volatile_static(|s| s.ident() == "vol_ptr")
.volatile_static(|s| s.ident() == "T1_fn_ptr_vol")
.volatile_fn_arg(|f, p| f.ident() == "T1_vol0" && p.ident() == "arg0")
.volatile_fn_arg(|f, p| f.ident() == "T1_vol2" && p.ident() == "arg1")
.volatile_fn_return_type(|f| f.ident() == "T1_vol1")
.volatile_fn_return_type(|f| f.ident() == "T1_vol2")
// The parameter `a` of the functions `T1r`, `T1s`, `T1t`, `T1v` is an array.
.array_arg(|f, p| matches!(f.ident(), "T1r" | "T1s" | "T1t" | "T1v") && p.ident() == "a")
.skip_roundtrip(|n| n == "Arr");
generate_test(&mut t1gen, "src/t1.rs", "t1gen.rs").unwrap();

let mut t2gen = TestGenerator::new();
t2gen
.header("t2.h")
.include("src")
// public C typedefs have to manually be specified because they are identical to normal
// structs on the Rust side.
.rename_union_ty(|ty| (ty == "T2Union").then_some(ty.to_string()))
.skip_roundtrip(|_| true);
generate_test(&mut t2gen, "src/t2.rs", "t2gen.rs").unwrap();
}
6 changes: 6 additions & 0 deletions ctest-next-test/src/bin/t1.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#![cfg(not(test))]
#![deny(warnings)]

use ctest_next_test::t1::*;

include!(concat!(env!("OUT_DIR"), "/t1gen.rs"));
6 changes: 6 additions & 0 deletions ctest-next-test/src/bin/t2.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#![cfg(not(test))]
#![deny(warnings)]

use ctest_next_test::t2::*;

include!(concat!(env!("OUT_DIR"), "/t2gen.rs"));
6 changes: 6 additions & 0 deletions ctest-next-test/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
//! `ctest-next-test` is a test crate for testing `ctest-next`. It consists
//! of two test binaries, t1 and t2 that test various aspects of `ctest-next`,
//! such as validation and generation of tests.

pub mod t1;
pub mod t2;
70 changes: 70 additions & 0 deletions ctest-next-test/src/t1.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
#include "t1.h"
#include <stdint.h>
#include <stdlib.h>

void T1a(void) {}
void *T1b(void) { return NULL; }
void *T1c(void *a) { return NULL; }
int32_t T1d(unsigned a) { return 0; }
void T1e(unsigned a, const struct T1Bar *b) {}
void T1f(void) {}
void T1g(int32_t *a) {}
void T1h(const int32_t *b) {}
void T1i(int32_t a[4]) {}
void T1j(const int32_t b[4]) {}
void T1o(int32_t (*a)[4]) {}
void T1p(int32_t (*const a)[4]) {}

void T1r(Arr a) {}
void T1s(const Arr a) {}
void T1t(Arr *a) {}
void T1v(const Arr *a) {}

unsigned T1static = 3;

const uint8_t T1_static_u8 = 42;
uint8_t T1_static_mut_u8 = 37;

uint8_t foo(uint8_t a, uint8_t b) { return a + b; }
void bar(uint8_t a) { return; }
void baz(void) { return; }

uint32_t (*nested(uint8_t arg))(uint16_t)
{
return NULL;
}

uint32_t (*nested2(uint8_t (*arg0)(uint8_t), uint16_t (*arg1)(uint16_t)))(uint16_t)
{
return NULL;
}

uint8_t (*T1_static_mut_fn_ptr)(uint8_t, uint8_t) = foo;
uint8_t (*const T1_static_const_fn_ptr_unsafe)(uint8_t, uint8_t) = foo;
void (*const T1_static_const_fn_ptr_unsafe2)(uint8_t) = bar;
void (*const T1_static_const_fn_ptr_unsafe3)(void) = baz;

const uint8_t T1_static_right = 7;
uint8_t (*T1_static_right2)(uint8_t, uint8_t) = foo;

uint32_t (*(*T1_fn_ptr_s)(uint8_t))(uint16_t) = nested;
uint32_t (*(*T1_fn_ptr_s2)(uint8_t (*arg0)(uint8_t), uint16_t (*arg1)(uint16_t)))(uint16_t) = nested2;

const int32_t T1_arr0[2] = {0, 0};
const int32_t T1_arr1[2][3] = {{0, 0, 0}, {0, 0, 0}};
const int32_t T1_arr2[1][2][3] = {{{0, 0, 0}, {0, 0, 0}}};

int32_t T1_arr3[2] = {0, 0};
int32_t T1_arr4[2][3] = {{0, 0, 0}, {0, 0, 0}};
int32_t T1_arr5[1][2][3] = {{{0, 0, 0}, {0, 0, 0}}};

int32_t T1_arr42[1][2][3] = {{{0, 0, 0}, {0, 0, 0}}};
const int16_t *T1_sref = (void *)(1337);

volatile uint8_t *vol_ptr = NULL;
void *T1_vol0(volatile void *x, void *a) { return a ? a : (void *)x; }
volatile void *T1_vol1(void *x, void *b) { return b ? (volatile void *)x : (volatile void *)x; }
volatile void *T1_vol2(void *c, volatile void *x) { return c ? x : x; }

// FIXME(#4365): duplicate symbol errors when enabled
// uint8_t (*volatile T1_fn_ptr_vol)(uint8_t, uint8_t) = foo;
187 changes: 187 additions & 0 deletions ctest-next-test/src/t1.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
#include <stdint.h>

typedef int32_t T1Foo;

#define T1N 5
#define T1S "foo"

struct T1Bar
{
int32_t a;
uint32_t b;
T1Foo c;
uint8_t d;
int64_t e[T1N];
int64_t f[T1N][2];
};

struct T1Baz
{
uint64_t a;
struct T1Bar b;
};

typedef union
{
uint64_t a;
uint32_t b;
} T1Union;

union T1NoTypedefUnion
{
uint64_t a;
uint32_t b;
};

struct T1StructWithUnion
{
union T1NoTypedefUnion u;
};

typedef double T1TypedefDouble;
typedef int *T1TypedefPtr;
typedef struct T1Bar T1TypedefStruct;

void T1a(void);
void *T1b(void);
void *T1c(void *);
int32_t T1d(unsigned);
void T1e(unsigned, const struct T1Bar *);
void T1f(void);
void T1g(int32_t *a);
void T1h(const int32_t *b);
void T1i(int32_t a[4]);
void T1j(const int32_t b[4]);
void T1o(int32_t (*a)[4]);
void T1p(int32_t (*const a)[4]);

typedef int32_t(Arr)[4];
typedef int32_t Transparent;

void T1r(Arr a);
void T1s(const Arr a);
void T1t(Arr *a);
void T1v(const Arr *a);

#define T1C 4

extern uint32_t T1static;
extern const uint8_t T1_static_u8;
/* FIXME(#4365): duplicate symbol errors when enabled
// uint8_t T1_static_mut_u8;
// uint8_t (*T1_static_mut_fn_ptr)(uint8_t, uint8_t);
extern uint8_t (*const T1_static_const_fn_ptr_unsafe)(uint8_t, uint8_t);
*/
extern void (*const T1_static_const_fn_ptr_unsafe2)(uint8_t);
extern void (*const T1_static_const_fn_ptr_unsafe3)(void);

extern const uint8_t T1_static_right;
/* FIXME(#4365): duplicate symbol errors when enabled
// uint8_t (*T1_static_right2)(uint8_t, uint8_t);

// T1_fn_ptr_nested: function pointer to a function, taking a uint8_t, and
// returning a function pointer to a function taking a uint16_t and returning a
// uint32_t
uint32_t (*(*T1_fn_ptr_s)(uint8_t))(uint16_t);

// T1_fn_ptr_nested: function pointer to a function, taking a function pointer
// uint8_t -> uint8_t, and returning a function pointer to a function taking a
// uint16_t and returning a uint32_t
uint32_t (*(*T1_fn_ptr_s2)(uint8_t(*)(uint8_t), uint16_t(*)(uint16_t)))(uint16_t);
*/

extern const int32_t T1_arr0[2];
extern const int32_t T1_arr1[2][3];
extern const int32_t T1_arr2[1][2][3];

extern int32_t T1_arr3[2];
extern int32_t T1_arr4[2][3];
extern int32_t T1_arr5[1][2][3];

extern int32_t T1_arr42[1][2][3];

extern const int16_t *T1_sref;

struct Q
{
uint8_t *q0;
uint8_t **q1;
uint8_t q2;
};

struct T1_conflict_foo
{
int a;
};

struct T1_conflict
{
int foo;
};

// test packed structs
//
// on msvc there is only pragma pack
// on clang and gcc there is a packed attribute

#pragma pack(push, 1)

struct Pack
{
uint8_t a;
uint16_t b;
};

#pragma pack(pop)

#pragma pack(push, 4)

struct Pack4
{
uint8_t a;
uint32_t b;
};

#pragma pack(pop)

// volatile pointers in struct fields:
struct V
{
volatile uint8_t *v;
};

// volatile pointers in externs:
extern volatile uint8_t *vol_ptr;

// volatile pointers in function arguments:
void *T1_vol0(volatile void *, void *);
volatile void *T1_vol1(void *, void *);
volatile void *T1_vol2(void *, volatile void *);

/* FIXME(#4365): duplicate symbol errors when enabled
// volatile function pointers:
uint8_t (*volatile T1_fn_ptr_vol)(uint8_t, uint8_t);
*/

#define LOG_MAX_LINE_LENGTH (1400)

typedef struct
{
long tv_sec;
int tv_usec;
} timeval;

typedef struct
{
long level;
char const *file;
long line;
char const *module;
timeval tv;
char message[LOG_MAX_LINE_LENGTH];
} log_record_t;

typedef struct
{
long double inner;
} LongDoubleWrap;
Loading
Loading