diff --git a/src/main/java/org/variantsync/diffdetective/variation/diff/DiffNode.java b/src/main/java/org/variantsync/diffdetective/variation/diff/DiffNode.java index f0f05f13c..8ce5bfb8e 100644 --- a/src/main/java/org/variantsync/diffdetective/variation/diff/DiffNode.java +++ b/src/main/java/org/variantsync/diffdetective/variation/diff/DiffNode.java @@ -733,10 +733,14 @@ public static DiffNode fromID(int id, String label) { * Checks that the VariationDiff is in a valid state. * In particular, this method checks that all edges are well-formed (e.g., edges can be inconsistent because edges are double-linked). * This method also checks that a node with exactly one parent was edited, and that a node with exactly two parents was not edited. + * To check all children recursively, use {@link VariationDiff#assertConsistency}. * @see Assert#assertTrue * @throws AssertionError when an inconsistency is detected. */ public void assertConsistency() { + // check that the projections are valid (i.e., node type specific consistency checks) + diffType.forAllTimesOfExistence(time -> this.projection(time).assertConsistency()); + // check consistency of children lists and edges for (final DiffNode c : getAllChildren()) { Assert.assertTrue(isChild(c), () -> "Child " + c + " of " + this + " is neither a before nor an after child!"); @@ -760,6 +764,10 @@ public void assertConsistency() { if (pb != null && pa == null) { Assert.assertTrue(isRem()); } + // the root was not edited + if (pb == null && pa == null) { + Assert.assertTrue(isNon()); + } // a node with exactly two parents was not edited if (pb != null && pa != null) { Assert.assertTrue(isNon()); @@ -770,22 +778,6 @@ public void assertConsistency() { Assert.assertTrue(pb.isNon()); } } - - // Else and Elif nodes have an If or Elif as parent. - if (this.isElse() || this.isElif()) { - Time.forAll(time -> { - if (getParent(time) != null) { - Assert.assertTrue(getParent(time).isIf() || getParent(time).isElif(), time + " parent " + getParent(time) + " of " + this + " is neither IF nor ELIF!"); - } - }); - } - - // Only if and elif nodes have a formula - if (this.isIf() || this.isElif()) { - Assert.assertTrue(this.getFormula() != null, "If or elif without feature mapping!"); - } else { - Assert.assertTrue(this.getFormula() == null, "Node with type " + getNodeType() + " has a non null feature mapping"); - } } /** diff --git a/src/main/java/org/variantsync/diffdetective/variation/diff/Projection.java b/src/main/java/org/variantsync/diffdetective/variation/diff/Projection.java index 91352292d..760de0d4c 100644 --- a/src/main/java/org/variantsync/diffdetective/variation/diff/Projection.java +++ b/src/main/java/org/variantsync/diffdetective/variation/diff/Projection.java @@ -130,4 +130,9 @@ public Node getFormula() { public int getID() { return getBackingNode().getID(); } + + @Override + public String toString() { + return String.format("Projection(%s, %s)", time, getBackingNode()); + } }; diff --git a/src/main/java/org/variantsync/diffdetective/variation/tree/VariationNode.java b/src/main/java/org/variantsync/diffdetective/variation/tree/VariationNode.java index c3e8d1f39..cbe8f6b4b 100644 --- a/src/main/java/org/variantsync/diffdetective/variation/tree/VariationNode.java +++ b/src/main/java/org/variantsync/diffdetective/variation/tree/VariationNode.java @@ -487,26 +487,28 @@ public VariationTreeNode toVariationTree(final Map - *
  • if-chains are nested correctly, - *
  • the root is an {@link NodeType#IF} with the feature mapping {@code "true"}, - *
  • the feature mapping is {@code null} iff {@code isConditionalAnnotation} is {@code false} - * and - *
  • all edges are well-formed (e.g., edges can be inconsistent because edges are - * double-linked). - * - * - *

    Some invariants are not checked. These include - *

      - *
    • There should be no cycles and - *
    • {@link getID} should be unique in the whole variation tree. - *
    - * - * @see Assert#assertTrue - * @throws AssertionError when an inconsistency is detected. - */ + * Checks that this node satisfies some easy to check invariants. + * In particular, this method checks that + *
      + *
    • if-chains are nested correctly, + *
    • the root is an {@link NodeType#IF} with the feature mapping {@code "true"}, + *
    • the feature mapping is {@code null} iff {@code isConditionalAnnotation} is {@code false} + * and + *
    • all edges are well-formed (e.g., edges can be inconsistent because edges are + * double-linked). + *
    + * + *

    Some invariants are not checked. These include + *

      + *
    • There should be no cycles, + *
    • {@link getID} should be unique in the whole variation tree, and + *
    • children are not checked recursively. + *
    + * Use {@link VariationTree#assertConsistency} to check all children recursively. + * + * @see Assert#assertTrue + * @throws AssertionError when an inconsistency is detected. + */ public void assertConsistency() { // ELSE and ELIF nodes have an IF or ELIF as parent. if (isElse() || isElif()) { @@ -537,6 +539,12 @@ public void assertConsistency() { "The root has to have the feature mapping 'true'"); } + // check that there is at most one ELIF/ELSE + Assert.assertTrue( + getChildren().stream().filter(c -> c.isElif() || c.isElse()).count() <= 1, + "There is more than one ELIF/ELSE node." + ); + // check consistency of children lists and edges for (var child : getChildren()) { Assert.assertTrue( diff --git a/src/main/java/org/variantsync/diffdetective/variation/tree/VariationTree.java b/src/main/java/org/variantsync/diffdetective/variation/tree/VariationTree.java index 722744ed7..9920b3e6a 100644 --- a/src/main/java/org/variantsync/diffdetective/variation/tree/VariationTree.java +++ b/src/main/java/org/variantsync/diffdetective/variation/tree/VariationTree.java @@ -5,6 +5,7 @@ import org.variantsync.diffdetective.util.Assert; import org.variantsync.diffdetective.variation.DiffLinesLabel; import org.variantsync.diffdetective.variation.Label; +import org.variantsync.diffdetective.variation.NodeType; // For Javadoc import org.variantsync.diffdetective.variation.diff.DiffNode; import org.variantsync.diffdetective.variation.diff.VariationDiff; import org.variantsync.diffdetective.variation.diff.Projection; @@ -213,6 +214,17 @@ public String unparse() { return result.toString(); } + /** + * Checks whether this {@link VariationTree} is consistent. + * Throws an error if this {@link VariationTree} is inconsistent (e.g., if there are multiple + * {@link NodeType#ELSE} nodes). Has no side-effects otherwise. + * + * @see VariationNode#assertConsistency + */ + public void assertConsistency() { + forAllPreorder(VariationTreeNode::assertConsistency); + } + @Override public String toString() { return "variation tree from " + source;