Java tutorial
/* * IaTestGen - Interval arithmetic test generator * Copyright 2013 * * Marco Nehmeier (nehmeier@informatik.uni-wuerzburg.de) * Institute of Computer Science, * University of Wuerzburg, Germany * * Michael Jedich (m.jedich@gmail.com) * University of Wuerzburg, Germany * * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package de.uniwue.info2.generator; import static de.uniwue.info2.generator.PlaceHolder.*; import java.io.BufferedWriter; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; import java.text.DecimalFormat; import java.text.SimpleDateFormat; import java.util.Date; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.apache.commons.lang.StringUtils; import de.uniwue.info2.numerics.FloatingPoint; import de.uniwue.info2.operations.Endpoints; import de.uniwue.info2.operations.GenericParameter; import de.uniwue.info2.operations.Interval; import de.uniwue.info2.operations.Operation; import de.uniwue.info2.operations.Set; import de.uniwue.info2.parser.DSLParser; import de.uniwue.info2.parser.ParseException; /** * This class generated unit-tests for all given language-specifications. * * @author Michael Jedich * */ public class TestcaseGenerator { // list of operations specified by Domain Specific Language private OperationsPool operations_; private static final String DSL_PARSER_AUTHORS = DSLParser.getParserAuthors(); private static final String DSL_PARSER_VERSION = DSLParser.getParserVersion(); private static final String DSL_PARSER_DESCRIPTION = DSLParser.getParserDescription(); private String dslAuthors_; private String dslVersion_; private String dslDescription_; // output folder private File outputFolder_; // generated string to write in test-file private String currentBuild_; private BufferedWriter currentFileWriter_, currentLogWriter_; // current language specification (c++, python, etc.) private LanguageSpecification currentLanguageSpecification_; private ArithmeticLibrarySpecification currentArithmeticLibrary_; private UnitTestLibrarySpecification currentUnitTestLibrary_; // translations for current language specification private HashMap<Class<?>, String[]> currentTypeTranslation_; private HashMap<String, String> currentOperationsTranslationTable_; private HashMap<String, String> currentMixedTypesOperationsTranslationTable_; private HashMap<Boolean, String> currentBooleanTranslation_; private HashMap<Class<?>, String[]> currentPositiveInfinityTable_; private HashMap<Class<?>, String[]> currentNegativeInfinityTable_; private String[] currentEmptyIntervalTranslation_; private String[] currentEntireIntervalTranslation_; private String lineComment_; private Boolean littleEndian_; private Class<?> currentMixedType; private static final DecimalFormat INDEX = new DecimalFormat("00"); // name for testfunctions, at the end a counter is being added private static final String TESTCASE = "test_"; /** * Generator for unit-tests. * * @param dsl * Domain Specific Language * @param output * Output-folder, where all files are generated */ public TestcaseGenerator(File dsl, File output) { // instantiate dsl parser (generated by JavaCC) try { DSLParser parser = new DSLParser(dsl); // get all operations extracted from dsl by our parser this.operations_ = parser.parse(); // set output folder this.outputFolder_ = output; // get dsl informations from head block comment this.dslAuthors_ = parser.getDslAuthors(); this.dslVersion_ = parser.getDslVersion(); this.dslDescription_ = parser.getDslDescription(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (ParseException e) { e.printStackTrace(); } } /** * Generate unit-tests for given language-specification. * * @param targetLanguage * the language-specification you want to generate unit-tests for. * @param useOptionalOperations * if true, optional operations are also generated * @return true if unit-tests were successfully generated */ public boolean generateUnitTest(LanguageSpecification targetLanguage, Boolean useOptionalOperations, List<String> optionalExceptions, Boolean littleEndian) { // log operations which are not supported by current language // specification StringBuffer log; // given language-specification this.currentLanguageSpecification_ = targetLanguage; // get language-specific primitive-types translations (e.g. short, int, // float, boolean // ...) this.currentTypeTranslation_ = currentLanguageSpecification_.getTypesTranslation(); if (this.currentTypeTranslation_ == null) this.currentTypeTranslation_ = new HashMap<Class<?>, String[]>(); // get boolean translation (true, false) this.currentBooleanTranslation_ = currentLanguageSpecification_.getBooleanTranslation(); if (this.currentBooleanTranslation_ == null) this.currentBooleanTranslation_ = new HashMap<Boolean, String>(); // get line comment definition this.lineComment_ = this.currentLanguageSpecification_.getLineCommentToken(); if (this.lineComment_ == null) this.lineComment_ = "/"; this.littleEndian_ = littleEndian; // testfunctions counter, used for function-names short currentTestNumber = 1; // starts with available unit-test libraries for (UnitTestLibrarySpecification uSpec : this.currentLanguageSpecification_.getUnitTestLibraryList()) { this.currentUnitTestLibrary_ = uSpec; // then iterates through arithmetic libraries for (ArithmeticLibrarySpecification aSpec : this.currentLanguageSpecification_ .getArithmeticLibraryList()) { log = new StringBuffer(); this.currentArithmeticLibrary_ = aSpec; // get translations for negative and positive infinity-limits this.currentPositiveInfinityTable_ = this.currentArithmeticLibrary_ .getPositiveInfinityTranslation(); if (this.currentPositiveInfinityTable_ == null) this.currentPositiveInfinityTable_ = new HashMap<Class<?>, String[]>(); this.currentNegativeInfinityTable_ = this.currentArithmeticLibrary_ .getNegativeInfinityTranslation(); if (this.currentNegativeInfinityTable_ == null) this.currentNegativeInfinityTable_ = new HashMap<Class<?>, String[]>(); // add interval translation from arithmetic library this.currentTypeTranslation_.put(Interval.class, aSpec.getIntervalTranslation()); this.currentEmptyIntervalTranslation_ = aSpec.getEmptyIntervalTranslation(); if (this.currentEmptyIntervalTranslation_ == null) this.currentEmptyIntervalTranslation_ = new String[0]; this.currentEntireIntervalTranslation_ = aSpec.getEntireIntervalTranslation(); if (this.currentEntireIntervalTranslation_ == null) this.currentEntireIntervalTranslation_ = new String[0]; // add all operation-translations this.currentOperationsTranslationTable_ = aSpec.getOperationsTranslation(); if (this.currentOperationsTranslationTable_ == null) this.currentOperationsTranslationTable_ = new HashMap<String, String>(); this.currentMixedTypesOperationsTranslationTable_ = aSpec.getMixedTypesOperationsTranslation(); if (this.currentMixedTypesOperationsTranslationTable_ == null) this.currentMixedTypesOperationsTranslationTable_ = new HashMap<String, String>(); // add operations to get lower and upper limit from intervall this.currentOperationsTranslationTable_.put("intervalLowerLimit", aSpec.getIntervalLowerLimit()); this.currentOperationsTranslationTable_.put("intervalUpperLimit", aSpec.getIntervalUpperLimit()); // get main program code-sequence this.currentBuild_ = this.currentLanguageSpecification_.getCodeSequence(); // insert head comment with authors, version and description this.currentBuild_ = replacePlaceHolder(this.currentBuild_, HEAD_COMMENT, this.getHeadComment() + "\n"); // inserts imports and definitions from current // LanguageSpecification-subclass this.currentBuild_ = replacePlaceHolder(this.currentBuild_, LANGUAGE_IMPORTS, this.currentLanguageSpecification_.getImportsAndDefinitions() + "\n"); // inserts imports and definitions from current // ArithmeticLibrarySpecification-subclass this.currentBuild_ = replacePlaceHolder(this.currentBuild_, ARITHMETIC_LIB_IMPORTS, aSpec.getImportsAndDefinitions() + "\n"); // inserts imports and definitions from current // ArithmeticLibrarySpecification-subclass this.currentBuild_ = replacePlaceHolder(this.currentBuild_, TEST_LIB_IMPORTS, uSpec.getImportsAndDefinitions() + "\n\n"); // inserts custom methods from current // LanguageSpecification-subclass this.currentBuild_ = replacePlaceHolder(this.currentBuild_, CUSTOM_METHODS, this.currentLanguageSpecification_.getLanguageCustomMethods() + "\n\n"); // get program code-sequence of test-case-section this.currentBuild_ = replacePlaceHolder(this.currentBuild_, TEST_CASES, uSpec.getCodeSequence() + "\n\n"); // write all test methods into this string String testMethods = ""; // iterate through all given operations Iterator<Operation> operationIterator = this.operations_.getOperations(); while (operationIterator.hasNext()) { Operation operation = operationIterator.next(); // private Class<?> currentMixedType; // given mixed type this.currentMixedType = operation.getMixedType(); boolean mixed_types = checkOperationForMixType(operation); // testing if operation is implemented if ((this.currentOperationsTranslationTable_.containsKey(operation.getName()) && !mixed_types) || (this.currentMixedTypesOperationsTranslationTable_.containsKey(operation.getName()) && mixed_types)) { // check if recommended operations are marked for generation // elaboate if block for more clarity boolean generateCurrentOp = false; if (operation.isRequired()) { generateCurrentOp = true; } else if (useOptionalOperations && !optionalExceptions.contains(operation.getName())) { generateCurrentOp = true; } else if (!useOptionalOperations && optionalExceptions.contains(operation.getName())) { generateCurrentOp = true; } if (generateCurrentOp) { Set currentSetConfig = operation.getSetRelation(); boolean isNegated = operation.isNegated(); // get raw test-method from unit-test-library testMethods += uSpec.getTestMethod(); // add comment provided by dsl to current operation String operationComments = getOperationComment(operation); testMethods = replacePlaceHolder(testMethods, TEST_CASE_COMMENTS, operationComments); // build test-case name from operations information String testcaseName = TESTCASE + INDEX.format(currentTestNumber++); String operationName = "_" + operation.getName().toLowerCase().replaceAll("[^a-z0-9]", ""); if (!operationName.equals("_")) { testcaseName += operationName; } // get input and output parameter of current // operation List<GenericParameter<?>> input_parameter = operation.getInputList(); List<GenericParameter<?>> output_parameter = operation.getOutputList(); // type declarations defined by current language // specification String declarations = ""; // assert string given by unit-test-library String assertString = ""; // raw operation string by name String function = ""; if (mixed_types) { function = this.currentMixedTypesOperationsTranslationTable_ .get(operation.getName()); } else { function = this.currentOperationsTranslationTable_.get(operation.getName()); } if (function == null) { throw new NullPointerException("function-translation is null!"); } String var_arguments = ""; // declare all input parameter for (int i = 0; i < input_parameter.size(); i++) { GenericParameter<?> input = input_parameter.get(i); String inputName = ""; if (input_parameter.size() < 2) { inputName = "input"; } else { inputName = "input_" + INDEX.format(i + 1); } // add to comment, that input parameter was // defined declarations += this.lineComment_ + " input parameter " + (i + 1) + ":" + "\n"; if (input.hasType(Interval.class)) { Interval<?> interval = (Interval<?>) input.getValue(); if (interval.isEmpty()) { declarations += getNewIntervalString(interval, inputName, true, false); } else if (interval.isEntire()) { declarations += getNewIntervalString(interval, inputName, false, true); } else { declarations += getNewIntervalString(interval, inputName, false, false); } } else { declarations += getParameterString(input, inputName); } if (function.contains(inputName(i + 1))) { function = function.replace(inputName(i + 1), inputName); } else if (function.contains(VAR_ARGS)) { if (function.split(VAR_ARGS).length > 1) { System.err.println("only one variable arguments parameter is possible"); } else { var_arguments += aSpec.getParameterSeparator() + " " + inputName; } } } if (!var_arguments.isEmpty()) { function = function.replace(VAR_ARGS, var_arguments); } else { function = function.replace(VAR_ARGS, ""); } // declare all output parameter for (int i = 0; i < output_parameter.size(); i++) { GenericParameter<?> output = output_parameter.get(i); String expectedOutputName = ""; String outputName = ""; if (output_parameter.size() < 2) { expectedOutputName = "output"; outputName = "lib_output"; } else { expectedOutputName = "output_" + INDEX.format(i + 1); outputName = "lib_output_" + INDEX.format(i + 1); } String type = ""; // add to comment, that output parameter was // defined declarations += this.lineComment_ + " expected output parameter " + (i + 1) + ":" + "\n"; assertString += "\n" + this.lineComment_ + " assert function for output " + (i + 1) + ":"; if (output.hasType(Interval.class)) { Interval<?> interval = (Interval<?>) output.getValue(); // get type translation from current // language-specification type = this.currentTypeTranslation_.get(interval.getTypeClass())[0]; if (interval.isEmpty()) { declarations += getNewIntervalString(interval, expectedOutputName, true, false); } else if (interval.isEntire()) { declarations += getNewIntervalString(interval, expectedOutputName, false, true); } else { declarations += getNewIntervalString(interval, expectedOutputName, false, false); } // get interval translation from current // arithmetic-library-specification String intervalType = this.currentTypeTranslation_ .get(((Interval<?>) output.getValue()).getTypeClass())[0]; if (interval.isEmpty()) { assertString += getAssertFunctionForEmptyInterval(expectedOutputName, outputName, currentSetConfig, isNegated); } else if (interval.isEntire()) { assertString += getAssertFunctionForEntireInterval(expectedOutputName, outputName, currentSetConfig, isNegated); } else { assertString += getAssertFunctionForInterval(intervalType, expectedOutputName, outputName, currentSetConfig, isNegated); } } else { declarations += getParameterString(output, expectedOutputName); type = this.currentTypeTranslation_.get(output.getTypeClass())[0]; assertString += "\n" + getAssertString(expectedOutputName, outputName, null, isNegated); } function = function.replace(outputName(i + 1), outputName); String[] intervalTranslation = this.currentTypeTranslation_ .get(output.getTypeClass()); function = function.replace(outputType(i + 1), intervalTranslation[0].replace(INTERVAL_TYPE, type)); } // insert one test method with current operation // name testMethods = replacePlaceHolder(testMethods, TEST_CASE_NAME, testcaseName); // add comment to current operation function declarations += "\n" + this.lineComment_ + " operation to test: " + operation.getName(); declarations += "\n" + function; testMethods = replacePlaceHolder(testMethods, ARITHMETIC_EVAL, declarations); testMethods = replacePlaceHolder(testMethods, ASSERTS, assertString + "\n"); testMethods += "\n\n"; } } else { String error = ""; if (!mixed_types) { error = "Operation with name: \"" + operation.getName() + "\" is not implemented! \n"; } else { error = "Mixed Type operation with name: \"" + operation.getName() + "\" is not implemented! \n"; } log.append(error); System.err.println(error); } } // insert custom methods from ia-library String arithCustomMethods = this.currentArithmeticLibrary_.getCustomMethods(); if (arithCustomMethods != null) { arithCustomMethods = this.lineComment_ + " Custom methods of IA-Library;\n" + arithCustomMethods + "\n"; this.currentBuild_ = replacePlaceHolder(currentBuild_, ARITHMETIC_CUSTOM_METHODS, arithCustomMethods); } // insert generated testcase-functions this.currentBuild_ = replacePlaceHolder(currentBuild_, DYNAMIC_TEST_METHODS, testMethods); // set up file name String namePlaceholders = this.currentLanguageSpecification_.getOutputFileName(); String outputFileName = ""; String replaceIllegalChras = "[^0-9a-zA-Z]+"; String langExt = this.currentLanguageSpecification_.getExtension(); String langName = this.currentLanguageSpecification_.getOptionName().replaceAll(replaceIllegalChras, ""); langName = Character.toUpperCase(langName.charAt(0)) + langName.substring(1); String unitName = this.currentUnitTestLibrary_.getOptionName().replaceAll(replaceIllegalChras, ""); unitName = Character.toUpperCase(unitName.charAt(0)) + unitName.substring(1); String arithName = this.currentArithmeticLibrary_.getOptionName().replaceAll(replaceIllegalChras, ""); arithName = Character.toUpperCase(arithName.charAt(0)) + arithName.substring(1); if (namePlaceholders != null) { if (!namePlaceholders.trim().isEmpty()) { namePlaceholders = replacePlaceHolder(namePlaceholders, LANGUAGE_SPEC_NAME, langName); namePlaceholders = replacePlaceHolder(namePlaceholders, ARITHMETIC_SPEC_NAME, arithName); namePlaceholders = replacePlaceHolder(namePlaceholders, UNITTEST_SPEC_NAME, unitName); outputFileName = namePlaceholders + "." + langExt; } } // build filename for current language specification if (outputFileName.isEmpty()) { outputFileName = (langName + "_" + unitName + "_" + arithName).toLowerCase() .replaceAll(replaceIllegalChras, "_") + "." + langExt; } this.currentBuild_ = replacePlaceHolder(this.currentBuild_, LANGUAGE_SPEC_NAME, langName); this.currentBuild_ = replacePlaceHolder(this.currentBuild_, ARITHMETIC_SPEC_NAME, arithName); this.currentBuild_ = replacePlaceHolder(this.currentBuild_, UNITTEST_SPEC_NAME, unitName); File outputFile = new File(this.outputFolder_, outputFileName); try { // if old file exists, backup it with current time in // filename if (outputFile.exists()) { backUpOldFile(outputFile); } // write file this.currentFileWriter_ = new BufferedWriter( new OutputStreamWriter(new FileOutputStream(new File(outputFolder_, outputFileName)))); if (log.length() > 2) { this.currentLogWriter_ = new BufferedWriter(new OutputStreamWriter( new FileOutputStream(new File(outputFolder_, outputFileName + ".log")))); this.currentLogWriter_.write(log.toString()); this.currentLogWriter_.flush(); } this.currentFileWriter_.write(currentBuild_.toString()); this.currentFileWriter_.flush(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } this.currentTypeTranslation_ = currentLanguageSpecification_.getTypesTranslation(); } } try { if (this.currentLogWriter_ != null) { this.currentLogWriter_.close(); } if (this.currentFileWriter_ != null) { this.currentFileWriter_.close(); return true; } } catch (IOException e) { e.printStackTrace(); } return false; } private boolean checkOperationForMixType(Operation operation) { List<GenericParameter<?>> input = operation.getInputList(); List<GenericParameter<?>> output = operation.getOutputList(); boolean isMixedType = (checkParameterForMixedType(input) || checkParameterForMixedType(output)); this.currentMixedType = operation.getMixedType(); if (this.currentMixedType != null && output.size() == 1) { if (output.get(0).hasType(Interval.class)) { Interval<?> interval = (Interval<?>) output.get(0).getValue(); if (!interval.hasType(this.currentMixedType)) { throw new IllegalArgumentException("\nERROR: Operation with name: \"" + operation.getName() + "\" was declared with mixed types,\nbut doesn't use the declared output-parameter-type: " + this.currentMixedType.getSimpleName() + "\n"); } } } if (this.currentMixedType != null) { if (!isMixedType) { System.err.println("NOTICE: Operation with name: \"" + operation.getName() + "\" was declared with mixed types,\nbut actually has no mixed types!\n"); } } else { } return isMixedType; } private boolean checkParameterForMixedType(List<GenericParameter<?>> parameter) { for (int i = 0; i < parameter.size(); i++) { GenericParameter<?> input = parameter.get(i); if (input.hasType(Interval.class)) { Interval<?> interval = (Interval<?>) input.getValue(); if (this.currentMixedType == null) { this.currentMixedType = interval.getTypeClass(); } else if (!interval.hasType(this.currentMixedType)) { return true; } } } return false; } /** * Get blockcomment for given operation. * * @param op * the operation * @return blockcomment containing operation-infos */ private String getOperationComment(Operation op) { StringBuffer comment = new StringBuffer(); comment.append(getSingleCommentTag("name", op.getName())); comment.append(getSingleCommentTag("description", op.getDescription())); comment.append(getSingleCommentTag("required", String.valueOf(op.isRequired()))); return comment.toString(); } /** * Get first blockcomment of generated unit-test-file. * * @return blockcomment with parser and dsl-information */ private String getHeadComment() { StringBuffer comment = new StringBuffer(); comment.append(this.lineComment_ + " " + StringUtils.repeat("*", 60) + "\n"); comment.append(getSingleCommentTag("parser_description", DSL_PARSER_DESCRIPTION)); comment.append(getSingleCommentTag("parser_authors", DSL_PARSER_AUTHORS)); comment.append(getSingleCommentTag("parser_version", DSL_PARSER_VERSION)); comment.append(this.lineComment_ + " " + StringUtils.repeat("*", 60) + "\n"); comment.append(getSingleCommentTag("dsl_description", this.dslDescription_)); comment.append(getSingleCommentTag("dsl_authors", this.dslAuthors_)); comment.append(getSingleCommentTag("dsl_version", this.dslVersion_)); comment.append(this.lineComment_ + " " + StringUtils.repeat("*", 60) + "\n"); return comment.toString(); } /** * Generates single comment-string. * * @param description * given description * @param commentString * given comment string * @return single comment-string */ private String getSingleCommentTag(String description, String commentString) { String tag = ""; if (commentString != null) { if (!commentString.trim().isEmpty()) { tag = this.lineComment_ + " @" + description + "\n" + this.lineComment_ + " \t\t" + commentString.trim().replace("\n", "\n" + this.lineComment_ + " \t\t") + "\n"; } } return tag; } /** * Assemles an assert function. * * @param type * current type * @param expectedOutputName * expected result * @param outputName * actual result * @return assert-function as string */ private String getAssertFunctionForInterval(String type, String expectedOutputName, String outputName, Set set, boolean negate) { String first_lower_limit_name = "lo_" + expectedOutputName; String second_lower_limit_name = "lo_" + outputName; String first_upper_limit_name = "hi_" + expectedOutputName; String second_upper_limit_name = "hi_" + outputName; String first_lower_limit_def = currentOperationsTranslationTable_.get("intervalLowerLimit") .replace(outputType(1), type).replace(outputName(1), first_lower_limit_name) .replace(inputName(1), expectedOutputName); String second_lower_limit_def = currentOperationsTranslationTable_.get("intervalLowerLimit") .replace(outputType(1), type).replace(outputName(1), second_lower_limit_name) .replace(inputName(1), outputName); String first_upper_limit_def = currentOperationsTranslationTable_.get("intervalUpperLimit") .replace(outputType(1), type).replace(outputName(1), first_upper_limit_name) .replace(inputName(1), expectedOutputName); String second_upper_limit_def = currentOperationsTranslationTable_.get("intervalUpperLimit") .replace(outputType(1), type).replace(outputName(1), second_upper_limit_name) .replace(inputName(1), outputName); if (negate) { negate = !negate; if (set == Set.PROPER_SUBSET) { set = Set.SUPERSET; } else if (set == Set.SUBSET) { set = Set.PROPER_SUPERSET; } else if (set == Set.PROPER_SUPERSET) { set = Set.SUBSET; } else if (set == Set.SUPERSET) { set = Set.PROPER_SUBSET; } } String lower_limit_test = getAssertString(first_lower_limit_name, second_lower_limit_name, set, negate); if (set != null) { negate = !negate; } String upper_limit_test = getAssertString(first_upper_limit_name, second_upper_limit_name, set, negate); return ("\n" + first_lower_limit_def + "\n" + second_lower_limit_def + "\n" + lower_limit_test + "\n" + first_upper_limit_def + "\n" + second_upper_limit_def + "\n" + upper_limit_test + "\n"); } /** * Assembles an assert function for an empty interval. * * @param expectedOutputName * expected result * @param outputName * actual result * @return assert-function as string */ private String getAssertFunctionForEmptyInterval(String expectedOutputName, String outputName, Set set, boolean negate) { String bool_expected = "bool_" + expectedOutputName; String bool_output = "bool_" + outputName; String type = this.currentTypeTranslation_.get(Boolean.class)[0]; String translation = currentOperationsTranslationTable_.get("is_empty"); if (translation != null) { String first_lower_limit_def = currentOperationsTranslationTable_.get("is_empty") .replace(outputType(1), type).replace(outputName(1), bool_expected) .replace(inputName(1), expectedOutputName); String second_lower_limit_def = currentOperationsTranslationTable_.get("is_empty") .replace(outputType(1), type).replace(outputName(1), bool_output) .replace(inputName(1), outputName); String lower_limit_test = getAssertString(bool_expected, bool_output, set, negate); return ("\n" + first_lower_limit_def + "\n" + second_lower_limit_def + "\n" + lower_limit_test + "\n"); } else { return "\n" + this.lineComment_ + " ERROR: is_empty-method not implemented\n"; } } /** * Assembles an assert function for an entire interval. * * @param expectedOutputName * expected result * @param outputName * actual result * @return assert-function as string */ private String getAssertFunctionForEntireInterval(String expectedOutputName, String outputName, Set set, boolean negate) { String bool_expected = "bool_" + expectedOutputName; String bool_output = "bool_" + outputName; String type = this.currentTypeTranslation_.get(Boolean.class)[0]; String translation = currentOperationsTranslationTable_.get("is_entire"); if (translation != null) { String first_lower_limit_def = currentOperationsTranslationTable_.get("is_entire") .replace(outputType(1), type).replace(outputName(1), bool_expected) .replace(inputName(1), expectedOutputName); String second_lower_limit_def = currentOperationsTranslationTable_.get("is_entire") .replace(outputType(1), type).replace(outputName(1), bool_output) .replace(inputName(1), outputName); String lower_limit_test = getAssertString(bool_expected, bool_output, set, negate); return ("\n" + first_lower_limit_def + "\n" + second_lower_limit_def + "\n" + lower_limit_test + "\n"); } else { return "\n" + this.lineComment_ + " ERROR: is_entire-method not implemented\n"; } } /** * General method to assemble assert-function. * * @param first * expected output * @param second * actual output * @return assert function as string */ private String getAssertString(String first, String second, Set set, boolean negate) { String assertString = currentUnitTestLibrary_.getAssertFunction(set, negate); assertString = assertString.replace(EXPECTED_OUTPUT, first); assertString = assertString.replace(CALCULATED_OUTPUT, second); return assertString; } /** * Get one parameter declaration for a give GenericParameter-String. * * @param par * the GenericParameter to build parameter string for. * @param name * name of parameter * @return translated parameter-string */ private String getParameterString(GenericParameter<?> par, String name) { return getParameterString(par.getTypeClass(), par, name); } /** * Get one parameter declaration for a give GenericParameter-String. * * @param type * type of parameter * @param par * the GenericParameter to build parameter string for. * @param name * name of parameter * @return translated parameter-string */ private String getParameterString(Class<?> type, GenericParameter<?> par, String name) { String[] translation = null; String parameter = null; if (par.hasType(Endpoints.class)) { Endpoints card = (Endpoints) par.getValue(); if (card == Endpoints.NEGATIVE_INFINITY) { translation = currentNegativeInfinityTable_.get(type); } if (card == Endpoints.POSITIVE_INFINITY) { translation = currentPositiveInfinityTable_.get(type); } } else { translation = currentTypeTranslation_.get(type); } if (translation != null) { parameter = translation[1]; parameter = parameter.replace(TYPE, translation[0]); parameter = parameter.replace(NAME, name); if (par.hasType(Endpoints.class)) { parameter = parameter.replace(TYPE, translation[0]); } else if (par.hasType(FloatingPoint.class)) { String fl; if (littleEndian_ == null) { fl = ((FloatingPoint) par.getValue()).getHexCodeForCurrentSystem(); } else if (littleEndian_ == true) { fl = ((FloatingPoint) par.getValue()).getHexCodeLittleEndian(); } else { fl = ((FloatingPoint) par.getValue()).getHexCodeBigEndian(); } parameter = parameter.replace(VALUE, fl); } else if (par.hasType(Boolean.class)) { String value = currentBooleanTranslation_.get(par.getValue()); parameter = parameter.replace(VALUE, value); } else if (par.hasType(Number.class)) { parameter = parameter.replace(VALUE, String.valueOf((Number) par.getValue())); } } return parameter + "\n"; } /** * Get interval declaration. * * @param interval * given interval * @param name * name of interval * @param empty * specifies, if interval is empty * @return interval string */ private String getNewIntervalString(Interval<?> interval, String name, boolean empty, boolean entire) { String declaration = ""; String inputType = currentTypeTranslation_.get(interval.getTypeClass())[0]; if (empty) { if (currentEmptyIntervalTranslation_.length == 2) { declaration += currentEmptyIntervalTranslation_[1]; declaration = declaration.replace(PARAM_TYPE, currentEmptyIntervalTranslation_[0]); declaration = declaration.replace(INTERVAL_TYPE, inputType); declaration = declaration.replace(INTERVAL_NAME, name) + "\n"; } else { declaration += this.lineComment_ + " ERROR: empty intervals are not implemented!\n"; } return declaration; } else if (entire) { if (currentEntireIntervalTranslation_.length == 2) { declaration += currentEntireIntervalTranslation_[1]; declaration = declaration.replace(PARAM_TYPE, currentEntireIntervalTranslation_[0]); declaration = declaration.replace(INTERVAL_TYPE, inputType); declaration = declaration.replace(INTERVAL_NAME, name) + "\n"; } else { declaration += this.lineComment_ + " ERROR: entire intervals are not implemented!\n"; } return declaration; } GenericParameter<?> lowerLimit = null; GenericParameter<?> upperLimit = null; if (interval.getLower_limit() != null) { lowerLimit = new GenericParameter<Object>(interval.getLower_limit()); } else { lowerLimit = new GenericParameter<Object>(interval.getLowerEndpoint()); } if (interval.getUpper_limit() != null) { upperLimit = new GenericParameter<Object>(interval.getUpper_limit()); } else { upperLimit = new GenericParameter<Object>(interval.getUpperEndpoint()); } String inputLowerName = name + "_lower"; String inputUpperName = name + "_upper"; declaration += getParameterString(interval.getTypeClass(), lowerLimit, inputLowerName); declaration += getParameterString(interval.getTypeClass(), upperLimit, inputUpperName); String[] intervalTranslation = currentTypeTranslation_.get(Interval.class); declaration += intervalTranslation[1]; declaration = declaration.replace(PARAM_TYPE, intervalTranslation[0]); declaration = declaration.replace(INTERVAL_TYPE, inputType); declaration = declaration.replace(INTERVAL_NAME, name); declaration = declaration.replace(LOWER_VALUE, inputLowerName); declaration = declaration.replace(UPPER_VALUE, inputUpperName) + "\n"; return declaration; } /** * Function to replace one PlaceHolder-String in current unit-test. * * @param original * original string, to replace PlaceHolder in. * @param placeholder * PlaceHolder-string * @param insert * new string to replace PlaceHolder with. * @return new modified string */ private String replacePlaceHolder(String original, String placeholder, String insert) { Pattern variable = Pattern.compile( "\\" + getID() + "(\\{[st]{1}_[0-9]*\\})?" + placeholder.replace(getID(), "") + "\\" + getID(), Pattern.CASE_INSENSITIVE); Matcher variableMatcher = variable.matcher(original); while (variableMatcher.find()) { String var = variableMatcher.group(); Pattern spacePattern = Pattern.compile("\\{[st]{1}_[0-9]*\\}", Pattern.CASE_INSENSITIVE); Matcher spaceMatcher = spacePattern.matcher(var); if (spaceMatcher.find()) { String spaceIndicator = spaceMatcher.group(); String spaceVar = spaceIndicator.replaceAll("[\\{\\}ts_]", ""); String space = ""; if (spaceIndicator.contains("{t_")) { space = StringUtils.repeat("\t", Short.valueOf(spaceVar)); } else if (spaceIndicator.contains("{s_")) { space = StringUtils.repeat(" ", Short.valueOf(spaceVar)); } insert = space + insert.replace("\n", "\n" + space); if (insert.endsWith(space)) { insert = insert.substring(0, insert.length() - space.length()); } } original = original.replace(var, insert); } return original; } /** * back up old generated files * * @param file * old file to backup */ private void backUpOldFile(File file) { long datetime = file.lastModified(); Date d = new Date(datetime); SimpleDateFormat sdf = new SimpleDateFormat("yyyy_MM_dd-hh_mm_ss"); String dateString = sdf.format(d); File temp = new File(file.getParent() + File.separator + dateString + "-" + file.getName() + ".bak"); if (temp.exists()) temp.delete(); file.renameTo(temp); } }