dsntk_examples/
lib.rs

1//! # Examples of decision models and decision tables
2
3mod compatibility;
4pub mod decision_logic;
5pub mod decision_tables;
6mod diagrams;
7mod examples;
8mod exhaustive;
9mod full_model;
10pub mod input_data;
11pub mod item_definition;
12
13pub use compatibility::*;
14pub use diagrams::*;
15pub use examples::valid::*;
16pub use examples::*;
17pub use exhaustive::*;
18pub use full_model::*;
19
20#[cfg(test)]
21mod utilities {
22  use std::collections::BTreeSet;
23  use std::fmt::Write;
24  use walkdir::WalkDir;
25
26  /// Generates multiple decision table variants.
27  #[test]
28  #[rustfmt::skip]
29  pub fn generate_decision_table_variants() {
30    let mut buffer = String::new();
31    let orientation = ["horizontal", "vertical", "crosstab"];
32    let information_item = ["absent", "present" ];
33    let output_label = ["absent", "present" ];
34    let allowed_values = ["absent", "present"];
35    let inputs = ["absent", "single", "double", "multiple"];
36    let outputs = ["single", "double", "multiple"];
37    let annotations = ["absent", "single", "double", "multiple"];
38    let _ = writeln!(&mut buffer, "┌──────┬─────────────┬─────────────┬─────────┬─────────┬──────────┬──────────┬─────────────┬─────────┬────────┐");
39    let _ = writeln!(&mut buffer, "│  No. │  Preferred  │ Information │ Output  │ Allowed │  Inputs  │ Outputs  │ Annotations │ Example │ Status │");
40    let _ = writeln!(&mut buffer, "│      │ orientation │  item name  │  label  │ values  │          │          │             │         │        │");
41    let _ = writeln!(&mut buffer, "├──────┼─────────────┼─────────────┼─────────┼─────────┼──────────┼──────────┼─────────────┼─────────┼────────┤");
42    let mut counter = 1;
43    for v_decision_table_orientation in orientation {
44      for v_information_item_name in information_item {
45        for v_output_label in output_label {
46          for v_allowed_values in allowed_values {
47            for v_inputs in inputs {
48              for v_outputs in outputs {
49                for v_annotations in annotations {
50                  let _ = writeln!(&mut buffer, "│ {counter:>4} │{v_decision_table_orientation:^13}│{v_information_item_name:^13}│{v_output_label:^9}│{v_allowed_values:^9}│{v_inputs:^10}│{v_outputs:^10}│{v_annotations:^13}│ DT_{counter:04} │        │");
51                  counter += 1;
52                }
53              }
54            }
55          }
56        }
57      }
58    }
59    let _ = writeln!(&mut buffer, "└──────┴─────────────┴─────────────┴─────────┴─────────┴──────────┴──────────┴─────────────┴─────────┴────────┘");
60    println!("{}", buffer);
61    assert_eq!(1157, buffer.lines().count());
62  }
63
64  /// This utility function compares the number of compatibility test models in this crate
65  /// with the number of compatibility test models in TCK repository.
66  #[test]
67  fn compare_the_number_of_models() {
68    let tck_models = count_models("../../tck/TestCases");
69    let tck_adjusted_models = tck_models
70      .iter()
71      .filter_map(|s| {
72        let segments = s.split('/').collect::<Vec<&str>>();
73        let first_segment = segments[0]
74          .replace("compliance-level-2", "level_2")
75          .replace("compliance-level-3", "level_3")
76          .replace("non-compliant", "non_compliant");
77        let last_segment = segments[2][0..4].to_string();
78        if last_segment.chars().next().unwrap().is_ascii_digit() {
79          Some(format!("{}/{}", first_segment, last_segment))
80        } else {
81          None
82        }
83      })
84      .collect::<BTreeSet<String>>();
85
86    let dsntk_models = count_models("src/compatibility");
87    let dsntk_adjusted_models = dsntk_models
88      .iter()
89      .map(|s| {
90        let segments = s.split('/').collect::<Vec<&str>>();
91        let first_segment = segments[0];
92        let last_segment = segments[1][2..6].to_string();
93        format!("{}/{}", first_segment, last_segment)
94      })
95      .collect::<BTreeSet<String>>();
96
97    let mut all_keys = BTreeSet::new();
98    all_keys.append(&mut tck_adjusted_models.clone());
99    all_keys.append(&mut dsntk_adjusted_models.clone());
100
101    println!("────────────────────────────────");
102    println!(" Model               TCK  DSNTK");
103    println!("────────────────────────────────");
104    for key in &all_keys {
105      println!(
106        "{:20}  {:>2}     {:>2}",
107        key,
108        if tck_adjusted_models.contains(key) { "OK" } else { "-" },
109        if dsntk_adjusted_models.contains(key) { "OK" } else { "-" }
110      )
111    }
112  }
113
114  /// Counts DMN models residing in the specified directory.
115  fn count_models(root_dir: &str) -> BTreeSet<String> {
116    let mut results = BTreeSet::new();
117    for entry_result in WalkDir::new(root_dir).into_iter() {
118      let entry = entry_result.unwrap();
119      let path = entry.path();
120      if path.is_file() && path.extension().is_some_and(|ext| ext == "dmn") {
121        results.insert(path.strip_prefix(root_dir).unwrap().display().to_string());
122      }
123    }
124    results
125  }
126}