use super::*;
#[test]
fn test_parse_simple_dimacs() {
let input = b"c comment\np cnf 3 2\n1 -2 0\n2 3 0\n";
let formula = CnfFormula::from_dimacs(&input[..]).unwrap().0;
assert_eq!(formula.num_vars, 3);
assert_eq!(formula.clauses.len(), 2);
assert_eq!(formula.clauses[0].literals.len(), 2);
assert_eq!(formula.clauses[0].literals[0], Literal::pos(VarId(0)));
assert_eq!(formula.clauses[0].literals[1], Literal::neg(VarId(1)));
assert_eq!(formula.clauses[1].literals.len(), 2);
assert_eq!(formula.clauses[1].literals[0], Literal::pos(VarId(1)));
assert_eq!(formula.clauses[1].literals[1], Literal::pos(VarId(2)));
}
#[test]
fn test_parse_empty_formula() {
let input = b"p cnf 3 0\n";
let formula = CnfFormula::from_dimacs(&input[..]).unwrap().0;
assert_eq!(formula.num_vars, 3);
assert_eq!(formula.clauses.len(), 0);
}
#[test]
fn test_parse_multiline_clause() {
let input = b"p cnf 4 1\n1 2\n3 4 0\n";
let formula = CnfFormula::from_dimacs(&input[..]).unwrap().0;
assert_eq!(formula.clauses.len(), 1);
assert_eq!(formula.clauses[0].literals.len(), 4);
}
#[test]
fn test_parse_rejects_invalid_tokens() {
let input = b"p cnf 3 1\n1 NONE69 0\n";
let result = CnfFormula::from_dimacs(&input[..]);
assert!(result.is_err(), "should reject non-integer token NONE69");
assert!(result.unwrap_err().to_string().contains("NONE69"));
}
#[test]
fn test_parse_rejects_bare_minus() {
let input = b"p cnf 3 1\n1 2 - 0\n";
let result = CnfFormula::from_dimacs(&input[..]);
assert!(result.is_err(), "should reject bare minus sign");
}
#[test]
fn test_parse_reads_beyond_declared_clause_count() {
let input = b"p cnf 3 2\n1 -2 0\n2 3 0\n1 3 0\n";
let formula = CnfFormula::from_dimacs(&input[..]).unwrap().0;
assert_eq!(
formula.clauses.len(),
3,
"should read all clauses, not just declared 2"
);
}
#[test]
fn test_parse_stops_at_satlib_eof() {
let input = b"p cnf 3 10\n1 -2 0\n%\n0\nGARBAGE\n";
let formula = CnfFormula::from_dimacs(&input[..]).unwrap().0;
assert_eq!(formula.clauses.len(), 1, "should stop at % marker");
}
#[test]
fn test_parse_deduplicates_literals() {
let input = b"p cnf 6 1\n1 6 6 0\n";
let formula = CnfFormula::from_dimacs(&input[..]).unwrap().0;
assert_eq!(formula.clauses.len(), 1);
assert_eq!(
formula.clauses[0].literals.len(),
2,
"duplicate literal should be removed: {:?}",
formula.clauses[0].literals
);
}
#[test]
fn test_parse_removes_tautological_clause() {
let input = b"p cnf 5 2\n1 2 0\n5 -5 3 0\n";
let formula = CnfFormula::from_dimacs(&input[..]).unwrap().0;
assert_eq!(
formula.clauses.len(),
1,
"tautological clause (5 ∨ ¬5) should be dropped"
);
assert_eq!(formula.clauses[0].literals.len(), 2);
}
#[test]
fn a_bare_zero_is_the_empty_clause() {
let input = b"p cnf 2 2\n1 2 0\n0\n";
let formula = CnfFormula::from_dimacs(&input[..]).unwrap().0;
assert_eq!(formula.clauses.len(), 2);
assert!(
formula.clauses[1].literals.is_empty(),
"the bare `0` must survive as the empty clause: {:?}",
formula.clauses,
);
}
#[test]
fn two_zeros_in_a_row_close_a_clause_and_then_the_empty_one() {
let input = b"p cnf 2 1\n1 2 0 0\n";
let formula = CnfFormula::from_dimacs(&input[..]).unwrap().0;
assert_eq!(formula.clauses.len(), 2);
assert_eq!(formula.clauses[0].literals.len(), 2);
assert!(
formula.clauses[1].literals.is_empty(),
"the second `0` must close the empty clause: {:?}",
formula.clauses,
);
}
#[test]
fn a_final_clause_without_its_zero_is_sorted_and_deduplicated() {
let input = b"p cnf 3 1\n3 1 3\n";
let formula = CnfFormula::from_dimacs(&input[..]).unwrap().0;
assert_eq!(formula.clauses.len(), 1);
assert_eq!(
formula.clauses[0].literals,
vec![Literal::pos(VarId(0)), Literal::pos(VarId(2))],
);
}
#[test]
fn a_final_tautological_clause_without_its_zero_is_dropped() {
let input = b"p cnf 3 2\n1 2 0\n3 -3 1\n";
let formula = CnfFormula::from_dimacs(&input[..]).unwrap().0;
assert_eq!(
formula.clauses.len(),
1,
"an unterminated tautology is dropped like a terminated one: {:?}",
formula.clauses,
);
}
#[test]
fn test_parse_no_duplicate_vars_in_clause() {
let input = b"p cnf 6 3\n1 2 3 4 0\n-2 -3 4 5 0\n-4 -5 6 6 0\n";
let formula = CnfFormula::from_dimacs(&input[..]).unwrap().0;
for (i, clause) in formula.clauses.iter().enumerate() {
let mut vars: Vec<u32> = clause.literals.iter().map(|l| l.var.0).collect();
vars.sort();
let before = vars.len();
vars.dedup();
assert_eq!(
vars.len(),
before,
"clause {} has duplicate variables: {:?}",
i,
clause.literals
);
}
}