### Question:
PushdownNegationVisitor extends BaseVisitor { public static JexlNode applyDeMorgans(JexlNode root, boolean negateRoot) { if (root == null) { throw new IllegalArgumentException("root must not be null"); } if (root.jjtGetNumChildren() == 0) { throw new IllegalStateException("root must have at least one child"); } List<JexlNode> negatedChildren = new ArrayList<>(root.jjtGetNumChildren()); for (int i = 0; i < root.jjtGetNumChildren(); i++) { negatedChildren.add(JexlNodes.negate(root.jjtGetChild(i))); } JexlNode newRoot; if (root instanceof ASTAndNode) { newRoot = JexlNodeFactory.createOrNode(negatedChildren); } else if (root instanceof ASTOrNode) { newRoot = JexlNodeFactory.createAndNode(negatedChildren); } else { throw new IllegalArgumentException("root must be either an ASTAndNode or ASTOrNode"); } if (negateRoot) { newRoot = JexlNodes.negate(newRoot); } if (root.jjtGetParent() != null) { JexlNodes.swap(root.jjtGetParent(), root, newRoot); } return newRoot; }  static JexlNode pushdownNegations(JexlNode tree); @Override Object visit(ASTNotNode node, Object data); @Override Object visit(ASTOrNode node, Object data); @Override Object visit(ASTAndNode node, Object data); @Override Object visit(ASTNENode node, Object data); @Override Object visit(ASTNRNode node, Object data); static JexlNode applyDeMorgans(JexlNode root, boolean negateRoot);  }### Answer:
@Test(expected = IllegalArgumentException.class) public void testApplyDeMorgansNull() { PushdownNegationVisitor.applyDeMorgans(null, false); }
@Test(expected = IllegalStateException.class) public void testApplyDeMorgansNoChildren() { PushdownNegationVisitor.applyDeMorgans(new ASTAndNode(1), false); }
@Test(expected = IllegalArgumentException.class) public void testApplyDeMorgansNotAndOrNode() { JexlNode node = JexlNodeFactory.buildEQNode("field", "value"); PushdownNegationVisitor.applyDeMorgans(node, false); }
@Test public void testApplyDeMorgansNegateAndRoot() { JexlNode child1 = JexlNodeFactory.buildEQNode("f1", "v1"); JexlNode child2 = JexlNodeFactory.buildEQNode("f2", "v2"); List<JexlNode> children = new ArrayList<>(); children.add(child1); children.add(child2); JexlNode and = JexlNodeFactory.createUnwrappedAndNode(children); JexlNode result = PushdownNegationVisitor.applyDeMorgans(and, true); Assert.assertEquals("!((!(f1 == 'v1') || !(f2 == 'v2')))", JexlStringBuildingVisitor.buildQuery(result)); }
@Test public void testApplyDeMorgansNegateOrRoot() { JexlNode child1 = JexlNodeFactory.buildEQNode("f1", "v1"); JexlNode child2 = JexlNodeFactory.buildEQNode("f2", "v2"); List<JexlNode> children = new ArrayList<>(); children.add(child1); children.add(child2); JexlNode or = JexlNodeFactory.createUnwrappedOrNode(children); JexlNode result = PushdownNegationVisitor.applyDeMorgans(or, true); Assert.assertEquals("!((!(f1 == 'v1') && !(f2 == 'v2')))", JexlStringBuildingVisitor.buildQuery(result)); }