Skip to content

Commit

Permalink
Merge pull request #569 from Soph1514/json_rule_format
Browse files Browse the repository at this point in the history
standardised format of json rule output
  • Loading branch information
ozgurakgun authored Jan 19, 2025
2 parents 166d36d + 707b5ca commit 9befb7f
Show file tree
Hide file tree
Showing 87 changed files with 103,721 additions and 45 deletions.
83 changes: 55 additions & 28 deletions conjure_oxide/src/utils/testing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -191,35 +191,15 @@ pub fn read_rule_trace(
test_name: &str,
prefix: &str,
accept: bool,
) -> Result<Vec<String>, std::io::Error> {
) -> Result<JsonValue, anyhow::Error> {
let filename = format!("{path}/{test_name}-{prefix}-rule-trace.json");
let mut rules_trace: Vec<String> = read_to_string(&filename)
.unwrap()
.lines()
.map(String::from)
.collect();

//only count the number of rule in generated file (assumming the expected version already has that line and it is correct)
if prefix == "generated" {
let rule_count = rules_trace.len();

let count_message = json!({
"message": " Number of rules applied",
"count": rule_count
});

// Append the count message to the vector
let count_message_string = serde_json::to_string(&count_message)?;
rules_trace.push(count_message_string.clone());

// Write the updated rules trace back to the file
let mut file = OpenOptions::new()
.write(true)
.truncate(true) // Overwrite the file with updated content
.open(&filename)?;

writeln!(file, "{}", rules_trace.join("\n"))?;
}
let rule_traces = if prefix == "generated" {
count_and_sort_rules(&filename)?
} else {
let file_contents = std::fs::read_to_string(filename)?;
serde_json::from_str(&file_contents)?
};

if accept {
std::fs::copy(
Expand All @@ -228,7 +208,54 @@ pub fn read_rule_trace(
)?;
}

Ok(rules_trace)
Ok(rule_traces)
}

pub fn count_and_sort_rules(filename: &str) -> Result<JsonValue, anyhow::Error> {
let file_contents = read_to_string(filename)?;

let sorted_json_rules = if file_contents.trim().is_empty() {
let rule_count_message = json!({
"Number of rules applied": 0,
});
rule_count_message
} else {
let rule_count = file_contents.lines().count();
let mut sorted_json_rules = sort_json_rules(&file_contents)?;

let rule_count_message = json!({
"Number of rules applied": rule_count,
});

if let Some(array) = sorted_json_rules.as_array_mut() {
array.push(rule_count_message);
} else {
return Err(anyhow::anyhow!("Expected JSON array"));
}
sort_json_object(&sorted_json_rules, false)
};

let generated_sorted_json_rules = serde_json::to_string_pretty(&sorted_json_rules)?;

let mut file = OpenOptions::new()
.write(true)
.truncate(true)
.open(filename)?;

file.write_all(generated_sorted_json_rules.as_bytes())?;

Ok(sorted_json_rules)
}

fn sort_json_rules(json_rule_traces: &str) -> Result<JsonValue, anyhow::Error> {
let mut sorted_rule_traces = Vec::new();

for line in json_rule_traces.lines() {
let pretty_json = sort_json_object(&serde_json::from_str(line)?, true);
sorted_rule_traces.push(pretty_json);
}

Ok(JsonValue::Array(sorted_rule_traces))
}

pub fn read_human_rule_trace(
Expand Down
47 changes: 30 additions & 17 deletions conjure_oxide/tests/generated_tests.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
use conjure_core::rule_engine::rewrite_naive;
use conjure_core::Model;
use conjure_oxide::utils::essence_parser::parse_essence_file_native;
use conjure_oxide::utils::testing::read_human_rule_trace;
use conjure_oxide::utils::testing::{read_human_rule_trace, read_rule_trace};
use glob::glob;
use itertools::Itertools;
use std::collections::BTreeMap;
use std::env;
use std::error::Error;
use std::fs;
use std::fs::File;
use tracing::{span, Level};
use tracing::{span, Level, Metadata as OtherMetadata};
use tracing_subscriber::{
filter::EnvFilter, filter::FilterFn, fmt, layer::SubscriberExt, Layer, Registry,
};

use uniplate::Biplate;

use tracing_appender::non_blocking::WorkerGuard;
Expand All @@ -36,9 +37,8 @@ use conjure_oxide::utils::testing::{
read_minion_solutions_json, read_model_json, save_minion_solutions_json, save_model_json,
};
use conjure_oxide::SolverFamily;
use serde::Deserialize;

use pretty_assertions::assert_eq;
use serde::Deserialize;

#[derive(Deserialize)]
#[serde(default)]
Expand Down Expand Up @@ -99,7 +99,7 @@ fn integration_test(path: &str, essence_base: &str, extension: &str) -> Result<(
// run tests in sequence not parallel when verbose logging, to ensure the logs are ordered
// correctly

let subscriber = create_scoped_subscriber(path, essence_base);
let (subscriber, _guards) = create_scoped_subscriber(path, essence_base);

// set the subscriber as default
tracing::subscriber::with_default(subscriber, || {
Expand Down Expand Up @@ -241,6 +241,11 @@ fn integration_test_inner(

//Stage 3: Check that the generated rules match with the expected in terms if type, order and count

let generated_json_rule_trace = read_rule_trace(path, essence_base, "generated", accept)?;
let expected_json_rule_trace = read_rule_trace(path, essence_base, "expected", accept)?;

assert_eq!(expected_json_rule_trace, generated_json_rule_trace);

let generated_rule_trace_human =
read_human_rule_trace(path, essence_base, "generated", accept)?;
let expected_rule_trace_human = read_human_rule_trace(path, essence_base, "expected", accept)?;
Expand Down Expand Up @@ -387,17 +392,20 @@ fn assert_constants_leq_one(parent_expr: &Expression, exprs: &[Expression]) {
pub fn create_scoped_subscriber(
path: &str,
test_name: &str,
) -> (impl tracing::Subscriber + Send + Sync) {
//let (target1_layer, guard1) = create_file_layer_json(path, test_name);
let target2_layer = create_file_layer_human(path, test_name);
let layered = target2_layer;
) -> (
impl tracing::Subscriber + Send + Sync,
Vec<tracing_appender::non_blocking::WorkerGuard>,
) {
let (target1_layer, guard1) = create_file_layer_json(path, test_name);
let (target2_layer, guard2) = create_file_layer_human(path, test_name);
let layered = target1_layer.and_then(target2_layer);

let subscriber = Arc::new(tracing_subscriber::registry().with(layered))
as Arc<dyn tracing::Subscriber + Send + Sync>;
// setting this subscriber as the default
let _default = tracing::subscriber::set_default(subscriber.clone());

subscriber
(subscriber, vec![guard1, guard2])
}

fn create_file_layer_json(
Expand All @@ -410,29 +418,34 @@ fn create_file_layer_json(

let layer1 = fmt::layer()
.with_writer(non_blocking)
.json()
.with_level(false)
.without_time()
.with_target(false)
.with_filter(EnvFilter::new("rule_engine=trace"))
.with_filter(FilterFn::new(|meta| meta.target() == "rule_engine"));
.without_time()
.with_filter(FilterFn::new(|meta: &OtherMetadata| {
meta.target() == "rule_engine"
}));

(layer1, guard1)
}

fn create_file_layer_human(path: &str, test_name: &str) -> (impl Layer<Registry> + Send + Sync) {
fn create_file_layer_human(
path: &str,
test_name: &str,
) -> (impl Layer<Registry> + Send + Sync, WorkerGuard) {
let file = File::create(format!("{path}/{test_name}-generated-rule-trace-human.txt"))
.expect("Unable to create log file");

let (non_blocking, guard2) = tracing_appender::non_blocking(file);

let layer2 = fmt::layer()
.with_writer(file)
.with_writer(non_blocking)
.with_level(false)
.without_time()
.with_target(false)
.with_filter(EnvFilter::new("rule_engine_human=trace"))
.with_filter(FilterFn::new(|meta| meta.target() == "rule_engine_human"));

layer2
(layer2, guard2)
}

#[test]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
[
{
"initial_expression": {
"Eq": [
{
"Abs": [
{
"Atomic": [
{
"Reference": {
"UserName": "x"
}
},
{
"clean": false,
"etype": null
}
]
},
{
"clean": false,
"etype": null
}
]
},
{
"Atomic": [
{
"Literal": {
"Int": 1
}
},
{
"clean": false,
"etype": null
}
]
},
{
"clean": false,
"etype": null
}
]
},
"rule_name": "introduce_abseq",
"rule_set": [
[
"Minion",
4400
]
],
"transformed _expression": {
"FlatAbsEq": [
{
"Literal": {
"Int": 1
}
},
{
"Reference": {
"UserName": "x"
}
},
{
"clean": false,
"etype": null
}
]
}
},
{
"Number of rules applied": 1
}
]
Loading

0 comments on commit 9befb7f

Please sign in to comment.