basic/
basic.rs

1mod common;
2
3use std::fs;
4use std::path::Path;
5use std::time::Instant;
6use json_eval_rs::JSONEval;
7use serde_json::{Map, Value};
8
9fn print_help(program_name: &str) {
10    println!("\nšŸš€ JSON Evaluation - Basic Example (JSON Schema)\n");
11    println!("USAGE:");
12    println!("    {} [OPTIONS] [FILTER]\n", program_name);
13    println!("OPTIONS:");
14    println!("    -h, --help         Show this help message");
15    println!("    --compare          Enable comparison with expected results");
16    println!("    --timing           Show detailed internal timing breakdown\n");
17    println!("ARGUMENTS:");
18    println!("    [FILTER]           Optional filter to match scenario names\n");
19    println!("DESCRIPTION:");
20    println!("    Evaluates JSON schemas using JSONEval::new() with JSON string input.\n");
21    println!("EXAMPLES:");
22    println!("    {}                 # Run all JSON schema scenarios", program_name);
23    println!("    {} zcc             # Run scenarios matching 'zcc'", program_name);
24    println!("    {} --compare       # Run with comparison enabled", program_name);
25    println!("    {} zcc --timing    # Run with detailed timing breakdown", program_name);
26}
27
28fn main() {
29    let args: Vec<String> = std::env::args().collect();
30    let program_name = args.get(0).map(|s| s.as_str()).unwrap_or("basic");
31    
32    let mut scenario_filter: Option<String> = None;
33    let mut enable_comparison = false;
34    let mut show_timing = false;
35    let mut i = 1;
36    
37    // Parse arguments
38    while i < args.len() {
39        let arg = &args[i];
40        
41        if arg == "-h" || arg == "--help" {
42            print_help(program_name);
43            return;
44        } else if arg == "--compare" {
45            enable_comparison = true;
46        } else if arg == "--timing" {
47            show_timing = true;
48        } else if !arg.starts_with('-') {
49            scenario_filter = Some(arg.clone());
50        } else {
51            eprintln!("Error: unknown option '{}'", arg);
52            print_help(program_name);
53            return;
54        }
55        
56        i += 1;
57    }
58    
59    println!("\nšŸš€ JSON Evaluation - Basic Example (JSON Schema)\n");
60    
61    if enable_comparison {
62        println!("šŸ” Comparison: enabled");
63    }
64    if show_timing {
65        println!("ā±ļø  Internal timing: enabled");
66    }
67    if enable_comparison || show_timing {
68        println!();
69    }
70    
71    let samples_dir = Path::new("samples");
72    let mut scenarios = common::discover_scenarios(samples_dir);
73    
74    // Filter out MessagePack scenarios - only use JSON
75    scenarios.retain(|s| !s.is_msgpack);
76    
77    // Filter scenarios if a filter is provided
78    if let Some(ref filter) = scenario_filter {
79        scenarios.retain(|s| s.name.contains(filter));
80        println!("šŸ“‹ Filtering scenarios matching: '{}'\n", filter);
81    }
82
83    if scenarios.is_empty() {
84        if let Some(filter) = scenario_filter {
85            println!(
86                "ā„¹ļø  No scenarios found matching '{}' in `{}`.",
87                filter,
88                samples_dir.display()
89            );
90        } else {
91            println!(
92                "ā„¹ļø  No scenarios discovered in `{}`. Add files like `name.json` and `name-data.json`.",
93                samples_dir.display()
94            );
95        }
96        return;
97    }
98    
99    println!("šŸ“Š Found {} scenario(s)\n", scenarios.len());
100
101    let mut total_parse_time = std::time::Duration::ZERO;
102    let mut total_eval_time = std::time::Duration::ZERO;
103    let mut successful_scenarios = 0;
104    let mut comparison_failures = 0;
105
106    for scenario in &scenarios {
107        println!("==============================");
108        println!("Scenario: {}", scenario.name);
109        println!("Schema: {} ({})", 
110            scenario.schema_path.display(),
111            if scenario.is_msgpack { "MessagePack" } else { "JSON" }
112        );
113        println!("Data: {}\n", scenario.data_path.display());
114
115        // Clear timing data from previous scenarios
116        if show_timing {
117            json_eval_rs::enable_timing();
118            json_eval_rs::clear_timing_data();
119        }
120
121        let data_str = fs::read_to_string(&scenario.data_path)
122            .unwrap_or_else(|e| panic!("failed to read {}: {}", scenario.data_path.display(), e));
123
124        // Step 1: Parse schema (JSONEval::new)
125        let parse_start = Instant::now();
126        
127        let schema_str = fs::read_to_string(&scenario.schema_path)
128            .unwrap_or_else(|e| panic!("failed to read {}: {}", scenario.schema_path.display(), e));
129        
130        let mut eval = JSONEval::new(&schema_str, None, Some(&data_str))
131            .unwrap_or_else(|e| panic!("failed to create JSONEval: {}", e));
132        
133        let parse_time = parse_start.elapsed();
134        println!("  šŸ“ Parse (new): {:?}", parse_time);
135        
136        // Step 2: Evaluate
137        let eval_start = Instant::now();
138        
139        eval.evaluate(&data_str, Some("{}"))
140            .unwrap_or_else(|e| panic!("evaluation failed: {}", e));
141        
142        let evaluated_schema = eval.get_evaluated_schema(false);
143        let eval_time = eval_start.elapsed();
144        
145        println!("  ⚔ Eval: {:?}", eval_time);
146        println!("  ā±ļø  Total: {:?}\n", parse_time + eval_time);
147        
148        // Print detailed timing breakdown if --timing flag is set
149        if show_timing {
150            json_eval_rs::print_timing_summary();
151        }
152        
153        total_parse_time += parse_time;
154        total_eval_time += eval_time;
155        successful_scenarios += 1;
156
157        // Save results
158        let evaluated_path = samples_dir.join(format!("{}-evaluated-schema.json", scenario.name));
159        let parsed_path = samples_dir.join(format!("{}-parsed-schema.json", scenario.name));
160
161        fs::write(&evaluated_path, common::pretty_json(&evaluated_schema))
162            .unwrap_or_else(|e| panic!("failed to write {}: {}", evaluated_path.display(), e));
163
164        let mut metadata_obj = Map::new();
165        metadata_obj.insert("dependencies".to_string(), serde_json::to_value(&*eval.dependencies).unwrap());
166        metadata_obj.insert("evaluations".to_string(), serde_json::to_value(&*eval.evaluations).unwrap());
167        metadata_obj.insert("sorted_evaluations".to_string(), serde_json::to_value(&*eval.sorted_evaluations).unwrap());
168
169        fs::write(&parsed_path, common::pretty_json(&Value::Object(metadata_obj)))
170            .unwrap_or_else(|e| panic!("failed to write {}: {}", parsed_path.display(), e));
171
172        println!("āœ… Results saved:");
173        println!("  - {}", evaluated_path.display());
174        println!("  - {}\n", parsed_path.display());
175
176        // Optional comparison
177        if enable_comparison {
178            if let Some(comp_path) = &scenario.comparison_path {
179                if common::compare_with_expected(&evaluated_schema, comp_path).is_err() {
180                    comparison_failures += 1;
181                }
182                println!();
183            }
184        }
185    }
186    
187    // Print summary
188    println!("{}", "=".repeat(50));
189    println!("šŸ“Š Summary");
190    println!("{}", "=".repeat(50));
191    println!("Total scenarios run: {}", successful_scenarios);
192    println!("Total parse time: {:?}", total_parse_time);
193    println!("Total eval time: {:?}", total_eval_time);
194    println!("Total time: {:?}", total_parse_time + total_eval_time);
195    
196    if successful_scenarios > 1 {
197        println!("\nAverage per scenario:");
198        println!("  Parse: {:?}", total_parse_time / successful_scenarios as u32);
199        println!("  Eval: {:?}", total_eval_time / successful_scenarios as u32);
200    }
201    
202    if enable_comparison {
203        println!("Comparison failures: {}", comparison_failures);
204    }
205    
206    println!("\nāœ… All scenarios completed!\n");
207}