Skip to main content

dsntk_examples/
lib.rs

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