182 lines
5.4 KiB
Rust
182 lines
5.4 KiB
Rust
use super::Directory;
|
|
use dever::compiler::{project::Project, toolchain::BuildTarget};
|
|
use std::path::Path;
|
|
use std::process::{Command, Output};
|
|
|
|
mod packaging;
|
|
mod skill;
|
|
|
|
fn cli(arguments: &[&str]) -> Output {
|
|
Command::new(env!("CARGO_BIN_EXE_dever"))
|
|
.args(arguments)
|
|
.output()
|
|
.unwrap()
|
|
}
|
|
|
|
fn success(output: Output) -> String {
|
|
assert!(
|
|
output.status.success(),
|
|
"{}",
|
|
String::from_utf8_lossy(&output.stderr)
|
|
);
|
|
String::from_utf8(output.stdout).unwrap()
|
|
}
|
|
|
|
#[test]
|
|
fn new_creates_plain_source_and_separate_docs_without_overwriting() {
|
|
let directory = Directory::new();
|
|
for name in ["plain", "second"] {
|
|
let root = directory.0.join(name);
|
|
let text = root.to_str().unwrap();
|
|
let arguments = vec!["new", text];
|
|
success(cli(&arguments));
|
|
let suffix = "dever";
|
|
assert!(
|
|
root.join(format!("module/hello/greeting/app.{suffix}"))
|
|
.is_file()
|
|
);
|
|
assert!(
|
|
root.join(format!("test/hello/greeting/greet.{suffix}"))
|
|
.is_file()
|
|
);
|
|
assert!(root.join("module/hello/greeting/README.md").is_file());
|
|
assert!(root.join("module/hello/greeting/doc/greeting.md").is_file());
|
|
let project = Project::load(&root).unwrap();
|
|
assert_eq!(project.check().unwrap().commands.len(), 1);
|
|
success(cli(&["check", text]));
|
|
success(cli(&["fmt", text, "--check"]));
|
|
let snapshot = std::fs::read(root.join("README.md")).unwrap();
|
|
assert!(!cli(&arguments).status.success());
|
|
assert_eq!(std::fs::read(root.join("README.md")).unwrap(), snapshot);
|
|
}
|
|
let path = directory.0.join("invalid");
|
|
assert!(
|
|
!cli(&["new", path.to_str().unwrap(), "--markdown"])
|
|
.status
|
|
.success()
|
|
);
|
|
assert!(!path.exists());
|
|
let link = directory.0.join("link");
|
|
std::os::unix::fs::symlink(directory.0.join("plain"), &link).unwrap();
|
|
let rejected = cli(&["new", link.to_str().unwrap()]);
|
|
assert!(!rejected.status.success());
|
|
assert!(String::from_utf8_lossy(&rejected.stderr).contains(link.to_str().unwrap()));
|
|
assert_eq!(
|
|
std::fs::read_link(&link).unwrap(),
|
|
directory.0.join("plain")
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn template_runs_tests_and_builds_a_real_native_executable_for_the_selected_target() {
|
|
let directory = Directory::new();
|
|
let root = directory.0.join("app");
|
|
dever::compiler::project::create(&root).unwrap();
|
|
let root = root.to_str().unwrap();
|
|
success(cli(&["test", root]));
|
|
let result = success(cli(&[
|
|
"run",
|
|
root,
|
|
"--",
|
|
"hello.greeting.greet",
|
|
r#"{"name":"Dever"}"#,
|
|
]));
|
|
assert_eq!(
|
|
serde_json::from_str::<serde_json::Value>(&result).unwrap()["data"],
|
|
"Hello, Dever"
|
|
);
|
|
let binary = directory.0.join("hello");
|
|
success(cli(&[
|
|
"build",
|
|
root,
|
|
"--output",
|
|
binary.to_str().unwrap(),
|
|
"--target",
|
|
BuildTarget::host().unwrap().name(),
|
|
]));
|
|
BuildTarget::host()
|
|
.unwrap()
|
|
.validate_executable(&std::fs::read(&binary).unwrap())
|
|
.unwrap();
|
|
let result = success(
|
|
Command::new(&binary)
|
|
.args(["hello.greeting.greet", r#"{"name":"native"}"#])
|
|
.output()
|
|
.unwrap(),
|
|
);
|
|
assert_eq!(
|
|
serde_json::from_str::<serde_json::Value>(&result).unwrap()["data"],
|
|
"Hello, native"
|
|
);
|
|
let before = std::fs::read(&binary).unwrap();
|
|
assert!(
|
|
!cli(&["build", root, "--output", binary.to_str().unwrap()])
|
|
.status
|
|
.success()
|
|
);
|
|
assert_eq!(std::fs::read(&binary).unwrap(), before);
|
|
assert!(
|
|
!cli(&["run", root, "--target", "linux-aarch64"])
|
|
.status
|
|
.success()
|
|
);
|
|
assert!(
|
|
!cli(&[
|
|
"build",
|
|
root,
|
|
"--output",
|
|
binary.to_str().unwrap(),
|
|
"--target",
|
|
"unsupported"
|
|
])
|
|
.status
|
|
.success()
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn elf_validation_checks_architecture_and_executable_type() {
|
|
let mut header = vec![0_u8; 64];
|
|
header[..7].copy_from_slice(b"\x7fELF\x02\x01\x01");
|
|
header[16..18].copy_from_slice(&2_u16.to_le_bytes());
|
|
header[18..20].copy_from_slice(&183_u16.to_le_bytes());
|
|
assert!(
|
|
BuildTarget::LinuxAarch64
|
|
.validate_executable(&header)
|
|
.is_ok()
|
|
);
|
|
assert!(
|
|
BuildTarget::LinuxX86_64
|
|
.validate_executable(&header)
|
|
.is_err()
|
|
);
|
|
header[16..18].copy_from_slice(&1_u16.to_le_bytes());
|
|
assert!(
|
|
BuildTarget::LinuxAarch64
|
|
.validate_executable(&header)
|
|
.is_err()
|
|
);
|
|
assert!(
|
|
BuildTarget::LinuxAarch64
|
|
.validate_executable(b"short")
|
|
.is_err()
|
|
);
|
|
assert!(BuildTarget::parse("linux-x86_64").is_ok());
|
|
assert!(BuildTarget::parse("esp32").is_err());
|
|
}
|
|
|
|
fn copy_tree(source: &Path, destination: &Path) {
|
|
if source.is_dir() {
|
|
std::fs::create_dir_all(destination).unwrap();
|
|
for entry in std::fs::read_dir(source)
|
|
.unwrap_or_else(|error| panic!("{}: {error}", source.display()))
|
|
{
|
|
let entry = entry.unwrap();
|
|
copy_tree(&entry.path(), &destination.join(entry.file_name()));
|
|
}
|
|
} else {
|
|
std::fs::create_dir_all(destination.parent().unwrap()).unwrap();
|
|
std::fs::copy(source, destination).unwrap();
|
|
}
|
|
}
|