/* This file is part of EasyTest CodeGen, a project to generate JUnit test cases from source code in EasyTest Template format and helping to keep them in sync during refactoring. EasyTest CodeGen, a tool provided by EaseTech Organization Under Apache License 2.0 http://www.apache.org/licenses/LICENSE-2.0.txt */ package org.easetech.easytest.codegen; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.StringTokenizer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.sun.javadoc.ClassDoc; import com.sun.javadoc.DocErrorReporter; import com.sun.javadoc.Doclet; import com.sun.javadoc.PackageDoc; import com.sun.javadoc.RootDoc; /** * An extension of {@link Doclet} for the EasyTest code generation. * This class's start() is first invoked when javadoc task is executed. * javadoc parses the source java classes from the input package directory and pass it to this customised Doclet. * This class is responsible for generating JUnit test cases in EasyTest/Customised template. * It invokes TestingStrategy classes for generating test cases and writing strategy classes for writing those to files * * @author Ravi Polampelli * */ public class JUnitDoclet extends Doclet implements JUnitDocletProperties { /** * An instance of logger associated. */ protected static final Logger LOG = LoggerFactory.getLogger(JUnitDoclet.class); protected static final String OPTION_INPUT_DIR = "-sourcepath"; protected static final String OPTION_OUTPUT_DIR = "-d"; protected static final String OPTION_PROPERTIES = "-properties"; protected static final String OPTION_TESTING = "-testing"; protected static final String OPTION_WRITING = "-writing"; protected static final String OPTION_NAMING = "-naming"; protected static final String OPTION_BUILDALL = "-buildall"; protected static final String OPTION_HELP = "-help"; protected static final String OPTION_SUBPACKAGE = "-subpackage"; protected static final String OPTION_TEST_IN_TEST = "-testintest"; protected static final String OPTION_STRICT = "-strict"; protected static final String OPTION_FILTER_PROPERTIES = "-filterProperties"; protected static final String OPTION_LOADER_TYPE = "-loaderType"; protected static final String OPTION_SEED_DATA = "-seedData"; /* JunitDoclet can't support looking for source files in class path. See javadoc tools documentation */ // default source path must be "" to support filesets, since there no // source path is set. Taking the current path in this case is an error // since the real source path of the files could be something different. protected static final String DEFAULT_SOURCE_PATH = ""; protected static final String USAGE_STRING = "Parameters of EasyTest CodeGen \n"+ "-d <out_dir> (required)\n"+ " Where to write the JUnit-Tests\n"+ "\n"+ "-subpackage <sub_package_name> (optional)\n"+ " Use a sub package to have the tests close to the\n"+ " application but separate. Usualy the sub-package is named \"test\".\n"+ "\n"+ "-buildall (optional)\n"+ " All tests are rebuild, even if application is unchanged.\n"+ "\n"+ "-properties <property_file_name> (optional)\n"+ " Holding all templates and definitions\n"+ " (default is junit4.properties)\n"+ "\n"+ "-naming <naming_strategy_class_name> (optional)\n"+ " Strategy class to define names\n"+ " (default is org.easetech.easytest.codegen.NamingStrategy)\n"+ "\n"+ "-writing <writing_strategy_class_name> (optional)\n"+ " Strategy class handle file access\n"+ " default is org.easetech.easytest.codegen.WritingStrategy)\n"+ "\n"+ "-testing <testing_strategy_class_name> (optional)\n"+ " Strategy class build the tests\n"+ " default is org.easetech.easytest.codegen.TestingStrategy)\n"+ "\n"+ "-testintest (optional)\n"+ " Generate TestCase for all classes that can be found in source path.\n"+ " If set, tests will be generated for all classes that are not \n"+ " TestCases or TestSuites themselves, even if they are in a \n"+ " test subpackage. This option is NOT recommended.\n"+ "\n"+ "-strict (optional)\n"+ " Promote every warning to an error. This option is helpfull to keep\n"+ " the regeneration process working during refactorings.\n"+ " Typical warnings would be:\n"+ " * any not empty testVault method\n"+ " * any missing marker (usually \"// JUnitDoclet begin import\")\n"; private String sourcePath; private String outputRoot; private INamingStrategy namingStrategy; private IWritingStrategy writingStrategy; private ITestingStrategy testingStrategy; private String namingStrategyName; private String writingStrategyName; private String testingStrategyName; private String propertyFileName; private String filterPropertyFileName; private String loaderType; private String seedDataFileName; private String subPackage; private boolean buildAll; private boolean testInTest; private boolean strict; private DocErrorReporter docErrorReporter; public JUnitDoclet() { super(); init(); } public void init() { LOG.info("init started"); setBuildAll(false); setTestInTest(false); setStrict(false); setSourcePath(null); setOutputRoot(null); setNamingStrategy(null); setWritingStrategy(null); setTestingStrategy(null); setNamingStrategyName("org.easetech.easytest.codegen.NamingStrategy"); setWritingStrategyName("org.easetech.easytest.codegen.WritingStrategy"); setTestingStrategyName("org.easetech.easytest.codegen.TestingStrategy"); setPropertyFileName(ConfigurableStrategy.DEFAULT_PROPERTY_FILE_NAME); setLoaderType(ConfigurableStrategy.DEFAULT_LOADER_TYPE); setSeedDataFileName(null); setSubPackage(null); LOG.info("init finished"); } public String getSourcePath() { return sourcePath; } public void setSourcePath(String theSourcePath) { sourcePath = theSourcePath; } public String getOutputRoot() { return outputRoot; } public void setOutputRoot(String outputRoot) { this.outputRoot = outputRoot; } public String getPropertyFileName() { return propertyFileName; } public String getSeedDataFileName() { return seedDataFileName; } public String getFilterPropertyFileName() { return filterPropertyFileName; } public void setPropertyFileName(String propertyFileName) { this.propertyFileName = propertyFileName; getNamingStrategy().setPropertyFileName(propertyFileName); getWritingStrategy().setPropertyFileName(propertyFileName); getTestingStrategy().setPropertyFileName(propertyFileName); } private void setFilterPropertyFileName(String propertyFileName) { this.filterPropertyFileName = propertyFileName; getNamingStrategy().setFilterPropertyFileName(propertyFileName); getWritingStrategy().setFilterPropertyFileName(propertyFileName); getTestingStrategy().setFilterPropertyFileName(propertyFileName); } public String getLoaderType() { return loaderType; } public void setLoaderType(String loaderType) { this.loaderType = loaderType; } public void setSeedDataFileName(String seedDataFileName) { this.seedDataFileName = seedDataFileName; getNamingStrategy().setSeedDataFileName(seedDataFileName); getWritingStrategy().setSeedDataFileName(seedDataFileName); getTestingStrategy().setSeedDataFileName(seedDataFileName); } public INamingStrategy getNamingStrategy() { if (namingStrategy == null) { setNamingStrategy((INamingStrategy) createByClassName(getNamingStrategyName())); } return namingStrategy; } public void setNamingStrategy(INamingStrategy namingStrategy) { this.namingStrategy = namingStrategy; if (namingStrategy != null) { namingStrategy.setPropertyFileName(getPropertyFileName()); namingStrategy.setSubPackage(getSubPackage()); namingStrategy.setTestInTest(isTestInTest()); } } public IWritingStrategy getWritingStrategy() { if (writingStrategy == null) { setWritingStrategy((IWritingStrategy) createByClassName(getWritingStrategyName())); } return writingStrategy; } public void setWritingStrategy(IWritingStrategy writingStrategy) { this.writingStrategy = writingStrategy; if (writingStrategy != null) { writingStrategy.setPropertyFileName(getPropertyFileName()); } } public ITestingStrategy getTestingStrategy() { if (testingStrategy == null) { setTestingStrategy((ITestingStrategy) createByClassName(getTestingStrategyName())); } return testingStrategy; } public void setTestingStrategy(ITestingStrategy testingStrategy) { this.testingStrategy = testingStrategy; if (testingStrategy != null) { testingStrategy.setPropertyFileName(getPropertyFileName()); } } public String getNamingStrategyName() { return namingStrategyName; } public void setNamingStrategyName(String namingStrategyName) { this.namingStrategyName = namingStrategyName; setNamingStrategy(null); } public String getWritingStrategyName() { return writingStrategyName; } public void setWritingStrategyName(String writingStrategyName) { this.writingStrategyName = writingStrategyName; setWritingStrategy(null); } public String getTestingStrategyName() { return testingStrategyName; } public void setTestingStrategyName(String testingStrategyName) { this.testingStrategyName = testingStrategyName; setTestingStrategy(null); } public boolean isBuildAll() { return buildAll; } public void setBuildAll(boolean buildAll) { this.buildAll = buildAll; } public boolean isTestInTest() { return testInTest; } public void setTestInTest(boolean testInTest) { this.testInTest = testInTest; } public String getSubPackage() { return subPackage; } public void setSubPackage(String subPackage) { this.subPackage = subPackage; getNamingStrategy().setSubPackage(subPackage); } private Object createByClassName(String className) { Object returnValue = null; Class clazz; try { clazz = Class.forName(className); returnValue = clazz.newInstance(); } catch (Exception e) { // not a valid class name } return returnValue; } /** * method to process package level information and creates a test suite for all the test classes. * * @param testSuiteVO contains package docs. * @param index to represent the package among the all packageDocs. * @param reporter * @return */ public boolean processPackage( TestSuiteVO testSuiteVO, int index, DocErrorReporter reporter) { LOG.info("processPackage started, index:"+index); boolean returnValue = true; StringBuffer newCode, oldCode; String fullTestSuiteName; ITestingStrategy testing; IWritingStrategy writing; INamingStrategy naming; testing = getTestingStrategy(); writing = getWritingStrategy(); naming = getNamingStrategy(); String testSuiteExtention = testing.getProperties().getProperty(TESTSUITE_EXTENSION); if(testSuiteExtention != null && !"".equals(testSuiteExtention)){ naming.setTEST_SUITE_EXT(testSuiteExtention); } if (testing.isTestablePackage(testSuiteVO.getPackageDocs()[index], naming)) { fullTestSuiteName = naming.getFullTestSuiteName(testSuiteVO.getPackageDocs()[index].name()); oldCode = writing.loadClassSource(getOutputRoot(), fullTestSuiteName); if ((oldCode == null) || testing.isValid(oldCode.toString())) { newCode = new StringBuffer(); testSuiteVO.setNaming(naming); testSuiteVO.setNewCode(newCode); testSuiteVO.setProperties(testing.getProperties()); System.out.println("testSuiteVO.getTestClasses():"+testSuiteVO.getTestClasses()); returnValue = testing.codeTestSuite(testSuiteVO, index); if (testing.isValid(newCode.toString())) { writing.indent(newCode); if (testing.merge(newCode, oldCode, fullTestSuiteName)) { if (isWritingNeeded(newCode, oldCode)) { reporter.printNotice("Writing TestSuite "+fullTestSuiteName+"."); writing.writeClassSource(getOutputRoot(), fullTestSuiteName, newCode); testSuiteVO.getTestSuiteClasses().add(fullTestSuiteName); } // no else } // no else } else { reporter.printError("Could not generate TestSuite "+fullTestSuiteName+ " (possible reason: missing or wrong properties)."); } } else { if (oldCode != null) { reporter.printWarning("TestSuite "+fullTestSuiteName+ " is invalid. It's not overwritten."); } } } LOG.info("processPackage finished, returnValue:"+returnValue); return returnValue; } /** * Method to process the classdoc and creates a test case for each class doc as for configuration. * It internally uses TestingStrategy class to create the test case * It writes the test case and test data to appropriate folder, and it uses WritingStrategy for that. * * @param doc is ClassDoc instance * @param packageDoc * @param reporter * @param testSuiteVO * @return */ public boolean processClass(ClassDoc doc, PackageDoc packageDoc, DocErrorReporter reporter, TestSuiteVO testSuiteVO) { LOG.info("processClass started, ClassDoc:"+doc); boolean returnValue = true; StringBuffer oldCode, newCode; String fullTestCaseName; String fullClassName; ITestingStrategy testing; IWritingStrategy writing; INamingStrategy naming; testing = getTestingStrategy(); writing = getWritingStrategy(); naming = getNamingStrategy(); if (packageDoc == null) { packageDoc = doc.containingPackage(); } fullClassName = doc.qualifiedTypeName(); String testCaseExtention = testing.getProperties().getProperty(TESTCASE_EXTENSION); if(testCaseExtention != null && !"".equals(testCaseExtention)){ naming.setTEST_CASE_EXT(testCaseExtention); } fullTestCaseName = naming.getFullTestCaseName(fullClassName); if (testing.isTestableClass(doc, naming)) { // generate TestCase only if it does not exist or is older than application class. if (isGenerationNeeded(fullClassName, fullTestCaseName)) { LOG.debug("getOutputRoot():"+getOutputRoot()); LOG.debug("fullTestCaseName:"+fullTestCaseName); oldCode = writing.loadClassSource(getOutputRoot(), fullTestCaseName); LOG.debug("oldCode:"+oldCode); if ((oldCode == null) ||testing.isValid(oldCode.toString())) { newCode = new StringBuffer(); StringBuffer sourceCode = writing.loadSourceClassSource(fullClassName,getSourcePath()); Map<String, StringBuffer> convertersMap = new HashMap<String,StringBuffer>(); TestCaseVO testCaseVO = new TestCaseVO(packageDoc, doc,naming,testing.getProperties(), convertersMap,new HashMap<String, List<Map<String, Object>>>(), sourceCode,newCode,new HashMap<String, List<String>>()); System.out.println("getLoaderType:"+getLoaderType()); testCaseVO.setLoaderType(StringHelper.getLoaderTypeFromExtension(getLoaderType())); returnValue = testing.codeTestCase(testCaseVO); if (testing.isValid(newCode.toString())) { writing.indent(newCode); if (isWritingNeeded(newCode, oldCode)) { reporter.printNotice("Writing TestCase "+fullTestCaseName+"."); writing.writeClassSource(getOutputRoot(), fullTestCaseName, newCode); LOG.debug("writeTestDataFile testData:"+testCaseVO.getTestData()); //creating test data xls writing.writeTestDataFile(getOutputRoot(), fullTestCaseName, testCaseVO,testing.getSeedData()); //generating converter classes LOG.debug("convertersMap:"+convertersMap); String testPackageName = fullTestCaseName.substring(0, fullTestCaseName.lastIndexOf(".")); //check the property overwrite converters, if yes then only generate the converters code String overwriteConverters = testCaseVO.getProperties().getProperty(OVERWRITE_EXISTING_CONVERTERS); writing.writeConverterSources(getOutputRoot(),testPackageName,convertersMap,overwriteConverters); testSuiteVO.getTestClasses().add(fullTestCaseName); } else { reporter.printNotice("TestCase "+fullTestCaseName+ " did not change but "+fullClassName+" did."); } } else { reporter.printError("Could not generate TestCase "+fullTestCaseName+ " (possible reason: missing or wrong properties)."); } } else { if (oldCode != null) { reporter.printWarning("TestCase "+fullTestCaseName+ " is invalid. It's not overwritten."); } } } else { // Do not regenerate TestCase. returnValue = true; } } else { // Do not generate test case. returnValue = true; } LOG.info("processClass finished, returnValue:"+returnValue); return returnValue; } /** * Checks if file of application class is modified later than TestCase file. * * @param fullClassName * @param fullTestCaseName * @return */ public boolean isGenerationNeeded(String fullClassName, String fullTestCaseName) { LOG.info("isGenerationNeeded started, fullClassName:"+fullClassName+" ,fullTestCaseName"+fullTestCaseName); boolean returnValue; returnValue = isBuildAll(); returnValue = returnValue || !getWritingStrategy().isExistingAndNewer(getOutputRoot(), fullTestCaseName, getSourcePath(), fullClassName); LOG.info("isGenerationNeeded finished, returnValue:"+returnValue); return returnValue; } /** * Checks if anything changed in the test case/class then decides whether to write that or not. * * @param newCode * @param oldCode * @return */ public boolean isWritingNeeded(StringBuffer newCode, StringBuffer oldCode) { LOG.info("isWritingNeeded started, newCode:"+newCode); boolean returnValue; returnValue = isBuildAll(); returnValue = returnValue || (oldCode == null); returnValue = returnValue || ((newCode != null) && (oldCode != null) && (!newCode.toString().equals(oldCode.toString()))); LOG.info("isWritingNeeded finished, returnValue:"+returnValue); return returnValue; } /** * This class is invoked first by Doclet after parsing the source code files * and encapsulate the meta-information in a RootDoc and pass it as parameter * * @param RootDoc doc encapsulated meta-information about source code */ public static boolean start(RootDoc doc) { LOG.info("start started, RootDoc:"+doc); JUnitDoclet instance; instance = new JUnitDoclet(); instance.setOptions(doc.options()); instance.setDocErrorReporter(doc); LOG.info("instanceExecute started, RootDoc:"+doc); //execute the instance boolean instanceExecute = instance.execute(doc); LOG.info("instanceExecute finished,"+instanceExecute); return instanceExecute; } public void setDocErrorReporter(DocErrorReporter doc) { docErrorReporter = doc; getNamingStrategy().setDocErrorReporter(doc); getWritingStrategy().setDocErrorReporter(doc); getTestingStrategy().setDocErrorReporter(doc); } /** * Execute the root doc * It fetches the package doc and class doc and invokes corresponding process methods. * * @param RootDoc doc encapsulated meta-information about source code */ public boolean execute(RootDoc doc) { boolean returnValue = true; PackageDoc[] packageDocs; ClassDoc[] classDocs; DocErrorReporter reporter; reporter = createErrorReporter(isStrict()); if (reporter != null) { reporter.printNotice("Generating TestSuites and TestCases."); packageDocs = doc.specifiedPackages(); classDocs = doc.specifiedClasses(); TestSuiteVO testSuiteVO = new TestSuiteVO(packageDocs,new ArrayList<String>()); for (int j = 0; j < classDocs.length; j++) { LOG.debug("specifiedClasses processing"); returnValue = returnValue && processClass(classDocs[j], null, reporter,testSuiteVO); } testSuiteVO.setTestSuiteClasses(new ArrayList<String>()); LOG.debug("specifiedPackages processing"); //traversing in reverse direction so that generation of test cases for sub packages(if specified) will happen first //and then goes up in hierarchy till base package. for (int i = packageDocs.length-1; i >= 0; i--) { //for sub packages no need to include upper level test cases, hence making them null. // to create new test suite for sub packages. //if( i > 0){ testSuiteVO.setTestClasses(new ArrayList<String>()); //} returnValue = returnValue && processPackageClasses(packageDocs[i],testSuiteVO,reporter); returnValue = returnValue && processPackage(testSuiteVO, i, reporter); /* String packageDocSpecified = packageDocs[i].name().replace('.', '/'); File file = new File(getSourcePath(),packageDocSpecified); LOG.debug("packageDocSpecified"+packageDocSpecified); LOG.debug("specified package/file name:"+file.getAbsolutePath()); if(file.isDirectory() && generateSubpackageTestCases ){ File[] packagesAndClasses = file.listFiles(); LOG.debug("packagesAndClasses:"+packagesAndClasses.length); for(File packagesOrClass:packagesAndClasses){ LOG.debug("packagesOrClass:"+packagesOrClass); if(packagesOrClass.isDirectory()){ //System.out.println("processing this package through javadoc execute:"+packagesOrClass); String subPackage = packageDocs[i].name()+"."+packagesOrClass.getName(); LOG.debug("processing this subPackage :"+subPackage); /*PackageDoc subPackageDoc = doc.packageNamed(subPackage); System.out.println("subPackageDoc:"+subPackageDoc.name()); ClassDoc[] allClasses = subPackageDoc.allClasses(); System.out.println("allClasses size"+allClasses.length); System.out.println("subPackageDoc is packageDoc"+subPackageDoc.commentText()); PackageDoc[] subPackageDocs = new PackageDoc[1]; subPackageDocs[0] = subPackageDoc; TestSuiteVO testSubPackageSuiteVO = new TestSuiteVO(subPackageDocs,new ArrayList<String>()); returnValue = returnValue && processPackageClasses(subPackageDoc, testSubPackageSuiteVO, reporter); returnValue = returnValue && processPackage(testSubPackageSuiteVO, 0, reporter); *//* LOG.debug("processing this subPackage through javadoc execute:"+subPackage); String[] javadocargs = {subPackage,"-d", getOutputRoot(), "-sourcepath", getSourcePath(), "-doclet", "org.easetech.easytest.codegen.JUnitDoclet", "-properties",getPropertyFileName(), "-classpath","maven.compile.classpath", "",""}; if(getSeedDataFileName() != null) { int arrLen = javadocargs.length; Arrays.fill(javadocargs,arrLen-2,arrLen-1,"-seedData"); Arrays.fill(javadocargs,arrLen-1,arrLen,getSeedDataFileName()); } int returnIntValue = com.sun.tools.javadoc.Main.execute(javadocargs); LOG.debug("returnIntValue"+returnIntValue); if(returnIntValue >= 0){ returnValue = returnValue && true; } else { returnValue = returnValue && false; } } } }*/ } } return returnValue; } private boolean processPackageClasses(PackageDoc packageDoc, TestSuiteVO testSuiteVO, DocErrorReporter reporter) { LOG.debug("processPackageClasses started"); ClassDoc[] classDocs; boolean returnValue = true; classDocs = packageDoc.ordinaryClasses(); LOG.debug("No.of class docs"+classDocs.length); for (int j = 0; j < classDocs.length; j++) { System.out.println("processClass started for"+classDocs[j].name()); returnValue = returnValue && processClass(classDocs[j], packageDoc, reporter,testSuiteVO); } LOG.debug("processPackageClasses finished with value"+returnValue); return returnValue; } protected DocErrorReporter createErrorReporter(boolean strict) { DocErrorReporter result; result = new StrictDocErrorReporter(strict); return result; } /** * This method sets the options provided as Java arguments to JavaDoc execute method. * @param options array of argument name and values */ public void setOptions(String[][] options) { for (int i = 0; (i < options.length); i++) { if (options[i][0].equals(OPTION_BUILDALL)) { setBuildAll(true); } if (options[i][0].equals(OPTION_STRICT)) { setStrict(true); } if (options[i][0].equals(OPTION_TEST_IN_TEST)) { setTestInTest(true); } if (options[i][0].equals(OPTION_INPUT_DIR)) { setSourcePath(options[i][1]); } if (options[i][0].equals(OPTION_OUTPUT_DIR)) { setOutputRoot(options[i][1]); } if (options[i][0].equals(OPTION_SUBPACKAGE)) { setSubPackage(options[i][1]); } if (options[i][0].equals(OPTION_PROPERTIES)) { setPropertyFileName(options[i][1]); } if (options[i][0].equals(OPTION_FILTER_PROPERTIES)) { setFilterPropertyFileName(options[i][1]); } if (options[i][0].equals(OPTION_LOADER_TYPE)) { setLoaderType(options[i][1]); } if (options[i][0].equals(OPTION_SEED_DATA)) { setSeedDataFileName(options[i][1]); } if (options[i][0].equals(OPTION_TESTING)) { setTestingStrategyName(options[i][1]); } if (options[i][0].equals(OPTION_WRITING)) { setWritingStrategyName(options[i][1]); } if (options[i][0].equals(OPTION_NAMING)) { setNamingStrategyName(options[i][1]); } } } public static int optionLength(String s) { int returnValue = 0; if (s.equals(OPTION_HELP)) { printUsage(); } else if (s.equals(OPTION_BUILDALL)) { returnValue = 1; } else if (s.equals(OPTION_STRICT)) { returnValue = 1; } else if (s.equals(OPTION_TEST_IN_TEST)) { returnValue = 1; } else if (s.equals(OPTION_OUTPUT_DIR)) { returnValue = 2; } else if (s.equals(OPTION_PROPERTIES)) { returnValue = 2; } else if (s.equals(OPTION_SUBPACKAGE)) { returnValue = 2; } else if (s.equals(OPTION_TESTING)) { returnValue = 2; } else if (s.equals(OPTION_WRITING)) { returnValue = 2; } else if (s.equals(OPTION_NAMING)) { returnValue = 2; } else if (s.equals(OPTION_SEED_DATA)) { returnValue = 2; } else if (s.equals(OPTION_LOADER_TYPE)) { returnValue = 2; } // no else return returnValue; } public static boolean validOptions(String[][] parameters, DocErrorReporter reporter) { LOG.debug("validOptions started"+parameters); boolean returnValue = true; boolean foundOutput = false; boolean isTestInTest = false; String subPackage = null; String sourcePath = DEFAULT_SOURCE_PATH; String outputPath = null; for (String[] parameter : parameters) { System.out.println("parameter:"+parameter[0]); if (parameter[0].equals(OPTION_OUTPUT_DIR)) { if (!ValidationHelper.isDirectoryName(parameter[1])) { returnValue = false; if (reporter != null) { reporter.printError("Error:" + parameter[1] + " is not a directory."); } } else { outputPath = parameter[1]; } foundOutput = true; } if (parameter[0].equals(OPTION_INPUT_DIR)) { sourcePath = parameter[1]; } if (parameter[0].equals(OPTION_TEST_IN_TEST)) { isTestInTest = true; } if (parameter[0].equals(OPTION_PROPERTIES)) { if (!ValidationHelper.isPropertyName(parameter[1])) { returnValue = false; if (reporter != null) { reporter.printError("Error:" + parameter[1] + " is not a property file."); } } } if (parameter[0].equals(OPTION_SEED_DATA)) { if (!ValidationHelper.isPropertyName(parameter[1])) { returnValue = false; if (reporter != null) { reporter.printError("Error:" + parameter[1] + " is not a property file."); } } } if (parameter[0].equals(OPTION_LOADER_TYPE)) { if (!ValidationHelper.isLoaderTypeName(parameter[1])) { returnValue = false; if (reporter != null) { reporter.printError("Error:" + parameter[1] + " is not a valid loader type."); } } } if (parameter[0].equals(OPTION_SUBPACKAGE)) { if (!ValidationHelper.isPackageName(parameter[1])) { returnValue = false; if (reporter != null) { reporter.printError("Error:" + parameter[1] + " is not a valid package name."); } } else { subPackage = parameter[1]; } } if (parameter[0].equals(OPTION_NAMING)) { if (!ValidationHelper.isClassName(parameter[1])) { returnValue = false; if (reporter != null) { reporter.printError("Error:" + parameter[1] + " is not a class."); } } } if (parameter[0].equals(OPTION_TESTING)) { if (!ValidationHelper.isClassName(parameter[1])) { returnValue = false; if (reporter != null) { reporter.printError("Error:" + parameter[1] + " is not a class."); } } } if (parameter[0].equals(OPTION_WRITING)) { if (!ValidationHelper.isClassName(parameter[1])) { returnValue = false; if (reporter != null) { reporter.printError("Error:" + parameter[1] + " is not a class."); } } } } returnValue = returnValue && foundOutput; // output path must not be in source path if no subpackage is specified if ((returnValue) && (subPackage == null) && !isTestInTest) { returnValue = !isOutputMatchingAnySource(sourcePath, outputPath, reporter); } return returnValue; } public static boolean isOutputMatchingAnySource(String sourcePath, String outputPath, DocErrorReporter reporter) { boolean returnValue = false; String canonicalSourcePath; String canonicalOutputPath = null; StringTokenizer sourcePathTokenizer = new StringTokenizer(sourcePath, File.pathSeparator); try { canonicalOutputPath = new File(outputPath).getCanonicalPath(); } catch (IOException e) { if (reporter != null) { reporter.printError("Error: File '" + outputPath + "' not found (" + e.toString() + ")."); } returnValue = true; } if (!returnValue && (canonicalOutputPath != null)) { while (sourcePathTokenizer.hasMoreTokens()) { try { canonicalSourcePath = new File(sourcePathTokenizer.nextToken()).getCanonicalPath(); if (canonicalOutputPath.equals(canonicalSourcePath)) { returnValue = true; } } catch (IOException e) { // ignore non existent elements in classpath } } if (returnValue) { if (reporter != null) { reporter.printError("Error: value of " + OPTION_OUTPUT_DIR + " must not be in value of " + OPTION_INPUT_DIR + ".\n" + "You may override this restriction with " + OPTION_TEST_IN_TEST + "."); } } } return returnValue; } private static void printUsage() { System.out.println(USAGE_STRING); } public boolean isStrict() { return strict; } public void setStrict(boolean strict) { this.strict = strict; } }