use std::fs;
use std::path::PathBuf;
use std::process::Command;
use scythe_backend::types::resolve_type;
use scythe_codegen::GeneratedCode;
use scythe_codegen::backends::get_backend;
fn scratch_dir() -> PathBuf {
std::env::temp_dir().join("scythe-pg-range-wrapper-compile-check")
}
fn write_scratch_crate(wrapper_source: &str) -> PathBuf {
let dir = scratch_dir();
let src_dir = dir.join("src");
fs::create_dir_all(&src_dir).expect("create scratch crate src directory");
let cargo_toml = r#"[package]
name = "scythe-pg-range-wrapper-compile-check"
version = "0.0.0"
edition = "2024"
publish = false
[workspace]
[dependencies]
tokio-postgres = "0.7"
postgres-protocol = "0.6"
"#;
fs::write(dir.join("Cargo.toml"), cargo_toml).expect("write scratch Cargo.toml");
let mut lib_rs = String::from(
"//! Scratch crate written by tokio_postgres_range_wrapper_compiles.rs -- not part of \
the scythe workspace, never committed. See that file for why it exists.\n\
#![allow(dead_code)]\n\n",
);
lib_rs.push_str(wrapper_source);
lib_rs.push_str(
"\n\n// Forces monomorphization of the FromSql/ToSql impls above for a concrete element \
type -- `i32`, the same element type `resolve_type(\"range<int32>\", ...)` maps to in \
production.\nfn _pg_range_i32_round_trips(v: PgRange<i32>) -> PgRange<i32> {\n v\n}\n",
);
fs::write(src_dir.join("lib.rs"), lib_rs).expect("write scratch src/lib.rs");
dir
}
#[test]
fn tokio_postgres_range_wrapper_compiles_with_a_real_toolchain() {
let backend = get_backend("rust-tokio-postgres", "postgresql").expect("rust-tokio-postgres/postgresql");
let resolved = resolve_type("range<int32>", backend.manifest(), false).expect("range<int32> must resolve");
let with_range = [GeneratedCode::build(|c| {
c.row_struct = Some(format!("pub struct GetSpanRow {{\n pub span: {resolved},\n}}\n"));
})];
let header = backend.file_header_for_results(&with_range);
assert!(
header.contains("pub enum PgRange<T>"),
"file_header_for_results did not emit the PgRange wrapper for a fragment naming it:\n{header}"
);
let dir = write_scratch_crate(&header);
let output = Command::new("cargo")
.args(["check", "--quiet"])
.current_dir(&dir)
.env("CARGO_TARGET_DIR", dir.join("target"))
.output()
.expect("spawn `cargo check` for the scratch crate -- cargo must be on PATH to have run this test at all");
assert!(
output.status.success(),
"the PgRange<T> wrapper rust-tokio-postgres emits does not compile:\n\
--- stdout ---\n{}\n--- stderr ---\n{}\n\
--- source (TokioPostgresBackend::PG_RANGE_SUPPORT, via file_header_for_results) ---\n{}",
String::from_utf8_lossy(&output.stdout),
String::from_utf8_lossy(&output.stderr),
header
);
}