mod common;
use tempfile::TempDir;
#[test]
fn flake_lock_roundtrip_path_input() {
if common::skip_if_offline("flake_lock_roundtrip") {
return;
}
let tmp = TempDir::new().unwrap();
let dep_dir = tmp.path().join("dep");
std::fs::create_dir_all(&dep_dir).unwrap();
std::fs::write(
dep_dir.join("flake.nix"),
r#"{
description = "test dependency";
outputs = { self }: { value = 42; };
}"#,
)
.unwrap();
let main_dir = tmp.path().join("main");
std::fs::create_dir_all(&main_dir).unwrap();
std::fs::write(
main_dir.join("flake.nix"),
&format!(
r#"{{
description = "test main";
inputs.dep.url = "path:{}";
outputs = {{ self, dep }}: {{ value = dep.value + 1; }};
}}"#,
dep_dir.display()
),
)
.unwrap();
for dir in [&dep_dir, &main_dir] {
match sui_eval::git::init_repo(dir, "main") {
Ok(repo) => {
let _ = sui_eval::git::commit_all(&repo, "init", "test", "test@test.com");
}
Err(e) => {
println!("git init failed for {}: {e}", dir.display());
}
}
}
match sui_eval::flake_lock::list_inputs(&main_dir) {
Ok(inputs) => println!("inputs: {inputs:?}"),
Err(e) => println!("list_inputs: {e} (expected -- no lock file yet)"),
}
match sui_eval::builtins::evaluate_flake(&main_dir) {
Ok(v) => println!("eval success: {:?}", v.type_name()),
Err(e) => println!("eval: {e}"),
}
}
#[test]
fn flake_lock_read_real_nix_repo() {
if common::skip_if_offline("flake_lock_read") {
return;
}
let root = common::pleme_io_root();
let nix_dir = root.join("nix");
if !nix_dir.join("flake.lock").exists() {
println!("skip: nix repo flake.lock not found");
return;
}
match sui_eval::flake_lock::list_inputs(&nix_dir) {
Ok(inputs) => {
println!(
"nix repo has {} inputs: {}",
inputs.len(),
inputs[..std::cmp::min(10, inputs.len())].join(", ")
);
if inputs.len() > 10 {
println!(" ... and {} more", inputs.len() - 10);
}
assert!(
!inputs.is_empty(),
"nix repo should have at least one input"
);
}
Err(e) => println!("list_inputs failed: {e}"),
}
}
#[test]
fn flake_lock_get_nixpkgs_rev() {
if common::skip_if_offline("flake_lock_nixpkgs_rev") {
return;
}
let root = common::pleme_io_root();
let nix_dir = root.join("nix");
if !nix_dir.join("flake.lock").exists() {
println!("skip: nix repo flake.lock not found");
return;
}
match sui_eval::flake_lock::get_input_rev(&nix_dir, "nixpkgs") {
Ok(Some(rev)) => {
println!("nixpkgs locked at: {rev}");
assert_eq!(rev.len(), 40, "git rev should be 40 hex chars");
assert!(
rev.chars().all(|c| c.is_ascii_hexdigit()),
"rev should be hex"
);
}
Ok(None) => println!("nixpkgs: no rev (unexpected for a locked input)"),
Err(e) => println!("get_input_rev failed: {e}"),
}
}
#[test]
fn flake_lock_roundtrip_no_inputs() {
if common::skip_if_offline("flake_lock_roundtrip_no_inputs") {
return;
}
let tmp = TempDir::new().unwrap();
let flake_dir = tmp.path().join("simple");
std::fs::create_dir_all(&flake_dir).unwrap();
std::fs::write(
flake_dir.join("flake.nix"),
r#"{
description = "simple roundtrip test";
outputs = { self }: {
answer = 42;
greeting = "hello";
nested = { a = 1; b = { c = true; }; };
};
}"#,
)
.unwrap();
match sui_eval::git::init_repo(&flake_dir, "main") {
Ok(repo) => {
let _ = sui_eval::git::commit_all(&repo, "init", "test", "test@test.com");
}
Err(e) => {
println!("git init failed: {e}");
return;
}
}
let result = match sui_eval::builtins::evaluate_flake(&flake_dir) {
Ok(v) => v,
Err(e) => {
println!("eval failed: {e}");
return;
}
};
if let sui_eval::value::Value::Attrs(ref attrs) = result {
if let Some(answer) = attrs.get("answer") {
let forced = sui_eval::eval::force_value(answer);
match forced {
Ok(sui_eval::value::Value::Int(42)) => println!("answer = 42 (correct)"),
Ok(other) => println!("answer = {other:?} (unexpected)"),
Err(e) => println!("force answer: {e}"),
}
}
if let Some(greeting) = attrs.get("greeting") {
let forced = sui_eval::eval::force_value(greeting);
match forced {
Ok(sui_eval::value::Value::String(ref s)) if s.as_str() == "hello" => {
println!("greeting = \"hello\" (correct)");
}
Ok(other) => println!("greeting = {other:?} (unexpected)"),
Err(e) => println!("force greeting: {e}"),
}
}
if let Some(nested) = attrs.get("nested") {
let forced = sui_eval::eval::force_value(nested);
match forced {
Ok(sui_eval::value::Value::Attrs(ref nested_attrs)) => {
println!(
"nested keys: {:?}",
nested_attrs.keys().collect::<Vec<_>>()
);
}
Ok(other) => println!("nested = {other:?} (unexpected)"),
Err(e) => println!("force nested: {e}"),
}
}
} else {
println!("result is not attrs: {}", result.type_name());
}
println!("flake lock roundtrip (no inputs) completed");
}
#[test]
fn flake_lock_enumerate_all_real_inputs() {
if common::skip_if_offline("flake_lock_enumerate") {
return;
}
let root = common::pleme_io_root();
let nix_dir = root.join("nix");
if !nix_dir.join("flake.lock").exists() {
println!("skip: nix repo flake.lock not found");
return;
}
let inputs = match sui_eval::flake_lock::list_inputs(&nix_dir) {
Ok(inputs) => inputs,
Err(e) => {
println!("list_inputs failed: {e}");
return;
}
};
println!("total inputs: {}", inputs.len());
let mut with_rev = 0u32;
let mut without_rev = 0u32;
let mut errors = 0u32;
for input in &inputs {
match sui_eval::flake_lock::get_input_rev(&nix_dir, input) {
Ok(Some(rev)) => {
with_rev += 1;
if with_rev <= 5 {
println!(" {input}: {}", &rev[..std::cmp::min(12, rev.len())]);
}
}
Ok(None) => {
without_rev += 1;
if without_rev <= 3 {
println!(" {input}: (no rev -- likely a follows redirect)");
}
}
Err(e) => {
errors += 1;
if errors <= 3 {
println!(" {input}: error: {e}");
}
}
}
}
println!(
"summary: {with_rev} with rev, {without_rev} without rev, {errors} errors"
);
}