use std::{
collections::HashSet,
env,
fs::{self, File},
io::{self, Write},
path::PathBuf,
};
use crate::tests::*;
use proc_macro2::TokenStream;
use proptest::prelude::*;
use quote::{format_ident, quote};
use uuid::Uuid;
struct GeneratedProject {
pub blocks: Vec<GeneratedBlock>,
pub name: Uuid,
}
impl GeneratedProject {
pub fn write(&self) -> io::Result<()> {
let root = self.root();
let tests = root.join("../gen_tests");
if !tests.exists() {
fs::create_dir(&tests)?;
}
let proj = tests.join(self.name.to_string());
let src = proj.join("src");
fs::create_dir(&proj)?;
fs::create_dir(&src)?;
let mut file = File::create(proj.join("Cargo.toml"))?;
file.write_all(self.cargo_toml().as_bytes())?;
let mut file = File::create(src.join("main.rs"))?;
file.write_all(self.main_rs().as_bytes())?;
Ok(())
}
pub fn root(&self) -> PathBuf {
PathBuf::from(env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR is not set"))
}
pub fn main_rs(&self) -> String {
let decs = self
.blocks
.iter()
.map(|blk| blk.as_dec())
.collect::<Vec<TokenStream>>();
let mut vars = Vec::new();
let insts = self
.blocks
.iter()
.map(|blk| {
let name = format_ident!("inst_{}", blk.name);
vars.push(name.clone());
let val = blk.as_val();
quote! { let #name = #val;}
})
.collect::<Vec<TokenStream>>();
quote! {
use brec::*;
#(#decs)*
fn main() {
#(#insts)*
}
}
.to_string()
}
pub fn cargo_toml(&self) -> String {
r#"[package]
name = "test_case"
version = "0.0.0"
edition = "2024"
[dependencies]
brec = { path = "../../../lib/core"}
"#
.to_string()
}
}
proptest! {
#![proptest_config(ProptestConfig {
max_shrink_iters: 50,
..ProptestConfig::with_cases(5)
})]
#[test]
fn test(mut blocks in proptest::collection::vec(GeneratedBlock::arbitrary(), 1..20)) {
let mut seen = HashSet::new();
blocks.retain(|blk| seen.insert(blk.name.clone()));
let pro = GeneratedProject { blocks, name: Uuid::new_v4()};
pro.write()?;
}
}