use ferroplan::{solve, Options, SolveError};
const DOM: &str = "(define (domain sw)
(:requirements :strips :constraints)
(:predicates (on) (off))
(:action flip-on :precondition (off) :effect (and (not (off)) (on)))
(:action flip-off :precondition (on) :effect (and (not (on)) (off))))";
const PROB_WITH_CONSTRAINT: &str = "(define (problem sw-1) (:domain sw)
(:init (off))
(:goal (on))
(:constraints (always (or (on) (off)))))";
const PROB_PLAIN: &str = "(define (problem sw-2) (:domain sw)
(:init (off))
(:goal (on)))";
#[test]
fn solve_rejects_trajectory_constraints_instead_of_ignoring_them() {
let err = solve(DOM, PROB_WITH_CONSTRAINT, &Options::default())
.expect_err("a (:constraints ...) block must be rejected, not silently dropped");
match err {
SolveError::Unsupported(msg) => {
assert!(
msg.contains(":constraints"),
"message should name the unsupported feature: {msg}"
);
}
other => panic!("expected SolveError::Unsupported, got {other:?}"),
}
}
#[test]
fn solve_still_works_without_constraints() {
let sol = solve(DOM, PROB_PLAIN, &Options::default()).expect("plain problem solves");
let plan = sol.plan.expect("a plan is found");
assert_eq!(plan.steps.len(), 1, "flip-on solves it in one step");
}
#[test]
fn cli_text_path_rejects_trajectory_constraints() {
let (out, code) = ferroplan::run_planner(DOM, PROB_WITH_CONSTRAINT, &Options::default(), false);
assert_eq!(code, 1, "constraint domain must exit non-zero:\n{out}");
assert!(
out.contains(":constraints"),
"output should explain the rejection:\n{out}"
);
}