diff --git a/lib/jtestdataaccessor/.antlr-eclipse b/lib/jtestdataaccessor/.antlr-eclipse new file mode 100644 index 0000000..3970aea --- /dev/null +++ b/lib/jtestdataaccessor/.antlr-eclipse @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/jtestdataaccessor/.classpath b/lib/jtestdataaccessor/.classpath new file mode 100644 index 0000000..2f2d66d --- /dev/null +++ b/lib/jtestdataaccessor/.classpath @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/lib/jtestdataaccessor/.project b/lib/jtestdataaccessor/.project new file mode 100644 index 0000000..e4e0d52 --- /dev/null +++ b/lib/jtestdataaccessor/.project @@ -0,0 +1,39 @@ + + + jtestdataaccessor + + + + + + org.antlr.eclipse.core.antlrbuilder + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.maven.ide.eclipse.maven2Builder + + + + + org.antlr.eclipse.core.warningcleanerbuilder + + + + + org.antlr.eclipse.core.smapbuilder + + + + + + org.antlr.eclipse.core.antlrnature + org.eclipse.jdt.core.javanature + org.maven.ide.eclipse.maven2Nature + + diff --git a/lib/jtestdataaccessor/COPYING b/lib/jtestdataaccessor/COPYING new file mode 100644 index 0000000..d511905 --- /dev/null +++ b/lib/jtestdataaccessor/COPYING @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + 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., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/lib/jtestdataaccessor/README b/lib/jtestdataaccessor/README new file mode 100644 index 0000000..416f14f --- /dev/null +++ b/lib/jtestdataaccessor/README @@ -0,0 +1,96 @@ +jtestdataaccessor +================= + +jtestdataaccessor - provide access to test data in unit tests. + +Copyright (C) 2006-2007 Manfred Stock + +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., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + +Installation +************ +Prerequisites: + o Java 1.5 + o Apache Maven 2 [1] or AntLR >= 2.7.6 and JUnit >= 4.0 + +After installing the prerequisites, a simple call to +$ mvn install +in the jtestdataaccessor directory should compile, unit test and install the +jtestdataaccessor library into the local Maven repository under ~/.m2. + +To create a .jar from the project, +$ mvn package +can be used. The generated .jar file will be stored in the target/ directory. +Since the .jar does not include AntLR and JUnit, they need to be on the +classpath when using the library. This can be avoided by using +$ mvn assembly:assembly +which will create target/jtestdataaccessor-bin.jar which includes those two +libraries as well. + +Javadoc documentation (and more) can be created by +$ mvn site +which creates the target/site/ directory containing an overview of the project +as well as the Javadoc documentation and the cross-referenced source code. + + +Unfortunately, there might be a problem with the AntLR version used by the +Maven AntLR plugin [2] - if the unit tests fail (see below if Maven does not +even execute them because of missing dependencies), this is most likely the +case. A workaround until the real problem is fixed is to modify the file +~/.m2/repository/org/apache/maven/plugins/maven-antlr-plugin/2.0-beta-1/maven-antlr-plugin-2.0-beta-1.pom +(or similar, if the problem persists in future releases after adapting the +pom.xml file to use such a release) by changing the AntLR dependency of groupId += antlr, artifactId = antlrall to groupId = antlr, artifactId = antlr and +version = 2.7.7 - after calling +$ mvn clean +to cleanup the generated and compiled sources, +$ mvn install +should succeed. + +The other problem is the missing support for Junit 4 in the current surefire +plugin, so the unit tests might not be executable at all. This can be solved by +adding the settings from [3] in ~/.m2/settings.xml - when doing so, the '...' +need to be replaced by and , respectively. Now +$ mvn -Papache install +should finally succeed (-Papache should be required only once, and the snapshot +will be updated periodically afterwards). + + +Usage +***** +To use the library, a depedency in the pom.xml of the project which looks like + + ch.ethz.infsec.jtestdataaccessor + jtestdataaccessor + 1.0-SNAPSHOT + test + +can be used. The library is then added to the classpath during unit testing and +may therefore be used in those tests. Some examples of the usage may be found +in the src/test/ subtree. + + +References +********** +[1] Apache Maven. + http://maven.apache.org/ +[2] Maven AntLR Plugin + http://maven.apache.org/plugins/maven-antlr-plugin/ +[3] Maven Snapshot Guide. + http://maven.apache.org/guides/development/guide-plugin-snapshot-repositories.html + + +$Id$ diff --git a/lib/jtestdataaccessor/pom.xml b/lib/jtestdataaccessor/pom.xml new file mode 100644 index 0000000..b68e204 --- /dev/null +++ b/lib/jtestdataaccessor/pom.xml @@ -0,0 +1,103 @@ + + + 4.0.0 + ch.ethz.infsec.jtestdataaccessor + jtestdataaccessor + JTestdataAccessor + 1.0-SNAPSHOT + 2006 + Library to provide access to testdata. + + Information Security Group, ETH Zurich + http://www.infsec.ethz.ch/ + + + + Manfred Stock + mstock + mstock@ethz.ch + +1 + + + + + + maven-compiler-plugin + + 1.5 + 1.5 + + + + maven-antlr-plugin + + + + generate + + + + + lp.g + + + + maven-assembly-plugin + + jtestdataaccessor + + src/assemble/bin.xml + src/assemble/src.xml + + + + + maven-surefire-plugin + 2.3-SNAPSHOT + + + + + + junit + junit + 4.1 + + + antlr + antlr + 2.7.7 + + + + + + org.apache.maven.plugins + maven-antlr-plugin + + lp.g + + + + org.apache.maven.plugins + maven-surefire-report-plugin + + + org.apache.maven.plugins + maven-javadoc-plugin + + 1.5 + + + + org.apache.maven.plugins + maven-jxr-plugin + + + + + scm:svn:https://svn.infsec.ethz.ch/infsec/trunk/teaching/theses/semesterarbeiten/2006_mstock_junit/jtestdataaccessor + https://svn.infsec.ethz.ch/viewsvn/infsec/trunk/teaching/theses/semesterarbeiten/2006_mstock_junit + + diff --git a/lib/jtestdataaccessor/src/assemble/bin.xml b/lib/jtestdataaccessor/src/assemble/bin.xml new file mode 100644 index 0000000..09aeff3 --- /dev/null +++ b/lib/jtestdataaccessor/src/assemble/bin.xml @@ -0,0 +1,20 @@ + + bin + + jar + + false + + + target/classes + / + + + + + / + true + runtime + + + \ No newline at end of file diff --git a/lib/jtestdataaccessor/src/assemble/src.xml b/lib/jtestdataaccessor/src/assemble/src.xml new file mode 100644 index 0000000..bd24672 --- /dev/null +++ b/lib/jtestdataaccessor/src/assemble/src.xml @@ -0,0 +1,34 @@ + + src + + tar.gz + tar.bz2 + zip + + + + + README* + LICENSE* + NOTICE* + pom.xml + build.xml + .project + .classpath + + + + + BigBattleship + + 755 + + + src + + + target/site + /doc + + + \ No newline at end of file diff --git a/lib/jtestdataaccessor/src/main/antlr/lp.g b/lib/jtestdataaccessor/src/main/antlr/lp.g new file mode 100644 index 0000000..b25183a --- /dev/null +++ b/lib/jtestdataaccessor/src/main/antlr/lp.g @@ -0,0 +1,358 @@ +header { + package ch.ethz.infsec.jtestdataaccessor.parser; + import ch.ethz.infsec.jtestdataaccessor.*; + import ch.ethz.infsec.jtestdataaccessor.nodes.*; + import java.util.*; +} + +/** + * Parser for test data. + */ +class TestdataParser extends Parser; + +{ + /* Root of tree with tests */ + private TestData testdata; + + /* Name of the function whose entry is currently parsed */ + private String currentFunctionName; + + /* Function which is currently parsed */ + private FunctionUnderTest cfut; + + /* Current testcase */ + private TestCase ctest; + + /* Parser currently in the scope of a function? */ + boolean fscope = true; + + /** + * Set the root of the tree where the testdata shall be written to + */ + public void setTestdata(TestData td){ + testdata = td; + } + + /** + * Identifiers which are used in the file with testdata. + */ + private enum ident { + RESULTTYPE, INPUTTYPES, SETUP, TEARDOWN, INPUT, RESULT, CHECKER, COMMENT + }; +} + +/* Root of the parser */ +startRule throws TestDataParseException: + ( sectionlist ) +; + +/* Section head with a name (which is a function) */ +section returns [String value=""]: + (LBRAK id:IDENTIFIER RBRAK) + { + value = id.getText(); + } +; + +/* A list of sections which contain definitions or testcase specifications */ +sectionlist throws TestDataParseException + { + String fname = null; + } + : + ( fname=section + { + /* Setup target of parsed data */ + currentFunctionName = fname; + cfut = new FunctionUnderTest(currentFunctionName); + testdata.addTest(cfut); + } + ( definition | test )* ( sectionlist )?) +; + +/* A definition, such as setup = ...; */ +definition throws TestDataParseException + { + List vl = null; + ident cident = null; + } + : + ( (cident=ident EQUALS vl=valuelist) ) + { + if(cident != null && vl != null && vl.size() > 0){ + if(fscope){ + /* Current scope is a function */ + switch(cident){ + case RESULTTYPE: + if(vl.size() == 1 && vl.get(0) instanceof Type){ + cfut.setResultType((Type)vl.get(0)); + }else{ + throw new TestDataParseException("resulttype only takes one type argument.", LT(0)); + } + break; + case INPUTTYPES: + for(Argument arg: vl){ + if(arg instanceof Type){ + Type type = (Type) arg; + cfut.addInputType(type); + }else{ + throw new TestDataParseException("inputtypes only takes type arguments.",LT(0)); + } + } + break; + case SETUP: + if(vl.size() == 1 && vl.get(0) instanceof Function){ + cfut.setSetup((Function) vl.get(0)); + }else{ + throw new TestDataParseException("setup requires a function argument.",LT(0)); + } + break; + case TEARDOWN: + if(vl.size() == 1 && vl.get(0) instanceof Function){ + cfut.setTeardown((Function) vl.get(0)); + }else{ + throw new TestDataParseException("teardown requires a function argument.",LT(0)); + } + break; + default: + throw new TestDataParseException("Identifier "+cident+" not allowed in function scope.", LT(0)); + } + }else{ + /* Current scope is a testcase */ + switch(cident){ + case INPUT: + for(Argument arg: vl){ + if(arg instanceof Value){ + ctest.addInput((Value)arg); + }else{ + throw new TestDataParseException("Inputs must be Values!", LT(0)); + } + } + break; + case RESULT: + if(vl.size() == 1 && vl.get(0) instanceof Value){ + ctest.setResult((Value)vl.get(0)); + }else if(vl.size() == 1 && vl.get(0) instanceof Type){ + ctest.setResult((Type)vl.get(0)); + }else{ + throw new TestDataParseException("Result must be a Value!",LT(0)); + } + break; + case CHECKER: + if(vl.size() == 1){ + if(vl.get(0) instanceof Function){ + ctest.setChecker(new ResultChecker((Function)vl.get(0),testdata)); + }else if(vl.get(0) instanceof ResultChecker){ + ctest.setChecker((ResultChecker)vl.get(0)); + } + } + break; + case COMMENT: + if(vl.size() == 1 && vl.get(0) instanceof SimpleValue){ + ctest.setComment(((SimpleValue)vl.get(0)).toString()); + }else{ + throw new TestDataParseException("comment requires a string argument.",LT(0)); + } + break; + default: + throw new TestDataParseException("Identifier "+cident+" not allowed in test scope.", LT(0)); + } + } + } + } +; + +/* An identifier/keyword such as setup */ +ident returns [ident value=null] + : + ( + RESULTTYPE { value=ident.RESULTTYPE; } + | INPUTTYPE { value = ident.INPUTTYPES; } + | SETUP { value = ident.SETUP; } + | TEARDOWN { value = ident.TEARDOWN; } + | INPUT { value = ident.INPUT; } + | RESULT { value = ident.RESULT; } + | CHECKER { value = ident.CHECKER; } + | COMMENT { value = ident.COMMENT; } + ) +; + +/* A testcase which is enclosed in {...} */ +test throws TestDataParseException + : + ( STEST { + ctest = new TestCase(); + cfut.addTest(ctest); + /* Current scope is test */ + fscope = false; + } (definition)+ { fscope = true; } ETEST ) +; + +/* A list of values, eg. "foo",10,true,"bar" */ +valuelist returns [Vector value=null] + { + ResultChecker.DefaultChecker c = null; + } + : + ( (id:IDENTIFIER ((l:LPAREN r:RPAREN) | (lb:LBRAK rb:RBRAK))? | s:STRING | (neg:DASH)? (i:INT | f:FLOAT) | tr:TRUE | fa:FALSE | ch:CHAR | c=checker) ( ( COMMA value=valuelist ) | SEMICOLON ) ) + { + if(value == null){ + value = new Vector(); + } + + /* Numbers should be negated */ + String negate = ""; + if(neg != null){ + negate = "-"; + } + + Argument a = null; + /* Create an object which represents the value */ + if(id != null){ + if(l != null && r != null){ + a = new Function(id.getText()); + }else if(lb != null && rb != null){ + a = new Type(id.getText()); + ((Type) a).setArray(true); + }else{ + a = new Type(id.getText()); + } + }else if(s != null){ + a = new SimpleValue(s.getText().replaceAll("\"","")); + }else if(i != null){ + a = new SimpleValue(new Integer(negate+i.getText())); + }else if(f != null){ + a = new SimpleValue(new Double(negate+f.getText())); + }else if(tr != null){ + a = new SimpleValue(new Boolean(tr.getText())); + }else if(fa != null){ + a = new SimpleValue(new Boolean(fa.getText())); + }else if(ch != null){ + a = new SimpleValue(new Character(ch.getText().charAt(1))); + }else if(c != null){ + a = new ResultChecker(c); + } + if(a != null){ + value.insertElementAt(a,0); + } + } +; + +/* Checker which is used to check the result */ +checker returns [ResultChecker.DefaultChecker value = null] + : (e:EQUALS | nt:FALSEC | t:TRUEC | nn:NOTNULL | n:NULL | ns:NOTSAME | s:SAME | f:FAIL | ne:NOTEQUAL) + { + if(e != null){ + value = ResultChecker.DefaultChecker.EQUALS; + }else if(nt != null){ + value = ResultChecker.DefaultChecker.FALSE; + }else if(t != null){ + value = ResultChecker.DefaultChecker.TRUE; + }else if(nn != null){ + value = ResultChecker.DefaultChecker.NOTNULL; + }else if(n != null){ + value = ResultChecker.DefaultChecker.NULL; + }else if(ns != null){ + value = ResultChecker.DefaultChecker.NOTSAME; + }else if(s != null){ + value = ResultChecker.DefaultChecker.SAME; + }else if(f != null){ + value = ResultChecker.DefaultChecker.FAIL; + }else if(ne != null){ + value = ResultChecker.DefaultChecker.NOTEQUAL; + } + } +; + + +/** + * The Lexer for testdata + */ +class TestdataLexer extends Lexer; + +/* Tokens which are keywords. The must not be used elsewhere in the file with testdata! */ +tokens { + RESULTTYPE = "resulttype"; + INPUTTYPE = "inputtypes"; + SETUP = "setup"; + TEARDOWN = "teardown"; + INPUT = "input"; + RESULT = "result"; + CHECKER = "checker"; + COMMENT = "comment"; + TRUE = "true"; + FALSE = "false"; + EQUALS = "EQUALS"; + FALSEC = "FALSE"; + TRUEC = "TRUE"; + NOTNULL = "NOTNULL"; + NULL = "NULL"; + NOTSAME = "NOTSAME"; + NOTEQUAL = "NOTEQUAL"; + SAME = "SAME"; + FAIL = "FAIL"; +} + +/* Alphanumeric identifiers */ +IDENTIFIER: ( ( 'a'..'z'|'A'..'Z' ) ('a'..'z'|'A'..'Z'|'0'..'9'|'-'|'_'|'.')* ); + +/* Strings */ +STRING: ('"' (~('"'))* '"' ); + +/* Single characters */ +CHAR: ('\''.'\''); + +/* Left ( */ +LPAREN: ( '(' ); + +/* Right ) */ +RPAREN: ( ')' ); + +/* Left [ */ +LBRAK: ( '[' ); + +/* Right ] */ +RBRAK: ( ']' ); + +/* Integers */ +protected +INT : ('0'..'9')+; + +/* Floats */ +protected +FLOAT: INT '.' INT; + +/* FLOAT or INT? */ +RANGE_OR_INT + : ( INT '.' ) => FLOAT { $setType(FLOAT); } + | INT { $setType(INT); } +; + +/* Start of a test */ +STEST: ( '{' ); + +/* End of a test */ +ETEST: ( '}' ); + +/* The equals sign */ +EQUALS: '='; + +/* A dash */ +DASH: '-'; + +/* A comma */ +COMMA: ','; + +/* A semicolon */ +SEMICOLON: ';'; + +/* Ignore newlines, whitespace and comments */ +NEWLINE + : ('\r' '\n' { newline(); } // DOS + | '\n' { newline(); } // UNIX + | ' ' + | '\t' + | '#' (~('\n' | '\r'))* + ) + { $setType(Token.SKIP); } //ignore these tokens +; diff --git a/lib/jtestdataaccessor/src/main/java/ch/ethz/infsec/jtestdataaccessor/FunctionUnderTest.java b/lib/jtestdataaccessor/src/main/java/ch/ethz/infsec/jtestdataaccessor/FunctionUnderTest.java new file mode 100644 index 0000000..2a6a03b --- /dev/null +++ b/lib/jtestdataaccessor/src/main/java/ch/ethz/infsec/jtestdataaccessor/FunctionUnderTest.java @@ -0,0 +1,217 @@ +package ch.ethz.infsec.jtestdataaccessor; + +import java.util.Iterator; +import java.util.List; +import java.util.Vector; + +import ch.ethz.infsec.jtestdataaccessor.nodes.Function; +import ch.ethz.infsec.jtestdataaccessor.nodes.Type; + +/** + * Contains the testcases, setup/teardown methods and types for a method which + * is to be tested. There will be several instances of this class if there is + * more than one section for the function in the file containing the testdata + * configuration. + * + * @author ms + * + */ +public class FunctionUnderTest { + + private Type resultType; + + private List inputTypes; + + private final String name; + + private List testCases; + + private Function teardown; + + private Function setup; + + private TestData testdata; + + /** + * Initialize the class. + * + * @param name + * of the function under test. + */ + public FunctionUnderTest(String name) { + this.name = name; + inputTypes = new Vector(); + testCases = new Vector(); + resultType = new Type("void"); + } + + /** + * Get a list with the input types. This will be used to select the correct + * method, especially in case of overloaded methods. + * + * @return the list of input types. + */ + public List getInputTypes() { + return inputTypes; + } + + /** + * Add another input type. + * + * @param inputType + * the additional type. + */ + public void addInputType(Type inputType) { + inputType.setTestData(testdata); + this.inputTypes.add(inputType); + } + + /** + * Get the name of the function. + * + * @return the name of the function. + */ + public String getName() { + return name; + } + + /** + * Get the type of the result. + * + * @return the type of the result. + */ + public Type getResultType() { + return resultType; + } + + /** + * Set the type of the result. + * + * @param resultType + * type of the result. + */ + public void setResultType(Type resultType) { + resultType.setTestData(testdata); + this.resultType = resultType; + } + + /** + * Set the method which will be called before executing the test. + * + * @param setup + * setup method. + */ + public void setSetup(Function setup) { + setup.setTestData(testdata); + this.setup = setup; + } + + /** + * Set the method which will be called after executing the test to do some + * cleanup. + * + * @param teardown + * teardown method. + */ + public void setTeardown(Function teardown) { + teardown.setTestData(testdata); + this.teardown = teardown; + } + + /** + * Get the setup method. + * + * @return the setup method. + */ + public Function getSetup() { + return setup; + } + + /** + * Get the teardown method. + * + * @return the teardown method. + */ + public Function getTeardown() { + return teardown; + } + + /** + * Get a list containing the testcases for this instance of the function. + * + * @return the testcases. + */ + public List getTests() { + return testCases; + } + + /** + * Add another test to the testcases. + * + * @param testCase + * another testcase. + */ + public void addTest(TestCase testCase) { + testCase.setTestData(testdata); + testCase.setFunctionUnderTest(this); + this.testCases.add(testCase); + } + + /** + * Get an array of classes containg the types of the parameters. + * + * @return an array with the parameter types. + * @throws ClassNotFoundException + */ + public Class[] getParams() throws ClassNotFoundException { + Class[] params = new Class[getInputTypes().size()]; + int i = 0; + for (Type arg : getInputTypes()) { + params[i] = arg.getTypeClass(); + i++; + } + return params; + } + + /** + * Set the object with testdata this instance belongs to. + * + * @param td + * the object this instance belongs to. + */ + public void setTestData(TestData td) { + this.testdata = td; + } + + @Override + public String toString() { + return toString(""); + } + + /** + * Pretty print some information on the function under test and the + * testcases. + * + * @param indent + * the indentation to use. + * @return the pretty string. + */ + public String toString(String indent) { + StringBuffer sb = new StringBuffer(); + sb.append(indent + name + "("); + for (Iterator inpt = inputTypes.iterator(); inpt.hasNext();) { + Type element = (Type) inpt.next(); + sb.append(element); + if (inpt.hasNext()) { + sb.append(", "); + } + } + sb.append(") :: " + resultType + "\n"); + sb.append(indent + " Setup: " + setup + "\n"); + sb.append(indent + " Teardown: " + teardown + "\n"); + for (TestCase testCase : testCases) { + sb.append(testCase.toString(indent + " ")); + } + return sb.toString(); + } +} \ No newline at end of file diff --git a/lib/jtestdataaccessor/src/main/java/ch/ethz/infsec/jtestdataaccessor/InvalidTestDataException.java b/lib/jtestdataaccessor/src/main/java/ch/ethz/infsec/jtestdataaccessor/InvalidTestDataException.java new file mode 100644 index 0000000..9a1205b --- /dev/null +++ b/lib/jtestdataaccessor/src/main/java/ch/ethz/infsec/jtestdataaccessor/InvalidTestDataException.java @@ -0,0 +1,19 @@ +package ch.ethz.infsec.jtestdataaccessor; + +/** + * Exception to be thrown when the provided testdata is not valid or does not + * contain enough information. + * + * @author ms + * + */ +public class InvalidTestDataException extends Exception { + /** + * A default serial version UID. + */ + private static final long serialVersionUID = 1L; + + public InvalidTestDataException(String msg) { + super(msg); + } +} diff --git a/lib/jtestdataaccessor/src/main/java/ch/ethz/infsec/jtestdataaccessor/TestCase.java b/lib/jtestdataaccessor/src/main/java/ch/ethz/infsec/jtestdataaccessor/TestCase.java new file mode 100644 index 0000000..f6501a6 --- /dev/null +++ b/lib/jtestdataaccessor/src/main/java/ch/ethz/infsec/jtestdataaccessor/TestCase.java @@ -0,0 +1,222 @@ +package ch.ethz.infsec.jtestdataaccessor; + +import java.util.List; +import java.util.Vector; + +import org.junit.Assert; +import static org.junit.Assert.fail; + +import ch.ethz.infsec.jtestdataaccessor.nodes.Argument; +import ch.ethz.infsec.jtestdataaccessor.nodes.ResultChecker; +import ch.ethz.infsec.jtestdataaccessor.nodes.Type; +import ch.ethz.infsec.jtestdataaccessor.nodes.Value; + +/** + * A testcase of a function. Contains inputvalues, the expected result, a + * comment and a checker for the result. + * + * @author ms + * + */ +public class TestCase { + + private String comment; + + private List inputs; + + private Value result; + + private ResultChecker checker; + + private TestData testdata; + + private FunctionUnderTest functionUnderTest; + + public TestCase() { + inputs = new Vector(); + } + + /** + * Get the checker of the result. + * + * @return the checker. + */ + public Argument getChecker() { + return checker; + } + + /** + * Set the checker for the result. + * + * @param checker + * the new checker. + */ + public void setChecker(ResultChecker checker) { + checker.setTestData(testdata); + checker.setTestCase(this); + this.checker = checker; + } + + /** + * Get the provided comment. + * + * @return the comment. + */ + public String getComment() { + return comment; + } + + /** + * Set a new comment. + * + * @param comment + * the new comment. + */ + public void setComment(String comment) { + this.comment = comment; + } + + /** + * Get the provided input values. + * + * @return the input values. + */ + public List getInputs() { + return inputs; + } + + /** + * Get the arguments which will be used to call the function under test. + * They may either be basic values or be returned by a user defined + * function. + * + * @return the arguments. + * @throws Throwable + */ + public Object[] getArguments() throws Throwable { + Object[] args = new Object[getInputs().size()]; + int i = 0; + for (Value input : getInputs()) { + args[i] = input.getValue(); + i++; + } + return args; + } + + /** + * Add another input value. + * + * @param input + * a new input value. + */ + public void addInput(Value input) { + input.setTestData(testdata); + this.inputs.add(input); + } + + /** + * Return the result value. + * + * @return the result value. + */ + public Value getResult() { + return result; + } + + /** + * Set a new result value. + * + * @param result + * a new result value. + */ + public void setResult(Value result) { + result.setTestData(testdata); + this.result = result; + } + + /** + * Check the result of a test run. + * + * @param actual + * the actual result. + * @param resulttype + * the type of the actual result. + * @throws Throwable + */ + public void checkResult(Object actual) throws Throwable { + if (checker != null) { + checker.check(actual); + } else { + if (getResult() instanceof Type) { + fail("A " + getResult().getValue() + + " exception was expected, but the result " + actual + + " is currently being checked. " + + (comment != null ? "Comment: "+comment : "")); + } else { + fail("No checker for this function provided. Please set a checker for this testcase."); + } + } + } + + @Override + public String toString() { + return toString(""); + } + + /** + * Pretty print a testcase. + * + * @param indent + * indentation to use. + * @return the pretty string. + */ + public String toString(String indent) { + StringBuffer sb = new StringBuffer(); + sb.append(indent + "Test:\n"); + sb.append(indent + " Comment: " + comment + "\n"); + sb.append(indent + " Arguments:\n"); + for (Argument arg : inputs) { + sb.append(indent + arg.toString(" ") + "\n"); + } + if (result != null) { + sb.append(indent + " Result:\n"); + sb.append(indent + result.toString(" ")); + sb.append("\n"); + } + if (checker != null) { + sb.append(indent + " Checker:\n"); + sb.append(indent + checker.toString(" ")); + sb.append("\n"); + } + return sb.toString(); + } + + /** + * Set the {@link TestData} this object belongs to. + * + * @param testdata + */ + public void setTestData(TestData testdata) { + this.testdata = testdata; + } + + /** + * Set the {@link FunctionUnderTest} this object belongs to. + * + * @param functionUnderTest + * this object belongs to. + */ + public void setFunctionUnderTest(FunctionUnderTest functionUnderTest) { + this.functionUnderTest = functionUnderTest; + } + + /** + * Get the {@link FunctionUnderTest} this object belongs to. + * + * @return the {@link FunctionUnderTest} this object belongs to. + */ + public FunctionUnderTest getFunctionUnderTest() { + return this.functionUnderTest; + } + +} \ No newline at end of file diff --git a/lib/jtestdataaccessor/src/main/java/ch/ethz/infsec/jtestdataaccessor/TestData.java b/lib/jtestdataaccessor/src/main/java/ch/ethz/infsec/jtestdataaccessor/TestData.java new file mode 100644 index 0000000..46a0ab6 --- /dev/null +++ b/lib/jtestdataaccessor/src/main/java/ch/ethz/infsec/jtestdataaccessor/TestData.java @@ -0,0 +1,87 @@ +package ch.ethz.infsec.jtestdataaccessor; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Vector; + +/** + * Root of the "tree" which contains the tests. + * + * @author ms + * + */ +public class TestData { + + private Map> functions; + + private TestDataAccessor testdataaccessor; + + public TestData() { + functions = new HashMap>(); + } + + /** + * Add testdata for another function to the testsuite. + * + * @param test + * testdata for the function. + */ + public void addTest(FunctionUnderTest test) { + List testlist = functions.get(test.getName()); + test.setTestData(this); + if (testlist != null) { + testlist.add(test); + } else { + testlist = new Vector(); + testlist.add(test); + functions.put(test.getName(), testlist); + } + } + + /** + * Get the tests of a given function. + * + * @param function + * the function. + * @return the tests. + */ + protected List getTests(String function) { + return functions.get(function); + } + + /** + * Pretty print the testdata. + */ + @Override + public String toString() { + StringBuffer sb = new StringBuffer(); + for (String fname : functions.keySet()) { + sb.append("Function under test: " + fname + "\n"); + for (FunctionUnderTest function : functions.get(fname)) { + sb.append(function.toString(" ")); + } + } + return sb.toString(); + } + + /** + * Set the {@link TestDataAccessor} these testdata belong to. + * + * @param testdataaccessor + * the testdataaccessor. + */ + public void setTestDataAccessor(TestDataAccessor testdataaccessor) { + this.testdataaccessor = testdataaccessor; + } + + /** + * Get the {@link TestDataAccessor} these testdata belong to. + * + * @return the testdataaccessor. + */ + public TestDataAccessor getTestDataAccessor() { + return testdataaccessor; + } + +} \ No newline at end of file diff --git a/lib/jtestdataaccessor/src/main/java/ch/ethz/infsec/jtestdataaccessor/TestDataAccessor.java b/lib/jtestdataaccessor/src/main/java/ch/ethz/infsec/jtestdataaccessor/TestDataAccessor.java new file mode 100644 index 0000000..7011c63 --- /dev/null +++ b/lib/jtestdataaccessor/src/main/java/ch/ethz/infsec/jtestdataaccessor/TestDataAccessor.java @@ -0,0 +1,118 @@ +package ch.ethz.infsec.jtestdataaccessor; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.util.List; +import antlr.RecognitionException; +import antlr.TokenStreamException; + +import ch.ethz.infsec.jtestdataaccessor.parser.TestdataLexer; +import ch.ethz.infsec.jtestdataaccessor.parser.TestdataParser; + +/** + * Provide fairly simple access to testdata. + * + * @author ms + * + */ +public class TestDataAccessor { + private File testdatafile; + + private TestData testdata; + + private TestDataUser testdatauser; + + /** + * Parse a given testdatafile. + * + * @param testdatafile + * the file containing testdata. + * @throws FileNotFoundException + * @throws RecognitionException + * @throws TokenStreamException + * @throws TestDataParseException + */ + public TestDataAccessor(String testdatafile) throws FileNotFoundException, + RecognitionException, TokenStreamException, TestDataParseException { + setTestdatafile(testdatafile); + } + + /** + * Return the absolute path to the file containing testdata. + * + * @return the path to the file with the testdata. + */ + public String getTestdatafile() { + return testdatafile.getAbsolutePath(); + } + + /** + * Set a new testdatafile. This results in parsing the file and creating a + * new internal tree with testdata. + * + * @param testdatafile + * the path to the file with testdata. + * @throws FileNotFoundException + * @throws RecognitionException + * @throws TokenStreamException + * @throws TestDataParseException + */ + public void setTestdatafile(String testdatafile) + throws FileNotFoundException, RecognitionException, + TokenStreamException, TestDataParseException { + this.testdatafile = new File(testdatafile); + TestdataLexer lexer = new TestdataLexer(new FileInputStream( + this.testdatafile)); + TestdataParser parser = new TestdataParser(lexer); + testdata = new TestData(); + testdata.setTestDataAccessor(this); + parser.setTestdata(testdata); + + parser.startRule(); + } + + /** + * Get the current user of this {@link TestDataAccessor}. + * + * @return the current user. + */ + public TestDataUser getTestDataUser() { + return testdatauser; + } + + /** + * Set a new user of this {@link TestDataAccessor}. + * + * @param testdatauser + * the new user. + */ + public void setTestDataUser(TestDataUser testdatauser) { + this.testdatauser = testdatauser; + } + + /** + * Get the tests of a certain function. + * + * @param function + * the name of the function. + * @return the tests. + */ + public List getTests(String function) { + return testdata.getTests(function); + } + + /** + * Pretty print the testdata. + * + * @return the pretty string. + */ + @Override + public String toString() { + StringBuffer sb = new StringBuffer(); + sb.append("Testdata of file " + testdatafile.getAbsolutePath() + ":\n"); + sb.append(testdata.toString()); + return sb.toString(); + } + +} diff --git a/lib/jtestdataaccessor/src/main/java/ch/ethz/infsec/jtestdataaccessor/TestDataParseException.java b/lib/jtestdataaccessor/src/main/java/ch/ethz/infsec/jtestdataaccessor/TestDataParseException.java new file mode 100644 index 0000000..a1ff6dd --- /dev/null +++ b/lib/jtestdataaccessor/src/main/java/ch/ethz/infsec/jtestdataaccessor/TestDataParseException.java @@ -0,0 +1,31 @@ +package ch.ethz.infsec.jtestdataaccessor; + +import antlr.Token; + +/** + * Thrown when an error occured during parsing of the testdatafile. + * + * @author ms + * + */ +public class TestDataParseException extends Exception { + + /** + * A default serial version uid. + */ + private static final long serialVersionUID = 1L; + + /** + * Create a new {@link TestDataParseException}; the message contains the + * current line where the error occurred. + * + * @param msg + * the user defined message. + * @param t + * the {@link Token} containing the line number. + */ + public TestDataParseException(String msg, Token t) { + super("line: " + t.getLine() + ": " + msg); + } + +} diff --git a/lib/jtestdataaccessor/src/main/java/ch/ethz/infsec/jtestdataaccessor/TestDataUser.java b/lib/jtestdataaccessor/src/main/java/ch/ethz/infsec/jtestdataaccessor/TestDataUser.java new file mode 100644 index 0000000..d391a8e --- /dev/null +++ b/lib/jtestdataaccessor/src/main/java/ch/ethz/infsec/jtestdataaccessor/TestDataUser.java @@ -0,0 +1,12 @@ +package ch.ethz.infsec.jtestdataaccessor; + +/** + * Marker interface to mark a class which uses {@link TestData}. + * + * @author ms + * + */ +public interface TestDataUser { + public String getClassUnderTest(); + public Object getTestObject(); +} diff --git a/lib/jtestdataaccessor/src/main/java/ch/ethz/infsec/jtestdataaccessor/TestHelper.java b/lib/jtestdataaccessor/src/main/java/ch/ethz/infsec/jtestdataaccessor/TestHelper.java new file mode 100644 index 0000000..135cffc --- /dev/null +++ b/lib/jtestdataaccessor/src/main/java/ch/ethz/infsec/jtestdataaccessor/TestHelper.java @@ -0,0 +1,128 @@ +package ch.ethz.infsec.jtestdataaccessor; + +import static org.junit.Assert.fail; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.List; + +import ch.ethz.infsec.jtestdataaccessor.nodes.Type; +import ch.ethz.infsec.jtestdataaccessor.oclexceptions.OclException; +import ch.ethz.infsec.jtestdataaccessor.oclexceptions.PreconditionFailedException; + +/** + * Provide some static helper functions which may be used in all tests. + */ +public class TestHelper { + + private String classUnderTest; + + private TestDataAccessor tda; + + private TestDataUser tduser; + + /** + * Create new {@link TestHelper} object. + * + * @param classUnderTest + * name of the class which is tested - must include the package + * the class is in. + * @param tda + * the {@link TestDataAccessor} which is used to access the + * testdata. + */ + public TestHelper(String classUnderTest, TestDataAccessor tda) { + this.classUnderTest = classUnderTest; + this.tda = tda; + } + + /** + * Invoke a method with the given parameters and arguments on the given + * object. + * + * @param aMethod + * name of the method to call. + * @param params + * parameter types of the method to call. + * @param args + * actual arguments for the call. + * @return the result of the call. + * @throws Throwable + * is thrown if something went wrong. + */ + private Object invoke(String aMethod, Class[] params, Object[] args) + throws Throwable { + try { + Class c = tduser.getClass(); + Method m = c.getDeclaredMethod("wrapped_" + aMethod, params); + return m.invoke(tduser, args); + } catch (InvocationTargetException e) { + throw e.getCause(); + } + } + + /** + * Execute tests of a given method. + * + * @param methodname + * of the method which is currently tested. + * @param tdu + * the user of the testdata, ie. the JUnit test calling this + * method. + * @throws Throwable + * if something went wrong. + */ + public void doTest(String methodname, TestDataUser tdu) throws Throwable { + tduser = tdu; + tda.setTestDataUser(tduser); + List tests = tda.getTests(methodname); + if (tests != null) { + // Execute tests for each section of the given function from the + // testdata file + for (FunctionUnderTest test : tests) { + Class[] params = test.getParams(); + try { + for (TestCase ctest : test.getTests()) { + Object[] args = ctest.getArguments(); + if (test.getSetup() != null) { + test.getSetup().call(); + } + Object result = null; + try { + result = invoke(methodname, params, args); + ctest.checkResult(result); + } catch (PreconditionFailedException pfe) { + System.err.println(pfe.getMessage() + + " <<< Precondition FAILURE!"); + } catch (OclException oe) { + String comment = ctest.getComment(); + fail((comment == null ? "" : comment + ": ") + + oe.getMessage()); + } catch (Exception e) { + // If there was an exception, this might have been + // intentionally - so check if the result was a type + // and the exception an instance of this type. + if (ctest.getResult() instanceof Type) { + Type exceptionType = (Type) ctest.getResult(); + if (!exceptionType.getTypeClass().isInstance(e)) { + throw e; + } + } else { + throw e; + } + } + if (test.getTeardown() != null) { + test.getTeardown().call(); + } + } + } catch (Exception e) { + e.printStackTrace(); + fail("Unexpected exception thrown: " + e.getMessage()); + } + } + } else { + System.err.println("No tests for method " + methodname + + " provided."); + } + } +} diff --git a/lib/jtestdataaccessor/src/main/java/ch/ethz/infsec/jtestdataaccessor/examples/IntArrayStore.java b/lib/jtestdataaccessor/src/main/java/ch/ethz/infsec/jtestdataaccessor/examples/IntArrayStore.java new file mode 100644 index 0000000..d102e80 --- /dev/null +++ b/lib/jtestdataaccessor/src/main/java/ch/ethz/infsec/jtestdataaccessor/examples/IntArrayStore.java @@ -0,0 +1,68 @@ +package ch.ethz.infsec.jtestdataaccessor.examples; + +public class IntArrayStore { + + private int[] array; + + public IntArrayStore(int[] array) { + this.array = array; + } + + /** + * Use bubblesort to sort an int[]. Taken from + * http://de.wikipedia.org/wiki/Bubblesort. + * + * @param array + * to sort + * @return the sorted array. + */ + public int[] getSorted() { + boolean sorted = true; + do { + sorted = true; + for (int i = 1; i < array.length; i++) { + if (array[i - 1] > array[i]) { + swap(i - 1, i); + sorted = false; + } + } + } while (!sorted); + return array; + } + + /** + * Use bubblesort to "wrongly" sort an int[]. + * + * @param array + * to sort + * @return the sorted array. + * @throws Exception + */ + public int[] getInvalidSorted() throws Exception { + boolean sorted = true; + do { + sorted = true; + for (int i = 1; i < array.length; i++) { + if (array[i - 1] < array[i]) { + swap(i - 1, i); + sorted = false; + } + } + } while (!sorted); + return array; + } + + /** + * Swap two elements of the array. + * + * @param i + * the first element. + * @param j + * the second element. + */ + private void swap(int i, int j) { + final int tmp = array[i]; + array[i] = array[j]; + array[j] = tmp; + } +} diff --git a/lib/jtestdataaccessor/src/main/java/ch/ethz/infsec/jtestdataaccessor/examples/IntMax.java b/lib/jtestdataaccessor/src/main/java/ch/ethz/infsec/jtestdataaccessor/examples/IntMax.java new file mode 100644 index 0000000..bc8ea75 --- /dev/null +++ b/lib/jtestdataaccessor/src/main/java/ch/ethz/infsec/jtestdataaccessor/examples/IntMax.java @@ -0,0 +1,16 @@ +package ch.ethz.infsec.jtestdataaccessor.examples; + +public class IntMax { + public static int max(int[] array) throws Exception { + int max = 0; + for(int i : array){ + if(i < 0){ + throw new Exception("Negative element detected."); + } + if(i > max){ + max = i; + } + } + return max; + } +} diff --git a/lib/jtestdataaccessor/src/main/java/ch/ethz/infsec/jtestdataaccessor/nodes/Argument.java b/lib/jtestdataaccessor/src/main/java/ch/ethz/infsec/jtestdataaccessor/nodes/Argument.java new file mode 100644 index 0000000..851a46c --- /dev/null +++ b/lib/jtestdataaccessor/src/main/java/ch/ethz/infsec/jtestdataaccessor/nodes/Argument.java @@ -0,0 +1,32 @@ +package ch.ethz.infsec.jtestdataaccessor.nodes; + +import ch.ethz.infsec.jtestdataaccessor.TestData; + +/** + * Represent a value which is found on the right hand side of the file with + * testdata. + * + * @author ms + * + */ +public abstract class Argument { + + protected TestData testdata; + + /** + * Convert to String, prepending some indentation. + * + * @param indent + * the required indentation. + * @return a pretty {@link String}. + */ + abstract public String toString(String indent); + + /** + * Set the {@link TestData} object this {@link Argument} belongs to. + */ + public void setTestData(TestData testdata) { + this.testdata = testdata; + } + +} \ No newline at end of file diff --git a/lib/jtestdataaccessor/src/main/java/ch/ethz/infsec/jtestdataaccessor/nodes/Function.java b/lib/jtestdataaccessor/src/main/java/ch/ethz/infsec/jtestdataaccessor/nodes/Function.java new file mode 100644 index 0000000..c793dc5 --- /dev/null +++ b/lib/jtestdataaccessor/src/main/java/ch/ethz/infsec/jtestdataaccessor/nodes/Function.java @@ -0,0 +1,124 @@ +package ch.ethz.infsec.jtestdataaccessor.nodes; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +import static org.junit.Assert.fail; + +/** + * A function node for a function which is used to set up the environment or to + * create some value. + * + * @author ms + * + */ +public class Function extends Value { + + private String name; + + /** + * Initialize a new function. + * + * @param name + * of the new function. + */ + public Function(String name) { + this.name = name; + } + + /** + * Get the name of the function. + * + * @return the name. + */ + public String getName() { + return name; + } + + /** + * Call the function on the object with the junit tests, discarding the + * result. + * + * @throws Throwable + * + */ + public void call() throws Throwable { + getValue(); + } + + /** + * Call the function using the given parameter types and arguments on the + * object with the junit tests, discarding the result. + * + * @throws Throwable + * + */ + public void call(Class[] classes, Object[] objects) throws Throwable { + getValue(classes, objects); + } + + /** + * Call the function on the object with the junit tests, but do not discard + * the result. + * + * @throws Throwable + */ + @Override + public Object getValue() throws Throwable { + return getValue((Class[]) null, (Object[]) null); + } + + /** + * Call the function using the given parameter types and arguments on the + * object with the junit tests and return the result. + * + * @param params + * types of the parameters. + * @param args + * arguments to call the function with. + * @return the value produced by the called function. + * @throws Throwable + */ + public Object getValue(Class[] params, Object[] args) throws Throwable { + try { + if (testdata != null && testdata.getTestDataAccessor() != null + && testdata.getTestDataAccessor().getTestDataUser() != null) { + Class c = testdata.getTestDataAccessor().getTestDataUser() + .getClass(); + Method m = c.getMethod(name, params); + return m.invoke(testdata.getTestDataAccessor() + .getTestDataUser(), args); + } else { + System.err + .println("No TestDataUser found to execute method on!"); + } + } catch (InvocationTargetException e) { + // The called function has thrown an exception, so return that + // exception instead of a InvocationTargetException which is not + // really useful outside. + throw e.getCause(); + } catch (Exception e) { + // There seems to be an exception in our code, which should not + // happen... + e.printStackTrace(); + fail("Failed to execute the specified function " + getName() + "."); + } + return null; + } + + @Override + public String toString() { + return toString(""); + } + + /** + * Pretty print the function name. + * + * @return the pretty name. + */ + @Override + public String toString(String indent) { + return indent + name + "()"; + } + +} \ No newline at end of file diff --git a/lib/jtestdataaccessor/src/main/java/ch/ethz/infsec/jtestdataaccessor/nodes/ResultChecker.java b/lib/jtestdataaccessor/src/main/java/ch/ethz/infsec/jtestdataaccessor/nodes/ResultChecker.java new file mode 100644 index 0000000..0571bba --- /dev/null +++ b/lib/jtestdataaccessor/src/main/java/ch/ethz/infsec/jtestdataaccessor/nodes/ResultChecker.java @@ -0,0 +1,191 @@ +package ch.ethz.infsec.jtestdataaccessor.nodes; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNotSame; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import org.junit.ComparisonFailure; + +import ch.ethz.infsec.jtestdataaccessor.TestCase; +import ch.ethz.infsec.jtestdataaccessor.TestData; + +/** + * Class used for checking the result. + * + * @author ms + * + */ +public class ResultChecker extends Argument { + + /** + * An enum of some default checkers which are mostly taken from + * org.junit.Assert. + * + * @author ms + * + */ + public static enum DefaultChecker { + EQUALS, FALSE, TRUE, NOTNULL, NULL, NOTSAME, SAME, FAIL, NOTEQUAL + }; + + private DefaultChecker defaultchecker; + + private Function functionchecker; + + private TestCase testcase; + + /** + * Create new {@link ResultChecker} using a {@link DefaultChecker}. + * + * @param defaultchecker + * a {@link DefaultChecker} + */ + public ResultChecker(DefaultChecker defaultchecker) { + this.defaultchecker = defaultchecker; + } + + /** + * Create a new {@link ResultChecker} using a {@link Function}. + * + * @param functionchecker + * a {@link Function} + */ + public ResultChecker(Function functionchecker, TestData td) { + functionchecker.setTestData(td); + this.setTestData(td); + this.functionchecker = functionchecker; + } + + @Override + public String toString() { + return toString(""); + } + + /** + * Pretty print the {@link ResultChecker}. + * + * @return the pretty printed {@link ResultChecker} + */ + @Override + public String toString(String indent) { + StringBuffer sb = new StringBuffer(); + if (defaultchecker != null) { + sb.append(defaultchecker.toString()); + } else if (functionchecker != null) { + sb.append(functionchecker.toString()); + } + return indent + sb.toString(); + } + + /** + * Execute a check on a given object. + * + * @param result + * the actual result. + * @param reference + * the reference value. + * @throws Throwable + */ + public void check(Object result) throws Throwable { + Object expected = null; + if (testcase.getResult() != null) { + expected = testcase.getResult().getValue(); + } + String comment = null; + if (testcase != null) { + comment = testcase.getComment(); + } + if (defaultchecker != null) { + switch (defaultchecker) { + case EQUALS: + assertEquals(comment, expected, result); + break; + case FAIL: + fail(comment); + break; + case FALSE: + assertFalse(comment, (Boolean) result); + break; + case NOTNULL: + assertNotNull(comment, result); + break; + case NOTSAME: + assertNotSame(comment, expected, result); + break; + case NULL: + assertNull(comment, result); + break; + case SAME: + assertSame(comment, expected, result); + break; + case TRUE: + assertTrue(comment, (Boolean) result); + break; + case NOTEQUAL: + assertNotEqual(comment, expected, result); + break; + } + } else if (functionchecker != null) { + Class argType = Object.class; + if (testcase != null && testcase.getFunctionUnderTest() != null + && testcase.getFunctionUnderTest().getResultType() != null) { + argType = testcase.getFunctionUnderTest().getResultType() + .getTypeClass(); + } + functionchecker.call(new Class[] { argType }, + new Object[] { result }); + } else { + fail("No checker provided."); + } + } + + /** + * Asserts that two objects are not equal. If they are not, an + * {@link AssertionError} is thrown with the given message. Adapted from + * org.junit.Assert. + * + * @param message + * the identifying message or null for the + * {@link AssertionError} + * @param expected + * expected value + * @param actual + * actual value + */ + static public void assertNotEqual(String message, Object unexpected, + Object actual) { + if (unexpected == null && actual == null) { + return; + } + if (unexpected != null && !unexpected.equals(actual)) { + return; + } + if (unexpected instanceof String && actual instanceof String) { + throw new ComparisonFailure(message, (String) unexpected, + (String) actual); + } else { + String formatted = ""; + if (message != null) { + formatted = message + " "; + } + fail(formatted + "unexpected:<" + unexpected + + "> but nevertheless got:<" + actual + ">"); + } + } + + /** + * Set the {@link TestCase} this {@link ResultChecker} belongs to. + * + * @param testcase + * the {@link TestCase} this object belongs to. + */ + public void setTestCase(TestCase testcase) { + this.testcase = testcase; + } + +} diff --git a/lib/jtestdataaccessor/src/main/java/ch/ethz/infsec/jtestdataaccessor/nodes/SimpleValue.java b/lib/jtestdataaccessor/src/main/java/ch/ethz/infsec/jtestdataaccessor/nodes/SimpleValue.java new file mode 100644 index 0000000..f113c0a --- /dev/null +++ b/lib/jtestdataaccessor/src/main/java/ch/ethz/infsec/jtestdataaccessor/nodes/SimpleValue.java @@ -0,0 +1,46 @@ +package ch.ethz.infsec.jtestdataaccessor.nodes; + +/** + * Represent a simple value such as int, boolean, String etc. + * + * @author ms + * + */ +public class SimpleValue extends Value { + + private Object value; + + /** + * Create new {@link SimpleValue} object containing the given value. + * + * @param value + * the value of this node. + */ + public SimpleValue(Object value) { + this.value = value; + } + + /** + * Get the value. + * + * @return gets the specified value. + */ + @Override + public Object getValue() { + return value; + } + + @Override + public String toString() { + return toString(""); + } + + /** + * Pretty print the {@link SimpleValue} node. + */ + @Override + public String toString(String indent) { + return indent + value.toString(); + } + +} \ No newline at end of file diff --git a/lib/jtestdataaccessor/src/main/java/ch/ethz/infsec/jtestdataaccessor/nodes/Type.java b/lib/jtestdataaccessor/src/main/java/ch/ethz/infsec/jtestdataaccessor/nodes/Type.java new file mode 100644 index 0000000..5c9b468 --- /dev/null +++ b/lib/jtestdataaccessor/src/main/java/ch/ethz/infsec/jtestdataaccessor/nodes/Type.java @@ -0,0 +1,134 @@ +package ch.ethz.infsec.jtestdataaccessor.nodes; + +import static org.junit.Assert.fail; + +import java.util.HashMap; + +/** + * Representation of a type given in the testdatafile. + * + * @author ms + * + */ +public class Type extends Value { + + private String name; + + private boolean isArray; + + private static final HashMap basicTypeMap = new HashMap(); + + private static final HashMap basicTypeArrayMap = new HashMap(); + + /** + * Create a new {@link Type} object. + * + * @param name + */ + public Type(String name) { + this.name = name; + if (basicTypeMap.size() == 0) { + basicTypeMap.put(Boolean.TYPE.getName(), Boolean.TYPE); + basicTypeMap.put(Byte.TYPE.getName(), Byte.TYPE); + basicTypeMap.put(Character.TYPE.getName(), Character.TYPE); + basicTypeMap.put(Short.TYPE.getName(), Short.TYPE); + basicTypeMap.put(Integer.TYPE.getName(), Integer.TYPE); + basicTypeMap.put(Long.TYPE.getName(), Long.TYPE); + basicTypeMap.put(Float.TYPE.getName(), Float.TYPE); + basicTypeMap.put(Double.TYPE.getName(), Double.TYPE); + } + if (basicTypeArrayMap.size() == 0) { + basicTypeArrayMap.put(Boolean.TYPE.getName(), boolean[].class); + basicTypeArrayMap.put(Byte.TYPE.getName(), byte[].class); + basicTypeArrayMap.put(Character.TYPE.getName(), char[].class); + basicTypeArrayMap.put(Short.TYPE.getName(), short[].class); + basicTypeArrayMap.put(Integer.TYPE.getName(), int[].class); + basicTypeArrayMap.put(Long.TYPE.getName(), long[].class); + basicTypeArrayMap.put(Float.TYPE.getName(), float[].class); + basicTypeArrayMap.put(Double.TYPE.getName(), double[].class); + } + } + + /** + * Get the {@link Class} object of this type. Distinguish between array and + * normal types and try to prepend java.lang if the class is not found at + * first. + * + * @return the {@link Class} object. + * @throws ClassNotFoundException + */ + public Class getTypeClass() throws ClassNotFoundException { + Class typeClass = null; + if (basicTypeMap.get(name) != null) { + if (isArray) { + typeClass = basicTypeArrayMap.get(name); + } else { + typeClass = basicTypeMap.get(name); + } + } else { + try { + typeClass = Class.forName((isArray ? "[L" : "") + name); + } catch (ClassNotFoundException e0) { + try { + typeClass = Class.forName((isArray ? "[L" : "") + + "java.lang." + name); + } catch (ClassNotFoundException e1) { + throw new ClassNotFoundException("Class " + name + + " not found!", new ClassNotFoundException(e1 + .getMessage(), new ClassNotFoundException(e0 + .getMessage()))); + } + } + } + return typeClass; + } + + @Override + public String toString() { + return toString(""); + } + + /** + * Pretty print this type. + * + * @return the given type name. + */ + @Override + public String toString(String indent) { + return indent + name; + } + + /** + * Return the class object, catching exceptions and failing if one occurs. + * + * @return the class object representing the type. + */ + @Override + public Class getValue() { + try { + return getTypeClass(); + } catch (ClassNotFoundException e) { + fail(e.getMessage()); + } + return null; + } + + /** + * Is this type an array? + * + * @return + */ + public boolean isArray() { + return isArray; + } + + /** + * Set this type to be an array. + * + * @param isArray + */ + public void setArray(boolean isArray) { + this.isArray = isArray; + } + +} diff --git a/lib/jtestdataaccessor/src/main/java/ch/ethz/infsec/jtestdataaccessor/nodes/Value.java b/lib/jtestdataaccessor/src/main/java/ch/ethz/infsec/jtestdataaccessor/nodes/Value.java new file mode 100644 index 0000000..dee5454 --- /dev/null +++ b/lib/jtestdataaccessor/src/main/java/ch/ethz/infsec/jtestdataaccessor/nodes/Value.java @@ -0,0 +1,23 @@ +package ch.ethz.infsec.jtestdataaccessor.nodes; + +/** + * Abstract {@link Value} class - {@link Function} and {@link SimpleValue} are + * examples of classes implementing this class, they may be used where a value + * is needed. + * + * @author ms + * + */ +public abstract class Value extends Argument { + + /** + * Get the value of the object. + * + * @return the value. + * @throws Throwable + * might be thrown if the result is generated by a function + * which itself has thrown an exception. + */ + abstract public Object getValue() throws Throwable; + +} \ No newline at end of file diff --git a/lib/jtestdataaccessor/src/main/java/ch/ethz/infsec/jtestdataaccessor/oclexceptions/InvariantFailedException.java b/lib/jtestdataaccessor/src/main/java/ch/ethz/infsec/jtestdataaccessor/oclexceptions/InvariantFailedException.java new file mode 100644 index 0000000..cf51421 --- /dev/null +++ b/lib/jtestdataaccessor/src/main/java/ch/ethz/infsec/jtestdataaccessor/oclexceptions/InvariantFailedException.java @@ -0,0 +1,20 @@ +package ch.ethz.infsec.jtestdataaccessor.oclexceptions; + +public class InvariantFailedException extends OclException { + + /** + * Thrown when the check of the invariant failed. + * + * @param string + * contains a message. + */ + public InvariantFailedException(String string) { + super(string); + } + + /** + * A default serial version uid. + */ + private static final long serialVersionUID = 1L; + +} diff --git a/lib/jtestdataaccessor/src/main/java/ch/ethz/infsec/jtestdataaccessor/oclexceptions/OclException.java b/lib/jtestdataaccessor/src/main/java/ch/ethz/infsec/jtestdataaccessor/oclexceptions/OclException.java new file mode 100644 index 0000000..9e5f97d --- /dev/null +++ b/lib/jtestdataaccessor/src/main/java/ch/ethz/infsec/jtestdataaccessor/oclexceptions/OclException.java @@ -0,0 +1,20 @@ +package ch.ethz.infsec.jtestdataaccessor.oclexceptions; + +public class OclException extends Exception { + + /** + * Thrown if the check of an OCL contract failed. + * + * @param string + * contains a message. + */ + public OclException(String string) { + super(string); + } + + /** + * A default serial version uid. + */ + private static final long serialVersionUID = 1L; + +} diff --git a/lib/jtestdataaccessor/src/main/java/ch/ethz/infsec/jtestdataaccessor/oclexceptions/PostconditionFailedException.java b/lib/jtestdataaccessor/src/main/java/ch/ethz/infsec/jtestdataaccessor/oclexceptions/PostconditionFailedException.java new file mode 100644 index 0000000..97e9321 --- /dev/null +++ b/lib/jtestdataaccessor/src/main/java/ch/ethz/infsec/jtestdataaccessor/oclexceptions/PostconditionFailedException.java @@ -0,0 +1,20 @@ +package ch.ethz.infsec.jtestdataaccessor.oclexceptions; + +public class PostconditionFailedException extends OclException { + + /** + * Thrown when a postcondition check failed. + * + * @param string + * contains a message. + */ + public PostconditionFailedException(String string) { + super(string); + } + + /** + * A default serial version uid. + */ + private static final long serialVersionUID = 1L; + +} diff --git a/lib/jtestdataaccessor/src/main/java/ch/ethz/infsec/jtestdataaccessor/oclexceptions/PreconditionFailedException.java b/lib/jtestdataaccessor/src/main/java/ch/ethz/infsec/jtestdataaccessor/oclexceptions/PreconditionFailedException.java new file mode 100644 index 0000000..669b860 --- /dev/null +++ b/lib/jtestdataaccessor/src/main/java/ch/ethz/infsec/jtestdataaccessor/oclexceptions/PreconditionFailedException.java @@ -0,0 +1,20 @@ +package ch.ethz.infsec.jtestdataaccessor.oclexceptions; + +public class PreconditionFailedException extends OclException { + + /** + * Thrown whenever a precondition check failed. + * + * @param string + * contains a message. + */ + public PreconditionFailedException(String string) { + super(string); + } + + /** + * A default serial version uid. + */ + private static final long serialVersionUID = 1L; + +} diff --git a/lib/jtestdataaccessor/src/test/java/ch/ethz/infsec/jtestdataaccessor/BasicTest.java b/lib/jtestdataaccessor/src/test/java/ch/ethz/infsec/jtestdataaccessor/BasicTest.java new file mode 100644 index 0000000..826ceef --- /dev/null +++ b/lib/jtestdataaccessor/src/test/java/ch/ethz/infsec/jtestdataaccessor/BasicTest.java @@ -0,0 +1,72 @@ +package ch.ethz.infsec.jtestdataaccessor; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FilenameFilter; + +import org.junit.Test; + +import antlr.RecognitionException; +import antlr.TokenStreamException; + +public class BasicTest { + + private void testConfigs(String path, boolean valid) + throws FileNotFoundException, RecognitionException, + TokenStreamException, TestDataParseException { + File dir = new File(path); + File[] files = dir.listFiles(new FilenameFilter() { + public boolean accept(File dirname, String name) { + if (name.endsWith(".conf")) { + return true; + } else { + return false; + } + } + }); + for (File file : files) { + System.out.println("Trying to parse " + file.getAbsolutePath()); + try { + TestDataAccessor tda = new TestDataAccessor(file + .getAbsolutePath()); + //System.out.println(tda.toString()); + } catch (TestDataParseException e) { + System.err.println(e.getClass().getName()+": "+e.getMessage()); + if (valid) { + throw e; + } + } + } + } + + @Test + public void validConfigs() throws FileNotFoundException, + RecognitionException, TokenStreamException, TestDataParseException { + System.out + .println("Running tests on presumably correct testdata-files:"); + testConfigs("src/test/resources/valid", true); + } + + @Test + public void invalidConfigs() throws FileNotFoundException, + RecognitionException, TokenStreamException { + System.out + .println("Running tests on presumably incorrect testdata-files, so expect exceptions:"); + try { + testConfigs("src/test/resources/invalid", false); + } catch (TestDataParseException e) { + e.printStackTrace(); + } + + } + + public static void main(String[] args) { + BasicTest b = new BasicTest(); + try { + b.validConfigs(); + b.invalidConfigs(); + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/lib/jtestdataaccessor/src/test/java/ch/ethz/infsec/jtestdataaccessor/examples/AbstractIntArrayStoreTest.java b/lib/jtestdataaccessor/src/test/java/ch/ethz/infsec/jtestdataaccessor/examples/AbstractIntArrayStoreTest.java new file mode 100644 index 0000000..fbf09b3 --- /dev/null +++ b/lib/jtestdataaccessor/src/test/java/ch/ethz/infsec/jtestdataaccessor/examples/AbstractIntArrayStoreTest.java @@ -0,0 +1,38 @@ +package ch.ethz.infsec.jtestdataaccessor.examples; + +import static org.junit.Assert.fail; + +public abstract class AbstractIntArrayStoreTest { + + static IntArrayStore testObject; + + /** + * Setup the {@link IntArrayStore} with some test array. + * + */ + public void setup1() { + testObject = new IntArrayStore(new int[] { 9, 2, 4, 4, 2, 5, 76, 8, 6, + 4, 3, 2 }); + } + + /** + * Check if the given result is sorted in ascending order. + * + * @param result + * to check. + */ + public void resultCheck1(int[] result) { + for (int i : result) { + System.out.print(i + " "); + } + System.out.println(); + if (result.length > 1) { + for (int i = 1; i < result.length; i++) { + if (result[i - 1] > result[i]) { + fail("Incorrectly sorted array."); + } + } + } + } + +} diff --git a/lib/jtestdataaccessor/src/test/java/ch/ethz/infsec/jtestdataaccessor/examples/AbstractIntMaxTest.java b/lib/jtestdataaccessor/src/test/java/ch/ethz/infsec/jtestdataaccessor/examples/AbstractIntMaxTest.java new file mode 100644 index 0000000..2c9972b --- /dev/null +++ b/lib/jtestdataaccessor/src/test/java/ch/ethz/infsec/jtestdataaccessor/examples/AbstractIntMaxTest.java @@ -0,0 +1,24 @@ +package ch.ethz.infsec.jtestdataaccessor.examples; + + +public abstract class AbstractIntMaxTest { + + static IntMax testObject; + + /** + * Return an array as input for the test + * + */ + public int[] getInput1() { + return new int[] {2,5,4,3,5,6,7,5,3,2,4,6,8,9,0}; + } + + /** + * Return an array as input for the test, including negative values + * + */ + public int[] getInput2() { + return new int[] {1,0,-1}; + } + +} diff --git a/lib/jtestdataaccessor/src/test/java/ch/ethz/infsec/jtestdataaccessor/examples/IntArrayStoreTest.java b/lib/jtestdataaccessor/src/test/java/ch/ethz/infsec/jtestdataaccessor/examples/IntArrayStoreTest.java new file mode 100644 index 0000000..458875e --- /dev/null +++ b/lib/jtestdataaccessor/src/test/java/ch/ethz/infsec/jtestdataaccessor/examples/IntArrayStoreTest.java @@ -0,0 +1,57 @@ +package ch.ethz.infsec.jtestdataaccessor.examples; + +import java.io.FileNotFoundException; + +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.Ignore; + +import antlr.RecognitionException; +import antlr.TokenStreamException; +import ch.ethz.infsec.jtestdataaccessor.TestDataAccessor; +import ch.ethz.infsec.jtestdataaccessor.TestDataParseException; +import ch.ethz.infsec.jtestdataaccessor.TestDataUser; +import ch.ethz.infsec.jtestdataaccessor.TestHelper; + +public class IntArrayStoreTest extends AbstractIntArrayStoreTest implements + TestDataUser { + + public static String classUnderTest = "ch.ethz.infsec.jtestdataaccessor.examples.IntArrayStore"; + + private static TestDataAccessor tda; + + private static TestHelper th; + + public String getClassUnderTest() { + return classUnderTest; + } + + public Object getTestObject() { + return testObject; + } + + @BeforeClass + public static void basicEnvSetup() throws FileNotFoundException, + RecognitionException, TokenStreamException, TestDataParseException { + tda = new TestDataAccessor( + "src/test/resources/ch/ethz/infsec/jtestdataaccessor/examples/TestdataIntArrayStore"); + th = new TestHelper(classUnderTest, tda); + } + + @Test + public void getSortedTest() throws Throwable { + String methodname = "getSorted"; + th.doTest(methodname, this); + } + + public int[] wrapped_getSorted(){ + return testObject.getSorted(); + } + + @Ignore + @Test + public void getInvalidSortedTest() throws Throwable { + String methodname = "getInvalidSorted"; + th.doTest(methodname, this); + } +} diff --git a/lib/jtestdataaccessor/src/test/java/ch/ethz/infsec/jtestdataaccessor/examples/IntMaxTest.java b/lib/jtestdataaccessor/src/test/java/ch/ethz/infsec/jtestdataaccessor/examples/IntMaxTest.java new file mode 100644 index 0000000..f2e746c --- /dev/null +++ b/lib/jtestdataaccessor/src/test/java/ch/ethz/infsec/jtestdataaccessor/examples/IntMaxTest.java @@ -0,0 +1,68 @@ +package ch.ethz.infsec.jtestdataaccessor.examples; + +import java.io.FileNotFoundException; + +import org.junit.BeforeClass; +import org.junit.Test; + +import antlr.RecognitionException; +import antlr.TokenStreamException; +import ch.ethz.infsec.jtestdataaccessor.TestDataAccessor; +import ch.ethz.infsec.jtestdataaccessor.TestDataParseException; +import ch.ethz.infsec.jtestdataaccessor.TestDataUser; +import ch.ethz.infsec.jtestdataaccessor.TestHelper; +import ch.ethz.infsec.jtestdataaccessor.oclexceptions.InvariantFailedException; +import ch.ethz.infsec.jtestdataaccessor.oclexceptions.PostconditionFailedException; +import ch.ethz.infsec.jtestdataaccessor.oclexceptions.PreconditionFailedException; + +public class IntMaxTest extends AbstractIntMaxTest implements TestDataUser { + + public static final String classUnderTest = "ch.ethz.infsec.jtestdataaccessor.examples.IntMax"; + + public String getClassUnderTest() { + return classUnderTest; + } + + private static TestDataAccessor tda; + + private static TestHelper th; + + @BeforeClass + public static void basicEnvSetup() throws FileNotFoundException, + RecognitionException, TokenStreamException, TestDataParseException { + tda = new TestDataAccessor( + "src/test/resources/ch/ethz/infsec/jtestdataaccessor/examples/TestdataIntMax"); + th = new TestHelper(classUnderTest, tda); + } + + @Test + public void maxTest() throws Throwable { + String methodname = "max"; + th.doTest(methodname, this); + } + + public int wrapped_max(int[] array) throws Throwable { + int result; + // Precondition check + if(array.length == 0){ + throw new PreconditionFailedException("Array was empty."); + } + // invoke method + result = testObject.max(array); + // Postcondition check + if(array.length == 0){ + throw new PostconditionFailedException("Array got emptied!"); + } + // Invariant check + checkInvariant(); + return result; + } + + public Object getTestObject() { + return testObject; + } + + public void checkInvariant() throws InvariantFailedException { + + } +} diff --git a/lib/jtestdataaccessor/src/test/java/ch/ethz/infsec/jtestdataaccessor/nodes/AbstractValueTest.java b/lib/jtestdataaccessor/src/test/java/ch/ethz/infsec/jtestdataaccessor/nodes/AbstractValueTest.java new file mode 100644 index 0000000..bbc2ce5 --- /dev/null +++ b/lib/jtestdataaccessor/src/test/java/ch/ethz/infsec/jtestdataaccessor/nodes/AbstractValueTest.java @@ -0,0 +1,24 @@ +package ch.ethz.infsec.jtestdataaccessor.nodes; + +import ch.ethz.infsec.jtestdataaccessor.nodes.SimpleValue; +import ch.ethz.infsec.jtestdataaccessor.nodes.Value; + +public abstract class AbstractValueTest { + + static Value testObject; + + /* + public static void defaultSetup(){ + testObject = new Value(); + } + */ + + public void setup1(){ + testObject = new SimpleValue("Hallo, Welt!"); + } + + public void setup2(){ + testObject = new SimpleValue("Hello, World!"); + } + +} diff --git a/lib/jtestdataaccessor/src/test/java/ch/ethz/infsec/jtestdataaccessor/nodes/ValueTest.java b/lib/jtestdataaccessor/src/test/java/ch/ethz/infsec/jtestdataaccessor/nodes/ValueTest.java new file mode 100644 index 0000000..1f5b4d1 --- /dev/null +++ b/lib/jtestdataaccessor/src/test/java/ch/ethz/infsec/jtestdataaccessor/nodes/ValueTest.java @@ -0,0 +1,49 @@ +package ch.ethz.infsec.jtestdataaccessor.nodes; + +import java.io.FileNotFoundException; + +import org.junit.BeforeClass; +import org.junit.Test; + +import ch.ethz.infsec.jtestdataaccessor.TestDataAccessor; +import ch.ethz.infsec.jtestdataaccessor.TestDataParseException; +import ch.ethz.infsec.jtestdataaccessor.TestDataUser; +import ch.ethz.infsec.jtestdataaccessor.TestHelper; + +import antlr.RecognitionException; +import antlr.TokenStreamException; + +public class ValueTest extends AbstractValueTest implements TestDataUser { + + public static String classUnderTest = "ch.ethz.infsec.jtestdataaccessor.nodes.Value"; + + private static TestDataAccessor tda; + + private static TestHelper th; + + public String getClassUnderTest() { + return classUnderTest; + } + + public Object getTestObject() { + return testObject; + } + + @BeforeClass + public static void basicEnvSetup() throws FileNotFoundException, + RecognitionException, TokenStreamException, TestDataParseException { + tda = new TestDataAccessor( + "src/test/resources/ch/ethz/infsec/jtestdataaccessor/nodes/TestdataValue"); + th = new TestHelper(classUnderTest,tda); + } + + @Test + public void getValueTest() throws Throwable { + String methodname = "getValue"; + th.doTest(methodname, this); + } + + public Object wrapped_getValue() throws Throwable{ + return testObject.getValue(); + } +} diff --git a/lib/jtestdataaccessor/src/test/resources/ch/ethz/infsec/jtestdataaccessor/examples/TestdataIntArrayStore b/lib/jtestdataaccessor/src/test/resources/ch/ethz/infsec/jtestdataaccessor/examples/TestdataIntArrayStore new file mode 100644 index 0000000..b17d219 --- /dev/null +++ b/lib/jtestdataaccessor/src/test/resources/ch/ethz/infsec/jtestdataaccessor/examples/TestdataIntArrayStore @@ -0,0 +1,13 @@ +[getSorted] +resulttype = int[]; +setup = setup1(); +{ + checker = resultCheck1(); +} + +[getInvalidSorted] +resulttype = int[]; +setup = setup1(); +{ + checker = resultCheck1(); +} diff --git a/lib/jtestdataaccessor/src/test/resources/ch/ethz/infsec/jtestdataaccessor/examples/TestdataIntMax b/lib/jtestdataaccessor/src/test/resources/ch/ethz/infsec/jtestdataaccessor/examples/TestdataIntMax new file mode 100644 index 0000000..1569afc --- /dev/null +++ b/lib/jtestdataaccessor/src/test/resources/ch/ethz/infsec/jtestdataaccessor/examples/TestdataIntMax @@ -0,0 +1,17 @@ +[max] +resulttype = int; +inputtypes = int[]; +{ + input = getInput1(); + result = 9; + checker = EQUALS; +} +{ + input = getInput1(); + result = 0; + checker = NOTEQUAL; +} +{ + input = getInput2(); + result = java.lang.Exception; +} diff --git a/lib/jtestdataaccessor/src/test/resources/ch/ethz/infsec/jtestdataaccessor/nodes/TestdataValue b/lib/jtestdataaccessor/src/test/resources/ch/ethz/infsec/jtestdataaccessor/nodes/TestdataValue new file mode 100644 index 0000000..07a7928 --- /dev/null +++ b/lib/jtestdataaccessor/src/test/resources/ch/ethz/infsec/jtestdataaccessor/nodes/TestdataValue @@ -0,0 +1,15 @@ +[getValue] +resulttype = String; +setup = setup1(); +{ + result = "Hallo, Welt!"; + checker = EQUALS; +} + +[getValue] +resulttype = String; +setup = setup2(); +{ + result = "Hello, World!"; + checker = EQUALS; +} diff --git a/lib/jtestdataaccessor/src/test/resources/invalid/invtest1.conf b/lib/jtestdataaccessor/src/test/resources/invalid/invtest1.conf new file mode 100644 index 0000000..1b695ac --- /dev/null +++ b/lib/jtestdataaccessor/src/test/resources/invalid/invtest1.conf @@ -0,0 +1,4 @@ +[foo] +{ + inputtypes = int, Boolean, String; +} diff --git a/lib/jtestdataaccessor/src/test/resources/invalid/invtest2.conf b/lib/jtestdataaccessor/src/test/resources/invalid/invtest2.conf new file mode 100644 index 0000000..c801d16 --- /dev/null +++ b/lib/jtestdataaccessor/src/test/resources/invalid/invtest2.conf @@ -0,0 +1,2 @@ +[foo] +input = 1, true, "Hi"; diff --git a/lib/jtestdataaccessor/src/test/resources/invalid/invtest3.conf b/lib/jtestdataaccessor/src/test/resources/invalid/invtest3.conf new file mode 100644 index 0000000..240d9f7 --- /dev/null +++ b/lib/jtestdataaccessor/src/test/resources/invalid/invtest3.conf @@ -0,0 +1 @@ +[foo] diff --git a/lib/jtestdataaccessor/src/test/resources/invalid/invtest4.conf b/lib/jtestdataaccessor/src/test/resources/invalid/invtest4.conf new file mode 100644 index 0000000..79a3ae6 --- /dev/null +++ b/lib/jtestdataaccessor/src/test/resources/invalid/invtest4.conf @@ -0,0 +1,2 @@ +[foo] +inputtypes = int diff --git a/lib/jtestdataaccessor/src/test/resources/invalid/invtest5.conf b/lib/jtestdataaccessor/src/test/resources/invalid/invtest5.conf new file mode 100644 index 0000000..48f04e1 --- /dev/null +++ b/lib/jtestdataaccessor/src/test/resources/invalid/invtest5.conf @@ -0,0 +1,2 @@ +[foo] +inputtype = int, Boolean, String; diff --git a/lib/jtestdataaccessor/src/test/resources/valid/test1.conf b/lib/jtestdataaccessor/src/test/resources/valid/test1.conf new file mode 100644 index 0000000..be8192d --- /dev/null +++ b/lib/jtestdataaccessor/src/test/resources/valid/test1.conf @@ -0,0 +1,32 @@ +[function-under-test] +resulttype = boolean; # Type of result if non-void +inputtypes = int, boolean, String; # Types of arguments - at least used for + # overloading +setup = function1(); # A function from AbstractTestX which sets + # up the environment - optional +teardown = function2(); # A function from AbstractTestX which tears + # down the environment - optional +{ + input = 1, true, "Hi"; + result = false; + checker = EQUALS; # A function which checks the result, eg. + # using a function provided by junit +} +{ + input = 100, true, "Foo"; + result = resultgen(); + checker = resultcheck(); # A function which checks the result, eg. + # a user defined function +} +[function-under-test] # Different testdata for the same function, + # eg. used for overloading or when testing + # another environment +resulttype = boolean; +inputtypes = int, int, boolean, String; +setup = function3(); +teardown = function2(); +{ + input = 1, 1, inputgen(), "Bar"; + result = java.lang.Exception; + comment = "Test if an exception is thrown"; # Comment to describe the test +} diff --git a/lib/jtestdataaccessor/src/test/resources/valid/test2.conf b/lib/jtestdataaccessor/src/test/resources/valid/test2.conf new file mode 100644 index 0000000..9c921b1 --- /dev/null +++ b/lib/jtestdataaccessor/src/test/resources/valid/test2.conf @@ -0,0 +1,30 @@ +[foo] +resulttype = boolean; +inputtypes = int, Boolean, String; +setup = function1(); +teardown = function2(); +{ + input = 1, true, "Hi"; + result = false; + checker = EQUALS; +} + +[bar] +resulttype = boolean; +inputtypes = int, Double; +{ + input = 1, 3.141592; + result = java.lang.Exception; +} + +[bar] +resulttype = boolean; +inputtypes = int, Double; +{ + input = 1, getInput(); + result = false; +} +{ + input = 'c', getInput(); + result = false; +} diff --git a/lib/jtestdataaccessor/src/test/resources/valid/test3.conf b/lib/jtestdataaccessor/src/test/resources/valid/test3.conf new file mode 100644 index 0000000..a4852fb --- /dev/null +++ b/lib/jtestdataaccessor/src/test/resources/valid/test3.conf @@ -0,0 +1,16 @@ +[foo] +{ + input = 1, true, "Hi"; + result = false; + checker = EQUALS; +} +resulttype = boolean; +inputtypes = int, Boolean, String; +setup = function1(); +teardown = function2(); +{ + input = 1, true, "Hi"; + result = false; + checker = EQUALS; +} +teardown = function3();