zoi_cli/pkg/package/
test.rs1use crate::{cmd, pkg};
2use anyhow::{Result, anyhow};
3use colored::*;
4use mlua::{Lua, LuaSerdeExt};
5
6pub fn run(args: &cmd::package::build::BuildCommand) -> Result<()> {
7 println!("Testing package from: {}", args.package_file.display());
8
9 let platform = if let Some(p) = args.platform.first() {
10 p.clone()
11 } else {
12 crate::pkg::utils::get_platform()?
13 };
14
15 let pkg_for_meta = pkg::lua::parser::parse_lua_package_for_platform(
16 args.package_file.to_str().ok_or_else(|| {
17 anyhow!(
18 "Path contains invalid UTF-8 characters: {:?}",
19 args.package_file
20 )
21 })?,
22 &platform,
23 args.version_override.as_deref(),
24 None,
25 false,
26 )?;
27
28 let version = if let Some(v) = &args.version_override {
29 v.clone()
30 } else {
31 pkg::resolve::get_default_version(&pkg_for_meta, None)?
32 };
33
34 let resolved_build_type = match crate::pkg::package::build::resolve_build_type(
35 args.r#type.as_deref(),
36 &pkg_for_meta.types,
37 &pkg_for_meta.name,
38 )? {
39 Some(t) => t,
40 None => {
41 println!(
42 "{} Skipping tests for package '{}': no build types supported.",
43 "::".bold().yellow(),
44 pkg_for_meta.name
45 );
46 return Ok(());
47 }
48 };
49
50 let build_dir = tempfile::Builder::new()
51 .prefix(&format!("zoi-test-{}-{}", pkg_for_meta.name, platform))
52 .tempdir()?;
53 println!("Using build directory: {}", build_dir.path().display());
54 let staging_dir = build_dir.path().join("staging");
55 std::fs::create_dir_all(&staging_dir)?;
56
57 let subs_to_test = if let Some(subs) = &args.sub {
58 subs.clone()
59 } else if let Some(subs) = &pkg_for_meta.sub_packages {
60 subs.clone()
61 } else {
62 vec!["".to_string()]
63 };
64
65 for sub_package in subs_to_test {
66 let sub_pkg_name = if sub_package.is_empty() {
67 None
68 } else {
69 Some(sub_package.as_str())
70 };
71
72 if !sub_package.is_empty() {
73 println!(
74 "{} Testing sub-package: {}",
75 "::".bold().blue(),
76 sub_package.cyan()
77 );
78 }
79
80 let lua = Lua::new();
81 pkg::lua::functions::setup_lua_environment(
82 &lua,
83 &platform,
84 Some(&version),
85 args.package_file.to_str(),
86 None,
87 Some(build_dir.path().to_str().unwrap_or("")),
88 Some(staging_dir.to_str().unwrap_or("")),
89 sub_pkg_name,
90 Some(pkg_for_meta.scope),
91 Some(resolved_build_type.as_str()),
92 false,
93 )
94 .map_err(|e| anyhow!(e.to_string()))?;
95
96 let pkg_table = lua
97 .to_value(&pkg_for_meta)
98 .map_err(|e| anyhow!(e.to_string()))?;
99 lua.globals()
100 .set("PKG", pkg_table)
101 .map_err(|e| anyhow!(e.to_string()))?;
102
103 let lua_code = std::fs::read_to_string(&args.package_file)?;
104 lua.load(&lua_code)
105 .exec()
106 .map_err(|e| anyhow!(e.to_string()))?;
107
108 let lua_args = lua.create_table().map_err(|e| anyhow!(e.to_string()))?;
109 if !sub_package.is_empty() {
110 lua_args
111 .set("sub", sub_package.clone())
112 .map_err(|e| anyhow!(e.to_string()))?;
113 }
114
115 if let Ok(prepare_fn) = lua.globals().get::<mlua::Function>("prepare") {
116 println!("Running prepare()...");
117 prepare_fn
118 .call::<()>(lua_args.clone())
119 .map_err(|e| anyhow!(e.to_string()))?;
120 }
121
122 if let Ok(package_fn) = lua.globals().get::<mlua::Function>("package") {
123 println!("Running package()...");
124 package_fn
125 .call::<()>(lua_args.clone())
126 .map_err(|e| anyhow!(e.to_string()))?;
127 }
128
129 if let Ok(test_fn) = lua.globals().get::<mlua::Function>("test") {
130 println!("Running test()...");
131 let success: bool = match test_fn.call::<mlua::Value>(lua_args.clone()) {
132 Ok(mlua::Value::Boolean(b)) => b,
133 Ok(mlua::Value::Nil) => {
134 return Err(anyhow!(
135 "The 'test' function in '{}' returned nil. It must explicitly return a boolean (true or false).",
136 args.package_file.display()
137 ));
138 }
139 Ok(v) => {
140 return Err(anyhow!(
141 "The 'test' function in '{}' returned a non-boolean value of type {:?}. It must return true or false.",
142 args.package_file.display(),
143 v.type_name()
144 ));
145 }
146 Err(e) => return Err(anyhow!(e.to_string())),
147 };
148 if !success {
149 return Err(anyhow!(
150 "Package tests failed for sub-package '{}'.",
151 sub_package
152 ));
153 }
154 } else if !sub_package.is_empty() {
155 println!(
156 "No test() function found for sub-package '{}', skipping.",
157 sub_package
158 );
159 }
160 }
161
162 println!("{}", "All tests passed successfully.".green());
163 Ok(())
164}