/* Protocol Definition Language Copyright (C) 2003-2006 Marcus Andersson This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package net.sf.nmedit.jpdl2.test; import java.io.StringReader; import net.sf.nmedit.jpdl2.PDLException; import net.sf.nmedit.jpdl2.PDLMessage; import net.sf.nmedit.jpdl2.PDLPacket; import net.sf.nmedit.jpdl2.PDLPacketParser; import net.sf.nmedit.jpdl2.dom.PDLDocument; import net.sf.nmedit.jpdl2.dom.PDLItemType; import net.sf.nmedit.jpdl2.format.PDL2Parser; import net.sf.nmedit.jpdl2.stream.BitStream; import org.junit.Assert; import org.junit.Test; public class PDLParseTests { public PDLDocument parse(String src) throws PDLException { PDL2Parser parser = new PDL2Parser(new StringReader(src)); parser.parse(); return parser.getDocument(); } public void test(String src) throws PDLException { // test parsing PDLDocument doc = parse(src); // generate src from DOM /* StringBuilder s = new StringBuilder(); PDLWriter w = new PDLWriter(s); w.setHeaderCommentEnabled(false); w.append(doc); String domSrc = s.toString(); src = normalizePDLSource(src); domSrc = normalizePDLSource(domSrc); if (!src.equals(domSrc)) { System.err.println("src: (normalized)\n"+src); System.err.println("gen: (normalized)\n"+domSrc); throw new RuntimeException("could not generate equivalent PDL source"); }*/ } private String normalizePDLSource(String src) { StringBuilder s = new StringBuilder(); for (int i=0;i<src.length();i++) { char c = src.charAt(i); switch (c) { case ' ': case '\n': case '\r': case '\t': case '(': case ')': break; default: s.append(c); } } return s.toString(); } // ************************************************************************************ // packet declarations // ************************************************************************************ @Test // empty file public void emptyFile() throws PDLException { test(""); } @Test // empty packet declaration public void emptyPacket() throws PDLException { test("Packet := ;"); } @Test(expected=PDLException.class) // packet with zero-padding public void packetWithZeroPadding() throws PDLException { test("Packet % 0 := ;"); } @Test // packet declaration without padding public void packetWithoutPadding() throws PDLException { test("Packet := ;"); } @Test(expected=PDLException.class) // packet exists public void packetExistsError() throws PDLException { test("Packet := ; Packet := ; "); } // ************************************************************************************ // packet references // ************************************************************************************ @Test // packet reference public void packetReference() throws PDLException { test("A := B$binding ; B := ;"); } @Test(expected=PDLException.class) // referenced packet missing public void referencedPacketMissing() throws PDLException { test("A := B$binding ;"); } @Test(expected=PDLException.class) // infinite recursion public void infiniteRecursion() throws PDLException { test("A := B$binding ; B := A$binding ;"); } @Test() // conditional recursion public void conditionalRecursion() throws PDLException { test("A := B$binding ; B := v:8 if (v == 0) A$binding ;"); } // ************************************************************************************ // number parsing // ************************************************************************************ @Test // number parsing: decimal public void decimalNumber() throws PDLException { test("Packet := 0:8 1:8 2:8 3:8 4:8 5:8 6:8 7:8 8:8 9:8 10:8 11:8 9876:32;"); } @Test(expected=PDLException.class) // decimal number public void invalidDecimalNumber() throws PDLException { test("Packet := 00002:8;"); } @Test // hexadecimal number public void hexadecimalNumber() throws PDLException { test("Packet := 0x01234567:32 0x89:32 0xabcdef:32 0xABCDEF:32;"); } @Test(expected=PDLException.class) // hexadecimal number with more than 8 digits public void toolargeHexadecimalNumber() throws PDLException { test("Packet := 0x01234567abcdef:32;"); } @Test // 32bit dual number public void dualNumber() throws PDLException { test("Packet := 10001000100010001000100010001000d:32;"); } @Test(expected=NumberFormatException.class) // 33bit dual number, leading 1 public void _33bitDualNumber1() throws PDLException { test("Packet := 110001000100010001000100010001000d:32;"); } @Test(expected=NumberFormatException.class) // 33bit dual number, leading 0 public void _33bitDualNumber0() throws PDLException { test("Packet := 010001000100010001000100010001000d:32;"); } // ************************************************************************************ // variables // ************************************************************************************ @Test // variable public void variable() throws PDLException { test("Packet := variable:8;"); } @Test(expected=PDLException.class) // variable with more than 32 bits public void variableWithMoreThan32Bits() throws PDLException { test("Packet := variable:33;"); } // ************************************************************************************ // variable lists // ************************************************************************************ @Test // variable-list with constant multiplicity public void variableListWithConstantMultiplicity() throws PDLException { test("Packet := 4*variable:8;"); } @Test // variable-list with variable multiplicity public void variableListWithVariableMultiplicity() throws PDLException { test("Packet := m:8 m*variable:8;"); } @Test(expected=PDLException.class) // constant with more than 32 bits public void constantWithMoreThan32Bits() throws PDLException { test("Packet := 3:33;"); } @Test(expected=PDLException.class) // big constant public void bigConstant() throws PDLException { test("Packet := 0xFF:1;"); } // ************************************************************************************ // labels // ************************************************************************************ @Test // label public void label() throws PDLException { test("Packet := @label;"); } // ************************************************************************************ // constants // ************************************************************************************ @Test // constant public void constant() throws PDLException { test("Packet := 0:8;"); } /* @Test(expected=PDLException.class) // variable referenced before assignment public void constant_variableReferencedBeforeAssignment() throws PDLException { test("Packet := v * 0:8 v:8;"); }*/ // ************************************************************************************ // names // ************************************************************************************ @Test(expected=PDLException.class) // variable / label with same name public void nameAlreadyInUse() throws PDLException { test("Packet := v:8 @v;"); } // ************************************************************************************ // message id // ************************************************************************************ @Test // packet with message id public void messageId() throws PDLException { test("Packet := messageId(\"themessageid\");"); } // ************************************************************************************ // anonym implicit variable // ************************************************************************************ @Test public void anonymVarTest() throws PDLException { int a = 1; int b = 1; int c = (((a&0xF)<<4) | (b&0xF)); Assert.assertTrue(isConditionTrue("anonym == c", "%anonym:8=(((a&0xF)<<4)|(b&0xF))", a, b, c)); Assert.assertFalse(isConditionTrue("anonym != c", "%anonym:8=(((a&0xF)<<4)|(b&0xF))", a, b, c)); } // ************************************************************************************ // mutual exclusion // ************************************************************************************ @Test(expected=PDLException.class) public void mutualExclusionNeverReached1() throws PDLException { test("Packet := (a:7 | b:8);"); } @Test(expected=PDLException.class) public void mutualExclusionNeverReached2() throws PDLException { test("Packet := (a:7 | 1:8);"); } @Test public void mutualExclusionReached1() throws PDLException { test("Packet := (b:8 | a:7);"); } @Test public void mutualExclusionReached2() throws PDLException { test("Packet := (1:8 | a:7);"); } @Test public void mutualExclusionConstantBeforeVariableOfSameSize() throws PDLException { test("Packet := (1:8 | a:8);"); } @Test(expected=PDLException.class) public void mutualExclusionConstantAfterVariableOfSameSize() throws PDLException { test("Packet := (a:8|1:8);"); } /* * unreachable code tests */ @Test(expected=PDLException.class) public void unreachAbleCode1() throws PDLException { test("Packet := break v:8;"); } @Test(expected=PDLException.class) public void unreachAbleCode2() throws PDLException { test("Packet := fail v:8;"); } @Test(expected=PDLException.class) public void unreachAbleCode3() throws PDLException { test("Packet := {break} v:8;"); } @Test(expected=PDLException.class) public void unreachAbleCode4() throws PDLException { test("Packet := {fail} v:8;"); } @Test(expected=PDLException.class) public void unreachAbleCode5() throws PDLException { test("Packet := if(true) {break v:8};"); } @Test(expected=PDLException.class) public void unreachAbleCode6() throws PDLException { test("Packet := if(true) {fail v:8};"); } @Test(expected=PDLException.class) public void unreachAbleCode7() throws PDLException { test("Packet := switch(1) {default:{break v:8}};"); } @Test(expected=PDLException.class) public void unreachAbleCode8() throws PDLException { test("Packet := switch(1) {default:{fail v:8}};"); } @Test(expected=PDLException.class) public void unreachAbleCode9() throws PDLException { test("Packet := ?{break v:8};"); } @Test(expected=PDLException.class) public void unreachAbleCode10() throws PDLException { test("Packet := ?{fail v:8};"); } public void unreachAbleCodeNoError1() throws PDLException { test("Packet := if(true) {break} v:8;"); } public void unreachAbleCodeNoError2() throws PDLException { test("Packet := if(true) {fail} v:8;"); } public void unreachAbleCodeNoError3() throws PDLException { test("Packet := switch(1) {default:{break}} v:8;"); } public void unreachAbleCodeNoError4() throws PDLException { test("Packet := switch(1) {default:{fail}} v:8;"); } public void unreachAbleCodeNoError5() throws PDLException { test("Packet := ?break v:8;"); } public void unreachAbleCodeNoError6() throws PDLException { test("Packet := ?fail v:8;"); } /* * operator precedence: * operator | associativity * ------------------------------------------------------------ * + - unary plus, minus | right * ~ bitwise NOT | * ! boolean (logical) NOT | * (type) type cast | * ------------------------------------------------------------ * * / % multiplication, division, remainder | left * + - addition, substraction | * << signed bit shift left | * >> signed bit shift right | * >>> unsigned bit shift right | * < <= less than, less than or equal to | * > >= greater than, greater than or equal to | * == equal to | * != not equal to | * & bitwise AND | * & boolean (logical) AND | * ^ bitwise XOR | * ^ boolean (logical) XOR | * | bitwise OR | * | boolean (logical) OR | * ------------------------------------------------------------ */ public boolean isConditionTrue(String condition, int a, int b, int c) throws PDLException { return isConditionTrue(condition, "", a, b, c); } public boolean isConditionTrue(String condition, String extra, int a, int b, int c) throws PDLException { final String OK_RESULT = "OK"; String src = "start Packet; Packet := a:8 b:8 c:8 "+extra+" if("+condition+") { messageId(\""+OK_RESULT+"\") };"; PDL2Parser parser = new PDL2Parser(new StringReader(src)); try { parser.parse(); } catch (PDLException e) { //System.out.println("error parsing:\n"+src); throw e; } PDLDocument doc = parser.getDocument(); BitStream bs = new BitStream(); bs.append(a, 8); bs.append(b, 8); bs.append(c, 8); PDLPacketParser packetParser = new PDLPacketParser(doc); PDLMessage message = packetParser.parseMessage(bs); return OK_RESULT.equals(message.getMessageId()); } @Test(expected=PDLException.class) public void testConditionNoBooleanExpression1() throws PDLException { isConditionTrue("5", 0, 0, 0); } @Test(expected=PDLException.class) public void testConditionNoBooleanExpression2() throws PDLException { isConditionTrue("5<<2", 0, 0, 0); } @Test public void testBooleanExpr() throws PDLException { { int a = 3, b = 4, c = 5; Assert.assertTrue(isConditionTrue((a+(b*c))+"==(a+(b*c))", a, b, c)); Assert.assertTrue(isConditionTrue(((a+b)*c)+"!=(a+(b*c))", a, b, c)); Assert.assertTrue(isConditionTrue((a+(b*c))+"==(a+b*c)", a, b, c)); Assert.assertTrue(isConditionTrue(((a+b)*c)+"!=(a+b*c)", a, b, c));; } { int a = 2, b = 8, c = 2; Assert.assertTrue(isConditionTrue("(a+b/c)==(a+(b/c))", a, b, c)); Assert.assertTrue(isConditionTrue("(a+b/c)!=((a+b)/c)", a, b, c)); Assert.assertTrue(isConditionTrue("(b/c+a)!=((a+b)/c)", a, b, c)); } Assert.assertTrue(isConditionTrue("1<2", 0,0,0)); Assert.assertFalse(isConditionTrue("1>2", 0,0,0)); Assert.assertTrue(isConditionTrue("1<=2", 0,0,0)); Assert.assertFalse(isConditionTrue("1>=2", 0,0,0)); Assert.assertTrue(isConditionTrue("1<=1", 0,0,0)); Assert.assertTrue(isConditionTrue("1>=1", 0,0,0)); Assert.assertTrue(isConditionTrue("1==1", 0,0,0)); Assert.assertFalse(isConditionTrue("1==2", 0,0,0)); Assert.assertTrue(isConditionTrue("1!=2", 0,0,0)); Assert.assertFalse(isConditionTrue("1!=1", 0,0,0)); Assert.assertTrue(isConditionTrue("-1==-1", 0,0,0)); Assert.assertTrue(isConditionTrue("1!=-1", 0,0,0)); Assert.assertTrue(isConditionTrue("0xFfFfFfFf==(~0)", 0,0,0)); } @Test public void testPrec() throws PDLException { int a = 3, b = 4, c = 5; Assert.assertTrue(isConditionTrue((a*b+c)+"==a*b+c", a, b, c)); Assert.assertTrue(isConditionTrue((a<<b+c)+"==a<<b+c", a, b, c)); Assert.assertTrue(isConditionTrue((c+a<<b)+"==c+a<<b", a, b, c)); Assert.assertTrue(isConditionTrue((a&b|c)+"==a&b|c", a, b, c)); } /** * inline packets */ @Test public void testInlinePacketRef() throws PDLException { String pdl = "start Start; Start:= a:8 b:8 Inline$$ ; Inline:= @lblEnd %inline:8=(1);"; PDL2Parser parser = new PDL2Parser(new StringReader(pdl)); parser.parse(); PDLDocument doc = parser.getDocument(); PDLPacketParser pp = new PDLPacketParser(doc); BitStream bs = new BitStream(); bs.append(0, 8); // a bs.append(0, 8); // b PDLPacket packet = pp.parse(bs); Assert.assertTrue("if defined: anonym variable", packet.getAllVariables().contains("inline")); Assert.assertTrue("anonym variable value", packet.getVariable("inline")==1); } /** * String def */ @Test public void testStringDef() throws PDLException { String pdl = "start Start; Start:= a:8 string:=\"TEXT\";"; PDL2Parser parser = new PDL2Parser(new StringReader(pdl)); parser.parse(); PDLDocument doc = parser.getDocument(); PDLPacketParser pp = new PDLPacketParser(doc); BitStream bs = new BitStream(); bs.append(0, 8); // a PDLPacket packet = pp.parse(bs); Assert.assertTrue("if defined: string", packet.getAllStrings().contains("string")); Assert.assertTrue("string value", "TEXT".equals(packet.getString("string"))); } public static String generateCodeForItem(PDLItemType type) { switch (type) { case AnonymousVariable: return "%anonym=(4)"; case Block: return "{}"; case Choice: return "(v:7 | 0x1:1)"; case Conditional: return "if (true) fail"; case Constant: return "3*0xF:8"; //case default: throw new InternalError(); } } }