1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
#[macro_use]
extern crate dmntk_macros;

mod boxed_expressions;
mod business_knowledge_model;
mod decision;
mod decision_service;
mod decision_table;
mod errors;
mod input_data;
mod input_data_context;
mod item_definition;
mod item_definition_context;
mod item_definition_type;
mod model_builder;
mod model_definitions;
mod model_evaluator;
mod type_ref;
mod variable;

#[cfg(test)]
mod tests;

pub use decision_table::build_decision_table_evaluator;
pub use model_evaluator::ModelEvaluator;

#[cfg(test)]
mod utilities {
  use dmntk_common::{color_red, color_reset, ColorMode};
  use std::collections::{BTreeMap, BTreeSet};
  use std::fs;
  use walkdir::WalkDir;

  /// This is a utility function for comparing the number of compatibility tests
  /// with the number of compatibility benchmarks, used to verify if all tests
  /// are also benchmarked.
  #[test]
  #[ignore]
  fn compare_the_number_of_tests_and_benchmarks() {
    let (tests, test_count) = count_number_of_artefacts("src/tests/compatibility", "#[test]");
    let (benches, bench_count) = count_number_of_artefacts("benches/compatibility", "#[bench]");
    println!("---------------------------------------------------------------");
    println!("      tests: {}", test_count);
    println!(" benchmarks: {}", bench_count);
    println!("---------------------------------------------------------------");
    println!(" {:29} {:^9} {:^6} {:^6}", "File name", "Tests", "Benchmarks", "Difference");
    println!("---------------------------------------------------------------");
    let mut file_names = BTreeSet::new();
    file_names.append(&mut tests.keys().map(|key| key.to_string()).collect::<BTreeSet<String>>());
    file_names.append(&mut benches.keys().map(|key| key.to_string()).collect::<BTreeSet<String>>());
    for file_name in &file_names {
      let t_count = tests.get(file_name).unwrap_or(&0_usize).to_owned();
      let b_count = benches.get(file_name).unwrap_or(&0_usize).to_owned();
      println!("{:30} {:>6} {:>12} {}", file_name, t_count, b_count, diff(t_count, b_count));
    }
    println!("---------------------------------------------------------------");
    println!("{:30} {:>6} {:>12} {}", "Total", test_count, bench_count, diff(test_count, bench_count));
  }

  /// Counts the number of specific words in a file.
  fn count_number_of_artefacts(root_dir: &str, artefact: &str) -> (BTreeMap<String, usize>, usize) {
    let mut results = BTreeMap::new();
    let mut total = 0_usize;
    for entry_result in WalkDir::new(root_dir).into_iter() {
      match entry_result {
        Ok(entry) => {
          let path = entry.path();
          if path.is_file() && path.extension().map_or(false, |ext| ext == "rs") {
            let content = fs::read_to_string(path).unwrap_or_else(|e| panic!("failed to load file: {} with reason: {}", path.display(), e));
            let mut count = 0_usize;
            for line in content.lines() {
              if line.trim() == artefact {
                count += 1;
              }
            }
            if count > 1 {
              results.insert(path.strip_prefix(root_dir).unwrap().display().to_string(), count);
              total += count;
            }
          }
        }
        Err(reason) => eprintln!("{}", reason),
      }
    }
    (results, total)
  }

  /// Prepares the difference in text format.
  fn diff(a: usize, b: usize) -> String {
    let color_red = color_red!(ColorMode::On);
    let color_reset = color_reset!(ColorMode::On);
    let diff = if a > b { a - b } else { b - a };
    if diff > 0 {
      format!("{1}{2:>9}{0}", color_reset, color_red, diff)
    } else {
      "".to_string()
    }
  }
}