summaryrefslogtreecommitdiff
path: root/tests/tests.rs
blob: 14f90bc766faee25a3842d89a114f97eebfad267 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
#[cfg(test)]
mod tests {
	use std::fs::File;
	use std::process::{Command, Output};
	use tinyld::linker::{LinkWarning, Linker};

	fn panic_warning_handler(warning: LinkWarning) {
		eprintln!("warning: {warning}");
		panic!("this should not generate a warning");
	}

	fn test_linker<'a>() -> Linker<'a> {
		let mut linker = Linker::new();
		linker.set_warning_handler(panic_warning_handler);
		linker
	}

	fn file(s: &str) -> String {
		format!("./tests/{s}")
	}

	fn add(linker: &mut Linker, src: &str, is_local: bool) {
		let f = file(src);
		let s = if is_local { &f } else { src };
		linker.add_input(s).expect(&format!("failed to add {s}"));
	}

	fn link(linker: &Linker, out: &str, entry: &str) {
		linker
			.link_to_file(&file(out), entry)
			.expect("failed to link");
	}

	fn run_with_stdin(name: &str, stdin: Option<&str>) -> Output {
		let mut command = Command::new(&file(name));
		if let Some(s) = stdin {
			let file = File::open(&file(s)).expect("stdin file does not exist");
			command.stdin(file);
		}

		let output = command.output().expect("failed to run output executable");
		assert!(output.status.success());
		assert!(output.stderr.is_empty());
		output
	}

	fn run(name: &str) -> std::process::Output {
		run_with_stdin(name, None)
	}

	#[test]
	fn tiny_c() {
		let mut linker = test_linker();
		add(&mut linker, "tiny.c", true);
		link(&linker, "test.out", "entry");
		let output = run("tiny.out");
		assert!(output.stdout.is_empty());
	}

	#[test]
	fn basic_c() {
		let mut linker = test_linker();
		add(&mut linker, "basic.c", true);
		add(&mut linker, "libc.so.6", false);
		link(&linker, "basic.out", "entry");
		let output = run("basic.out");
		assert_eq!(output.stdout, b"137\n");
	}

	#[test]
	fn dylib_c() {
		let status = Command::new("gcc")
			.args(&[
				"-m32",
				"-fPIC",
				"-shared",
				&file("dylib.c"),
				"-o",
				&file("dylib.so"),
			])
			.status()
			.expect("failed to create dylib.so");
		assert!(status.success());

		let mut linker = test_linker();
		add(&mut linker, "dylib-test.c", true);
		add(&mut linker, "dylib.so", true);
		add(&mut linker, "libc.so.6", false);
		link(&linker, "dylib-test.out", "entry");
		let output = run("dylib-test.out");
		assert_eq!(output.stdout, b"7\n8\n");
	}

	#[test]
	fn cpp() {
		let mut linker = test_linker();
		add(&mut linker, "cpp.cpp", true);
		add(&mut linker, "libc.so.6", false);
		add(&mut linker, "libstdc++.so.6", false);
		link(&linker, "cpp.out", "main");
		let output = run_with_stdin("cpp.out", Some("cpp-input.txt"));
		assert_eq!(output.stdout, b"0\n7\n65\n212\n233\n");
	}
}