Skip to main content

conjure_oxide/
test_solve.rs

1use std::path::PathBuf;
2use std::process::exit;
3use std::sync::Arc;
4
5use crate::cli::GlobalArgs;
6use crate::solve::{self, init_solver};
7use clap::ValueHint;
8use conjure_cp::instantiate::{instantiate_model, validate_instantiation_conditions};
9use conjure_cp_cli::utils::conjure::{
10    get_solutions, get_solutions_from_conjure, solutions_to_json,
11};
12use conjure_cp_cli::utils::testing::normalize_solutions_for_comparison;
13
14#[derive(Clone, Debug, clap::Args)]
15pub struct Args {
16    /// The input Essence problem file
17    #[arg(value_name = "INPUT_ESSENCE",value_hint=ValueHint::FilePath)]
18    pub input_file: PathBuf,
19
20    /// The input Essence parameter file
21    #[arg(value_name = "PARAM_ESSENCE", value_hint=ValueHint::FilePath)]
22    pub param_file: Option<PathBuf>,
23}
24
25pub fn run_test_solve_command(global_args: GlobalArgs, local_args: Args) -> anyhow::Result<()> {
26    // stealing most of the steps of the solve command, except the solver stuff.
27    let input_file = local_args.input_file;
28    let param_file = local_args.param_file;
29
30    // each step is in its own method so that similar commands
31    // (e.g. testsolve) can reuse some of these steps.
32
33    let context = solve::init_context(&global_args, input_file.clone(), param_file.clone())?;
34
35    // get input and param file name from context
36    let ctx_lock = context.read().unwrap();
37    let essence_file_name = ctx_lock
38        .essence_file_name
39        .as_ref()
40        .expect("context should contain the problem input file");
41    let param_file_name = ctx_lock.param_file_name.as_ref();
42
43    // parse models
44    let problem_model = solve::parse(&global_args, Arc::clone(&context), essence_file_name)?;
45
46    let unified_model = match param_file_name {
47        Some(param_file_name) => {
48            let param_model = solve::parse(&global_args, Arc::clone(&context), param_file_name)?;
49            instantiate_model(problem_model, param_model)?
50        }
51        None => {
52            let mut problem_model = problem_model;
53            validate_instantiation_conditions(&mut problem_model)?;
54            problem_model
55        }
56    };
57
58    drop(ctx_lock);
59
60    let rewritten_model = solve::rewrite(unified_model, &global_args, Arc::clone(&context))?;
61
62    let solver = init_solver(&global_args);
63
64    // now we are stealing from the integration tester
65
66    let our_solutions = get_solutions(
67        solver,
68        rewritten_model,
69        0,
70        false,
71        &global_args.save_solver_input_file,
72        global_args.rule_trace_cdp,
73    )?;
74
75    let conjure_solutions = get_solutions_from_conjure(
76        input_file.to_str().unwrap(),
77        param_file.as_deref().map(|f| f.to_str().unwrap()),
78        Arc::clone(&context),
79    )?;
80
81    let our_solutions = normalize_solutions_for_comparison(&our_solutions);
82    let conjure_solutions = normalize_solutions_for_comparison(&conjure_solutions);
83
84    let mut our_solutions_json = solutions_to_json(&our_solutions);
85    let mut conjure_solutions_json = solutions_to_json(&conjure_solutions);
86
87    our_solutions_json.sort_all_objects();
88    conjure_solutions_json.sort_all_objects();
89
90    if our_solutions_json == conjure_solutions_json {
91        eprintln!("Success: solutions match!");
92        exit(0);
93    } else {
94        eprintln!("=== our solutions:");
95        eprintln!("{our_solutions_json}");
96        eprintln!("=== conjure's solutions:");
97        eprintln!("{conjure_solutions_json}");
98        eprintln!("Failure: solutions do not match!");
99        exit(1);
100    }
101}