/* * SPDX-FileCopyrightText: 2023 The Refinery Authors * * SPDX-License-Identifier: EPL-2.0 */ package tools.refinery.store.query.dnf; import org.junit.jupiter.api.Test; import tools.refinery.store.query.InvalidQueryException; import tools.refinery.store.query.term.NodeVariable; import tools.refinery.store.query.term.ParameterDirection; import tools.refinery.store.query.term.Variable; import tools.refinery.store.query.view.AnySymbolView; import tools.refinery.store.query.view.KeyOnlyView; import tools.refinery.store.representation.Symbol; import java.util.List; import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.jupiter.api.Assertions.assertThrows; import static tools.refinery.store.query.literal.Literals.not; import static tools.refinery.store.query.tests.QueryMatchers.structurallyEqualTo; class TopologicalSortTest { private static final Symbol friend = Symbol.of("friend", 2); private static final AnySymbolView friendView = new KeyOnlyView<>(friend); private static final Dnf example = Dnf.of("example", builder -> { var a = builder.parameter("a", ParameterDirection.IN); var b = builder.parameter("b", ParameterDirection.IN); var c = builder.parameter("c", ParameterDirection.OUT); var d = builder.parameter("d", ParameterDirection.OUT); builder.clause( friendView.call(a, b), friendView.call(b, c), friendView.call(c, d) ); }); private static final NodeVariable p = Variable.of("p"); private static final NodeVariable q = Variable.of("q"); private static final NodeVariable r = Variable.of("r"); private static final NodeVariable s = Variable.of("s"); private static final NodeVariable t = Variable.of("t"); @Test void topologicalSortTest() { var actual = Dnf.builder("Actual") .parameter(p, ParameterDirection.IN) .parameter(q, ParameterDirection.OUT) .clause( not(friendView.call(p, q)), example.call(p, q, r, s), example.call(r, t, q, s), friendView.call(r, t) ) .build(); assertThat(actual, structurallyEqualTo( List.of( new SymbolicParameter(p, ParameterDirection.IN), new SymbolicParameter(q, ParameterDirection.OUT) ), List.of( List.of( friendView.call(r, t), example.call(r, t, q, s), not(friendView.call(p, q)), example.call(p, q, r, s) ) ) )); } @Test void missingInputTest() { var builder = Dnf.builder("Actual") .parameter(p, ParameterDirection.OUT) .parameter(q, ParameterDirection.OUT) .clause( not(friendView.call(p, q)), example.call(p, q, r, s), example.call(r, t, q, s), friendView.call(r, t) ); assertThrows(InvalidQueryException.class, builder::build); } @Test void missingVariableTest() { var builder = Dnf.builder("Actual") .parameter(p, ParameterDirection.IN) .parameter(q, ParameterDirection.OUT) .clause( not(friendView.call(p, q)), example.call(p, q, r, s), example.call(r, t, q, s) ); assertThrows(InvalidQueryException.class, builder::build); } @Test void circularDependencyTest() { var builder = Dnf.builder("Actual") .parameter(p, ParameterDirection.IN) .parameter(q, ParameterDirection.OUT) .clause( not(friendView.call(p, q)), example.call(p, q, r, s), example.call(r, t, q, s), example.call(p, q, r, t) ); assertThrows(InvalidQueryException.class, builder::build); } }