Skip to content

Commit

Permalink
Merge pull request #94 from ozgurakgun/cases
Browse files Browse the repository at this point in the history
Adding test cases and updating the tester
  • Loading branch information
ozgurakgun authored Nov 21, 2023
2 parents 23322aa + dbb4fc4 commit acdbcc1
Show file tree
Hide file tree
Showing 14 changed files with 196 additions and 99 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
*.log
coverage

conjure_oxide/tests/**/*.generated.*

## Rust
debug/
target/
Expand Down
47 changes: 32 additions & 15 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 4 additions & 1 deletion conjure_oxide/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,11 @@ version = "0.0.1"
edition = "2021"
default-run = "conjure_oxide"

# these are available inside build.rs
[build-dependencies]
walkdir = "2.4.0"

[dependencies]
assert-json-diff = "2.0.2"
serde = { version = "1.0.192", features = ["derive"] }
serde_json = "1.0.108"
serde_with = "3.4.0"
Expand Down
69 changes: 47 additions & 22 deletions conjure_oxide/build.rs
Original file line number Diff line number Diff line change
@@ -1,30 +1,55 @@
use std::{
env::var,
fs::File,
fs::{read_dir, DirEntry},
io::Write,
path::Path,
};
use std::env::var;
use std::fs::{read_dir, File};
use std::io::{self, Write};
use std::path::Path;
use walkdir::WalkDir;

fn main() {
let out_dir = var("OUT_DIR").unwrap();
fn main() -> io::Result<()> {
let out_dir = var("OUT_DIR").map_err(|e| io::Error::new(io::ErrorKind::Other, e))?; // wrapping in a std::io::Error to match main's error type
let dest = Path::new(&out_dir).join("gen_tests.rs");
let mut f = File::create(&dest).unwrap();
let mut f = File::create(&dest)?;

let test_dir = "tests/integration";
for dir in read_dir(test_dir).unwrap() {
write_test(&mut f, &dir.unwrap());

for subdir in WalkDir::new(test_dir) {
let subdir = subdir?;
if subdir.file_type().is_dir() {
let essence_files: Vec<String> = read_dir(subdir.path())?
.filter_map(Result::ok)
.filter(|entry| {
entry
.path()
.extension()
.map_or(false, |ext| ext == "essence")
})
.filter_map(|entry| {
entry
.path()
.file_stem()
.and_then(|stem| stem.to_str())
.map(|s| s.to_owned())
})
.collect();

write_test(&mut f, subdir.path().display().to_string(), essence_files)?;
}
}

Ok(())
}

fn write_test(file: &mut File, dir: &DirEntry) {
let binding = dir.path();
let path = binding.to_str().unwrap();
write!(
file,
include_str!("./tests/gen_test_template"),
name = path.replace("./", "").replace("/", "_"),
path = path
)
.unwrap();
fn write_test(file: &mut File, path: String, essence_files: Vec<String>) -> io::Result<()> {
// TODO: Consider supporting multiple Essence files?
if essence_files.len() == 1 {
write!(
file,
include_str!("./tests/gen_test_template"),
// TODO: better sanitisation of paths to function names
test_name = path.replace("./", "").replace("/", "_").replace("-", "_"),
test_dir = path,
essence_file = essence_files[0]
)
} else {
Ok(())
}
}
2 changes: 1 addition & 1 deletion conjure_oxide/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::{collections::HashMap, fs::File, io::Read};
use std::collections::HashMap;

use conjure_oxide::ast::*;

Expand Down
4 changes: 2 additions & 2 deletions conjure_oxide/tests/gen_test_template
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#[test]
fn {name}() -> Result<(), Box<dyn Error>> {{
integration_test("{path}")
fn {test_name}() -> Result<(), Box<dyn Error>> {{
integration_test("{test_dir}", "{essence_file}")
}}
58 changes: 45 additions & 13 deletions conjure_oxide/tests/generated_tests.rs
Original file line number Diff line number Diff line change
@@ -1,34 +1,66 @@
use assert_json_diff::assert_json_eq;
use std::env;
use std::error::Error;
use std::fs::File;
use std::io::prelude::*;

use conjure_oxide::ast::Model;

fn integration_test(path: &str) -> Result<(), Box<dyn Error>> {
println!("Integration test for: {}", path);
use std::path::Path;

fn main() {
let file_path = Path::new("/path/to/your/file.txt");
let base_name = file_path.file_stem().and_then(|stem| stem.to_str());

match base_name {
Some(name) => println!("Base name: {}", name),
None => println!("Could not extract the base name"),
}
}

fn integration_test(path: &str, essence_base: &str) -> Result<(), Box<dyn Error>> {
// --------------------------------------------------------------------------------
// -- parsing the essence file

// calling conjure to convert Essence to astjson
let mut cmd = std::process::Command::new("conjure");
let output = cmd
.arg("pretty")
.arg("--output-format=astjson")
.arg(format!("{path}/input.essence", path = path))
.arg(format!("{path}/{essence_base}.essence"))
.output()?;
assert!(
String::from_utf8(output.stderr)?.is_empty(),
"conjure's stderr is not empty"
);
let astjson = String::from_utf8(output.stdout)?;

// "parsing" astjson as Model
let generated_mdl = Model::from_json(&astjson)?;

let mut expected_str = String::new();
let mut f = File::open(format!(
"{path}/input.serialised.expected.json",
path = path
))?;
f.read_to_string(&mut expected_str)?;
// serialise to file
let generated_json = serde_json::to_string_pretty(&generated_mdl)?;
File::create(format!("{path}/{essence_base}.generated.serialised.json"))?
.write_all(generated_json.as_bytes())?;

if std::env::var("ACCEPT").map_or(false, |v| v == "true") {
std::fs::copy(
format!("{path}/{essence_base}.generated.serialised.json"),
format!("{path}/{essence_base}.expected.serialised.json"),
)?;
}

// --------------------------------------------------------------------------------
// -- reading the expected version from the filesystem

let expected_str =
std::fs::read_to_string(format!("{path}/{essence_base}.expected.serialised.json"))?;

let mut expected_mdl: Model = serde_json::from_str(&expected_str)?;
expected_mdl.constraints = Vec::new(); // TODO - remove this line once we parse constraints

println!("Expected {:#?}", expected_mdl);
println!("\nActual {:#?}", generated_mdl);
// --------------------------------------------------------------------------------
// assert that they are the same model

// assert_json_eq!(serde_json::to_string_pretty(&generated_mdl)?, expected_str); // TODO - replace line once we parse constraints
assert_eq!(generated_mdl, expected_mdl);

Ok(())
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
find x : bool
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"variables": [
[
{
"UserName": "x"
},
{
"domain": "BoolDomain"
}
]
],
"constraints": []
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
find x, y : bool
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"variables": [
[
{
"UserName": "y"
},
{
"domain": "BoolDomain"
}
],
[
{
"UserName": "x"
},
{
"domain": "BoolDomain"
}
]
],
"constraints": []
}
2 changes: 2 additions & 0 deletions conjure_oxide/tests/integration/basic/bool-03/bool-03.essence
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
find x, y : bool
such that x != y
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"variables": [
[
{
"UserName": "x"
},
{
"domain": "BoolDomain"
}
],
[
{
"UserName": "y"
},
{
"domain": "BoolDomain"
}
]
],
"constraints": []
}
Loading

0 comments on commit acdbcc1

Please sign in to comment.