Skip to content

Commit

Permalink
feat: add tests for the ast
Browse files Browse the repository at this point in the history
  • Loading branch information
Wybxc committed Oct 18, 2024
1 parent 635aec6 commit 4fbf926
Show file tree
Hide file tree
Showing 25 changed files with 293 additions and 1 deletion.
6 changes: 6 additions & 0 deletions bootstrap/src/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@ impl Run for TestCommand {
cprintln!("<r,s>Test failed</r,s>: {}", info);
}));

cprintln!("<b>[TEST]</b> running cargo test");
let mut command = std::process::Command::new("cargo");
command.args(["test", "--manifest-path", "crates/Cargo.toml"]);
log::debug!("running {:?}", command);
assert!(command.status().unwrap().success(), "failed to run {:?}", command);

let testcases = self.collect_testcases(manifest);
cprintln!("<b>[TEST]</b> found {} testcases", testcases.len());

Expand Down
1 change: 1 addition & 0 deletions crates/rustc_codegen_c_ast/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use crate::pretty::Print;
extern crate rustc_arena;
extern crate rustc_ast_pretty;
extern crate rustc_data_structures;
extern crate rustc_driver;
extern crate rustc_type_ir;

pub mod arena;
Expand Down
3 changes: 2 additions & 1 deletion crates/rustc_codegen_c_ast/src/pretty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ impl PrinterCtx {
}
}

pub(crate) trait Print {
/// Trait for a type that can be pretty printed.
pub trait Print {
fn print_to(&self, ctx: &mut PrinterCtx);
}
1 change: 1 addition & 0 deletions crates/rustc_codegen_c_ast/tests/blessed/test_decl_var.out
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
int32_t _42 = 42;
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
(1 + 2)
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
foo(1, 2)
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
(int32_t) 42
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
foo(1, (int32_t) (1 + 2)).bar
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
_42.foo
1 change: 1 addition & 0 deletions crates/rustc_codegen_c_ast/tests/blessed/test_expr_raw.out
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
42
6 changes: 6 additions & 0 deletions crates/rustc_codegen_c_ast/tests/blessed/test_function.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
int32_t foo(int32_t _0)
{
int32_t _1;
(_1 = 1);
return _1;
}
13 changes: 13 additions & 0 deletions crates/rustc_codegen_c_ast/tests/blessed/test_module.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#include <stdio.h>

// blessed test

int32_t _42;
int32_t foo(int32_t _0);

int32_t foo(int32_t _0)
{
int32_t _1;
(_1 = 1);
return _1;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{ foo(1, 2); }
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
int32_t _42 = 42;
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
foo(1, 2);
1 change: 1 addition & 0 deletions crates/rustc_codegen_c_ast/tests/blessed/test_stmt_if.out
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
return foo(1, 2);
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
foo
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
_42
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
42
39 changes: 39 additions & 0 deletions crates/rustc_codegen_c_ast/tests/blessed_test/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
use std::path::Path;

use rustc_codegen_c_ast::pretty::{Print, PrinterCtx};
use rustc_codegen_c_ast::{ModuleArena, ModuleCtx};

/// Run a blessed test.
///
/// When the environment variable `RUST_BLESS` is set, this function will store
/// the output of the test case in the corresponding file, otherwise it will
/// compare the output of the test case with the stored output, making sure they
/// are the same.
#[track_caller]
pub fn blessed_test(name: &str, bless: impl Fn() -> String) {
let test_case_path = Path::new("tests/blessed").join(name).with_extension("out");
test_case_path.parent().map(std::fs::create_dir_all);

let output = bless();
let expected_output = std::fs::read_to_string(&test_case_path).unwrap_or_default();
if std::env::var("RUST_BLESS").is_ok() {
std::fs::write(test_case_path, output).unwrap();
} else {
assert_eq!(output, expected_output, "blessed test '{name}' failed");
}
}

/// Run a blessed test for a printable value.
pub fn printer_test<F>(name: &str, test: F)
where
F: for<'mx> Fn(ModuleCtx<'mx>) -> Box<dyn Print + 'mx>, // anyway to avoid the Box?
{
blessed_test(name, || {
let module = ModuleArena::new("// blessed test");
let ctx = ModuleCtx(&module);

let mut pp = PrinterCtx::new();
test(ctx).print_to(&mut pp);
pp.finish()
});
}
19 changes: 19 additions & 0 deletions crates/rustc_codegen_c_ast/tests/decl.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#![feature(rustc_private)]

use blessed_test::*;
use rustc_codegen_c_ast::expr::CValue;
use rustc_type_ir::IntTy;

extern crate rustc_driver;
extern crate rustc_type_ir;
mod blessed_test;

#[test]
fn test_decl_var() {
printer_test("test_decl_var", |ctx| {
let ty = ctx.get_int_type(IntTy::I32);
let name = CValue::Local(42);
let value = ctx.value(CValue::Scalar(42));
Box::new(ctx.var(name, ty, Some(value)))
});
}
84 changes: 84 additions & 0 deletions crates/rustc_codegen_c_ast/tests/expr.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
#![feature(rustc_private)]

use blessed_test::*;
use rustc_codegen_c_ast::expr::CValue;
use rustc_type_ir::IntTy;

extern crate rustc_type_ir;
extern crate rustc_driver;
mod blessed_test;

#[test]
fn test_value_scalar() {
printer_test("test_value_scalar", |_| Box::new(CValue::Scalar(42)));
}

#[test]
fn test_value_local() {
printer_test("test_value_local", |_| Box::new(CValue::Local(42)));
}

#[test]
fn test_value_func() {
printer_test("test_value_func", |_| Box::new(CValue::Func("foo")));
}

#[test]
fn test_expr_raw() {
printer_test("test_expr_raw", |ctx| Box::new(ctx.raw("42")));
}

#[test]
fn test_expr_binary() {
printer_test("test_expr_binary", |ctx| {
let lhs = ctx.value(CValue::Scalar(1));
let rhs = ctx.value(CValue::Scalar(2));
Box::new(ctx.binary(lhs, rhs, "+"))
});
}

#[test]
fn test_expr_cast() {
printer_test("test_expr_cast", |ctx| {
let ty = ctx.get_int_type(IntTy::I32);
let expr = ctx.value(CValue::Scalar(42));
Box::new(ctx.cast(ty, expr))
});
}

#[test]
fn test_expr_call() {
printer_test("test_expr_call", |ctx| {
let callee = ctx.value(CValue::Func("foo"));
let args = vec![ctx.value(CValue::Scalar(1)), ctx.value(CValue::Scalar(2))];
Box::new(ctx.call(callee, args))
});
}

#[test]
fn test_expr_member() {
printer_test("test_expr_member", |ctx| {
let expr = ctx.value(CValue::Local(42));
Box::new(ctx.member(expr, "foo"))
});
}

#[test]
fn test_expr_complex() {
printer_test("test_expr_complex", |ctx| {
let lhs = ctx.value(CValue::Scalar(1));
let rhs = ctx.value(CValue::Scalar(2));
let expr = ctx.binary(lhs, rhs, "+");

let ty = ctx.get_int_type(IntTy::I32);
let cast = ctx.cast(ty, expr);

let callee = ctx.value(CValue::Func("foo"));
let args = vec![ctx.value(CValue::Scalar(1)), cast];
let call = ctx.call(callee, args);

let member = ctx.member(call, "bar");

Box::new(member)
});
}
26 changes: 26 additions & 0 deletions crates/rustc_codegen_c_ast/tests/func.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#![feature(rustc_private)]

use blessed_test::*;
use rustc_codegen_c_ast::expr::CValue;
use rustc_codegen_c_ast::func::{CFunc, CFuncKind};
use rustc_type_ir::IntTy;

extern crate rustc_driver;
extern crate rustc_type_ir;
mod blessed_test;

#[test]
fn test_function() {
printer_test("test_function", |ctx| {
let func = ctx.func(CFuncKind::new(
"foo",
ctx.get_int_type(IntTy::I32),
vec![ctx.get_int_type(IntTy::I32)],
));
let x = func.next_local_var();
func.push_stmt(ctx.decl_stmt(ctx.var(x, ctx.get_int_type(IntTy::I32), None)));
func.push_stmt(ctx.expr_stmt(ctx.binary(ctx.value(x), ctx.value(CValue::Scalar(1)), "=")));
func.push_stmt(ctx.ret(Some(ctx.value(x))));
Box::new(CFunc::new_unchecked(func))
});
}
32 changes: 32 additions & 0 deletions crates/rustc_codegen_c_ast/tests/module.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#![feature(rustc_private)]

use blessed_test::*;
use rustc_codegen_c_ast::expr::CValue;
use rustc_codegen_c_ast::func::{CFunc, CFuncKind};
use rustc_type_ir::IntTy;

extern crate rustc_driver;
extern crate rustc_type_ir;
mod blessed_test;

#[test]
fn test_module() {
printer_test("test_module", |ctx| {
let module = ctx.module();
module.push_include("stdio.h");

module.push_decl(ctx.var(CValue::Local(42), ctx.get_int_type(IntTy::I32), None));

let func = ctx.func(CFuncKind::new(
"foo",
ctx.get_int_type(IntTy::I32),
vec![ctx.get_int_type(IntTy::I32)],
));
let x = func.next_local_var();
func.push_stmt(ctx.decl_stmt(ctx.var(x, ctx.get_int_type(IntTy::I32), None)));
func.push_stmt(ctx.expr_stmt(ctx.binary(ctx.value(x), ctx.value(CValue::Scalar(1)), "=")));
func.push_stmt(ctx.ret(Some(ctx.value(x))));
module.push_func(CFunc::new_unchecked(func));
Box::new(module.clone())
});
}
51 changes: 51 additions & 0 deletions crates/rustc_codegen_c_ast/tests/stmt.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#![feature(rustc_private)]

use blessed_test::*;
use rustc_codegen_c_ast::expr::CValue;
use rustc_type_ir::IntTy;

extern crate rustc_driver;
extern crate rustc_type_ir;
mod blessed_test;

#[test]
fn test_stmt_expr() {
printer_test("test_stmt_expr", |ctx| {
let callee = ctx.value(CValue::Func("foo"));
let args = vec![ctx.value(CValue::Scalar(1)), ctx.value(CValue::Scalar(2))];
let expr = ctx.call(callee, args);
Box::new(ctx.expr_stmt(expr))
});
}

#[test]
fn test_stmt_decl() {
printer_test("test_stmt_decl", |ctx| {
let ty = ctx.get_int_type(IntTy::I32);
let name = CValue::Local(42);
let value = ctx.value(CValue::Scalar(42));
let decl = ctx.var(name, ty, Some(value));
Box::new(ctx.decl_stmt(decl))
});
}

#[test]
fn test_stmt_block() {
printer_test("test_stmt_block", |ctx| {
let callee = ctx.value(CValue::Func("foo"));
let args = vec![ctx.value(CValue::Scalar(1)), ctx.value(CValue::Scalar(2))];
let expr = ctx.call(callee, args);
let stmt = ctx.expr_stmt(expr);
Box::new(ctx.compound(vec![stmt]))
});
}

#[test]
fn test_stmt_ret() {
printer_test("test_stmt_if", |ctx| {
let callee = ctx.value(CValue::Func("foo"));
let args = vec![ctx.value(CValue::Scalar(1)), ctx.value(CValue::Scalar(2))];
let expr = ctx.call(callee, args);
Box::new(ctx.ret(Some(expr)))
});
}

0 comments on commit 4fbf926

Please sign in to comment.