1
// Tests for rewriting/simplifying parts of the AST
2

            
3
use conjure_core::rule::Rule;
4
use conjure_rules::{get_rule_by_name, get_rules};
5
use core::panic;
6
use std::collections::HashMap;
7

            
8
use conjure_oxide::{ast::*, eval_constant, rewrite::rewrite, solvers::FromConjureModel};
9
use minion_rs::ast::{Constant as MinionConstant, VarName};
10

            
11
#[test]
12
fn rules_present() {
13
    let rules = conjure_rules::get_rules();
14
    assert!(!rules.is_empty());
15
}
16

            
17
#[test]
18
fn sum_of_constants() {
19
    let valid_sum_expression = Expression::Sum(vec![
20
        Expression::Constant(Constant::Int(1)),
21
        Expression::Constant(Constant::Int(2)),
22
        Expression::Constant(Constant::Int(3)),
23
    ]);
24

            
25
    let invalid_sum_expression = Expression::Sum(vec![
26
        Expression::Constant(Constant::Int(1)),
27
        Expression::Reference(Name::UserName(String::from("a"))),
28
    ]);
29

            
30
    match evaluate_sum_of_constants(&valid_sum_expression) {
31
        Some(result) => assert_eq!(result, 6),
32
        None => panic!(),
33
    }
34

            
35
    if evaluate_sum_of_constants(&invalid_sum_expression).is_some() {
36
        panic!()
37
    }
38
}
39

            
40
fn evaluate_sum_of_constants(expr: &Expression) -> Option<i32> {
41
    match expr {
42
        Expression::Sum(expressions) => {
43
            let mut sum = 0;
44
            for e in expressions {
45
                match e {
46
                    Expression::Constant(Constant::Int(value)) => {
47
                        sum += value;
48
                    }
49
                    _ => return None,
50
                }
51
            }
52
            Some(sum)
53
        }
54
        _ => None,
55
    }
56
}
57

            
58
#[test]
59
fn recursive_sum_of_constants() {
60
    let complex_expression = Expression::Eq(
61
        Box::new(Expression::Sum(vec![
62
            Expression::Constant(Constant::Int(1)),
63
            Expression::Constant(Constant::Int(2)),
64
            Expression::Sum(vec![
65
                Expression::Constant(Constant::Int(1)),
66
                Expression::Constant(Constant::Int(2)),
67
            ]),
68
            Expression::Reference(Name::UserName(String::from("a"))),
69
        ])),
70
        Box::new(Expression::Constant(Constant::Int(3))),
71
    );
72
    let correct_simplified_expression = Expression::Eq(
73
        Box::new(Expression::Sum(vec![
74
            Expression::Constant(Constant::Int(1)),
75
            Expression::Constant(Constant::Int(2)),
76
            Expression::Constant(Constant::Int(3)),
77
            Expression::Reference(Name::UserName(String::from("a"))),
78
        ])),
79
        Box::new(Expression::Constant(Constant::Int(3))),
80
    );
81

            
82
    let simplified_expression = simplify_expression(complex_expression.clone());
83
    assert_eq!(simplified_expression, correct_simplified_expression);
84
}
85

            
86
fn simplify_expression(expr: Expression) -> Expression {
87
    match expr {
88
        Expression::Sum(expressions) => {
89
            if let Some(result) = evaluate_sum_of_constants(&Expression::Sum(expressions.clone())) {
90
                Expression::Constant(Constant::Int(result))
91
            } else {
92
                Expression::Sum(expressions.into_iter().map(simplify_expression).collect())
93
            }
94
        }
95
        Expression::Eq(left, right) => Expression::Eq(
96
            Box::new(simplify_expression(*left)),
97
            Box::new(simplify_expression(*right)),
98
        ),
99
        Expression::Geq(left, right) => Expression::Geq(
100
            Box::new(simplify_expression(*left)),
101
            Box::new(simplify_expression(*right)),
102
        ),
103
        _ => expr,
104
    }
105
}
106

            
107
#[test]
108
fn rule_sum_constants() {
109
    let sum_constants = get_rule_by_name("sum_constants").unwrap();
110
    let unwrap_sum = get_rule_by_name("unwrap_sum").unwrap();
111

            
112
    let mut expr = Expression::Sum(vec![
113
        Expression::Constant(Constant::Int(1)),
114
        Expression::Constant(Constant::Int(2)),
115
        Expression::Constant(Constant::Int(3)),
116
    ]);
117

            
118
    expr = sum_constants.apply(&expr).unwrap();
119
    expr = unwrap_sum.apply(&expr).unwrap();
120

            
121
    assert_eq!(expr, Expression::Constant(Constant::Int(6)));
122
}
123

            
124
#[test]
125
fn rule_sum_mixed() {
126
    let sum_constants = get_rule_by_name("sum_constants").unwrap();
127

            
128
    let mut expr = Expression::Sum(vec![
129
        Expression::Constant(Constant::Int(1)),
130
        Expression::Constant(Constant::Int(2)),
131
        Expression::Reference(Name::UserName(String::from("a"))),
132
    ]);
133

            
134
    expr = sum_constants.apply(&expr).unwrap();
135

            
136
    assert_eq!(
137
        expr,
138
        Expression::Sum(vec![
139
            Expression::Reference(Name::UserName(String::from("a"))),
140
            Expression::Constant(Constant::Int(3)),
141
        ])
142
    );
143
}
144

            
145
#[test]
146
fn rule_sum_geq() {
147
    let flatten_sum_geq = get_rule_by_name("flatten_sum_geq").unwrap();
148

            
149
    let mut expr = Expression::Geq(
150
        Box::new(Expression::Sum(vec![
151
            Expression::Constant(Constant::Int(1)),
152
            Expression::Constant(Constant::Int(2)),
153
        ])),
154
        Box::new(Expression::Constant(Constant::Int(3))),
155
    );
156

            
157
    expr = flatten_sum_geq.apply(&expr).unwrap();
158

            
159
    assert_eq!(
160
        expr,
161
        Expression::SumGeq(
162
            vec![
163
                Expression::Constant(Constant::Int(1)),
164
                Expression::Constant(Constant::Int(2)),
165
            ],
166
            Box::new(Expression::Constant(Constant::Int(3)))
167
        )
168
    );
169
}
170

            
171
fn callback(solution: HashMap<VarName, MinionConstant>) -> bool {
172
    println!("Solution: {:?}", solution);
173
    false
174
}
175

            
176
///
177
/// Reduce and solve:
178
/// ```text
179
/// find a,b,c : int(1..3)
180
/// such that a + b + c <= 2 + 3 - 1
181
/// such that a < b
182
/// ```
183
#[test]
184
fn reduce_solve_xyz() {
185
    println!("Rules: {:?}", conjure_rules::get_rules());
186
    let sum_constants = get_rule_by_name("sum_constants").unwrap();
187
    let unwrap_sum = get_rule_by_name("unwrap_sum").unwrap();
188
    let lt_to_ineq = get_rule_by_name("lt_to_ineq").unwrap();
189
    let sum_leq_to_sumleq = get_rule_by_name("sum_leq_to_sumleq").unwrap();
190

            
191
    // 2 + 3 - 1
192
    let mut expr1 = Expression::Sum(vec![
193
        Expression::Constant(Constant::Int(2)),
194
        Expression::Constant(Constant::Int(3)),
195
        Expression::Constant(Constant::Int(-1)),
196
    ]);
197

            
198
    expr1 = sum_constants.apply(&expr1).unwrap();
199
    expr1 = unwrap_sum.apply(&expr1).unwrap();
200
    assert_eq!(expr1, Expression::Constant(Constant::Int(4)));
201

            
202
    // a + b + c = 4
203
    expr1 = Expression::Leq(
204
        Box::new(Expression::Sum(vec![
205
            Expression::Reference(Name::UserName(String::from("a"))),
206
            Expression::Reference(Name::UserName(String::from("b"))),
207
            Expression::Reference(Name::UserName(String::from("c"))),
208
        ])),
209
        Box::new(expr1),
210
    );
211
    expr1 = sum_leq_to_sumleq.apply(&expr1).unwrap();
212
    assert_eq!(
213
        expr1,
214
        Expression::SumLeq(
215
            vec![
216
                Expression::Reference(Name::UserName(String::from("a"))),
217
                Expression::Reference(Name::UserName(String::from("b"))),
218
                Expression::Reference(Name::UserName(String::from("c"))),
219
            ],
220
            Box::new(Expression::Constant(Constant::Int(4)))
221
        )
222
    );
223

            
224
    // a < b
225
    let mut expr2 = Expression::Lt(
226
        Box::new(Expression::Reference(Name::UserName(String::from("a")))),
227
        Box::new(Expression::Reference(Name::UserName(String::from("b")))),
228
    );
229
    expr2 = lt_to_ineq.apply(&expr2).unwrap();
230
    assert_eq!(
231
        expr2,
232
        Expression::Ineq(
233
            Box::new(Expression::Reference(Name::UserName(String::from("a")))),
234
            Box::new(Expression::Reference(Name::UserName(String::from("b")))),
235
            Box::new(Expression::Constant(Constant::Int(-1)))
236
        )
237
    );
238

            
239
    let mut model = Model {
240
        variables: HashMap::new(),
241
        constraints: Expression::And(vec![expr1, expr2]),
242
    };
243
    model.variables.insert(
244
        Name::UserName(String::from("a")),
245
        DecisionVariable {
246
            domain: Domain::IntDomain(vec![Range::Bounded(1, 3)]),
247
        },
248
    );
249
    model.variables.insert(
250
        Name::UserName(String::from("b")),
251
        DecisionVariable {
252
            domain: Domain::IntDomain(vec![Range::Bounded(1, 3)]),
253
        },
254
    );
255
    model.variables.insert(
256
        Name::UserName(String::from("c")),
257
        DecisionVariable {
258
            domain: Domain::IntDomain(vec![Range::Bounded(1, 3)]),
259
        },
260
    );
261

            
262
    let minion_model = conjure_oxide::solvers::minion::MinionModel::from_conjure(model).unwrap();
263

            
264
    minion_rs::run_minion(minion_model, callback).unwrap();
265
}
266

            
267
#[test]
268
fn rule_remove_double_negation() {
269
    let remove_double_negation = get_rule_by_name("remove_double_negation").unwrap();
270

            
271
    let mut expr = Expression::Not(Box::new(Expression::Not(Box::new(Expression::Constant(
272
        Constant::Bool(true),
273
    )))));
274

            
275
    expr = remove_double_negation.apply(&expr).unwrap();
276

            
277
    assert_eq!(expr, Expression::Constant(Constant::Bool(true)));
278
}
279

            
280
#[test]
281
fn rule_unwrap_nested_or() {
282
    let unwrap_nested_or = get_rule_by_name("unwrap_nested_or").unwrap();
283

            
284
    let mut expr = Expression::Or(vec![
285
        Expression::Or(vec![
286
            Expression::Constant(Constant::Bool(true)),
287
            Expression::Constant(Constant::Bool(false)),
288
        ]),
289
        Expression::Constant(Constant::Bool(true)),
290
    ]);
291

            
292
    expr = unwrap_nested_or.apply(&expr).unwrap();
293

            
294
    assert_eq!(
295
        expr,
296
        Expression::Or(vec![
297
            Expression::Constant(Constant::Bool(true)),
298
            Expression::Constant(Constant::Bool(false)),
299
            Expression::Constant(Constant::Bool(true)),
300
        ])
301
    );
302
}
303

            
304
#[test]
305
fn rule_unwrap_nested_and() {
306
    let unwrap_nested_and = get_rule_by_name("unwrap_nested_and").unwrap();
307

            
308
    let mut expr = Expression::And(vec![
309
        Expression::And(vec![
310
            Expression::Constant(Constant::Bool(true)),
311
            Expression::Constant(Constant::Bool(false)),
312
        ]),
313
        Expression::Constant(Constant::Bool(true)),
314
    ]);
315

            
316
    expr = unwrap_nested_and.apply(&expr).unwrap();
317

            
318
    assert_eq!(
319
        expr,
320
        Expression::And(vec![
321
            Expression::Constant(Constant::Bool(true)),
322
            Expression::Constant(Constant::Bool(false)),
323
            Expression::Constant(Constant::Bool(true)),
324
        ])
325
    );
326
}
327

            
328
#[test]
329
fn unwrap_nested_or_not_changed() {
330
    let unwrap_nested_or = get_rule_by_name("unwrap_nested_or").unwrap();
331

            
332
    let expr = Expression::Or(vec![
333
        Expression::Constant(Constant::Bool(true)),
334
        Expression::Constant(Constant::Bool(false)),
335
    ]);
336

            
337
    let result = unwrap_nested_or.apply(&expr);
338

            
339
    assert!(result.is_err());
340
}
341

            
342
#[test]
343
fn unwrap_nested_and_not_changed() {
344
    let unwrap_nested_and = get_rule_by_name("unwrap_nested_and").unwrap();
345

            
346
    let expr = Expression::And(vec![
347
        Expression::Constant(Constant::Bool(true)),
348
        Expression::Constant(Constant::Bool(false)),
349
    ]);
350

            
351
    let result = unwrap_nested_and.apply(&expr);
352

            
353
    assert!(result.is_err());
354
}
355

            
356
#[test]
357
fn remove_trivial_and_or() {
358
    let remove_trivial_and = get_rule_by_name("remove_trivial_and").unwrap();
359
    let remove_trivial_or = get_rule_by_name("remove_trivial_or").unwrap();
360

            
361
    let mut expr_and = Expression::And(vec![Expression::Constant(Constant::Bool(true))]);
362
    let mut expr_or = Expression::Or(vec![Expression::Constant(Constant::Bool(false))]);
363

            
364
    expr_and = remove_trivial_and.apply(&expr_and).unwrap();
365
    expr_or = remove_trivial_or.apply(&expr_or).unwrap();
366

            
367
    assert_eq!(expr_and, Expression::Constant(Constant::Bool(true)));
368
    assert_eq!(expr_or, Expression::Constant(Constant::Bool(false)));
369
}
370

            
371
#[test]
372
fn rule_remove_constants_from_or() {
373
    let remove_constants_from_or = get_rule_by_name("remove_constants_from_or").unwrap();
374

            
375
    let mut expr = Expression::Or(vec![
376
        Expression::Constant(Constant::Bool(true)),
377
        Expression::Constant(Constant::Bool(false)),
378
        Expression::Reference(Name::UserName(String::from("a"))),
379
    ]);
380

            
381
    expr = remove_constants_from_or.apply(&expr).unwrap();
382

            
383
    assert_eq!(expr, Expression::Constant(Constant::Bool(true)));
384
}
385

            
386
#[test]
387
fn rule_remove_constants_from_and() {
388
    let remove_constants_from_and = get_rule_by_name("remove_constants_from_and").unwrap();
389

            
390
    let mut expr = Expression::And(vec![
391
        Expression::Constant(Constant::Bool(true)),
392
        Expression::Constant(Constant::Bool(false)),
393
        Expression::Reference(Name::UserName(String::from("a"))),
394
    ]);
395

            
396
    expr = remove_constants_from_and.apply(&expr).unwrap();
397

            
398
    assert_eq!(expr, Expression::Constant(Constant::Bool(false)));
399
}
400

            
401
#[test]
402
fn remove_constants_from_or_not_changed() {
403
    let remove_constants_from_or = get_rule_by_name("remove_constants_from_or").unwrap();
404

            
405
    let expr = Expression::Or(vec![
406
        Expression::Reference(Name::UserName(String::from("a"))),
407
        Expression::Reference(Name::UserName(String::from("b"))),
408
    ]);
409

            
410
    let result = remove_constants_from_or.apply(&expr);
411

            
412
    assert!(result.is_err());
413
}
414

            
415
#[test]
416
fn remove_constants_from_and_not_changed() {
417
    let remove_constants_from_and = get_rule_by_name("remove_constants_from_and").unwrap();
418

            
419
    let expr = Expression::And(vec![
420
        Expression::Reference(Name::UserName(String::from("a"))),
421
        Expression::Reference(Name::UserName(String::from("b"))),
422
    ]);
423

            
424
    let result = remove_constants_from_and.apply(&expr);
425

            
426
    assert!(result.is_err());
427
}
428

            
429
#[test]
430
fn rule_distribute_not_over_and() {
431
    let distribute_not_over_and = get_rule_by_name("distribute_not_over_and").unwrap();
432

            
433
    let mut expr = Expression::Not(Box::new(Expression::And(vec![
434
        Expression::Reference(Name::UserName(String::from("a"))),
435
        Expression::Reference(Name::UserName(String::from("b"))),
436
    ])));
437

            
438
    expr = distribute_not_over_and.apply(&expr).unwrap();
439

            
440
    assert_eq!(
441
        expr,
442
        Expression::Or(vec![
443
            Expression::Not(Box::new(Expression::Reference(Name::UserName(
444
                String::from("a")
445
            )))),
446
            Expression::Not(Box::new(Expression::Reference(Name::UserName(
447
                String::from("b")
448
            )))),
449
        ])
450
    );
451
}
452

            
453
#[test]
454
fn rule_distribute_not_over_or() {
455
    let distribute_not_over_or = get_rule_by_name("distribute_not_over_or").unwrap();
456

            
457
    let mut expr = Expression::Not(Box::new(Expression::Or(vec![
458
        Expression::Reference(Name::UserName(String::from("a"))),
459
        Expression::Reference(Name::UserName(String::from("b"))),
460
    ])));
461

            
462
    expr = distribute_not_over_or.apply(&expr).unwrap();
463

            
464
    assert_eq!(
465
        expr,
466
        Expression::And(vec![
467
            Expression::Not(Box::new(Expression::Reference(Name::UserName(
468
                String::from("a")
469
            )))),
470
            Expression::Not(Box::new(Expression::Reference(Name::UserName(
471
                String::from("b")
472
            )))),
473
        ])
474
    );
475
}
476

            
477
#[test]
478
fn rule_distribute_not_over_and_not_changed() {
479
    let distribute_not_over_and = get_rule_by_name("distribute_not_over_and").unwrap();
480

            
481
    let expr = Expression::Not(Box::new(Expression::Reference(Name::UserName(
482
        String::from("a"),
483
    ))));
484

            
485
    let result = distribute_not_over_and.apply(&expr);
486

            
487
    assert!(result.is_err());
488
}
489

            
490
#[test]
491
fn rule_distribute_not_over_or_not_changed() {
492
    let distribute_not_over_or = get_rule_by_name("distribute_not_over_or").unwrap();
493

            
494
    let expr = Expression::Not(Box::new(Expression::Reference(Name::UserName(
495
        String::from("a"),
496
    ))));
497

            
498
    let result = distribute_not_over_or.apply(&expr);
499

            
500
    assert!(result.is_err());
501
}
502

            
503
#[test]
504
fn rule_distribute_or_over_and() {
505
    let distribute_or_over_and = get_rule_by_name("distribute_or_over_and").unwrap();
506

            
507
    let mut expr = Expression::Or(vec![
508
        Expression::And(vec![
509
            Expression::Reference(Name::MachineName(1)),
510
            Expression::Reference(Name::MachineName(2)),
511
        ]),
512
        Expression::Reference(Name::MachineName(3)),
513
    ]);
514

            
515
    expr = distribute_or_over_and.apply(&expr).unwrap();
516

            
517
    assert_eq!(
518
        expr,
519
        Expression::And(vec![
520
            Expression::Or(vec![
521
                Expression::Reference(Name::MachineName(3)),
522
                Expression::Reference(Name::MachineName(1)),
523
            ]),
524
            Expression::Or(vec![
525
                Expression::Reference(Name::MachineName(3)),
526
                Expression::Reference(Name::MachineName(2)),
527
            ]),
528
        ]),
529
    );
530
}
531

            
532
///
533
/// Reduce and solve:
534
/// ```text
535
/// find a,b,c : int(1..3)
536
/// such that a + b + c = 4
537
/// such that a < b
538
/// ```
539
///
540
/// This test uses the rewrite function to simplify the expression instead
541
/// of applying the rules manually.
542
#[test]
543
fn rewrite_solve_xyz() {
544
    println!("Rules: {:?}", conjure_rules::get_rules());
545

            
546
    // Create variables and domains
547
    let variable_a = Name::UserName(String::from("a"));
548
    let variable_b = Name::UserName(String::from("b"));
549
    let variable_c = Name::UserName(String::from("c"));
550
    let domain = Domain::IntDomain(vec![Range::Bounded(1, 3)]);
551

            
552
    // Construct nested expression
553
    let nested_expr = Expression::And(vec![
554
        Expression::Eq(
555
            Box::new(Expression::Sum(vec![
556
                Expression::Reference(variable_a.clone()),
557
                Expression::Reference(variable_b.clone()),
558
                Expression::Reference(variable_c.clone()),
559
            ])),
560
            Box::new(Expression::Constant(Constant::Int(4))),
561
        ),
562
        Expression::Lt(
563
            Box::new(Expression::Reference(variable_a.clone())),
564
            Box::new(Expression::Reference(variable_b.clone())),
565
        ),
566
    ]);
567

            
568
    // Apply rewrite function to the nested expression
569
    let rewritten_expr = rewrite(&nested_expr);
570

            
571
    // Check if the expression is in its simplest form
572
    let expr = rewritten_expr.clone();
573
    assert!(is_simple(&expr));
574

            
575
    // Create model with variables and constraints
576
    let mut model = Model {
577
        variables: HashMap::new(),
578
        constraints: rewritten_expr,
579
    };
580

            
581
    // Insert variables and domains
582
    model.variables.insert(
583
        variable_a.clone(),
584
        DecisionVariable {
585
            domain: domain.clone(),
586
        },
587
    );
588
    model.variables.insert(
589
        variable_b.clone(),
590
        DecisionVariable {
591
            domain: domain.clone(),
592
        },
593
    );
594
    model.variables.insert(
595
        variable_c.clone(),
596
        DecisionVariable {
597
            domain: domain.clone(),
598
        },
599
    );
600

            
601
    // Convert the model to MinionModel
602
    let minion_model = conjure_oxide::solvers::minion::MinionModel::from_conjure(model).unwrap();
603

            
604
    // Run the solver with the rewritten model
605
    minion_rs::run_minion(minion_model, callback).unwrap();
606
}
607

            
608
struct RuleResult<'a> {
609
    rule: Rule<'a>,
610
    new_expression: Expression,
611
}
612

            
613
/// # Returns
614
/// - True if `expression` is in its simplest form.
615
/// - False otherwise.
616
pub fn is_simple(expression: &Expression) -> bool {
617
    let rules = get_rules();
618
    let mut new = expression.clone();
619
    while let Some(step) = is_simple_iteration(&new, &rules) {
620
        new = step;
621
    }
622
    new == *expression
623
}
624

            
625
/// # Returns
626
/// - Some(<new_expression>) after applying the first applicable rule to `expr` or a sub-expression.
627
/// - None if no rule is applicable to the expression or any sub-expression.
628
fn is_simple_iteration<'a>(
629
    expression: &'a Expression,
630
    rules: &'a Vec<Rule<'a>>,
631
) -> Option<Expression> {
632
    let rule_results = apply_all_rules(expression, rules);
633
    if let Some(new) = choose_rewrite(&rule_results) {
634
        return Some(new);
635
    } else {
636
        match expression.sub_expressions() {
637
            None => {}
638
            Some(mut sub) => {
639
                for i in 0..sub.len() {
640
                    if let Some(new) = is_simple_iteration(sub[i], rules) {
641
                        sub[i] = &new;
642
                        return Some(expression.with_sub_expressions(sub));
643
                    }
644
                }
645
            }
646
        }
647
    }
648
    None // No rules applicable to this branch of the expression
649
}
650

            
651
/// # Returns
652
/// - A list of RuleResults after applying all rules to `expression`.
653
/// - An empty list if no rules are applicable.
654
fn apply_all_rules<'a>(
655
    expression: &'a Expression,
656
    rules: &'a Vec<Rule<'a>>,
657
) -> Vec<RuleResult<'a>> {
658
    let mut results = Vec::new();
659
    for rule in rules {
660
        match rule.apply(expression) {
661
            Ok(new) => {
662
                results.push(RuleResult {
663
                    rule: rule.clone(),
664
                    new_expression: new,
665
                });
666
            }
667
            Err(_) => continue,
668
        }
669
    }
670
    results
671
}
672

            
673
/// # Returns
674
/// - Some(<new_expression>) after applying the first rule in `results`.
675
/// - None if `results` is empty.
676
fn choose_rewrite(results: &Vec<RuleResult>) -> Option<Expression> {
677
    if results.is_empty() {
678
        return None;
679
    }
680
    // Return the first result for now
681
    // println!("Applying rule: {:?}", results[0].rule);
682
    Some(results[0].new_expression.clone())
683
}
684

            
685
#[test]
686
fn eval_const_int() {
687
    let expr = Expression::Constant(Constant::Int(1));
688
    let result = eval_constant(&expr);
689
    assert_eq!(result, Some(Constant::Int(1)));
690
}
691

            
692
#[test]
693
fn eval_const_bool() {
694
    let expr = Expression::Constant(Constant::Bool(true));
695
    let result = eval_constant(&expr);
696
    assert_eq!(result, Some(Constant::Bool(true)));
697
}
698

            
699
#[test]
700
fn eval_const_and() {
701
    let expr = Expression::And(vec![
702
        Expression::Constant(Constant::Bool(true)),
703
        Expression::Constant(Constant::Bool(false)),
704
    ]);
705
    let result = eval_constant(&expr);
706
    assert_eq!(result, Some(Constant::Bool(false)));
707
}
708

            
709
#[test]
710
fn eval_const_ref() {
711
    let expr = Expression::Reference(Name::UserName(String::from("a")));
712
    let result = eval_constant(&expr);
713
    assert_eq!(result, None);
714
}
715

            
716
#[test]
717
fn eval_const_nested_ref() {
718
    let expr = Expression::Sum(vec![
719
        Expression::Constant(Constant::Int(1)),
720
        Expression::And(vec![
721
            Expression::Constant(Constant::Bool(true)),
722
            Expression::Reference(Name::UserName(String::from("a"))),
723
        ]),
724
    ]);
725
    let result = eval_constant(&expr);
726
    assert_eq!(result, None);
727
}
728

            
729
#[test]
730
fn eval_const_eq_int() {
731
    let expr = Expression::Eq(
732
        Box::new(Expression::Constant(Constant::Int(1))),
733
        Box::new(Expression::Constant(Constant::Int(1))),
734
    );
735
    let result = eval_constant(&expr);
736
    assert_eq!(result, Some(Constant::Bool(true)));
737
}
738

            
739
#[test]
740
fn eval_const_eq_bool() {
741
    let expr = Expression::Eq(
742
        Box::new(Expression::Constant(Constant::Bool(true))),
743
        Box::new(Expression::Constant(Constant::Bool(true))),
744
    );
745
    let result = eval_constant(&expr);
746
    assert_eq!(result, Some(Constant::Bool(true)));
747
}
748

            
749
#[test]
750
fn eval_const_eq_mixed() {
751
    let expr = Expression::Eq(
752
        Box::new(Expression::Constant(Constant::Int(1))),
753
        Box::new(Expression::Constant(Constant::Bool(true))),
754
    );
755
    let result = eval_constant(&expr);
756
    assert_eq!(result, None);
757
}
758

            
759
#[test]
760
fn eval_const_sum_mixed() {
761
    let expr = Expression::Sum(vec![
762
        Expression::Constant(Constant::Int(1)),
763
        Expression::Constant(Constant::Bool(true)),
764
    ]);
765
    let result = eval_constant(&expr);
766
    assert_eq!(result, None);
767
}
768

            
769
#[test]
770
fn eval_const_sum_xyz() {
771
    let expr = Expression::And(vec![
772
        Expression::Eq(
773
            Box::new(Expression::Sum(vec![
774
                Expression::Reference(Name::UserName(String::from("x"))),
775
                Expression::Reference(Name::UserName(String::from("y"))),
776
                Expression::Reference(Name::UserName(String::from("z"))),
777
            ])),
778
            Box::new(Expression::Constant(Constant::Int(4))),
779
        ),
780
        Expression::Geq(
781
            Box::new(Expression::Reference(Name::UserName(String::from("x")))),
782
            Box::new(Expression::Reference(Name::UserName(String::from("y")))),
783
        ),
784
    ]);
785
    let result = eval_constant(&expr);
786
    assert_eq!(result, None);
787
}
788

            
789
#[test]
790
fn eval_const_or() {
791
    let expr = Expression::Or(vec![
792
        Expression::Constant(Constant::Bool(false)),
793
        Expression::Constant(Constant::Bool(false)),
794
    ]);
795
    let result = eval_constant(&expr);
796
    assert_eq!(result, Some(Constant::Bool(false)));
797
}