package net.sf.jsqlparser.util.cnfexpression;
import static org.junit.Assert.*;
import org.junit.Test;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
/**
* this class is mainly used for testing whether we generate the
* correct CNF form of an expression tree. We use the name of
* variables that is reflected in the steps defined in the class.
* @author messfish
*
*/
public class CNFTest {
/**
* The purpose of this method is to check when there is a Not Operator
* at the root. Which means the root must be switched.
*
* Here is the expression tree:
*
* NOT
* |
* ( )
* |
* AND
* / \
* ( ) ( )
* | |
* OR OR
* / \ / \
* < = != >=
* / \ / \ / \ / \
* 1.2 2.3 3.5 4.6 1.1 2.5 8.0 7.2
*
* Here is the converted expression tree:
*
* AND
* / \
* AND ( )
* / \ |
* AND ( ) OR
* / \ | / \
* ( ) ( ) OR NOT NOT
* | | / \ | |
* OR OR NOT NOT = >=
* / \ / \ | | / \ / \
* NOT NOT NOT NOT = != 3.5 4.6 8.0 7.2
* | | | | / \ / \
* < != < >=
* / \ / \ / \ / \
* 1.2 2.3 1.1 2.5 1.2 2.3 8.0 7.2
*
*/
@Test
public void test1() throws Exception {
Expression expr = CCJSqlParserUtil.parseCondExpression(
"NOT ((1.2 < 2.3 OR 3.5 = 4.6) AND (1.1 <> 2.5 OR 8.0 >= 7.2))");
Expression expected = CCJSqlParserUtil.parseCondExpression(
"(NOT 1.2 < 2.3 OR NOT 1.1 <> 2.5) AND (NOT 1.2 < 2.3 OR NOT 8.0 >= 7.2) AND"
+ " (NOT 3.5 = 4.6 OR NOT 1.1 <> 2.5) AND (NOT 3.5 = 4.6 OR NOT 8.0 >= 7.2)");
Expression result = CNFConverter.convertToCNF(expr);
assertEquals(expected.toString(), result.toString());
}
/**
* The purpose is to test the double negation law. As you can
* see when you build the tree, there will be two Not Operators
* together on the line. It is there when we use the double negation law.
*
* Here is the expression tree:
* ( )
* |
* OR
* / \
* ( ) ( )
* | |
* NOT AND
* | / \
* ( ) LIKE =
* | / \ / \
* OR S.A "%%%" S.B "orz"
* / \
* NOT <
* | / \
* >= 3.3 4.5
* / \
* 1.1 2.3
*
* Here is the converted expression tree:
*
* AND
* / \
* AND ( )
* / \ |
* AND ( ) OR
* / \ | / \
* ( ) ( ) OR NOT =
* | | / \ | / \
* OR OR NOT LIKE < S.B "orz"
* / \ / \ | / \ / \
* >= LIKE >= = < S.A "%%%" 3.3 4.5
* / \ / \ / \ / \
* 1.1 2.3 S.A "%%%" 1.1 2.3 S.B "orz"
*
*/
@Test
public void test2() throws Exception {
Expression expr = CCJSqlParserUtil.parseCondExpression(
"((NOT (NOT 1.1 >= 2.3 OR 3.3 < 4.5)) OR "
+ "(S.A LIKE '\"%%%\"' AND S.B = '\"orz\"'))");
Expression expected = CCJSqlParserUtil.parseCondExpression(
"(1.1 >= 2.3 OR S.A LIKE '\"%%%\"') AND (1.1 >= 2.3 OR S.B = '\"orz\"')"
+ " AND (NOT 3.3 < 4.5 OR S.A LIKE '\"%%%\"') AND (NOT 3.3 < 4.5 OR S.B = '\"orz\"')");
Expression result = CNFConverter.convertToCNF(expr);
assertEquals(expected.toString(), result.toString());
}
/**
* This is the case when we test a more complex tree structure,
* Notice you could see the amount of line to build up the CNF tree.
* You could tell how complicated the CNF could be.
*
* OR
* / \
* ( ) ( )
* | |
* AND OR
* / \ / \
* >= <= ( ) NOT
* / \ / \ | |
* 7.0 8.0 9.0 10.0 AND OR
* / \ / \
* ( ) = != ( )
* | / \ / \ |
* AND 11.0 12.0 13.0 14.0 AND
* / \ / \
* < > = ( )
* / \ / \ / \ |
* 7.0 8.0 9.0 10.0 15.0 16.0 OR
* / \
* = >
* / \ / \
* 17.0 18.0 19.0 20.0
*
* Here is the converted expression tree:
*
* AND
* / \
* AND ( )
* / \ |
* AND ( ) part18
* / \ |
* AND ( ) part17
* / \ |
* AND ( ) part16
* / \ |
* AND ( ) part15
* / \ |
* AND ( ) part14
* / \ |
* AND ( ) part13
* / \ |
* AND ( ) part12
* / \ |
* AND ( ) part11
* / \ |
* AND ( ) part10
* / \ |
* AND ( ) part9
* / \ |
* AND ( ) part8
* / \ |
* AND ( ) part7
* / \ |
* AND ( ) part6
* / \ |
* AND ( ) part5
* / \ |
* AND ( ) part4
* / \ |
* ( ) ( ) part3
* | |
* part1 part2
*
* part1: OR
* / \
* OR NOT
* / \ |
* >= < !=
* / \ / \ / \
* 3.0 4.0 7.0 8.0 13.0 14.0
*
* part2: OR
* / \
* OR NOT
* / \ |
* OR NOT =
* / \ | / \
* >= < = 17.0 18.0
* / \ / \ / \
* 3.0 4.0 7.0 8.0 15.0 16.0
*
* part3: OR
* / \
* OR NOT
* / \ |
* OR NOT =
* / \ | / \
* >= < = 19.0 20.0
* / \ / \ / \
* 3.0 4.0 7.0 8.0 15.0 16.0
*
* part4: OR
* / \
* OR NOT
* / \ |
* >= < !=
* / \ / \ / \
* 3.0 4.0 9.0 10.0 13.0 14.0
*
* part5: OR
* / \
* OR NOT
* / \ |
* OR NOT =
* / \ | / \
* >= < = 17.0 18.0
* / \ / \ / \
* 3.0 4.0 9.0 10.0 15.0 16.0
*
* part6: OR
* / \
* OR NOT
* / \ |
* OR NOT =
* / \ | / \
* >= < = 19.0 20.0
* / \ / \ / \
* 3.0 4.0 9.0 10.0 15.0 16.0
*
* part7: OR
* / \
* OR NOT
* / \ |
* >= < !=
* / \ / \ / \
* 3.0 4.0 11.0 12.0 13.0 14.0
*
* part8: OR
* / \
* OR NOT
* / \ |
* OR NOT =
* / \ | / \
* >= < = 17.0 18.0
* / \ / \ / \
* 3.0 4.0 11.0 12.0 15.0 16.0
*
* part9: OR
* / \
* OR NOT
* / \ |
* OR NOT =
* / \ | / \
* >= < = 19.0 20.0
* / \ / \ / \
* 3.0 4.0 11.0 12.0 15.0 16.0
*
* part10: OR
* / \
* OR NOT
* / \ |
* >= < !=
* / \ / \ / \
* 5.0 6.0 7.0 8.0 13.0 14.0
*
* part11: OR
* / \
* OR NOT
* / \ |
* OR NOT =
* / \ | / \
* >= < = 17.0 18.0
* / \ / \ / \
* 5.0 6.0 7.0 8.0 15.0 16.0
*
* part12: OR
* / \
* OR NOT
* / \ |
* OR NOT =
* / \ | / \
* >= < = 19.0 20.0
* / \ / \ / \
* 5.0 6.0 7.0 8.0 15.0 16.0
*
* part13: OR
* / \
* OR NOT
* / \ |
* >= < !=
* / \ / \ / \
* 5.0 6.0 9.0 10.0 13.0 14.0
*
* part14: OR
* / \
* OR NOT
* / \ |
* OR NOT =
* / \ | / \
* >= < = 17.0 18.0
* / \ / \ / \
* 5.0 6.0 9.0 10.0 15.0 16.0
*
* part15: OR
* / \
* OR NOT
* / \ |
* OR NOT =
* / \ | / \
* >= < = 19.0 20.0
* / \ / \ / \
* 5.0 6.0 9.0 10.0 15.0 16.0
*
* part16: OR
* / \
* OR NOT
* / \ |
* >= < !=
* / \ / \ / \
* 5.0 6.0 11.0 12.0 13.0 14.0
*
* part17: OR
* / \
* OR NOT
* / \ |
* OR NOT =
* / \ | / \
* >= < = 17.0 18.0
* / \ / \ / \
* 5.0 6.0 11.0 12.0 15.0 16.0
*
* part18: OR
* / \
* OR NOT
* / \ |
* OR NOT =
* / \ | / \
* >= < = 19.0 20.0
* / \ / \ / \
* 5.0 6.0 11.0 12.0 15.0 16.0
*
*/
@Test
public void test3() throws Exception {
Expression expr = CCJSqlParserUtil.parseCondExpression(
"(3.0 >= 4.0 AND 5.0 <= 6.0) OR "
+ "(((7.0 < 8.0 AND 9.0 > 10.0) AND 11.0 = 12.0) OR "
+ "NOT (13.0 <> 14.0 OR (15.0 = 16.0 AND (17.0 = 18.0 OR 19.0 > 20.0))))");
Expression expected = CCJSqlParserUtil.parseCondExpression(
"(3.0 >= 4.0 OR 7.0 < 8.0 OR NOT 13.0 <> 14.0) AND "
+ "(3.0 >= 4.0 OR 7.0 < 8.0 OR NOT 15.0 = 16.0 OR NOT 17.0 = 18.0) AND "
+ "(3.0 >= 4.0 OR 7.0 < 8.0 OR NOT 15.0 = 16.0 OR NOT 19.0 > 20.0) AND "
+ "(3.0 >= 4.0 OR 9.0 > 10.0 OR NOT 13.0 <> 14.0) AND "
+ "(3.0 >= 4.0 OR 9.0 > 10.0 OR NOT 15.0 = 16.0 OR NOT 17.0 = 18.0) AND "
+ "(3.0 >= 4.0 OR 9.0 > 10.0 OR NOT 15.0 = 16.0 OR NOT 19.0 > 20.0) AND "
+ "(3.0 >= 4.0 OR 11.0 = 12.0 OR NOT 13.0 <> 14.0) AND "
+ "(3.0 >= 4.0 OR 11.0 = 12.0 OR NOT 15.0 = 16.0 OR NOT 17.0 = 18.0) AND "
+ "(3.0 >= 4.0 OR 11.0 = 12.0 OR NOT 15.0 = 16.0 OR NOT 19.0 > 20.0) AND "
+ "(5.0 <= 6.0 OR 7.0 < 8.0 OR NOT 13.0 <> 14.0) AND "
+ "(5.0 <= 6.0 OR 7.0 < 8.0 OR NOT 15.0 = 16.0 OR NOT 17.0 = 18.0) AND "
+ "(5.0 <= 6.0 OR 7.0 < 8.0 OR NOT 15.0 = 16.0 OR NOT 19.0 > 20.0) AND "
+ "(5.0 <= 6.0 OR 9.0 > 10.0 OR NOT 13.0 <> 14.0) AND "
+ "(5.0 <= 6.0 OR 9.0 > 10.0 OR NOT 15.0 = 16.0 OR NOT 17.0 = 18.0) AND "
+ "(5.0 <= 6.0 OR 9.0 > 10.0 OR NOT 15.0 = 16.0 OR NOT 19.0 > 20.0) AND "
+ "(5.0 <= 6.0 OR 11.0 = 12.0 OR NOT 13.0 <> 14.0) AND "
+ "(5.0 <= 6.0 OR 11.0 = 12.0 OR NOT 15.0 = 16.0 OR NOT 17.0 = 18.0) AND "
+ "(5.0 <= 6.0 OR 11.0 = 12.0 OR NOT 15.0 = 16.0 OR NOT 19.0 > 20.0)");
Expression result = CNFConverter.convertToCNF(expr);
assertEquals(expected.toString(), result.toString());
}
/**
* This is the case when we test a very simple tree structure that
* has neither AND operator or OR operator.
*
* Here is the expression tree:
*
* NOT
* |
* >
* / \
* S.D {d '2017-03-25'}
*
* Here is the converted expression tree:
*
* NOT
* |
* >
* / \
* S.D {d '2017-03-25'}
*
*/
@Test
public void test4() throws Exception {
Expression expr = CCJSqlParserUtil.parseCondExpression("NOT S.D > {d '2017-03-25'}");
Expression expected = CCJSqlParserUtil.parseCondExpression("NOT S.D > {d '2017-03-25'}");
Expression result = CNFConverter.convertToCNF(expr);
assertEquals(expected.toString(), result.toString());
}
/**
* This is the case when we test the tree that only contains AND
* operator without having an OR operator.
*
* Here is the original expression tree:
* NOT
* |
* ( )
* |
* OR
* / \
* ( ) ( )
* | |
* NOT OR
* | / \
* AND LIKE =
* / \ / \ / \
* > < S.C "%%" S.D {t '12:04:34'}
* / \ / \
* S.A 3.5 S.B 4
*
* Here is the converted expression tree:
*
* AND
* / \
* AND =
* / \ / \
* AND NOT LIKE S.D {t '12:04:34'}
* / \ / \
* > < S.C "%%"
* / \ / \
* S.A 3.5 S.B 4
*
*/
@Test
public void test5() throws Exception {
Expression expr = CCJSqlParserUtil.parseCondExpression(
"NOT ((NOT (S.A > 3.5 AND S.B < 4)) OR "
+ "(S.C LIKE '\"%%\"' OR S.D = {t '12:04:34'}))");
Expression expected = CCJSqlParserUtil.parseCondExpression(
"S.A > 3.5 AND S.B < 4 AND S.C NOT LIKE '\"%%\"' "
+ "AND NOT S.D = {t '12:04:34'}");
Expression result = CNFConverter.convertToCNF(expr);
assertEquals(expected.toString(), result.toString());
}
}