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()); } }