diff --git a/.classpath b/.classpath index 6d488d7cbbf8..f648ca63c5ff 100644 --- a/.classpath +++ b/.classpath @@ -1,6 +1,10 @@ - - - - - - + + + + + + + + + + diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 000000000000..43cf4920bd13 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,21 @@ +* text eol=lf +*.gif binary +*.GIF binary +*.jar binary +*.png binary +*.jpg binary +*.svg text eol=lf + +# These files do not have unix line endings. Do not normalize them for now. +# Will fix these right before we cut JUnit 4.13. +/src/main/java/org/junit/experimental/categories/CategoryFilterFactory.java -text +/src/main/java/org/junit/experimental/categories/ExcludeCategories.java -text +/src/main/java/org/junit/experimental/categories/IncludeCategories.java -text +/src/main/java/org/junit/internal/Classes.java -text +/src/main/java/org/junit/runner/FilterFactories.java -text +/src/main/java/org/junit/runner/FilterFactory.java -text +/src/main/java/org/junit/runner/FilterFactoryParams.java -text +/src/main/java/org/junit/runner/JUnitCommandLineParseResult.java -text +/src/test/java/org/junit/experimental/categories/CategoryFilterFactoryTest.java -text +/src/test/java/org/junit/runner/FilterFactoriesTest.java -text +/src/test/java/org/junit/runner/JUnitCommandLineParseResultTest.java -text diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000000..54f5aa75e33f --- /dev/null +++ b/.gitignore @@ -0,0 +1,13 @@ +MaxCore.ser +bin +junit4.* +target +MaxCore.max +# IntelliJ +.idea +*.ipr +*.iml +*.iws +out +java.hprof.txt +.DS_Store diff --git a/.mvn/wrapper/maven-wrapper.jar b/.mvn/wrapper/maven-wrapper.jar new file mode 100755 index 000000000000..41c70a7e0b7d Binary files /dev/null and b/.mvn/wrapper/maven-wrapper.jar differ diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties new file mode 100755 index 000000000000..37cb61582de0 --- /dev/null +++ b/.mvn/wrapper/maven-wrapper.properties @@ -0,0 +1 @@ +distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.1.1/apache-maven-3.1.1-bin.zip \ No newline at end of file diff --git a/.project b/.project index 42fab9b65f39..88756880f282 100644 --- a/.project +++ b/.project @@ -1,24 +1,18 @@ - - - junit - - - - - - org.eclipse.jdt.core.javabuilder - - - - - com.agitar.eclipse.project.agitatorbuilder - - - - - - org.eclipse.jdt.core.javanature - org.eclipse.team.cvs.core.cvsnature - com.agitar.eclipse.project.agitatornature - - + + + junit + + + + + + org.eclipse.jdt.core.javabuilder + + + + + + org.eclipse.jdt.core.javanature + org.eclipse.team.cvs.core.cvsnature + + diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 000000000000..d54f4c25de99 --- /dev/null +++ b/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,357 @@ +#Mon Oct 12 21:57:10 EDT 2009 +eclipse.preferences.version=1 +org.eclipse.jdt.core.codeComplete.argumentPrefixes= +org.eclipse.jdt.core.codeComplete.argumentSuffixes= +org.eclipse.jdt.core.codeComplete.fieldPrefixes=f +org.eclipse.jdt.core.codeComplete.fieldSuffixes= +org.eclipse.jdt.core.codeComplete.localPrefixes= +org.eclipse.jdt.core.codeComplete.localSuffixes= +org.eclipse.jdt.core.codeComplete.staticFieldPrefixes= +org.eclipse.jdt.core.codeComplete.staticFieldSuffixes= +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=1.5 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.doc.comment.support=enabled +org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.autoboxing=ignore +org.eclipse.jdt.core.compiler.problem.comparingIdentical=warning +org.eclipse.jdt.core.compiler.problem.deadCode=warning +org.eclipse.jdt.core.compiler.problem.deprecation=warning +org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled +org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled +org.eclipse.jdt.core.compiler.problem.discouragedReference=ignore +org.eclipse.jdt.core.compiler.problem.emptyStatement=ignore +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.problem.fallthroughCase=ignore +org.eclipse.jdt.core.compiler.problem.fatalOptionalError=enabled +org.eclipse.jdt.core.compiler.problem.fieldHiding=ignore +org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning +org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning +org.eclipse.jdt.core.compiler.problem.forbiddenReference=error +org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning +org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning +org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=ignore +org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=ignore +org.eclipse.jdt.core.compiler.problem.invalidJavadoc=warning +org.eclipse.jdt.core.compiler.problem.invalidJavadocTags=disabled +org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsDeprecatedRef=disabled +org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsNotVisibleRef=disabled +org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsVisibility=protected +org.eclipse.jdt.core.compiler.problem.localVariableHiding=ignore +org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning +org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=warning +org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=ignore +org.eclipse.jdt.core.compiler.problem.missingJavadocComments=ignore +org.eclipse.jdt.core.compiler.problem.missingJavadocCommentsOverriding=disabled +org.eclipse.jdt.core.compiler.problem.missingJavadocCommentsVisibility=protected +org.eclipse.jdt.core.compiler.problem.missingJavadocTagDescription=no_tag +org.eclipse.jdt.core.compiler.problem.missingJavadocTags=ignore +org.eclipse.jdt.core.compiler.problem.missingJavadocTagsOverriding=disabled +org.eclipse.jdt.core.compiler.problem.missingJavadocTagsVisibility=protected +org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=warning +org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning +org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=ignore +org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning +org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning +org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=ignore +org.eclipse.jdt.core.compiler.problem.nullReference=warning +org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning +org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore +org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=ignore +org.eclipse.jdt.core.compiler.problem.potentialNullReference=ignore +org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning +org.eclipse.jdt.core.compiler.problem.redundantNullCheck=ignore +org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=warning +org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled +org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning +org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled +org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore +org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning +org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning +org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore +org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning +org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore +org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=warning +org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=warning +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled +org.eclipse.jdt.core.compiler.problem.unusedImport=warning +org.eclipse.jdt.core.compiler.problem.unusedLabel=warning +org.eclipse.jdt.core.compiler.problem.unusedLocal=warning +org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore +org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled +org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled +org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled +org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning +org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning +org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning +org.eclipse.jdt.core.compiler.source=1.5 +org.eclipse.jdt.core.compiler.taskCaseSensitive=enabled +org.eclipse.jdt.core.compiler.taskPriorities=NORMAL,NORMAL,HIGH,NORMAL +org.eclipse.jdt.core.compiler.taskTags=TODO,REVISIT,HACK,QUESTION +org.eclipse.jdt.core.formatter.align_type_members_on_columns=false +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16 +org.eclipse.jdt.core.formatter.alignment_for_assignment=0 +org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16 +org.eclipse.jdt.core.formatter.alignment_for_compact_if=16 +org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80 +org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0 +org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16 +org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16 +org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16 +org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16 +org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16 +org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16 +org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16 +org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16 +org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16 +org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16 +org.eclipse.jdt.core.formatter.blank_lines_after_imports=1 +org.eclipse.jdt.core.formatter.blank_lines_after_package=1 +org.eclipse.jdt.core.formatter.blank_lines_before_field=1 +org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0 +org.eclipse.jdt.core.formatter.blank_lines_before_imports=1 +org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1 +org.eclipse.jdt.core.formatter.blank_lines_before_method=1 +org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1 +org.eclipse.jdt.core.formatter.blank_lines_before_package=0 +org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1 +org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1 +org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line +org.eclipse.jdt.core.formatter.comment.clear_blank_lines=false +org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false +org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false +org.eclipse.jdt.core.formatter.comment.format_block_comments=true +org.eclipse.jdt.core.formatter.comment.format_comments=true +org.eclipse.jdt.core.formatter.comment.format_header=false +org.eclipse.jdt.core.formatter.comment.format_html=true +org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true +org.eclipse.jdt.core.formatter.comment.format_line_comments=true +org.eclipse.jdt.core.formatter.comment.format_source_code=true +org.eclipse.jdt.core.formatter.comment.indent_parameter_description=true +org.eclipse.jdt.core.formatter.comment.indent_root_tags=true +org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert +org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=insert +org.eclipse.jdt.core.formatter.comment.line_length=80 +org.eclipse.jdt.core.formatter.compact_else_if=true +org.eclipse.jdt.core.formatter.continuation_indentation=2 +org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2 +org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false +org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true +org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true +org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true +org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true +org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true +org.eclipse.jdt.core.formatter.indent_empty_lines=false +org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true +org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true +org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true +org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=false +org.eclipse.jdt.core.formatter.indentation.size=4 +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_member=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert +org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert +org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert +org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert +org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert +org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert +org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert +org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert +org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert +org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert +org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert +org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert +org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert +org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert +org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert +org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false +org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false +org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false +org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false +org.eclipse.jdt.core.formatter.lineSplit=80 +org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false +org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false +org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0 +org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1 +org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true +org.eclipse.jdt.core.formatter.tabulation.char=space +org.eclipse.jdt.core.formatter.tabulation.size=4 +org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false +org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true diff --git a/.settings/org.eclipse.jdt.ui.prefs b/.settings/org.eclipse.jdt.ui.prefs new file mode 100644 index 000000000000..dd34e34a0426 --- /dev/null +++ b/.settings/org.eclipse.jdt.ui.prefs @@ -0,0 +1,13 @@ +#Tue Jul 22 09:31:38 PDT 2008 +eclipse.preferences.version=1 +formatter_profile=_junit +formatter_settings_version=11 +internal.default.compliance=default +org.eclipse.jdt.ui.exception.name=e +org.eclipse.jdt.ui.gettersetter.use.is=true +org.eclipse.jdt.ui.ignorelowercasenames=true +org.eclipse.jdt.ui.importorder=java;javax;com; +org.eclipse.jdt.ui.keywordthis=false +org.eclipse.jdt.ui.ondemandthreshold=99 +org.eclipse.jdt.ui.overrideannotation=true +org.eclipse.jdt.ui.text.custom_code_templates= diff --git a/.travis.settings.xml b/.travis.settings.xml new file mode 100644 index 000000000000..332f39daa17b --- /dev/null +++ b/.travis.settings.xml @@ -0,0 +1,22 @@ + + + + central + GCS Maven Central mirror + https://maven-central.storage-download.googleapis.com/maven2/ + google-maven-central + + + + + junit-snapshot-repo + ${env.OSSRH_USERNAME} + ${env.OSSRH_PASSWORD} + + + junit-releases-repo + ${env.OSSRH_USERNAME} + ${env.OSSRH_PASSWORD} + + + diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 000000000000..5b1744397f29 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,69 @@ +dist: trusty + +language: java + +script: ./mvnw verify javadoc:javadoc site:site + +install: +- ./mvnw --version + +stages: + - test + - name: deploy + if: (branch = main) AND (NOT type IN (pull_request)) + +jobs: + include: + - name: Java 6 + env: JDK=openjdk6 + addons: + apt: + packages: + - openjdk-6-jdk + install: + # Download dependencies with JDK 8 because Mave Central supports + # TLS 1.2 only but OpenJDK 6 does not. + - export ORIGINAL_JAVA_HOME=$JAVA_HOME + - jdk_switcher use oraclejdk8 + - ./mvnw test -DskipTests + # Delete all files created with JDK 8 + - ./mvnw clean + # Restore desired JDK + - export JAVA_HOME=$ORIGINAL_JAVA_HOME + - jdk_switcher use openjdk6 + - ./mvnw --version + - name: Java 7 + jdk: openjdk7 + - name: Java 8 + jdk: oraclejdk8 + - name: Java 9 + jdk: oraclejdk9 + - name: Java 10 + jdk: openjdk10 + - name: Java 11 + jdk: openjdk11 + - stage: deploy + name: "Publish snapshot artifacts" + addons: + apt: + packages: + - openjdk-6-jdk + install: + # Download dependencies with JDK 8 because Mave Central supports + # TLS 1.2 only but OpenJDK 6 does not. + - export ORIGINAL_JAVA_HOME=$JAVA_HOME + - jdk_switcher use oraclejdk8 + - ./mvnw test -DskipTests + # Delete all files created with JDK 8 + - ./mvnw clean + # Restore desired JDK + - export JAVA_HOME=$ORIGINAL_JAVA_HOME + - jdk_switcher use openjdk6 + - ./mvnw --version + env: + - JDK=openjdk6 + # OSSRH_USERNAME + - secure: griGZYDtqDMRUaYex/uAnpkWIQ/yodM6IOn4G8izWKpyGLeCxyXBG0FDcVo81xRq/9mMevj2idyW/xNP/HAQ45G4pyJUk/vTSMkNslzVjr7OBEtQQCN8XahSaOO0l0CJ5lzA6LdwWg7uDaf9znqZ0slt81u0S1NJmUZyYeUEim0= + # OSSRH_PASSWORD + - secure: EM7Z2M09HvLJXYJaeD/YmeF5A6tqavG2tBBeDcFZ7C6k0AI/wApe882pEMMoUG06xufKfSlt7WFJxoyU3M+fPOpeK5qZpJQxsHWnNJwbcbKzqMpM9mDsgIL9rtAvm9MuIIbIY2spiT0Cx3sHdh5qofaJHPL/u8Or5L9tE8FV1ew= + script: ./mvnw deploy --batch-mode --activate-profiles generate-docs --settings .travis.settings.xml diff --git a/BUILDING b/BUILDING new file mode 100644 index 000000000000..496eeb03b820 --- /dev/null +++ b/BUILDING @@ -0,0 +1,14 @@ +BUILDING FROM GITHUB: +===================== + +git clone https://github.com/junit-team/junit4.git +cd junit4 +mvn install + +BUILDING FROM JARS OR ZIPS: +=========================== + +The contents of the zip and jar files are largely maintained for historical +reasons. We do not at this time have an official way to build from the src +jar or zip. If this is an important missing feature, please let us know +at http://github.com/junit-team/junit4/issues diff --git a/CODING_STYLE.txt b/CODING_STYLE.txt new file mode 100644 index 000000000000..fefecdd26f83 --- /dev/null +++ b/CODING_STYLE.txt @@ -0,0 +1,9 @@ +JUnit project uses the Google Java Style (https://github.com/google/styleguide) for all new +code (under org.junit.*). Deviating from this, indentation is 4 spaces instead of 2. + +Be sure to set text file encoding to UTF-8 and line delimiters to UNIX style. + +Since not all code has been formatted yet, please format only code lines you changed to avoid extraneous changes. + +Legacy code (under junit.*) used the legacy guide specified in LEGACY_CODING_STYLE.txt in the +project root. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 000000000000..1943d567915c --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,45 @@ +## Project License: Eclipse Public License v1.0 + +- You will only Submit Contributions where You have authored 100% of the content. +- You will only Submit Contributions to which You have the necessary rights. This means that if You are employed You have received the necessary permissions from Your employer to make the Contributions. +- Whatever content You Contribute will be provided under the Project License(s). + +## Coding Conventions + +### Formatting + +See [CODING_STYLE.txt](CODING_STYLE.txt) for how we format our code. + +## How to submit a pull request + +We love pull requests. Here is a quick guide: + +1. You need to have Maven and a JDK (at least version 1.5) installed. +2. [Fork the repo](https://help.github.com/articles/fork-a-repo). +3. [Create a new branch](https://help.github.com/articles/creating-and-deleting-branches-within-your-repository/) from `main`. +4. Ensure that you have a clean state by running `./mvnw verify`. +5. Add your change together with a test (tests are not needed for refactorings and documentation changes). +6. Format your code: Import the JUnit project in Eclipse and use its formatter or apply the rules in the `CODING_STYLE` file manually. Only format the code you've changed; reformatting unrelated code makes it harder for us to review your changes. +7. Run `./mvnw verify` again and ensure all tests are passing. +8. Push to your fork and [submit a pull request](https://help.github.com/articles/creating-a-pull-request/). + +Now you are waiting on us. We review your pull request and at least leave some comments. + + +Note that if you are thinking of providing a fix for one of the bugs or feature requests, it's usually +a good idea to add a comment to the bug to make sure that there's agreement on how we should proceed. + +## Limitations + +The JUnit team is not accepting changes to the code under the following paths: + +* `src/main/java/junit` +* `test/java/junit/tests/framework` +* `test/java/junit/tests/extensions` + +The reasoning is that the JUnit team feels that our users should focus on using either the JUnit4 or JUnit5 APIs. + +The team is also reluctant to accept changes that only update code from one code style to another. +Generally the code in JUnit was approved by at least one person, so two people agreed that the style was reasonable. + +To find other places where you can have an impact, please see the [Issues tagged "up-for-grabs"](https://github.com/junit-team/junit4/issues?q=is%3Aissue+is%3Aopen+label%3Aup-for-grabs). diff --git a/KEYS b/KEYS new file mode 100644 index 000000000000..0433e72f3343 --- /dev/null +++ b/KEYS @@ -0,0 +1,70 @@ +This file contains the PGP key that is used to sign releases. + +Importing: `pgp < KEYS` or `gpg --import KEYS` + +Adding a key: +`pgp -kxa >> KEYS`, +or `(pgpk -ll && pgpk -xa ) >> KEYS`, +or `(gpg --list-sigs && gpg --armor --export ) >> KEYS` + +================================ + +pub rsa4096 2018-04-08 [SC] + FF6E2C001948C5F2F38B0CC385911F425EC61B51 +uid [ unknown] Open Source Development +sig 3 85911F425EC61B51 2018-04-08 Open Source Development +sub rsa4096 2018-04-08 [E] +sig 85911F425EC61B51 2018-04-08 Open Source Development + +-----BEGIN PGP PUBLIC KEY BLOCK----- + +mQINBFrKW9IBEACkqUvM7hU1WqOOeb1gZ7pUsRliHuoUvYIrd+hdp+qhPmJ0NG0W +YhZK5UtJBmqvtHKRkbwYxUuya9zlBmCfQFf0GpFKJ65JSrPSkZADI3aZ4aUkxIUw +nIRoUHucmr10Xftpebr/zaJk5oR8RdaL5FapapmcZmAaHR9CDWB8XtI318u314jq +M5rKatnAZMERoPugOvvuAOz4bfZKwdfCmZKfYUM/TMSrSinXrGExSW6z4RhtqmpC +E5M/7OoVfvDynVJKqNazqgigpmMNhOyzAhQsiKh1K0akyxTZbjeZKsdYfhCXvq0q +k9+KM/cTllQ54MPnFWiObLkHeK0Waw8bI/vAJ4h4x/XM9iGYpkXv7F2/FVsHQdPe +YJcwD/CkD8KHyiPaRKMeApiUtZsdAHU0L4X/lNmcooea/7ipskruUgwcm+RdLhRZ +P949t1e7nqDZfpEHy90NiFxmlRAPSNqBLwefxY/hwBgog2jabDALJVcLCMosFWPj +MQhFlGSIODiVcW8folGIjzkyNZbNMWkwnl2QnWp/h2TAwYQJOMqcv2MG9o5pyzpx +97Iz1ngq1FlM/gJnGnNUydP2tAjT2L2U3MP1uX/EdRChdgPqdolqYhdFfwCr0Fpf +W527bUZpReHCEiQ29ABSnQ711mO+d9+qM6edRyHUoBWz89IHt8sCunuvNwARAQAB +tC1PcGVuIFNvdXJjZSBEZXZlbG9wbWVudCA8bWFpbEBtYXJjcGhpbGlwcC5kZT6J +Ak4EEwEIADgWIQT/biwAGUjF8vOLDMOFkR9CXsYbUQUCWspb0gIbAwULCQgHAgYV +CAkKCwIEFgIDAQIeAQIXgAAKCRCFkR9CXsYbUQyRD/9xm3BqdpWcRCE5UyB6nbwV +8TgzMmbOhpFhhcjzobly/pKAbcofKsjhreENJkfBVUo+zAFx21ToC5tbH20wRtIE +vQVCP6sAIzhYWU1ohafqVFP4+PztNBuYTnS6vGvSwzp0IXLIIoxSxo0IOED9uUS9 +DTxh1n9NnDLDe2pfjrXBblQtLSW3W5ISDoUvcoyO7Hk1OByW6MNsSoLvXIUNeVhB +ju9TfYxFACJSWBhUxJfgip9Y2GrNBJaYGLZrTAoW1Lh1H1DfLV3wHDClQ1+H+oyx +IOZULEGYY3MgZTd6Ner2yNAUCB7gVa50NiCZXCS74m+XzMrTEsdWjSMUaOe+dL0I +9MCrgi4ycUHWIfTKx9gGlIOo3hSDMN+8Nj33XPjLT8kcfoFeUX8jTOvC1HFfTuQJ +x2t/dKHizdrS3F6A/JQa7v8GNTrZFnEXkwgRTf3ccLoo3gPwzNJeCm2xNjvne1VH +fvxzwNmq8M05oicEigvEed2VMStMhvT7dSiMAf66rEJHjjaHAoNqbLDEATYrWUP2 +I52txHSSxSJohxVP6Ec6dERnqqYi0mVyzBPo7mmFFBisq74w8RvZXyzvXE3BTiDL +we1E/Z/AXbtJye9DickQ/G6RFtVLbUHQfzyRS/65JPtlH8rqJr58YWlylGImVLwE +OsKNQrwLZ0UkfaWV7wqr3rkCDQRaylvSARAAnQG636wliEOLkXN662OZS6Qz2+cF +ltCWboq9oX9FnA1PHnTY2cAtwS214RfWZxkjg6Stau+d1Wb8TsF/SUN3eKRSyrkA +xlX0v552vj3xmmfNsslQX47e6aEWZ0du0M8jw7/f7Qxp0InkBfpQwjSg4ECoH4cA +6dOFJIdxBv8dgS4K90HNuIHa+QYfVSVMjGwOjD9St6Pwkbg1sLedITRo59Bbv0J1 +4nE9LdWbCiwNrkDr24jTewdgrDaCpN6msUwcH1E0nYxuKAetHEi2OpgBhaY3RQ6Q +PQB6NywvmD0xRllMqu4hSp70pHFtm8LvJdWOsJ5we3KijHuZzEbBVTTl+2DhNMI0 +KMoh+P/OmyNOfWD8DL4NO3pVv+mPDZn82/eZ3XY1/oSQrpyJaCBjRKasVTtfiA/F +gYqTml6qZMjy6iywg84rLezELgcxHHvjhAKd4CfxyuCCgnGT0iRLFZKw44ZmOUqP +DkyvGRddIyHag1K7UaM/2UMn6iPMy7XWcaFiH5Huhz43SiOdsWGuwNk4dDxHdxmz +Sjps0H5dkfCciOFhEc54AFcGEXCWHXuxVqIq/hwqTmVl1RY+PTcQUIOfx36WW1ix +JQf8TpVxUbooK8vr1jOFF6khorDXoZDJNhI2VKomWp8Y38EPGyiUPZNcnmSiezx+ +MoQwAbeqjFMKG7UAEQEAAYkCNgQYAQgAIBYhBP9uLAAZSMXy84sMw4WRH0JexhtR +BQJaylvSAhsMAAoJEIWRH0JexhtR0LEP/RvYGlaokoosAYI5vNORAiYEc1Ow2McP +I1ZafHhcVxZhlwF48dAC2bYcasDX/PbEdcD6pwo8ZU8eI8Ht0VpRQxeV/sP01m2Y +EpAuyZ6jI7IQQCGcwQdN4qzQJxMAASl9JlplH2NniXV1/994FOtesT59ePMyexm5 +7lzhYXP1PGcdt8dH37r6z3XQu0lHRG/KBn7YhyA3zwJcno324KdBRJiynlc7uqQq ++ZptU9fR1+Nx0uoWZoFMsrQUmY34aAOPJu7jGMTG+VseMH6vDdNhhZs9JOlD/e/V +aF7NyadjOUD4j/ud7c0z2EwqjDKMFTHGbIdawT/7jartT+9yGUO+EmScBMiMuJUT +dCP4YDh3ExRdqefEBff3uE/rAP73ndNYdIVq9U0gY0uSNCD9JPfj4aCN52y9a2pS +7Dg7KB/Z8SH1R9IWP+t0HvVtAILdsLExNFTedJGHRh7uaC7pwRz01iivmtAKYICz +ruqlJie/IdEFFK/sus6fZek29odTrQxx42HGHO5GCNyEdK9jKVAeuZ10vcaNbuBp +iP7sf8/BsiEU4wHE8gjFeUPRiSjnERgXQwfJosLgf/K/SShQn2dCkYZRNF+SWJ6Z +2tQxcW5rpUjtclV/bRVkUX21EYfwA6SMB811mI7AVy8WPXCe8La72ukmaxEGbpJ8 +mdzS2PJko7mm +=l0XA +-----END PGP PUBLIC KEY BLOCK----- diff --git a/LEGACY_CODING_STYLE.txt b/LEGACY_CODING_STYLE.txt new file mode 100644 index 000000000000..81e553b31f45 --- /dev/null +++ b/LEGACY_CODING_STYLE.txt @@ -0,0 +1,132 @@ +================================== +Coding style +================================== + +---------------------------------- +Tabs and Indents +---------------------------------- +* Tab size : 4 +* Indent : 4 +* Continuation indent : 8 +* Label indent : 0 + +> Don't use tab characters. + +---------------------------------- +Spaces +---------------------------------- +Before Parentheses +* if parentheses +* for parentheses +* while parentheses +* switch parentheses +* try parentheses +* catch parentheses +* synchronized parentheses + +Around Operators +* Assignment operators (=, +=, …) +* Logical operators (&&, ||) +* Equality operators (==, !=) +* Relational operators (<, >, <=, >=) +* Bitwise operators (&, |, ^) +* Additive operators (+, -) +* Multiplicative operators (*, /, %) +* Shift operators (<<, >>, >>>) + +Before Left Brace +* Class left brace +* Method left brace +* if left brace +* else left brace +* for left brace +* while left brace +* do left brace +* switch left brace +* try left brace +* catch left brace +* finally left brace +* synchronized left brace + +Before Keywords +* else keyword +* while keyword +* catch keyword +* finally keyword + +In Ternary Operator (?:) +* Before ? +* After ? +* Before : +* After : + +Within Type Arguments +* After comma + +Other +* After comma +* After semicolon +* After type cast + +---------------------------------- +Wrapping and Braces +---------------------------------- +Braces placement +* In class declaration : End of line +* In method declaration : End of line +* Other : End of line + +Use Of Braces +* if() statement : When multiline +* for() statement : When multiline +* while() statement : When multiline +* do .. while() statement : When multiline + +Annotations +* Class annotations : Wrap always +* Method annotations : Wrap always +* Field annotations : Wrap always +* Parameter annotations : Do not wrap +* Local variable annotations : Do not wrap + +---------------------------------- +Blank Lines +---------------------------------- +Minimum Blank Lines +* Before package statement : 0 +* After package statement : 1 +* Before imports : 1 +* After imports : 1 +* Around class : 1 +* After class header : 0 +* After anonymous class header : 0 +* Around field in interface : 0 +* Around field : 0 +* Around method in interface : 1 +* Around method : 1 +* Before method body : 0 + +---------------------------------- +JavaDoc +---------------------------------- +Alignment +* Align thrown exception descriptions + +Blank Lines +* After description + +Other +* Enable leading asterisks +* Use @throws rather than @exception +* Keep empty lines + +---------------------------------- +Imports +---------------------------------- +import static (all other imports) + +import java.* +import javax.* +import com.* + +import (all other imports) diff --git a/LICENSE-junit.txt b/LICENSE-junit.txt new file mode 100644 index 000000000000..fb686291a055 --- /dev/null +++ b/LICENSE-junit.txt @@ -0,0 +1,214 @@ +JUnit + +Eclipse Public License - v 1.0 + +THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC +LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM +CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. + +1. DEFINITIONS + +"Contribution" means: + + a) in the case of the initial Contributor, the initial code and + documentation distributed under this Agreement, and + b) in the case of each subsequent Contributor: + + i) changes to the Program, and + + ii) additions to the Program; + + where such changes and/or additions to the Program originate from and are +distributed by that particular Contributor. A Contribution 'originates' from a +Contributor if it was added to the Program by such Contributor itself or anyone +acting on such Contributor's behalf. Contributions do not include additions to +the Program which: (i) are separate modules of software distributed in +conjunction with the Program under their own license agreement, and (ii) are +not derivative works of the Program. + +"Contributor" means any person or entity that distributes the Program. + +"Licensed Patents " mean patent claims licensable by a Contributor which are +necessarily infringed by the use or sale of its Contribution alone or when +combined with the Program. + +"Program" means the Contributions distributed in accordance with this Agreement. + +"Recipient" means anyone who receives the Program under this Agreement, +including all Contributors. + +2. GRANT OF RIGHTS + + a) Subject to the terms of this Agreement, each Contributor hereby grants +Recipient a non-exclusive, worldwide, royalty-free copyright license to +reproduce, prepare derivative works of, publicly display, publicly perform, +distribute and sublicense the Contribution of such Contributor, if any, and +such derivative works, in source code and object code form. + + b) Subject to the terms of this Agreement, each Contributor hereby grants +Recipient a non-exclusive, worldwide, royalty-free patent license under +Licensed Patents to make, use, sell, offer to sell, import and otherwise +transfer the Contribution of such Contributor, if any, in source code and +object code form. This patent license shall apply to the combination of the +Contribution and the Program if, at the time the Contribution is added by the +Contributor, such addition of the Contribution causes such combination to be +covered by the Licensed Patents. The patent license shall not apply to any +other combinations which include the Contribution. No hardware per se is +licensed hereunder. + + c) Recipient understands that although each Contributor grants the +licenses to its Contributions set forth herein, no assurances are provided by +any Contributor that the Program does not infringe the patent or other +intellectual property rights of any other entity. Each Contributor disclaims +any liability to Recipient for claims brought by any other entity based on +infringement of intellectual property rights or otherwise. As a condition to +exercising the rights and licenses granted hereunder, each Recipient hereby +assumes sole responsibility to secure any other intellectual property rights +needed, if any. For example, if a third party patent license is required to +allow Recipient to distribute the Program, it is Recipient's responsibility to +acquire that license before distributing the Program. + + d) Each Contributor represents that to its knowledge it has sufficient +copyright rights in its Contribution, if any, to grant the copyright license +set forth in this Agreement. + +3. REQUIREMENTS + +A Contributor may choose to distribute the Program in object code form under +its own license agreement, provided that: + + a) it complies with the terms and conditions of this Agreement; and + + b) its license agreement: + + i) effectively disclaims on behalf of all Contributors all warranties and +conditions, express and implied, including warranties or conditions of title +and non-infringement, and implied warranties or conditions of merchantability +and fitness for a particular purpose; + + ii) effectively excludes on behalf of all Contributors all liability for +damages, including direct, indirect, special, incidental and consequential +damages, such as lost profits; + + iii) states that any provisions which differ from this Agreement are +offered by that Contributor alone and not by any other party; and + + iv) states that source code for the Program is available from such +Contributor, and informs licensees how to obtain it in a reasonable manner on +or through a medium customarily used for software exchange. + +When the Program is made available in source code form: + + a) it must be made available under this Agreement; and + + b) a copy of this Agreement must be included with each copy of the +Program. + +Contributors may not remove or alter any copyright notices contained within the +Program. + +Each Contributor must identify itself as the originator of its Contribution, if +any, in a manner that reasonably allows subsequent Recipients to identify the +originator of the Contribution. + +4. COMMERCIAL DISTRIBUTION + +Commercial distributors of software may accept certain responsibilities with +respect to end users, business partners and the like. While this license is +intended to facilitate the commercial use of the Program, the Contributor who +includes the Program in a commercial product offering should do so in a manner +which does not create potential liability for other Contributors. Therefore, if +a Contributor includes the Program in a commercial product offering, such +Contributor ("Commercial Contributor") hereby agrees to defend and indemnify +every other Contributor ("Indemnified Contributor") against any losses, damages +and costs (collectively "Losses") arising from claims, lawsuits and other legal +actions brought by a third party against the Indemnified Contributor to the +extent caused by the acts or omissions of such Commercial Contributor in +connection with its distribution of the Program in a commercial product +offering. The obligations in this section do not apply to any claims or Losses +relating to any actual or alleged intellectual property infringement. In order +to qualify, an Indemnified Contributor must: a) promptly notify the Commercial +Contributor in writing of such claim, and b) allow the Commercial Contributor +to control, and cooperate with the Commercial Contributor in, the defense and +any related settlement negotiations. The Indemnified Contributor may +participate in any such claim at its own expense. + +For example, a Contributor might include the Program in a commercial product +offering, Product X. That Contributor is then a Commercial Contributor. If that +Commercial Contributor then makes performance claims, or offers warranties +related to Product X, those performance claims and warranties are such +Commercial Contributor's responsibility alone. Under this section, the +Commercial Contributor would have to defend claims against the other +Contributors related to those performance claims and warranties, and if a court +requires any other Contributor to pay any damages as a result, the Commercial +Contributor must pay those damages. + +5. NO WARRANTY + +EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR +IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, +NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each +Recipient is solely responsible for determining the appropriateness of using +and distributing the Program and assumes all risks associated with its exercise +of rights under this Agreement, including but not limited to the risks and +costs of program errors, compliance with applicable laws, damage to or loss of +data, programs or equipment, and unavailability or interruption of operations. + +6. DISCLAIMER OF LIABILITY + +EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY +CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST +PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY +WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS +GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + +7. GENERAL + +If any provision of this Agreement is invalid or unenforceable under applicable +law, it shall not affect the validity or enforceability of the remainder of the +terms of this Agreement, and without further action by the parties hereto, such +provision shall be reformed to the minimum extent necessary to make such +provision valid and enforceable. + +If Recipient institutes patent litigation against any +entity (including a cross-claim or counterclaim in a lawsuit) alleging that the +Program itself (excluding combinations of the Program with other software or +hardware) infringes such Recipient's patent(s), then such Recipient's rights +granted under Section 2(b) shall terminate as of the date such litigation is +filed. + +All Recipient's rights under this Agreement shall terminate if it fails to +comply with any of the material terms or conditions of this Agreement and does +not cure such failure in a reasonable period of time after becoming aware of +such noncompliance. If all Recipient's rights under this Agreement terminate, +Recipient agrees to cease use and distribution of the Program as soon as +reasonably practicable. However, Recipient's obligations under this Agreement +and any licenses granted by Recipient relating to the Program shall continue +and survive. + +Everyone is permitted to copy and distribute copies of this Agreement, but in +order to avoid inconsistency the Agreement is copyrighted and may only be +modified in the following manner. The Agreement Steward reserves the right to +publish new versions (including revisions) of this Agreement from time to time. +No one other than the Agreement Steward has the right to modify this Agreement. +The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation may assign the responsibility to +serve as the Agreement Steward to a suitable separate entity. Each new version +of the Agreement will be given a distinguishing version number. The Program +(including Contributions) may always be distributed subject to the version of +the Agreement under which it was received. In addition, after a new version of +the Agreement is published, Contributor may elect to distribute the Program +(including its Contributions) under the new version. Except as expressly stated +in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to +the intellectual property of any Contributor under this Agreement, whether +expressly, by implication, estoppel or otherwise. All rights in the Program not +expressly granted under this Agreement are reserved. + +This Agreement is governed by the laws of the State of New York and the +intellectual property laws of the United States of America. No party to this +Agreement will bring a legal action under this Agreement more than one year +after the cause of action arose. Each party waives its rights to a jury trial +in any resulting litigation. + diff --git a/NOTICE.txt b/NOTICE.txt new file mode 100644 index 000000000000..69b4faf86b2b --- /dev/null +++ b/NOTICE.txt @@ -0,0 +1,5 @@ + =================================================================================== + == Notices and attributions required by libraries that the project depends on == + =================================================================================== + + The JUnit depends on Java Hamcrest (http://hamcrest.org/JavaHamcrest/). diff --git a/README.html b/README.html deleted file mode 100644 index df6f10f3eacf..000000000000 --- a/README.html +++ /dev/null @@ -1,736 +0,0 @@ - - - - - - - JUnit 3.8 - - -

-JUnit -3.8.2

-
-
-11/11/2004
-
- -

-Summary of Changes -between 3.8.1 and 3.8.2

-The changes between the versions are minimal and -the focus was on fixing the accumulated bug reports. The most -signifanct change is replacing the much-reviled string comparison -format with something easier to read and use.
-
-
    -
  • ComparisonFailure shows context. 
    -
  • -
      -
    • assertEquals("Mary had a little lamb", "Mary had the little -lamb") shows: expected:<Mary had [a] little lamb> but -was:<Mary had [the] little lamb>
      -Longer prefixes and suffixes are truncated to a fixed size (currently -20):
    • -
    • expected:<...st of the emergency [broadcasting] -system> but was:<...st of the emergency [locating] system>
      -
    • -
    -
  • Running single tests.  -junit.ui.TestRunner can be invoked with "-m ClassName.testName" -to run a single test.
  • -
  • TestSuite(Class[]).  -There is a new TestSuite constructor that takes an array of classes as -a parameter and returns a suite of suites, each of which is constructed -from a single class.
  • -
-

Closed Bugs/Patches and Enhancment -Requests
-

- -

Summary of Changes between 3.8 and 3.8.1

- -

-Summary of Changes between 3.7 and 3.8

-

-Framework

-
    -
  • - Made the string argument TestCase constructor -optional. You can now delete -constructors of the form "FooTestCase(String name) { super(name); }".
  • -
  • - Deleted deprecated assert(boolean) in favor -of assertTrue(boolean) and -assertFalse(boolean). To migrate to JUnit 3.8, rename calls to -assert(boolean) -to call assertTrue(boolean).
  • -
  • - Added assertFalse() to avoid the difficult of -reading the assertTrue(! -condition).
  • -
  • - Added assertNotSame(Object, Object).
  • -
  • - Deleted deprecated TestCase.name() in favor -of TestCase.getName().
  • -
  • - Deleted deprecated package junit.ui in favor -of junit.awtui.
  • -
-

-Test Runner

-
    -
  • - When you compare two long strings with a -small delta embedded in the middle, it -is hard to spot the difference. In 3.8, when you call -assertEquals(String, -String), only the differences between the strings are displayed. The -common -prefix and suffix are replaced with "...".
  • -
  • - Added initial version of a TestRunListener -attached to TestRunners which -eventually will replace TestListeners attached to the TestResult.
  • -
  • - Filled in ActiveTestSuite constructors.
  • -
  • - Added these packages to the -excluded.properties: -
      -
    • org.w3c.dom.*
    • -
    • org.xml.sax.*
    • -
    • net.jini.*
    • -
    -
  • -
  • Extracted textual formatting of a -TestResult from junit.textui.TestRunner into ResultPrinter.
  • -
-

Documentation

-
    -
  • Much improved FAQ -thanks to Mike Clark.
  • -
    -
-

Closed Bugs

- -

-Summary of Changes between 3.6 and 3.7

-

-GUI

-
    -
  • - Eliminated warning when re-running tests when -class loading checkbox is -unchecked. There are legitimate reasons for doing this, so a warning -didn't -make much sense, and it was too obtrusive.
  • -
  • - Stopped reloading classes when running in -VisualAge for Java.
  • -
  • - Print total number of tests as well as number -of tests run so far (Swing -only).
  • -
-

-Framework

-
    -
  • - Introduced Assert.assertTrue(boolean) and -assertTrue(String, boolean) deprecated -assert(boolean) and assert(String, boolean) in preparation for the -assert -keyword in Java 1.4. We plan to support native assertions when they are -publicly available. You can either move to assertTrue() or wait for 1.4 -and delete parentheses as the syntax is e.g. "assert 2 == 3".
  • -
  • - Added accessors for TestCase.fName and -TestSuite.fName.
  • -
  • - Added a no argument TestCase constructor to -support serialization.
  • -
  • - Improved warnings when constructing -TestSuites.
  • -
-

-Text Runner

-
    -
  • - Made doRun() public so clients can create a -text runner with a specified -output stream and then run tests.
  • -
-

-Fixed Bugs (SourceForge Bug Tracker Ids)

-    [420315] No trace when fail -with message... -
-    [419375] reload warning lags -
-    [418849] Classloader warning too obtrusive -
-    [417978] constructor stack trace, please -
-    [415103] Reload checkbox should be ignored in VAJ -
-    [414954] error reporting when invoking suite() -
-    [407296] Make doRun() public -
-    [227578] rmi callbacks fail since TestCase has no -noArg constructor -
-    [422603] Decorated decorators bug -
-

Summary of Changes between 3.5 and 3.6

-

-TestRunner

-
    -
  • - The UI test runners provide a check box to -enable/disable the custom class -loader. The user is warned when running a second test with the non -loading -class loader.
  • -
  • - Renames to address file name length -limitation on MacOS:
  • -
      -
    • - LoadingClassPathTestCollector -> -LoadingTestCollector
    • -
    • - SimpleClassPathTestCollector -> -SimpleTestCollector
    • -
    -
-

-Framework

-
    -
  • - Added TestSuite.getName()
  • -
-

-Builds

-
    -
  • - Updated the build script for Ant 1.3.
  • -
-

-Fixed Bugs (SourceForge Bug Tracker Ids)

-
[ #229753 ] assertEquals on NaN and -Infinity does not work -correctly -
-[ #229287 ] Class Name too long "SimpleClassPathTestCollector" -
-[ #229609 ] Stack Filtering missing in textui.TesRunner -
-[ #229870 ] Clicking on ... after tests failed gives NPE -
-[ #229974 ] Incorrect icon shown for first element in Swing GUI -
-[ #230581 ] swingui.TestTreeModel: results of decorated testcases... -
-[ #230971 ] Make junit.extensions.TestDecorator.getTest() public -
-[ #231569 ] DocBug: JUnit Test Infected: Programmers Love Writing Tests -
-[ #232645 ] BaseTestRunner.getTest loses exception information -
-[ #233094 ] TestSuite masks exceptions -
-[ #410967 ] No icon provided for first test -
-[ #230745 ] ClassPathTestCollector sometimes lists classes in duplicate
-

-Documentation

-
    -
  • - Added documentation about the properties -supported by TestRunners.
  • -
  • - Updated the FAQ
  • -
-

-Summary of Changes between 3.4 and 3.5

-

-Framework

-
    -
  • - Added TestSuite.addTestSuite(Class testClass)
  • -
    -This method allows to create a TestSuite with a class containing test -cases directly. -
    -Instead of writing suite.addTest(new TestSuite(AssertTest.class)) - you -can now write suite.addTestSuite(AssertTest.class); -
  • Added assertEquals methods for all primitive types: float, -boolean, byte, -char, int, short
  • -
  • -The signature of  TestListeners.addFailure(Test test, Throwable t)
  • -
    -was changed to addFailure(Test test, AssertionFailedError t)
    -
-

-TestRunner

-
    -
  • - The Swing TestRunner provides an experimental -feature to browse test classes. -There is an additional browse ("...") button besides the suite combo. -It -shows a simple dialog to select a test class from a list. Different -strategies -to locate Test classes are supported and you can plug-in your own -strategy. -This allows to leverage functionality provided by an extension API of -an -integrated development environment (IDE). To define a custom test -collector -you 1) implement the junit.runner.TestCollector interface and -2) -add an entry to the junit.properties file with the key TestCollectorClass -and the name of your TestCollector implementation class as the key:
  • -
    -        -TestCollectorClass=junit.swingui.LoadingClassPathTestCollector -
    -This class has to be installed on the class path. -
    -JUnit provides two different TestCollector implementations: -
    -
      -
    • - simple -(junit.runner.SimpleClassPathTestCollector) - considers all classes -on the class path on the file system that contain "Test" in their name. -Classes in JARs are not considered.
    • -
    • - loading -(junit.runner.LoadingClassPathTestCollector) - loads all classes -on the class path and tests whether the class is assignable from Test -or -has a static suite method.
    • -
    - By default the simple the test collector is -used. The loading collector -is more precise but much slower than the simple one. The loading -collector -doesn't scale up when many classes are available on the class path. -
    - Notice: that both TestCollectors -assume that the class files reside are kept in the file system. This -isn't -case in VA/Java and they will not work there. A custom TestCollector is -required for VA/Java. -
  • The Swing TestRunner now provides an additional test result view -that shows -all tests of the executed test suite as a tree. The view shows the -success -status for each test. The view is shown as an additional tab in the -TestRunner -window. In previous versions of JUnit this view was shown in a separate -window.
  • -
  • -The failure panels in the Swing and AWT TestRunners filter the -exception -stack trace so that only non-framework stack frames are shown.
  • -
  • -There is support to plug-in a custom failure panel that provides -additional -functionality like navigating from a failure to the source. To do so -you -implement the junit.runner.FailureDetailView interface and -register -the implementation class in the junit.properties file under the key FailureViewClass, -for example
  • -
    -        -FailureViewClass=MyFailureViewClassName. -
  • The Swing and AWT TestRunners now understand an additional -command line -argument "-noloading". When this argument is set then the standard -system -class loader is used to load classes. This is an alternative to setting -the loading property to false in the junit.properties file.
  • -
  • -Swing TestRunner - the maximum test history length shown in the suite -combo -can be defined in the junit.properties file with the key maxhistory.
  • -
  • -BaseTestRunner.getLoader() is no longer a static method and can -now be overridden in subclasses.
  • -
  • -BaseTestRunner removed dependency on JDK 1.2.
  • -
  • -Swing TestRunner - fixed the problem that a suite name was sometimes -duplicated -in the history combo.
  • -
  • -Swing TestRunner - the Run button is now the default button.
  • -
  • -Output string truncation can now be controlled by adding the maxmessage -key with the desired maximum length to the junit.properties file. -Setting -maxmessage to -1 means no output truncation.
  • -
  • -The Text TestRunner now shows the summary at the very end so that you -don't -have to scroll back.
  • -
    -
-

-Tests

-
    -
  • - TextRunnerTest now only depends on a nonzero -status to indicate abnormal -termination.
  • -
  • - TextRunnerTest now also passes on JDK 1.1.*. -It uses the -classpath command -line argument instead of -cp.
  • -
-

-Documentation

-
    -
  • - Add an FAQ entry about what to do when the -junit tests provided with the -distribution can't be found.
  • -
-

-Older Change Notes

-
-
  • Changes between 2.1 and 3.4
  • -
  • - Changes between 1.0 -and 2.1
  • -
    -

    -Contents of the Release

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    README.html this file
    junit.jara jar file with the JUnit framework and  tools 
    src.jara jar file with the source code of the junit framework
    junitthe source code of the JUnit samples
        samplessample test cases
        teststest cases for JUnit itself
    javadocjavadoc generated documentation
    docdocumentation and articles
    -

    -Installation

    -Below are the installation steps for installing -JUnit: - -
      -
    1. - unzip the junit.zip file
    2. -
    3. - add junit.jar to the -CLASSPATH. For example: set -classpath=%classpath%;INSTALL_DIR\junit3\junit.jar
    4. -
    5. - test the installation by using either the -batch or the graphical TestRunner -tool to run the tests that come with this release. All the tests should -pass OK.
    6. -
      - Notice: that the tests are not -contained in the junit.jar but in the installation directory directly. -Therefore make sure that the installation directory is on the class -path -
      -
        -
      • - for the batch TestRunner type:
      • -
        -     java junit.textui.TestRunner -junit.samples.AllTests -
      • for the graphical TestRunner type:
      • -
        -     java junit.awtui.TestRunner -junit.samples.AllTests -
      • for the Swing based graphical TestRunner type:
      • -
        -     java junit.swingui.TestRunner -junit.samples.AllTests
        -
      -
    -Important: -don't install the junit.jar -into the extension directory of your JDK installation. If you do so the -test class on the files system will not be found. - -

    Getting Started

    -To get started with unit testing and JUnit read -the Java Report article: -Test -Infected - Programmers Love Writing Tests. -
    -This article demonstrates the development process with JUnit in the -context of multiple currency arithmetic. The corresponding source code -is in junit\samples\money. -
    -

    You find additional samples in the -junit.samples package: -

    -
      -
    • - SimpleTest.java - some simple test cases
    • -
    • - VectorTest.java - test cases for -java.util.Vector
    • -
    -

    -Documentation

    -
    JUnit -Cookbook -
    -    A cookbook for implementing tests with JUnit. -
    - Test Infected - Programmers -Love Writing Tests -
    -    An article demonstrating the development process -with JUnit. -
    - JUnit - A cooks tour -
    - Javadoc -
    -    API documentation generated with javadoc. -
    - Frequently asked questions -
    -    Some frequently asked questions about using JUnit. -
    - TestRunner Preference settings -
    -    Describes the preferences settings that can be -configured -for the JUnit TestRunners.
    - License -
    -    The terms of the common public license used for -JUnit.
    -

    -Extending JUnit

    -Examples of possible JUnit extensions can be -found in the junit.extensions -package: - -
      -
    • - TestDecorator -- A decorator for Test. You can use it as the base class for -implementing -decorators to extend test cases.
    • -
    • - ActiveTestSuite -- A TestSuite which runs each test in a separate thread and waits until -they are all terminated.
    • -
    • - TestSetup - A -Decorator -to set up and tear down additional fixture state. Subclass TestSetup -and -insert it into your tests when you want to set up additional state once -before the tests are run.
    • -
    • - ExceptionTestCase -- A TestCase that expects a particular Exception to be thrown.
    • -
    -
    -SourceForge Logo - - diff --git a/README.md b/README.md new file mode 100644 index 000000000000..f73f89ca5ed0 --- /dev/null +++ b/README.md @@ -0,0 +1,9 @@ +# JUnit 4 +JUnit is a simple framework to write repeatable tests. It is an instance of the xUnit architecture for unit testing frameworks. + +For more information, please visit: +* [Wiki](https://github.com/junit-team/junit4/wiki) +* [Download and Install guide](https://github.com/junit-team/junit4/wiki/Download-and-Install) +* [Getting Started](https://github.com/junit-team/junit4/wiki/Getting-started) + +[![Build Status](https://travis-ci.org/junit-team/junit4.svg?branch=main)](https://travis-ci.org/junit-team/junit4) diff --git a/acknowledgements.txt b/acknowledgements.txt new file mode 100644 index 000000000000..bbc24dfe041f --- /dev/null +++ b/acknowledgements.txt @@ -0,0 +1,163 @@ +2006 March 9 + Matthias Schmidt: improved org.junit package javadoc + +2006 August 3 + giovanni: better test for TestCase without a name. + Matthias Pfau: better error message when test case constructor fails + +2006 November 21 + dakcalouro: Found defect with comparing ints and longs (1555161) + Ben Maurer: Found defect with timeouts taking twice as long as specified (1536198) + +2007 February 08 + Kazimierz Pogoda: Found defect with null array elements (1438163) + +2007 July 09 + wangqq: Found defect with @After not running after a timeout (1745048) + +2007 July 18 + Andrew Dick: Found defect with assertEquals comparing non-Integer Numbers (1715326) + Michael Schechter: Found defect with Filters and suite() methods (1739095) + +2008 February 5 + Walter Gildersleeve: Found assertEquals(null, "null") defect (1857283) + +2008 July 1 + Johannes Link: Submitted test for running subclasses of Suite + +2008 July 23 + Daniel Brolund: Submitted patch for build.xml, fixing 1.5 compatibility (2021396) + +2008 Aug 1 + Nat Pryce: Found defect in treatment of validation errors from custom + subclasses of the legacy JUnit4ClassRunner. + +2008 Aug 18 + Nir Soffer: Suggested adding to the cookbook information about running + running JUnit from the command line. + +2008 Aug 19 + Jack Woehr: Discovered build.xml was missing from junit-4.x.zip + +2009 Jan 5 + Amanda Robinson: Fixed overly permissive @DataPoint processing. + +2009 Feb 9 + Mark Shapiro: Discovered bug in test counting after an ignored method (2106324) + +2009 Apr 20 + Chris Felaco: Discovered regression in handling suite() methods with JUnit 3 runner (1812200) + Toby Byron: Suggested updating linking in javadoc (2090230) + Raphael Parree: Improved docs on Parameterized (2186792) + Robin de Silva Jayasinghe: Fixed Javadoc code sample for AfterClass (2126279) + +2009 May 04 + James Abbley: Submitted a patch that fixed the 2-second limit on Parallel execution. + +2009 Nov 16 + Kristian Rosenvold: Submitted a patch (github#16) that improves thread-safety of + result counting +2010 Feb 08 + Paul Holser: Submitted additional test for TestName rule. + +2010 May 03 + jonas22@github: Found bug (github#98) with assumptions and expected exceptions. + +2011 Jan 03 + jens.schauder@freenet.de: Found bug (github#74) with Categories and + Parameterized. + +2011 Jan 18 + Markus Keller: Reported bug (github#163): + Bad comparison failure message when using assertEquals(String, String) + + Kevin Cooney (kcooney@github): + Patches for runLeaf, public multiple failure exception, + assertion messages and null. + +2011 Mar 04 + Jerome Lacoste (lacostej@github) for initial patch for GH-191. + +2011 Apr 15 + reinholdfuereder@github For initial test for GH-39 + +2011 Apr 15 + ububenheimer@github for bug report https://github.com/junit-team/junit4/issues/208 + +2011 Apr 29 + reinholdfuereder@github: bug report, test, and fix for GH-38: + ParentRunner filtering +2011 Apr 29 + Markus Keller (mkeller@github): Report for GH-187: + Unintentional dependency on Java 6 + +2011 May 31 + Kevin Cooney (kcooney@github): Patches for filtering test suites: + copy List returned by getChildren() before mutating it; + optimize ParentRunner.filter for nested suites; + optimize Filter.intersect for common cases + +2011 Jun 06 + Vampire@github: Report for GH-235: 4.7 release notes incorrect. + +2011 Jun 24 + Samuel Le Berrigaud (sleberrigaud@github): Report for GH-248: + protected BlockJUnit4ClassRunner#rules method removed from 4.8.2 + +2011 Jun 24 + Daniel Rothmaler (drothmaler@github): + #299: random temp file/folder creation + #300: ErrorCollector.checkThat overload + +2011 Jun 25 + Juan Cortez (jcortez@github): Fixed issue #219 where floats were being + printed and represented as doubles in error messages. + +2011 Jul 06 + Stefan Birkner: Fixed wrong documentation of ClassRule (github#254). + +2011 Jul 08 + Paul Holser (pholser@alumni.rice.edu): Beginnings of fix for GH-64: + Theories doesn't honor parameterized types + +2011 Jul 09 + Nigel Charman: Reported Rules bugs github#257 and gihub#258. + +2011 Jul 09 + Stefan Birkner: Fixed rules bugs (github#257, gihub#258, github#260). + +2011 Jul 09 + Stefan Birkner: Fixed rules bugs (github#257, gihub#258, github#260). + +2011 Jul 16 + Rob Dawson: Submitted a patch that makes Results serlializable. + +2011 Jul 20 + Asaf Ary, Stefan Birkner: Fixed FailOnTimeout class (github#265). + +2011 Jul 22 + Andreas Köhler, Stefan Birkner: Fixed wrong documentation of Parameterized (github#89). + +2011 Jul 28 + electrickery, Stefan Birkner: Fixed typo in JavaDoc (github#134). + +2011 Aug 07 + Esko Luontola: Fixed TemporaryFolder creating files in the current working directory (github#278). + +2011 Aug 09 + Stefan Birkner: Fixed JavaDoc links. + +2011 Aug 10 + rodolfoliviero@github and JoseRibeiro@github: feature to create recursive temporary folders. + +2011 Aug 12 + Esko Luontola: Fixed syntax error in Parameterized's usage example (github#285). + +2011 Sep 09 + Robert Munteanu, Stefan Birkner: + TestWatcher and TestWatchman don't call failed when assumption is violated (github#296). + digulla@github, Stefan Birkner: Removed useless code (github#289). + +== NOTE: as of September 2011, we have stopped recording contributions here. + For a full list of everyone who has contributed great bug reports and code, please see + http://github.com/junit-team/junit4 diff --git a/build.xml b/build.xml deleted file mode 100644 index dff506ce1363..000000000000 --- a/build.xml +++ /dev/null @@ -1,121 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/cpl-v10.html b/cpl-v10.html deleted file mode 100644 index 36aa208d4a29..000000000000 --- a/cpl-v10.html +++ /dev/null @@ -1,125 +0,0 @@ - - - -Common Public License - v 1.0 - - - - - - -

    Common Public License - v 1.0 -

    -

    THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS COMMON PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. -

    -

    1. DEFINITIONS -

    "Contribution" means: - -

      a) in the case of the initial Contributor, the initial code and documentation distributed under this Agreement, and
      -b) in the case of each subsequent Contributor:
    - - -
      i) changes to the Program, and
    - - -
      ii) additions to the Program;
    - - -
      where such changes and/or additions to the Program originate from and are distributed by that particular Contributor. A Contribution 'originates' from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributor's behalf. Contributions do not include additions to the Program which: (i) are separate modules of software distributed in conjunction with the Program under their own license agreement, and (ii) are not derivative works of the Program.
    - -

    -

    "Contributor" means any person or entity that distributes the Program. -

    -

    "Licensed Patents " mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program. -

    -

    "Program" means the Contributions distributed in accordance with this Agreement. -

    -

    "Recipient" means anyone who receives the Program under this Agreement, including all Contributors. -

    -

    2. GRANT OF RIGHTS - -

      a) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, distribute and sublicense the Contribution of such Contributor, if any, and such derivative works, in source code and object code form.
    - - -
    - - -
      b) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in source code and object code form. This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder.
    - - -
    - - -
      c) Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any. For example, if a third party patent license is required to allow Recipient to distribute the Program, it is Recipient's responsibility to acquire that license before distributing the Program.
    - - -
    - - -
      d) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement.
    - - -
    - -

    3. REQUIREMENTS -

    A Contributor may choose to distribute the Program in object code form under its own license agreement, provided that: - -

      a) it complies with the terms and conditions of this Agreement; and
    - - -
      b) its license agreement:
    - - -
      i) effectively disclaims on behalf of all Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose;
    - - -
      ii) effectively excludes on behalf of all Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits;
    - - -
      iii) states that any provisions which differ from this Agreement are offered by that Contributor alone and not by any other party; and
    - - -
      iv) states that source code for the Program is available from such Contributor, and informs licensees how to obtain it in a reasonable manner on or through a medium customarily used for software exchange.
    - - -
    - -

    When the Program is made available in source code form: - -

      a) it must be made available under this Agreement; and
    - - -
      b) a copy of this Agreement must be included with each copy of the Program.
    - -

    -

    Contributors may not remove or alter any copyright notices contained within the Program. -

    -

    Each Contributor must identify itself as the originator of its Contribution, if any, in a manner that reasonably allows subsequent Recipients to identify the originator of the Contribution. -

    -

    4. COMMERCIAL DISTRIBUTION -

    Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor ("Commercial Contributor") hereby agrees to defend and indemnify every other Contributor ("Indemnified Contributor") against any losses, damages and costs (collectively "Losses") arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may participate in any such claim at its own expense. -

    -

    For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone. Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages. -

    -

    5. NO WARRANTY -

    EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the appropriateness of using and distributing the Program and assumes all risks associated with its exercise of rights under this Agreement, including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations. -

    -

    6. DISCLAIMER OF LIABILITY -

    EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. -

    -

    7. GENERAL -

    If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable. -

    -

    If Recipient institutes patent litigation against a Contributor with respect to a patent applicable to software (including a cross-claim or counterclaim in a lawsuit), then any patent licenses granted by that Contributor to such Recipient under this Agreement shall terminate as of the date such litigation is filed. In addition, if Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed. -

    -

    All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive. -

    -

    Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish new versions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the right to modify this Agreement. IBM is the initial Agreement Steward. IBM may assign the responsibility to serve as the Agreement Steward to a suitable separate entity. Each new version of the Agreement will be given a distinguishing version number. The Program (including Contributions) may always be distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to distribute the Program (including its Contributions) under the new version. Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or otherwise. All rights in the Program not expressly granted under this Agreement are reserved. -

    -

    This Agreement is governed by the laws of the State of New York and the intellectual property laws of the United States of America. No party to this Agreement will bring a legal action under this Agreement more than one year after the cause of action arose. Each party waives its rights to a jury trial in any resulting litigation. -

    -

    - - - - \ No newline at end of file diff --git a/doc/Changes34.html b/doc/Changes34.html deleted file mode 100644 index 083b4d4b4a43..000000000000 --- a/doc/Changes34.html +++ /dev/null @@ -1,226 +0,0 @@ - - - - - - - JUnit 3 - - - -

      -

      -Summary of Changes between 3.3 and 3.4

      - -
        -
      • -Eliminated code in ActiveTestSuite that could not compile in VA/Java.
      • - -
      • -Fixed bug related to incorrect error progress feedback when running a single -test.
      • -
      - -

      -Summary of Changes between 3.2 and 3.3

      - -

      -Framework

      - -
        -
      • -Fixed Assert.assertEquals(double,double,double) when the actual value is -a Double.NaN.
      • -
      - -

      -Extensions

      - -
        -
      • -Fixed ActiveTest support. Replaced ActiveTest with an ActiveTestSuite, -the ActiveTestSuite waits until the tests running in separate threads have -finished.
      • - -
      • -Added an example that illustrates how to launch a new VM for running a -Test - see TextRunnerTest.java.
      • -
      - -

      -TestRunner

      - -
        -
      • -Refactored the TestRunner classes, they now all descend from junit.runner.BaseTestRunner.
      • - -
      • -Eliminated the non-loading/loading TestRunner flavors. All TestRunners -are now loading by default except when the TestRunners detect that they -run inside VA/Java (BaseTestRunner.getLoader()).
      • - -
      • -Added a junit.properties file for preference settings. It is stored -in the folder referred to by the "user.home" property. The supported setting -is loading, it can be set to true or false to enable or disable -the loading behavior.
      • - -
      • -Renamed junit.ui to junit.awtui (with backward compatibility).
      • - -
      • -Renamed junit.utils to junit.runner.
      • - -
      • -You can now put test cases that should be reloaded into a JAR file. The -TestCaseClassLoader now supports a simple version of class loading from -a JAR file.
      • - -
      • -Simplified  invoking the TestRunners programmatically. They now all -support a static method run(Class test).
      • - -
      • -Clarified the exit behavior of junit.textui.TestRunner:
      • - -
          -
        • -TestRunner only exits the VM when it is invoked by main, when the TestRunner -is invoked by run() it will not explicitly exit and terminate the -VM.
        • - -
        • -TestRunner exits with 0 when the tests passed.
        • -
        -
      - -

      -Release

      - -
        -
      • -Removed VA/Java specific installation support
      • -
      - -

      -Summary of Changes between 3.1 and 3.2

      - -
        -
      • -Fixed bug in the handling of inherited test methods.
      • - -
      • -The junit.swing.TestRunner support selective test execution. A Test Browser -shows the contents of the entered test suite as a tree and you can select -the test case to be run. The Test Browser can be launched from JUnit menu.
      • - -
      • -The history file of junit.swingui.TestRunner is stored in .junit on non -Windows platforms.
      • - -
      • -Support for rerunning a failed test was previously only available inside -VisualAge for Java. It is now generally available when using the LoadingTestRunners.
      • - -
      • -The junit.textui.TestRunner exits with -1 when the test run fails.
      • -
      - -

      -Summary of Changes between 2.1 and 3.1

      - -

      -JUnit Framework

      - -
        -
      • -TestSuite now extracts inherited test methods. The test extraction stops -at the first class that doesn't implement Test.
      • - -
      • -Added support for TestListeners. A TestListeners observes changes to the -TestResult. It enables to have multiple observers on the same result and -allowed us to delete the TestResult subclasses (parallel class hierarchy) -as the TestRunners now implement TestListener. It also allows clients to -generate additional kinds of test run feedback.
      • - -
      • -Added an ExceptionTestCase -class. A TestCase that expects a particular exception to be thrown.
      • - -
      • -Fixed TestSetup so that errors in setUp are caught and reported correctly.
      • - -
      • -Assertion checks where moved from TestCase into a separate Assert -class. This enables programming by contract.
      • - -
      • -Added support for protected blocks. A protected block has to implement -the Protectable -interface. We used it to factor out a common template method to run tests. -To implement your own protected block that logs thrown exceptions, pass -a Protectable to TestResult.runProtected().
      • - -
      • -Clarified and deprecated method names in TestResult: testErrors, testFailures -and runTests are now called errorCount, failureCount and runCount.
      • - -
      • -TestCase.getResult got removed you can add access to the current TestResult -in your own TestCase subclasses.
      • - -
      • -TestCase.setUp() and tearDown() now throw a Throwable, so you can allow -exceptions in setUp() to propagate.
      • -
      - -

      -TestRunner

      - -
        -
      • -There is a new version of a Swing based graphical TestRunner. It supports -a combo box with a persistent history of ran test suites. You can start -it with:
      • - -
            java junit.swingui.TestRunner -
        There is also a LoadingTestRunner for Swing. The Swing TestRunner requires -Swing 1.1 (javax.swing package structure) or jdk 1.2. -
      • -Some common code among the TestRunners was moved into the package junit.util.
      • - -
      • -The batch TestRunner unit.textui.TestRunner can now be given a PrintStream -to output the results to.
      • - -
      • -The batch TestRunner can be given a class to run directly. To start the -batch runner from your main you can write:
      • - -
        public static void main(String args[]) { -
          junit.textui.TestRunner.run(MoneyTest.class); -
        }
      - -

      -Documentation

      - -
        -
      • -There is a new article: JUnit a cook's tour included.
      • -
      - -

      -Release

      - -
        -
      • -We no longer provide a .dat file for VAJ users. You install JUnit into -VAJ by importing the resources from the junit.jar and the sources from -the src.zip files.
      • -
      -
    - -
    - - diff --git a/doc/JUnitProperties.html b/doc/JUnitProperties.html deleted file mode 100644 index f471be98ac00..000000000000 --- a/doc/JUnitProperties.html +++ /dev/null @@ -1,74 +0,0 @@ - - - - - - - JUnit 2 - - - -

    -JUnit TestRunner Properties

    -The TestRunners use a properties file for preference settings. This file -is stored in the folder referred to by the "user.home" system property. -The following properties are supported: -
      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    loadingUse a custom class loader to load classes for each run. Default value=true.
    filterstackFilter JUnit internal methods in failure or error stack traces. Default -value=true. 
    maxmessageThe maximum output length. Default value=500. Set maxmessage to -1 -to disable output truncation. Disabling the output truncation will result -in long test runs when an assertEquals method fails and the toString() -method results in massive output. 
    TestCollectorClass -
    Swing UI TestRunner only
    The Swing TestRunner supports to browse test classes. There is an additional -browse ("...") button besides the suite combo. It shows a simple dialog -to select a test class from a list. Different strategies to locate Test -classes are supported and you can plug-in your own strategy. This allows -to leverage functionality provided by an extension API of an integrated -development environment (IDE). To define a custom test collector you 1) -implement the junit.runner.TestCollector interface and 2) add an entry -to the junit.properties file with the key TestCollectorClass and the name -of your TestCollector implementation class as the key:  -
                 -TestCollectorClass=junit.swingui.LoadingTestCollector  -
    This class has to be installed on the class path. 
    FailureViewClass -
    Swing UI TestRunner only
    Plug-in a custom failure panel that provides additional functionality -like navigating from a failure to the source. To do so you implement the -junit.runner.FailureDetailView interface and register the implementation -class in the junit.properties file under the key FailureViewClass, for -example.  -
                 -FailureViewClass=somepackage.MyFailureViewClassName.  -
    This class has to be installed on the class path. 
    - - - diff --git a/doc/ReleaseNotes4.10.html b/doc/ReleaseNotes4.10.html new file mode 100644 index 000000000000..b6b9483b8a74 --- /dev/null +++ b/doc/ReleaseNotes4.10.html @@ -0,0 +1,93 @@ +

    Summary of Changes in version 4.10

    + +

    A full summary of commits between 4.9 and 4.10 is on github

    + +

    junit-dep has correct contents

    + +

    junit-dep-4.9.jar incorrectly contained hamcrest classes, which could lead to version conflicts in projects that depend on hamcrest directly. This is fixed in 4.10 [@dsaff, closing gh-309]

    + +

    RuleChain

    + +

    The RuleChain rule allows ordering of TestRules:

    + +
    public static class UseRuleChain {
    +    @Rule
    +    public TestRule chain= RuleChain
    +                           .outerRule(new LoggingRule("outer rule")
    +                           .around(new LoggingRule("middle rule")
    +                           .around(new LoggingRule("inner rule");
    +
    +    @Test
    +    public void example() {
    +        assertTrue(true);
    +    }
    +}
    +
    + +

    writes the log

    + +
    starting outer rule
    +starting middle rule
    +starting inner rule
    +finished inner rule
    +finished middle rule
    +finished outer rule
    +
    + +

    TemporaryFolder

    + +
      +
    • TemporaryFolder#newFolder(String... folderNames) creates recursively deep temporary folders +[@rodolfoliviero, closing gh-283]
    • +
    • TemporaryFolder#newFile() creates a randomly named new file, and #newFolder() creates a randomly named new folder +[@Daniel Rothmaler, closing gh-299]
    • +
    + +

    Theories

    + +

    The Theories runner does not anticipate theory parameters that have generic +types, as reported by github#64. Fixing this won't happen until Theories is +moved to junit-contrib. In anticipation of this, 4.9.1 adds some of the +necessary machinery to the runner classes, and deprecates a method that only +the Theories runner uses, FrameworkMethod#producesType(). +The Common Public License that JUnit is released under is now included +in the source repository.

    + +

    Thanks to @pholser for identifying a potential resolution for github#64 +and initiating work on it.

    + +

    Bug fixes

    + +
      +
    • Built-in Rules implementations +
        +
      • TemporaryFolder should not create files in the current working directory if applying the rule fails +[@orfjackal, fixing gh-278]
      • +
      • TestWatcher and TestWatchman should not call failed for AssumptionViolatedExceptions +[@stefanbirkner, fixing gh-296]
      • +
    • +
    • Javadoc bugs +
        +
      • Assert documentation [@stefanbirkner, fixing gh-134]
      • +
      • ClassRule [@stefanbirkner, fixing gh-254]
      • +
      • Parameterized [@stefanbirkner, fixing gh-89]
      • +
      • Parameterized, again [@orfjackal, fixing gh-285]
      • +
    • +
    • Miscellaneous +
        +
      • Useless code in RunAfters [@stefanbirkner, fixing gh-289]
      • +
      • Parameterized test classes should be able to have @Category annotations +[@dsaff, fixing gh-291]
      • +
      • Error count should be initialized in junit.tests.framework.TestListenerTest [@stefanbirkner, fixing gh-225]
      • +
      • AssertionFailedError constructor shouldn't call super with null message [@stefanbirkner, fixing gh-318]
      • +
      • Clearer error message for non-static inner test classes [@stefanbirkner, fixing gh-42]
      • +
    • +
    + +

    Minor changes

    + +
      +
    • Description, Result and Failure are Serializable [@ephox-rob, closing gh-101]
    • +
    • FailOnTimeout is reusable, allowing for retrying Rules [@stefanbirkner, closing gh-265]
    • +
    • New ErrorCollector.checkThat overload, that allows you to specify a reason [@drothmaler, closing gh-300]
    • +
    diff --git a/doc/ReleaseNotes4.10.md b/doc/ReleaseNotes4.10.md new file mode 100644 index 000000000000..5f19bf744889 --- /dev/null +++ b/doc/ReleaseNotes4.10.md @@ -0,0 +1,86 @@ +## Summary of Changes in version 4.10 ## + +Thanks to a full cast of contributors of bug fixes and new features. + +A full summary of commits between 4.9 and 4.10 is on [github](https://github.com/junit-team/junit4/compare/r4.9...r4.10) + +### junit-dep has correct contents ### + +junit-dep-4.9.jar incorrectly contained hamcrest classes, which could lead to version conflicts in projects that depend on hamcrest directly. This is fixed in 4.10 [@dsaff, closing gh-309] + +### RuleChain ### + +The RuleChain rule allows ordering of TestRules: + +```java +public static class UseRuleChain { + @Rule + public TestRule chain= RuleChain + .outerRule(new LoggingRule("outer rule") + .around(new LoggingRule("middle rule") + .around(new LoggingRule("inner rule"); + + @Test + public void example() { + assertTrue(true); + } +} +``` + +writes the log + + starting outer rule + starting middle rule + starting inner rule + finished inner rule + finished middle rule + finished outer rule + +### TemporaryFolder ### + +- `TemporaryFolder#newFolder(String... folderNames)` creates recursively deep temporary folders + [@rodolfoliviero, closing gh-283] +- `TemporaryFolder#newFile()` creates a randomly named new file, and `#newFolder()` creates a randomly named new folder + [@Daniel Rothmaler, closing gh-299] + +### Theories ### + +The `Theories` runner does not anticipate theory parameters that have generic +types, as reported by github#64. Fixing this won't happen until `Theories` is +moved to junit-contrib. In anticipation of this, 4.9.1 adds some of the +necessary machinery to the runner classes, and deprecates a method that only +the `Theories` runner uses, `FrameworkMethod`#producesType(). +The Common Public License that JUnit is released under is now included +in the source repository. + +Thanks to `@pholser` for identifying a potential resolution for github#64 +and initiating work on it. + +### Bug fixes ### + +- Built-in Rules implementations + - TemporaryFolder should not create files in the current working directory if applying the rule fails + [@orfjackal, fixing gh-278] + - TestWatcher and TestWatchman should not call failed for AssumptionViolatedExceptions + [@stefanbirkner, fixing gh-296] +- Javadoc bugs + - Assert documentation [@stefanbirkner, fixing gh-134] + - ClassRule [@stefanbirkner, fixing gh-254] + - Parameterized [@stefanbirkner, fixing gh-89] + - Parameterized, again [@orfjackal, fixing gh-285] +- Miscellaneous + - Useless code in RunAfters [@stefanbirkner, fixing gh-289] + - Parameterized test classes should be able to have `@Category` annotations + [@dsaff, fixing gh-291] + - Error count should be initialized in junit.tests.framework.TestListenerTest [@stefanbirkner, fixing gh-225] + - AssertionFailedError constructor shouldn't call super with null message [@stefanbirkner, fixing gh-318] + - Clearer error message for non-static inner test classes [@stefanbirkner, fixing gh-42] + +### Minor changes ### + +- Description, Result and Failure are Serializable [@ephox-rob, closing gh-101] +- FailOnTimeout is reusable, allowing for retrying Rules [@stefanbirkner, closing gh-265] +- New `ErrorCollector.checkThat` overload, that allows you to specify a reason [@drothmaler, closing gh-300] + + + diff --git a/doc/ReleaseNotes4.10.txt b/doc/ReleaseNotes4.10.txt new file mode 100644 index 000000000000..bc63f07611c7 --- /dev/null +++ b/doc/ReleaseNotes4.10.txt @@ -0,0 +1 @@ +Please see ReleaseNotes4.10.md diff --git a/doc/ReleaseNotes4.11.html b/doc/ReleaseNotes4.11.html new file mode 100644 index 000000000000..fefd79f6910a --- /dev/null +++ b/doc/ReleaseNotes4.11.html @@ -0,0 +1,121 @@ +

    Summary of changes in version 4.11

    + +

    Matchers: Upgrade to Hamcrest 1.3

    + +

    JUnit now uses the latest version of Hamcrest. Thus, you can use all the available matchers and benefit from an improved assertThat which will now print the mismatch description from the matcher when an assertion fails.

    + +

    Example

    + +
    assertThat(Long.valueOf(1), instanceOf(Integer.class));
    +
    + +

    Old error message:

    + +
    Expected: an instance of java.lang.Integer
    +     got: <1L>
    +
    + +

    New error message:

    + +
    Expected: an instance of java.lang.Integer
    +     but: <1L> is a java.lang.Long
    +
    + +

    Hamcrest's new FeatureMatcher makes writing custom matchers that make use of custom mismatch descriptions quite easy:

    + +
    @Test
    +public void featureMatcher() throws Exception {
    +    assertThat("Hello World!", length(is(0)));
    +}
    +
    +private Matcher<String> length(Matcher<? super Integer> matcher) {
    +    return new FeatureMatcher<String, Integer>(matcher, "a String of length that", "length") {
    +        @Override
    +        protected Integer featureValueOf(String actual) {
    +            return actual.length();
    +        }
    +    };
    +}
    +
    + +

    Running this test will return the following failure message:

    + +
    Expected: a String of length that is <0>
    +     but: length was <12>
    +
    + +

    Most of the matchers in JUnitMatchers have been deprecated. Please use org.hamcrest.CoreMatchers directly.

    + +

    Parameterized Tests

    + +

    In order to easily identify the individual test cases in a Parameterized test, you may provide a name using the @Parameters annotation. This name is allowed to contain placeholders that are replaced at runtime:

    + +
      +
    • {index}: the current parameter index
    • +
    • {0}, {1}, …: the first, second, and so on, parameter value
    • +
    + +

    Example

    + +
    @RunWith(Parameterized.class)
    +public class FibonacciTest {
    +
    +    @Parameters(name = "{index}: fib({0})={1}")
    +    public static Iterable<Object[]> data() {
    +        return Arrays.asList(new Object[][] { { 0, 0 }, { 1, 1 }, { 2, 1 },
    +                { 3, 2 }, { 4, 3 }, { 5, 5 }, { 6, 8 } });
    +    }
    +
    +    private int input;
    +    private int expected;
    +
    +    public FibonacciTest(int input, int expected) {
    +        this.input = input;
    +        this.expected = expected;
    +    }
    +
    +    @Test
    +    public void test() {
    +        assertEquals(expected, Fibonacci.compute(input));
    +    }
    +}
    +
    + +

    In the example given above, the Parameterized runner creates names like [1: fib(3)=2]. If you don't specify a name, the current parameter index will be used by default.

    + +

    Test execution order

    + +

    By design, JUnit does not specify the execution order of test method invocations. Until now, the methods were simply invoked in the order returned by the reflection API. However, using the JVM order is unwise since the Java platform does not specify any particular order, and in fact JDK 7 returns a more or less random order. Of course, well-written test code would not assume any order, but some does, and a predictable failure is better than a random failure on certain platforms.

    + +

    From now on, JUnit will by default use a deterministic, but not predictable, order (MethodSorters.DEFAULT). To change the test execution order simply annotate your test class using @FixMethodOrder and specify one of the available MethodSorters:

    + +
      +
    • @FixMethodOrder(MethodSorters.JVM): Leaves the test methods in the order returned by the JVM. This order may vary from run to run.

    • +
    • @FixMethodOrder(MethodSorters.NAME_ASCENDING): Sorts the test methods by method name, in lexicographic order.

    • +
    + +

    Maven artifacts

    + +

    Up until now there were two Maven artifacts for JUnit: junit:junit-dep and junit:junit. From a Maven point-of-view only the former made sense because it did not contain the Hamcrest classes but declared a dependency to the Hamcrest Maven artifact. The latter included the Hamcrest classes which was very un-Maven-like.

    + +

    From this release on, you should use junit:junit which will be what junit:junit-dep used to. If you still reference junit:junit-dep, Maven will automatically relocate you to the new junit:junit and issue a warning for you to fix.

    + +

    Rules

    + +

    A number of improvements have been made to Rules:

    + +
      +
    • MethodRule is no longer deprecated.
    • +
    • Both @Rule and @ClassRule can now be used on methods that return a TestRule.
    • +
    • ExpectedException now always prints the stacktrace of the actual exception in case of failure.
    • +
    • A parent folder can be specified for TemporaryFolder. In addition, the newFile/newFolder methods will now fail when the file or folder could not be created.
    • +
    • TestWatcher has a new template method called skipped that is invoked when a test is skipped due to a failed assumption.
    • +
    + +

    Improvements to Assert and Assume

    + +
      +
    • assertNotEquals has been added to Assert.
    • +
    • assertEquals has been overloaded in order to check whether two floats are equal given a certain float delta.
    • +
    • Most methods in Assume now allow to pass a custom message.
    • +
    diff --git a/doc/ReleaseNotes4.11.md b/doc/ReleaseNotes4.11.md new file mode 100644 index 000000000000..740c64a09d7c --- /dev/null +++ b/doc/ReleaseNotes4.11.md @@ -0,0 +1,116 @@ +## Summary of changes in version 4.11 + +### Matchers: Upgrade to Hamcrest 1.3 + +JUnit now uses the latest version of Hamcrest. Thus, you can use all the available matchers and benefit from an improved `assertThat` which will now print the mismatch description from the matcher when an assertion fails. + +#### Example + +```java +assertThat(Long.valueOf(1), instanceOf(Integer.class)); +``` + +Old error message: + + Expected: an instance of java.lang.Integer + got: <1L> + +New error message: + + Expected: an instance of java.lang.Integer + but: <1L> is a java.lang.Long + +Hamcrest's new `FeatureMatcher` makes writing custom matchers that make use of custom mismatch descriptions quite easy: + +```java +@Test +public void featureMatcher() throws Exception { + assertThat("Hello World!", length(is(0))); +} + +private Matcher length(Matcher matcher) { + return new FeatureMatcher(matcher, "a String of length that", "length") { + @Override + protected Integer featureValueOf(String actual) { + return actual.length(); + } + }; +} +``` + +Running this test will return the following failure message: + + Expected: a String of length that is <0> + but: length was <12> + + +Most of the matchers in `JUnitMatchers` have been deprecated. Please use `org.hamcrest.CoreMatchers` directly. + +### Parameterized Tests + +In order to easily identify the individual test cases in a Parameterized test, you may provide a name using the `@Parameters` annotation. This name is allowed to contain placeholders that are replaced at runtime: + +* `{index}`: the current parameter index +* `{0}`, `{1}`, …: the first, second, and so on, parameter value + +#### Example + +```java +@RunWith(Parameterized.class) +public class FibonacciTest { + + @Parameters(name = "{index}: fib({0})={1}") + public static Iterable data() { + return Arrays.asList(new Object[][] { { 0, 0 }, { 1, 1 }, { 2, 1 }, + { 3, 2 }, { 4, 3 }, { 5, 5 }, { 6, 8 } }); + } + + private int input; + private int expected; + + public FibonacciTest(int input, int expected) { + this.input = input; + this.expected = expected; + } + + @Test + public void test() { + assertEquals(expected, Fibonacci.compute(input)); + } +} +``` + +In the example given above, the `Parameterized` runner creates names like `[1: fib(3)=2]`. If you don't specify a name, the current parameter index will be used by default. + +### Test execution order + +By design, JUnit does not specify the execution order of test method invocations. Until now, the methods were simply invoked in the order returned by the reflection API. However, using the JVM order is unwise since the Java platform does not specify any particular order, and in fact JDK 7 returns a more or less random order. Of course, well-written test code would not assume any order, but some does, and a predictable failure is better than a random failure on certain platforms. + +From now on, JUnit will by default use a deterministic, but not predictable, order (`MethodSorters.DEFAULT`). To change the test execution order simply annotate your test class using `@FixMethodOrder` and specify one of the available `MethodSorters`: + +* `@FixMethodOrder(MethodSorters.JVM)`: Leaves the test methods in the order returned by the JVM. This order may vary from run to run. + +* `@FixMethodOrder(MethodSorters.NAME_ASCENDING)`: Sorts the test methods by method name, in lexicographic order. + +### Maven artifacts + +Up until now there were two Maven artifacts for JUnit: `junit:junit-dep` and `junit:junit`. From a Maven point-of-view only the former made sense because it did not contain the Hamcrest classes but declared a dependency to the Hamcrest Maven artifact. The latter included the Hamcrest classes which was very un-Maven-like. + +From this release on, you should use `junit:junit` which will be what `junit:junit-dep` used to. If you still reference `junit:junit-dep`, Maven will automatically relocate you to the new `junit:junit` and issue a warning for you to fix. + +### Rules + +A number of improvements have been made to Rules: + +* `MethodRule` is no longer deprecated. +* Both `@Rule` and `@ClassRule` can now be used on methods that return a `TestRule`. +* `ExpectedException` now always prints the stacktrace of the actual exception in case of failure. +* A parent folder can be specified for `TemporaryFolder`. In addition, the `newFile`/`newFolder` methods will now fail when the file or folder could not be created. +* `TestWatcher` has a new template method called `skipped` that is invoked when a test is skipped due to a failed assumption. + +### Improvements to Assert and Assume + +* `assertNotEquals` has been added to `Assert`. +* `assertEquals` has been overloaded in order to check whether two floats are equal given a certain float delta. +* Most methods in `Assume` now allow to pass a custom message. + diff --git a/doc/ReleaseNotes4.11.txt b/doc/ReleaseNotes4.11.txt new file mode 100644 index 000000000000..2138b03b4480 --- /dev/null +++ b/doc/ReleaseNotes4.11.txt @@ -0,0 +1 @@ +Please see ReleaseNotes4.11.md diff --git a/doc/ReleaseNotes4.12.md b/doc/ReleaseNotes4.12.md new file mode 100644 index 000000000000..744ecf369062 --- /dev/null +++ b/doc/ReleaseNotes4.12.md @@ -0,0 +1,734 @@ +## Summary of changes in version 4.12 + +# Assertions + +### [Pull request #611:](https://github.com/junit-team/junit4/pull/611) Assert.assertNotEquals() for `float` parameters + +Version 4.11 added `Assert.assertEquals()` for `float` parameters with a delta, and `Assert.assertNotEquals()`. This is the combination of those two features. + + +### [Pull request #632:](https://github.com/junit-team/junit4/pull/632) Assert.assertArrayEquals() for `boolean[]` parameters. + +`Assert.assertArrayEquals()` previously existed for all primitive array types, except `boolean[]`. This has now been added for `boolean[]`. + + +### [Pull request #918:](https://github.com/junit-team/junit4/pull/918) Avoid potentially expensive reflection-based loop in Assert.assertArrayEquals() + +In the usual case, where the array elements are in fact exactly equal, the potentially expensive reflection-based loop to compare them is avoided by using `Arrays.deepEquals()` first. The exact comparison is only executed when `deepEquals()` returns `false`. + + +# Command-line options +### [Pull request #647:](https://github.com/junit-team/junit4/pull/647) Support command-line `--filter` param. + +When running JUnit from the command line, a command-line parameter can be supplied using `--filter`, which supplies a filter that will restrict which tests and subtests from the rest of the command will be run. For example, this will run only the tests in ExampleTestSuite that are in categories Cat1 or Cat2: + +``` +java org.junit.runner.JUnitCore \ + --filter=org.junit.experimental.categories.IncludeCategories=pkg.of.Cat1,pkg.of.Cat2 \ + com.example.ExampleTestSuite +``` + +In general, the argument to `--filter` should be `ClassName=param`, where `ClassName` names an implementation of `FilterFactory`, whose `createFilter` method will be called with an instance of `FilterFactoryParams` that contains `"param"`, in order to return the filter to be applied. + +# Test Runners + + +### [Pull request #763:](https://github.com/junit-team/junit4/pull/763) Allow custom test runners to create their own TestClasses and customize the scanning of annotations. + +This introduces some extension points to `ParentRunner` to allow subclasses to control creation +of the `TestClass` instance and to scan for annotations. + +### [Pull request #817:](https://github.com/junit-team/junit4/pull/817) Support for context hierarchies + +The `AnnotatedBuilder` is a strategy for constructing runners for test classes that have been annotated with the `@RunWith` annotation. All tests within such a class will be executed using the runner that was specified within the annotation. + +Prior to JUnit 4.12, this covered only the tests within the annotated test class. With 4.12, the `AnnotationBuilder` will also support inner member classes. If a custom test runner supports inner member classes (which JUnit does not support out-of-the-box), the member classes will inherit the runner from the enclosing class, e.g.: + +```java +@RunWith(MyRunner.class) +public class MyTest { + // some tests might go here + + public class MyMemberClass { + @Test + public void thisTestRunsWith_MyRunner() { + // some test logic + } + + // some more tests might go here + } + + @RunWith(AnotherRunner.class) + public class AnotherMemberClass { + // some tests might go here + + public class DeepInnerClass { + @Test + public void thisTestRunsWith_AnotherRunner() { + // some test logic + } + } + + public class DeepInheritedClass extends SuperTest { + @Test + public void thisTestRunsWith_SuperRunner() { + // some test logic + } + } + } +} + +@RunWith(SuperRunner.class) +public class SuperTest { + // some tests might go here +} +``` + +The key points to note here are: + +* If there is no `@RunWith` annotation, no runner will be created. +* The resolve step is inside-out, e.g. the closest `@RunWith` annotation wins. +* `@RunWith` annotations are inherited and work as if the class was annotated itself. +* The default JUnit runner does not support inner member classes, so this is only valid for custom runners that support inner member classes. +* Custom runners with support for inner classes may or may not support `@RunWith` annotations for member classes. Please refer to the custom runner documentation. + +One example of a runner that makes use of this extension is the Hierarchical Context Runner (see https://github.com/bechte/junit-hierarchicalcontextrunner/wiki). + + +### [Pull request #716:](https://github.com/junit-team/junit4/pull/716) Fix annotation collection from superclasses of JUnit3 tests. + +Previously `Description.getAnnotations()` would always return an empty list for _test*_ methods derived from superclasses. + + +### [Pull request #625 (commit 72af03c49f):](https://github.com/junit-team/junit4/commit/72af03c49fdad5f10e36c7eb4e7045feb971d253) Make `RunNotifier` code concurrent. + +When running tests from multiple threads, JUnit will now call `RunListener` methods from multiple threads if the listener class is annotated with `@RunListener.ThreadSafe`. In addition, the code in `RunNotifier` has been modified to not use locks. + + +### [Pull request #684:](https://github.com/junit-team/junit4/pull/684) Adding `AnnotationValidator` framework and validation checks for `@Category`. + +This allows for validation to be added to annotations. Validators should extend `AnnotationValidator` and be attached to annotations with the `@ValidateWith` annotation. `CategoryValidator` extends `AnnotationValidator` and ensures that incompatible annotations (`@BeforeClass`, `@AfterClass`, `@Before`, `@After`) are not used in conjunction with `@Category`. + + +# Exception Testing + + +### [Pull request #583:](https://github.com/junit-team/junit4/pull/583) [Pull request #720:](https://github.com/junit-team/junit4/pull/720) Fix handling of `AssertionError` and `AssumptionViolatedException` in `ExpectedException` rule. + +`ExpectedException` didn't handle `AssertionError`s and `AssumptionViolatedException` well. This has been fixed. The new documentation explains the usage of `ExpectedException` for testing these exceptions. The two methods `handleAssertionErrors()` and `handleAssumptionViolatedExceptions()` are not needed anymore. If you have used them, just remove it and read `ExpectedException`'s documentation. + + +### [Pull request #818:](https://github.com/junit-team/junit4/pull/818) [Pull request #993:](https://github.com/junit-team/junit4/pull/993) External version of AssumptionViolatedException + +In JUnit 4.11 and earlier, if you wanted to write a custom runner that handled +`AssumptionViolatedException` or you needed to create an instance of `AssumptionViolatedException` +directly, you needed to import an internal class (`org.junit.internal.AssumptionViolatedException`). +Now you can import `org.junit.AssumptionViolatedException` (which extends +`org.junit.internal.AssumptionViolatedException`). + +The classes in `Assume` have been modified to throw `org.junit.AssumptionViolatedException`. + +The constructors in the external `AssumptionViolatedException` are also +simpler than the ones in the internal version. That being said, +it's recommended that you create `AssumptionViolatedException` via the methods in `Assume`. + + +### [Pull request #985:](https://github.com/junit-team/junit4/pull/985) Change AssumptionViolatedException to not set the cause to null; fixes issue #494 + +Previously, the `AssumptionViolatedException` constructors would explicitly set the cause to `null` +(unless you use a constructor where you provide a `Throwable`, in which case it would set that as +the cause). This prevented code directly creating the exception from setting a cause. + +With this change, the cause is only set if you pass in a `Throwable`. + +It's recommended that you create `AssumptionViolatedException` via the methods in `Assume`. + + +### [Pull request #542:](https://github.com/junit-team/junit4/pull/542) Customized failure message for `ExpectedException` + +`ExpectedException` now allows customization of the failure message when the test does not throw the expected exception. For example: + +```java +thrown.reportMissingExceptionWithMessage("FAIL: Expected exception to be thrown"); +``` + +If a custom failure message is not provided, a default message is used. + + +### [Pull request #1013:](https://github.com/junit-team/junit4/pull/1013) Make ErrorCollector#checkSucceeds generic + +The method `ErrorCollector.checkSucceeds()` is now generic. Previously, you could only pass +in a `Callable` and it returned `Object`. You can now pass any `Callable` and the +return type will match the type of the callable. + + +# Timeout for Tests +*See also [Timeout for tests](https://github.com/junit-team/junit4/wiki/Timeout-for-tests)* + +### [Pull request #823:](https://github.com/junit-team/junit4/pull/823) Throw `TestFailedOnTimeoutException` instead of plain `Exception` on timeout + +When a test times out, a `org.junit.runners.model.TestTimedOutException` is now thrown instead of a plain `java.lang.Exception`. + + +### [Pull request #742:](https://github.com/junit-team/junit4/pull/742) [Pull request #986:](https://github.com/junit-team/junit4/pull/986) `Timeout` exceptions now include stack trace from stuck thread (experimental) + +`Timeout` exceptions try to determine if there is a child thread causing the problem, and if so its stack trace is included in the exception in addition to the one of the main thread. This feature must be enabled with the timeout rule by creating it through the new `Timeout.builder()` method: + +```java +public class HasGlobalTimeout { + @Rule public final TestRule timeout = Timeout.builder() + .withTimeout(10, TimeUnit.SECONDS) + .withLookingForStuckThread(true) + .build(); + + @Test + public void testInfiniteLoop() { + for (;;) { + } + } +} +``` + + +### [Pull request #544:](https://github.com/junit-team/junit4/pull/544) New constructor and factories in `Timeout` + +`Timeout` deprecated the old constructor `Timeout(int millis)`. +A new constructor is available: `Timeout(long timeout, TimeUnit unit)`. It enables you to use different granularities of time units like `NANOSECONDS`, `MICROSECONDS`, `MILLISECONDS`, and `SECONDS`. Examples: + +```java +@Rule public final TestRule globalTimeout = new Timeout(50, TimeUnit.MILLISECONDS); +``` + +```java +@Rule public final TestRule globalTimeout = new Timeout(10, TimeUnit.SECONDS); +``` + +and factory methods in `Timeout`: + +```java +@Rule public final TestRule globalTimeout = Timeout.millis(50); +``` + +```java +@Rule public final TestRule globalTimeout = Timeout.seconds(10); +``` + +This usage avoids the truncation, which was the problem in the deprecated constructor `Timeout(int millis)` when casting `long` to `int`. + + +### [Pull request #549:](https://github.com/junit-team/junit4/pull/549) fixes for #544 and #545 + +The `Timeout` rule applies the same timeout to all test methods in a class: + +```java +public class HasGlobalTimeout { + @Rule + public Timeout globalTimeout = new Timeout(10, TimeUnit.SECONDS); + + @Test + public void testInfiniteLoop() { + for (;;) { + } + } + + @Test + public synchronized void testInterruptableLock() throws InterruptedException { + wait(); + } + + @Test + public void testInterruptableIO() throws IOException { + for (;;) { + FileChannel channel = new RandomAccessFile(file, "rw").getChannel(); + + // Interrupted thread closes channel and throws ClosedByInterruptException. + channel.write(buffer); + channel.close(); + } + } +} +``` +Each test is run in a new _daemon_ thread. If the specified timeout elapses before the test completes, its execution is interrupted via `Thread#interrupt()`. This happens in interruptable I/O (operations throwing `java.io.InterruptedIOException` and `java.nio.channels.ClosedByInterruptException`), locks (package `java.util.concurrent`) and methods in `java.lang.Object` and `java.lang.Thread` throwing `java.lang.InterruptedException`. + +### [Pull request #876:](https://github.com/junit-team/junit4/pull/876) The timeout rule never times out if you pass in a timeout of zero. + +A specified timeout of 0 will be interpreted as not set, however tests still launch from separate threads. This can be useful for disabling timeouts in environments where they are dynamically set based on some property. + + +# Parameterized Tests + + +### [Pull request #702:](https://github.com/junit-team/junit4/pull/702) Support more return types for the `@Parameters` method of the `Parameterized` runner + +The return types `Iterator`, `Object[]` and `Object[][]` are now supported on methods annotated with `@Parameters`. You don't have to wrap arrays with `Iterable`s and single parameters with `Object` arrays. + + +### [Pull request #773:](https://github.com/junit-team/junit4/pull/773) Allow configurable creation of child runners of parameterized suites + +The factory for creating the `Runner` instance of a single set of parameters is now configurable. It can be specified by the `@UseParametersRunnerFactory` annotation. + + +# Rules + + +### [Pull request #552:](https://github.com/junit-team/junit4/pull/552) [Pull request #937:](https://github.com/junit-team/junit4/pull/937) `Stopwatch` rule + +The `Stopwatch` Rule notifies one of its own protected methods of the time spent by a test. Override them to get the time in nanoseconds. For example, this class will keep logging the time spent by each passed, failed, skipped, and finished test: + +```java +public static class StopwatchTest { + private static final Logger logger = Logger.getLogger(""); + + private static void logInfo(String testName, String status, long nanos) { + logger.info(String.format("Test %s %s, spent %d microseconds", + testName, status, Stopwatch.toMicros(nanos))); + } + + @Rule + public Stopwatch stopwatch = new Stopwatch() { + @Override + protected void succeeded(long nanos, Description description) { + logInfo(description.getMethodName(), "succeeded", nanos); + } + + @Override + protected void failed(long nanos, Throwable e, Description description) { + logInfo(description.getMethodName(), "failed", nanos); + } + + @Override + protected void skipped(long nanos, AssumptionViolatedException e, Description description) { + logInfo(description.getMethodName(), "skipped", nanos); + } + + @Override + protected void finished(long nanos, Description description) { + logInfo(description.getMethodName(), "finished", nanos); + } + }; + + @Test + public void succeeds() { + } + + @Test + public void fails() { + fail(); + } + + @Test + public void skips() { + assumeTrue(false); + } +} +``` + +An example to assert running time: + +```java +@Test +public void performanceTest() throws InterruptedException { + long delta = 30; + Thread.sleep(300L); + assertEquals(300D, stopwatch.runtime(MILLISECONDS), delta); + Thread.sleep(500L); + assertEquals(800D, stopwatch.runtime(MILLISECONDS), delta); +} +``` + +### [Pull request #932:](https://github.com/junit-team/junit4/pull/932) Allow static `@Rule`s also annotated with `@ClassRule` + +JUnit 4.11 introduced restrictions requiring `@Rule` members to be non-static and `@ClassRule` members to be static. These restrictions have been relaxed slightly, in that a static member annotated with both `@Rule` and `@ClassRule` is now considered valid. This means a single rule may be used to perform actions both before/after a class (e.g. setup/tear down an external resource) and between tests (e.g. reset the external resource), without the need for any workarounds mentioned in issue [#793](https://github.com/junit-team/junit4/issues/793). + +Note that a non-static `@ClassRule` annotated member is still considered invalid, even if annotated with `@Rule`. + +```java +public class CommonRuleTest { + @Rule + @ClassRule + public static MySetupResetAndTearDownRule rule = new MySetupResetAndTearDownRule(); +} +``` + +Be warned that if you have static methods or fields annotated with `@Rule` you will not be able to run your test methods in parallel. + +### [Pull request #956:](https://github.com/junit-team/junit4/pull/956) `DisableOnDebug` rule + +The `DisableOnDebug` rule allows users to disable other rules when the JVM is launched in debug mode. Prior to this feature the common approach to disable rules that make debugging difficult was to comment them out and remember to revert the change. When using this feature users no longer have to modify their test code nor do they need to remember to revert changes. + +This rule is particularly useful in combination with the `Timeout` rule. + +``` +@Rule +public DisableOnDebug timeout = new DisableOnDebug(Timeout.seconds(1)); +``` + +See the Javadoc for more detail and limitations. Related to https://github.com/junit-team/junit4/issues/738 + +### [Pull request #974:](https://github.com/junit-team/junit4/pull/974) Updated `TemporaryFolder.newFolder()` to give an error message if a path contains a slash. + +If you call `TemporaryFolder.newFolder("foo/bar")` in JUnit 4.10 the method returns a `File` object for the new folder but actually fails to create it. That is contrary to the expected behaviour of the method which is to actually create the folder. In JUnit 4.11 the same call throws an exception. Nowhere in the documentation does it explain that the String(s) passed to that method can only be single path components. + +With this fix, folder names are validated to contain single path name. If the folder name consists of multiple path names, an exception is thrown stating that usage of multiple path components in a string containing folder name is disallowed. + +### [Pull request #1015:](https://github.com/junit-team/junit4/pull/1015) Methods annotated with `Rule` can return a `MethodRule`. + +Methods annotated with `@Rule` can now return either a `TestRule` (or subclass) or a +`MethodRule` (or subclass). + +Prior to this change, all public methods annotated with `@Rule` were called, but the +return value was ignored if it could not be assigned to a `TestRule`. After this change, +the method is only called if the return type could be assigned to `TestRule` or +`MethodRule`. For methods annotated with `@Rule` that return other values, see the notes +for pull request #1020. + +### [Pull request #1020:](https://github.com/junit-team/junit4/pull/1020) Added validation that @ClassRule should only be implementation of TestRule. + +Prior to this change, fields annotated with `@ClassRule` that did not have a type of `TestRule` +(or a class that implements `TestRule`) were ignored. With this change, the test will fail +with a validation error. + +Prior to this change, methods annotated with `@ClassRule` that did specify a return type +of `TestRule`(or a class that implements `TestRule`) were ignored. With this change, the test +will fail with a validation error. + +### [Pull request #1021:](https://github.com/junit-team/junit4/pull/1021) JavaDoc of TemporaryFolder: folder not guaranteed to be deleted. + +Adjusted JavaDoc of TemporaryFolder to reflect that temporary folders are not guaranteed to be +deleted. + +# Theories + + +### [Pull request #529:](https://github.com/junit-team/junit4/pull/529) `@DataPoints`-annotated methods can now yield `null` values + +Up until JUnit 4.11 a `@DataPoints`-annotated array field could contain `null` values, but the array returned by a `@DataPoints`-annotated method could not. This asymmetry has been resolved: _both_ can now provide a `null` data point. + + +### [Pull request #572:](https://github.com/junit-team/junit4/pull/572) Ensuring no-generic-type-parms validator called/tested for theories + +The `Theories` runner now disallows `Theory` methods with parameters that have "unresolved" generic type parameters (e.g. `List` where `T` is a type variable). It is exceedingly difficult for the `DataPoint(s)` scraper or other `ParameterSupplier`s to correctly decide values that can legitimately be assigned to such parameters in a type-safe way, so JUnit now disallows them altogether. Theory parameters such as `List` and `Iterable` are still allowed. + +The machinery to perform this validation was in the code base for some time, but not used. It now is used. + +[junit.contrib](https://github.com/junit-team/junit.contrib)'s rendition of theories performs the same validation. + + +### [Pull request #607:](https://github.com/junit-team/junit4/pull/607) Improving theory failure messages + +Theory failure messages previously were of the form: `ParameterizedAssertionError: theoryTest(badDatapoint, allValues[1], otherVar)`, where allValues, badDatapoint and otherVar were the variables the datapoints was sourced from. These messages are now of the form: + +```java +ParameterizedAssertionError: theoryTest(null , "good value" , + [toString() threw RuntimeException: Error message] ) +``` + + +### [Pull request #601:](https://github.com/junit-team/junit4/pull/601) Allow use of `Assume` in tests run by `Theories` runner + +If, in a theory, all parameters were "assumed" away, the `Theories` runner would properly fail, informing you that no parameters were found to actually test something. However, if you had another method in that same class, that was not a theory (annotated with `@Test` only,) you could not use Assume in that test. Now, the `Theories` runner will verify the method is annotated with `@Theory` before failing due to no parameters being found. + +```java +@RunWith(Theories.class) +public class TheoriesAndTestsTogether { + @DataPoint + public static Object o; + + @Theory + public void theory(Object o) { + // this will still fail: java.lang.AssertionError: Never found parameters that satisfied method assumptions. + Assume.assumeTrue(false); + } + + @Test + public void test() { + // this will no longer fail + Assume.assumeTrue(false); + } +} +``` + + +### [Pull request #623:](https://github.com/junit-team/junit4/pull/623) Ensure data points array fields and methods are `public` and `static` in Theory classes. + +Previously if a data points array field or method was non-`static` or non-`public` it would be silently ignored and the data points not used. Now the `Theories` runner verifies that all `@DataPoint` or `@DataPoints` annotated fields or methods in classes are both `public` and `static`, and such classes will fail to run with `InitializationError`s if they are not. + + +### [Pull request #621:](https://github.com/junit-team/junit4/pull/621) Added mechanism for matching specific data points in theories to specific parameters, by naming data points. + +`@DataPoints` fields or methods can now be given (one or more) names in the annotation, and `@Theory` method parameters can be annotated with `@FromDataPoints(name)`, to limit the data points considered for that parameter to only the data points with that name: + +```java +@DataPoints +public static String[] unnamed = new String[] { ... }; + +@DataPoints("regexes") +public static String[] regexStrings = new String[] { ... }; + +@DataPoints({"forMatching", "alphanumeric"}) +public static String[] testStrings = new String[] { ... }; + +@Theory +public void stringTheory(String param) { + // This will be called with every value in 'regexStrings', + // 'testStrings' and 'unnamed'. +} + +@Theory +public void regexTheory(@FromDataPoints("regexes") String regex, + @FromDataPoints("forMatching") String value) { + // This will be called with only the values in 'regexStrings' as + // regex, only the values in 'testStrings' as value, and none + // of the values in 'unnamed'. +} +``` + + +### [Pull request #654:](https://github.com/junit-team/junit4/pull/654) Auto-generation of `enum` and `boolean` data points + +Any theory method parameters with `boolean` or `enum` types that cannot be supplied with values by any other sources will be automatically supplied with default values: `true` and `false`, or every value of the given `enum`. If other explicitly defined values are available (e.g. from a specified `ParameterSupplier` or some `DataPoints` method in the theory class), only those explicitly defined values will be used. + + +### [Pull request #651:](https://github.com/junit-team/junit4/pull/651) Improvements to Theory parameter and DataPoint type matching + + * Validity of `DataPoints` for theory parameters for all field data points and multi-valued method data points (i.e. not single-valued method data points) is now done on runtime type, not field/method return type (previously this was the case for multi-valued array methods only). + + * Validity of `DataPoints` for theory parameters for all data points now correctly handles boxing and unboxing for primitive and wrapper types; e.g. `int` values will be considered for theory parameters that are `Integer` assignable, and vice versa. + + +### [Pull request #639:](https://github.com/junit-team/junit4/pull/639) Failing theory datapoint methods now cause theory test failures + +Previously `@DataPoint(s)` methods that threw exceptions were quietly ignored and if another `DataPoint` source was available then those values alone were used, leaving the theory passing using only a subset of the (presumably) intended input values. Now, any data point method failures during invocation of a theory will cause the theory being tested to fail immediately. + +*This is a non-backward-compatible change*, and could potentially break theory tests that depended on failing methods. If that was desired behavior, then the expected exceptions can instead be specifically ignored using the new `ignoredExceptions` array attribute on `@DataPoint` and `@DataPoints` methods. Adding an exception to this `ignoredExceptions` array will stop theory methods from failing if the given exception, or subclasses of it, are thrown in the annotated method. This attribute has no effect on data point fields. + + +### [Pull request #658:](https://github.com/junit-team/junit4/pull/658) `Iterable`s can now be used as data points + +Previously, when building sets of data points for theory parameters, the only valid multi-valued `@DataPoints` types were arrays. This has now been extended to also take parameters from `Iterable` `@DataPoints` methods and fields. + + +# Categories + + +### [Pull request #566:](https://github.com/junit-team/junit4/pull/566) Enables inheritance on `Category` by adding `@Inherited` + +`@interface Category` now is annotated with `@Inherited` itself. This enables inheritance of categories from ancestors (e.g. abstract test-classes). Note that you are able to "overwrite" `@Category` on inheritors and that this has no effect on method-level categories (see [@Inherited](http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/annotation/Inherited.html)). + + +### [Pull request #503:](https://github.com/junit-team/junit4/pull/503) Configurable Categories + +From a given set of test classes, the `Categories` runner runs only the classes and methods +that are annotated with either the category given with the `@IncludeCategory` annotation, or a subtype of that category. Either classes or interfaces can be used as categories. Subtyping works, so if you say `@IncludeCategory(SuperClass.class)`, a test marked `@Category({SubClass.class})` will be run. + +You can also exclude categories by using the `@ExcludeCategory` annotation; see `SlowTestSuiteWithoutFast`. + +The suite `FastOrSmokeTestSuite` is an example to run multiple categories. + +To execute tests which match all categories, use `matchAny = false` in annotations. See `FastAndSmokeTestSuite`. + +Example: + +```java +public static interface FastTests { /* category marker */ } +public static interface SlowTests { /* category marker */ } +public static interface SmokeTests { /* category marker */ } + +public static class A { + public void a() { + fail(); + } + + @Category(SlowTests.class) + @Test + public void b() { + } + + @Category({FastTests.class, SmokeTests.class}) + @Test + public void c() { + } +} + +@Category({SlowTests.class, FastTests.class}) +public static class B { + @Test + public void d() { + } +} + +@RunWith(Categories.class) +@Categories.IncludeCategory(SlowTests.class) +@Suite.SuiteClasses({A.class, B.class}) +public static class SlowTestSuite { + // Will run A.b and B.d, but not A.a and A.c +} + +@RunWith(Categories.class) +@Categories.IncludeCategory({FastTests.class, SmokeTests.class}) +@Suite.SuiteClasses({A.class, B.class}) +public static class FastOrSmokeTestSuite { + // Will run A.c and B.d, but not A.b because it is not any of FastTests or SmokeTests +} + +@RunWith(Categories.class) +@Categories.IncludeCategory(value = {FastTests.class, SmokeTests.class}, matchAny = false) +@Suite.SuiteClasses({A.class, B.class}) +public static class FastAndSmokeTestSuite { + // Will run only A.c => match both FastTests AND SmokeTests +} + +@RunWith(Categories.class) +@Categories.IncludeCategory(SlowTests.class) +@Categories.ExcludeCategory(FastTests.class) +@Suite.SuiteClasses({A.class, B.class}) // Note that Categories is a kind of Suite +public class SlowTestSuiteWithoutFast { + // Will run A.b, but not A.a, A.c or B.d +} +``` + + +# Use with Maven + + +### [Pull request #879:] (https://github.com/junit-team/junit4/pull/879) Add the default 'Implementation-*' headers to the manifest + +The default Maven-style 'Implementation-*' headers are now present in the manifest of `junit.jar`. Example: +``` +Implementation-Vendor: JUnit +Implementation-Title: JUnit +Implementation-Version: 4.12 +Implementation-Vendor-Id: junit +``` + + +### [Pull request #511:](https://github.com/junit-team/junit4/pull/511) Maven project junit:junit:jar + + +#### How to install Maven + +Download the Maven binary [http://www.us.apache.org/dist/maven/maven-3/3.0.4/binaries](http://www.us.apache.org/dist/maven/maven-3/3.0.4/binaries). + +(wget http://www.us.apache.org/dist/maven/maven-3/3.0.4/binaries/apache-maven-3.0.4-bin.tar.gz) + +If you are in the project root, extract the archive (tar xvzf apache-maven-3.0.4-bin.tar.gz). +Create directory _.m2_ in your _user home_. Then the artifacts and plugins are stored in `~/.m2/repository`. +( _~_ stands for user home) + + +#### How to launch the build from the command line + +Clone the project (git clone https://github.com/junit-team/junit4.git) and navigate to the project root on your local system (cd junit). +Clean the previous build in _target_ directory, build the project, and install new artifacts in your local repository: + +`apache-maven-3.0.4/bin/mvn clean install` + +On Windows type the command `apache-maven-3.0.4\bin\mvn clean install`. + +Set the environment variables `M2_HOME` and `PATH` when frequently building via command line `mvn clean install`. + +[http://maven.apache.org/guides/development/guide-building-m2.html#Building_Maven_Without_Maven_Installed](http://maven.apache.org/guides/development/guide-building-m2.html#Building_Maven_Without_Maven_Installed) + + +#### How to install and build the Maven project in Eclipse + +I made a clone of JUnit project from GitHub to local folder `C:\cygwin\usr\local\etc\junit`. + +In menu go to _File -> Import..._ + +In the popup menu open section _Maven_, click on _Existing Maven Projects_ and click on _Next_. In _Import Maven Projects_ specify the project root, and next proceed further with installing maven support plugin in Eclipse. + +You have created the Maven project, and now build the project. + +In the Package Explorer click on _pom.xml_. In the menu _Run -> Run As -> 2 Maven build..._ open the popup _Edit Configuration_ and specify the build phase _clean install_ in section _Goals_. Click on _Run_ and build the project. + +#### How to install and build the Maven project in IntelliJ IDEA + +In IDEA menu create a new project _File -> New Project..._. + +Select _Create Java project from existing sources_, then click on Next and specify _Project file location_. + +On the right-hand side is the _Maven Projects_ tab. Click on + and add _pom.xml_ into the project. Then click on the icon _Maven Settings_, and set _Maven home directory_ as the location of extracted Maven archive on your system. Click on the green triangle and launch the build. + +See the IntelliJ IDEA Web help +[http://www.jetbrains.com/idea/webhelp/maven-2.html](http://www.jetbrains.com/idea/webhelp/maven-2.html) + +#### How to install the Maven project with documentation +Use the profile `generate-docs` to build _sources.jar_ and _javadoc.jar_. Building Maven site is not yeat supported. + +Example: `mvn -Pgenerate-docs install` + +#### How to activate and deactivate Maven profiles in Integrated Development Environments: + +In _Eclipse_, from the main menu navigate to Run -> Run As -> 2 Maven build..., open the popup _Edit Configuration_ and specify the profiles. + +Follow this link for _IntelliJ IDEA_: [http://www.jetbrains.com/idea/webhelp/activating-and-deactivating-maven-profiles.html](http://www.jetbrains.com/idea/webhelp/activating-and-deactivating-maven-profiles.html) + + +# Miscellaneous + + +### [Pull request #776:](https://github.com/junit-team/junit4/pull/776) Add support for [Travis CI](http://travis-ci.org) + +Travis CI is a free CI server for public Github repositories. Every pull request is run by Travis CI and Github's web interface shows the CI result for each pull request. Every user can use Travis CI for testing her branches, too. + +### [Pull request #921:](https://github.com/junit-team/junit4/pull/921) Apply Google Code Style + +JUnit is now using the well documented [Google Code Style](http://google-styleguide.googlecode.com/svn/trunk/javaguide.html) + +### [Pull request #939](https://github.com/junit-team/junit4/pull/939) Renamed license file + +While using JUnit in Android apps, if any other referenced library has a file named `LICENSE.txt`, the APK generation failed with the following error - + +`Error generating final archive: Found duplicate file for APK: LICENSE.txt` + +To avoid this, the license file has been renamed to `LICENSE-junit.txt` + + +### [Pull request #962:](https://github.com/junit-team/junit4/pull/962) Do not include thread start time in test timeout measurements. + +The time it takes to start a thread can be surprisingly large. +Especially in virtualized cloud environments where noisy neighbours. +This change reduces the probability of non-deterministic failures of +tests with timeouts (@Test(timeout=…)) by not beginning the timeout +clock until we have observed the starting of the task thread – the +thread that runs the actual test. This should make tests with small +timeout values more reliable in general, and especially in cloud CI +environments. + +# Fixes to issues introduced in JUnit 4.12 + +The following section lists fixes to problems introduced in the first +release candidates for JUnit 4.12. You can ignore this section if you are +trying to understand the changes between 4.11 and 4.12. + +### [Pull request #961:](https://github.com/junit-team/junit4/pull/961) Restore field names with f prefix. + +In order to make the JUnit code more consistent with current coding practices, we changed +a number of field names to not start with the prefix "f". Unfortunately, at least one IDE +referenced a private field via reflection. This change reverts the field names for fields +known to be read via reflection. + +### [Pull request #988:](https://github.com/junit-team/junit4/pull/988) Revert "Delete classes that are deprecated for six years." + +In [745ca05](https://github.com/junit-team/junit4/commit/745ca05dccf5cc907e43a58142bb8be97da2b78f) +we removed classes that were deprecated for many releases. There was some concern that people +might not expect classes to be removed in a 4.x release. Even though we are not aware of any +problems from the deletion, we decided to add them back. + +These classes may be removed in JUnit 5.0 or later. + +### [Pull request #989:](https://github.com/junit-team/junit4/pull/989) Add JUnitSystem.exit() back. + +In [917a88f](https://github.com/junit-team/junit4/commit/917a88fad06ce108a596a8fdb4607b1a2fbb3f3e) +the exit() method in JUnit was removed. This caused problems for at least one user. Even +though this class is in an internal package, we decided to add it back, and deprecated it. + +This method may be removed in JUnit 5.0 or later. + +### [Pull request #994:](https://github.com/junit-team/junit4/pull/994) [Pull request #1000:](https://github.com/junit-team/junit4/pull/1000) Ensure serialization compatibility where possible. + +JUnit 4.12 RC1 introduced serilization incompatibilities with some of the classes. For example, +these pre-release versions of JUnit could not read instances of `Result` that were serialized +in JUnit 4.11 and earlier. These changes fix that problem. + diff --git a/doc/ReleaseNotes4.13.1.md b/doc/ReleaseNotes4.13.1.md new file mode 100644 index 000000000000..ab44490622c6 --- /dev/null +++ b/doc/ReleaseNotes4.13.1.md @@ -0,0 +1,7 @@ +## Summary of changes in version 4.13.1 + +# Test Runners + +### [Pull request #1669:](https://github.com/junit-team/junit/pull/1669) Make `FrameworkField` constructor public + +Prior to this change, custom runners could make `FrameworkMethod` instances, but not `FrameworkField` instances. This small change allows for both now, because `FrameworkField`'s constructor has been promoted from package-private to public. diff --git a/doc/ReleaseNotes4.13.md b/doc/ReleaseNotes4.13.md new file mode 100644 index 000000000000..a3ec73e178cf --- /dev/null +++ b/doc/ReleaseNotes4.13.md @@ -0,0 +1,327 @@ +## Summary of changes in version 4.13 + +# Assertions + +### [Pull request #1054:](https://github.com/junit-team/junit/pull/1054) Improved error message for `assertArrayEquals` when multi-dimensional arrays have different lengths + +Previously, JUnit's assertion error message would indicate only that some array lengths _x_ and _y_ were unequal, without indicating whether this pertained to the outer array or some nested array. Now, in case of a length mismatch between two nested arrays, JUnit will tell at which indices they reside. + +### [Pull request #1154](https://github.com/junit-team/junit/pull/1154) and [#1504](https://github.com/junit-team/junit/pull/1504) Add `assertThrows` + +The `Assert` class now includes methods that can assert that a given function call (specified, for instance, as a lambda expression or method reference) results in a particular type of exception being thrown. In addition it returns the exception that was thrown, so that further assertions can be made (e.g. to verify that the message and cause are correct). + +### [Pull request #1300:](https://github.com/junit-team/junit/pull/1300) Show contents of actual array when array lengths differ + +Previously, when comparing two arrays which differ in length, `assertArrayEquals()` would only report that they differ in length. Now, it does the usual array comparison even when arrays differ in length, producing a failure message which combines the difference in length and the first difference in content. Where the content is another array, it is described by its type and length. + +### [Pull request #1315:](https://github.com/junit-team/junit4/pull/1315) `assertArrayEquals` shouldn't throw an NPE when test suites are compiled/run across versions of junit + +A redundant field, `fCause`, was removed on v4.12, and was seemingly harmless because `Throwable#initCause()` could directly initialize `cause` in the constructor. Unfortunately, this backwards incompatible change got aggravated when a test class, compiled with the latest (4.12+), ran with an older version that depended on fCause when building the assertion message[1](#1315-f1). + +This change adds back `fCause`, and overrides `getCause()` to handle forward compatibility[2](#1315-f2). + +To ensure serializability of further changes in `ArrayAssertionFailure` (until excising these fields by a major rev), a unit test now runs against v4.11, v4.12 failures, asserting around `#toString/getCause()`. + +[1] [Issue #1178](https://github.com/junit-team/junit4/issues/1178) details a particular case where gradle v2.2 is packaged with junit v4.11 and is used on running a test, generating test reports, despite specifying a particular version of junit (users would specify v4.12, or v4.+) in the test compile dependencies). + +[2] [Case](https://github.com/junit-team/junit4/pull/1315#issuecomment-222905229) if the test class is compiled with <= v4.11, where only `fCause` is initialized and not `Throwable#cause`, it can now fallback to the field, `fCause`, when building the message. + +### [Pull request #1150:](https://github.com/junit-team/junit4/pull/1150) Deprecate `Assert#assertThat` + +The method `assertThat` is used for writing assertions with Hamcrest. Hamcrest is an independent assertion library and contains an own `assertThat` method in the class `org.hamcrest.MatcherAssert`. It is available both in the old Hamcrest 1.3 release and in the current Hamcrest 2.1. Therefore the JUnit team recommends to use Hamcrest's own `assertThat` directly. + +# Test Runners + +### [Pull request #1037:](https://github.com/junit-team/junit/pull/1037) `BlockJUnit4ClassRunner#createTest` now accepts `FrameworkMethod` + +Subclasses of `BlockJUnit4ClassRunner` can now produce a custom test object based on the `FrameworkMethod` test being executed by implementing the new `createTest(FrameworkMethod)` method. The default implementation calls the existing `createTest()` method. + +### [Pull request #1082](https://github.com/junit-team/junit/pull/1082): Ensure exceptions from `BlockJUnit4ClassRunner.methodBlock()` don't result in unrooted tests + +The introduction of the `runLeaf()` method in `BlockJUnit4ClassRunner` in JUnit 4.9 introduced a regression with regard to exception handling. Specifically, in JUnit 4.9 through 4.12 the invocation of `methodBlock()` is no longer executed within a try-catch block as was the case in previous versions of JUnit. Custom modifications to `methodBlock()` or the methods it invokes may in fact throw exceptions, and such exceptions cause the current test execution to abort immediately. As a result, the failing test method is unrooted in test reports, and subsequent test methods are never invoked. Furthermore, any `RunListener` registered with JUnit is not notified. + +As of JUnit 4.13, the invocation of `methodBlock()` is once again wrapped within a try-catch block. If an exception is _not_ thrown, the resulting `Statement` is passed to `runLeaf()`. If an exception _is_ thrown, it is wrapped in a `Fail` statement which is passed to `runLeaf()`. + +### [Pull request #1286](https://github.com/junit-team/junit/pull/1286): Provide better feedback to the user in case of invalid test classes + +Only one exception per invalid test class is now thrown, rather than one per validation error. +The message of the exception includes all of the validation errors. + +Example: + + org.junit.runners.InvalidTestClassError: Invalid test class 'com.example.MyTest': + 1. Method staticAfterMethod() should not be static + 2. Method staticBeforeMethod() should not be static + +is the exception thrown when running the following test class with any kind of `ParentRunner`: + + public class MyTest { + + @Before + public static void staticBeforeMethod() { .. } + + @After + public static void staticAfterMethod() { .. } + + @Test + public void myTest() { .. } + } + +Validation errors for the same test class now count only once in the failure count. Therefore, in the example above, `Result#getFailureCount` will return 1. + +### [Pull request #1252](https://github.com/junit-team/junit4/pull/1252): Restore ability use ParentRunner lost in separate class loader + +`ParentRunner.getDescription()` now uses the class instance of the test class to create the description +(previously the class instance was loaded using the current classloader). + +### [Pull request #1377](https://github.com/junit-team/junit4/pull/1377): Description produced by Request.classes() shouldn't be null + +When obtaining a `Runner` via [Request.classes(Class... classes)](http://junit.org/junit4/javadoc/4.12/org/junit/runner/Request.html#classes(java.lang.Class...)), that Runner's `Description` will now print "classes" for the root item. This replaces the misleading output of String "null". + +### [Issue #1290](https://github.com/junit-team/junit4/issues/1290): Tests expecting AssumptionViolatedException are now correctly marked as passed + + @Test(expected = AssumptionViolatedException.class) + public void shouldThrowAssumptionViolatedException() { + throw new AssumptionViolatedException("expected"); + } + +This test would previously be marked as skipped; now will be marked as passed. + + +### [Pull request #1465](https://github.com/junit-team/junit/pull/1465): Provide helpful message if parameter cannot be set. + +JUnit throws an exception with a message like + + Cannot set parameter 'name'. Ensure that the the field 'name' is public. + +if a field of a parameterized test is annotated `@Parameter`, but its visibility is not public. Before an IllegalAccessException was thrown with a message like "Class ... can not access a member of class X with modifiers private". + + +### [Issue #1329](https://github.com/junit-team/junit4/issus/1329): Support assumptions in `@Parameters` method + +No test is run when an assumption in the `@Parameters` method fails. The test result for this test class contains one assumption failure and run count is zero. + + +### [Pull request #1449](https://github.com/junit-team/junit/pull/1449): Parameterized runner reuses TestClass instance + +Reduce memory consumption of parameterized tests by not creating a new instance of `TestClass` for every test. + +### [Pull request #1130](https://github.com/junit-team/junit/pull/1130): Add Ordering, Orderable and @OrderWith + +Test classes can now be annotated with `@OrderWith` to specify that the tests should execute in a particular +order. All runners extending `ParentRunner` support `@OrderWith`. Runners can also be ordered using +`Request.orderWith(Ordering)` + +Classes annotated with `@RunWith(Suite.class)` can also be ordered with `@OrderWith`. Note that if this is done, nested classes annotated with `@FixMethodOrder` will not be reordered (i.e. the `@FixMethodOrder` annotation is +always respected). Having a test class annotated with both `@OrderWith` and `@FixMethodOrder` will result in a +validation error (see +[pull request #1638](https://github.com/junit-team/junit4/pull/1638)). + +### [Pull request #1408](https://github.com/junit-team/junit/pull/1408): Suites don't have to be public + +Classes annotated with `@RunWith(Suite.class)` do not need to be public. This fixes a regression bug in JUnit 4.12. Suites didn't had to be public before 4.12. + +### [Pull request #1638](https://github.com/junit-team/junit4/pull/1638): Never reorder classes annotated with @FixMethodOrder + +Changing the order of a test run using `Request.sortWith()` no longer changes the order of test classes annotated +with `@FixMethodOrder`. The same holds true when you reorder tests with `Request.orderWith()` (`orderWith()` +was introduced in [Pull request #1130](https://github.com/junit-team/junit/pull/1130)). + +This was done because usually `@FixMethodOrder` is added to a class because the tests in the class they only pass +if run in a specific order. + +Test suites annotated with `@OrderWith` will also respect the `@FixMethodOrder` annotation. + +Having a test class annotated with both `@OrderWith` and `@FixMethodOrder` will result in a validation error. + +# Rules + +### [Pull request #1044:](https://github.com/junit-team/junit/pull/1044) Strict verification of resource deletion in `TemporaryFolder` rule + +Previously `TemporaryFolder` rule did not fail the test if some temporary resources could not be deleted. With this change a new `assuredDeletion` parameter is introduced which will fail the test with an `AssertionError`, if resource deletion fails. The default behavior of `TemporaryFolder` is unchanged. + +This feature must be enabled by creating a `TemporaryFolder` using the `TemporaryFolder.builder()` method: +```java +@Rule public TemporaryFolder folder = TemporaryFolder.builder().assureDeletion().build(); +``` + +### [Issue #1100:](https://github.com/junit-team/junit/issues/1110) StopWatch does not need to be abstract. + +Previously `StopWatch` was an abstract class, which means it cannot be used without extending it or using an anonymous class. The abstract modifier has been removed and StopWatch can be used easily now. + +### [Issue #1157:](https://github.com/junit-team/junit/issues/1157) TestName: Make 'name' field volatile + +The `name` field in the `TestName` rule was updated to be volatile. This should ensure that the name +is published even when tests are running in parallel. + +### [Issue #1223:](https://github.com/junit-team/junit/issues/1223) TemporaryFolder doesn't work for parallel test execution in several JVMs + +Previously `TemporaryFolder` rule silently succeeded if it failed to create a fresh temporary directory. With this change it will notice the failure, retry with a new name, and ultimately throw an `IOException` if all such attempts fail. + +### [Pull request #1305:](https://github.com/junit-team/junit/pull/1305) Add `ErrorCollector.checkThrows` + +The `ErrorCollector` class now has a `checkThrows` method that can assert that a given function call (specified, for instance, as a lambda expression or method reference) results in a particular type of exception being thrown. + +### [Issue #1303:](https://github.com/junit-team/junit/issues/1303) Prevent following symbolic links when deleting temporary directories + +Previously, `TemporaryFolder` would follow symbolic links; now it just deletes them. + +Following symbolic links when removing files can lead to the removal of files outside the directory structure rooted in the temporary folder, and it can lead to unbounded recursion if a symbolic link points to a directory where the link is directly reachable from. + +### [Issue #1295:](https://github.com/junit-team/junit/issues/1295) Javadoc for RuleChain contains errors + +Removed error from RuleChain Javadoc and clarified how it works with existing rules. Removed `static` modifier, added missing closing parenthesis of method calls and added clarification. + +### [Pull request #1313](https://github.com/junit-team/junit4/pull/1313): `RuleChain.around()` rejects null arguments +`RuleChain.around()` now implements a fail-fast strategy which also allows for better feedback to the final user, as the stacktrace will point to the exact line where the null rule is declared. + +### [Pull request #1397](https://github.com/junit-team/junit4/pull/1397): Change generics on `ExpectedException.expectCause()` +The signature of `ExpectedException.expectCause()` would not allow the caller to pass in a `Matcher` (which is returned by `CoreMatchers.notNullValue()`). This was fixed by changing the method to take in a +`Matcher` (ideally, the method should take in `Matcher` but there was concern that +changing the parameter type to `Matcher` would break some callers). + +### [Pull request #1443](https://github.com/junit-team/junit4/pull/1443): `ExpectedException.isAnyExceptionExpected()` is now public +The method `ExpectedException.isAnyExceptionExpected()` returns `true` if there is at least one expectation present for the `ExpectedException` rule. + +### [Pull request #1395](https://github.com/junit-team/junit4/pull/1395): Wrap assumption violations in ErrorCollector +Both `ErrorCollector.addError()` and `ErrorCollector.checkSucceeds()` now wrap `AssumptionViolatedException`. +In addition, `ErrorCollector.addError()` will throw a `NullPointerException` if you pass in a `null` value. + +### [Pull request #1402](https://github.com/junit-team/junit4/pull/1402): TemporaryFolder.newFolder(String) supports paths with slashes +There was a regression in JUnit 4.12 where `TemporaryFolder.newFolder(String)` no longer supported passing +in strings with separator characters. This has been fixed. he overload of newFolder() that +supports passing in multiple strings still does not allow path separators. + +### [Pull requests #1406 (part 1)](https://github.com/junit-team/junit4/pull/1406) and [#1568](https://github.com/junit-team/junit4/pull/1568): Improve error message when TemporaryFolder.newFolder(String) fails +When `newFolder(String path)` was not able to create the folder then it always failed with the error message "a folder with the name '``' already exists" although the reason for the failure could be something else. This message is now only used if the folder really exists. The message is "a file with the path '``' exists" if the whole path or a part of the path points to a file. In all other cases it fails now with the message "could not create a folder with the path '``'" + +### [Pull request #1406 (part 2)](https://github.com/junit-team/junit4/pull/1406): TemporaryFolder.newFolder(String...) supports path separator +You can now pass paths with path separators to `TemporaryFolder.newFolder(String...)`. E.g. + + tempFolder.newFolder("temp1", "temp2", "temp3/temp4") + +It creates a folder `temp1/temp2/temp3/temp4`. + + +### [Pull request #1406 (part 3)](https://github.com/junit-team/junit4/pull/1406): TemporaryFolder.newFolder(String...) fails for empty array + +When you call + + tempFolder.newFolder(new String[]) + +then it throws an `IllegalArgumentException` instead of returning an already existing folder. + + +### [Pull request #1335](https://github.com/junit-team/junit4/pull/1335): Fix ExternalResource: the test failure could be lost +When both the test failed and closing the resource failed, only the exception coming from the `after()` method was propagated, as per semantics of the try-finally (see also http://docs.oracle.com/javase/specs/jls/se8/html/jls-14.html#jls-14.20.2). + +The new behavior is compatible with @After method semantics, as implemented in [RunAfters](https://github.com/junit-team/junit4/blob/HEAD/src/main/java/org/junit/internal/runners/statements/RunAfters.java). + +### [Pull request #1435](https://github.com/junit-team/junit4/pull/1435): @BeforeParam/@AfterParam method annotations for Parameterized tests. +This allows having preparation and/or cleanup in tests for specific parameter values. + +### [Pull request #1460](https://github.com/junit-team/junit4/pull/1460): Handle assumption violations in the @Parameters method for Parameterized tests. +This allows skipping the whole test class when its assumptions are not met. + +### [Pull request #1445](https://github.com/junit-team/junit4/pull/1445) and [Pull request #1335](https://github.com/junit-team/junit4/pull/1501): Declarative ordering of rules. +The order in which rules are executed is specified by the annotation attribute: `@Rule(order = N)`, deprecating `RuleChain`. This may be used for avoiding some common pitfalls with `TestWatcher, `ErrorCollector` and `ExpectedException` for example. The Javadoc of `TestWatcher` was retrofitted accordingly. + +### [Pull request #1517](https://github.com/junit-team/junit4/pull/1517): Timeout rule destroys its ThreadGroups at the end +The `ThreadGroup` created for handling the timeout of tests is now destroyed, so the main thread group no longer keeps a reference to all timeout groups created during the tests. This caused the `threadGroup` to remain in memory, and all of its context along with it. + +### [Pull request #1633](https://github.com/junit-team/junit4/pull/1633): Deprecate ExpectedException.none() +The method Assert.assertThrows provides a nicer way for verifying exceptions. In addition the use of ExpectedException is error-prone when used with other rules like TestWatcher because the order of rules is important in that case. + +### [Pull request #1413](https://github.com/junit-team/junit4/pull/1413): Ignore bridge methods when scanning for annotated methods + +In a setup with a class hierarchy for test classes the order of rules (from methods), before methods, after methods and others depends on the class that contains these methods. Compilers can add bridge methods to child classes and therefore the order of the aforementioned methods can change in older JUnit releases. This is now fixed because bridge methods are ignored when scanning for annotated methods. + +### [Pull request #1612](https://github.com/junit-team/junit4/pull/1612): Make @ValidateWith only applicable to annotation types + +`@Target(ANNOTATION_TYPE)` has been added to `@ValidateWith` since it's only designed to be applied to another annotation. + +# Run Listener + +### [Pull request #1118:](https://github.com/junit-team/junit4/pull/1118) Add suite start/finish events to listener + +The `RunListener` class now has `fireTestSuiteStarted` and `fireTestSuiteFinished` methods that notify when test suites are about to be started/finished. + + +# Exception Testing + +### [Pull request #1359:](https://github.com/junit-team/junit4/pull/1359) Fixes how `MultipleFailureException` stack traces are printed + +Previously, calling `MultipleFailureException.printStackTrace()` only printed the stack trace for the `MultipleFailureException` itself. After this change, the stack trace for each exception caught in the `MultipleFailureException` is printed. + +### [Pull request #1376:](https://github.com/junit-team/junit4/pull/1376) Initializing MultipleFailureException with an empty list will now fail the test + +Previously, initializing `MultipleFailureException` with an empty list of contained Exceptions and throwing it in a test case wouldn't actually fail the test. Now an `IllegalArgumentException` will be raised in this situation and thus also fail the test. + +### [Pull request #1371:](https://github.com/junit-team/junit4/pull/1371) Update MultipleFailureException.assertEmpty() to wrap assumption failure + +`MultipleFailureException` will now wrap `MultipleFailureException` with `TestCouldNotBeSkippedException`. Previously, if you passed `MultipleFailureException` one `MultipleFailureException`--and no other exceptions-- +then the test would be skipped, otherwise it would fail. With the new behavior, it will always fail. + +### [Issue #1290:](https://github.com/junit-team/junit4/issues/1290) `@Test(expected = AssumptionViolatedException.class)` passes for AssumptionViolatedException + +Tests annotated with `@test(expected = AssumptionViolatedException.class)` +which throw AssumptionViolatedException had been marked as skipped. Now the are marked as successful tests. + + +# JUnit 3 Changes + +### [Pull request #1227:](https://github.com/junit-team/junit/pull/1227) Behave better if the `SecurityManager` denies access to `junit.properties` + +Previously, running tests with a `SecurityManager` would cause the test runner itself to throw an `AccessControlException` if the security policy didn't want it reading from `~/junit.properties`. This will now be treated the same as if the file does not exist. + +# Misc + +### [Pull request #1571:](https://github.com/junit-team/junit4/pull/1571) Set "junit" as "Automatic-Module-Name" + +For existing releases of JUnit the `Automatic-Module-Name` was derived from the name of the jar. In most cases it is already the name "junit". JUnit 4.13 explicitly sets the module name to "junit" so that it is independent from the jar's name. + + +### [Pull request #1028:](https://github.com/junit-team/junit4/pull/1028) Trim stack trace + +JUnit's command-line runner (`JUnitCore`) prints smaller stack traces. It skips all stack trace elements that come before the test method so that it starts at the test method. E.g. the output for the example from [Getting started](https://github.com/junit-team/junit4/wiki/Getting-started) page is now + + .E + Time: 0,006 + There was 1 failure: + 1) evaluatesExpression(CalculatorTest) + java.lang.AssertionError: expected:<6> but was:<-6> + at org.junit.Assert.fail(Assert.java:89) + at org.junit.Assert.failNotEquals(Assert.java:835) + at org.junit.Assert.assertEquals(Assert.java:647) + at org.junit.Assert.assertEquals(Assert.java:633) + at CalculatorTest.evaluatesExpression(CalculatorTest.java:9) + + FAILURES!!! + Tests run: 1, Failures: 1 + + +### [Pull request #1403:](https://github.com/junit-team/junit4/pull/1403) Restore CategoryFilter constructor + +The constructor `CategoryFilter(Class includedCategory, Class excludedCategory)` has been removed in JUnit 4.12. It is now available again. + + +### [Pull request #1530:](https://github.com/junit-team/junit4/pull/1530) Add Result#getAssumptionFailureCount + +Add method `getAssumptionFailureCount()` to `Result` which returns the number of assumption failures. + +### [Pull request #1292:](https://github.com/junit-team/junit4/pull/1292) Fix ResultMatchers#hasFailureContaining + +`ResultMatchers.hasFailureContaining()` should return `false` when the given `PrintableResult` has no failures. + +### [Pull request #1380:](https://github.com/junit-team/junit4/pull/1380) Fix Assume#assumeNotNull + +`Assume.assumeNotNull` should throw AssumptionViolatedException when called with a `null` array. + +### [Pull request #1557:](https://github.com/junit-team/junit4/pull/1380) MaxCore always closes stream of history file + +MaxCore didn't close the output stream of the history file when write failed. Now it does. + +### Signing + +The 4.13 release is signed with a new key (id 5EC61B51): +https://github.com/junit-team/junit4/blob/8c0df64ff17fead54c304a8b189da839084925c2/KEYS diff --git a/doc/ReleaseNotes4.4.html b/doc/ReleaseNotes4.4.html new file mode 100644 index 000000000000..383d7b504038 --- /dev/null +++ b/doc/ReleaseNotes4.4.html @@ -0,0 +1,271 @@ +

    Summary of Changes in version 4.5

    + +

    Categories

    + +

    Each test method and test class can be annotated as belonging to a category:

    + +
    public static class SomeUITests {
    +    @Category(UserAvailable.class)
    +    @Test
    +    public void askUserToPressAKey() { }
    +
    +    @Test
    +    public void simulatePressingKey() { }
    +}
    +
    +@Category(InternetConnected.class)
    +public static class InternetTests {
    +    @Test
    +    public void pingServer() { }
    +}
    +
    + +

    To run all of the tests in a particular category, you must currently explicitly create a custom request:

    + +
    new JUnitCore().run(Request.aClass(SomeUITests.class).inCategories(UserAvailable.class));
    +
    + +

    This feature will very likely be improved before the final release of JUnit 4.5

    + +

    Miscellaneous

    + +
      +
    • @Before and @After methods are run before and after each set of attempted parameters +on a Theory

    • +
    • Refactoring removed duplication that used to exist in classes MethodRoadie and ClassRoadie

    • +
    • Exposed API ParameterSignature.getType()

    • +
    + +

    Summary of Changes in version 4.4

    + +

    JUnit is designed to efficiently capture developers' intentions about +their code, and quickly check their code matches those intentions. +Over the last year, we've been talking about what things developers +would like to say about their code that have been difficult in the +past, and how we can make them easier.

    + +

    Download

    + +

    assertThat

    + +

    Two years ago, Joe Walnes built a new assertion mechanism on top of what was +then JMock 1. The method name was assertThat, and the syntax looked like this:

    + +
    assertThat(x, is(3));
    +assertThat(x, is(not(4)));
    +assertThat(responseString, either(containsString("color")).or(containsString("colour")));
    +assertThat(myList, hasItem("3"));
    +
    + +

    More generally:

    + +
    assertThat([value], [matcher statement]);
    +
    + +

    Advantages of this assertion syntax include:

    + +
      +
    • More readable and typeable: this syntax allows you to think in terms of subject, verb, object +(assert "x is 3") rather than assertEquals, which uses verb, object, subject (assert "equals 3 x")

    • +
    • Combinations: any matcher statement s can be negated (not(s)), combined (either(s).or(t)), +mapped to a collection (each(s)), or used in custom combinations (afterFiveSeconds(s))

    • +
    • Readable failure messages. Compare

      + +
      assertTrue(responseString.contains("color") || responseString.contains("colour"));
      +// ==> failure message: 
      +// java.lang.AssertionError:
      +
      +
      +assertThat(responseString, anyOf(containsString("color"), containsString("colour")));
      +// ==> failure message:
      +// java.lang.AssertionError: 
      +// Expected: (a string containing "color" or a string containing "colour")
      +//      got: "Please choose a font"
      +
    • +
    • Custom Matchers. By implementing the Matcher interface yourself, you can get all of the +above benefits for your own custom assertions.

    • +
    • For a more thorough description of these points, see Joe Walnes's +original post.

    • +
    + +

    We have decided to include this API directly in JUnit. +It's an extensible and readable syntax, and it enables +new features, like assumptions and theories.

    + +

    Some notes:

    + +
      +
    • The old assert methods are never, ever, going away. Developers may +continue using the old assertEquals, assertTrue, and so on.
    • +
    • The second parameter of an assertThat statement is a Matcher. +We include the Matchers we want as static imports, like this:

      + +
      import static org.hamcrest.CoreMatchers.is;
      +
      + +

      or:

      + +
      import static org.hamcrest.CoreMatchers.*;
      +
    • +
    • Manually importing Matcher methods can be frustrating. Eclipse 3.3 includes the ability to +define +"Favorite" classes to import static methods from, which makes it easier +(Search for "Favorites" in the Preferences dialog). +We expect that support for static imports will improve in all Java IDEs in the future.

    • +
    • To allow compatibility with a wide variety of possible matchers, +we have decided to include the classes from hamcrest-core, +from the Hamcrest project. This is the first time that +third-party classes have been included in JUnit.

    • +
    • JUnit currently ships with a few matchers, defined in +org.hamcrest.CoreMatchers and org.junit.matchers.JUnitMatchers.
      +To use many, many more, consider downloading the full hamcrest package.

    • +
    • JUnit contains special support for comparing string and array +values, giving specific information on how they differ. This is not +yet available using the assertThat syntax, but we hope to bring +the two assert methods into closer alignment in future releases.

    • +
    + +

    + +

    Assumptions

    + +

    Ideally, the developer writing a test has control of all of the forces that might cause a test to fail. +If this isn't immediately possible, making dependencies explicit can often improve a design.
    +For example, if a test fails when run in a different locale than the developer intended, +it can be fixed by explicitly passing a locale to the domain code.

    + +

    However, sometimes this is not desirable or possible.
    +It's good to be able to run a test against the code as it is currently written, +implicit assumptions and all, or to write a test that exposes a known bug. +For these situations, JUnit now includes the ability to express "assumptions":

    + +
    import static org.junit.Assume.*
    +
    +@Test public void filenameIncludesUsername() {
    +   assumeThat(File.separatorChar, is('/'));
    +   assertThat(new User("optimus").configFileName(), is("configfiles/optimus.cfg"));
    +}
    +
    +@Test public void correctBehaviorWhenFilenameIsNull() {
    +   assumeTrue(bugFixed("13356"));  // bugFixed is not included in JUnit
    +   assertThat(parse(null), is(new NullDocument()));
    +}
    +
    + +

    With this release, a failed assumption will lead to the test being marked as passing, +regardless of what the code below the assumption may assert. +In the future, this may change, and a failed assumption may lead to the test being ignored: +however, third-party runners do not currently allow this option.

    + +

    We have included assumeTrue for convenience, but thanks to the +inclusion of Hamcrest, we do not need to create assumeEquals, +assumeSame, and other analogues to the assert* methods. All of +those functionalities are subsumed in assumeThat, with the appropriate +matcher.

    + +

    A failing assumption in a @Before or @BeforeClass method will have the same effect +as a failing assumption in each @Test method of the class.

    + +

    + +

    Theories

    + +

    More flexible and expressive assertions, combined with the ability to +state assumptions clearly, lead to a new kind of statement of intent, +which we call a "Theory". A test captures the intended behavior in +one particular scenario. A theory captures some aspect of the +intended behavior in possibly +infinite numbers of potential scenarios. For example:

    + +
    @RunWith(Theories.class)
    +public class UserTest {
    +  @DataPoint public static String GOOD_USERNAME = "optimus";
    +  @DataPoint public static String USERNAME_WITH_SLASH = "optimus/prime";
    +
    +  @Theory public void filenameIncludesUsername(String username) {
    +    assumeThat(username, not(containsString("/")));
    +    assertThat(new User(username).configFileName(), containsString(username));
    +  }
    +}
    +
    + +

    This makes it clear that the user's filename should be included in the +config file name, only if it doesn't contain a slash. Another test +or theory might define what happens when a username does contain a slash.

    + +

    UserTest will attempt to run filenameIncludesUsername on +every compatible DataPoint defined in the class. If any of the +assumptions fail, the data point is silently ignored. If all of the +assumptions pass, but an assertion fails, the test fails.

    + +

    The support for Theories has been absorbed from the Popper +project, and more complete documentation can be found +there.

    + +

    Defining general statements in this way can jog the developer's memory +about other potential data points and tests, also allows automated +tools to search for new, unexpected data +points that expose bugs.

    + +

    Other changes

    + +

    This release contains other bug fixes and new features. Among them:

    + +
      +
    • Annotated descriptions

      + +

      Runner UIs, Filters, and Sorters operate on Descriptions of test +methods and test classes. These Descriptions now include the +annotations on the original Java source element, allowing for richer +display of test results, and easier development of annotation-based +filters.

    • +
    • Bug fix (1715326): assertEquals now compares all Numbers using their +native implementation of equals. This assertion, which passed in +4.3, will now fail:

      + +
      assertEquals(new Integer(1), new Long(1));
      +
      + +

      Non-integer Numbers (Floats, Doubles, BigDecimals, etc), +which were compared incorrectly in 4.3, are now fixed.

    • +
    • assertEquals(long, long) and assertEquals(double, double) have +been re-introduced to the Assert class, to take advantage of +Java's native widening conversions. Therefore, this still passes:

      + +
      assertEquals(1, 1L);
      +
    • +
    • The default runner for JUnit 4 test classes has been refactored. +The old version was named TestClassRunner, and the new is named +JUnit4ClassRunner. Likewise, OldTestClassRunner is now +JUnit3ClassRunner. The new design allows variations in running +individual test classes to be expressed with fewer custom classes. +For a good example, see the source to +org.junit.experimental.theories.Theories.

    • +
    • The rules for determining which runner is applied by default to a +test class have been simplified:

      + +
        +
      1. If the class has a @RunWith annotation, the annotated runner +class is used.

      2. +
      3. If the class can be run with the JUnit 3 test runner (it +subclasses TestCase, or contains a public static Test suite() +method), JUnit38ClassRunner is used.

      4. +
      5. Otherwise, JUnit4ClassRunner is used.

      6. +
      + +

      This default guess can always be overridden by an explicit +@RunWith(JUnit4ClassRunner.class) or +@RunWith(JUnit38ClassRunner.class) annotation.

      + +

      The old class names TestClassRunner and OldTestClassRunner +remain as deprecated.

    • +
    • Bug fix (1739095): Filters and Sorters work correctly on test +classes that contain a suite method like:

      + +
      public static junit.framework.Test suite() {
      +  return new JUnit4TestAdapter(MyTest.class);
      +}
      +
    • +
    • Bug fix (1745048): @After methods are now correctly called +after a test method times out.

    • +
    diff --git a/doc/ReleaseNotes4.4.md b/doc/ReleaseNotes4.4.md new file mode 100644 index 000000000000..2be5e49bd01f --- /dev/null +++ b/doc/ReleaseNotes4.4.md @@ -0,0 +1,319 @@ +## Summary of Changes in version 4.5 ## + +### Categories ### +Each test method and test class can be annotated as belonging to a _category_: + +```java +public static class SomeUITests { + @Category(UserAvailable.class) + @Test + public void askUserToPressAKey() { } + + @Test + public void simulatePressingKey() { } +} + +@Category(InternetConnected.class) +public static class InternetTests { + @Test + public void pingServer() { } +} +``` + +To run all of the tests in a particular category, you must currently explicitly create a custom request: + +```java +new JUnitCore().run(Request.aClass(SomeUITests.class).inCategories(UserAvailable.class)); +``` + +This feature will very likely be improved before the final release of JUnit 4.5 + +### Theories ### + +- `@Before` and `@After` methods are run before and after each set of attempted parameters + on a Theory, and each set of parameters is run on a new instance of the test class. + +- Exposed API's `ParameterSignature.getType()` and `ParameterSignature.getAnnotations()` + +- An array of data points can be introduced by a field or method marked with the new annotation `@DataPoints` + +- The Theories custom runner has been refactored to make it easier to extend + +### JUnit 4 Runner API ### + +- There has been a drastic rewrite of the API for custom Runners in 4.5. This + needs to be written up separately before release. + +- Tests with failed assumptions are now marked as Ignored, rather than silently passing. + This may change behavior in some client tests, and also will require some new support + on the part of IDE's. + +## Summary of Changes in version 4.4 ## + +JUnit is designed to efficiently capture developers' intentions about +their code, and quickly check their code matches those intentions. +Over the last year, we've been talking about what things developers +would like to say about their code that have been difficult in the +past, and how we can make them easier. + +[Download][] + +[Download]: http://sourceforge.net/project/showfiles.php?group_id=15278 + +### assertThat ### + +Two years ago, Joe Walnes built a [new assertion mechanism][walnes] on top of what was +then [JMock 1][]. The method name was `assertThat`, and the syntax looked like this: + +[walnes]: http://joewalnes.com/2005/05/13/flexible-junit-assertions-with-assertthat/ +[JMock 1]: http://www.jmock.org/download.html + +```java +assertThat(x, is(3)); +assertThat(x, is(not(4))); +assertThat(responseString, either(containsString("color")).or(containsString("colour"))); +assertThat(myList, hasItem("3")); +``` + +More generally: + +```java +assertThat([value], [matcher statement]); +``` + +Advantages of this assertion syntax include: + +- More readable and typeable: this syntax allows you to think in terms of subject, verb, object + (assert "x is 3") rather than `assertEquals`, which uses verb, object, subject (assert "equals 3 x") + +- Combinations: any matcher statement `s` can be negated (`not(s)`), combined (`either(s).or(t)`), + mapped to a collection (`each(s)`), or used in custom combinations (`afterFiveSeconds(s)`) + +- Readable failure messages. Compare + +```java +assertTrue(responseString.contains("color") || responseString.contains("colour")); +// ==> failure message: +// java.lang.AssertionError: + +assertThat(responseString, anyOf(containsString("color"), containsString("colour"))); +// ==> failure message: +// java.lang.AssertionError: +// Expected: (a string containing "color" or a string containing "colour") +// got: "Please choose a font" +``` + +- Custom Matchers. By implementing the `Matcher` interface yourself, you can get all of the + above benefits for your own custom assertions. + +- For a more thorough description of these points, see [Joe Walnes's + original post][walnes]. + +We have decided to include this API directly in JUnit. +It's an extensible and readable syntax, and it enables +new features, like [assumptions][] and [theories][]. + +[assumptions]: #assumptions +[theories]: #theories + +Some notes: + +- The old assert methods are never, ever, going away. Developers may + continue using the old `assertEquals`, `assertTrue`, and so on. +- The second parameter of an `assertThat` statement is a `Matcher`. + We include the Matchers we want as static imports, like this: + +```java +import static org.hamcrest.CoreMatchers.is; +``` + + or: + +```java +import static org.hamcrest.CoreMatchers.*; +``` + +- Manually importing `Matcher` methods can be frustrating. [Eclipse 3.3][] includes the ability to + define + "Favorite" classes to import static methods from, which makes it easier + (Search for "Favorites" in the Preferences dialog). + We expect that support for static imports will improve in all Java IDEs in the future. + +[Eclipse 3.3]: http://www.eclipse.org/downloads/ + +- To allow compatibility with a wide variety of possible matchers, + we have decided to include the classes from hamcrest-core, + from the [Hamcrest][] project. This is the first time that + third-party classes have been included in JUnit. + +[Hamcrest]: http://code.google.com/p/hamcrest/ + +- JUnit currently ships with a few matchers, defined in + `org.hamcrest.CoreMatchers` and `org.junit.matchers.JUnitMatchers`. + To use many, many more, consider downloading the [full hamcrest package][]. + +[full hamcrest package]: http://hamcrest.googlecode.com/files/hamcrest-all-1.1.jar + +- JUnit contains special support for comparing string and array + values, giving specific information on how they differ. This is not + yet available using the `assertThat` syntax, but we hope to bring + the two assert methods into closer alignment in future releases. + + +### Assumptions ### + +Ideally, the developer writing a test has control of all of the forces that might cause a test to fail. +If this isn't immediately possible, making dependencies explicit can often improve a design. +For example, if a test fails when run in a different locale than the developer intended, +it can be fixed by explicitly passing a locale to the domain code. + +However, sometimes this is not desirable or possible. +It's good to be able to run a test against the code as it is currently written, +implicit assumptions and all, or to write a test that exposes a known bug. +For these situations, JUnit now includes the ability to express "assumptions": + +```java +import static org.junit.Assume.* + +@Test public void filenameIncludesUsername() { + assumeThat(File.separatorChar, is('/')); + assertThat(new User("optimus").configFileName(), is("configfiles/optimus.cfg")); +} + +@Test public void correctBehaviorWhenFilenameIsNull() { + assumeTrue(bugFixed("13356")); // bugFixed is not included in JUnit + assertThat(parse(null), is(new NullDocument())); +} +``` + +With this release, a failed assumption will lead to the test being marked as passing, +regardless of what the code below the assumption may assert. +In the future, this may change, and a failed assumption may lead to the test being ignored: +however, third-party runners do not currently allow this option. + +We have included `assumeTrue` for convenience, but thanks to the +inclusion of Hamcrest, we do not need to create `assumeEquals`, +`assumeSame`, and other analogues to the `assert*` methods. All of +those functionalities are subsumed in `assumeThat`, with the appropriate +matcher. + +A failing assumption in a `@Before` or `@BeforeClass` method will have the same effect +as a failing assumption in each `@Test` method of the class. + + +### Theories ### + +More flexible and expressive assertions, combined with the ability to +state assumptions clearly, lead to a new kind of statement of intent, +which we call a "Theory". A test captures the intended behavior in +one particular scenario. A theory captures some aspect of the +intended behavior in possibly +infinite numbers of potential scenarios. For example: + +```java +@RunWith(Theories.class) +public class UserTest { + @DataPoint public static String GOOD_USERNAME = "optimus"; + @DataPoint public static String USERNAME_WITH_SLASH = "optimus/prime"; + + @Theory public void filenameIncludesUsername(String username) { + assumeThat(username, not(containsString("/"))); + assertThat(new User(username).configFileName(), containsString(username)); + } +} +``` + +This makes it clear that the user's filename should be included in the +config file name, only if it doesn't contain a slash. Another test +or theory might define what happens when a username does contain a slash. + +`UserTest` will attempt to run `filenameIncludesUsername` on +every compatible `DataPoint` defined in the class. If any of the +assumptions fail, the data point is silently ignored. If all of the +assumptions pass, but an assertion fails, the test fails. + +The support for Theories has been absorbed from the [Popper][] +project, and [more complete documentation][popper-docs] can be found +there. + +[Popper]: http://popper.tigris.org +[popper-docs]: http://popper.tigris.org/tutorial.html + +Defining general statements in this way can jog the developer's memory +about other potential data points and tests, also allows [automated +tools][junit-factory] to [search][my-blog] for new, unexpected data +points that expose bugs. + +[junit-factory]: http://www.junitfactory.org +[my-blog]: http://shareandenjoy.saff.net/2007/04/popper-and-junitfactory.html + +### Other changes ### + +This release contains other bug fixes and new features. Among them: + +- Annotated descriptions + + Runner UIs, Filters, and Sorters operate on Descriptions of test + methods and test classes. These Descriptions now include the + annotations on the original Java source element, allowing for richer + display of test results, and easier development of annotation-based + filters. + +- Bug fix (1715326): assertEquals now compares all Numbers using their + native implementation of `equals`. This assertion, which passed in + 4.3, will now fail: + +```java +assertEquals(new Integer(1), new Long(1)); +``` + + Non-integer Numbers (Floats, Doubles, BigDecimals, etc), + which were compared incorrectly in 4.3, are now fixed. + +- `assertEquals(long, long)` and `assertEquals(double, double)` have + been re-introduced to the `Assert` class, to take advantage of + Java's native widening conversions. Therefore, this still passes: + +```java +assertEquals(1, 1L); +``` + +- The default runner for JUnit 4 test classes has been refactored. + The old version was named `TestClassRunner`, and the new is named + `JUnit4ClassRunner`. Likewise, `OldTestClassRunner` is now + `JUnit3ClassRunner`. The new design allows variations in running + individual test classes to be expressed with fewer custom classes. + For a good example, see the source to + `org.junit.experimental.theories.Theories`. + +- The rules for determining which runner is applied by default to a + test class have been simplified: + + 1. If the class has a `@RunWith` annotation, the annotated runner + class is used. + + 2. If the class can be run with the JUnit 3 test runner (it + subclasses `TestCase`, or contains a `public static Test suite()` + method), JUnit38ClassRunner is used. + + 3. Otherwise, JUnit4ClassRunner is used. + + This default guess can always be overridden by an explicit + `@RunWith(JUnit4ClassRunner.class)` or + `@RunWith(JUnit38ClassRunner.class)` annotation. + + The old class names `TestClassRunner` and `OldTestClassRunner` + remain as deprecated. + +- Bug fix (1739095): Filters and Sorters work correctly on test + classes that contain a `suite` method like: + +```java +public static junit.framework.Test suite() { + return new JUnit4TestAdapter(MyTest.class); +} +``` + +- Bug fix (1745048): @After methods are now correctly called + after a test method times out. + diff --git a/doc/ReleaseNotes4.4.txt b/doc/ReleaseNotes4.4.txt new file mode 100644 index 000000000000..63a0a8110501 --- /dev/null +++ b/doc/ReleaseNotes4.4.txt @@ -0,0 +1 @@ +Please see ReleaseNotes4.4.md diff --git a/doc/ReleaseNotes4.5.html b/doc/ReleaseNotes4.5.html new file mode 100644 index 000000000000..d6549aa5badc --- /dev/null +++ b/doc/ReleaseNotes4.5.html @@ -0,0 +1,320 @@ +

    Summary of Changes in version 4.5

    + +

    Installation

    + +
      +
    • We are releasing junit-4.5.jar, which contains all the classes +necessary to run JUnit, and junit-dep-4.5.jar, which leaves out +hamcrest classes, for developers who already use hamcrest outside of +JUnit.
    • +
    + +

    Basic JUnit operation

    + +
      +
    • JUnitCore now more often exits with the correct exit code (0 for +success, 1 for failure)

    • +
    • Badly formed test classes (exceptions in constructors, classes +without tests, multiple constructors, Suite without @SuiteClasses) +produce more helpful error messages

    • +
    • Test classes whose only test methods are inherited from superclasses +now run.

    • +
    • Optimization to annotation processing can cut JUnit overhead by more than half +on large test classes, especially when using Theories. [Bug 1796847]

    • +
    • A failing assumption in a constructor ignores the class

    • +
    • Correct results when comparing the string "null" with potentially +null values. [Bug 1857283]

    • +
    • Annotating a class with @RunWith(JUnit4.class) will always invoke the +default JUnit 4 runner in the current version of JUnit. This default changed +from JUnit4ClassRunner in 4.4 to BlockJUnit4ClassRunner in 4.5 (see below), +and may change again.

    • +
    + +

    Extension

    + +
      +
    • BlockJUnit4Runner is a new implementation of the standard JUnit 4 +test class functionality. In contrast to JUnit4ClassRunner (the old +implementation):

      + +
        +
      • BlockJUnit4Runner has a much simpler implementation based on +Statements, allowing new operations to be inserted into the +appropriate point in the execution flow.

      • +
      • BlockJUnit4Runner is published, and extension and reuse are +encouraged, whereas JUnit4ClassRunner was in an internal package, +and is now deprecated.

      • +
    • +
    • ParentRunner is a base class for runners that iterate over +a list of "children", each an object representing a test or suite to run. +ParentRunner provides filtering, sorting, @BeforeClass, @AfterClass, +and method validation to subclasses.

    • +
    • TestClass wraps a class to be run, providing efficient, repeated access +to all methods with a given annotation.

    • +
    • The new RunnerBuilder API allows extending the behavior of +Suite-like custom runners.

    • +
    • AssumptionViolatedException.toString() is more informative

    • +
    + +

    Extra Runners

    + +
      +
    • Parameterized.eachOne() has been removed

    • +
    • New runner Enclosed runs all static inner classes of an outer class.

    • +
    + +

    Theories

    + +
      +
    • @Before and @After methods are run before and after each set of attempted parameters +on a Theory, and each set of parameters is run on a new instance of the test class.

    • +
    • Exposed API's ParameterSignature.getType() and ParameterSignature.getAnnotations()

    • +
    • An array of data points can be introduced by a field or method +marked with the new annotation @DataPoints

    • +
    • The Theories custom runner has been refactored to make it faster and +easier to extend

    • +
    + +

    Development

    + +
      +
    • Source has been split into directories src/main/java and +src/test/java, making it easier to exclude tests from builds, and +making JUnit more maven-friendly

    • +
    • Test classes in org.junit.tests have been organized into +subpackages, hopefully making finding tests easier.

    • +
    • ResultMatchers has more informative descriptions.

    • +
    • TestSystem allows testing return codes and other system-level interactions.

    • +
    + +

    Summary of Changes in version 4.4

    + +

    JUnit is designed to efficiently capture developers' intentions about +their code, and quickly check their code matches those intentions. +Over the last year, we've been talking about what things developers +would like to say about their code that have been difficult in the +past, and how we can make them easier.

    + +

    assertThat

    + +

    Two years ago, Joe Walnes built a new assertion mechanism on top of what was +then JMock 1. The method name was assertThat, and the syntax looked like this:

    + +
    assertThat(x, is(3));
    +assertThat(x, is(not(4)));
    +assertThat(responseString, either(containsString("color")).or(containsString("colour")));
    +assertThat(myList, hasItem("3"));
    +
    + +

    More generally:

    + +
    assertThat([value], [matcher statement]);
    +
    + +

    Advantages of this assertion syntax include:

    + +
      +
    • More readable and typeable: this syntax allows you to think in terms of subject, verb, object +(assert "x is 3") rathern than assertEquals, which uses verb, object, subject (assert "equals 3 x")

    • +
    • Combinations: any matcher statement s can be negated (not(s)), combined (either(s).or(t)), +mapped to a collection (each(s)), or used in custom combinations (afterFiveSeconds(s))

    • +
    • Readable failure messages. Compare

      + +
      assertTrue(responseString.contains("color") || responseString.contains("colour"));
      +// ==> failure message: 
      +// java.lang.AssertionError:
      +
      +
      +assertThat(responseString, anyOf(containsString("color"), containsString("colour")));
      +// ==> failure message:
      +// java.lang.AssertionError: 
      +// Expected: (a string containing "color" or a string containing "colour")
      +//      got: "Please choose a font"
      +
    • +
    • Custom Matchers. By implementing the Matcher interface yourself, you can get all of the +above benefits for your own custom assertions.

    • +
    • For a more thorough description of these points, see Joe Walnes's +original post.:

    • +
    + +

    We have decided to include this API directly in JUnit. +It's an extensible and readable syntax, and because it enables +new features, like assumptions and theories.

    + +

    Some notes:

    + +
      +
    • The old assert methods are never, ever, going away.
      +Developers may continue using the old assertEquals, assertTrue, and +so on.
    • +
    • The second parameter of an assertThat statement is a Matcher. +We include the Matchers we want as static imports, like this:

      + +
      import static org.hamcrest.CoreMatchers.is;
      +
      + +

      or:

      + +
      import static org.hamcrest.CoreMatchers.*;
      +
    • +
    • Manually importing Matcher methods can be frustrating. [Eclipse +3.3][] includes the ability to +define +"Favorite" classes to import static methods from, which makes it easier +(Search for "Favorites" in the Preferences dialog). +We expect that support for static imports will improve in all Java IDEs in the future.

    • +
    • To allow compatibility with a wide variety of possible matchers, +we have decided to include the classes from hamcrest-core, +from the Hamcrest project. This is the first time that +third-party classes have been included in JUnit.

    • +
    • To allow developers to maintain full control of the classpath contents, the JUnit distribution also provides an unbundled junit-dep jar, +ie without hamcrest-core classes included. This is intended for situations when using other libraries that also depend on hamcrest-core, to +avoid classloading conflicts or issues. Developers using junit-dep should ensure a compatible version of hamcrest-core jar (ie 1.1+) is present in the classpath.

    • +
    • JUnit currently ships with a few matchers, defined in +org.hamcrest.CoreMatchers and org.junit.matchers.JUnitMatchers.
      +To use many, many more, consider downloading the full hamcrest package.

    • +
    • JUnit contains special support for comparing string and array +values, giving specific information on how they differ. This is not +yet available using the assertThat syntax, but we hope to bring +the two assert methods into closer alignment in future releases.

    • +
    + +

    assumeThat

    + +

    +Ideally, the developer writing a test has control of all of the forces that might cause a test to fail. +If this isn't immediately possible, making dependencies explicit can often improve a design.
    +For example, if a test fails when run in a different locale than the developer intended, +it can be fixed by explicitly passing a locale to the domain code.

    + +

    However, sometimes this is not desirable or possible.
    +It's good to be able to run a test against the code as it is currently written, +implicit assumptions and all, or to write a test that exposes a known bug. +For these situations, JUnit now includes the ability to express "assumptions":

    + +
    import static org.junit.Assume.*
    +
    +@Test public void filenameIncludesUsername() {
    +   assumeThat(File.separatorChar, is('/'));
    +   assertThat(new User("optimus").configFileName(), is("configfiles/optimus.cfg"));
    +}
    +
    +@Test public void correctBehaviorWhenFilenameIsNull() {
    +   assumeTrue(bugFixed("13356"));  // bugFixed is not included in JUnit
    +   assertThat(parse(null), is(new NullDocument()));
    +}
    +
    + +

    With this beta release, a failed assumption will lead to the test being marked as passing, +regardless of what the code below the assumption may assert. +In the future, this may change, and a failed assumption may lead to the test being ignored: +however, third-party runners do not currently allow this option.

    + +

    We have included assumeTrue for convenience, but thanks to the +inclusion of Hamcrest, we do not need to create assumeEquals, +assumeSame, and other analogues to the assert* methods. All of +those functionalities are subsumed in assumeThat, with the appropriate +matcher.

    + +

    A failing assumption in a @Before or @BeforeClass method will have the same effect +as a failing assumption in each @Test method of the class.

    + +

    Theories

    + +

    +More flexible and expressive assertions, combined with the ability to +state assumptions clearly, lead to a new kind of statement of intent, +which we call a "Theory". A test captures the intended behavior in +one particular scenario. A theory allows a developer to be +as precise as desired about the behavior of the code in possibly +infinite numbers of possible scenarios. For example:

    + +
    @RunWith(Theories.class)
    +public class UserTest {
    +  @DataPoint public static String GOOD_USERNAME = "optimus";
    +  @DataPoint public static String USERNAME_WITH_SLASH = "optimus/prime";
    +
    +  @Theory public void filenameIncludesUsername(String username) {
    +    assumeThat(username, not(containsString("/")));
    +    assertThat(new User(username).configFileName(), containsString(username));
    +  }
    +}
    +
    + +

    This makes it clear that the user's filename should be included in the +config file name, only if it doesn't contain a slash. Another test +or theory might define what happens when a username does contain a slash.

    + +

    UserTest will attempt to run filenameIncludesUsername on +every compatible DataPoint defined in the class. If any of the +assumptions fail, the data point is silently ignored. If all of the +assumptions pass, but an assertion fails, the test fails.

    + +

    The support for Theories has been absorbed from the Popper +project, and more complete documentation can be found +there.

    + +

    Defining general statements in this way can jog the developer's memory +about other potential data points and tests, also allows automated +tools to search for new, unexpected data +points that expose bugs.

    + +

    Other changes

    + +

    This release contains other bug fixes and new features. Among them:

    + +
      +
    • Annotated descriptions

      + +

      Runner UIs, Filters, and Sorters operate on Descriptions of test +methods and test classes. These Descriptions now include the +annotations on the original Java source element, allowing for richer +display of test results, and easier development of annotation-based +filters.

    • +
    • Bug fix (1715326): assertEquals now compares all Numbers using their +native implementation of equals. This assertion, which passed in +4.3, will now fail:

      + +

      assertEquals(new Integer(1), new Long(1));

      + +

      Non-integer Numbers (Floats, Doubles, BigDecimals, etc), +which were compared incorrectly in 4.3, are now fixed.

    • +
    • assertEquals(long, long) and assertEquals(double, double) have +been re-introduced to the Assert class, to take advantage of +Java's native widening conversions. Therefore, this still passes:

      + +

      assertEquals(1, 1L);

    • +
    • The default runner for JUnit 4 test classes has been refactored. +The old version was named TestClassRunner, and the new is named +JUnit4ClassRunner. Likewise, OldTestClassRunner is now +JUnit3ClassRunner. The new design allows variations in running +individual test classes to be expressed with fewer custom classes. +For a good example, see the source to +org.junit.experimental.theories.Theories.

    • +
    • The rules for determining which runner is applied by default to a +test class have been simplified:

      + +
        +
      1. If the class has a @RunWith annotation, the annotated runner +class is used.

      2. +
      3. If the class can be run with the JUnit 3 test runner (it +subclasses TestCase, or contains a public static Test suite() +method), JUnit38ClassRunner is used.

      4. +
      5. Otherwise, JUnit4ClassRunner is used.

      6. +
      + +

      This default guess can always be overridden by an explicit +@RunWith(JUnit4ClassRunner.class) or +@RunWith(JUnit38ClassRunner.class) annotation.

      + +

      The old class names TestClassRunner and OldTestClassRunner +remain as deprecated.

    • +
    • Bug fix (1739095): Filters and Sorters work correctly on test +classes that contain a suite method like:

      + +

      public static junit.framework.Test suite() { + return new JUnit4TestAdapter(MyTest.class); +}

    • +
    • Bug fix (1745048): @After methods are now correctly called +after a test method times out.

    • +
    diff --git a/doc/ReleaseNotes4.5.md b/doc/ReleaseNotes4.5.md new file mode 100644 index 000000000000..66aac7004a25 --- /dev/null +++ b/doc/ReleaseNotes4.5.md @@ -0,0 +1,96 @@ +## Summary of Changes in version 4.5 ## + +### Installation ### + +- We are releasing `junit-4.5.jar`, which contains all the classes + necessary to run JUnit, and `junit-dep-4.5.jar`, which leaves out + hamcrest classes, for developers who already use hamcrest outside of + JUnit. + +### Basic JUnit operation ### + +- JUnitCore now more often exits with the correct exit code (0 for + success, 1 for failure) + +- Badly formed test classes (exceptions in constructors, classes + without tests, multiple constructors, Suite without @SuiteClasses) + produce more helpful error messages + +- Test classes whose only test methods are inherited from superclasses + now run. + +- Optimization to annotation processing can cut JUnit overhead by more than half + on large test classes, especially when using Theories. [Bug 1796847] + +- A failing assumption in a constructor ignores the class + +- Correct results when comparing the string "null" with potentially + null values. [Bug 1857283] + +- Annotating a class with `@RunWith(JUnit4.class)` will always invoke the + default JUnit 4 runner in the current version of JUnit. This default changed + from `JUnit4ClassRunner` in 4.4 to `BlockJUnit4ClassRunner` in 4.5 (see below), + and may change again. + +### Extension ### + +- `BlockJUnit4Runner` is a new implementation of the standard JUnit 4 + test class functionality. In contrast to `JUnit4ClassRunner` (the old + implementation): + + - `BlockJUnit4Runner` has a much simpler implementation based on + Statements, allowing new operations to be inserted into the + appropriate point in the execution flow. + + - `BlockJUnit4Runner` is published, and extension and reuse are + encouraged, whereas `JUnit4ClassRunner` was in an internal package, + and is now deprecated. + +- `ParentRunner` is a base class for runners that iterate over + a list of "children", each an object representing a test or suite to run. + `ParentRunner` provides filtering, sorting, `@BeforeClass`, `@AfterClass`, + and method validation to subclasses. + +- `TestClass` wraps a class to be run, providing efficient, repeated access + to all methods with a given annotation. + +- The new `RunnerBuilder` API allows extending the behavior of + Suite-like custom runners. + +- `AssumptionViolatedException.toString()` is more informative + +### Extra Runners ### + +- `Parameterized.eachOne()` has been removed + +- New runner `Enclosed` runs all static inner classes of an outer class. + +### Theories ### + +- `@Before` and `@After` methods are run before and after each set of attempted parameters + on a Theory, and each set of parameters is run on a new instance of the test class. + +- Exposed API's `ParameterSignature.getType()` and `ParameterSignature.getAnnotations()` + +- An array of data points can be introduced by a field or method + marked with the new annotation `@DataPoints` + +- The Theories custom runner has been refactored to make it faster and + easier to extend + +### Development ### + +- Source has been split into directories `src/main/java` and + `src/test/java`, making it easier to exclude tests from builds, and + making JUnit more maven-friendly + +- Test classes in `org.junit.tests` have been organized into + subpackages, hopefully making finding tests easier. + +- `ResultMatchers` has more informative descriptions. + +- `TestSystem` allows testing return codes and other system-level interactions. + +### Incompatible changes ### + +- Removed Request.classes(String, Class...) factory method diff --git a/doc/ReleaseNotes4.5.txt b/doc/ReleaseNotes4.5.txt new file mode 100644 index 000000000000..704e8023abe5 --- /dev/null +++ b/doc/ReleaseNotes4.5.txt @@ -0,0 +1 @@ +Please see ReleaseNotes4.5.md diff --git a/doc/ReleaseNotes4.6.html b/doc/ReleaseNotes4.6.html new file mode 100644 index 000000000000..36c432a86070 --- /dev/null +++ b/doc/ReleaseNotes4.6.html @@ -0,0 +1,106 @@ +

    Summary of Changes in version 4.6

    + +

    Max

    + +

    JUnit now includes a new experimental Core, MaxCore. MaxCore +remembers the results of previous test runs in order to run new +tests out of order. MaxCore prefers new tests to old tests, fast +tests to slow tests, and recently failing tests to tests that last +failed long ago. There's currently not a standard UI for running +MaxCore included in JUnit, but there is a UI included in the JUnit +Max Eclipse plug-in at:

    + +

    http://www.junitmax.com/junitmax/subscribe.html

    + +

    Example:

    + +
    public static class TwoUnEqualTests {
    +    @Test
    +    public void slow() throws InterruptedException {
    +        Thread.sleep(100);
    +        fail();
    +    }
    +
    +    @Test
    +    public void fast() {
    +        fail();
    +    }
    +}
    +
    +@Test
    +public void rememberOldRuns() {
    +    File maxFile = new File("history.max");
    +    MaxCore firstMax = MaxCore.storedLocally(maxFile);
    +    firstMax.run(TwoUnEqualTests.class);
    +
    +    MaxCore useHistory= MaxCore.storedLocally(maxFile);
    +    List<Failure> failures= useHistory.run(TwoUnEqualTests.class)
    +            .getFailures();
    +    assertEquals("fast", failures.get(0).getDescription().getMethodName());
    +    assertEquals("slow", failures.get(1).getDescription().getMethodName());
    +}
    +
    + +

    Test scheduling strategies

    + +

    JUnitCore now includes an experimental method that allows you to +specify a model of the Computer that runs your tests. Currently, +the only built-in Computers are the default, serial runner, and two +runners provided in the ParallelRunner class: +ParallelRunner.classes(), which runs classes in parallel, and +ParallelRunner.methods(), which runs classes and methods in parallel.

    + +

    This feature is currently less stable than MaxCore, and may be +merged with MaxCore in some way in the future.

    + +

    Example:

    + +
    public static class Example {
    +    @Test public void one() throws InterruptedException {
    +        Thread.sleep(1000);
    +    }
    +    @Test public void two() throws InterruptedException {
    +        Thread.sleep(1000);
    +    }
    +}
    +
    +@Test public void testsRunInParallel() {
    +    long start= System.currentTimeMillis();
    +    Result result= JUnitCore.runClasses(ParallelComputer.methods(),
    +            Example.class);
    +    assertTrue(result.wasSuccessful());
    +    long end= System.currentTimeMillis();
    +    assertThat(end - start, betweenInclusive(1000, 1500));
    +}
    +
    + +

    Comparing double arrays

    + +

    Arrays of doubles can be compared, using a delta allowance for equality:

    + +
    @Test
    +public void doubleArraysAreEqual() {
    +    assertArrayEquals(new double[] {1.0, 2.0}, new double[] {1.0, 2.0}, 0.01);
    +}
    +
    + +

    Filter.matchDescription API

    + +

    Since 4.0, it has been possible to run a single method using the Request.method +API. In 4.6, the filter that implements this is exposed as Filter.matchDescription.

    + +

    Documentation

    + +
      +
    • A couple classes and packages that once had empty javadoc have been +doc'ed.

    • +
    • Added how to run JUnit from the command line to the cookbook.

    • +
    • junit-4.x.zip now contains build.xml

    • +
    + +

    Bug fixes

    + +
      +
    • Fixed overly permissive @DataPoint processing (2191102)
    • +
    • Fixed bug in test counting after an ignored method (2106324)
    • +
    diff --git a/doc/ReleaseNotes4.6.md b/doc/ReleaseNotes4.6.md new file mode 100644 index 000000000000..f1f6a8e6ac6b --- /dev/null +++ b/doc/ReleaseNotes4.6.md @@ -0,0 +1,106 @@ +## Summary of Changes in version 4.6 ## + +### Max ### + +JUnit now includes a new experimental Core, `MaxCore`. `MaxCore` +remembers the results of previous test runs in order to run new +tests out of order. `MaxCore` prefers new tests to old tests, fast +tests to slow tests, and recently failing tests to tests that last +failed long ago. There's currently not a standard UI for running +`MaxCore` included in JUnit, but there is a UI included in the JUnit +Max Eclipse plug-in at: + + http://www.junitmax.com/junitmax/subscribe.html + +Example: + +```java +public static class TwoUnEqualTests { + @Test + public void slow() throws InterruptedException { + Thread.sleep(100); + fail(); + } + + @Test + public void fast() { + fail(); + } +} + +@Test +public void rememberOldRuns() { + File maxFile = new File("history.max"); + MaxCore firstMax = MaxCore.storedLocally(maxFile); + firstMax.run(TwoUnEqualTests.class); + + MaxCore useHistory= MaxCore.storedLocally(maxFile); + List failures= useHistory.run(TwoUnEqualTests.class) + .getFailures(); + assertEquals("fast", failures.get(0).getDescription().getMethodName()); + assertEquals("slow", failures.get(1).getDescription().getMethodName()); +} +``` + +### Test scheduling strategies ### + +`JUnitCore` now includes an experimental method that allows you to +specify a model of the `Computer` that runs your tests. Currently, +the only built-in Computers are the default, serial runner, and two +runners provided in the `ParallelRunner` class: +`ParallelRunner.classes()`, which runs classes in parallel, and +`ParallelRunner.methods()`, which runs classes and methods in parallel. + +This feature is currently less stable than MaxCore, and may be +merged with MaxCore in some way in the future. + +Example: + +```java +public static class Example { + @Test public void one() throws InterruptedException { + Thread.sleep(1000); + } + @Test public void two() throws InterruptedException { + Thread.sleep(1000); + } +} + +@Test public void testsRunInParallel() { + long start= System.currentTimeMillis(); + Result result= JUnitCore.runClasses(ParallelComputer.methods(), + Example.class); + assertTrue(result.wasSuccessful()); + long end= System.currentTimeMillis(); + assertThat(end - start, betweenInclusive(1000, 1500)); +} +``` + +### Comparing double arrays ### + +Arrays of doubles can be compared, using a delta allowance for equality: + +```java +@Test +public void doubleArraysAreEqual() { + assertArrayEquals(new double[] {1.0, 2.0}, new double[] {1.0, 2.0}, 0.01); +} +``` + +### `Filter.matchDescription` API ### + +Since 4.0, it has been possible to run a single method using the `Request.method` +API. In 4.6, the filter that implements this is exposed as `Filter.matchDescription`. + +### Documentation ### + +- A couple classes and packages that once had empty javadoc have been + doc'ed. + +- Added how to run JUnit from the command line to the cookbook. + +- junit-4.x.zip now contains build.xml + +### Bug fixes ### +- Fixed overly permissive @DataPoint processing (2191102) +- Fixed bug in test counting after an ignored method (2106324) diff --git a/doc/ReleaseNotes4.6.txt b/doc/ReleaseNotes4.6.txt new file mode 100644 index 000000000000..ab4977e116fe --- /dev/null +++ b/doc/ReleaseNotes4.6.txt @@ -0,0 +1 @@ +Please see ReleaseNotes4.6.md diff --git a/doc/ReleaseNotes4.7.html b/doc/ReleaseNotes4.7.html new file mode 100644 index 000000000000..69b66c6a3768 --- /dev/null +++ b/doc/ReleaseNotes4.7.html @@ -0,0 +1,229 @@ +

    Summary of Changes in version 4.7

    + +

    Rules

    + +
      +
    • Rules allow very flexible addition or redefinition of the behavior +of each test method in a test class. Testers can reuse or extend one of the +provided Rules below, or write their own.

      + +

      For more on this feature, see http://www.threeriversinstitute.org/blog/?p=155

    • +
    • The TemporaryFolder Rule allows creation of files and folders +that are guaranteed to be deleted when the test method finishes +(whether it passes or fails):

      + +

      public static class HasTempFolder { + @Rule + public TemporaryFolder folder= new TemporaryFolder();

      + +
      @Test
      +public void testUsingTempFolder() throws IOException {
      +    File createdFile= folder.newFile("myfile.txt");
      +    File createdFolder= folder.newFolder("subfolder");
      +    // ...
      +}
      +
      + +

      }

    • +
    • ExternalResource is a base class for Rules (like TemporaryFolder) +that set up an external resource before a test (a file, socket, server, +database connection, etc.), and guarantee to tear it down afterward:

      + +

      public static class UsesExternalResource { + Server myServer = new Server();

      + +
      @Rule public ExternalResource resource = new ExternalResource() {
      +    @Override
      +    protected void before() throws Throwable {
      +        myServer.connect();
      +    };
      +
      +
      +
      @Override
      +protected void after() {
      +    myServer.disconnect();
      +};
      +
      + +}; + + +@Test public void testFoo() { + new Client().run(myServer); +} +
      + +

      }

    • +
    • The ErrorCollector Rule allows execution of a test to continue +after the first problem is found (for example, to collect all the +incorrect rows in a table, and report them all at once):

      + +

      public static class UsesErrorCollectorTwice { + @Rule + public ErrorCollector collector= new ErrorCollector();

      + +
      @Test public void example() {
      +    collector.addError(new Throwable("first thing went wrong"));
      +    collector.addError(new Throwable("second thing went wrong"));
      +}
      +
      + +

      }

    • +
    • Verifier is a base class for Rules like ErrorCollector, which +can turn otherwise passing test methods into failing tests if a verification +check is failed

      + +

      public static class ErrorLogVerifier() { + private ErrorLog errorLog = new ErrorLog();

      + +

      @Rule + public MethodRule verifier = new Verifier() { + @Override public void verify() { + assertTrue(errorLog.isEmpty()); + } + }

      + +

      @Test public void testThatMightWriteErrorLog() { + // ... + } +}

    • +
    • TestWatchman is a base class for Rules that take note +of the testing action, without modifying it. +For example, this class will keep a log of each passing and failing +test:

      + +

      public static class WatchmanTest { + private static String watchedLog;

      + +
      @Rule
      +public MethodRule watchman= new TestWatchman() {
      +    @Override
      +    public void failed(Throwable e, FrameworkMethod method) {
      +        watchedLog+= method.getName() + " "
      +                + e.getClass().getSimpleName() + "\n";
      +    }
      +
      +
      +
      @Override
      +public void succeeded(FrameworkMethod method) {
      +    watchedLog+= method.getName() + " " + "success!\n";
      +}
      +
      + +}; + + +@Test +public void fails() { + fail(); +} + + +@Test +public void succeeds() { +} +
      + +

      }

    • +
    • The TestName Rule makes the current test name available inside test methods:

      + +

      public class NameRuleTest { + @Rule public TestName name = new TestName();

      + +
      @Test public void testA() {
      +    assertEquals("testA", name.getMethodName());
      +}
      +
      +
      +@Test public void testB() {
      +    assertEquals("testB", name.getMethodName());
      +}
      +
      + +

      }

    • +
    • The Timeout Rule applies the same timeout to all test methods in a class:

      + +

      public static class HasGlobalTimeout { + public static String log;

      + +
      @Rule public MethodRule globalTimeout = new Timeout(20);
      +
      +
      +@Test public void testInfiniteLoop1() {
      +    log+= "ran1";
      +    for(;;) {}
      +}
      +
      +
      +@Test public void testInfiniteLoop2() {
      +    log+= "ran2";
      +    for(;;) {}
      +}
      +
      + +

      }

    • +
    • The ExpectedException Rule allows in-test specification +of expected exception types and messages:

      + +

      public static class HasExpectedException { + @Rule + public ExpectedException thrown= ExpectedException.none();

      + +
      @Test
      +public void throwsNothing() {
      +
      +
      +}
      +
      +
      +@Test
      +public void throwsNullPointerException() {
      +    thrown.expect(NullPointerException.class);
      +    throw new NullPointerException();
      +}
      +
      +
      +@Test
      +public void throwsNullPointerExceptionWithMessage() {
      +    thrown.expect(NullPointerException.class);
      +    thrown.expectMessage("happened?");
      +    thrown.expectMessage(startsWith("What"));
      +    throw new NullPointerException("What happened?");
      +}
      +
      + +

      }

    • +
    + +

    Timeouts

    + +
      +
    • Tests that time out now show the stack trace of the test thread.
    • +
    + +

    Matchers

    + +
      +
    • Due to typing incompatibilities, JUnit is still including the 1.1 release +of hamcrest. This is not a change from 4.6, but is a change from +pre-beta releases of 4.7. Due to this incompatibility, tests using +Hamcrest 1.2 must still use the MatcherAssert.assertThat method from +Hamcrest, not Assert.assertThat from JUnit.
    • +
    + +

    Docs

    + +
      +
    • Javadocs now link to online JDK javadocs (bug 2090230)
    • +
    • Parameterized runner javadocs improved (bug 2186792)
    • +
    • Fixed Javadoc code sample for AfterClass (2126279)
    • +
    • Fixed Javadoc for assertArraysEqual(float[], float[])
    • +
    + +

    Bug fixes

    + +
      +
    • Fixed: BaseTestRunner.getTest() requires class to extend TestCase (1812200)
    • +
    • Fixed: Suite does not allow for inheritance in annotations (2783118)
    • +
    • Fixed: ParallelComputer skipped tests that took longer than 2 seconds
    • +
    diff --git a/doc/ReleaseNotes4.7.md b/doc/ReleaseNotes4.7.md new file mode 100644 index 000000000000..1f9607074106 --- /dev/null +++ b/doc/ReleaseNotes4.7.md @@ -0,0 +1,210 @@ +## Summary of Changes in version 4.7 ## + +### Rules ### + +- Rules allow very flexible addition or redefinition of the behavior + of each test method in a test class. Testers can reuse or extend one of the + provided Rules below, or write their own. + + For more on this feature, see http://www.threeriversinstitute.org/blog/?p=155 + +- The TemporaryFolder Rule allows creation of files and folders + that are guaranteed to be deleted when the test method finishes + (whether it passes or fails): + +```java +public static class HasTempFolder { + @Rule + public TemporaryFolder folder= new TemporaryFolder(); + + @Test + public void testUsingTempFolder() throws IOException { + File createdFile= folder.newFile("myfile.txt"); + File createdFolder= folder.newFolder("subfolder"); + // ... + } +} +``` + +- ExternalResource is a base class for Rules (like TemporaryFolder) + that set up an external resource before a test (a file, socket, server, + database connection, etc.), and guarantee to tear it down afterward: + +```java +public static class UsesExternalResource { + Server myServer = new Server(); + + @Rule public ExternalResource resource = new ExternalResource() { + @Override + protected void before() throws Throwable { + myServer.connect(); + } + + @Override + protected void after() { + myServer.disconnect(); + } + }; + + @Test public void testFoo() { + new Client().run(myServer); + } +} +``` + +- The ErrorCollector Rule allows execution of a test to continue + after the first problem is found (for example, to collect _all_ the + incorrect rows in a table, and report them all at once): + +```java +public static class UsesErrorCollectorTwice { + @Rule + public ErrorCollector collector= new ErrorCollector(); + + @Test public void example() { + collector.addError(new Throwable("first thing went wrong")); + collector.addError(new Throwable("second thing went wrong")); + } +} +``` + +- Verifier is a base class for Rules like ErrorCollector, which + can turn otherwise passing test methods into failing tests if a verification + check is failed + +```java +public static class ErrorLogVerifier() { + private ErrorLog errorLog = new ErrorLog(); + + @Rule + public MethodRule verifier = new Verifier() { + @Override public void verify() { + assertTrue(errorLog.isEmpty()); + } + } + + @Test public void testThatMightWriteErrorLog() { + // ... + } +} +``` + +- TestWatchman is a base class for Rules that take note + of the testing action, without modifying it. + For example, this class will keep a log of each passing and failing + test: + +```java +public static class WatchmanTest { + private static String watchedLog; + + @Rule + public MethodRule watchman= new TestWatchman() { + @Override + public void failed(Throwable e, FrameworkMethod method) { + watchedLog+= method.getName() + " " + + e.getClass().getSimpleName() + "\n"; + } + + @Override + public void succeeded(FrameworkMethod method) { + watchedLog+= method.getName() + " " + "success!\n"; + } + }; + + @Test + public void fails() { + fail(); + } + + @Test + public void succeeds() { + } +} +``` + +- The TestName Rule makes the current test name available inside test methods: + +```java +public class NameRuleTest { + @Rule public TestName name = new TestName(); + + @Test public void testA() { + assertEquals("testA", name.getMethodName()); + } + + @Test public void testB() { + assertEquals("testB", name.getMethodName()); + } +} +``` + +- The Timeout Rule applies the same timeout to all test methods in a class: + +```java +public static class HasGlobalTimeout { + public static String log; + + @Rule public MethodRule globalTimeout = new Timeout(20); + + @Test public void testInfiniteLoop1() { + log+= "ran1"; + for(;;) {} + } + + @Test public void testInfiniteLoop2() { + log+= "ran2"; + for(;;) {} + } +} +``` + +- The ExpectedException Rule allows in-test specification + of expected exception types and messages: + +```java +public static class HasExpectedException { + @Rule + public ExpectedException thrown= ExpectedException.none(); + + @Test + public void throwsNothing() { + + } + + @Test + public void throwsNullPointerException() { + thrown.expect(NullPointerException.class); + throw new NullPointerException(); + } + + @Test + public void throwsNullPointerExceptionWithMessage() { + thrown.expect(NullPointerException.class); + thrown.expectMessage("happened?"); + thrown.expectMessage(startsWith("What")); + throw new NullPointerException("What happened?"); + } +} +``` + +### Timeouts ### +- Tests that time out now show the stack trace of the test thread. + +### Matchers ### +- Due to typing incompatibilities, JUnit is still including the 1.1 release + of hamcrest. This is not a change from 4.6, but is a change from + pre-beta releases of 4.7. Due to this incompatibility, tests using + Hamcrest 1.2 must still use the MatcherAssert.assertThat method from + Hamcrest, not Assert.assertThat from JUnit. + +### Docs ### +- Javadocs now link to online JDK javadocs (bug 2090230) +- Parameterized runner javadocs improved (bug 2186792) +- Fixed Javadoc code sample for AfterClass (2126279) +- Fixed Javadoc for assertArraysEqual(float[], float[]) + +### Bug fixes ### +- Fixed: BaseTestRunner.getTest() requires class to extend TestCase (1812200) +- Fixed: Suite does not allow for inheritance in annotations (2783118) +- Fixed: ParallelComputer skipped tests that took longer than 2 seconds diff --git a/doc/ReleaseNotes4.7.txt b/doc/ReleaseNotes4.7.txt new file mode 100644 index 000000000000..58765736986d --- /dev/null +++ b/doc/ReleaseNotes4.7.txt @@ -0,0 +1 @@ +Please see ReleaseNotes4.7.md diff --git a/doc/ReleaseNotes4.8.1.html b/doc/ReleaseNotes4.8.1.html new file mode 100644 index 000000000000..32e36a656d8d --- /dev/null +++ b/doc/ReleaseNotes4.8.1.html @@ -0,0 +1,9 @@ +

    Summary of Changes in version 4.8.1

    + +

    This was a quick bugfix release for an important bug

    + +

    Bug fixes

    + +
      +
    • github#61: Category annotations on classes were not honored.
    • +
    diff --git a/doc/ReleaseNotes4.8.1.md b/doc/ReleaseNotes4.8.1.md new file mode 100644 index 000000000000..bc13f26ae14a --- /dev/null +++ b/doc/ReleaseNotes4.8.1.md @@ -0,0 +1,7 @@ +## Summary of Changes in version 4.8.1 ## + +This was a quick bugfix release for an important bug + +### Bug fixes ### + +- github#61: Category annotations on classes were not honored. \ No newline at end of file diff --git a/doc/ReleaseNotes4.8.1.txt b/doc/ReleaseNotes4.8.1.txt new file mode 100644 index 000000000000..ef1cd68a7a25 --- /dev/null +++ b/doc/ReleaseNotes4.8.1.txt @@ -0,0 +1 @@ +Please see ReleaseNotes4.8.1.md diff --git a/doc/ReleaseNotes4.8.2.html b/doc/ReleaseNotes4.8.2.html new file mode 100644 index 000000000000..273f03bcf220 --- /dev/null +++ b/doc/ReleaseNotes4.8.2.html @@ -0,0 +1,10 @@ +

    Summary of Changes in version 4.8.2

    + +

    This was a quick bugfix release

    + +

    Bug fixes

    + +
      +
    • github#96: TestSuite(MyTestCase.class) should dynamically detect if MyTestCase +is a TestCase
    • +
    diff --git a/doc/ReleaseNotes4.8.2.md b/doc/ReleaseNotes4.8.2.md new file mode 100644 index 000000000000..8631275cacbc --- /dev/null +++ b/doc/ReleaseNotes4.8.2.md @@ -0,0 +1,8 @@ +## Summary of Changes in version 4.8.2 ## + +This was a quick bugfix release + +### Bug fixes ### + +- github#96: TestSuite(MyTestCase.class) should dynamically detect if MyTestCase + is a TestCase diff --git a/doc/ReleaseNotes4.8.2.txt b/doc/ReleaseNotes4.8.2.txt new file mode 100644 index 000000000000..e6a2ec01bcdc --- /dev/null +++ b/doc/ReleaseNotes4.8.2.txt @@ -0,0 +1 @@ +Please see ReleaseNotes4.8.2.md diff --git a/doc/ReleaseNotes4.8.html b/doc/ReleaseNotes4.8.html new file mode 100644 index 000000000000..086f5d0f5220 --- /dev/null +++ b/doc/ReleaseNotes4.8.html @@ -0,0 +1,59 @@ +

    Summary of Changes in version 4.8

    + +

    Categories

    + +

    From a given set of test classes, the Categories runner +runs only the classes and methods +that are annotated with either the category given with the @IncludeCategory +annotation, or a subtype of that category. Either classes or interfaces can be +used as categories. Subtyping works, so if you say @IncludeCategory(SuperClass.class), +a test marked @Category({SubClass.class}) will be run.

    + +

    You can also exclude categories by using the @ExcludeCategory annotation

    + +

    Example:

    + +
    public interface FastTests { /* category marker */ }
    +public interface SlowTests { /* category marker */ }
    +
    +public class A {
    +    @Test
    +    public void a() {
    +        fail();
    +    }
    +
    +    @Category(SlowTests.class)
    +    @Test
    +    public void b() {
    +    }
    +}
    +
    +@Category({SlowTests.class, FastTests.class})
    +public class B {
    +    @Test
    +    public void c() {
    +
    +    }
    +}
    +
    +@RunWith(Categories.class)
    +@IncludeCategory(SlowTests.class)
    +@SuiteClasses( { A.class, B.class }) // Note that Categories is a kind of Suite
    +public class SlowTestSuite {
    +  // Will run A.b and B.c, but not A.a
    +}
    +
    +@RunWith(Categories.class)
    +@IncludeCategory(SlowTests.class)
    +@ExcludeCategory(FastTests.class)
    +@SuiteClasses( { A.class, B.class }) // Note that Categories is a kind of Suite
    +public class SlowTestSuite {
    +  // Will run A.b, but not A.a or B.c
    +}
    +
    + +

    Bug fixes

    + +
      +
    • github#16: thread safety of Result counting
    • +
    diff --git a/doc/ReleaseNotes4.8.md b/doc/ReleaseNotes4.8.md new file mode 100644 index 000000000000..cc429ea08b74 --- /dev/null +++ b/doc/ReleaseNotes4.8.md @@ -0,0 +1,57 @@ +## Summary of Changes in version 4.8 ## + +### Categories ### + +From a given set of test classes, the `Categories` runner +runs only the classes and methods +that are annotated with either the category given with the `@IncludeCategory` +annotation, or a subtype of that category. Either classes or interfaces can be +used as categories. Subtyping works, so if you say `@IncludeCategory(SuperClass.class)`, +a test marked `@Category({SubClass.class})` will be run. + +You can also exclude categories by using the `@ExcludeCategory` annotation + +Example: + +```java +public interface FastTests { /* category marker */ } +public interface SlowTests { /* category marker */ } + +public class A { + @Test + public void a() { + fail(); + } + + @Category(SlowTests.class) + @Test + public void b() { + } +} + +@Category({SlowTests.class, FastTests.class}) +public class B { + @Test + public void c() { + } +} + +@RunWith(Categories.class) +@IncludeCategory(SlowTests.class) +@SuiteClasses( { A.class, B.class }) // Note that Categories is a kind of Suite +public class SlowTestSuite { + // Will run A.b and B.c, but not A.a +} + +@RunWith(Categories.class) +@IncludeCategory(SlowTests.class) +@ExcludeCategory(FastTests.class) +@SuiteClasses( { A.class, B.class }) // Note that Categories is a kind of Suite +public class SlowTestSuite { + // Will run A.b, but not A.a or B.c +} +``` + +### Bug fixes ### + +- github#16: thread safety of Result counting diff --git a/doc/ReleaseNotes4.8.txt b/doc/ReleaseNotes4.8.txt new file mode 100644 index 000000000000..6f4904e020f4 --- /dev/null +++ b/doc/ReleaseNotes4.8.txt @@ -0,0 +1 @@ +Please see ReleaseNotes4.8.md diff --git a/doc/ReleaseNotes4.9.1.md b/doc/ReleaseNotes4.9.1.md new file mode 100644 index 000000000000..eded783dbb66 --- /dev/null +++ b/doc/ReleaseNotes4.9.1.md @@ -0,0 +1,14 @@ +## Summary of Changes in version 4.9.1 [unreleased!] ## + +### Theories ### + +The `Theories` runner does not anticipate theory parameters that have generic +types, as reported by github#64. Fixing this won't happen until `Theories` is +moved to junit-contrib. In anticipation of this, 4.9.1 adds some of the +necessary machinery to the runner classes, and deprecates a method that only +the `Theories` runner uses, `FrameworkMethod`#producesType(). +The Common Public License that JUnit is released under is now included +in the source repository. + +Thanks to `@pholser` for identifying a potential resolution for github#64 +and initiating work on it. diff --git a/doc/ReleaseNotes4.9.1.txt b/doc/ReleaseNotes4.9.1.txt new file mode 100644 index 000000000000..1a0a67b89fa7 --- /dev/null +++ b/doc/ReleaseNotes4.9.1.txt @@ -0,0 +1 @@ +Please see ReleaseNotes4.9.1.md diff --git a/doc/ReleaseNotes4.9.html b/doc/ReleaseNotes4.9.html new file mode 100644 index 000000000000..36921023a654 --- /dev/null +++ b/doc/ReleaseNotes4.9.html @@ -0,0 +1,96 @@ +

    Summary of Changes in version 4.9, final

    + +

    Release theme: Test-class and suite level Rules.

    + +

    ClassRule

    + +

    The ClassRule annotation extends the idea of method-level Rules, +adding static fields that can affect the operation of a whole class. Any +subclass of ParentRunner, including the standard BlockJUnit4ClassRunner +and Suite classes, will support ClassRules.

    + +

    For example, here is a test suite that connects to a server once before +all the test classes run, and disconnects after they are finished:

    + +
    @RunWith(Suite.class)
    +@SuiteClasses({A.class, B.class, C.class})
    +public class UsesExternalResource {
    +    public static Server myServer= new Server();
    +
    +    @ClassRule
    +    public static ExternalResource resource= new ExternalResource() {
    +        @Override
    +        protected void before() throws Throwable {
    +            myServer.connect();
    +        };
    +
    +        @Override
    +        protected void after() {
    +            myServer.disconnect();
    +        };
    +    };
    +}
    +
    + +

    TestRule

    + +

    In JUnit 4.9, fields that can be annotated with either @Rule or @ClassRule +should be of type TestRule. The old MethodRule type, which only made sense +for method-level rules, will still work, but is deprecated.

    + +

    Most built-in Rules have been moved to the new type already, in a way that +should be transparent to most users. TestWatchman has been deprecated, +and replaced by TestWatcher, which has the same functionality, but implements +the new type.

    + +

    Maven support

    + +

    Maven bundles have, in the past, been uploaded by kind volunteers. Starting +with this release, the JUnit team is attempting to perform this task ourselves.

    + +

    LICENSE checked in

    + +

    The Common Public License that JUnit is released under is now included +in the source repository.

    + +

    Bug fixes

    + +
      +
    • github#98: assumeTrue() does not work with expected exceptions
    • +
    • github#74: Categories + Parameterized

      + +

      In JUnit 4.8.2, the Categories runner would fail to run correctly +if any contained test class had a custom Runner with a structure +significantly different from the built-in Runner. With this fix, +such classes can be assigned one or more categories at the class level, +and will be run correctly. Trying to assign categories to methods within +such a class will flag an error.

    • +
    • github#38: ParentRunner filters more than once

      + +

      Thanks to @reinholdfuereder

    • +
    • github#248: protected BlockJUnit4ClassRunner#rules method removed from 4.8.2

    • +
    • github#187: Accidental dependency on Java 6
    • +
    + +

    Thanks to @kcooney for:

    + +
      +
    • github#163: Bad comparison failure message when using assertEquals(String, String)
    • +
    • github#227: ParentRunner now assumes that getChildren() returns a modifiable list
    • +
    + +

    Minor changes

    + +
      +
    • Backed out unused folder "experimental-use-of-antunit", replaced by +bash-based script at build_tests.sh
    • +
    • Various Javadoc fixes
    • +
    + +

    Thanks to @kcooney for:

    + +
      +
    • Made MultipleFailureException public, to assist extension writers.
    • +
    • github#240: Add "test" target to build.xml, for faster ant-driven testing.
    • +
    • github#247: Give InitializationError a useful message
    • +
    diff --git a/doc/ReleaseNotes4.9.md b/doc/ReleaseNotes4.9.md new file mode 100644 index 000000000000..7d8d75880c48 --- /dev/null +++ b/doc/ReleaseNotes4.9.md @@ -0,0 +1,91 @@ +## Summary of Changes in version 4.9, final ## + +Release theme: Test-class and suite level Rules. + +### ClassRule ### + +The `ClassRule` annotation extends the idea of method-level Rules, +adding static fields that can affect the operation of a whole class. Any +subclass of `ParentRunner`, including the standard `BlockJUnit4ClassRunner` +and `Suite` classes, will support `ClassRule`s. + +For example, here is a test suite that connects to a server once before +all the test classes run, and disconnects after they are finished: + +```java +@RunWith(Suite.class) +@SuiteClasses({A.class, B.class, C.class}) +public class UsesExternalResource { + public static Server myServer= new Server(); + + @ClassRule + public static ExternalResource resource= new ExternalResource() { + @Override + protected void before() throws Throwable { + myServer.connect(); + } + + @Override + protected void after() { + myServer.disconnect(); + } + }; +} +``` + +### TestRule ### + +In JUnit 4.9, fields that can be annotated with either `@Rule` or `@ClassRule` +should be of type `TestRule`. The old `MethodRule` type, which only made sense +for method-level rules, will still work, but is deprecated. + +Most built-in Rules have been moved to the new type already, in a way that +should be transparent to most users. `TestWatchman` has been deprecated, +and replaced by `TestWatcher`, which has the same functionality, but implements +the new type. + +### Maven support ### + +Maven bundles have, in the past, been uploaded by kind volunteers. Starting +with this release, the JUnit team is attempting to perform this task ourselves. + +### LICENSE checked in ### + +The Common Public License that JUnit is released under is now included +in the source repository. + +### Bug fixes ### + +- github#98: assumeTrue() does not work with expected exceptions +- github#74: Categories + Parameterized + + In JUnit 4.8.2, the Categories runner would fail to run correctly + if any contained test class had a custom Runner with a structure + significantly different from the built-in Runner. With this fix, + such classes can be assigned one or more categories at the class level, + and will be run correctly. Trying to assign categories to methods within + such a class will flag an error. + +- github#38: ParentRunner filters more than once + + Thanks to `@reinholdfuereder` + +- github#248: protected BlockJUnit4ClassRunner#rules method removed from 4.8.2 +- github#187: Accidental dependency on Java 6 + +Thanks to `@kcooney` for: + +- github#163: Bad comparison failure message when using assertEquals(String, String) +- github#227: ParentRunner now assumes that getChildren() returns a modifiable list + +### Minor changes ### + +- Backed out unused folder "experimental-use-of-antunit", replaced by + bash-based script at build_tests.sh +- Various Javadoc fixes + +Thanks to `@kcooney` for: + +- Made MultipleFailureException public, to assist extension writers. +- github#240: Add "test" target to build.xml, for faster ant-driven testing. +- github#247: Give InitializationError a useful message diff --git a/doc/ReleaseNotes4.9.txt b/doc/ReleaseNotes4.9.txt new file mode 100644 index 000000000000..a9d7d6033877 --- /dev/null +++ b/doc/ReleaseNotes4.9.txt @@ -0,0 +1 @@ +Please see ReleaseNotes4.9.md diff --git a/doc/building-junit.txt b/doc/building-junit.txt new file mode 100644 index 000000000000..91169e3427b3 --- /dev/null +++ b/doc/building-junit.txt @@ -0,0 +1,98 @@ +Steps to build junit: + +- Must be manual + - Write release notes +- Not too tedious: + - Push to github (junit-team) + - Run the ./mvnw clean install + - If not done, update $M2_HOME/settings.xml + - If not done, copy GnuPG keys in to ${gpg.homedir}. See settings.xml. + - Perform Maven deployment of a snapshot or release version in Jenkins + Remember that the version specified in the pom.xml indicates the version + to be deployed, with -SNAPSHOT indicating that this is an unofficial + pre-release version towards the goal of the version without the -SNAPSHOT + + - (to deploy gpg signed snapshot version) + + $ ./mvnw -Pjunit-release clean deploy + + - (to cut a release of the current targetted version) + + $ ./mvnw -B release:prepare release:perform + + This will result in the current pom.xml version having -SNAPSHOT removed + and the release cut from that version. The version will then be incremented + and -SNAPSHOT added back in anticipation of the next release version. + + - (to cut a release of while changing the version from the current target) + + $ ./mvnw -B -DreleaseVersion=5.0 release:prepare release:perform + + This will ignore the current version in the pom.xml, set it to 5.0 and + the release cut from that 5.0 version. Then 5.0 will be incremented (to 5.1) + and -SNAPSHOT added back in anticipation of the next release version. + + - (to deploy specified release version and next target release in non-interactive mode -B) + An example with the next development version and deploying release version: + + $ ./mvnw -B -DreleaseVersion=4.12 -DdevelopmentVersion=4.13-SNAPSHOT release:prepare release:perform + + - If you are not an official release manager, and you want to cut a release of + JUnit for use within your organization, use the following command + + $ ./mvnw -DpushChanges=false -DlocalCheckout '-Darguments=-Dgpg.skip=true -DaltDeploymentRepository=my-company-repo-id::default::my-company-repo-url' -B -DreleaseVersion=4.12-mycompany-1 release:prepare release:perform + + where + - my-company-repo-id is the of your company's entry in your + settings.xml with the credentials to deploy to your company's Maven repository + - my-company-repo-url is the deployment URL of your company's Maven repository + - 4.12-mycompany-1 is the version you are deploying, be sure to namespace + the version so that you don't conflict with others, hence why the text "mycompany" + is included in the example version number. + + - Promote the maven artifacts and close staging repository if released successfully +- Tedious: + - Update SourceForge if major release + - Update javadocs on github site (and "latest" link) + - Update javadocs on junit.org + - Put release notes on github. + - Announce on blog, user list, dev list, announce list, junit.org, twitter +- Profit! + + +=================================================================================== +== Internal template of Maven settings used by JUnit build machine. == +== settings.xml == +=================================================================================== + + + + + junit-snapshot-repo + + + + + junit-releases-repo + + + + + + + junit-release + + + ... + false + true + /private/.../.gnupg + /private/.../.gnupg/pubring.gpg + /private/.../.gnupg/secring.gpg + + + + +=================================================================================== diff --git a/doc/changes21.html b/doc/changes21.html deleted file mode 100644 index ba54d5877995..000000000000 --- a/doc/changes21.html +++ /dev/null @@ -1,108 +0,0 @@ - - - - - - - JUnit 2 - - - -

    -Summary of Changes between 1.0 and 2.1

    -The focus of this release was to refactor parts of the framework and to -make it more consistent. In addition, we have simplified the writing and -running of tests. -
      -
    • -We renamed the package prefix for all junit classes from "test" to "junit."
    • - -
    • -This version extracts test -suites automatically. TestSuite now provides a constructor TestSuite(Class -theClass). This constructor adds all the methods from the given class -starting with "test" as test cases to the suite. This avoids you having -to update the suite method manually when adding a new test. For example, -the suite() method of the VectorTest can now be written as:
    • - -
        public static Test suite() { -
          return new TestSuite(VectorTest.class); -
        }
      - -
    • -Several new assert methods were added:
    • - -
        -
      • -assertNotNull(Object object)
      • - -
      • -assertNotNull(String message, Object object)
      • - -
      • -assertNull(Object object)
      • - -
      • -assertNull(String message, Object object)
      • - -
      • -assertSame(Object actual, Object expected)
      • - -
      • -assertSame(String message, Object actual, Object expected)
      • - -
      • -fail()
      • - -
      • -fail(String message).
      • -
      - -
    • -Exceptions during setUp() and tearDown() are now caught and reported.
    • - -
    • -A warning is now given when a TestCase class isn't public or has no test -methods.
    • - -
    • -All the assert methods are now public.
    • -
    - -
      -
    • -Both the batch and the interactive TestRunner no longer require that the -Test class provides a static suite() method. If there is no suite method -all the public void methods starting with "test" and no arguments are run -(see above). There is a new variation of the graphical TestRunner (junit.ui.TestRunner) -the LoadingTestRunner. The LoadingTestRunner uses a custom class loader -to reload user classes for each test run. This avoids that the TestRunner -tool needs to be restarted for each run. The old TestRunner attempted to -address this by making assumptions about the garbage collection of classes -which were not portable.  In particular, the old scheme would not -work at Notice, in an environment with dynamic object migration support -or hot code updating like VisualAge for Java this isn't an issue.
    • - -
      There, the environment takes care of updating the code and objects -run by the TestRunner. When using JUnit with VisualAge for Java, just use -the standard junit.ui.TestRunner. -
    • -When the graphical TestRunner is run under Visual Age for Java there is -an additional run button to rerun a failed test. This is typically used -to set a breakpoint in the test method and to rerun it under the debugger.
    • - -
    • -The TestRunners support the command line option -c TestClassName. This -allows you to run them  as VisualAge for Java tools.
    • - -
      Once you have JUnit installed as a VAJ tool you can select the Test -class and run its tests from a VAJ menu (see how to run JUnit as a VisualAge -for Java tool). -
    • -The batch TestRunner supports a runAndWait method to run a suite and wait -until the user types RETURN.
    • -
    - -
    - - diff --git a/doc/cookbook/IMG00001.GIF b/doc/cookbook/IMG00001.GIF deleted file mode 100644 index e37f8c2bac81..000000000000 Binary files a/doc/cookbook/IMG00001.GIF and /dev/null differ diff --git a/doc/cookbook/cookbook.htm b/doc/cookbook/cookbook.htm deleted file mode 100644 index 5b32d1975de8..000000000000 --- a/doc/cookbook/cookbook.htm +++ /dev/null @@ -1,257 +0,0 @@ - - - - - - - JUnit Cookbook - - - -

    -JUnit Cookbook

    - -

    -Kent Beck, Erich Gamma

    - -
    -
    Here is a short cookbook showing you the steps you can follow in writing -and organizing your own tests using JUnit. -

    -Simple Test Case

    -How do you write testing code? -

    The simplest way is as an expression in a debugger. You can change debug -expressions without recompiling, and you can wait to decide what to write -until you have seen the running objects. You can also write test expressions -as statements which print to the standard output stream. Both styles of -tests are limited because they require human judgment to analyze their -results. Also, they don't compose nicely- you can only execute one debug -expression at a time and a program with too many print statements causes -the dreaded "Scroll Blindness". -

    JUnit tests do not require human judgment to interpret, and it is easy -to run many of them at the same time. When you need to test something, -here is what you do: -

      -
    1. -Create a subclass of TestCase.
    2. - -
    3. -Override the method runTest()
    4. - -
    5. -When you want to check a value, call assertTrue() and pass a boolean -that is true if the test succeeds
    6. -
    -For example, to test that the sum of two Moneys with the same currency -contains a value which is the sum of the values of the two Moneys, write: -
    -
    public void testSimpleAdd() {
    -    Money m12CHF= new Money(12, "CHF"); 
    -    Money m14CHF= new Money(14, "CHF"); 
    -    Money expected= new Money(26, "CHF"); 
    -    Money result= m12CHF.add(m14CHF); 
    -    assertTrue(expected.equals(result));
    -}
    -
    -If you want to write a test similar to one you have already written, write -a Fixture instead. When you want to run more than one test, create a Suite. -

    -Fixture

    -What if you have two or more tests that operate on the same or similar -sets of objects? -

    Tests need to run against the background of a known set of objects. -This set of objects is called a test fixture. When you are writing tests -you will often find that you spend more time writing the code to set up -the fixture than you do in actually testing values. -

    To some extent, you can make writing the fixture code easier by paying -careful attention to the constructors you write. However, a much bigger -savings comes from sharing fixture code. Often, you will be able to use -the same fixture for several different tests. Each case will send slightly -different messages or parameters to the fixture and will check for different -results. -

    When you have a common fixture, here is what you do: -

      -
    1. -Create a subclass of TestCase
    2. - -
    3. -Add an instance variable for each part of the fixture
    4. - -
    5. -Override setUp() -to initialize the variables
    6. - -
    7. -Override tearDown() -to release any permanent resources you allocated in setUp
    8. -
    -For example, to write several test cases that want to work with different -combinations of 12 Swiss Francs, 14 Swiss Francs, and 28 US Dollars, first -create a fixture: -
    public class MoneyTest extends TestCase { 
    -    private Money f12CHF; 
    -    private Money f14CHF; 
    -    private Money f28USD; 
    -    
    -    protected void setUp() { 
    -        f12CHF= new Money(12, "CHF"); 
    -        f14CHF= new Money(14, "CHF"); 
    -        f28USD= new Money(28, "USD"); 
    -    }
    -}
    -Once you have the Fixture in place, you can write as many Test Cases as -you'd like. -

    -Test Case

    -How do you write and invoke an individual test case when you have a Fixture? -

    Writing a test case without a fixture is simple- override runTest -in an anonymous subclass of TestCase. You write test cases for a Fixture -the same way, by making a subclass of TestCase for your set up code and -then making anonymous subclasses for the individual test cases. However, -after a few such tests you would notice that a large percentage of your -lines of code are sacrificed to syntax. -

    JUnit provides a more concise way to write a test against a Fixture. -Here is what you do: -

      -
    1. -Write a public void method in the fixture class. By convention, the name of the -method begins with "test".
    2. - -
    -For example, to test the addition of a Money and a MoneyBag, write: -
    -
    public void testMoneyMoneyBag() { 
    -    // [12 CHF] + [14 CHF] + [28 USD] == {[26 CHF][28 USD]} 
    -    Money bag[]= { f26CHF, f28USD }; 
    -    MoneyBag expected= new MoneyBag(bag); 
    -    assertEquals(expected, f12CHF.add(f28USD.add(f14CHF)));
    -}
    -
    -Create an instance of of MoneyTest that will run this test case like this: -
    -
    new MoneyTest("testMoneyMoneyBag")
    -
    -When the test is run, the name of the test is used to look up the method -to run. -

    Once you have several tests, organize them into a Suite. -

    -Suite

    -How do you run several tests at once? -

    As soon as you have two tests, you'll want to run them together. You -could run the tests one at a time yourself, but you would quickly grow -tired of that. Instead, JUnit provides an object, TestSuite -which runs any number of test cases together. -

    For example, to run a single test case, you execute: -

    -
    TestResult result= (new MoneyTest("testMoneyMoneyBag")).run();
    -
    -To create a suite of two test cases and run them together, execute: -
    -
    TestSuite suite= new TestSuite();
    -suite.addTest(new MoneyTest("testMoneyEquals"));
    -suite.addTest(new MoneyTest("testSimpleAdd"));
    -TestResult result= suite.run();
    -
    -Another way is to let JUnit extract a suite from a TestCase. To do so you -pass the class of your TestCase to the -
    TestSuite constructor. -
    -
    TestSuite suite= new TestSuite(MoneyTest.class);
    -TestResult result= suite.run();
    -
    -

    Use the manual way when you want a suite to only contain a subset of -the test cases. Otherwise the automatic suite extraction is the preferred -way. It avoids you having to update the suite creation code when you add -a new test case. -

    TestSuites don't only have to contain TestCases. They contain any object -that implements the Test -interface. For example, you can create a TestSuite in your code and I can -create one in mine, and we can run them together by creating a TestSuite -that contains both: -

    -
    TestSuite suite= new TestSuite();
    -suite.addTest(Kent.suite());
    -suite.addTest(Erich.suite());
    -TestResult result= suite.run();
    - -
    - -

    -TestRunner

    -How do you run your tests and collect their results? -

    Once you have a test suite, you'll want to run it. JUnit provides tools -to define the suite to be run and to display its results. You make your -suite accessible to a TestRunner tool with a static method suite -that returns a test suite. -
    For example, to make a MoneyTest suite available to a TestRunner, add -the following code to MoneyTest: -

    -
    public static Test suite() { 
    -    TestSuite suite= new TestSuite(); 
    -    suite.addTest(new MoneyTest("testMoneyEquals")); 
    -    suite.addTest(new MoneyTest("testSimpleAdd")); 
    -    return suite;
    -}
    -
    -Or, as a shortcut: -
    -
    public static Test suite() { 
    -    return new TestSuite(MoneyTest.class); 
    -}
    -
    -

    If a TestCase class doesn't define a suite method a TestRunner will extract -a suite and fill it with all the methods starting with "test".

    -

    JUnit provides both a graphical and a textual version of a TestRunner -tool. Start it by typing java junit.awtui.TestRunner -or junit.swingui.TestRunner. -The graphical user interface presents a window with: -

      -
    • -a field to type in the name of a class with a suite method,
    • - -
    • -a Run button to start the test,
    • - -
    • -a progress indicator that turns from green to red in the case of a failed -test,
    • - -
    • -a list of failed tests.
    • -
    -In the case of an unsuccessful test JUnit reports the failed tests in a -list at the bottom. JUnit distinguishes between failures and errors. -A failure is anticipated and checked for with assertions. Errors are unanticipated -problems like an ArrayIndexOutOfBoundsException. The following figure -shows an example of a failed test. -
    - -


    -

    You have to restart the graphical interface each time you change the code. This -is tedious and time consuming. As an alternative JUnit's AWT and Swing UIs use -junit.runner.LoadingTestCollector -. -This LoadingTestCollector reloads all your classes for each test run. This feature can -be disabled by unchecking the 'Reload classes every run' checkbox. The most -common JUnit problem is that many packages want to use their own class loader. -Include such packages in excluded.properties. See the FAQ -for details. -

    There is a batch interface to JUnit, also. To use it typejava junit.textui.TestRunner -followed by the name of the class with a suite method at an operating system -prompt. The batch interface shows the result as text output. An alternative -way to invoke the batch interface is to define a main method in your TestCase -class. -

    For example, to start the batch TestRunner for MoneyTest, write: -

    -
    public static void main(String args[]) { 
    -    junit.textui.TestRunner.run(suite());
    -}
    -
    -With this definition of main you can run your tests by simply typing java -MoneyTest at an operating system prompt. -

    For using either the graphical or the textual version make sure that -the junit.jar file is on your CLASSPATH. -
    -


    - - diff --git a/doc/cookstour/cookstour.htm b/doc/cookstour/cookstour.htm index aac98998aed4..597dcd8462ea 100644 --- a/doc/cookstour/cookstour.htm +++ b/doc/cookstour/cookstour.htm @@ -12,7 +12,7 @@

    JUnit A Cook's Tour

    - +
    Note: this article is based on JUnit 3.8.x.

    1. Introduction

    In an earlier article (see Test Infected: Programmers @@ -660,7 +660,7 @@

    rewarded) for our monomania by a continuous flow of insights into JUnit, testing, object design, framework development, and opportunities for further articles. -The latest version of JUnit can be downloaded from ftp://www.armaties.com/D/home/armaties/ftp/TestingFramework/JUnit/. +The latest version of JUnit can be downloaded from http://www.junit.org.

    5. Acknowledgements

    Thanks to John Vlissides, Ralph Johnson, and Nick Edgar for careful reading and gentle correction. diff --git a/doc/faq/faq.htm b/doc/faq/faq.htm deleted file mode 100644 index 9f27c7eb7cd4..000000000000 --- a/doc/faq/faq.htm +++ /dev/null @@ -1,2835 +0,0 @@ - - - - - JUnit FAQ - - - - - - - -

    - JUnit FAQ -

    -
    - - - -

    - -JUnit is an open source Java testing framework used to write and run -automated test. -
    -It is an instance of the xUnit architecture for unit -testing frameworks. -
    -

    -
    -

    -Editor: Mike Clark, -Clarkware Consulting -

    -

    -Last modified on December 28, 2004 -

    - -
    - - - -
    -Table of Contents -
    -
      -
    1. -

      - FAQ Info -

      -
        -
      1. Who is responsible for this FAQ?
      2. -
      3. How can I contribute to this FAQ?
      4. -
      5. Where do I get the latest version of - this FAQ?
      6. -
      -
    2. -
    3. -

      - Overview -

      -
        -
      1. What is JUnit?
      2. -
      3. Where is the JUnit home page?
      4. -
      5. Where are the JUnit mailing lists and - forums?
      6. -
      7. Where is the JUnit documentation?
      8. -
      9. Where can I find articles on JUnit?
      10. -
      11. What's the latest news on JUnit?
      12. -
      13. How is JUnit licensed?
      14. -
      15. What awards has JUnit won?
      16. -
      -
    4. -
    5. -

      - Getting Started -

      -
        -
      1. Where do I download JUnit?
      2. -
      3. How do I install JUnit?
      4. -
      5. How do I uninstall JUnit?
      6. -
      7. How do I ask questions?
      8. -
      9. How do I submit bugs, patches, or - feature requests?
      10. -
      -
    6. -
    7. -

      - Writing Tests -

      -
        -
      1. How do I write and run a simple test?
      2. -
      3. How do I use a test fixture?
      4. -
      5. Why isn't my test fixture being run?
      6. -
      7. How do I test a method that doesn't - return anything?
      8. -
      9. Under what conditions should I test get() - and set() methods?
      10. -
      11. Under what conditions should I not test - get() and set() methods?
      12. -
      13. How do I write a test that passes when an - expected exception is thrown?
      14. -
      15. How do I write a test that fails when an - unexpected exception is thrown?
      16. -
      17. What's the difference between a failure - and an error?
      18. -
      19. How do I test protected methods?
      20. -
      21. How do I test private methods?
      22. -
      23. Why does JUnit only report the first - failure in a single test?
      24. -
      25. In Java 1.4, 'assert' is a - keyword. Won't this conflict with JUnit's assert() - method?
      26. -
      27. How do I test things that must be run in - a J2EE container (e.g. servlets, EJBs)?
      28. -
      29. Do I need to write a TestCase class for - every class I need to test?
      30. -
      31. Is there a basic template I can use to - create a test?
      32. -
      33. How do I write a test for an abstract - class?
      34. -
      35. When are tests garbage collected?
      36. -
      -
    8. -
    9. -

      - Organizing Tests -

      -
        -
      1. Where should I put my test files?
      2. -
      3. How do I write a test suite for all of - my tests?
      4. -
      5. How can I run setUp() and tearDown() - code once for all of my tests?
      6. -
      -
    10. -
    11. -

      - Running Tests -

      -
        -
      1. What CLASSPATH settings are needed to - run JUnit?
      2. -
      3. Why do I get a NoClassDefFoundError - when trying to test JUnit or run the samples? -
      4. -
      5. How do I run the JUnit GUI test runner? -
      6. -
      7. How do I run JUnit from my command window? -
      8. -
      9. How do I run JUnit using Ant? -
      10. -
      11. How do I use Ant to create HTML test reports? -
      12. -
      13. How do I pass command-line arguments to a test execution? -
      14. -
      15. Why do I get an error (ClassCastException or - LinkageError) using the GUI TestRunners? -
      16. -
      17. Why do I get a LinkageError when using - XML interfaces in my TestCase? -
      18. -
      19. Why do I get a ClassCastException when I - use narrow() in an EJB client TestCase? -
      20. -
      21. Why do I get the warning "AssertionFailedError: No - tests found in XXX" when I run my test? -
      22. -
      23. Why do I see "Unknown Source" in the stack trace of - a test failure, rather than the source file's line number? -
      24. -
      25. Why does the "excluded.properties" trick not - work when running JUnit's GUI from inside my favorite IDE? -
      26. -
      27. How do I get one test suite to invoke another? -
      28. -
      29. How do I organize all test classes in a TestSuite - automatically and not use or manage a TestSuite explicitly? -
      30. -
      -
    12. -
    13. -

      - Best Practices -

      -
        -
      1. When should tests be written?
      2. -
      3. Do I have to write a test for - everything?
      4. -
      5. How simple is 'too simple to break'?
      6. -
      7. How often should I run my tests?
      8. -
      9. What do I do when a defect is reported?
      10. -
      11. Why not just use System.out.println()?
      12. -
      13. Why not just use a debugger?
      14. -
      -
    14. -
    15. -

      - Extending JUnit -

      -
        -
      1. How do I extend JUnit?
      2. -
      3. What kinds of extensions are - available?
      4. -
      -
    16. -
    17. -

      - Miscellaneous -

      -
        -
      1. How do I integrate JUnit with my IDE?
      2. -
      3. How do I launch a debugger when a test - fails?
      4. -
      5. Where can I find unit testing frameworks - similar to JUnit for other languages?
      6. -
      -
    18. -
    - - - -
      -
    1. -

      - Who is responsible for this FAQ? -

      -

      - The current version of this FAQ is maintained by Mike Clark. -

      -

      - Most of the wisdom contained in this FAQ comes from the - collective insights and hard-won experiences of the many good - folks who participate on the JUnit mailing list and the JUnit - community at large. -

      -

      - If you see your genius represented anywhere in this FAQ without - due credit to you, please send me an email and I'll make things - right. -

      -
    2. -
    3. -

      - How can I contribute to this FAQ? -

      -

      - Your contributions to this FAQ are greatly appreciated! The - JUnit community thanks you in advance. -

      -

      - To contribute to this FAQ, simply write a JUnit-related question - and answer, then send the unformatted text to Mike Clark. Corrections to - this FAQ are always appreciated, as well. -

      -

      - No reasonable contribution will be denied. Your name will - always appear along with any contribution you make. -

      -
    4. -
    5. -

      - Where do I get the latest version of this - FAQ? -

      -

      - The master copy of this FAQ is available at http://junit.sourceforge.net/doc/faq/faq.htm. -

      -

      - The JUnit distribution also includes this FAQ in - the doc directory. -

      -
    6. - -
    - - - - -
      -
    1. -

      - What is JUnit? -

      -

      - JUnit is an open source Java testing framework used to write and - run repeatable tests. It is an instance of the xUnit - architecture for unit testing frameworks. -

      -

      - JUnit features include: -

      -
        -
      • Assertions for testing expected results
      • -
      • Test fixtures for sharing common test data
      • -
      • Test suites for easily organizing and running tests
      • -
      • Graphical and textual test runners
      • -
      -

      - JUnit was originally written by Erich Gamma and Kent Beck. -

      -
    2. -
    3. -

      - Where is the JUnit home page? -

      -

      - The official JUnit home page is http://junit.org. -

      -
    4. -
    5. -

      - Where are the JUnit mailing lists and - forums? -

      -

      - There are 3 mailing lists dedicated to everything JUnit: -

      - -

      - You can search the JUnit - user list archives for answers to frequently asked questions not - included here. -

      -

      - There is also a jGuru - discussion forum dedicated to everything JUnit. -

      -
    6. -
    7. -

      - Where is the JUnit - documentation? -

      -

      - The following documents are included in the JUnit distribution - in the doc directory: -

      - -
    8. -
    9. -

      - Where can I find articles on - JUnit? -

      -

      - The JUnit home page maintains a list of JUnit - articles. -

      -
    10. -
    11. -

      - What's the latest news on JUnit? -

      -

      - The JUnit home page publishes the latest JUnit - news. -

      -
    12. -
    13. -

      - How is JUnit licensed? -

      -

      - JUnit is Open Source - Software, released under IBM's - Common Public License Version 0.5 and hosted on SourceForge. -

      -
    14. -
    15. -

      - What awards has JUnit won? -

      - -
    16. -
    - - - - -
      -
    1. -

      - Where do I download JUnit? -

      -

      - The latest version of JUnit is available on SourceForge. -

      -
    2. -
    3. -

      - How do I install JUnit? -

      -
        -
      1. -

        - First, download - the - latest version of JUnit, referred to below - as junit.zip. -

        -
      2. -
      3. -

        - Then install JUnit on your platform of choice: -

        -

        - Windows -

        -

        - To install JUnit on Windows, follow these steps: -

        -
          -
        1. -

          - Unzip the junit.zip distribution file to - a directory referred to as %JUNIT_HOME%. -

          -
        2. -
        3. Add JUnit to the classpath: -

          - set CLASSPATH=%CLASSPATH%;%JUNIT_HOME%\junit.jar -

          -
        4. -
        -

        - Unix (bash) -

        -

        - To install JUnit on Unix, follow these steps: -

        -
          -
        1. -

          - Unzip the junit.zip distribution file to - a directory referred to as $JUNIT_HOME. -

          -
        2. -
        3. -

          - Add JUnit to the classpath: -

          -

          - export CLASSPATH=$CLASSPATH:$JUNIT_HOME/junit.jar -

          -
        4. -
        -
      4. -
      5. -

        - (Optional) Unzip - the $JUNIT_HOME/src.jar file. -

        -
      6. -
      7. -

        - Test the installation by using either the textual or - graphical test runner to run the sample tests distributed - with JUnit. -

        -

        - Note: The sample tests are not contained in - the junit.jar, but in the installation - directory directly. Therefore, make sure that the JUnit - installation directory is in the CLASSPATH. -

        -

        - For the textual TestRunner, type: -

        -
        -
        - java junit.textui.TestRunner junit.samples.AllTests -
        -
        -

        - For the graphical TestRunner, type: -

        -
        -
        - java junit.swingui.TestRunner junit.samples.AllTests -
        -
        -

        - All the tests should pass with an "OK" (textual) or a - green bar (graphical). -

        -

        - If the tests don't pass, verify - that junit.jar is in the CLASSPATH. -

        -
      8. -
      9. -

        - Finally, read the documentation. -

        -
      10. -
      -
    4. -
    5. -

      - How do I uninstall JUnit? -

      -
        -
      1. -

        - Delete the directory structure where you unzipped the JUnit - distribution. -

        -
      2. -
      3. -

        - Remove junit.jar from the classpath -

        -
      4. -
      -

      - JUnit does not modify the registry so simply removing all the - files will fully uninstall it. -

      -
    6. -
    7. -

      - How do I ask questions? -

      -

      - Questions that are not answered in the FAQ or - in the documentation should be posted - to the jGuru - discussion forum or the JUnit user mailing - list. -

      -

      - Please stick to technical issues on the discussion forum and - mailing lists. Keep in mind that these are public, so - do not include any confidental information in your - questions! -

      -

      - You should also read "How - to ask questions the smart way" by Eric Raymond before - participating in the discussion forum and mailing lists. -

      -

      - NOTE: -
      Please do NOT submit bugs, patches, or feature requests - to the discussion forum or mailing lists.
      Refer instead - to "How do I submit bugs, patches, or - feature requests?". -
      -

      -
    8. -
    9. -

      - How do I submit bugs, patches, or - feature requests? -

      -

      - JUnit celebrates programmers testing their own software. In this - spirit, bugs, patches, and feature requests that include JUnit - tests have a better chance of being addressed than those - without. -

      -

      - JUnit is forged on SourceForge. - Please use the tools provided by SourceForge for your - submissions. -

      -
    10. -
    - - - - -
      -
    1. -

      - How do I write and run a simple test? -

      -
        -
      1. -

        - Create a subclass of TestCase: -

        -
        -
        
        -	      
        -  package junitfaq;
        -	      
        -  import java.util.*;
        -  import junit.framework.*;
        -  
        -  public class SimpleTest extends TestCase {
        -	  
        -
        -
      2. -
      3. -

        - Write a test method to assert expected results on the - object under test: -

        -
        -
        
        -
        -    public void testEmptyCollection() {
        -        Collection collection = new ArrayList();
        -        assertTrue(collection.isEmpty());
        -    }
        -	  
        -
        -
      4. -
      5. -

        - Write a suite() method that uses reflection - to dynamically create a test suite containing all - the testXXX() methods: -

        -
        -
        
        -
        -    public static Test suite() {
        -        return new TestSuite(SimpleTest.class);
        -    }
        -	  
        -
        -
      6. -
      7. -

        - Write a main() method to conveniently run the - test with the textual test runner: -

        -
        -
        
        -
        -        public static void main(String args[]) {
        -            junit.textui.TestRunner.run(suite());
        -        }
        -    }
        -	  
        -
        -
      8. -
      9. -

        - Run the test: -

        -
          -
        • -

          - To run the test with the textual test runner used - in main(), type: -

          -
          -
          -java junitfaq.SimpleTest -
          -
          -

          - The passing test results in the following textual output: -

          -
          -
          -
          
          -.
          -Time: 0
          -
          -OK (1 tests)
          -		
          -
          -
          -
        • -
        • -

          - To run the test with the graphical test runner, type: -

          -
          -
          -java junit.swingui.TestRunner junitfaq.SimpleTest -
          -
          -

          - The passing test results in a green bar displayed in - the graphical UI. -

          -
        • -
        -
      10. -
      -
    2. -
    3. -

      - How do I use a test fixture? -

      -

      - A test fixture is useful if you have two or more tests for a - common set of objects. Using a test fixture avoids duplicating - the test code necessary to initialize and cleanup those common - objects for each test. -

      -

      - Tests can use the objects (variables) in a test fixture, with - each test invoking different methods on objects in the fixture - and asserting different expected results. Each test runs in its - own test fixture to isolate tests from the changes made by other - tests. That is, tests don't share the state of objects in the - test fixture. Because the tests are isolated, they can be run - in any order. -

      -

      - To create a test fixture, define a setUp() method - that initializes common objects and a tearDown() - method to cleanup those objects. The JUnit framework - automatically invokes the setUp() method before - each test is run and the tearDown() method after - each test is run. -

      -

      - The following test uses a test fixture to initialize and cleanup - a common Collection object such that both tests are - isolated from changes made by the other: -

      -
      -
      
      -
      -    package junitfaq;
      -
      -    import junit.framework.*;
      -    import java.util.*;
      -    
      -    public class SimpleTest extends TestCase {
      -    
      -        private Collection collection;
      -	
      -        protected void setUp() {
      -            collection = new ArrayList();
      -        }
      -	
      -        protected void tearDown() {
      -            collection.clear();
      -        }
      -
      -        public void testEmptyCollection() {
      -            assertTrue(collection.isEmpty());
      -        }
      -	
      -        public void testOneItemCollection() {
      -            collection.add("itemA");
      -            assertEquals(1, collection.size());
      -        }
      -    }
      -      
      -
      -

      - Given this test, the methods might execute in the following - order: -

      -
      -
      -
      
      -setUp()
      -testOneItemCollection()
      -tearDown()
      -setUp()
      -testEmptyCollection()
      -tearDown()
      -	
      -
      -
      -

      - The ordering of test-method invocations is not guaranteed, - so testEmptyCollection() might be executed - before testOneItemCollection(). This is why the - test methods themselves must be written to be independent of one - another. What is guaranteed is that setUp() will - execute before each test method and tearDown() will - execute after each test method. -

      -
    4. -
    5. -

      - Why isn't my test fixture being run? -

      -

      - Make sure the test fixture methods are defined as follows, - noting that both method names are case sensitive: -

      -
      -
      -protected void setUp() {
      -    // initialization code
      -}
      -
      -protected void tearDown() {
      -    // cleanup code
      -}
      -      
      -
      -
    6. -
    7. -

      - How do I test a method that doesn't - return anything? -

      -

      - (Submitted by: Dave Astels) -

      -

      - Often if a method doesn't return a value, it will have some side - effect. Actually, if it doesn't return a value AND doesn't have - a side effect, it isn't doing anything. -

      -

      - There may be a way to verify that the side effect actually - occurred as expected. For example, consider - the add() method in the Collection classes. There - are ways of verifying that the side effect happened (i.e. the - object was added). You can check the size and assert that it is - what is expected: -

      -
      -
      
      -
      -    public void testCollectionAdd() {
      -        Collection collection = new ArrayList();
      -        assertEquals(0, collection.size());
      -        collection.add("itemA");
      -        assertEquals(1, collection.size());
      -        collection.add("itemB");
      -        assertEquals(2, collection.size());
      -    }
      -      
      -
      -

      - Another approach is to make use of MockObjects. -

      -

      - A related issue is to design for testing. For example, if you - have a method that is meant to output to a file, don't pass in a - filename, or even a FileWriter. Instead, pass in - a Writer. That way you can pass in - a StringWriter to capture the output for testing - purposes. Then you can add a method - (e.g. writeToFileNamed(String filename)) to - encapsulate the FileWriter creation. -

      -
    8. -
    9. -

      - Under what conditions should I test - get() and set() methods? -

      -

      - Unit tests are intended to alleviate fear that something might - break. If you think a get() or set() - method could reasonably break, or has in fact contributed to a - defect, then by all means write a test. -

      -

      - In short, test until you're confident. What you choose to test - is subjective, based on your experiences and confidence level. - Remember to be practical and maximize your testing investment. -

      -

      - Refer also to "How simple is 'too simple to - break'?". -

      -
    10. -
    11. -

      - Under what conditions should I not test - get() and set() methods? -

      -

      - (Submitted by: J. B. Rainsberger) -

      -

      - Most of the time, get/set methods just can't break, and if they - can't break, then why test them? While it is usually better to - test more, there is a definite curve of diminishing returns on - test effort versus "code coverage". Remember the maxim: "Test - until fear turns to boredom." -

      -

      - Assume that the getX() method only does "return x;" - and that the setX() method only does "this.x = - x;". If you write this test: -

      -
      -
      -testGetSetX() {
      -    setX(23);
      -    assertEquals(23, getX());
      -}
      -      
      -
      -

      - then you are testing the equivalent of the following: -

      -
      -
      -testGetSetX() {
      -    x = 23;
      -    assertEquals(23, x);
      -}
      -
      -
      -

      - or, if you prefer, -

      -
      -
      -testGetSetX() {
      -    assertEquals(23, 23);
      -}
      -
      -
      -

      - At this point, you are testing the Java compiler, or possibly - the interpreter, and not your component or application. There is - generally no need for you to do Java's testing for them. -

      -

      - If you are concerned about whether a property has already been - set at the point you wish to call getX(), then you - want to test the constructor, and not the getX() - method. This kind of test is especially useful if you have - multiple constructors: -

      -
      -
      -testCreate() {
      -    assertEquals(23, new MyClass(23).getX());
      -}
      -      
      -
      -
    12. -
    13. -

      - How do I write a test that passes when - an expected exception is thrown? -

      -

      - Catch the exception within the test method. If it isn't thrown, - call the fail() method to signal the failure of the - test. -

      -

      - The following is an example test that passes when the - expected IndexOutOfBoundsException is raised: -

      -
      -
      
      -
      -    public void testIndexOutOfBoundsException() {
      -		
      -        ArrayList emptyList = new ArrayList();
      -		
      -        try {
      -	
      -            Object o = emptyList.get(0);
      -	
      -            fail("Should raise an IndexOutOfBoundsException");
      -	
      -        } catch (IndexOutOfBoundsException expected) {
      -            assertTrue(true);
      -        }
      -    }
      -      
      -
      -
    14. -
    15. -

      - How do I write a test that fails when - an unexpected exception is thrown? -

      -

      - Declare the exception in the throws clause of the - test method and don't catch the exception within the test - method. Uncaught exceptions will cause the test to fail with an - error. -

      -

      - The following is an example test that fails when - the IndexOutOfBoundsException is raised: -

      -
      -
      
      -
      -    public void testIndexOutOfBoundsExceptionNotRaised() 
      -        throws IndexOutOfBoundsException {
      -    
      -        ArrayList emptyList = new ArrayList();
      -        Object o = emptyList.get(0);
      -    }
      -      
      -
      -
    16. -
    17. -

      - What's the difference between a failure - and an error? -

      -

      - Assertions are used to check for the possibility of failures, - therefore failures are anticipated. Errors are unanticipated - problems resulting in uncaught exceptions being propagated from - a JUnit test method. -

      -

      - In the following example, the FileNotFoundException - is expected and checked with an assertion. If the expected - exception is not raised, then a failure is produced. If any - other unexpected IOException or unchecked exception - (e.g. NullPointerException) is raised, the JUnit - framework catches the exception and signals an error. -

      -
      -
      
      -
      -    public void testNonexistentFileRead() throws IOException {
      -        try {
      -
      -            File file = new File("doesNotExist.txt");
      -            FileReader reader = new FileReader(file);
      -            assertEquals('a', (char)reader.read());
      -			
      -            fail("Read from a nonexistent file?!");
      -	
      -        } catch (FileNotFoundException expected) {
      -            assertTrue(true);
      -        }
      -    } 
      -      
      -
      -

      - In the following example, an IOException is not - expected. The JUnit framework will signal an error if - an IOException - (e.g. FileNotFoundException) or any unchecked - exception (e.g. NullPointerException) is raised. -

      -
      -
      
      -
      -    public void testExistingFileRead() throws IOException {
      -
      -        // exists.txt created in setup(), perhaps
      -
      -        File file = new File("exists.txt");  
      -        FileReader reader = new FileReader(file);
      -			
      -        assertEquals('a', (char)reader.read());
      -    } 
      -      
      -
      -

      - Both failures and errors will cause the test to fail. However, - it is useful to differentiate between failures and errors - because the debugging process is slightly different. -

      -

      - In the first example, the use of fail() will not - generate a complete stack trace including the method that raised - the exception. In this case that's sufficient since we - anticipate that the exception will be raised. If it's not - raised, then it's a problem with the test itself. -

      -

      - In the second example, the JUnit framework catches the exception - and generates an error with a complete stack trace for the - exception. Since we don't expect this exception to be raised, a - complete stack trace is useful in debugging why it was raised. -

      -
    18. -
    19. -

      - How do I test protected methods? -

      -

      - Place your tests in the same package as the classes under test. -

      -

      - Refer to "Where should I put my test - files?" for examples of how to organize tests for protected - method access. -

      -
    20. -
    21. -

      - How do I test private methods? -

      -

      - Testing private methods may be an indication that those methods - should be moved into another class to promote reusability. -

      -

      - But if you must... -

      -

      - You can use reflection to subvert the access control mechanism. - If you are using JDK 1.3 or higher you can use the PrivilegedAccessor - class. Examples of how to use this class are available in PrivilegedAccessorTest. -

      -
    22. -
    23. -

      - Why does JUnit only report the first - failure in a single test? -

      -

      - (Submitted by: J. B. Rainsberger) -

      -

      - Reporting multiple failures in a single test is generally a sign - that the test does too much, compared to what a unit test ought - to do. Usually this means either that the test is really a - functional/acceptance/customer test or, if it is a unit test, - then it is too big a unit test. -

      -

      - JUnit is designed to work best with a number of small tests. It - executes each test within a separate instance of the test - class. It reports failure on each test. Shared setup code is - most natural when sharing between tests. This is a design - decision that permeates JUnit, and when you decide to report - multiple failures per test, you begin to fight against - JUnit. This is not recommended. -

      -

      - Long tests are a design smell and indicate the likelihood of a - design problem. Kent Beck is fond of saying in this case that - "there is an opportunity to learn something about your design." - We would like to see a pattern language develop around these - problems, but it has not yet been written down. -

      -

      - Finally, note that a single test with multiple assertions is - isomorphic to a test case with multiple tests: -

      -

      - One test method, three assertions: -

      -
      -
      
      -public class MyTestCase extends TestCase {
      -    public void testSomething() {
      -        // Set up for the test, manipulating local variables
      -        assertTrue(condition1);
      -        assertTrue(condition2);
      -        assertTrue(condition3);
      -    }
      -}
      -      
      -
      -

      - Three test methods, one assertion each: -

      -
      -
      
      -public class MyTestCase extends TestCase {
      -    // Locale variables become instance variables
      -
      -    protected void setUp() {
      -        // Set up for the test, manipulating instance variables
      -    }
      -    
      -    public void testCondition1() {
      -        assertTrue(condition1);
      -    }
      -
      -    public void testCondition2() {
      -        assertTrue(condition2);
      -    }
      -
      -    public void testCondition3() {
      -        assertTrue(condition3);
      -    }
      -}
      -      
      -
      -

      - The resulting tests use JUnit's natural execution and reporting - mechanism and, failure in one test does not affect the execution - of the other tests. You generally want exactly one test to fail - for any given bug, if you can manage it. -

      -
    24. -
    25. -

      - In Java 1.4, 'assert' is a - keyword. Won't this conflict - with JUnit's assert() method? -

      -

      - (Submitted by: David Stagner) -

      -

      - JUnit 3.7 deprecated assert() and replaced it - with assertTrue(), which works exactly the same - way. -

      -

      - Simply upgrade your JUnit to version 3.7 or higher and change - all assert() calls in your existing tests - to assertTrue(). -

      -
    26. -
    27. -

      - How do I test things that must be run - in a J2EE container (e.g. servlets, EJBs)? -

      -

      - Refactoring J2EE components to delegate functionality to other - objects that don't have to be run in a J2EE container will - improve the design and testability of the software. -

      -

      - Cactus - is an open source JUnit extension that can be used to test J2EE - components in their natural environment. -

      -
    28. -
    29. -

      - Do I need to write - a TestCase class for every class I need to - test? -

      -

      - (Submitted by: J. B. Rainsberger) -

      -

      - No. It is a convention to start with one TestCase - class per class under test, but it is not necessary. -

      -

      - TestCase classes only provide a way to organize - tests, nothing more. Generally you will start with - one TestCase class per class under test, but then - you may find that a small group of tests belong together with - their own common test fixture.[1] In this case, you may move - those tests to a new TestCase object. This is a - simple object-oriented refactoring: separating responsibilities - of an object that does too much. -

      -

      - Another point to consider is that the TestSuite is - the smallest execution unit in JUnit: you cannot execute - anything smaller than a TestSuite at one time without changing - source code. In this case, you probably do not want to put tests - in the same TestCase class unless they somehow - "belong together". If you have two groups of tests that you - think you'd like to execute separately from one another, it is - wise to place them in separate TestCase classes. -

      -

      - - [1] A test fixture is a common set of test data and - collaborating objects shared by many tests. Generally they are - implemented as instance variables in the TestCase - class. - -

      -
    30. -
    31. -

      - Is there a basic template I can use to - create a test? -

      -

      - (Submitted by: Eric Armstrong) -

      -

      - The following templates are a good starting point. Copy/paste - and edit these templates to suit your coding style. -

      -

      - SampleTest is a basic test template: -

      -
      -
      
      -import junit.framework.TestCase;
      -
      -public class SampleTest extends TestCase {
      -
      -    private java.util.List emptyList;
      -
      -    /**
      -     * Sets up the test fixture. 
      -     * (Called before every test case method.)
      -     */
      -    protected void setUp() {
      -        emptyList = new java.util.ArrayList();
      -    }
      -
      -    /**
      -     * Tears down the test fixture. 
      -     * (Called after every test case method.)
      -     */
      -    protected void tearDown() {
      -        emptyList = null;
      -    }
      -    
      -    public void testSomeBehavior() {
      -        assertEquals("Empty list should have 0 elements", 0, emptyList.size());
      -    }
      -
      -    public void testForException() {
      -
      -        try {
      -
      -            Object o = emptyList.get(0);
      -
      -            fail("Should raise an IndexOutOfBoundsException");
      -
      -        } catch (IndexOutOfBoundsException success) {
      -        }
      -    }
      -
      -    public static void main(String args[]) {
      -        junit.textui.TestRunner.run(SampleTest.class);
      -    }
      -}
      -      
      -
      -

      - SampleTestSuite is a template for a suite of tests: -

      -
      -
      
      -import junit.framework.Test;
      -import junit.framework.TestSuite;
      -
      -public class SampleTestSuite {
      -
      -    public static Test suite() {
      -
      -        TestSuite suite = new TestSuite("Sample Tests");
      -        
      -        //
      -        // Add one entry for each test class
      -        // or test suite.
      -        //
      -        suite.addTestSuite(SampleTest.class);
      -        
      -        //
      -        // For a master test suite, use this pattern.
      -        // (Note that here, it's recursive!)
      -        //
      -        suite.addTest(AnotherTestSuite.suite());
      -
      -        return suite;
      -    }
      -
      -    public static void main(String args[]) {
      -        junit.textui.TestRunner.run(suite());
      -    }
      -}
      -      
      -
      -
    32. -
    33. -

      - How do I write a test for an abstract - class? -

      -

      - Refer to http://c2.com/cgi/wiki?AbstractTestCases. -

      -
    34. -
    35. -

      - When are tests garbage collected? -

      -

      - (Submitted by: Timothy Wall and Kent Beck) -

      -

      - By design, the tree of Test instances is built in one pass, then - the tests are executed in a second pass. The test runner holds - strong references to all Test instances for the duration of the - test execution. This means that for a very long test run with - many Test instances, none of the tests may be garbage collected - until the end of the entire test run. -

      -

      - Therefore, if you allocate external or limited resources in a - test, you are responsible for freeing those resources. - Explicitly setting an object to null in - the tearDown() method, for example, allows it to be - garbage collected before the end of the entire test run. -

      -
    36. -
    - - - - -
      -
    1. -

      - Where should I put my test files? -

      -

      - You can place your tests in the same package and directory as - the classes under test. -

      -

      - For example: -

      -
      -
      -src
      -   com
      -      xyz
      -         SomeClass.java
      -         SomeClassTest.java	 
      -      
      -
      -

      - While adequate for small projects, many developers feel that - this approach clutters the source directory, and makes it hard - to package up client deliverables without also including - unwanted test code, or writing unnecessarily complex packaging - tasks. -

      -

      - An arguably better way is to place the tests in a separate - parallel directory structure with package alignment. -

      -

      - For example: -

      -
      -
      -src
      -   com
      -      xyz
      -         SomeClass.java
      -test
      -   com
      -      xyz
      -         SomeClassTest.java	 
      -      
      -
      -

      - These approaches allow the tests to access to all the public and - package visible methods of the classes under test. -

      -

      - Some developers have argued in favor of putting the tests in a - sub-package of the classes under test (e.g. com.xyz.test). The - author of this FAQ sees no clear advantage to adopting this - approach and believes that said developers also put their curly - braces on the wrong line. :-) -

      -
    2. -
    3. -

      - How do I write a test suite for all - of my tests? -

      -

      - Write a suite() method that creates - a TestSuite containing all your tests. -

      -

      - For example: -

      -
      -
      
      -
      -    import junit.framework.*;
      -
      -    public class AllTests {
      -
      -        public static Test suite() {
      -
      -            TestSuite suite = new TestSuite();
      -
      -            suite.addTest(SomeTest.suite());
      -            suite.addTest(AnotherTest.suite());
      -		
      -            return suite;
      -        }
      -
      -        public static void main(String[] args) {
      -            junit.textui.TestRunner.run(suite());
      -        }
      -    }
      -      
      -
      -

      - Running AllTests will automatically run all of its - contained tests in one fell swoop. -

      -

      - You can arbitrarily group any tests into test suites as - appropriate by package, logical layers, test type, etc. -

      -
    4. -
    5. -

      - How can I run setUp() and tearDown() - code once for all of my tests? -

      -

      - The desire to do this is usually a symptom of excessive coupling - in your design. If two or more tests must share the same test - fixture state, then the tests may be trying to tell you that the - classes under test have some undesirable dependencies. -

      -

      - Refactoring the design to further decouple the classes under - test and eliminate code duplication is usually a better - investment than setting up a shared test fixture. -

      -

      - But if you must... -

      -

      - You can wrap the test suite containing all your tests in a - subclass of TestSetup which - invokes setUp() exactly once before all the tests - are run and invokes tearDown() exactly once after - all the tests have been run. -

      -

      - The following is an example suite() method that - uses a TestSetup for one-time initialization and - cleanup: -

      -
      -
      
      -
      -    import junit.framework.*;
      -    import junit.extensions.TestSetup;
      -
      -    public class AllTestsOneTimeSetup {
      -
      -        public static Test suite() {
      -  
      -            TestSuite suite = new TestSuite();
      -
      -            suite.addTest(SomeTest.suite());
      -            suite.addTest(AnotherTest.suite());
      -
      -            TestSetup wrapper = new TestSetup(suite) {
      -
      -                protected void setUp() {
      -                    oneTimeSetUp();
      -                }
      -
      -                protected void tearDown() {
      -                    oneTimeTearDown();
      -                }
      -            };
      -
      -            return wrapper;
      -        }
      -
      -        public static void oneTimeSetUp() {
      -            // one-time initialization code
      -        }
      -
      -        public static void oneTimeTearDown() {
      -            // one-time cleanup code
      -        } 
      -    }
      -      
      -
      -
    6. -
    - - - - -
      -
    1. -

      - What CLASSPATH settings are needed to - run JUnit? -

      -

      - (Submitted by: Eric Armstrong) -

      -

      - To run your JUnit tests, you'll need the following elemements in - your CLASSPATH: -

      -
        -
      • JUnit class files
      • -
      • Your class files, including your JUnit test classes
      • -
      • Libraries your class files depend on
      • -
      -

      - If attempting to run your tests results in - a NoClassDefFoundError, then something is missing - from your CLASSPATH. -

      -

      - Windows Example: -

      -

      - set - CLASSPATH=%JUNIT_HOME%\junit.jar;c:\myproject\classes;c:\myproject\lib\something.jar -

      -

      - Unix (bash) Example: -

      -

      - export CLASSPATH=$JUNIT_HOME/junit.jar:/myproject/classes:/myproject/lib/something.jar -

      -
    2. -
    3. -

      - Why do I get - a NoClassDefFoundError when trying to test JUnit - or run the samples? -

      -

      - (Submitted by: J.B. Rainsberger and Jason Rogers) -

      -

      - Most likely your CLASSPATH doesn't include the JUnit - installation directory. -

      -

      - Refer to "What CLASSPATH settings are - needed to run JUnit?" for more guidance. -

      -

      - Also consider running WhichJunit - to print the absolute location of the JUnit class files required - to run and test JUnit and its samples. -

      -

      - If the CLASSPATH seems mysterious, read this! -

      -
    4. -
    5. -

      - How do I run the JUnit GUI test runner? -

      -

      - (Submitted by: Eric Armstrong) -

      -
        -
      1. -

        - Set your CLASSPATH -

        -
      2. -
      3. -

        - Invoke the runner: -

        -

        - - java junit.swingui.TestRunner <test class name> - -

        -
      4. -
      -
    6. -
    7. -

      - How do I run JUnit from my command window? -

      -

      - (Submitted by: Eric Armstrong) -

      -
        -
      1. -

        - Set your CLASSPATH -

        -
      2. -
      3. -

        - Invoke the runner: -

        -

        - - java junit.textui.TestRunner <test class name> - -

        -
      4. -
      -
    8. -
    9. -

      - How do I run JUnit using Ant? -

      -

      - (Submitted by: Eric Armstrong) -

      -
        -
      1. -

        - Define any necessary Ant properties: -

        -
        -
        
        -<property name="src" value="./src" />
        -<property name="lib" value="./lib" />
        -<property name="classes" value="./classes" />
        -<property name="test.class.name" value="com.xyz.MyTestSuite" />
        -	  
        -
        -
      2. -
      3. -

        - Set up the CLASSPATH to be used by JUnit: -

        -
        -
        
        -<path id="test.classpath">
        -  <pathelement location="${classes}" />
        -  <pathelement location="/path/to/junit.jar" />
        -  <fileset dir="${lib}">
        -    <include name="**/*.jar"/>
        -  </fileset>
        -</path>
        -	  
        -
        -
      4. -
      5. -

        - Define the Ant task for running JUnit: -

        -
        -
        
        -<target name="test">
        -  <junit fork="yes" haltonfailure="yes">
        -    <test name="${test.class.name}" />
        -    <formatter type="plain" usefile="false" />
        -    <classpath refid="test.classpath" />
        -  </junit>
        -</target>
        -	  
        -
        -
      6. -
      7. -

        - Run the test: -

        -
        - - ant test - -
        -
      8. -
      -

      - Refer to the JUnit - Ant Task for more information. -

      -
    10. -
    11. -

      - How do I use Ant to create HTML test - reports? -

      -

      - (Submitted by: Eric Armstrong and Steffen Gemkow) -

      -
        -
      1. -

        - Ensure that Ant's optional.jar file is either - in your CLASSPATH or exists in - your $ANT_HOME/lib directory. -

        -
      2. -
      3. -

        - Add an ANT property for the directory containing the HTML reports: -

        -
        - -<property name="test.reports" value="./reports" /> - -
        -
      4. -
      5. -

        - Define the Ant task for running JUnit and generating reports: -

        -
        -
        
        -<target name="test-html">
        -  <junit fork="yes" printsummary="no" haltonfailure="no">
        -    <batchtest fork="yes" todir="${test.reports}" >
        -      <fileset dir="${classes}">
        -        <include name="**/*Test.class" />
        -      </fileset>
        -    </batchtest>
        -    <formatter type="xml" />
        -    <classpath refid="test.classpath" />
        -  </junit>
        -
        -  <junitreport todir="${test.reports}">
        -    <fileset dir="${test.reports}">
        -      <include name="TEST-*.xml" />
        -    </fileset>
        -    <report todir="${test.reports}" />
        -  </junitreport>
        -</target>
        -	  
        -
        -
      6. -
      7. -

        - Run the test: -

        -
        - - ant test-html - -
        -
      8. -
      -

      - Refer to the - JUnit Ant Task - for more information. -

      -
    12. -
    13. -

      - How do I pass command-line arguments - to a test execution? -

      -

      - Use the -D JVM command-line options, as in: -

      -
      -
      --DparameterName=parameterValue -
      -
      -

      - If the number of parameters on the command line gets unweildy, - pass in the location of a property file that defines a set of - parameters. Alternatively, the JUnit-addons package - contains the XMLPropertyManager - and PropertyManager classes that allow you to define a - property file (or XML file) containing test parameters. -

      -
    14. -
    15. -

      - Why do I get an error - (ClassCastException or - LinkageError) using the GUI TestRunners? -

      -

      - (Submitted by: Scott Stirling) -

      -

      - JUnit's GUI TestRunners use a custom class loader - (junit.runner.TestCaseClassLoader) to dynamically - reload your code every time you press the "Run" button - so you don't have to restart the GUI to reload your classes if - you recompile them. The default classloaders of the Java Virtual - Machine do not dynamically reload changed classes. But - JUnit's custom class loader finds and loads classes from the - same CLASSPATH used by the JVM's system classloader. So, by - design, it "sits in front of" the system loader and - applies a filter to determine whether it should load a given - class or delegate the loading of a class to the system - classloader. This filter is configured with a list of String - patterns in a properties file - called excluded.properties. -

      -

      - The excluded.properties file contains a numbered - list - (excluded.0, excluded.1, excluded.2, - etc.) of properties whose values are patterns for packages. This - file is packaged in junit.jar - as junit/runner/excluded.properties. As of JUnit - 3.7 and Java 1.4, its contents are: -

      -
      -
      -#
      -# The list of excluded package paths for the TestCaseClassLoader
      -#
      -excluded.0=sun.*
      -excluded.1=com.sun.*
      -excluded.2=org.omg.*
      -excluded.3=javax.*
      -excluded.4=sunw.*
      -excluded.5=java.*
      -      
      -
      -

      - There are some conditions, discussed below, where the default - exclusions are insufficient and you will want to add some more - to this list and then either update the junit.jar - file with your customized version or place your customized - version in the CLASSPATH before junit.jar. -

      -
    16. -
    17. -

      - Why do I get - a LinkageError when using - XML interfaces in my TestCase? -

      -

      - (Submitted by: Scott Stirling) -

      -

      - The workaround as of JUnit 3.7 is to - add org.w3c.dom.* and org.xml.sax.* to - your excluded.properties. -

      -

      - It's just a matter of time before this fix becomes incorporated - into the released version of - JUnit's excluded.properties, since JAXP is a - standard part of JDK 1.4. It will be just like - excluding org.omg.*. By the way, if you download - the JUnit source from its Sourceforge CVS, you will find that - these patterns have already been added to the default - excluded.properties and so has a pattern for JINI. In fact, here - is the current version in CVS, which demonstrates how to add - exclusions to the list too: -

      -
      -
      -#
      -# The list of excluded package paths for the TestCaseClassLoader
      -#
      -excluded.0=sun.*
      -excluded.1=com.sun.*
      -excluded.2=org.omg.*
      -excluded.3=javax.*
      -excluded.4=sunw.*
      -excluded.5=java.*
      -excluded.6=org.w3c.dom.*
      -excluded.7=org.xml.sax.*
      -excluded.8=net.jini.*
      -      
      -
      -

      - This is the most common case where the - default excluded.properties list needs - modification. The cause of the LinkageError is - related to using JAXP in your test cases. By JAXP I mean the - whole set of javax.xml.* classes and the - supporting org.w3c.dom.* - and org.xml.sax.* classes. -

      -

      - As stated above, the JUnit GUI TestRunners' classloader relies - on the excluded.properties for classes it should - delegate to the system classloader. JAXP is an unusual case - because it is a standard Java extension library dependent on - classes whose package names (org.w3c.dom.* - and org.xml.sax.*) do not begin with a standard - Java or Sun prefix. This is similar to the relationship - between javax.rmi.* and the org.omg.* - classes, which have been excluded by default in - JUnit'ss excluded.properties for a while. -

      -

      - What can happen, and frequently does when using the JUnit Swing - or AWT UI with test cases that reference, use or depend on JAXP - classes, such as Log4J, Apache SOAP, Axis, Cocoon, etc., is that - the JUnit class loader (properly) - delegates javax.xml.* classes it "sees" - to the system loader. But then the system loader, in the process - of initializing and loading that JAXP class, links and loads up - a bunch of org.w3c.dom/org.xml.sax - classes. When it does so, the JUnit custom classloader is not - involved at all because the system classloader never delegates - "down" or checks with custom classloaders to see if a - class is already loaded. At any point after this, if the JUnit - loader is asked to load - an org.w3c.dom/org.xml.sax class that - it's never seen before, it will try to load it because the - class' name doesn't match any of the patterns in the default - exclude list. That's when a LinkageError - occurs. This is really a flaw in the JUnit classloader design, - but there is the workaround given above. -

      -

      - Java 2 JVMs keep classes (remember, classes and objects, though - related, are different entities to the JVM - I'm talking - about classes here, not object instances) in namespaces, - identifying them by their fully qualified classname plus the - instance of their defining (not initiating) loader. The JVM will - attempt to assign all unloaded classes referenced by an already - defined and loaded class to that class's defining loader. The - JVM's classresolver routine (implemented as a C function in the - JVM source code) keeps track of all these class loading events - and "sees" if another classloader (such as the JUnit - custom loader) attempts to define a class that has already been - defined by the system loader. According to the rules of Java 2 - loader constraints, in case a class has already been defined by - the system loader, any attempts to load a class should first be - delegated to the system loader. A "proper" way for - JUnit to handle this feature would be to load classes from a - repository other than the CLASSPATH that the system classloader - knows nothing about. And then the JUnit custom classloader could - follow the standard Java 2 delegation model, which is to always - delegate class loading to the system loader, and only attempt to - load if that fails. Since they both load from the CLASSPATH in - the current model, if the JUnit loader delegated like it's - supposed to, it would never get to load any classes since the - system loader would always find them. -

      -

      - You could try to hack around this in the JUnit source by - catching the LinkageError in - TestCaseClassLoader's loadClass() method and then - making a recovery call to findSystemClass() -- - thereby delegating to the system loader after the violation has - been caught. But this hack only works some of the time, because - now you can have the reverse problem where the JUnit loader will - load a host of org.w3c.dom/org.xml.sax - classes, and then the system loader violates the loader - contraints at some point when it tries to do exactly what I - described above with JAXP because it doesn't ever delegate to - its logical child (the JUnit loader). Inevitably, if your test - cases use many JAXP and related XML classes, one or the other - classloader will end up violating the constraints whatever you - do. -

      -
    18. -
    19. -

      - Why do I get - a ClassCastException when - I use narrow() in an EJB client TestCase? -

      -

      - (Submitted by: Scott Stirling) -

      -

      - The solution is to prevent your EJB's interface classes from - being loaded by the JUnit custom class loader by adding them - to excluded.properties. -

      -

      - This is another problem inherent to JUnit's dynamically - reloading TestCaseClassLoader. Similar to the LinkageErrors - with JAXP and the org.xml.sax - and org.w3c.dom classes, but with a different - result. -

      -

      - Here's some example code: -

      -
      -
      -Point point;
      -PointHome pointHome;
      -
      -// The next line works in textui, but throws
      -// ClassCastException in swingui
      -
      -pointHome = (PointHome)PortableRemoteObject.
      -    narrow(ctx.lookup("base/PointHome"), PointHome.class);
      -      
      -
      -

      - When you call InitialContext.lookup(), it returns - an object that was loaded and defined by the JVM's system - classloader (sun.misc.Launcher$AppClassLoader), but - the PointEJBHome.class type is loaded by JUnit's - TestCaseClassLoader. In the narrow(), the two fully - qualified class names are the same, but the defining - classloaders for the two are different so you get the exception - during the narrow because the JVM doesn't see them as being the - same runtime class type. -

      -

      - Recall that in Java 2 an object's class (a.k.a. "runtime type") - is identified in the JVM as the pair of - <fully-qualified-classname;definingClassLoaderInstance> or - (in shorter form) <C;L>. That is, the defining loader's - identity is part of the runtime name identifying that class in - the JVM. Also recall that the JVM will expect a class's defining - loader to load all unloaded classes referenced by the classes it - loads. -

      -

      - If interested for debugging purposes, you can find out more - about which loader loaded which class by doing something like - this: -

      -
      -
      -System.out.println(ctx.lookup("base/PointEJBHome").getClass().getClassLoader());
      -System.out.println(PointEJBHome.class.getClassLoader());
      -      
      -
      -

      - You'll find when using the GUI TestRunners that - the PointEJBHome type is defined by the JUnit - TestCaseClassLoader and the object returned - from InitialContext.lookup() was defined through - the JVM's system class loader. When using the tex-based - TestRunner they'll both have been loaded through the system - loader. -

      -

      - If you use Ant's <batchtest> task to run your test cases - and you have this problem, you can work around it by - setting fork="true" - on <batchtest>, which causes it to run each - test in its own Java Virtual Machine separate from Ant's - launching JVM. -

      -

      - For further reading about the principles of Java dynamic - classloading, the best resource is the short paper by Sheng - Liang, the architect of the Java 2 classloader architecture: Dynamic Class Loading - in the Java Virtual Machine, OOPSLA 1998. -

      -
    20. -
    21. -

      - Why do I get the warning - "AssertionFailedError: No - tests found in XXX" when I run my test? -

      -

      - Make sure the test contains one or more methods with names - beginning with "test". -

      -

      - For example: -

      -
      -
      -public void testSomething() {
      -}
      -      
      -
      -

      - This error also commonly occurs when using - the addTestSuite() in an attempt to create a - hiearchy of test suites. For more information, see "How do I get one test suite to invoke - another?". -

      -
    22. -
    23. -

      - Why do I see "Unknown Source" in the - stack trace of -a test failure, rather than the source file's line number? -

      -

      - The debug option for the Java compiler must be enabled in order - to see source file and line number information in a stack trace. -

      -

      - When invoking the Java compiler from the command line, use - the -g option to generate all debugging info. -

      -

      - When invoking the Java compiler from an - Ant task, use the - debug="on" attribute. For example: -

      -
      -
      -<javac srcdir="${src}" destdir="${build}" debug="on" /> -
      -
      -

      - When using older JVMs pre-Hotspot (JDK 1.1 and most/all 1.2), - run JUnit with the -DJAVA_COMPILER=none JMV command - line argument to prevent runtime JIT compilation from obscuring - line number info. -

      -

      - Compiling the test source with debug enabled will show the line - where the assertion failed. Compiling the non-test source with - debug enabled will show the line where an exception was raised - in the class under test. -

      -
    24. -
    25. -

      - Why does the "excluded.properties" - trick not work when running JUnit's GUI from inside my - favorite IDE? -

      -

      - (Submitted by: William Pietri) -

      -

      - Some IDEs come with a copy of JUnit, so your copy of JUnit in - the project classpath isn't the one being used. Replace - the junit.jar file used by the IDE with - a junit.jar file containing a - custom excluded.properties and your bar will once - again be green. -

      -
    26. -
    27. -

      - How do I get one test suite to - invoke another? -

      -

      - (Submitted by: Eric Armstrong) -

      -

      - To add a suite to a suite, use: -

      -
      -
      -suite.addTest(someOtherSuite.suite()); -
      -
      -
    28. -
    29. -

      - How do I organize all test classes - in a TestSuite automatically and not use or manage a TestSuite - explicitly? -

      -

      - (Submitted by: Bill de hora) -

      -

      - There are a number of ways to do this: -

      -
        -
      1. -

        - In Ant, use the junit task and - the batchtest element: -

        -
        -
        
        -<junit printsummary="yes" haltonfailure="yes">
        -  ...
        -  <batchtest fork="yes">
        -    <fileset dir="${src.dir}">
        -       <include name="**/*Test.java" />
        -       <include name="**/Test*.java" />
        -    </fileset>
        -  </batchtest>
        -</junit> 
        -	  
        -
        -

        - Idiomatic naming patterns for unit tests - are Test*.java and *Test.java. - Documentation and examples are at http://ant.apache.org/manual/OptionalTasks/junit.html. -

        -
      2. -
      3. -

        - Use the DirectorySuiteBuilder - and ArchiveSuiteBuilder (for jar/zip files) - classes provided by JUnit-addons project: -

        -
        -
        -DirectorySuiteBuilder builder = new DirectorySuiteBuilder();
        -builder.setSuffix("Test");
        -Test suite = builer.suite("/home/project/myproject/tests"); 
        -	  
        -
        -

        - Documentation and examples are at http://junit-addons.sourceforge.net. -

        -
      4. -
      5. -

        - Write your own custom suite builder. -

        -

        - Have your test classes implement an interface and write a - treewalker to load each class in a directory, inspect the - class, and add any classes that implement the interface to a - TestSuite. -

        -

        - You might only want to do this if you are very - uncomfortable with using a naming convention for test - classes. Aside from being slow for larger suites, ultimately - it's arguable whether it's more effort to follow a naming - convention that have test classes implement an interface! -

        -

        - An example of this approach is at - http://www.javaworld.com/javaworld/jw-12-2000/jw-1221-junit_p.html. -

        -
      6. -
      -
    30. -
    - - - -
      -
    1. -

      - When should tests be written? -

      -

      - Tests should be written before the code. Test-first programming - is practiced by only writing new code when an automated test is - failing. -

      -

      - Good tests tell you how to best design the system for its - intended use. They effectively communicate in an executable - format how to use the software. They also prevent tendencies to - over-build the system based on speculation. When all the tests - pass, you know you're done! -

      -

      - Whenever a customer test fails or a bug is reported, first write - the necessary unit test(s) to expose the bug(s), then - fix them. This makes it almost impossible for that particular - bug to resurface later. -

      -

      - Test-driven development is a lot more fun than writing tests - after the code seems to be working. Give it a try! -

      -
    2. -
    3. -

      - Do I have to write a test for - everything? -

      -

      - No, just test everything that could reasonably break. -

      -

      - Be practical and maximize your testing investment. Remember - that investments in testing are equal investments in design. If - defects aren't being reported and your design responds well to - change, then you're probably testing enough. If you're spending - a lot of time fixing defects and your design is difficult to - grow, you should write more tests. -

      -

      - If something is difficult to test, it's usually an opportunity - for a design improvement. Look to improve the design so that - it's easier to test, and by doing so a better design will - usually emerge. -

      -
    4. -
    5. -

      - How simple is 'too simple to break'? -

      -

      - (Submitted by: J. B. Rainsberger) -

      -

      - The general philosophy is this: if it can't break on its - own, it's too simple to break. -

      -

      - First example is the getX() method. Suppose - the getX() method only answers the value of an - instance variable. In that case, getX() cannot - break unless either the compiler or the interpreter is also - broken. For that reason, don't test getX(); there - is no benefit. The same is true of the setX() - method, although if your setX() method does any - parameter validation or has any side effects, you likely need to - test it. -

      -

      - Next example: suppose you have written a method that does - nothing but forward parameters into a method called on another - object. That method is too simple to break. -

      -
      -
      -public void myMethod(final int a, final String b) {
      -    myCollaborator.anotherMethod(a, b);
      -}
      -      
      -
      -

      - myMethod cannot possibly break because it does nothing: it - forwards its input to another object and that's all. -

      -

      - The only precondition for this method is "myCollaborator != - null", but that is generally the responsibility of the - constructor, and not of myMethod. If you are concerned, add a - test to verify that myCollaborator is always set to something - non-null by every constructor. -

      -

      - The only way myMethod could break would be - if myCollaborator.anotherMethod() were broken. In - that case, test myCollaborator, and not the current - class. -

      -

      - It is true that adding tests for even these simple methods - guards against the possibility that someone refactors and makes - the methods "not-so-simple" anymore. In that case, though, the - refactorer needs to be aware that the method is now complex - enough to break, and should write tests for it -- and preferably - before the refactoring. -

      -

      - Another example: suppose you have a JSP and, like a good - programmer, you have removed all business logic from it. All it - does is provide a layout for a number of JavaBeans and never - does anything that could change the value of any object. That - JSP is too simple to break, and since JSPs are notoriously - annoying to test, you should strive to make all your JSPs too - simple to break. -

      -

      - Here's the way testing goes: -

      -
      -
      -becomeTimidAndTestEverything
      -while writingTheSameThingOverAndOverAgain
      -    becomeMoreAggressive
      -    writeFewerTests
      -    writeTestsForMoreInterestingCases
      -    if getBurnedByStupidDefect
      -        feelStupid
      -        becomeTimidAndTestEverything
      -    end
      -end
      -      
      -
      -

      - The loop, as you can see, never terminates. -

      -
    6. -
    7. -

      - How often should I run my tests? -

      -

      - Run all your unit tests as often as possible, ideally every time - the code is changed. Make sure all your unit tests always run - at 100%. Frequent testing gives you confidence that your - changes didn't break anything and generally lowers the stress of - programming in the dark. -

      -

      - For larger systems, you may just run specific test suites that - are relevant to the code you're working on. -

      -

      - Run all your acceptance, integration, stress, and unit tests at - least once per day (or night). -

      -
    8. -
    9. -

      - What do I do when a defect is reported? -

      -

      - Test-driven development generally lowers the defect density of - software. But we're all fallible, so sometimes a defect will - slip through. When this happens, write a failing test that - exposes the defect. When the test passes, you know the defect - is fixed! -

      -

      - Don't forget to use this as a learning opportunity. Perhaps the - defect could have been prevented by being more aggressive about - testing everything that could reasonably break. -

      -
    10. -
    11. -

      - Why not just use System.out.println()? -

      -

      - Inserting debug statements into code is a low-tech method for - debugging it. It usually requires that output be scanned - manually every time the program is run to ensure that the code - is doing what's expected. -

      -

      - It generally takes less time in the long run to codify - expectations in the form of an automated JUnit test that retains - its value over time. If it's difficult to write a test to - assert expectations, the tests may be telling you that shorter - and more cohesive methods would improve your design. -

      -
    12. -
    13. -

      - Why not just use a debugger? -

      -

      - Debuggers are commonly used to step through code and inspect - that the variables along the way contain the expected values. - But stepping through a program in a debugger is a manual process - that requires tedious visual inspections. In essence, the - debugging session is nothing more than a manual check of - expected vs. actual results. Moreover, every time the program - changes we must manually step back through the program in the - debugger to ensure that nothing broke. -

      -

      - It generally takes less time to codify expectations in the form - of an automated JUnit test that retains its value over time. If - it's difficult to write a test to assert expected values, the - tests may be telling you that shorter and more cohesive methods - would improve your design. -

      -
    14. -
    - - - - -
      -
    1. -

      - How do I extend JUnit? -

      -

      - JUnit is a testing framework intended to be customized for - specialized use. Browsing the JUnit source code is an excellent - way to learn its design and discover how it can be extended. -

      -

      - Examples of JUnit extensions can be found in - the junit.extensions package: -

      -
        -
      • - TestDecorator -

        - A decorator for Tests. You can use it as the base class for - implementing new test decorators that add behavior before or - after a test is run. -

        -
      • -
      • - ActiveTestSuite -

        - A TestSuite that runs each test in a separate - thread and waits until all threads have terminated. -

        -
      • -
      • - TestSetup -

        - A TestDecorator to initialize and cleanup - test fixture state once before the test is run. -

        -
      • -
      • - RepeatedTest -

        - A TestDecorator that runs a test repeatedly. -

        -
      • -
      • - ExceptionTestCase -

        - A TestCase that expects a - particular Exception to be thrown. -

        -

        - Kent Beck has mentioned that ExceptionTestCase - likely does not provide enough to be useful; it is just as - easy to write the "exception test" yourself. Refer to the "Writing Tests" section for guidance. -

        -
      • -
      -
    2. -
    3. -

      - What kinds of extensions are available? -

      -

      - The JUnit home page has a complete list of available JUnit - extensions. -

      -
    4. -
    - - - - -
      -
    1. -

      - How do I integrate JUnit with my IDE? -

      -

      - The JUnit home page maintains a list of IDE integration - instructions. -

      -
    2. -
    3. -

      - How do I launch a debugger when a test fails? -

      -

      - Start the TestRunner under the debugger and - configure the debugger so that it catches - the junit.framework.AssertionFailedError. -

      -

      - How you configure this depends on the debugger you prefer to - use. Most Java debuggers provide support to stop the program - when a specific exception is raised. -

      -

      - Notice that this will only launch the debugger when an expected - failure occurs. -

      -
    4. -
    5. -

      - Where can I find unit testing frameworks - similar to JUnit for other languages? -

      -

      - XProgramming.com maintains a complete list of available xUnit testing - frameworks. -

      -
    6. -
    - -
    - -
    - - Valid XHTML 1.0! -
    - - - diff --git a/doc/markdown.sh b/doc/markdown.sh new file mode 100644 index 000000000000..e235b638aa37 --- /dev/null +++ b/doc/markdown.sh @@ -0,0 +1 @@ +~/bin/Markdown.pl ReleaseNotes4.8.txt >ReleaseNotes4.8.html \ No newline at end of file diff --git a/doc/testinfected/testing.htm b/doc/testinfected/testing.htm index 1b484bf27f4a..c5721e752b8d 100644 --- a/doc/testinfected/testing.htm +++ b/doc/testinfected/testing.htm @@ -10,6 +10,7 @@

    JUnit Test Infected: Programmers Love Writing Tests

    +
    Note: this article describes JUnit 3.8.x.

    Testing is not closely integrated with development. This prevents you @@ -180,14 +181,14 @@

    result report. The value a string representation created by the toString converter method. There are -other asertXXXX variants not discussed here. +other assertXXXX variants not discussed here.

    Now that we have implemented two test cases we notice some code duplication for setting-up the tests. It would be nice to reuse some of this test set-up code. In other words, we would like to have a common fixture for running the tests. With JUnit you can do so by storing the fixture's objects in instance variables of your TestCase -subclass and initialize them by overridding +subclass and initialize them by overriding the setUp method. The symmetric operation to setUp is tearDown which you can override to clean up the test fixture at the end of a test. Each test runs in its own fixture and JUnit calls setUp and tearDown for each test @@ -434,7 +435,7 @@

    public IMoney addMoneyBag(MoneyBag s) {     return s.addMoney(this); } -Here is the implemenation in MoneyBag which assumes additional constructors +Here is the implementation in MoneyBag which assumes additional constructors to create a MoneyBag from a Money and a MoneyBag and from two MoneyBags.
    public IMoney addMoney(Money m) {
         return new MoneyBag(m, this);
    @@ -452,7 +453,7 @@ 

    public void testSimplify() {
         // {[12 CHF][7 USD]} + [-12 CHF] == [7 USD]
         Money expected= new Money(7, "USD");
    -    Assert.assertEquals(expected, fMS1.add(new Money(-12, "CHF")));
    +    Assert.assertEquals(expected, fMB1.add(new Money(-12, "CHF")));
     }
    When you are developing in this style you will often have a thought and turn immediately to writing a test, rather than going straight to the code. diff --git a/epl-v10.html b/epl-v10.html new file mode 100644 index 000000000000..3998fcebeebe --- /dev/null +++ b/epl-v10.html @@ -0,0 +1,261 @@ + + + + + + +Eclipse Public License - Version 1.0 + + + + + + +

    Eclipse Public License - v 1.0

    + +

    THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE +PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR +DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS +AGREEMENT.

    + +

    1. DEFINITIONS

    + +

    "Contribution" means:

    + +

    a) in the case of the initial Contributor, the initial +code and documentation distributed under this Agreement, and

    +

    b) in the case of each subsequent Contributor:

    +

    i) changes to the Program, and

    +

    ii) additions to the Program;

    +

    where such changes and/or additions to the Program +originate from and are distributed by that particular Contributor. A +Contribution 'originates' from a Contributor if it was added to the +Program by such Contributor itself or anyone acting on such +Contributor's behalf. Contributions do not include additions to the +Program which: (i) are separate modules of software distributed in +conjunction with the Program under their own license agreement, and (ii) +are not derivative works of the Program.

    + +

    "Contributor" means any person or entity that distributes +the Program.

    + +

    "Licensed Patents" mean patent claims licensable by a +Contributor which are necessarily infringed by the use or sale of its +Contribution alone or when combined with the Program.

    + +

    "Program" means the Contributions distributed in accordance +with this Agreement.

    + +

    "Recipient" means anyone who receives the Program under +this Agreement, including all Contributors.

    + +

    2. GRANT OF RIGHTS

    + +

    a) Subject to the terms of this Agreement, each +Contributor hereby grants Recipient a non-exclusive, worldwide, +royalty-free copyright license to reproduce, prepare derivative works +of, publicly display, publicly perform, distribute and sublicense the +Contribution of such Contributor, if any, and such derivative works, in +source code and object code form.

    + +

    b) Subject to the terms of this Agreement, each +Contributor hereby grants Recipient a non-exclusive, worldwide, +royalty-free patent license under Licensed Patents to make, use, sell, +offer to sell, import and otherwise transfer the Contribution of such +Contributor, if any, in source code and object code form. This patent +license shall apply to the combination of the Contribution and the +Program if, at the time the Contribution is added by the Contributor, +such addition of the Contribution causes such combination to be covered +by the Licensed Patents. The patent license shall not apply to any other +combinations which include the Contribution. No hardware per se is +licensed hereunder.

    + +

    c) Recipient understands that although each Contributor +grants the licenses to its Contributions set forth herein, no assurances +are provided by any Contributor that the Program does not infringe the +patent or other intellectual property rights of any other entity. Each +Contributor disclaims any liability to Recipient for claims brought by +any other entity based on infringement of intellectual property rights +or otherwise. As a condition to exercising the rights and licenses +granted hereunder, each Recipient hereby assumes sole responsibility to +secure any other intellectual property rights needed, if any. For +example, if a third party patent license is required to allow Recipient +to distribute the Program, it is Recipient's responsibility to acquire +that license before distributing the Program.

    + +

    d) Each Contributor represents that to its knowledge it +has sufficient copyright rights in its Contribution, if any, to grant +the copyright license set forth in this Agreement.

    + +

    3. REQUIREMENTS

    + +

    A Contributor may choose to distribute the Program in object code +form under its own license agreement, provided that:

    + +

    a) it complies with the terms and conditions of this +Agreement; and

    + +

    b) its license agreement:

    + +

    i) effectively disclaims on behalf of all Contributors +all warranties and conditions, express and implied, including warranties +or conditions of title and non-infringement, and implied warranties or +conditions of merchantability and fitness for a particular purpose;

    + +

    ii) effectively excludes on behalf of all Contributors +all liability for damages, including direct, indirect, special, +incidental and consequential damages, such as lost profits;

    + +

    iii) states that any provisions which differ from this +Agreement are offered by that Contributor alone and not by any other +party; and

    + +

    iv) states that source code for the Program is available +from such Contributor, and informs licensees how to obtain it in a +reasonable manner on or through a medium customarily used for software +exchange.

    + +

    When the Program is made available in source code form:

    + +

    a) it must be made available under this Agreement; and

    + +

    b) a copy of this Agreement must be included with each +copy of the Program.

    + +

    Contributors may not remove or alter any copyright notices contained +within the Program.

    + +

    Each Contributor must identify itself as the originator of its +Contribution, if any, in a manner that reasonably allows subsequent +Recipients to identify the originator of the Contribution.

    + +

    4. COMMERCIAL DISTRIBUTION

    + +

    Commercial distributors of software may accept certain +responsibilities with respect to end users, business partners and the +like. While this license is intended to facilitate the commercial use of +the Program, the Contributor who includes the Program in a commercial +product offering should do so in a manner which does not create +potential liability for other Contributors. Therefore, if a Contributor +includes the Program in a commercial product offering, such Contributor +("Commercial Contributor") hereby agrees to defend and +indemnify every other Contributor ("Indemnified Contributor") +against any losses, damages and costs (collectively "Losses") +arising from claims, lawsuits and other legal actions brought by a third +party against the Indemnified Contributor to the extent caused by the +acts or omissions of such Commercial Contributor in connection with its +distribution of the Program in a commercial product offering. The +obligations in this section do not apply to any claims or Losses +relating to any actual or alleged intellectual property infringement. In +order to qualify, an Indemnified Contributor must: a) promptly notify +the Commercial Contributor in writing of such claim, and b) allow the +Commercial Contributor to control, and cooperate with the Commercial +Contributor in, the defense and any related settlement negotiations. The +Indemnified Contributor may participate in any such claim at its own +expense.

    + +

    For example, a Contributor might include the Program in a commercial +product offering, Product X. That Contributor is then a Commercial +Contributor. If that Commercial Contributor then makes performance +claims, or offers warranties related to Product X, those performance +claims and warranties are such Commercial Contributor's responsibility +alone. Under this section, the Commercial Contributor would have to +defend claims against the other Contributors related to those +performance claims and warranties, and if a court requires any other +Contributor to pay any damages as a result, the Commercial Contributor +must pay those damages.

    + +

    5. NO WARRANTY

    + +

    EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS +PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS +OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, +ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY +OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely +responsible for determining the appropriateness of using and +distributing the Program and assumes all risks associated with its +exercise of rights under this Agreement , including but not limited to +the risks and costs of program errors, compliance with applicable laws, +damage to or loss of data, programs or equipment, and unavailability or +interruption of operations.

    + +

    6. DISCLAIMER OF LIABILITY

    + +

    EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT +NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING +WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR +DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED +HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.

    + +

    7. GENERAL

    + +

    If any provision of this Agreement is invalid or unenforceable under +applicable law, it shall not affect the validity or enforceability of +the remainder of the terms of this Agreement, and without further action +by the parties hereto, such provision shall be reformed to the minimum +extent necessary to make such provision valid and enforceable.

    + +

    If Recipient institutes patent litigation against any entity +(including a cross-claim or counterclaim in a lawsuit) alleging that the +Program itself (excluding combinations of the Program with other +software or hardware) infringes such Recipient's patent(s), then such +Recipient's rights granted under Section 2(b) shall terminate as of the +date such litigation is filed.

    + +

    All Recipient's rights under this Agreement shall terminate if it +fails to comply with any of the material terms or conditions of this +Agreement and does not cure such failure in a reasonable period of time +after becoming aware of such noncompliance. If all Recipient's rights +under this Agreement terminate, Recipient agrees to cease use and +distribution of the Program as soon as reasonably practicable. However, +Recipient's obligations under this Agreement and any licenses granted by +Recipient relating to the Program shall continue and survive.

    + +

    Everyone is permitted to copy and distribute copies of this +Agreement, but in order to avoid inconsistency the Agreement is +copyrighted and may only be modified in the following manner. The +Agreement Steward reserves the right to publish new versions (including +revisions) of this Agreement from time to time. No one other than the +Agreement Steward has the right to modify this Agreement. The Eclipse +Foundation is the initial Agreement Steward. The Eclipse Foundation may +assign the responsibility to serve as the Agreement Steward to a +suitable separate entity. Each new version of the Agreement will be +given a distinguishing version number. The Program (including +Contributions) may always be distributed subject to the version of the +Agreement under which it was received. In addition, after a new version +of the Agreement is published, Contributor may elect to distribute the +Program (including its Contributions) under the new version. Except as +expressly stated in Sections 2(a) and 2(b) above, Recipient receives no +rights or licenses to the intellectual property of any Contributor under +this Agreement, whether expressly, by implication, estoppel or +otherwise. All rights in the Program not expressly granted under this +Agreement are reserved.

    + +

    This Agreement is governed by the laws of the State of New York and +the intellectual property laws of the United States of America. No party +to this Agreement will bring a legal action under this Agreement more +than one year after the cause of action arose. Each party waives its +rights to a jury trial in any resulting litigation.

    + + + + \ No newline at end of file diff --git a/junit/awtui/AboutDialog.java b/junit/awtui/AboutDialog.java deleted file mode 100644 index 38f57bbda66c..000000000000 --- a/junit/awtui/AboutDialog.java +++ /dev/null @@ -1,77 +0,0 @@ -package junit.awtui; - -import java.awt.Button; -import java.awt.Dialog; -import java.awt.Font; -import java.awt.Frame; -import java.awt.GridBagConstraints; -import java.awt.GridBagLayout; -import java.awt.Insets; -import java.awt.Label; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.WindowAdapter; -import java.awt.event.WindowEvent; - -import junit.runner.Version; - -class AboutDialog extends Dialog { - public AboutDialog(Frame parent) { - super(parent); - - setResizable(false); - setLayout(new GridBagLayout()); - setSize(330, 138); - setTitle("About"); - - Button button= new Button("Close"); - button.addActionListener( - new ActionListener() { - public void actionPerformed(ActionEvent e) { - dispose(); - } - } - ); - - Label label1= new Label("JUnit"); - label1.setFont(new Font("dialog", Font.PLAIN, 36)); - - Label label2= new Label("JUnit "+Version.id()+ " by Kent Beck and Erich Gamma"); - label2.setFont(new Font("dialog", Font.PLAIN, 14)); - - Logo logo= new Logo(); - - GridBagConstraints constraintsLabel1= new GridBagConstraints(); - constraintsLabel1.gridx = 3; constraintsLabel1.gridy = 0; - constraintsLabel1.gridwidth = 1; constraintsLabel1.gridheight = 1; - constraintsLabel1.anchor = GridBagConstraints.CENTER; - add(label1, constraintsLabel1); - - GridBagConstraints constraintsLabel2= new GridBagConstraints(); - constraintsLabel2.gridx = 2; constraintsLabel2.gridy = 1; - constraintsLabel2.gridwidth = 2; constraintsLabel2.gridheight = 1; - constraintsLabel2.anchor = GridBagConstraints.CENTER; - add(label2, constraintsLabel2); - - GridBagConstraints constraintsButton1= new GridBagConstraints(); - constraintsButton1.gridx = 2; constraintsButton1.gridy = 2; - constraintsButton1.gridwidth = 2; constraintsButton1.gridheight = 1; - constraintsButton1.anchor = GridBagConstraints.CENTER; - constraintsButton1.insets= new Insets(8, 0, 8, 0); - add(button, constraintsButton1); - - GridBagConstraints constraintsLogo1= new GridBagConstraints(); - constraintsLogo1.gridx = 2; constraintsLogo1.gridy = 0; - constraintsLogo1.gridwidth = 1; constraintsLogo1.gridheight = 1; - constraintsLogo1.anchor = GridBagConstraints.CENTER; - add(logo, constraintsLogo1); - - addWindowListener( - new WindowAdapter() { - public void windowClosing(WindowEvent e) { - dispose(); - } - } - ); - } -} \ No newline at end of file diff --git a/junit/awtui/Logo.java b/junit/awtui/Logo.java deleted file mode 100644 index 4cc3b4ff7552..000000000000 --- a/junit/awtui/Logo.java +++ /dev/null @@ -1,58 +0,0 @@ -package junit.awtui; - -import java.awt.Canvas; -import java.awt.Graphics; -import java.awt.Image; -import java.awt.MediaTracker; -import java.awt.SystemColor; -import java.awt.Toolkit; -import java.awt.image.ImageProducer; -import java.net.URL; - -import junit.runner.BaseTestRunner; - -public class Logo extends Canvas { - private Image fImage; - private int fWidth; - private int fHeight; - - public Logo() { - fImage= loadImage("logo.gif"); - MediaTracker tracker= new MediaTracker(this); - tracker.addImage(fImage, 0); - try { - tracker.waitForAll(); - } catch (Exception e) { - } - - if (fImage != null) { - fWidth= fImage.getWidth(this); - fHeight= fImage.getHeight(this); - } else { - fWidth= 20; - fHeight= 20; - } - setSize(fWidth, fHeight); - } - - public Image loadImage(String name) { - Toolkit toolkit= Toolkit.getDefaultToolkit(); - try { - URL url= BaseTestRunner.class.getResource(name); - return toolkit.createImage((ImageProducer) url.getContent()); - } catch (Exception ex) { - } - return null; - } - - public void paint(Graphics g) { - paintBackground(g); - if (fImage != null) - g.drawImage(fImage, 0, 0, fWidth, fHeight, this); - } - - public void paintBackground( java.awt.Graphics g) { - g.setColor(SystemColor.control); - g.fillRect(0, 0, getBounds().width, getBounds().height); - } -} \ No newline at end of file diff --git a/junit/awtui/ProgressBar.java b/junit/awtui/ProgressBar.java deleted file mode 100644 index 03e7ec22c6d0..000000000000 --- a/junit/awtui/ProgressBar.java +++ /dev/null @@ -1,88 +0,0 @@ -package junit.awtui; - -import java.awt.Canvas; -import java.awt.Color; -import java.awt.Graphics; -import java.awt.Rectangle; -import java.awt.SystemColor; - -public class ProgressBar extends Canvas { - public boolean fError= false; - public int fTotal= 0; - public int fProgress= 0; - public int fProgressX= 0; - - public ProgressBar() { - super(); - setSize(20, 30); - } - - private Color getStatusColor() { - if (fError) - return Color.red; - return Color.green; - } - - public void paint(Graphics g) { - paintBackground(g); - paintStatus(g); - } - - public void paintBackground(Graphics g) { - g.setColor(SystemColor.control); - Rectangle r= getBounds(); - g.fillRect(0, 0, r.width, r.height); - g.setColor(Color.darkGray); - g.drawLine(0, 0, r.width-1, 0); - g.drawLine(0, 0, 0, r.height-1); - g.setColor(Color.white); - g.drawLine(r.width-1, 0, r.width-1, r.height-1); - g.drawLine(0, r.height-1, r.width-1, r.height-1); - } - - public void paintStatus(Graphics g) { - g.setColor(getStatusColor()); - Rectangle r= new Rectangle(0, 0, fProgressX, getBounds().height); - g.fillRect(1, 1, r.width-1, r.height-2); - } - - private void paintStep(int startX, int endX) { - repaint(startX, 1, endX-startX, getBounds().height-2); - } - - public void reset() { - fProgressX= 1; - fProgress= 0; - fError= false; - paint(getGraphics()); - } - - public int scale(int value) { - if (fTotal > 0) - return Math.max(1, value*(getBounds().width-1)/fTotal); - return value; - } - - public void setBounds(int x, int y, int w, int h) { - super.setBounds(x, y, w, h); - fProgressX= scale(fProgress); - } - - public void start(int total) { - fTotal= total; - reset(); - } - - public void step(boolean successful) { - fProgress++; - int x= fProgressX; - - fProgressX= scale(fProgress); - - if (!fError && !successful) { - fError= true; - x= 1; - } - paintStep(x, fProgressX); - } -} \ No newline at end of file diff --git a/junit/awtui/TestRunner.java b/junit/awtui/TestRunner.java deleted file mode 100644 index cb735d59f737..000000000000 --- a/junit/awtui/TestRunner.java +++ /dev/null @@ -1,571 +0,0 @@ -package junit.awtui; - -import java.awt.BorderLayout; -import java.awt.Button; -import java.awt.Checkbox; -import java.awt.Color; -import java.awt.Component; -import java.awt.Font; -import java.awt.Frame; -import java.awt.GridBagConstraints; -import java.awt.GridBagLayout; -import java.awt.GridLayout; -import java.awt.Image; -import java.awt.Insets; -import java.awt.Label; -import java.awt.List; -import java.awt.Menu; -import java.awt.MenuBar; -import java.awt.MenuItem; -import java.awt.Panel; -import java.awt.SystemColor; -import java.awt.TextArea; -import java.awt.TextField; -import java.awt.Toolkit; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.ItemEvent; -import java.awt.event.ItemListener; -import java.awt.event.TextEvent; -import java.awt.event.TextListener; -import java.awt.event.WindowAdapter; -import java.awt.event.WindowEvent; -import java.awt.image.ImageProducer; -import java.util.Vector; - -import junit.framework.Test; -import junit.framework.TestCase; -import junit.framework.TestResult; -import junit.framework.TestSuite; -import junit.runner.BaseTestRunner; -import junit.runner.TestRunListener; - -/** - * An AWT based user interface to run tests. - * Enter the name of a class which either provides a static - * suite method or is a subclass of TestCase. - *
    - * Synopsis: java junit.awtui.TestRunner [-noloading] [TestCase]
    - * 
    - * TestRunner takes as an optional argument the name of the testcase class to be run. - */ - public class TestRunner extends BaseTestRunner { - protected Frame fFrame; - protected Vector fExceptions; - protected Vector fFailedTests; - protected Thread fRunner; - protected TestResult fTestResult; - - protected TextArea fTraceArea; - protected TextField fSuiteField; - protected Button fRun; - protected ProgressBar fProgressIndicator; - protected List fFailureList; - protected Logo fLogo; - protected Label fNumberOfErrors; - protected Label fNumberOfFailures; - protected Label fNumberOfRuns; - protected Button fQuitButton; - protected Button fRerunButton; - protected TextField fStatusLine; - protected Checkbox fUseLoadingRunner; - - protected static final Font PLAIN_FONT= new Font("dialog", Font.PLAIN, 12); - private static final int GAP= 4; - - public TestRunner() { - } - - private void about() { - AboutDialog about= new AboutDialog(fFrame); - about.setModal(true); - about.setLocation(300, 300); - about.setVisible(true); - } - - public void testStarted(String testName) { - showInfo("Running: "+testName); - } - - public void testEnded(String testName) { - setLabelValue(fNumberOfRuns, fTestResult.runCount()); - synchronized(this) { - fProgressIndicator.step(fTestResult.wasSuccessful()); - } - } - - public void testFailed(int status, Test test, Throwable t) { - switch (status) { - case TestRunListener.STATUS_ERROR: - fNumberOfErrors.setText(Integer.toString(fTestResult.errorCount())); - appendFailure("Error", test, t); - break; - case TestRunListener.STATUS_FAILURE: - fNumberOfFailures.setText(Integer.toString(fTestResult.failureCount())); - appendFailure("Failure", test, t); - break; - } - } - - protected void addGrid(Panel p, Component co, int x, int y, int w, int fill, double wx, int anchor) { - GridBagConstraints c= new GridBagConstraints(); - c.gridx= x; c.gridy= y; - c.gridwidth= w; - c.anchor= anchor; - c.weightx= wx; - c.fill= fill; - if (fill == GridBagConstraints.BOTH || fill == GridBagConstraints.VERTICAL) - c.weighty= 1.0; - c.insets= new Insets(y == 0 ? GAP : 0, x == 0 ? GAP : 0, GAP, GAP); - p.add(co, c); - } - - private void appendFailure(String kind, Test test, Throwable t) { - kind+= ": " + test; - String msg= t.getMessage(); - if (msg != null) { - kind+= ":" + truncate(msg); - } - fFailureList.add(kind); - fExceptions.addElement(t); - fFailedTests.addElement(test); - if (fFailureList.getItemCount() == 1) { - fFailureList.select(0); - failureSelected(); - } - } - /** - * Creates the JUnit menu. Clients override this - * method to add additional menu items. - */ - protected Menu createJUnitMenu() { - Menu menu= new Menu("JUnit"); - MenuItem mi= new MenuItem("About..."); - mi.addActionListener( - new ActionListener() { - public void actionPerformed(ActionEvent event) { - about(); - } - } - ); - menu.add(mi); - - menu.addSeparator(); - mi= new MenuItem("Exit"); - mi.addActionListener( - new ActionListener() { - public void actionPerformed(ActionEvent event) { - System.exit(0); - } - } - ); - menu.add(mi); - return menu; - } - - protected void createMenus(MenuBar mb) { - mb.add(createJUnitMenu()); - } - protected TestResult createTestResult() { - return new TestResult(); - } - - protected Frame createUI(String suiteName) { - Frame frame= new Frame("JUnit"); - Image icon= loadFrameIcon(); - if (icon != null) - frame.setIconImage(icon); - - frame.setLayout(new BorderLayout(0, 0)); - frame.setBackground(SystemColor.control); - final Frame finalFrame= frame; - - frame.addWindowListener( - new WindowAdapter() { - public void windowClosing(WindowEvent e) { - finalFrame.dispose(); - System.exit(0); - } - } - ); - - MenuBar mb = new MenuBar(); - createMenus(mb); - frame.setMenuBar(mb); - - //---- first section - Label suiteLabel= new Label("Test class name:"); - - fSuiteField= new TextField(suiteName != null ? suiteName : ""); - fSuiteField.selectAll(); - fSuiteField.requestFocus(); - fSuiteField.setFont(PLAIN_FONT); - fSuiteField.setColumns(40); - fSuiteField.addActionListener( - new ActionListener() { - public void actionPerformed(ActionEvent e) { - runSuite(); - } - } - ); - fSuiteField.addTextListener( - new TextListener() { - public void textValueChanged(TextEvent e) { - fRun.setEnabled(fSuiteField.getText().length() > 0); - fStatusLine.setText(""); - } - } - ); - fRun= new Button("Run"); - fRun.setEnabled(false); - fRun.addActionListener( - new ActionListener() { - public void actionPerformed(ActionEvent e) { - runSuite(); - } - } - ); - boolean useLoader= useReloadingTestSuiteLoader(); - fUseLoadingRunner= new Checkbox("Reload classes every run", useLoader); - if (inVAJava()) - fUseLoadingRunner.setVisible(false); - - //---- second section - fProgressIndicator= new ProgressBar(); - - //---- third section - fNumberOfErrors= new Label("0000", Label.RIGHT); - fNumberOfErrors.setText("0"); - fNumberOfErrors.setFont(PLAIN_FONT); - - fNumberOfFailures= new Label("0000", Label.RIGHT); - fNumberOfFailures.setText("0"); - fNumberOfFailures.setFont(PLAIN_FONT); - - fNumberOfRuns= new Label("0000", Label.RIGHT); - fNumberOfRuns.setText("0"); - fNumberOfRuns.setFont(PLAIN_FONT); - - Panel numbersPanel= createCounterPanel(); - - //---- fourth section - Label failureLabel= new Label("Errors and Failures:"); - - fFailureList= new List(5); - fFailureList.addItemListener( - new ItemListener() { - public void itemStateChanged(ItemEvent e) { - failureSelected(); - } - } - ); - fRerunButton= new Button("Run"); - fRerunButton.setEnabled(false); - fRerunButton.addActionListener( - new ActionListener() { - public void actionPerformed(ActionEvent e) { - rerun(); - } - } - ); - - Panel failedPanel= new Panel(new GridLayout(0, 1, 0, 2)); - failedPanel.add(fRerunButton); - - fTraceArea= new TextArea(); - fTraceArea.setRows(5); - fTraceArea.setColumns(60); - - //---- fifth section - fStatusLine= new TextField(); - fStatusLine.setFont(PLAIN_FONT); - fStatusLine.setEditable(false); - fStatusLine.setForeground(Color.red); - - fQuitButton= new Button("Exit"); - fQuitButton.addActionListener( - new ActionListener() { - public void actionPerformed(ActionEvent e) { - System.exit(0); - } - } - ); - - // --------- - fLogo= new Logo(); - - //---- overall layout - Panel panel= new Panel(new GridBagLayout()); - - addGrid(panel, suiteLabel, 0, 0, 2, GridBagConstraints.HORIZONTAL, 1.0, GridBagConstraints.WEST); - - addGrid(panel, fSuiteField, 0, 1, 2, GridBagConstraints.HORIZONTAL, 1.0, GridBagConstraints.WEST); - addGrid(panel, fRun, 2, 1, 1, GridBagConstraints.HORIZONTAL, 0.0, GridBagConstraints.CENTER); - addGrid(panel, fUseLoadingRunner, 0, 2, 2, GridBagConstraints.NONE, 1.0, GridBagConstraints.WEST); - addGrid(panel, fProgressIndicator, 0, 3, 2, GridBagConstraints.HORIZONTAL, 1.0, GridBagConstraints.WEST); - addGrid(panel, fLogo, 2, 3, 1, GridBagConstraints.NONE, 0.0, GridBagConstraints.NORTH); - - addGrid(panel, numbersPanel, 0, 4, 2, GridBagConstraints.NONE, 0.0, GridBagConstraints.WEST); - - addGrid(panel, failureLabel, 0, 5, 2, GridBagConstraints.HORIZONTAL, 1.0, GridBagConstraints.WEST); - addGrid(panel, fFailureList, 0, 6, 2, GridBagConstraints.BOTH, 1.0, GridBagConstraints.WEST); - addGrid(panel, failedPanel, 2, 6, 1, GridBagConstraints.HORIZONTAL, 0.0, GridBagConstraints.CENTER); - addGrid(panel, fTraceArea, 0, 7, 2, GridBagConstraints.BOTH, 1.0, GridBagConstraints.WEST); - - addGrid(panel, fStatusLine, 0, 8, 2, GridBagConstraints.HORIZONTAL, 1.0, GridBagConstraints.CENTER); - addGrid(panel, fQuitButton, 2, 8, 1, GridBagConstraints.HORIZONTAL, 0.0, GridBagConstraints.CENTER); - - frame.add(panel, BorderLayout.CENTER); - frame.pack(); - return frame; - } - - protected Panel createCounterPanel() { - Panel numbersPanel= new Panel(new GridBagLayout()); - addToCounterPanel( - numbersPanel, - new Label("Runs:"), - 0, 0, 1, 1, 0.0, 0.0, - GridBagConstraints.CENTER, GridBagConstraints.NONE, - new Insets(0, 0, 0, 0) - ); - addToCounterPanel( - numbersPanel, - fNumberOfRuns, - 1, 0, 1, 1, 0.33, 0.0, - GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, - new Insets(0, 8, 0, 40) - ); - addToCounterPanel( - numbersPanel, - new Label("Errors:"), - 2, 0, 1, 1, 0.0, 0.0, - GridBagConstraints.CENTER, GridBagConstraints.NONE, - new Insets(0, 8, 0, 0) - ); - addToCounterPanel( - numbersPanel, - fNumberOfErrors, - 3, 0, 1, 1, 0.33, 0.0, - GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, - new Insets(0, 8, 0, 40) - ); - addToCounterPanel( - numbersPanel, - new Label("Failures:"), - 4, 0, 1, 1, 0.0, 0.0, - GridBagConstraints.CENTER, GridBagConstraints.NONE, - new Insets(0, 8, 0, 0) - ); - addToCounterPanel( - numbersPanel, - fNumberOfFailures, - 5, 0, 1, 1, 0.33, 0.0, - GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, - new Insets(0, 8, 0, 0) - ); - return numbersPanel; - } - - private void addToCounterPanel(Panel counter, Component comp, - int gridx, int gridy, int gridwidth, int gridheight, - double weightx, double weighty, - int anchor, int fill, - Insets insets) { - - GridBagConstraints constraints= new GridBagConstraints(); - constraints.gridx= gridx; - constraints.gridy= gridy; - constraints.gridwidth= gridwidth; - constraints.gridheight= gridheight; - constraints.weightx= weightx; - constraints.weighty= weighty; - constraints.anchor= anchor; - constraints.fill= fill; - constraints.insets= insets; - counter.add(comp, constraints); - } - - - public void failureSelected() { - fRerunButton.setEnabled(isErrorSelected()); - showErrorTrace(); - } - - private boolean isErrorSelected() { - return fFailureList.getSelectedIndex() != -1; - } - - private Image loadFrameIcon() { - Toolkit toolkit= Toolkit.getDefaultToolkit(); - try { - java.net.URL url= BaseTestRunner.class.getResource("smalllogo.gif"); - return toolkit.createImage((ImageProducer) url.getContent()); - } catch (Exception ex) { - } - return null; - } - - public Thread getRunner() { - return fRunner; - } - - public static void main(String[] args) { - new TestRunner().start(args); - } - - public static void run(Class test) { - String args[]= { test.getName() }; - main(args); - } - - public void rerun() { - int index= fFailureList.getSelectedIndex(); - if (index == -1) - return; - - Test test= (Test)fFailedTests.elementAt(index); - rerunTest(test); - } - - private void rerunTest(Test test) { - if (!(test instanceof TestCase)) { - showInfo("Could not reload "+ test.toString()); - return; - } - Test reloadedTest= null; - TestCase rerunTest= (TestCase)test; - try { - Class reloadedTestClass= getLoader().reload(test.getClass()); - reloadedTest= TestSuite.createTest(reloadedTestClass, rerunTest.getName()); - } catch(Exception e) { - showInfo("Could not reload "+ test.toString()); - return; - } - TestResult result= new TestResult(); - reloadedTest.run(result); - - String message= reloadedTest.toString(); - if(result.wasSuccessful()) - showInfo(message+" was successful"); - else if (result.errorCount() == 1) - showStatus(message+" had an error"); - else - showStatus(message+" had a failure"); - } - - protected void reset() { - setLabelValue(fNumberOfErrors, 0); - setLabelValue(fNumberOfFailures, 0); - setLabelValue(fNumberOfRuns, 0); - fProgressIndicator.reset(); - fRerunButton.setEnabled(false); - fFailureList.removeAll(); - fExceptions= new Vector(10); - fFailedTests= new Vector(10); - fTraceArea.setText(""); - - } - - protected void runFailed(String message) { - showStatus(message); - fRun.setLabel("Run"); - fRunner= null; - } - - synchronized public void runSuite() { - if (fRunner != null && fTestResult != null) { - fTestResult.stop(); - } else { - setLoading(shouldReload()); - fRun.setLabel("Stop"); - showInfo("Initializing..."); - reset(); - - showInfo("Load Test Case..."); - - final Test testSuite= getTest(fSuiteField.getText()); - if (testSuite != null) { - fRunner= new Thread() { - public void run() { - fTestResult= createTestResult(); - fTestResult.addListener(TestRunner.this); - fProgressIndicator.start(testSuite.countTestCases()); - showInfo("Running..."); - - long startTime= System.currentTimeMillis(); - testSuite.run(fTestResult); - - if (fTestResult.shouldStop()) { - showStatus("Stopped"); - } else { - long endTime= System.currentTimeMillis(); - long runTime= endTime-startTime; - showInfo("Finished: " + elapsedTimeAsString(runTime) + " seconds"); - } - fTestResult= null; - fRun.setLabel("Run"); - fRunner= null; - System.gc(); - } - }; - fRunner.start(); - } - } - } - - private boolean shouldReload() { - return !inVAJava() && fUseLoadingRunner.getState(); - } - - private void setLabelValue(Label label, int value) { - label.setText(Integer.toString(value)); - label.invalidate(); - label.getParent().validate(); - - } - - public void setSuiteName(String suite) { - fSuiteField.setText(suite); - } - - private void showErrorTrace() { - int index= fFailureList.getSelectedIndex(); - if (index == -1) - return; - - Throwable t= (Throwable) fExceptions.elementAt(index); - fTraceArea.setText(getFilteredTrace(t)); - } - - - private void showInfo(String message) { - fStatusLine.setFont(PLAIN_FONT); - fStatusLine.setForeground(Color.black); - fStatusLine.setText(message); - } - - protected void clearStatus() { - showStatus(""); - } - - private void showStatus(String status) { - fStatusLine.setFont(PLAIN_FONT); - fStatusLine.setForeground(Color.red); - fStatusLine.setText(status); - } - /** - * Starts the TestRunner - */ - public void start(String[] args) { - String suiteName= processArguments(args); - fFrame= createUI(suiteName); - fFrame.setLocation(200, 200); - fFrame.setVisible(true); - - if (suiteName != null) { - setSuiteName(suiteName); - runSuite(); - } - } -} \ No newline at end of file diff --git a/junit/extensions/ActiveTestSuite.java b/junit/extensions/ActiveTestSuite.java deleted file mode 100644 index 9fc4eddb8bba..000000000000 --- a/junit/extensions/ActiveTestSuite.java +++ /dev/null @@ -1,66 +0,0 @@ -package junit.extensions; - -import junit.framework.Test; -import junit.framework.TestResult; -import junit.framework.TestSuite; - -/** - * A TestSuite for active Tests. It runs each - * test in a separate thread and waits until all - * threads have terminated. - * -- Aarhus Radisson Scandinavian Center 11th floor - */ -public class ActiveTestSuite extends TestSuite { - private volatile int fActiveTestDeathCount; - - public ActiveTestSuite() { - } - - public ActiveTestSuite(Class theClass) { - super(theClass); - } - - public ActiveTestSuite(String name) { - super (name); - } - - public ActiveTestSuite(Class theClass, String name) { - super(theClass, name); - } - - public void run(TestResult result) { - fActiveTestDeathCount= 0; - super.run(result); - waitUntilFinished(); - } - - public void runTest(final Test test, final TestResult result) { - Thread t= new Thread() { - public void run() { - try { - // inlined due to limitation in VA/Java - //ActiveTestSuite.super.runTest(test, result); - test.run(result); - } finally { - ActiveTestSuite.this.runFinished(); - } - } - }; - t.start(); - } - - synchronized void waitUntilFinished() { - while (fActiveTestDeathCount < testCount()) { - try { - wait(); - } catch (InterruptedException e) { - return; // ignore - } - } - } - - synchronized public void runFinished() { - fActiveTestDeathCount++; - notifyAll(); - } -} \ No newline at end of file diff --git a/junit/extensions/ExceptionTestCase.java b/junit/extensions/ExceptionTestCase.java deleted file mode 100644 index 70040856088c..000000000000 --- a/junit/extensions/ExceptionTestCase.java +++ /dev/null @@ -1,46 +0,0 @@ -package junit.extensions; - -import junit.framework.TestCase; - -/** - * A TestCase that expects an Exception of class fExpected to be thrown. - * The other way to check that an expected exception is thrown is: - *
    - * try {
    - *   shouldThrow();
    - * }
    - * catch (SpecialException e) {
    - *   return;
    - * }
    - * fail("Expected SpecialException");
    - * 
    - * - * To use ExceptionTestCase, create a TestCase like: - *
    - * new ExceptionTestCase("testShouldThrow", SpecialException.class);
    - * 
    - */ -public class ExceptionTestCase extends TestCase { - Class fExpected; - - public ExceptionTestCase(String name, Class exception) { - super(name); - fExpected= exception; - } - /** - * Execute the test method expecting that an Exception of - * class fExpected or one of its subclasses will be thrown - */ - protected void runTest() throws Throwable { - try { - super.runTest(); - } - catch (Exception e) { - if (fExpected.isAssignableFrom(e.getClass())) - return; - else - throw e; - } - fail("Expected exception " + fExpected); - } -} \ No newline at end of file diff --git a/junit/extensions/RepeatedTest.java b/junit/extensions/RepeatedTest.java deleted file mode 100644 index be5c4395a59c..000000000000 --- a/junit/extensions/RepeatedTest.java +++ /dev/null @@ -1,32 +0,0 @@ -package junit.extensions; - -import junit.framework.Test; -import junit.framework.TestResult; - -/** - * A Decorator that runs a test repeatedly. - * - */ -public class RepeatedTest extends TestDecorator { - private int fTimesRepeat; - - public RepeatedTest(Test test, int repeat) { - super(test); - if (repeat < 0) - throw new IllegalArgumentException("Repetition count must be > 0"); - fTimesRepeat= repeat; - } - public int countTestCases() { - return super.countTestCases()*fTimesRepeat; - } - public void run(TestResult result) { - for (int i= 0; i < fTimesRepeat; i++) { - if (result.shouldStop()) - break; - super.run(result); - } - } - public String toString() { - return super.toString()+"(repeated)"; - } -} \ No newline at end of file diff --git a/junit/extensions/TestDecorator.java b/junit/extensions/TestDecorator.java deleted file mode 100644 index 2111e8f5cb3c..000000000000 --- a/junit/extensions/TestDecorator.java +++ /dev/null @@ -1,40 +0,0 @@ -package junit.extensions; - -import junit.framework.Assert; -import junit.framework.Test; -import junit.framework.TestResult; - -/** - * A Decorator for Tests. Use TestDecorator as the base class - * for defining new test decorators. Test decorator subclasses - * can be introduced to add behaviour before or after a test - * is run. - * - */ -public class TestDecorator extends Assert implements Test { - protected Test fTest; - - public TestDecorator(Test test) { - fTest= test; - } - /** - * The basic run behaviour. - */ - public void basicRun(TestResult result) { - fTest.run(result); - } - public int countTestCases() { - return fTest.countTestCases(); - } - public void run(TestResult result) { - basicRun(result); - } - - public String toString() { - return fTest.toString(); - } - - public Test getTest() { - return fTest; - } -} \ No newline at end of file diff --git a/junit/extensions/TestSetup.java b/junit/extensions/TestSetup.java deleted file mode 100644 index 9ee8b057672d..000000000000 --- a/junit/extensions/TestSetup.java +++ /dev/null @@ -1,39 +0,0 @@ -package junit.extensions; - -import junit.framework.Protectable; -import junit.framework.Test; -import junit.framework.TestResult; - -/** - * A Decorator to set up and tear down additional fixture state. - * Subclass TestSetup and insert it into your tests when you want - * to set up additional state once before the tests are run. - */ -public class TestSetup extends TestDecorator { - - public TestSetup(Test test) { - super(test); - } - public void run(final TestResult result) { - Protectable p= new Protectable() { - public void protect() throws Exception { - setUp(); - basicRun(result); - tearDown(); - } - }; - result.runProtected(this, p); - } - /** - * Sets up the fixture. Override to set up additional fixture - * state. - */ - protected void setUp() throws Exception { - } - /** - * Tears down the fixture. Override to tear down the additional - * fixture state. - */ - protected void tearDown() throws Exception { - } -} \ No newline at end of file diff --git a/junit/framework/Assert.java b/junit/framework/Assert.java deleted file mode 100644 index ec6e8383ca44..000000000000 --- a/junit/framework/Assert.java +++ /dev/null @@ -1,289 +0,0 @@ -package junit.framework; - -/** - * A set of assert methods. Messages are only displayed when an assert fails. - */ - -public class Assert { - /** - * Protect constructor since it is a static only class - */ - protected Assert() { - } - - /** - * Asserts that a condition is true. If it isn't it throws - * an AssertionFailedError with the given message. - */ - static public void assertTrue(String message, boolean condition) { - if (!condition) - fail(message); - } - /** - * Asserts that a condition is true. If it isn't it throws - * an AssertionFailedError. - */ - static public void assertTrue(boolean condition) { - assertTrue(null, condition); - } - /** - * Asserts that a condition is false. If it isn't it throws - * an AssertionFailedError with the given message. - */ - static public void assertFalse(String message, boolean condition) { - assertTrue(message, !condition); - } - /** - * Asserts that a condition is false. If it isn't it throws - * an AssertionFailedError. - */ - static public void assertFalse(boolean condition) { - assertFalse(null, condition); - } - /** - * Fails a test with the given message. - */ - static public void fail(String message) { - throw new AssertionFailedError(message); - } - /** - * Fails a test with no message. - */ - static public void fail() { - fail(null); - } - /** - * Asserts that two objects are equal. If they are not - * an AssertionFailedError is thrown with the given message. - */ - static public void assertEquals(String message, Object expected, Object actual) { - if (expected == null && actual == null) - return; - if (expected != null && expected.equals(actual)) - return; - failNotEquals(message, expected, actual); - } - /** - * Asserts that two objects are equal. If they are not - * an AssertionFailedError is thrown. - */ - static public void assertEquals(Object expected, Object actual) { - assertEquals(null, expected, actual); - } - /** - * Asserts that two Strings are equal. - */ - static public void assertEquals(String message, String expected, String actual) { - if (expected == null && actual == null) - return; - if (expected != null && expected.equals(actual)) - return; - throw new ComparisonFailure(message, expected, actual); - } - /** - * Asserts that two Strings are equal. - */ - static public void assertEquals(String expected, String actual) { - assertEquals(null, expected, actual); - } - /** - * Asserts that two doubles are equal concerning a delta. If they are not - * an AssertionFailedError is thrown with the given message. If the expected - * value is infinity then the delta value is ignored. - */ - static public void assertEquals(String message, double expected, double actual, double delta) { - if (Double.compare(expected, actual) == 0) - return; - if (!(Math.abs(expected-actual) <= delta)) - failNotEquals(message, new Double(expected), new Double(actual)); - } - /** - * Asserts that two doubles are equal concerning a delta. If the expected - * value is infinity then the delta value is ignored. - */ - static public void assertEquals(double expected, double actual, double delta) { - assertEquals(null, expected, actual, delta); - } - /** - * Asserts that two floats are equal concerning a delta. If they are not - * an AssertionFailedError is thrown with the given message. If the expected - * value is infinity then the delta value is ignored. - */ - static public void assertEquals(String message, float expected, float actual, float delta) { - // handle infinity specially since subtracting to infinite values gives NaN and the - // the following test fails - if (Float.isInfinite(expected)) { - if (!(expected == actual)) - failNotEquals(message, new Float(expected), new Float(actual)); - } else if (!(Math.abs(expected-actual) <= delta)) - failNotEquals(message, new Float(expected), new Float(actual)); - } - /** - * Asserts that two floats are equal concerning a delta. If the expected - * value is infinity then the delta value is ignored. - */ - static public void assertEquals(float expected, float actual, float delta) { - assertEquals(null, expected, actual, delta); - } - /** - * Asserts that two longs are equal. If they are not - * an AssertionFailedError is thrown with the given message. - */ - static public void assertEquals(String message, long expected, long actual) { - assertEquals(message, new Long(expected), new Long(actual)); - } - /** - * Asserts that two longs are equal. - */ - static public void assertEquals(long expected, long actual) { - assertEquals(null, expected, actual); - } - /** - * Asserts that two booleans are equal. If they are not - * an AssertionFailedError is thrown with the given message. - */ - static public void assertEquals(String message, boolean expected, boolean actual) { - assertEquals(message, Boolean.valueOf(expected), Boolean.valueOf(actual)); - } - /** - * Asserts that two booleans are equal. - */ - static public void assertEquals(boolean expected, boolean actual) { - assertEquals(null, expected, actual); - } - /** - * Asserts that two bytes are equal. If they are not - * an AssertionFailedError is thrown with the given message. - */ - static public void assertEquals(String message, byte expected, byte actual) { - assertEquals(message, new Byte(expected), new Byte(actual)); - } - /** - * Asserts that two bytes are equal. - */ - static public void assertEquals(byte expected, byte actual) { - assertEquals(null, expected, actual); - } - /** - * Asserts that two chars are equal. If they are not - * an AssertionFailedError is thrown with the given message. - */ - static public void assertEquals(String message, char expected, char actual) { - assertEquals(message, new Character(expected), new Character(actual)); - } - /** - * Asserts that two chars are equal. - */ - static public void assertEquals(char expected, char actual) { - assertEquals(null, expected, actual); - } - /** - * Asserts that two shorts are equal. If they are not - * an AssertionFailedError is thrown with the given message. - */ - static public void assertEquals(String message, short expected, short actual) { - assertEquals(message, new Short(expected), new Short(actual)); - } - /** - * Asserts that two shorts are equal. - */ - static public void assertEquals(short expected, short actual) { - assertEquals(null, expected, actual); - } - /** - * Asserts that two ints are equal. If they are not - * an AssertionFailedError is thrown with the given message. - */ - static public void assertEquals(String message, int expected, int actual) { - assertEquals(message, new Integer(expected), new Integer(actual)); - } - /** - * Asserts that two ints are equal. - */ - static public void assertEquals(int expected, int actual) { - assertEquals(null, expected, actual); - } - /** - * Asserts that an object isn't null. - */ - static public void assertNotNull(Object object) { - assertNotNull(null, object); - } - /** - * Asserts that an object isn't null. If it is - * an AssertionFailedError is thrown with the given message. - */ - static public void assertNotNull(String message, Object object) { - assertTrue(message, object != null); - } - /** - * Asserts that an object is null. - */ - static public void assertNull(Object object) { - assertNull(null, object); - } - /** - * Asserts that an object is null. If it is not - * an AssertionFailedError is thrown with the given message. - */ - static public void assertNull(String message, Object object) { - assertTrue(message, object == null); - } - /** - * Asserts that two objects refer to the same object. If they are not - * an AssertionFailedError is thrown with the given message. - */ - static public void assertSame(String message, Object expected, Object actual) { - if (expected == actual) - return; - failNotSame(message, expected, actual); - } - /** - * Asserts that two objects refer to the same object. If they are not - * the same an AssertionFailedError is thrown. - */ - static public void assertSame(Object expected, Object actual) { - assertSame(null, expected, actual); - } - /** - * Asserts that two objects do not refer to the same object. If they do - * refer to the same object an AssertionFailedError is thrown with the - * given message. - */ - static public void assertNotSame(String message, Object expected, Object actual) { - if (expected == actual) - failSame(message); - } - /** - * Asserts that two objects do not refer to the same object. If they do - * refer to the same object an AssertionFailedError is thrown. - */ - static public void assertNotSame(Object expected, Object actual) { - assertNotSame(null, expected, actual); - } - - static public void failSame(String message) { - String formatted= ""; - if (message != null) - formatted= message+" "; - fail(formatted+"expected not same"); - } - - static public void failNotSame(String message, Object expected, Object actual) { - String formatted= ""; - if (message != null) - formatted= message+" "; - fail(formatted+"expected same:<"+expected+"> was not:<"+actual+">"); - } - - static public void failNotEquals(String message, Object expected, Object actual) { - fail(format(message, expected, actual)); - } - - static String format(String message, Object expected, Object actual) { - String formatted= ""; - if (message != null) - formatted= message+" "; - return formatted+"expected:<"+expected+"> but was:<"+actual+">"; - } -} diff --git a/junit/framework/AssertionFailedError.java b/junit/framework/AssertionFailedError.java deleted file mode 100644 index b041f062ee8f..000000000000 --- a/junit/framework/AssertionFailedError.java +++ /dev/null @@ -1,15 +0,0 @@ -package junit.framework; - -/** - * Thrown when an assertion failed. - */ -public class AssertionFailedError extends Error { - - private static final long serialVersionUID= 1L; - - public AssertionFailedError () { - } - public AssertionFailedError (String message) { - super (message); - } -} \ No newline at end of file diff --git a/junit/framework/ComparisonCompactor.java b/junit/framework/ComparisonCompactor.java deleted file mode 100644 index bbc3ba1cd451..000000000000 --- a/junit/framework/ComparisonCompactor.java +++ /dev/null @@ -1,72 +0,0 @@ -package junit.framework; - -public class ComparisonCompactor { - - private static final String ELLIPSIS= "..."; - private static final String DELTA_END= "]"; - private static final String DELTA_START= "["; - - private int fContextLength; - private String fExpected; - private String fActual; - private int fPrefix; - private int fSuffix; - - public ComparisonCompactor(int contextLength, String expected, String actual) { - fContextLength= contextLength; - fExpected= expected; - fActual= actual; - } - - public String compact(String message) { - if (fExpected == null || fActual == null || areStringsEqual()) - return Assert.format(message, fExpected, fActual); - - findCommonPrefix(); - findCommonSuffix(); - String expected= compactString(fExpected); - String actual= compactString(fActual); - return Assert.format(message, expected, actual); - } - - private String compactString(String source) { - String result= DELTA_START + source.substring(fPrefix, source.length() - fSuffix + 1) + DELTA_END; - if (fPrefix > 0) - result= computeCommonPrefix() + result; - if (fSuffix > 0) - result= result + computeCommonSuffix(); - return result; - } - - private void findCommonPrefix() { - fPrefix= 0; - int end= Math.min(fExpected.length(), fActual.length()); - for (; fPrefix < end; fPrefix++) { - if (fExpected.charAt(fPrefix) != fActual.charAt(fPrefix)) - break; - } - } - - private void findCommonSuffix() { - int expectedSuffix= fExpected.length() - 1; - int actualSuffix= fActual.length() - 1; - for (; actualSuffix >= fPrefix && expectedSuffix >= fPrefix; actualSuffix--, expectedSuffix--) { - if (fExpected.charAt(expectedSuffix) != fActual.charAt(actualSuffix)) - break; - } - fSuffix= fExpected.length() - expectedSuffix; - } - - private String computeCommonPrefix() { - return (fPrefix > fContextLength ? ELLIPSIS : "") + fExpected.substring(Math.max(0, fPrefix - fContextLength), fPrefix); - } - - private String computeCommonSuffix() { - int end= Math.min(fExpected.length() - fSuffix + 1 + fContextLength, fExpected.length()); - return fExpected.substring(fExpected.length() - fSuffix + 1, end) + (fExpected.length() - fSuffix + 1 < fExpected.length() - fContextLength ? ELLIPSIS : ""); - } - - private boolean areStringsEqual() { - return fExpected.equals(fActual); - } -} diff --git a/junit/framework/ComparisonFailure.java b/junit/framework/ComparisonFailure.java deleted file mode 100644 index c31068fa75e9..000000000000 --- a/junit/framework/ComparisonFailure.java +++ /dev/null @@ -1,51 +0,0 @@ -package junit.framework; - -/** - * Thrown when an assert equals for Strings failed. - * - * Inspired by a patch from Alex Chaffee mailto:alex@purpletech.com - */ -public class ComparisonFailure extends AssertionFailedError { - private static final int MAX_CONTEXT_LENGTH= 20; - private static final long serialVersionUID= 1L; - - private String fExpected; - private String fActual; - - /** - * Constructs a comparison failure. - * @param message the identifying message or null - * @param expected the expected string value - * @param actual the actual string value - */ - public ComparisonFailure (String message, String expected, String actual) { - super (message); - fExpected= expected; - fActual= actual; - } - - /** - * Returns "..." in place of common prefix and "..." in - * place of common suffix between expected and actual. - * - * @see java.lang.Throwable#getMessage() - */ - public String getMessage() { - return new ComparisonCompactor(MAX_CONTEXT_LENGTH, fExpected, fActual).compact(super.getMessage()); - } - - /** - * Gets the actual string value - * @return the actual string value - */ - public String getActual() { - return fActual; - } - /** - * Gets the expected string value - * @return the expected string value - */ - public String getExpected() { - return fExpected; - } -} \ No newline at end of file diff --git a/junit/framework/Test.java b/junit/framework/Test.java deleted file mode 100644 index a016ee8308f1..000000000000 --- a/junit/framework/Test.java +++ /dev/null @@ -1,17 +0,0 @@ -package junit.framework; - -/** - * A Test can be run and collect its results. - * - * @see TestResult - */ -public interface Test { - /** - * Counts the number of test cases that will be run by this test. - */ - public abstract int countTestCases(); - /** - * Runs a test and collects its result in a TestResult instance. - */ - public abstract void run(TestResult result); -} \ No newline at end of file diff --git a/junit/framework/TestCase.java b/junit/framework/TestCase.java deleted file mode 100644 index e54b16b91035..000000000000 --- a/junit/framework/TestCase.java +++ /dev/null @@ -1,207 +0,0 @@ -package junit.framework; - -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; - -/** - * A test case defines the fixture to run multiple tests. To define a test case
    - * 1) implement a subclass of TestCase
    - * 2) define instance variables that store the state of the fixture
    - * 3) initialize the fixture state by overriding setUp
    - * 4) clean-up after a test by overriding tearDown.
    - * Each test runs in its own fixture so there - * can be no side effects among test runs. - * Here is an example: - *
    - * public class MathTest extends TestCase {
    - *     protected double fValue1;
    - *     protected double fValue2;
    - *
    - *    protected void setUp() {
    - *         fValue1= 2.0;
    - *         fValue2= 3.0;
    - *     }
    - * }
    - * 
    - * - * For each test implement a method which interacts - * with the fixture. Verify the expected results with assertions specified - * by calling assertTrue with a boolean. - *
    - *    public void testAdd() {
    - *        double result= fValue1 + fValue2;
    - *        assertTrue(result == 5.0);
    - *    }
    - * 
    - * Once the methods are defined you can run them. The framework supports - * both a static type safe and more dynamic way to run a test. - * In the static way you override the runTest method and define the method to - * be invoked. A convenient way to do so is with an anonymous inner class. - *
    - * TestCase test= new MathTest("add") {
    - *        public void runTest() {
    - *            testAdd();
    - *        }
    - * };
    - * test.run();
    - * 
    - * The dynamic way uses reflection to implement runTest. It dynamically finds - * and invokes a method. - * In this case the name of the test case has to correspond to the test method - * to be run. - *
    - * TestCase test= new MathTest("testAdd");
    - * test.run();
    - * 
    - * The tests to be run can be collected into a TestSuite. JUnit provides - * different test runners which can run a test suite and collect the results. - * A test runner either expects a static method suite as the entry - * point to get a test to run or it will extract the suite automatically. - *
    - * public static Test suite() {
    - *      suite.addTest(new MathTest("testAdd"));
    - *      suite.addTest(new MathTest("testDivideByZero"));
    - *      return suite;
    - *  }
    - * 
    - * @see TestResult - * @see TestSuite - */ - -public abstract class TestCase extends Assert implements Test { - /** - * the name of the test case - */ - private String fName; - - /** - * No-arg constructor to enable serialization. This method - * is not intended to be used by mere mortals without calling setName(). - */ - public TestCase() { - fName= null; - } - /** - * Constructs a test case with the given name. - */ - public TestCase(String name) { - fName= name; - } - /** - * Counts the number of test cases executed by run(TestResult result). - */ - public int countTestCases() { - return 1; - } - /** - * Creates a default TestResult object - * - * @see TestResult - */ - protected TestResult createResult() { - return new TestResult(); - } - /** - * A convenience method to run this test, collecting the results with a - * default TestResult object. - * - * @see TestResult - */ - public TestResult run() { - TestResult result= createResult(); - run(result); - return result; - } - /** - * Runs the test case and collects the results in TestResult. - */ - public void run(TestResult result) { - result.run(this); - } - /** - * Runs the bare test sequence. - * @exception Throwable if any exception is thrown - */ - public void runBare() throws Throwable { - Throwable exception= null; - setUp(); - try { - runTest(); - } catch (Throwable running) { - exception= running; - } - finally { - try { - tearDown(); - } catch (Throwable tearingDown) { - if (exception == null) exception= tearingDown; - } - } - if (exception != null) throw exception; - } - /** - * Override to run the test and assert its state. - * @exception Throwable if any exception is thrown - */ - protected void runTest() throws Throwable { - assertNotNull(fName); // Some VMs crash when calling getMethod(null,null); - Method runMethod= null; - try { - // use getMethod to get all public inherited - // methods. getDeclaredMethods returns all - // methods of this class but excludes the - // inherited ones. - runMethod= getClass().getMethod(fName, (Class[])null); - } catch (NoSuchMethodException e) { - fail("Method \""+fName+"\" not found"); - } - if (!Modifier.isPublic(runMethod.getModifiers())) { - fail("Method \""+fName+"\" should be public"); - } - - try { - runMethod.invoke(this, (Object[])new Class[0]); - } - catch (InvocationTargetException e) { - e.fillInStackTrace(); - throw e.getTargetException(); - } - catch (IllegalAccessException e) { - e.fillInStackTrace(); - throw e; - } - } - /** - * Sets up the fixture, for example, open a network connection. - * This method is called before a test is executed. - */ - protected void setUp() throws Exception { - } - /** - * Tears down the fixture, for example, close a network connection. - * This method is called after a test is executed. - */ - protected void tearDown() throws Exception { - } - /** - * Returns a string representation of the test case - */ - public String toString() { - return getName() + "(" + getClass().getName() + ")"; - } - /** - * Gets the name of a TestCase - * @return returns a String - */ - public String getName() { - return fName; - } - /** - * Sets the name of a TestCase - * @param name The name to set - */ - public void setName(String name) { - fName= name; - } -} diff --git a/junit/framework/TestFailure.java b/junit/framework/TestFailure.java deleted file mode 100644 index aff6a5a85706..000000000000 --- a/junit/framework/TestFailure.java +++ /dev/null @@ -1,57 +0,0 @@ -package junit.framework; - -import java.io.PrintWriter; -import java.io.StringWriter; - - -/** - * A TestFailure collects a failed test together with - * the caught exception. - * @see TestResult - */ -public class TestFailure extends Object { - protected Test fFailedTest; - protected Throwable fThrownException; - - - /** - * Constructs a TestFailure with the given test and exception. - */ - public TestFailure(Test failedTest, Throwable thrownException) { - fFailedTest= failedTest; - fThrownException= thrownException; - } - /** - * Gets the failed test. - */ - public Test failedTest() { - return fFailedTest; - } - /** - * Gets the thrown exception. - */ - public Throwable thrownException() { - return fThrownException; - } - /** - * Returns a short description of the failure. - */ - public String toString() { - StringBuffer buffer= new StringBuffer(); - buffer.append(fFailedTest+": "+fThrownException.getMessage()); - return buffer.toString(); - } - public String trace() { - StringWriter stringWriter= new StringWriter(); - PrintWriter writer= new PrintWriter(stringWriter); - thrownException().printStackTrace(writer); - StringBuffer buffer= stringWriter.getBuffer(); - return buffer.toString(); - } - public String exceptionMessage() { - return thrownException().getMessage(); - } - public boolean isFailure() { - return thrownException() instanceof AssertionFailedError; - } -} \ No newline at end of file diff --git a/junit/framework/TestListener.java b/junit/framework/TestListener.java deleted file mode 100644 index 9b6944361b9d..000000000000 --- a/junit/framework/TestListener.java +++ /dev/null @@ -1,23 +0,0 @@ -package junit.framework; - -/** - * A Listener for test progress - */ -public interface TestListener { - /** - * An error occurred. - */ - public void addError(Test test, Throwable t); - /** - * A failure occurred. - */ - public void addFailure(Test test, AssertionFailedError t); - /** - * A test ended. - */ - public void endTest(Test test); - /** - * A test started. - */ - public void startTest(Test test); -} \ No newline at end of file diff --git a/junit/framework/TestResult.java b/junit/framework/TestResult.java deleted file mode 100644 index 8535ce015c53..000000000000 --- a/junit/framework/TestResult.java +++ /dev/null @@ -1,166 +0,0 @@ -package junit.framework; - -import java.util.Enumeration; -import java.util.Vector; - -/** - * A TestResult collects the results of executing - * a test case. It is an instance of the Collecting Parameter pattern. - * The test framework distinguishes between failures and errors. - * A failure is anticipated and checked for with assertions. Errors are - * unanticipated problems like an ArrayIndexOutOfBoundsException. - * - * @see Test - */ -public class TestResult extends Object { - protected Vector fFailures; - protected Vector fErrors; - protected Vector fListeners; - protected int fRunTests; - private boolean fStop; - - public TestResult() { - fFailures= new Vector(); - fErrors= new Vector(); - fListeners= new Vector(); - fRunTests= 0; - fStop= false; - } - /** - * Adds an error to the list of errors. The passed in exception - * caused the error. - */ - public synchronized void addError(Test test, Throwable t) { - fErrors.addElement(new TestFailure(test, t)); - for (Enumeration e= cloneListeners().elements(); e.hasMoreElements(); ) { - ((TestListener)e.nextElement()).addError(test, t); - } - } - /** - * Adds a failure to the list of failures. The passed in exception - * caused the failure. - */ - public synchronized void addFailure(Test test, AssertionFailedError t) { - fFailures.addElement(new TestFailure(test, t)); - for (Enumeration e= cloneListeners().elements(); e.hasMoreElements(); ) { - ((TestListener)e.nextElement()).addFailure(test, t); - } - } - /** - * Registers a TestListener - */ - public synchronized void addListener(TestListener listener) { - fListeners.addElement(listener); - } - /** - * Unregisters a TestListener - */ - public synchronized void removeListener(TestListener listener) { - fListeners.removeElement(listener); - } - /** - * Returns a copy of the listeners. - */ - private synchronized Vector cloneListeners() { - return (Vector)fListeners.clone(); - } - /** - * Informs the result that a test was completed. - */ - public void endTest(Test test) { - for (Enumeration e= cloneListeners().elements(); e.hasMoreElements(); ) { - ((TestListener)e.nextElement()).endTest(test); - } - } - /** - * Gets the number of detected errors. - */ - public synchronized int errorCount() { - return fErrors.size(); - } - /** - * Returns an Enumeration for the errors - */ - public synchronized Enumeration errors() { - return fErrors.elements(); - } - /** - * Gets the number of detected failures. - */ - public synchronized int failureCount() { - return fFailures.size(); - } - /** - * Returns an Enumeration for the failures - */ - public synchronized Enumeration failures() { - return fFailures.elements(); - } - /** - * Runs a TestCase. - */ - protected void run(final TestCase test) { - startTest(test); - Protectable p= new Protectable() { - public void protect() throws Throwable { - test.runBare(); - } - }; - runProtected(test, p); - - endTest(test); - } - /** - * Gets the number of run tests. - */ - public synchronized int runCount() { - return fRunTests; - } - /** - * Runs a TestCase. - */ - public void runProtected(final Test test, Protectable p) { - try { - p.protect(); - } - catch (AssertionFailedError e) { - addFailure(test, e); - } - catch (ThreadDeath e) { // don't catch ThreadDeath by accident - throw e; - } - catch (Throwable e) { - addError(test, e); - } - } - /** - * Checks whether the test run should stop - */ - public synchronized boolean shouldStop() { - return fStop; - } - /** - * Informs the result that a test will be started. - */ - public void startTest(Test test) { - final int count= test.countTestCases(); - synchronized(this) { - fRunTests+= count; - } - for (Enumeration e= cloneListeners().elements(); e.hasMoreElements(); ) { - ((TestListener)e.nextElement()).startTest(test); - } - } - /** - * Marks that the test run should stop. - */ - public synchronized void stop() { - fStop= true; - } - /** - * Returns whether the entire test was successful or not. - */ - public synchronized boolean wasSuccessful() { - return failureCount() == 0 && errorCount() == 0; - } -} \ No newline at end of file diff --git a/junit/framework/TestSuite.java b/junit/framework/TestSuite.java deleted file mode 100644 index 5a96bc2a397f..000000000000 --- a/junit/framework/TestSuite.java +++ /dev/null @@ -1,293 +0,0 @@ -package junit.framework; - -import java.io.PrintWriter; -import java.io.StringWriter; -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; -import java.util.Enumeration; -import java.util.Vector; - -/** - * A TestSuite is a Composite of Tests. - * It runs a collection of test cases. Here is an example using - * the dynamic test definition. - *
    - * TestSuite suite= new TestSuite();
    - * suite.addTest(new MathTest("testAdd"));
    - * suite.addTest(new MathTest("testDivideByZero"));
    - * 
    - * Alternatively, a TestSuite can extract the tests to be run automatically. - * To do so you pass the class of your TestCase class to the - * TestSuite constructor. - *
    - * TestSuite suite= new TestSuite(MathTest.class);
    - * 
    - * This constructor creates a suite with all the methods - * starting with "test" that take no arguments. - *

    - * A final option is to do the same for a large array of test classes. - *

    - * Class[] testClasses = { MathTest.class, AnotherTest.class }
    - * TestSuite suite= new TestSuite(testClasses);
    - * 
    - * - * @see Test - */ -public class TestSuite implements Test { - - /** - * ...as the moon sets over the early morning Merlin, Oregon - * mountains, our intrepid adventurers type... - */ - static public Test createTest(Class theClass, String name) { - Constructor constructor; - try { - constructor= getTestConstructor(theClass); - } catch (NoSuchMethodException e) { - return warning("Class "+theClass.getName()+" has no public constructor TestCase(String name) or TestCase()"); - } - Object test; - try { - if (constructor.getParameterTypes().length == 0) { - test= constructor.newInstance(new Object[0]); - if (test instanceof TestCase) - ((TestCase) test).setName(name); - } else { - test= constructor.newInstance(new Object[]{name}); - } - } catch (InstantiationException e) { - return(warning("Cannot instantiate test case: "+name+" ("+exceptionToString(e)+")")); - } catch (InvocationTargetException e) { - return(warning("Exception in constructor: "+name+" ("+exceptionToString(e.getTargetException())+")")); - } catch (IllegalAccessException e) { - return(warning("Cannot access test case: "+name+" ("+exceptionToString(e)+")")); - } - return (Test) test; - } - - /** - * Gets a constructor which takes a single String as - * its argument or a no arg constructor. - */ - public static Constructor getTestConstructor(Class theClass) throws NoSuchMethodException { - Class[] args= { String.class }; - try { - return theClass.getConstructor(args); - } catch (NoSuchMethodException e) { - // fall through - } - return theClass.getConstructor(new Class[0]); - } - - /** - * Returns a test which will fail and log a warning message. - */ - public static Test warning(final String message) { - return new TestCase("warning") { - protected void runTest() { - fail(message); - } - }; - } - - /** - * Converts the stack trace into a string - */ - private static String exceptionToString(Throwable t) { - StringWriter stringWriter= new StringWriter(); - PrintWriter writer= new PrintWriter(stringWriter); - t.printStackTrace(writer); - return stringWriter.toString(); - - } - private String fName; - - private Vector fTests= new Vector(10); - - /** - * Constructs an empty TestSuite. - */ - public TestSuite() { - } - - /** - * Constructs a TestSuite from the given class. Adds all the methods - * starting with "test" as test cases to the suite. - * Parts of this method was written at 2337 meters in the Hueffihuette, - * Kanton Uri - */ - public TestSuite(final Class theClass) { - fName= theClass.getName(); - try { - getTestConstructor(theClass); // Avoid generating multiple error messages - } catch (NoSuchMethodException e) { - addTest(warning("Class "+theClass.getName()+" has no public constructor TestCase(String name) or TestCase()")); - return; - } - - if (!Modifier.isPublic(theClass.getModifiers())) { - addTest(warning("Class "+theClass.getName()+" is not public")); - return; - } - - Class superClass= theClass; - Vector names= new Vector(); - while (Test.class.isAssignableFrom(superClass)) { - Method[] methods= superClass.getDeclaredMethods(); - for (int i= 0; i < methods.length; i++) { - addTestMethod(methods[i], names, theClass); - } - superClass= superClass.getSuperclass(); - } - if (fTests.size() == 0) - addTest(warning("No tests found in "+theClass.getName())); - } - - /** - * Constructs a TestSuite from the given class with the given name. - * @see TestSuite#TestSuite(Class) - */ - public TestSuite(Class theClass, String name) { - this(theClass); - setName(name); - } - - /** - * Constructs an empty TestSuite. - */ - public TestSuite(String name) { - setName(name); - } - - /** - * Constructs a TestSuite from the given array of classes. - * @param classes - */ - public TestSuite (Class[] classes) { - for (int i= 0; i < classes.length; i++) - addTest(new TestSuite(classes[i])); - } - - /** - * Constructs a TestSuite from the given array of classes with the given name. - * @see TestSuite#TestSuite(Class[]) - */ - public TestSuite(Class[] classes, String name) { - this(classes); - setName(name); - } - - /** - * Adds a test to the suite. - */ - public void addTest(Test test) { - fTests.addElement(test); - } - - /** - * Adds the tests from the given class to the suite - */ - public void addTestSuite(Class testClass) { - addTest(new TestSuite(testClass)); - } - - /** - * Counts the number of test cases that will be run by this test. - */ - public int countTestCases() { - int count= 0; - for (Enumeration e= tests(); e.hasMoreElements(); ) { - Test test= (Test)e.nextElement(); - count= count + test.countTestCases(); - } - return count; - } - - /** - * Returns the name of the suite. Not all - * test suites have a name and this method - * can return null. - */ - public String getName() { - return fName; - } - - /** - * Runs the tests and collects their result in a TestResult. - */ - public void run(TestResult result) { - for (Enumeration e= tests(); e.hasMoreElements(); ) { - if (result.shouldStop() ) - break; - Test test= (Test)e.nextElement(); - runTest(test, result); - } - } - - public void runTest(Test test, TestResult result) { - test.run(result); - } - - /** - * Sets the name of the suite. - * @param name The name to set - */ - public void setName(String name) { - fName= name; - } - - /** - * Returns the test at the given index - */ - public Test testAt(int index) { - return (Test)fTests.elementAt(index); - } - - /** - * Returns the number of tests in this suite - */ - public int testCount() { - return fTests.size(); - } - - /** - * Returns the tests as an enumeration - */ - public Enumeration tests() { - return fTests.elements(); - } - - /** - */ - public String toString() { - if (getName() != null) - return getName(); - return super.toString(); - } - - private void addTestMethod(Method m, Vector names, Class theClass) { - String name= m.getName(); - if (names.contains(name)) - return; - if (! isPublicTestMethod(m)) { - if (isTestMethod(m)) - addTest(warning("Test method isn't public: "+m.getName())); - return; - } - names.addElement(name); - addTest(createTest(theClass, name)); - } - - private boolean isPublicTestMethod(Method m) { - return isTestMethod(m) && Modifier.isPublic(m.getModifiers()); - } - - private boolean isTestMethod(Method m) { - String name= m.getName(); - Class[] parameters= m.getParameterTypes(); - Class returnType= m.getReturnType(); - return parameters.length == 0 && name.startsWith("test") && returnType.equals(Void.TYPE); - } -} \ No newline at end of file diff --git a/junit/runner/BaseTestRunner.java b/junit/runner/BaseTestRunner.java deleted file mode 100644 index 1518f7cf4ef9..000000000000 --- a/junit/runner/BaseTestRunner.java +++ /dev/null @@ -1,343 +0,0 @@ -package junit.runner; - -import java.io.BufferedReader; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.PrintWriter; -import java.io.StringReader; -import java.io.StringWriter; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; -import java.text.NumberFormat; -import java.util.Properties; - -import junit.framework.AssertionFailedError; -import junit.framework.Test; -import junit.framework.TestListener; -import junit.framework.TestSuite; - -/** - * Base class for all test runners. - * This class was born live on stage in Sardinia during XP2000. - */ -public abstract class BaseTestRunner implements TestListener { - public static final String SUITE_METHODNAME= "suite"; - - private static Properties fPreferences; - static int fgMaxMessageLength= 500; - static boolean fgFilterStack= true; - boolean fLoading= true; - - /* - * Implementation of TestListener - */ - public synchronized void startTest(Test test) { - testStarted(test.toString()); - } - - protected static void setPreferences(Properties preferences) { - fPreferences= preferences; - } - - protected static Properties getPreferences() { - if (fPreferences == null) { - fPreferences= new Properties(); - fPreferences.put("loading", "true"); - fPreferences.put("filterstack", "true"); - readPreferences(); - } - return fPreferences; - } - - public static void savePreferences() throws IOException { - FileOutputStream fos= new FileOutputStream(getPreferencesFile()); - try { - // calling of the deprecated save method to enable compiling under 1.1.7 - getPreferences().save(fos, ""); - } finally { - fos.close(); - } - } - - public static void setPreference(String key, String value) { - getPreferences().put(key, value); - } - - public synchronized void endTest(Test test) { - testEnded(test.toString()); - } - - public synchronized void addError(final Test test, final Throwable t) { - testFailed(TestRunListener.STATUS_ERROR, test, t); - } - - public synchronized void addFailure(final Test test, final AssertionFailedError t) { - testFailed(TestRunListener.STATUS_FAILURE, test, t); - } - - // TestRunListener implementation - - public abstract void testStarted(String testName); - - public abstract void testEnded(String testName); - - public abstract void testFailed(int status, Test test, Throwable t); - - /** - * Returns the Test corresponding to the given suite. This is - * a template method, subclasses override runFailed(), clearStatus(). - */ - public Test getTest(String suiteClassName) { - if (suiteClassName.length() <= 0) { - clearStatus(); - return null; - } - Class testClass= null; - try { - testClass= loadSuiteClass(suiteClassName); - } catch (ClassNotFoundException e) { - String clazz= e.getMessage(); - if (clazz == null) - clazz= suiteClassName; - runFailed("Class not found \""+clazz+"\""); - return null; - } catch(Exception e) { - runFailed("Error: "+e.toString()); - return null; - } - Method suiteMethod= null; - try { - suiteMethod= testClass.getMethod(SUITE_METHODNAME, new Class[0]); - } catch(Exception e) { - // try to extract a test suite automatically - clearStatus(); - return new TestSuite(testClass); - } - if (! Modifier.isStatic(suiteMethod.getModifiers())) { - runFailed("Suite() method must be static"); - return null; - } - Test test= null; - try { - test= (Test)suiteMethod.invoke(null, (Object[])new Class[0]); // static method - if (test == null) - return test; - } - catch (InvocationTargetException e) { - runFailed("Failed to invoke suite():" + e.getTargetException().toString()); - return null; - } - catch (IllegalAccessException e) { - runFailed("Failed to invoke suite():" + e.toString()); - return null; - } - - clearStatus(); - return test; - } - - /** - * Returns the formatted string of the elapsed time. - */ - public String elapsedTimeAsString(long runTime) { - return NumberFormat.getInstance().format((double)runTime/1000); - } - - /** - * Processes the command line arguments and - * returns the name of the suite class to run or null - */ - protected String processArguments(String[] args) { - String suiteName= null; - for (int i= 0; i < args.length; i++) { - if (args[i].equals("-noloading")) { - setLoading(false); - } else if (args[i].equals("-nofilterstack")) { - fgFilterStack= false; - } else if (args[i].equals("-c")) { - if (args.length > i+1) - suiteName= extractClassName(args[i+1]); - else - System.out.println("Missing Test class name"); - i++; - } else { - suiteName= args[i]; - } - } - return suiteName; - } - - /** - * Sets the loading behaviour of the test runner - */ - public void setLoading(boolean enable) { - fLoading= enable; - } - /** - * Extract the class name from a String in VA/Java style - */ - public String extractClassName(String className) { - if(className.startsWith("Default package for")) - return className.substring(className.lastIndexOf(".")+1); - return className; - } - - /** - * Truncates a String to the maximum length. - */ - public static String truncate(String s) { - if (fgMaxMessageLength != -1 && s.length() > fgMaxMessageLength) - s= s.substring(0, fgMaxMessageLength)+"..."; - return s; - } - - /** - * Override to define how to handle a failed loading of - * a test suite. - */ - protected abstract void runFailed(String message); - - /** - * Returns the loaded Class for a suite name. - */ - protected Class loadSuiteClass(String suiteClassName) throws ClassNotFoundException { - return getLoader().load(suiteClassName); - } - - /** - * Clears the status message. - */ - protected void clearStatus() { // Belongs in the GUI TestRunner class - } - - /** - * Returns the loader to be used. - */ - public TestSuiteLoader getLoader() { - if (useReloadingTestSuiteLoader()) - return new ReloadingTestSuiteLoader(); - return new StandardTestSuiteLoader(); - } - - protected boolean useReloadingTestSuiteLoader() { - return getPreference("loading").equals("true") && !inVAJava() && fLoading; - } - - private static File getPreferencesFile() { - String home= System.getProperty("user.home"); - return new File(home, "junit.properties"); - } - - private static void readPreferences() { - InputStream is= null; - try { - is= new FileInputStream(getPreferencesFile()); - setPreferences(new Properties(getPreferences())); - getPreferences().load(is); - } catch (IOException e) { - try { - if (is != null) - is.close(); - } catch (IOException e1) { - } - } - } - - public static String getPreference(String key) { - return getPreferences().getProperty(key); - } - - public static int getPreference(String key, int dflt) { - String value= getPreference(key); - int intValue= dflt; - if (value == null) - return intValue; - try { - intValue= Integer.parseInt(value); - } catch (NumberFormatException ne) { - } - return intValue; - } - - public static boolean inVAJava() { - try { - Class.forName("com.ibm.uvm.tools.DebugSupport"); - } - catch (Exception e) { - return false; - } - return true; - } - - public static boolean inMac() { - return System.getProperty("mrj.version") != null; - } - - - /** - * Returns a filtered stack trace - */ - public static String getFilteredTrace(Throwable t) { - StringWriter stringWriter= new StringWriter(); - PrintWriter writer= new PrintWriter(stringWriter); - t.printStackTrace(writer); - StringBuffer buffer= stringWriter.getBuffer(); - String trace= buffer.toString(); - return BaseTestRunner.getFilteredTrace(trace); - } - - /** - * Filters stack frames from internal JUnit classes - */ - public static String getFilteredTrace(String stack) { - if (showStackRaw()) - return stack; - - StringWriter sw= new StringWriter(); - PrintWriter pw= new PrintWriter(sw); - StringReader sr= new StringReader(stack); - BufferedReader br= new BufferedReader(sr); - - String line; - try { - while ((line= br.readLine()) != null) { - if (!filterLine(line)) - pw.println(line); - } - } catch (Exception IOException) { - return stack; // return the stack unfiltered - } - return sw.toString(); - } - - protected static boolean showStackRaw() { - return !getPreference("filterstack").equals("true") || fgFilterStack == false; - } - - static boolean filterLine(String line) { - String[] patterns= new String[] { - "junit.framework.TestCase", - "junit.framework.TestResult", - "junit.framework.TestSuite", - "junit.framework.Assert.", // don't filter AssertionFailure - "junit.swingui.TestRunner", - "junit.awtui.TestRunner", - "junit.textui.TestRunner", - "java.lang.reflect.Method.invoke(" - }; - for (int i= 0; i < patterns.length; i++) { - if (line.indexOf(patterns[i]) > 0) - return true; - } - return false; - } - - static { - fgMaxMessageLength= getPreference("maxmessage", fgMaxMessageLength); - } - -} diff --git a/junit/runner/ClassPathTestCollector.java b/junit/runner/ClassPathTestCollector.java deleted file mode 100644 index 0dbb98e530d6..000000000000 --- a/junit/runner/ClassPathTestCollector.java +++ /dev/null @@ -1,83 +0,0 @@ -package junit.runner; - -import java.io.File; -import java.util.Enumeration; -import java.util.Hashtable; -import java.util.StringTokenizer; -import java.util.Vector; - -/** - * An implementation of a TestCollector that consults the - * class path. It considers all classes on the class path - * excluding classes in JARs. It leaves it up to subclasses - * to decide whether a class is a runnable Test. - * - * @see TestCollector - */ -public abstract class ClassPathTestCollector implements TestCollector { - - static final int SUFFIX_LENGTH= ".class".length(); - - public ClassPathTestCollector() { - } - - public Enumeration collectTests() { - String classPath= System.getProperty("java.class.path"); - Hashtable result = collectFilesInPath(classPath); - return result.elements(); - } - - public Hashtable collectFilesInPath(String classPath) { - Hashtable result= collectFilesInRoots(splitClassPath(classPath)); - return result; - } - - Hashtable collectFilesInRoots(Vector roots) { - Hashtable result= new Hashtable(100); - Enumeration e= roots.elements(); - while (e.hasMoreElements()) - gatherFiles(new File((String)e.nextElement()), "", result); - return result; - } - - void gatherFiles(File classRoot, String classFileName, Hashtable result) { - File thisRoot= new File(classRoot, classFileName); - if (thisRoot.isFile()) { - if (isTestClass(classFileName)) { - String className= classNameFromFile(classFileName); - result.put(className, className); - } - return; - } - String[] contents= thisRoot.list(); - if (contents != null) { - for (int i= 0; i < contents.length; i++) - gatherFiles(classRoot, classFileName+File.separatorChar+contents[i], result); - } - } - - Vector splitClassPath(String classPath) { - Vector result= new Vector(); - String separator= System.getProperty("path.separator"); - StringTokenizer tokenizer= new StringTokenizer(classPath, separator); - while (tokenizer.hasMoreTokens()) - result.addElement(tokenizer.nextToken()); - return result; - } - - protected boolean isTestClass(String classFileName) { - return - classFileName.endsWith(".class") && - classFileName.indexOf('$') < 0 && - classFileName.indexOf("Test") > 0; - } - - protected String classNameFromFile(String classFileName) { - // convert /a/b.class to a.b - String s= classFileName.substring(0, classFileName.length()-SUFFIX_LENGTH); - String s2= s.replace(File.separatorChar, '.'); - if (s2.startsWith(".")) - return s2.substring(1); - return s2; - } -} diff --git a/junit/runner/FailureDetailView.java b/junit/runner/FailureDetailView.java deleted file mode 100644 index fc9aaf495f5e..000000000000 --- a/junit/runner/FailureDetailView.java +++ /dev/null @@ -1,23 +0,0 @@ -package junit.runner; - -import java.awt.Component; - -import junit.framework.TestFailure; - -/** - * A view to show a details about a failure - */ -public interface FailureDetailView { - /** - * Returns the component used to present the TraceView - */ - public Component getComponent(); - /** - * Shows details of a TestFailure - */ - public void showFailure(TestFailure failure); - /** - * Clears the view - */ - public void clear(); -} \ No newline at end of file diff --git a/junit/runner/LoadingTestCollector.java b/junit/runner/LoadingTestCollector.java deleted file mode 100644 index 21a314447f70..000000000000 --- a/junit/runner/LoadingTestCollector.java +++ /dev/null @@ -1,70 +0,0 @@ -package junit.runner; - -import java.lang.reflect.Modifier; - -import junit.framework.Test; -import junit.framework.TestSuite; - -/** - * An implementation of a TestCollector that loads - * all classes on the class path and tests whether - * it is assignable from Test or provides a static suite method. - * @see TestCollector - */ -public class LoadingTestCollector extends ClassPathTestCollector { - - TestCaseClassLoader fLoader; - - public LoadingTestCollector() { - fLoader= new TestCaseClassLoader(); - } - - protected boolean isTestClass(String classFileName) { - try { - if (classFileName.endsWith(".class")) { - Class testClass= classFromFile(classFileName); - return (testClass != null) && isTestClass(testClass); - } - } - catch (ClassNotFoundException expected) { - } - catch (NoClassDefFoundError notFatal) { - } - return false; - } - - Class classFromFile(String classFileName) throws ClassNotFoundException { - String className= classNameFromFile(classFileName); - if (!fLoader.isExcluded(className)) - return fLoader.loadClass(className, false); - return null; - } - - boolean isTestClass(Class testClass) { - if (hasSuiteMethod(testClass)) - return true; - if (Test.class.isAssignableFrom(testClass) && - Modifier.isPublic(testClass.getModifiers()) && - hasPublicConstructor(testClass)) - return true; - return false; - } - - boolean hasSuiteMethod(Class testClass) { - try { - testClass.getMethod(BaseTestRunner.SUITE_METHODNAME, new Class[0]); - } catch(Exception e) { - return false; - } - return true; - } - - boolean hasPublicConstructor(Class testClass) { - try { - TestSuite.getTestConstructor(testClass); - } catch(NoSuchMethodException e) { - return false; - } - return true; - } -} diff --git a/junit/runner/ReloadingTestSuiteLoader.java b/junit/runner/ReloadingTestSuiteLoader.java deleted file mode 100644 index 537504b0763c..000000000000 --- a/junit/runner/ReloadingTestSuiteLoader.java +++ /dev/null @@ -1,19 +0,0 @@ -package junit.runner; - -/** - * A TestSuite loader that can reload classes. - */ -public class ReloadingTestSuiteLoader implements TestSuiteLoader { - - public Class load(String suiteClassName) throws ClassNotFoundException { - return createLoader().loadClass(suiteClassName, true); - } - - public Class reload(Class aClass) throws ClassNotFoundException { - return createLoader().loadClass(aClass.getName(), true); - } - - protected TestCaseClassLoader createLoader() { - return new TestCaseClassLoader(); - } -} \ No newline at end of file diff --git a/junit/runner/SimpleTestCollector.java b/junit/runner/SimpleTestCollector.java deleted file mode 100644 index 9d1956ad2f7e..000000000000 --- a/junit/runner/SimpleTestCollector.java +++ /dev/null @@ -1,20 +0,0 @@ -package junit.runner; - -/** - * An implementation of a TestCollector that considers - * a class to be a test class when it contains the - * pattern "Test" in its name - * @see TestCollector - */ -public class SimpleTestCollector extends ClassPathTestCollector { - - public SimpleTestCollector() { - } - - protected boolean isTestClass(String classFileName) { - return - classFileName.endsWith(".class") && - classFileName.indexOf('$') < 0 && - classFileName.indexOf("Test") > 0; - } -} diff --git a/junit/runner/Sorter.java b/junit/runner/Sorter.java deleted file mode 100644 index e868992aa4cc..000000000000 --- a/junit/runner/Sorter.java +++ /dev/null @@ -1,36 +0,0 @@ -package junit.runner; - -import java.util.Vector; - -/** - * A custom quick sort with support to customize the swap behaviour. - * NOTICE: We can't use the the sorting support from the JDK 1.2 collection - * classes because of the JDK 1.1.7 compatibility. - */ -public class Sorter { - public static interface Swapper { - public void swap(Vector values, int left, int right); - } - - public static void sortStrings(Vector values , int left, int right, Swapper swapper) { - int oleft= left; - int oright= right; - String mid= (String)values.elementAt((left + right) / 2); - do { - while (((String)(values.elementAt(left))).compareTo(mid) < 0) - left++; - while (mid.compareTo((String)(values.elementAt(right))) < 0) - right--; - if (left <= right) { - swapper.swap(values, left, right); - left++; - right--; - } - } while (left <= right); - - if (oleft < right) - sortStrings(values, oleft, right, swapper); - if (left < oright) - sortStrings(values, left, oright, swapper); - } -} \ No newline at end of file diff --git a/junit/runner/StandardTestSuiteLoader.java b/junit/runner/StandardTestSuiteLoader.java deleted file mode 100644 index 54f29c1b274f..000000000000 --- a/junit/runner/StandardTestSuiteLoader.java +++ /dev/null @@ -1,19 +0,0 @@ -package junit.runner; - -/** - * The standard test suite loader. It can only load the same class once. - */ -public class StandardTestSuiteLoader implements TestSuiteLoader { - /** - * Uses the system class loader to load the test class - */ - public Class load(String suiteClassName) throws ClassNotFoundException { - return Class.forName(suiteClassName); - } - /** - * Uses the system class loader to load the test class - */ - public Class reload(Class aClass) throws ClassNotFoundException { - return aClass; - } -} \ No newline at end of file diff --git a/junit/runner/TestCaseClassLoader.java b/junit/runner/TestCaseClassLoader.java deleted file mode 100644 index b4bbc243e49a..000000000000 --- a/junit/runner/TestCaseClassLoader.java +++ /dev/null @@ -1,240 +0,0 @@ -package junit.runner; - -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.net.URL; -import java.util.Enumeration; -import java.util.Properties; -import java.util.StringTokenizer; -import java.util.Vector; -import java.util.zip.ZipEntry; -import java.util.zip.ZipFile; - -/** - * A custom class loader which enables the reloading - * of classes for each test run. The class loader - * can be configured with a list of package paths that - * should be excluded from loading. The loading - * of these packages is delegated to the system class - * loader. They will be shared across test runs. - *

    - * The list of excluded package paths is specified in - * a properties file "excluded.properties" that is located in - * the same place as the TestCaseClassLoader class. - *

    - * Known limitation: the TestCaseClassLoader cannot load classes - * from jar files. - */ - - -public class TestCaseClassLoader extends ClassLoader { - /** scanned class path */ - private Vector fPathItems; - /** default excluded paths */ - private String[] defaultExclusions= { - "junit.framework.", - "junit.extensions.", - "junit.runner." - }; - /** name of excluded properties file */ - static final String EXCLUDED_FILE= "excluded.properties"; - /** excluded paths */ - private Vector fExcluded; - - /** - * Constructs a TestCaseLoader. It scans the class path - * and the excluded package paths - */ - public TestCaseClassLoader() { - this(System.getProperty("java.class.path")); - } - - /** - * Constructs a TestCaseLoader. It scans the class path - * and the excluded package paths - */ - public TestCaseClassLoader(String classPath) { - scanPath(classPath); - readExcludedPackages(); - } - - private void scanPath(String classPath) { - String separator= System.getProperty("path.separator"); - fPathItems= new Vector(10); - StringTokenizer st= new StringTokenizer(classPath, separator); - while (st.hasMoreTokens()) { - fPathItems.addElement(st.nextToken()); - } - } - - public URL getResource(String name) { - return ClassLoader.getSystemResource(name); - } - - public InputStream getResourceAsStream(String name) { - return ClassLoader.getSystemResourceAsStream(name); - } - - public boolean isExcluded(String name) { - for (int i= 0; i < fExcluded.size(); i++) { - if (name.startsWith((String) fExcluded.elementAt(i))) { - return true; - } - } - return false; - } - - public synchronized Class loadClass(String name, boolean resolve) - throws ClassNotFoundException { - - Class c= findLoadedClass(name); - if (c != null) - return c; - // - // Delegate the loading of excluded classes to the - // standard class loader. - // - if (isExcluded(name)) { - try { - c= findSystemClass(name); - return c; - } catch (ClassNotFoundException e) { - // keep searching - } - } - if (c == null) { - byte[] data= lookupClassData(name); - if (data == null) - throw new ClassNotFoundException(); - c= defineClass(name, data, 0, data.length); - } - if (resolve) - resolveClass(c); - return c; - } - - private byte[] lookupClassData(String className) throws ClassNotFoundException { - byte[] data= null; - for (int i= 0; i < fPathItems.size(); i++) { - String path= (String) fPathItems.elementAt(i); - String fileName= className.replace('.', '/')+".class"; - if (isJar(path)) { - data= loadJarData(path, fileName); - } else { - data= loadFileData(path, fileName); - } - if (data != null) - return data; - } - throw new ClassNotFoundException(className); - } - - boolean isJar(String pathEntry) { - return pathEntry.endsWith(".jar") || pathEntry.endsWith(".zip"); - } - - private byte[] loadFileData(String path, String fileName) { - File file= new File(path, fileName); - if (file.exists()) { - return getClassData(file); - } - return null; - } - - private byte[] getClassData(File f) { - FileInputStream stream= null; - try { - stream= new FileInputStream(f); - ByteArrayOutputStream out= new ByteArrayOutputStream(1000); - byte[] b= new byte[1000]; - int n; - while ((n= stream.read(b)) != -1) - out.write(b, 0, n); - stream.close(); - out.close(); - return out.toByteArray(); - - } catch (IOException e) { - } - finally { - if (stream != null) - try { - stream.close(); - } catch (IOException e1) { - } - } - return null; - } - - private byte[] loadJarData(String path, String fileName) { - ZipFile zipFile= null; - InputStream stream= null; - File archive= new File(path); - if (!archive.exists()) - return null; - try { - zipFile= new ZipFile(archive); - } catch(IOException io) { - return null; - } - ZipEntry entry= zipFile.getEntry(fileName); - if (entry == null) - return null; - int size= (int) entry.getSize(); - try { - stream= zipFile.getInputStream(entry); - byte[] data= new byte[size]; - int pos= 0; - while (pos < size) { - int n= stream.read(data, pos, data.length - pos); - pos += n; - } - zipFile.close(); - return data; - } catch (IOException e) { - } finally { - try { - if (stream != null) - stream.close(); - } catch (IOException e) { - } - } - return null; - } - - private void readExcludedPackages() { - fExcluded= new Vector(10); - for (int i= 0; i < defaultExclusions.length; i++) - fExcluded.addElement(defaultExclusions[i]); - - InputStream is= getClass().getResourceAsStream(EXCLUDED_FILE); - if (is == null) - return; - Properties p= new Properties(); - try { - p.load(is); - } - catch (IOException e) { - return; - } finally { - try { - is.close(); - } catch (IOException e) { - } - } - for (Enumeration e= p.propertyNames(); e.hasMoreElements(); ) { - String key= (String)e.nextElement(); - if (key.startsWith("excluded.")) { - String path= p.getProperty(key); - path= path.trim(); - if (path.endsWith("*")) - path= path.substring(0, path.length()-1); - if (path.length() > 0) - fExcluded.addElement(path); - } - } - } -} \ No newline at end of file diff --git a/junit/runner/TestCollector.java b/junit/runner/TestCollector.java deleted file mode 100644 index 276e7faac069..000000000000 --- a/junit/runner/TestCollector.java +++ /dev/null @@ -1,17 +0,0 @@ -package junit.runner; - -import java.util.Enumeration; -import junit.swingui.TestSelector; - - -/** - * Collects Test class names to be presented - * by the TestSelector. - * @see TestSelector - */ -public interface TestCollector { - /** - * Returns an enumeration of Strings with qualified class names - */ - public Enumeration collectTests(); -} diff --git a/junit/runner/TestRunListener.java b/junit/runner/TestRunListener.java deleted file mode 100644 index b11ef074418e..000000000000 --- a/junit/runner/TestRunListener.java +++ /dev/null @@ -1,19 +0,0 @@ -package junit.runner; -/** - * A listener interface for observing the - * execution of a test run. Unlike TestListener, - * this interface using only primitive objects, - * making it suitable for remote test execution. - */ - public interface TestRunListener { - /* test status constants*/ - public static final int STATUS_ERROR= 1; - public static final int STATUS_FAILURE= 2; - - public void testRunStarted(String testSuiteName, int testCount); - public void testRunEnded(long elapsedTime); - public void testRunStopped(long elapsedTime); - public void testStarted(String testName); - public void testEnded(String testName); - public void testFailed(int status, String testName, String trace); -} diff --git a/junit/runner/TestSuiteLoader.java b/junit/runner/TestSuiteLoader.java deleted file mode 100644 index 2db589eeed28..000000000000 --- a/junit/runner/TestSuiteLoader.java +++ /dev/null @@ -1,9 +0,0 @@ -package junit.runner; - -/** - * An interface to define how a test suite should be loaded. - */ -public interface TestSuiteLoader { - abstract public Class load(String suiteClassName) throws ClassNotFoundException; - abstract public Class reload(Class aClass) throws ClassNotFoundException; -} \ No newline at end of file diff --git a/junit/runner/excluded.properties b/junit/runner/excluded.properties deleted file mode 100644 index 011ae3c9a913..000000000000 --- a/junit/runner/excluded.properties +++ /dev/null @@ -1,13 +0,0 @@ -# -# The list of excluded package paths for the TestCaseClassLoader -# -excluded.0=sun.* -excluded.1=com.sun.* -excluded.2=org.omg.* -excluded.3=javax.* -excluded.4=sunw.* -excluded.5=java.* -excluded.6=org.w3c.dom.* -excluded.7=org.xml.sax.* -excluded.8=net.jini.* -excluded.9=org.apache.commons.logging.* \ No newline at end of file diff --git a/junit/runner/logo.gif b/junit/runner/logo.gif deleted file mode 100644 index d0e154738605..000000000000 Binary files a/junit/runner/logo.gif and /dev/null differ diff --git a/junit/samples/AllTests.java b/junit/samples/AllTests.java deleted file mode 100644 index 862fbb6f0ee6..000000000000 --- a/junit/samples/AllTests.java +++ /dev/null @@ -1,22 +0,0 @@ -package junit.samples; - -import junit.framework.Test; -import junit.framework.TestSuite; - -/** - * TestSuite that runs all the sample tests - * - */ -public class AllTests { - - public static void main (String[] args) { - junit.textui.TestRunner.run (suite()); - } - public static Test suite ( ) { - TestSuite suite= new TestSuite("All JUnit Tests"); - suite.addTest(VectorTest.suite()); - suite.addTest(new TestSuite(junit.samples.money.MoneyTest.class)); - suite.addTest(junit.tests.AllTests.suite()); - return suite; - } -} \ No newline at end of file diff --git a/junit/samples/SimpleTest.java b/junit/samples/SimpleTest.java deleted file mode 100644 index 7abdc8be0ec6..000000000000 --- a/junit/samples/SimpleTest.java +++ /dev/null @@ -1,65 +0,0 @@ -package junit.samples; - -import junit.framework.Test; -import junit.framework.TestCase; -import junit.framework.TestSuite; - -/** - * Some simple tests. - * - */ -public class SimpleTest extends TestCase { - protected int fValue1; - protected int fValue2; - - protected void setUp() { - fValue1= 2; - fValue2= 3; - } - public static Test suite() { - - /* - * the type safe way - * - TestSuite suite= new TestSuite(); - suite.addTest( - new SimpleTest("add") { - protected void runTest() { testAdd(); } - } - ); - - suite.addTest( - new SimpleTest("testDivideByZero") { - protected void runTest() { testDivideByZero(); } - } - ); - return suite; - */ - - /* - * the dynamic way - */ - return new TestSuite(SimpleTest.class); - } - public void testAdd() { - double result= fValue1 + fValue2; - // forced failure result == 5 - assertTrue(result == 6); - } - public void testDivideByZero() { - int zero= 0; - int result= 8/zero; - result++; // avoid warning for not using result - } - public void testEquals() { - assertEquals(12, 12); - assertEquals(12L, 12L); - assertEquals(new Long(12), new Long(12)); - - assertEquals("Size", 12, 13); - assertEquals("Capacity", 12.0, 11.99, 0.0); - } - public static void main (String[] args) { - junit.textui.TestRunner.run(suite()); - } -} \ No newline at end of file diff --git a/junit/samples/VectorTest.java b/junit/samples/VectorTest.java deleted file mode 100644 index 0048c34fc380..000000000000 --- a/junit/samples/VectorTest.java +++ /dev/null @@ -1,66 +0,0 @@ -package junit.samples; - -import java.util.Vector; - -import junit.framework.Test; -import junit.framework.TestCase; -import junit.framework.TestSuite; - -/** - * A sample test case, testing java.util.Vector. - * - */ -public class VectorTest extends TestCase { - protected Vector fEmpty; - protected Vector fFull; - - public static void main (String[] args) { - junit.textui.TestRunner.run (suite()); - } - protected void setUp() { - fEmpty= new Vector(); - fFull= new Vector(); - fFull.addElement(new Integer(1)); - fFull.addElement(new Integer(2)); - fFull.addElement(new Integer(3)); - } - public static Test suite() { - return new TestSuite(VectorTest.class); - } - public void testCapacity() { - int size= fFull.size(); - for (int i= 0; i < 100; i++) - fFull.addElement(new Integer(i)); - assertTrue(fFull.size() == 100+size); - } - public void testClone() { - Vector clone= (Vector)fFull.clone(); - assertTrue(clone.size() == fFull.size()); - assertTrue(clone.contains(new Integer(1))); - } - public void testContains() { - assertTrue(fFull.contains(new Integer(1))); - assertTrue(!fEmpty.contains(new Integer(1))); - } - public void testElementAt() { - Integer i= (Integer)fFull.elementAt(0); - assertTrue(i.intValue() == 1); - - try { - fFull.elementAt(fFull.size()); - } catch (ArrayIndexOutOfBoundsException e) { - return; - } - fail("Should raise an ArrayIndexOutOfBoundsException"); - } - public void testRemoveAll() { - fFull.removeAllElements(); - fEmpty.removeAllElements(); - assertTrue(fFull.isEmpty()); - assertTrue(fEmpty.isEmpty()); - } - public void testRemoveElement() { - fFull.removeElement(new Integer(3)); - assertTrue(!fFull.contains(new Integer(3)) ); - } -} \ No newline at end of file diff --git a/junit/samples/money/IMoney.java b/junit/samples/money/IMoney.java deleted file mode 100644 index 838f6523f00d..000000000000 --- a/junit/samples/money/IMoney.java +++ /dev/null @@ -1,42 +0,0 @@ -package junit.samples.money; - -/** - * The common interface for simple Monies and MoneyBags - * - */ -public interface IMoney { - /** - * Adds a money to this money. - */ - public abstract IMoney add(IMoney m); - /** - * Adds a simple Money to this money. This is a helper method for - * implementing double dispatch - */ - public abstract IMoney addMoney(Money m); - /** - * Adds a MoneyBag to this money. This is a helper method for - * implementing double dispatch - */ - public abstract IMoney addMoneyBag(MoneyBag s); - /** - * Tests whether this money is zero - */ - public abstract boolean isZero(); - /** - * Multiplies a money by the given factor. - */ - public abstract IMoney multiply(int factor); - /** - * Negates this money. - */ - public abstract IMoney negate(); - /** - * Subtracts a money from this money. - */ - public abstract IMoney subtract(IMoney m); - /** - * Append this to a MoneyBag m. - */ - public abstract void appendTo(MoneyBag m); -} \ No newline at end of file diff --git a/junit/samples/money/Money.java b/junit/samples/money/Money.java deleted file mode 100644 index 8c275dd2fe9a..000000000000 --- a/junit/samples/money/Money.java +++ /dev/null @@ -1,73 +0,0 @@ -package junit.samples.money; - -/** - * A simple Money. - * - */ -public class Money implements IMoney { - - private int fAmount; - private String fCurrency; - - /** - * Constructs a money from the given amount and currency. - */ - public Money(int amount, String currency) { - fAmount= amount; - fCurrency= currency; - } - /** - * Adds a money to this money. Forwards the request to the addMoney helper. - */ - public IMoney add(IMoney m) { - return m.addMoney(this); - } - public IMoney addMoney(Money m) { - if (m.currency().equals(currency()) ) - return new Money(amount()+m.amount(), currency()); - return MoneyBag.create(this, m); - } - public IMoney addMoneyBag(MoneyBag s) { - return s.addMoney(this); - } - public int amount() { - return fAmount; - } - public String currency() { - return fCurrency; - } - public boolean equals(Object anObject) { - if (isZero()) - if (anObject instanceof IMoney) - return ((IMoney)anObject).isZero(); - if (anObject instanceof Money) { - Money aMoney= (Money)anObject; - return aMoney.currency().equals(currency()) - && amount() == aMoney.amount(); - } - return false; - } - public int hashCode() { - return fCurrency.hashCode()+fAmount; - } - public boolean isZero() { - return amount() == 0; - } - public IMoney multiply(int factor) { - return new Money(amount()*factor, currency()); - } - public IMoney negate() { - return new Money(-amount(), currency()); - } - public IMoney subtract(IMoney m) { - return add(m.negate()); - } - public String toString() { - StringBuffer buffer = new StringBuffer(); - buffer.append("["+amount()+" "+currency()+"]"); - return buffer.toString(); - } - public /*this makes no sense*/ void appendTo(MoneyBag m) { - m.appendMoney(this); - } -} \ No newline at end of file diff --git a/junit/samples/money/MoneyBag.java b/junit/samples/money/MoneyBag.java deleted file mode 100644 index c454bcc88987..000000000000 --- a/junit/samples/money/MoneyBag.java +++ /dev/null @@ -1,132 +0,0 @@ -package junit.samples.money; - -import java.util.Enumeration; -import java.util.Vector; - -/** - * A MoneyBag defers exchange rate conversions. For example adding - * 12 Swiss Francs to 14 US Dollars is represented as a bag - * containing the two Monies 12 CHF and 14 USD. Adding another - * 10 Swiss francs gives a bag with 22 CHF and 14 USD. Due to - * the deferred exchange rate conversion we can later value a - * MoneyBag with different exchange rates. - * - * A MoneyBag is represented as a list of Monies and provides - * different constructors to create a MoneyBag. - */ -class MoneyBag implements IMoney { - private Vector fMonies= new Vector(5); - - static IMoney create(IMoney m1, IMoney m2) { - MoneyBag result= new MoneyBag(); - m1.appendTo(result); - m2.appendTo(result); - return result.simplify(); - } - public IMoney add(IMoney m) { - return m.addMoneyBag(this); - } - public IMoney addMoney(Money m) { - return MoneyBag.create(m, this); - } - public IMoney addMoneyBag(MoneyBag s) { - return MoneyBag.create(s, this); - } - void appendBag(MoneyBag aBag) { - for (Enumeration e= aBag.fMonies.elements(); e.hasMoreElements(); ) - appendMoney((Money)e.nextElement()); - } - void appendMoney(Money aMoney) { - if (aMoney.isZero()) return; - IMoney old= findMoney(aMoney.currency()); - if (old == null) { - fMonies.addElement(aMoney); - return; - } - fMonies.removeElement(old); - IMoney sum= old.add(aMoney); - if (sum.isZero()) - return; - fMonies.addElement(sum); - } - public boolean equals(Object anObject) { - if (isZero()) - if (anObject instanceof IMoney) - return ((IMoney)anObject).isZero(); - - if (anObject instanceof MoneyBag) { - MoneyBag aMoneyBag= (MoneyBag)anObject; - if (aMoneyBag.fMonies.size() != fMonies.size()) - return false; - - for (Enumeration e= fMonies.elements(); e.hasMoreElements(); ) { - Money m= (Money) e.nextElement(); - if (!aMoneyBag.contains(m)) - return false; - } - return true; - } - return false; - } - private Money findMoney(String currency) { - for (Enumeration e= fMonies.elements(); e.hasMoreElements(); ) { - Money m= (Money) e.nextElement(); - if (m.currency().equals(currency)) - return m; - } - return null; - } - private boolean contains(Money m) { - Money found= findMoney(m.currency()); - if (found == null) return false; - return found.amount() == m.amount(); - } - public int hashCode() { - int hash= 0; - for (Enumeration e= fMonies.elements(); e.hasMoreElements(); ) { - Object m= e.nextElement(); - hash^= m.hashCode(); - } - return hash; - } - public boolean isZero() { - return fMonies.size() == 0; - } - public IMoney multiply(int factor) { - MoneyBag result= new MoneyBag(); - if (factor != 0) { - for (Enumeration e= fMonies.elements(); e.hasMoreElements(); ) { - Money m= (Money) e.nextElement(); - result.appendMoney((Money)m.multiply(factor)); - } - } - return result; - } - public IMoney negate() { - MoneyBag result= new MoneyBag(); - for (Enumeration e= fMonies.elements(); e.hasMoreElements(); ) { - Money m= (Money) e.nextElement(); - result.appendMoney((Money)m.negate()); - } - return result; - } - private IMoney simplify() { - if (fMonies.size() == 1) - return (IMoney)fMonies.elements().nextElement(); - return this; - } - public IMoney subtract(IMoney m) { - return add(m.negate()); - } - public String toString() { - StringBuffer buffer = new StringBuffer(); - buffer.append("{"); - for (Enumeration e= fMonies.elements(); e.hasMoreElements(); ) - buffer.append(e.nextElement()); - buffer.append("}"); - return buffer.toString(); - } - public void appendTo(MoneyBag m) { - m.appendBag(this); - } -} \ No newline at end of file diff --git a/junit/samples/money/MoneyTest.java b/junit/samples/money/MoneyTest.java deleted file mode 100644 index 0b991cd27e77..000000000000 --- a/junit/samples/money/MoneyTest.java +++ /dev/null @@ -1,142 +0,0 @@ -package junit.samples.money; - -import junit.framework.TestCase; - -public class MoneyTest extends TestCase { - private Money f12CHF; - private Money f14CHF; - private Money f7USD; - private Money f21USD; - - private IMoney fMB1; - private IMoney fMB2; - - public static void main(String args[]) { - junit.textui.TestRunner.run(MoneyTest.class); - } - protected void setUp() { - f12CHF= new Money(12, "CHF"); - f14CHF= new Money(14, "CHF"); - f7USD= new Money( 7, "USD"); - f21USD= new Money(21, "USD"); - - fMB1= MoneyBag.create(f12CHF, f7USD); - fMB2= MoneyBag.create(f14CHF, f21USD); - } - public void testBagMultiply() { - // {[12 CHF][7 USD]} *2 == {[24 CHF][14 USD]} - IMoney expected= MoneyBag.create(new Money(24, "CHF"), new Money(14, "USD")); - assertEquals(expected, fMB1.multiply(2)); - assertEquals(fMB1, fMB1.multiply(1)); - assertTrue(fMB1.multiply(0).isZero()); - } - public void testBagNegate() { - // {[12 CHF][7 USD]} negate == {[-12 CHF][-7 USD]} - IMoney expected= MoneyBag.create(new Money(-12, "CHF"), new Money(-7, "USD")); - assertEquals(expected, fMB1.negate()); - } - public void testBagSimpleAdd() { - // {[12 CHF][7 USD]} + [14 CHF] == {[26 CHF][7 USD]} - IMoney expected= MoneyBag.create(new Money(26, "CHF"), new Money(7, "USD")); - assertEquals(expected, fMB1.add(f14CHF)); - } - public void testBagSubtract() { - // {[12 CHF][7 USD]} - {[14 CHF][21 USD] == {[-2 CHF][-14 USD]} - IMoney expected= MoneyBag.create(new Money(-2, "CHF"), new Money(-14, "USD")); - assertEquals(expected, fMB1.subtract(fMB2)); - } - public void testBagSumAdd() { - // {[12 CHF][7 USD]} + {[14 CHF][21 USD]} == {[26 CHF][28 USD]} - IMoney expected= MoneyBag.create(new Money(26, "CHF"), new Money(28, "USD")); - assertEquals(expected, fMB1.add(fMB2)); - } - public void testIsZero() { - assertTrue(fMB1.subtract(fMB1).isZero()); - assertTrue(MoneyBag.create(new Money (0, "CHF"), new Money (0, "USD")).isZero()); - } - public void testMixedSimpleAdd() { - // [12 CHF] + [7 USD] == {[12 CHF][7 USD]} - IMoney expected= MoneyBag.create(f12CHF, f7USD); - assertEquals(expected, f12CHF.add(f7USD)); - } - public void testBagNotEquals() { - IMoney bag= MoneyBag.create(f12CHF, f7USD); - assertFalse(bag.equals(new Money(12, "DEM").add(f7USD))); - } - public void testMoneyBagEquals() { - assertTrue(!fMB1.equals(null)); - - assertEquals(fMB1, fMB1); - IMoney equal= MoneyBag.create(new Money(12, "CHF"), new Money(7, "USD")); - assertTrue(fMB1.equals(equal)); - assertTrue(!fMB1.equals(f12CHF)); - assertTrue(!f12CHF.equals(fMB1)); - assertTrue(!fMB1.equals(fMB2)); - } - public void testMoneyBagHash() { - IMoney equal= MoneyBag.create(new Money(12, "CHF"), new Money(7, "USD")); - assertEquals(fMB1.hashCode(), equal.hashCode()); - } - public void testMoneyEquals() { - assertTrue(!f12CHF.equals(null)); - Money equalMoney= new Money(12, "CHF"); - assertEquals(f12CHF, f12CHF); - assertEquals(f12CHF, equalMoney); - assertEquals(f12CHF.hashCode(), equalMoney.hashCode()); - assertTrue(!f12CHF.equals(f14CHF)); - } - public void testMoneyHash() { - assertTrue(!f12CHF.equals(null)); - Money equal= new Money(12, "CHF"); - assertEquals(f12CHF.hashCode(), equal.hashCode()); - } - public void testSimplify() { - IMoney money= MoneyBag.create(new Money(26, "CHF"), new Money(28, "CHF")); - assertEquals(new Money(54, "CHF"), money); - } - public void testNormalize2() { - // {[12 CHF][7 USD]} - [12 CHF] == [7 USD] - Money expected= new Money(7, "USD"); - assertEquals(expected, fMB1.subtract(f12CHF)); - } - public void testNormalize3() { - // {[12 CHF][7 USD]} - {[12 CHF][3 USD]} == [4 USD] - IMoney ms1= MoneyBag.create(new Money(12, "CHF"), new Money(3, "USD")); - Money expected= new Money(4, "USD"); - assertEquals(expected, fMB1.subtract(ms1)); - } - public void testNormalize4() { - // [12 CHF] - {[12 CHF][3 USD]} == [-3 USD] - IMoney ms1= MoneyBag.create(new Money(12, "CHF"), new Money(3, "USD")); - Money expected= new Money(-3, "USD"); - assertEquals(expected, f12CHF.subtract(ms1)); - } - public void testPrint() { - assertEquals("[12 CHF]", f12CHF.toString()); - } - public void testSimpleAdd() { - // [12 CHF] + [14 CHF] == [26 CHF] - Money expected= new Money(26, "CHF"); - assertEquals(expected, f12CHF.add(f14CHF)); - } - public void testSimpleBagAdd() { - // [14 CHF] + {[12 CHF][7 USD]} == {[26 CHF][7 USD]} - IMoney expected= MoneyBag.create(new Money(26, "CHF"), new Money(7, "USD")); - assertEquals(expected, f14CHF.add(fMB1)); - } - public void testSimpleMultiply() { - // [14 CHF] *2 == [28 CHF] - Money expected= new Money(28, "CHF"); - assertEquals(expected, f14CHF.multiply(2)); - } - public void testSimpleNegate() { - // [14 CHF] negate == [-14 CHF] - Money expected= new Money(-14, "CHF"); - assertEquals(expected, f14CHF.negate()); - } - public void testSimpleSubtract() { - // [14 CHF] - [12 CHF] == [2 CHF] - Money expected= new Money(2, "CHF"); - assertEquals(expected, f14CHF.subtract(f12CHF)); - } -} \ No newline at end of file diff --git a/junit/swingui/AboutDialog.java b/junit/swingui/AboutDialog.java deleted file mode 100644 index c55b4201136d..000000000000 --- a/junit/swingui/AboutDialog.java +++ /dev/null @@ -1,93 +0,0 @@ -package junit.swingui; - -import java.awt.Font; -import java.awt.GridBagConstraints; -import java.awt.GridBagLayout; -import java.awt.Insets; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.WindowAdapter; -import java.awt.event.WindowEvent; - -import javax.swing.Icon; -import javax.swing.JButton; -import javax.swing.JDialog; -import javax.swing.JFrame; -import javax.swing.JLabel; - -import junit.runner.BaseTestRunner; -import junit.runner.Version; - -/** - * The AboutDialog. - */ -class AboutDialog extends JDialog { - public AboutDialog(JFrame parent) { - super(parent, true); - - setResizable(false); - getContentPane().setLayout(new GridBagLayout()); - setSize(330, 138); - setTitle("About"); - // setLocationRelativeTo is only available in JDK 1.4 - try { - setLocationRelativeTo(parent); - } catch (NoSuchMethodError e) { - TestSelector.centerWindow(this); - } - - JButton close= new JButton("Close"); - close.addActionListener( - new ActionListener() { - public void actionPerformed(ActionEvent e) { - dispose(); - } - } - ); - getRootPane().setDefaultButton(close); - JLabel label1= new JLabel("JUnit"); - label1.setFont(new Font("dialog", Font.PLAIN, 36)); - - JLabel label2= new JLabel("JUnit "+Version.id()+" by Kent Beck and Erich Gamma"); - label2.setFont(new Font("dialog", Font.PLAIN, 14)); - - JLabel logo= createLogo(); - - GridBagConstraints constraintsLabel1= new GridBagConstraints(); - constraintsLabel1.gridx = 3; constraintsLabel1.gridy = 0; - constraintsLabel1.gridwidth = 1; constraintsLabel1.gridheight = 1; - constraintsLabel1.anchor = GridBagConstraints.CENTER; - getContentPane().add(label1, constraintsLabel1); - - GridBagConstraints constraintsLabel2= new GridBagConstraints(); - constraintsLabel2.gridx = 2; constraintsLabel2.gridy = 1; - constraintsLabel2.gridwidth = 2; constraintsLabel2.gridheight = 1; - constraintsLabel2.anchor = GridBagConstraints.CENTER; - getContentPane().add(label2, constraintsLabel2); - - GridBagConstraints constraintsButton1= new GridBagConstraints(); - constraintsButton1.gridx = 2; constraintsButton1.gridy = 2; - constraintsButton1.gridwidth = 2; constraintsButton1.gridheight = 1; - constraintsButton1.anchor = GridBagConstraints.CENTER; - constraintsButton1.insets= new Insets(8, 0, 8, 0); - getContentPane().add(close, constraintsButton1); - - GridBagConstraints constraintsLogo1= new GridBagConstraints(); - constraintsLogo1.gridx = 2; constraintsLogo1.gridy = 0; - constraintsLogo1.gridwidth = 1; constraintsLogo1.gridheight = 1; - constraintsLogo1.anchor = GridBagConstraints.CENTER; - getContentPane().add(logo, constraintsLogo1); - - addWindowListener( - new WindowAdapter() { - public void windowClosing(WindowEvent e) { - dispose(); - } - } - ); - } - protected JLabel createLogo() { - Icon icon= TestRunner.getIconResource(BaseTestRunner.class, "logo.gif"); - return new JLabel(icon); - } -} \ No newline at end of file diff --git a/junit/swingui/CounterPanel.java b/junit/swingui/CounterPanel.java deleted file mode 100644 index cac4427476c0..000000000000 --- a/junit/swingui/CounterPanel.java +++ /dev/null @@ -1,118 +0,0 @@ -package junit.swingui; - -import java.awt.Component; -import java.awt.GridBagConstraints; -import java.awt.GridBagLayout; -import java.awt.Insets; - -import javax.swing.BorderFactory; -import javax.swing.Icon; -import javax.swing.JLabel; -import javax.swing.JPanel; -import javax.swing.JTextField; -import javax.swing.SwingConstants; - -/** - * A panel with test run counters - */ -public class CounterPanel extends JPanel { - private JTextField fNumberOfErrors; - private JTextField fNumberOfFailures; - private JTextField fNumberOfRuns; - private Icon fFailureIcon= TestRunner.getIconResource(getClass(), "icons/failure.gif"); - private Icon fErrorIcon= TestRunner.getIconResource(getClass(), "icons/error.gif"); - - private int fTotal; - - public CounterPanel() { - super(new GridBagLayout()); - fNumberOfErrors= createOutputField(5); - fNumberOfFailures= createOutputField(5); - fNumberOfRuns= createOutputField(9); - - addToGrid(new JLabel("Runs:", SwingConstants.CENTER), - 0, 0, 1, 1, 0.0, 0.0, - GridBagConstraints.CENTER, GridBagConstraints.NONE, - new Insets(0, 0, 0, 0)); - addToGrid(fNumberOfRuns, - 1, 0, 1, 1, 0.33, 0.0, - GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, - new Insets(0, 8, 0, 0)); - - addToGrid(new JLabel("Errors:", fErrorIcon, SwingConstants.LEFT), - 2, 0, 1, 1, 0.0, 0.0, - GridBagConstraints.CENTER, GridBagConstraints.NONE, - new Insets(0, 8, 0, 0)); - addToGrid(fNumberOfErrors, - 3, 0, 1, 1, 0.33, 0.0, - GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, - new Insets(0, 8, 0, 0)); - - addToGrid(new JLabel("Failures:", fFailureIcon, SwingConstants.LEFT), - 4, 0, 1, 1, 0.0, 0.0, - GridBagConstraints.CENTER, GridBagConstraints.NONE, - new Insets(0, 8, 0, 0)); - addToGrid(fNumberOfFailures, - 5, 0, 1, 1, 0.33, 0.0, - GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, - new Insets(0, 8, 0, 0)); - } - - private JTextField createOutputField(int width) { - JTextField field= new JTextField("0", width); - // force a fixed layout to avoid accidental hiding on relayout - field.setMinimumSize(field.getPreferredSize()); - field.setMaximumSize(field.getPreferredSize()); - field.setHorizontalAlignment(SwingConstants.LEFT); - field.setFont(StatusLine.BOLD_FONT); - field.setEditable(false); - field.setBorder(BorderFactory.createEmptyBorder()); - return field; - } - - public void addToGrid(Component comp, - int gridx, int gridy, int gridwidth, int gridheight, - double weightx, double weighty, - int anchor, int fill, - Insets insets) { - - GridBagConstraints constraints= new GridBagConstraints(); - constraints.gridx= gridx; - constraints.gridy= gridy; - constraints.gridwidth= gridwidth; - constraints.gridheight= gridheight; - constraints.weightx= weightx; - constraints.weighty= weighty; - constraints.anchor= anchor; - constraints.fill= fill; - constraints.insets= insets; - add(comp, constraints); - } - - public void reset() { - setLabelValue(fNumberOfErrors, 0); - setLabelValue(fNumberOfFailures, 0); - setLabelValue(fNumberOfRuns, 0); - fTotal= 0; - } - - public void setTotal(int value) { - fTotal= value; - } - - public void setRunValue(int value) { - fNumberOfRuns.setText(Integer.toString(value) + "/" + fTotal); - } - - public void setErrorValue(int value) { - setLabelValue(fNumberOfErrors, value); - } - - public void setFailureValue(int value) { - setLabelValue(fNumberOfFailures, value); - } - - private void setLabelValue(JTextField label, int value) { - label.setText(Integer.toString(value)); - } -} \ No newline at end of file diff --git a/junit/swingui/DefaultFailureDetailView.java b/junit/swingui/DefaultFailureDetailView.java deleted file mode 100644 index 51e79c7286bb..000000000000 --- a/junit/swingui/DefaultFailureDetailView.java +++ /dev/null @@ -1,101 +0,0 @@ -package junit.swingui; - -import java.awt.Component; -import java.awt.Font; -import java.util.StringTokenizer; -import java.util.Vector; - -import javax.swing.AbstractListModel; -import javax.swing.DefaultListCellRenderer; -import javax.swing.JList; -import javax.swing.ListSelectionModel; - -import junit.framework.TestFailure; -import junit.runner.BaseTestRunner; -import junit.runner.FailureDetailView; - -/** - * A view that shows a stack trace of a failure - */ -public class DefaultFailureDetailView implements FailureDetailView { - JList fList; - - /** - * A ListModel representing the scanned failure stack trace. - */ - static class StackTraceListModel extends AbstractListModel { - private Vector fLines= new Vector(20); - - public Object getElementAt(int index) { - return fLines.elementAt(index); - } - - public int getSize() { - return fLines.size(); - } - - public void setTrace(String trace) { - scan(trace); - fireContentsChanged(this, 0, fLines.size()); - } - - public void clear() { - fLines.removeAllElements(); - fireContentsChanged(this, 0, fLines.size()); - } - - private void scan(String trace) { - fLines.removeAllElements(); - StringTokenizer st= new StringTokenizer(trace, "\n\r", false); - while (st.hasMoreTokens()) - fLines.addElement(st.nextToken()); - } - } - - /** - * Renderer for stack entries - */ - static class StackEntryRenderer extends DefaultListCellRenderer { - - public Component getListCellRendererComponent( - JList list, Object value, int modelIndex, - boolean isSelected, boolean cellHasFocus) { - String text= ((String)value).replace('\t', ' '); - Component c= super.getListCellRendererComponent(list, text, modelIndex, isSelected, cellHasFocus); - setText(text); - setToolTipText(text); - return c; - } - } - - /** - * Returns the component used to present the trace - */ - public Component getComponent() { - if (fList == null) { - fList= new JList(new StackTraceListModel()); - fList.setFont(new Font("Dialog", Font.PLAIN, 12)); - fList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); - fList.setVisibleRowCount(5); - fList.setCellRenderer(new StackEntryRenderer()); - } - return fList; - } - - /** - * Shows a TestFailure - */ - public void showFailure(TestFailure failure) { - getModel().setTrace(BaseTestRunner.getFilteredTrace(failure.trace())); - } - /** - * Clears the output. - */ - public void clear() { - getModel().clear(); - } - - private StackTraceListModel getModel() { - return (StackTraceListModel)fList.getModel(); - } -} \ No newline at end of file diff --git a/junit/swingui/FailureRunView.java b/junit/swingui/FailureRunView.java deleted file mode 100644 index 3ec61269c342..000000000000 --- a/junit/swingui/FailureRunView.java +++ /dev/null @@ -1,122 +0,0 @@ -package junit.swingui; - -import java.awt.Component; -import java.awt.Font; - -import javax.swing.DefaultListCellRenderer; -import javax.swing.Icon; -import javax.swing.JList; -import javax.swing.JScrollPane; -import javax.swing.JTabbedPane; -import javax.swing.ListModel; -import javax.swing.ListSelectionModel; -import javax.swing.ScrollPaneConstants; -import javax.swing.event.ListSelectionEvent; -import javax.swing.event.ListSelectionListener; - -import junit.framework.Test; -import junit.framework.TestFailure; -import junit.framework.TestResult; -import junit.runner.BaseTestRunner; - - -/** - * A view presenting the test failures as a list. - */ -public class FailureRunView implements TestRunView { - JList fFailureList; - TestRunContext fRunContext; - - /** - * Renders TestFailures in a JList - */ - static class FailureListCellRenderer extends DefaultListCellRenderer { - private Icon fFailureIcon; - private Icon fErrorIcon; - - FailureListCellRenderer() { - super(); - loadIcons(); - } - - void loadIcons() { - fFailureIcon= TestRunner.getIconResource(getClass(), "icons/failure.gif"); - fErrorIcon= TestRunner.getIconResource(getClass(), "icons/error.gif"); - } - - public Component getListCellRendererComponent( - JList list, Object value, int modelIndex, - boolean isSelected, boolean cellHasFocus) { - - Component c= super.getListCellRendererComponent(list, value, modelIndex, isSelected, cellHasFocus); - TestFailure failure= (TestFailure)value; - String text= failure.failedTest().toString(); - String msg= failure.exceptionMessage(); - if (msg != null) - text+= ":" + BaseTestRunner.truncate(msg); - - if (failure.isFailure()) { - if (fFailureIcon != null) - setIcon(fFailureIcon); - } else { - if (fErrorIcon != null) - setIcon(fErrorIcon); - } - setText(text); - setToolTipText(text); - return c; - } - } - - public FailureRunView(TestRunContext context) { - fRunContext= context; - fFailureList= new JList(fRunContext.getFailures()); - fFailureList.setFont(new Font("Dialog", Font.PLAIN, 12)); - - fFailureList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); - fFailureList.setCellRenderer(new FailureListCellRenderer()); - fFailureList.setVisibleRowCount(5); - - fFailureList.addListSelectionListener( - new ListSelectionListener() { - public void valueChanged(ListSelectionEvent e) { - testSelected(); - } - } - ); - } - - public Test getSelectedTest() { - int index= fFailureList.getSelectedIndex(); - if (index == -1) - return null; - - ListModel model= fFailureList.getModel(); - TestFailure failure= (TestFailure)model.getElementAt(index); - return failure.failedTest(); - } - - public void activate() { - testSelected(); - } - - public void addTab(JTabbedPane pane) { - JScrollPane scrollPane= new JScrollPane(fFailureList, ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS); - Icon errorIcon= TestRunner.getIconResource(getClass(), "icons/error.gif"); - pane.addTab("Failures", errorIcon, scrollPane, "The list of failed tests"); - } - - public void revealFailure(Test failure) { - fFailureList.setSelectedIndex(0); - } - - public void aboutToStart(Test suite, TestResult result) { - } - - public void runFinished(Test suite, TestResult result) { - } - - protected void testSelected() { - fRunContext.handleTestSelected(getSelectedTest()); - } -} diff --git a/junit/swingui/MacProgressBar.java b/junit/swingui/MacProgressBar.java deleted file mode 100644 index 1de6cfdabd35..000000000000 --- a/junit/swingui/MacProgressBar.java +++ /dev/null @@ -1,20 +0,0 @@ -package junit.swingui; - -import javax.swing.JTextField; - -/** - http://java.sun.com/developer/technicalArticles/JavaLP/JavaToMac2/ -*/ -public class MacProgressBar extends ProgressBar { - - private JTextField component; - - public MacProgressBar(JTextField component) { - super(); - this.component= component; - } - - protected void updateBarColor() { - component.setBackground(getStatusColor()); - } -} diff --git a/junit/swingui/ProgressBar.java b/junit/swingui/ProgressBar.java deleted file mode 100644 index d5de71e6daf8..000000000000 --- a/junit/swingui/ProgressBar.java +++ /dev/null @@ -1,46 +0,0 @@ -package junit.swingui; - -import java.awt.Color; - -import javax.swing.JProgressBar; - -/** - * A progress bar showing the green/red status - */ -class ProgressBar extends JProgressBar { - boolean fError= false; - - public ProgressBar() { - super(); - setForeground(getStatusColor()); - } - - protected Color getStatusColor() { - if (fError) - return Color.red; - return Color.green; - } - - public void reset() { - fError= false; - updateBarColor(); - setValue(0); - } - - public void start(int total) { - setMaximum(total); - reset(); - } - - public void step(int value, boolean successful) { - setValue(value); - if (!fError && !successful) { - fError= true; - updateBarColor(); - } - } - - protected void updateBarColor() { - setForeground(getStatusColor()); - } -} diff --git a/junit/swingui/StatusLine.java b/junit/swingui/StatusLine.java deleted file mode 100644 index e18fda241b0b..000000000000 --- a/junit/swingui/StatusLine.java +++ /dev/null @@ -1,45 +0,0 @@ -package junit.swingui; - -import java.awt.Color; -import java.awt.Dimension; -import java.awt.Font; - -import javax.swing.BorderFactory; -import javax.swing.JTextField; -import javax.swing.border.BevelBorder; - -/** - * A status line component. - */ -public class StatusLine extends JTextField { - public static final Font PLAIN_FONT= new Font("dialog", Font.PLAIN, 12); - public static final Font BOLD_FONT= new Font("dialog", Font.BOLD, 12); - - public StatusLine(int preferredWidth) { - super(); - setFont(BOLD_FONT); - setEditable(false); - setBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED)); - Dimension d= getPreferredSize(); - d.width= preferredWidth; - setPreferredSize(d); - } - - public void showInfo(String message) { - setFont(PLAIN_FONT); - setForeground(Color.black); - setText(message); - } - - public void showError(String status) { - setFont(BOLD_FONT); - setForeground(Color.red); - setText(status); - setToolTipText(status); - } - - public void clear() { - setText(""); - setToolTipText(null); - } -} \ No newline at end of file diff --git a/junit/swingui/TestHierarchyRunView.java b/junit/swingui/TestHierarchyRunView.java deleted file mode 100644 index 89bd29784e36..000000000000 --- a/junit/swingui/TestHierarchyRunView.java +++ /dev/null @@ -1,77 +0,0 @@ -package junit.swingui; - -import java.util.Vector; - -import javax.swing.Icon; -import javax.swing.JTabbedPane; -import javax.swing.JTree; -import javax.swing.event.TreeSelectionEvent; -import javax.swing.event.TreeSelectionListener; -import javax.swing.tree.TreePath; - -import junit.framework.Test; -import junit.framework.TestResult; - -/** - * A hierarchical view of a test run. - * The contents of a test suite is shown - * as a tree. - */ -public class TestHierarchyRunView implements TestRunView { - TestSuitePanel fTreeBrowser; - TestRunContext fTestContext; - - public TestHierarchyRunView(TestRunContext context) { - fTestContext= context; - fTreeBrowser= new TestSuitePanel(); - fTreeBrowser.getTree().addTreeSelectionListener( - new TreeSelectionListener() { - public void valueChanged(TreeSelectionEvent e) { - testSelected(); - } - } - ); - } - - public void addTab(JTabbedPane pane) { - Icon treeIcon= TestRunner.getIconResource(getClass(), "icons/hierarchy.gif"); - pane.addTab("Test Hierarchy", treeIcon, fTreeBrowser, "The test hierarchy"); - } - - public Test getSelectedTest() { - return fTreeBrowser.getSelectedTest(); - } - - public void activate() { - testSelected(); - } - - public void revealFailure(Test failure) { - JTree tree= fTreeBrowser.getTree(); - TestTreeModel model= (TestTreeModel)tree.getModel(); - Vector vpath= new Vector(); - int index= model.findTest(failure, (Test)model.getRoot(), vpath); - if (index >= 0) { - Object[] path= new Object[vpath.size()+1]; - vpath.copyInto(path); - Object last= path[vpath.size()-1]; - path[vpath.size()]= model.getChild(last, index); - TreePath selectionPath= new TreePath(path); - tree.setSelectionPath(selectionPath); - tree.makeVisible(selectionPath); - } - } - - public void aboutToStart(Test suite, TestResult result) { - fTreeBrowser.showTestTree(suite); - result.addListener(fTreeBrowser); - } - - public void runFinished(Test suite, TestResult result) { - result.removeListener(fTreeBrowser); - } - - protected void testSelected() { - fTestContext.handleTestSelected(getSelectedTest()); - } -} diff --git a/junit/swingui/TestRunContext.java b/junit/swingui/TestRunContext.java deleted file mode 100644 index 038e3c417652..000000000000 --- a/junit/swingui/TestRunContext.java +++ /dev/null @@ -1,21 +0,0 @@ -package junit.swingui; - -import javax.swing.ListModel; - -import junit.framework.Test; - -/** - * The interface for accessing the Test run context. Test run views - * should use this interface rather than accessing the TestRunner - * directly. - */ -public interface TestRunContext { - /** - * Handles the selection of a Test. - */ - public void handleTestSelected(Test test); - /** - * Returns the failure model - */ - public ListModel getFailures(); -} \ No newline at end of file diff --git a/junit/swingui/TestRunView.java b/junit/swingui/TestRunView.java deleted file mode 100644 index 1eb5491b672f..000000000000 --- a/junit/swingui/TestRunView.java +++ /dev/null @@ -1,39 +0,0 @@ -package junit.swingui; - -import javax.swing.JTabbedPane; - -import junit.framework.Test; -import junit.framework.TestResult; - -/** - * A TestRunView is shown as a page in a tabbed folder. - * It contributes the page contents and can return - * the currently selected tests. A TestRunView is - * notified about the start and finish of a run. - */ -interface TestRunView { - /** - * Returns the currently selected Test in the View - */ - public Test getSelectedTest(); - /** - * Activates the TestRunView - */ - public void activate(); - /** - * Reveals the given failure - */ - public void revealFailure(Test failure); - /** - * Adds the TestRunView to the test run views tab - */ - public void addTab(JTabbedPane pane); - /** - * Informs that the suite is about to start - */ - public void aboutToStart(Test suite, TestResult result); - /** - * Informs that the run of the test suite has finished - */ - public void runFinished(Test suite, TestResult result); -} \ No newline at end of file diff --git a/junit/swingui/TestRunner.java b/junit/swingui/TestRunner.java deleted file mode 100644 index 44aa7a705848..000000000000 --- a/junit/swingui/TestRunner.java +++ /dev/null @@ -1,849 +0,0 @@ -package junit.swingui; - -import java.awt.BorderLayout; -import java.awt.Component; -import java.awt.GridBagConstraints; -import java.awt.GridBagLayout; -import java.awt.GridLayout; -import java.awt.Image; -import java.awt.Insets; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.ItemEvent; -import java.awt.event.ItemListener; -import java.awt.event.KeyAdapter; -import java.awt.event.KeyEvent; -import java.awt.event.WindowAdapter; -import java.awt.event.WindowEvent; -import java.io.BufferedReader; -import java.io.BufferedWriter; -import java.io.File; -import java.io.FileReader; -import java.io.FileWriter; -import java.io.IOException; -import java.lang.reflect.Constructor; -import java.net.URL; -import java.util.Enumeration; -import java.util.Vector; - -import javax.swing.DefaultListModel; -import javax.swing.Icon; -import javax.swing.ImageIcon; -import javax.swing.JButton; -import javax.swing.JCheckBox; -import javax.swing.JComboBox; -import javax.swing.JFrame; -import javax.swing.JLabel; -import javax.swing.JMenu; -import javax.swing.JMenuBar; -import javax.swing.JMenuItem; -import javax.swing.JOptionPane; -import javax.swing.JPanel; -import javax.swing.JScrollPane; -import javax.swing.JSeparator; -import javax.swing.JSplitPane; -import javax.swing.JTabbedPane; -import javax.swing.ListModel; -import javax.swing.ScrollPaneConstants; -import javax.swing.SwingConstants; -import javax.swing.SwingUtilities; -import javax.swing.event.ChangeEvent; -import javax.swing.event.ChangeListener; -import javax.swing.event.DocumentEvent; - -import junit.framework.Test; -import junit.framework.TestCase; -import junit.framework.TestFailure; -import junit.framework.TestResult; -import junit.framework.TestSuite; -import junit.runner.BaseTestRunner; -import junit.runner.FailureDetailView; -import junit.runner.SimpleTestCollector; -import junit.runner.TestCollector; -import junit.runner.TestRunListener; -import junit.runner.Version; - -/** - * A Swing based user interface to run tests. - * Enter the name of a class which either provides a static - * suite method or is a subclass of TestCase. - *

    - * Synopsis: java junit.swingui.TestRunner [-noloading] [TestCase]
    - * 
    - * TestRunner takes as an optional argument the name of the testcase class to be run. - */ -public class TestRunner extends BaseTestRunner implements TestRunContext { - private static final int GAP= 4; - private static final int HISTORY_LENGTH= 5; - - protected JFrame fFrame; - private Thread fRunner; - private TestResult fTestResult; - - private JComboBox fSuiteCombo; - private ProgressBar fProgressIndicator; - private DefaultListModel fFailures; - private JLabel fLogo; - private CounterPanel fCounterPanel; - private JButton fRun; - private JButton fQuitButton; - private JButton fRerunButton; - private StatusLine fStatusLine; - private FailureDetailView fFailureView; - private JTabbedPane fTestViewTab; - private JCheckBox fUseLoadingRunner; - private Vector fTestRunViews= new Vector(); // view associated with tab in tabbed pane - - private static final String TESTCOLLECTOR_KEY= "TestCollectorClass"; - private static final String FAILUREDETAILVIEW_KEY= "FailureViewClass"; - - public TestRunner() { - } - - public static void main(String[] args) { - new TestRunner().start(args); - } - - public static void run(Class test) { - String args[]= { test.getName() }; - main(args); - } - - public void testFailed(final int status, final Test test, final Throwable t) { - SwingUtilities.invokeLater( - new Runnable() { - public void run() { - switch (status) { - case TestRunListener.STATUS_ERROR: - fCounterPanel.setErrorValue(fTestResult.errorCount()); - appendFailure(test, t); - break; - case TestRunListener.STATUS_FAILURE: - fCounterPanel.setFailureValue(fTestResult.failureCount()); - appendFailure(test, t); - break; - } - } - } - ); - } - - public void testStarted(String testName) { - postInfo("Running: "+testName); - } - - public void testEnded(String stringName) { - synchUI(); - SwingUtilities.invokeLater( - new Runnable() { - public void run() { - if (fTestResult != null) { - fCounterPanel.setRunValue(fTestResult.runCount()); - fProgressIndicator.step(fTestResult.runCount(), fTestResult.wasSuccessful()); - } - } - } - ); - } - - public void setSuite(String suiteName) { - fSuiteCombo.getEditor().setItem(suiteName); - } - - private void addToHistory(final String suite) { - for (int i= 0; i < fSuiteCombo.getItemCount(); i++) { - if (suite.equals(fSuiteCombo.getItemAt(i))) { - fSuiteCombo.removeItemAt(i); - fSuiteCombo.insertItemAt(suite, 0); - fSuiteCombo.setSelectedIndex(0); - return; - } - } - fSuiteCombo.insertItemAt(suite, 0); - fSuiteCombo.setSelectedIndex(0); - pruneHistory(); - } - - private void pruneHistory() { - int historyLength= getPreference("maxhistory", HISTORY_LENGTH); - if (historyLength < 1) - historyLength= 1; - for (int i= fSuiteCombo.getItemCount()-1; i > historyLength-1; i--) - fSuiteCombo.removeItemAt(i); - } - - private void appendFailure(Test test, Throwable t) { - fFailures.addElement(new TestFailure(test, t)); - if (fFailures.size() == 1) - revealFailure(test); - } - - private void revealFailure(Test test) { - for (Enumeration e= fTestRunViews.elements(); e.hasMoreElements(); ) { - TestRunView v= (TestRunView) e.nextElement(); - v.revealFailure(test); - } - } - - protected void aboutToStart(final Test testSuite) { - for (Enumeration e= fTestRunViews.elements(); e.hasMoreElements(); ) { - TestRunView v= (TestRunView) e.nextElement(); - v.aboutToStart(testSuite, fTestResult); - } - } - - protected void runFinished(final Test testSuite) { - SwingUtilities.invokeLater( - new Runnable() { - public void run() { - for (Enumeration e= fTestRunViews.elements(); e.hasMoreElements(); ) { - TestRunView v= (TestRunView) e.nextElement(); - v.runFinished(testSuite, fTestResult); - } - } - } - ); - } - - protected CounterPanel createCounterPanel() { - return new CounterPanel(); - } - - protected JPanel createFailedPanel() { - JPanel failedPanel= new JPanel(new GridLayout(0, 1, 0, 2)); - fRerunButton= new JButton("Run"); - fRerunButton.setEnabled(false); - fRerunButton.addActionListener( - new ActionListener() { - public void actionPerformed(ActionEvent e) { - rerun(); - } - } - ); - failedPanel.add(fRerunButton); - return failedPanel; - } - - protected FailureDetailView createFailureDetailView() { - String className= BaseTestRunner.getPreference(FAILUREDETAILVIEW_KEY); - if (className != null) { - Class viewClass= null; - try { - viewClass= Class.forName(className); - return (FailureDetailView)viewClass.newInstance(); - } catch(Exception e) { - JOptionPane.showMessageDialog(fFrame, "Could not create Failure DetailView - using default view"); - } - } - return new DefaultFailureDetailView(); - } - - /** - * Creates the JUnit menu. Clients override this - * method to add additional menu items. - */ - protected JMenu createJUnitMenu() { - JMenu menu= new JMenu("JUnit"); - menu.setMnemonic('J'); - JMenuItem mi1= new JMenuItem("About..."); - mi1.addActionListener( - new ActionListener() { - public void actionPerformed(ActionEvent event) { - about(); - } - } - ); - mi1.setMnemonic('A'); - menu.add(mi1); - - menu.addSeparator(); - JMenuItem mi2= new JMenuItem(" Exit "); - mi2.addActionListener( - new ActionListener() { - public void actionPerformed(ActionEvent event) { - terminate(); - } - } - ); - mi2.setMnemonic('x'); - menu.add(mi2); - - return menu; - } - - protected JFrame createFrame() { - JFrame frame= new JFrame("JUnit"); - Image icon= loadFrameIcon(); - if (icon != null) - frame.setIconImage(icon); - frame.getContentPane().setLayout(new BorderLayout(0, 0)); - - frame.addWindowListener( - new WindowAdapter() { - public void windowClosing(WindowEvent e) { - terminate(); - } - } - ); - return frame; - } - - protected JLabel createLogo() { - JLabel label; - Icon icon= getIconResource(BaseTestRunner.class, "logo.gif"); - if (icon != null) - label= new JLabel(icon); - else - label= new JLabel("JV"); - label.setToolTipText("JUnit Version "+Version.id()); - return label; - } - - protected void createMenus(JMenuBar mb) { - mb.add(createJUnitMenu()); - } - - protected JCheckBox createUseLoaderCheckBox() { - boolean useLoader= useReloadingTestSuiteLoader(); - JCheckBox box= new JCheckBox("Reload classes every run", useLoader); - box.setToolTipText("Use a custom class loader to reload the classes for every run"); - if (inVAJava()) - box.setVisible(false); - return box; - } - - protected JButton createQuitButton() { - // spaces required to avoid layout flicker - // Exit is shorter than Stop that shows in the same column - JButton quit= new JButton(" Exit "); - quit.addActionListener( - new ActionListener() { - public void actionPerformed(ActionEvent e) { - terminate(); - } - } - ); - return quit; - } - - protected JButton createRunButton() { - JButton run= new JButton("Run"); - run.setEnabled(true); - run.addActionListener( - new ActionListener() { - public void actionPerformed(ActionEvent e) { - runSuite(); - } - } - ); - return run; - } - - protected Component createBrowseButton() { - JButton browse= new JButton("..."); - browse.setToolTipText("Select a Test class"); - browse.addActionListener( - new ActionListener() { - public void actionPerformed(ActionEvent e) { - browseTestClasses(); - } - } - ); - return browse; - } - - protected StatusLine createStatusLine() { - return new StatusLine(380); - } - - protected JComboBox createSuiteCombo() { - JComboBox combo= new JComboBox(); - combo.setEditable(true); - combo.setLightWeightPopupEnabled(false); - - combo.getEditor().getEditorComponent().addKeyListener( - new KeyAdapter() { - public void keyTyped(KeyEvent e) { - textChanged(); - if (e.getKeyChar() == KeyEvent.VK_ENTER) - runSuite(); - } - } - ); - try { - loadHistory(combo); - } catch (IOException e) { - // fails the first time - } - combo.addItemListener( - new ItemListener() { - public void itemStateChanged(ItemEvent event) { - if (event.getStateChange() == ItemEvent.SELECTED) { - textChanged(); - } - } - } - ); - return combo; - } - - protected JTabbedPane createTestRunViews() { - JTabbedPane pane= new JTabbedPane(SwingConstants.BOTTOM); - - FailureRunView lv= new FailureRunView(this); - fTestRunViews.addElement(lv); - lv.addTab(pane); - - TestHierarchyRunView tv= new TestHierarchyRunView(this); - fTestRunViews.addElement(tv); - tv.addTab(pane); - - pane.addChangeListener( - new ChangeListener() { - public void stateChanged(ChangeEvent e) { - testViewChanged(); - } - } - ); - return pane; - } - - public void testViewChanged() { - TestRunView view= (TestRunView)fTestRunViews.elementAt(fTestViewTab.getSelectedIndex()); - view.activate(); - } - - protected TestResult createTestResult() { - return new TestResult(); - } - - protected JFrame createUI(String suiteName) { - JFrame frame= createFrame(); - JMenuBar mb= new JMenuBar(); - createMenus(mb); - frame.setJMenuBar(mb); - - JLabel suiteLabel= new JLabel("Test class name:"); - fSuiteCombo= createSuiteCombo(); - fRun= createRunButton(); - frame.getRootPane().setDefaultButton(fRun); - Component browseButton= createBrowseButton(); - - fUseLoadingRunner= createUseLoaderCheckBox(); - - fStatusLine= createStatusLine(); - if (inMac()) - fProgressIndicator= new MacProgressBar(fStatusLine); - else - fProgressIndicator= new ProgressBar(); - fCounterPanel= createCounterPanel(); - - fFailures= new DefaultListModel(); - - fTestViewTab= createTestRunViews(); - JPanel failedPanel= createFailedPanel(); - - fFailureView= createFailureDetailView(); - JScrollPane tracePane= new JScrollPane(fFailureView.getComponent(), ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS); - - - - fQuitButton= createQuitButton(); - fLogo= createLogo(); - - JPanel panel= new JPanel(new GridBagLayout()); - - addGrid(panel, suiteLabel, 0, 0, 2, GridBagConstraints.HORIZONTAL, 1.0, GridBagConstraints.WEST); - addGrid(panel, fSuiteCombo, 0, 1, 1, GridBagConstraints.HORIZONTAL, 1.0, GridBagConstraints.WEST); - addGrid(panel, browseButton, 1, 1, 1, GridBagConstraints.NONE, 0.0, GridBagConstraints.WEST); - addGrid(panel, fRun, 2, 1, 1, GridBagConstraints.HORIZONTAL, 0.0, GridBagConstraints.CENTER); - - addGrid(panel, fUseLoadingRunner, 0, 2, 3, GridBagConstraints.NONE, 1.0, GridBagConstraints.WEST); - //addGrid(panel, new JSeparator(), 0, 3, 3, GridBagConstraints.HORIZONTAL, 1.0, GridBagConstraints.WEST); - - - addGrid(panel, fProgressIndicator, 0, 3, 2, GridBagConstraints.HORIZONTAL, 1.0, GridBagConstraints.WEST); - addGrid(panel, fLogo, 2, 3, 1, GridBagConstraints.NONE, 0.0, GridBagConstraints.NORTH); - - addGrid(panel, fCounterPanel, 0, 4, 2, GridBagConstraints.NONE, 0.0, GridBagConstraints.WEST); - addGrid(panel, new JSeparator(), 0, 5, 2, GridBagConstraints.HORIZONTAL, 1.0, GridBagConstraints.WEST); - addGrid(panel, new JLabel("Results:"), 0, 6, 2, GridBagConstraints.HORIZONTAL, 1.0, GridBagConstraints.WEST); - - JSplitPane splitter= new JSplitPane(JSplitPane.VERTICAL_SPLIT, fTestViewTab, tracePane); - addGrid(panel, splitter, 0, 7, 2, GridBagConstraints.BOTH, 1.0, GridBagConstraints.WEST); - - addGrid(panel, failedPanel, 2, 7, 1, GridBagConstraints.HORIZONTAL, 0.0, GridBagConstraints.NORTH/*CENTER*/); - - addGrid(panel, fStatusLine, 0, 9, 2, GridBagConstraints.HORIZONTAL, 1.0, GridBagConstraints.CENTER); - addGrid(panel, fQuitButton, 2, 9, 1, GridBagConstraints.HORIZONTAL, 0.0, GridBagConstraints.CENTER); - - frame.setContentPane(panel); - frame.pack(); - frame.setLocation(200, 200); - return frame; - } - - private void addGrid(JPanel p, Component co, int x, int y, int w, int fill, double wx, int anchor) { - GridBagConstraints c= new GridBagConstraints(); - c.gridx= x; c.gridy= y; - c.gridwidth= w; - c.anchor= anchor; - c.weightx= wx; - c.fill= fill; - if (fill == GridBagConstraints.BOTH || fill == GridBagConstraints.VERTICAL) - c.weighty= 1.0; - c.insets= new Insets(y == 0 ? 10 : 0, x == 0 ? 10 : GAP, GAP, GAP); - p.add(co, c); - } - - protected String getSuiteText() { - if (fSuiteCombo == null) - return ""; - return (String)fSuiteCombo.getEditor().getItem(); - } - - public ListModel getFailures() { - return fFailures; - } - - public void insertUpdate(DocumentEvent event) { - textChanged(); - } - - protected Object instanciateClass(String fullClassName, Object param) { - try { - Class clazz= Class.forName(fullClassName); - if (param == null) { - return clazz.newInstance(); - } else { - Class[] clazzParam= {param.getClass()}; - Constructor clazzConstructor= clazz.getConstructor(clazzParam); - Object[] objectParam= {param}; - return clazzConstructor.newInstance(objectParam); - } - } catch (Exception e) { - e.printStackTrace(); - } - return null; - } - - public void browseTestClasses() { - TestCollector collector= createTestCollector(); - TestSelector selector= new TestSelector(fFrame, collector); - if (selector.isEmpty()) { - JOptionPane.showMessageDialog(fFrame, "No Test Cases found.\nCheck that the configured \'TestCollector\' is supported on this platform."); - return; - } - selector.show(); - String className= selector.getSelectedItem(); - if (className != null) - setSuite(className); - } - - TestCollector createTestCollector() { - String className= BaseTestRunner.getPreference(TESTCOLLECTOR_KEY); - if (className != null) { - Class collectorClass= null; - try { - collectorClass= Class.forName(className); - return (TestCollector)collectorClass.newInstance(); - } catch(Exception e) { - JOptionPane.showMessageDialog(fFrame, "Could not create TestCollector - using default collector"); - } - } - return new SimpleTestCollector(); - } - - private Image loadFrameIcon() { - ImageIcon icon= (ImageIcon)getIconResource(BaseTestRunner.class, "smalllogo.gif"); - if (icon != null) - return icon.getImage(); - return null; - } - - private void loadHistory(JComboBox combo) throws IOException { - BufferedReader br= new BufferedReader(new FileReader(getSettingsFile())); - int itemCount= 0; - try { - String line; - while ((line= br.readLine()) != null) { - combo.addItem(line); - itemCount++; - } - if (itemCount > 0) - combo.setSelectedIndex(0); - - } finally { - br.close(); - } - } - - private File getSettingsFile() { - String home= System.getProperty("user.home"); - return new File(home,".junitsession"); - } - - private void postInfo(final String message) { - SwingUtilities.invokeLater( - new Runnable() { - public void run() { - showInfo(message); - } - } - ); - } - - private void postStatus(final String status) { - SwingUtilities.invokeLater( - new Runnable() { - public void run() { - showStatus(status); - } - } - ); - } - - public void removeUpdate(DocumentEvent event) { - textChanged(); - } - - private void rerun() { - TestRunView view= (TestRunView)fTestRunViews.elementAt(fTestViewTab.getSelectedIndex()); - Test rerunTest= view.getSelectedTest(); - if (rerunTest != null) - rerunTest(rerunTest); - } - - private void rerunTest(Test test) { - if (!(test instanceof TestCase)) { - showInfo("Could not reload "+ test.toString()); - return; - } - Test reloadedTest= null; - TestCase rerunTest= (TestCase)test; - - try { - Class reloadedTestClass= getLoader().reload(test.getClass()); - reloadedTest= TestSuite.createTest(reloadedTestClass, rerunTest.getName()); - } catch(Exception e) { - showInfo("Could not reload "+ test.toString()); - return; - } - TestResult result= new TestResult(); - reloadedTest.run(result); - - String message= reloadedTest.toString(); - if(result.wasSuccessful()) - showInfo(message+" was successful"); - else if (result.errorCount() == 1) - showStatus(message+" had an error"); - else - showStatus(message+" had a failure"); - } - - protected void reset() { - fCounterPanel.reset(); - fProgressIndicator.reset(); - fRerunButton.setEnabled(false); - fFailureView.clear(); - fFailures.clear(); - } - - protected void runFailed(String message) { - showStatus(message); - fRun.setText("Run"); - fRunner= null; - } - - synchronized public void runSuite() { - if (fRunner != null) { - fTestResult.stop(); - } else { - setLoading(shouldReload()); - reset(); - showInfo("Load Test Case..."); - final String suiteName= getSuiteText(); - final Test testSuite= getTest(suiteName); - if (testSuite != null) { - addToHistory(suiteName); - doRunTest(testSuite); - } - } - } - - private boolean shouldReload() { - return !inVAJava() && fUseLoadingRunner.isSelected(); - } - - - synchronized protected void runTest(final Test testSuite) { - if (fRunner != null) { - fTestResult.stop(); - } else { - reset(); - if (testSuite != null) { - doRunTest(testSuite); - } - } - } - - private void doRunTest(final Test testSuite) { - setButtonLabel(fRun, "Stop"); - fRunner= new Thread("TestRunner-Thread") { - public void run() { - TestRunner.this.start(testSuite); - postInfo("Running..."); - - long startTime= System.currentTimeMillis(); - testSuite.run(fTestResult); - - if (fTestResult.shouldStop()) { - postStatus("Stopped"); - } else { - long endTime= System.currentTimeMillis(); - long runTime= endTime-startTime; - postInfo("Finished: " + elapsedTimeAsString(runTime) + " seconds"); - } - runFinished(testSuite); - setButtonLabel(fRun, "Run"); - fRunner= null; - System.gc(); - } - }; - // make sure that the test result is created before we start the - // test runner thread so that listeners can register for it. - fTestResult= createTestResult(); - fTestResult.addListener(TestRunner.this); - aboutToStart(testSuite); - - fRunner.start(); - } - - private void saveHistory() throws IOException { - BufferedWriter bw= new BufferedWriter(new FileWriter(getSettingsFile())); - try { - for (int i= 0; i < fSuiteCombo.getItemCount(); i++) { - String testsuite= fSuiteCombo.getItemAt(i).toString(); - bw.write(testsuite, 0, testsuite.length()); - bw.newLine(); - } - } finally { - bw.close(); - } - } - - private void setButtonLabel(final JButton button, final String label) { - SwingUtilities.invokeLater( - new Runnable() { - public void run() { - button.setText(label); - } - } - ); - } - - public void handleTestSelected(Test test) { - fRerunButton.setEnabled(test != null && (test instanceof TestCase)); - showFailureDetail(test); - } - - private void showFailureDetail(Test test) { - if (test != null) { - ListModel failures= getFailures(); - for (int i= 0; i < failures.getSize(); i++) { - TestFailure failure= (TestFailure)failures.getElementAt(i); - if (failure.failedTest() == test) { - fFailureView.showFailure(failure); - return; - } - } - } - fFailureView.clear(); - } - - private void showInfo(String message) { - fStatusLine.showInfo(message); - } - - private void showStatus(String status) { - fStatusLine.showError(status); - } - - /** - * Starts the TestRunner - */ - public void start(String[] args) { - String suiteName= processArguments(args); - fFrame= createUI(suiteName); - fFrame.pack(); - fFrame.setVisible(true); - - if (suiteName != null) { - setSuite(suiteName); - runSuite(); - } - } - - private void start(final Test test) { - SwingUtilities.invokeLater( - new Runnable() { - public void run() { - int total= test.countTestCases(); - fProgressIndicator.start(total); - fCounterPanel.setTotal(total); - } - } - ); - } - - /** - * Wait until all the events are processed in the event thread - */ - private void synchUI() { - try { - SwingUtilities.invokeAndWait( - new Runnable() { - public void run() {} - } - ); - } - catch (Exception e) { - } - } - - /** - * Terminates the TestRunner - */ - public void terminate() { - fFrame.dispose(); - try { - saveHistory(); - } catch (IOException e) { - System.out.println("Couldn't save test run history"); - } - System.exit(0); - } - - public void textChanged() { - fRun.setEnabled(getSuiteText().length() > 0); - clearStatus(); - } - - protected void clearStatus() { - fStatusLine.clear(); - } - - public static Icon getIconResource(Class clazz, String name) { - URL url= clazz.getResource(name); - if (url == null) { - System.err.println("Warning: could not load \""+name+"\" icon"); - return null; - } - return new ImageIcon(url); - } - - private void about() { - AboutDialog about= new AboutDialog(fFrame); - about.show(); - } -} diff --git a/junit/swingui/TestSelector.java b/junit/swingui/TestSelector.java deleted file mode 100644 index f0f1f9ee91b5..000000000000 --- a/junit/swingui/TestSelector.java +++ /dev/null @@ -1,285 +0,0 @@ -package junit.swingui; - -import java.awt.Component; -import java.awt.Cursor; -import java.awt.Dimension; -import java.awt.Frame; -import java.awt.GridBagConstraints; -import java.awt.GridBagLayout; -import java.awt.Insets; -import java.awt.Toolkit; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.KeyAdapter; -import java.awt.event.KeyEvent; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; -import java.awt.event.WindowAdapter; -import java.awt.event.WindowEvent; -import java.util.Enumeration; -import java.util.Vector; - -import javax.swing.DefaultListCellRenderer; -import javax.swing.Icon; -import javax.swing.JButton; -import javax.swing.JDialog; -import javax.swing.JLabel; -import javax.swing.JList; -import javax.swing.JScrollPane; -import javax.swing.ListModel; -import javax.swing.ListSelectionModel; -import javax.swing.UIManager; -import javax.swing.event.ListSelectionEvent; -import javax.swing.event.ListSelectionListener; - -import junit.runner.Sorter; -import junit.runner.TestCollector; - -/** - * A test class selector. A simple dialog to pick the name of a test suite. - */ -public class TestSelector extends JDialog { - private JButton fCancel; - private JButton fOk; - private JList fList; - private JScrollPane fScrolledList; - private JLabel fDescription; - private String fSelectedItem; - - /** - * Renders TestFailures in a JList - */ - static class TestCellRenderer extends DefaultListCellRenderer { - Icon fLeafIcon; - Icon fSuiteIcon; - - public TestCellRenderer() { - fLeafIcon= UIManager.getIcon("Tree.leafIcon"); - fSuiteIcon= UIManager.getIcon("Tree.closedIcon"); - } - - public Component getListCellRendererComponent( - JList list, Object value, int modelIndex, - boolean isSelected, boolean cellHasFocus) { - Component c= super.getListCellRendererComponent(list, value, modelIndex, isSelected, cellHasFocus); - String displayString= displayString((String)value); - - if (displayString.startsWith("AllTests")) - setIcon(fSuiteIcon); - else - setIcon(fLeafIcon); - - setText(displayString); - return c; - } - - public static String displayString(String className) { - int typeIndex= className.lastIndexOf('.'); - if (typeIndex < 0) - return className; - return className.substring(typeIndex+1) + " - " + className.substring(0, typeIndex); - } - - public static boolean matchesKey(String s, char ch) { - return ch == Character.toUpperCase(s.charAt(typeIndex(s))); - } - - private static int typeIndex(String s) { - int typeIndex= s.lastIndexOf('.'); - int i= 0; - if (typeIndex > 0) - i= typeIndex+1; - return i; - } - } - - protected class DoubleClickListener extends MouseAdapter { - public void mouseClicked(MouseEvent e) { - if (e.getClickCount() == 2) { - okSelected(); - } - } - } - - protected class KeySelectListener extends KeyAdapter { - public void keyTyped(KeyEvent e) { - keySelectTestClass(e.getKeyChar()); - } - } - - public TestSelector(Frame parent, TestCollector testCollector) { - super(parent, true); - setSize(350, 300); - setResizable(false); - // setLocationRelativeTo only exists in 1.4 - try { - setLocationRelativeTo(parent); - } catch (NoSuchMethodError e) { - centerWindow(this); - } - setTitle("Test Selector"); - - Vector list= null; - try { - parent.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); - list= createTestList(testCollector); - } finally { - parent.setCursor(Cursor.getDefaultCursor()); - } - fList= new JList(list); - fList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); - fList.setCellRenderer(new TestCellRenderer()); - fScrolledList= new JScrollPane(fList); - - fCancel= new JButton("Cancel"); - fDescription= new JLabel("Select the Test class:"); - fOk= new JButton("OK"); - fOk.setEnabled(false); - getRootPane().setDefaultButton(fOk); - - defineLayout(); - addListeners(); - } - - public static void centerWindow(Component c) { - Dimension paneSize= c.getSize(); - Dimension screenSize= c.getToolkit().getScreenSize(); - c.setLocation((screenSize.width-paneSize.width)/2, (screenSize.height-paneSize.height)/2); - } - - private void addListeners() { - fCancel.addActionListener( - new ActionListener() { - public void actionPerformed(ActionEvent e) { - dispose(); - } - } - ); - - fOk.addActionListener( - new ActionListener() { - public void actionPerformed(ActionEvent e) { - okSelected(); - } - } - ); - - fList.addMouseListener(new DoubleClickListener()); - fList.addKeyListener(new KeySelectListener()); - fList.addListSelectionListener( - new ListSelectionListener() { - public void valueChanged(ListSelectionEvent e) { - checkEnableOK(e); - } - } - ); - - addWindowListener( - new WindowAdapter() { - public void windowClosing(WindowEvent e) { - dispose(); - } - } - ); - } - - private void defineLayout() { - getContentPane().setLayout(new GridBagLayout()); - GridBagConstraints labelConstraints = new GridBagConstraints(); - labelConstraints.gridx= 0; labelConstraints.gridy= 0; - labelConstraints.gridwidth= 1; labelConstraints.gridheight= 1; - labelConstraints.fill= GridBagConstraints.BOTH; - labelConstraints.anchor= GridBagConstraints.WEST; - labelConstraints.weightx= 1.0; - labelConstraints.weighty= 0.0; - labelConstraints.insets= new Insets(8, 8, 0, 8); - getContentPane().add(fDescription, labelConstraints); - - GridBagConstraints listConstraints = new GridBagConstraints(); - listConstraints.gridx= 0; listConstraints.gridy= 1; - listConstraints.gridwidth= 4; listConstraints.gridheight= 1; - listConstraints.fill= GridBagConstraints.BOTH; - listConstraints.anchor= GridBagConstraints.CENTER; - listConstraints.weightx= 1.0; - listConstraints.weighty= 1.0; - listConstraints.insets= new Insets(8, 8, 8, 8); - getContentPane().add(fScrolledList, listConstraints); - - GridBagConstraints okConstraints= new GridBagConstraints(); - okConstraints.gridx= 2; okConstraints.gridy= 2; - okConstraints.gridwidth= 1; okConstraints.gridheight= 1; - okConstraints.anchor= java.awt.GridBagConstraints.EAST; - okConstraints.insets= new Insets(0, 8, 8, 8); - getContentPane().add(fOk, okConstraints); - - - GridBagConstraints cancelConstraints = new GridBagConstraints(); - cancelConstraints.gridx= 3; cancelConstraints.gridy= 2; - cancelConstraints.gridwidth= 1; cancelConstraints.gridheight= 1; - cancelConstraints.anchor= java.awt.GridBagConstraints.EAST; - cancelConstraints.insets= new Insets(0, 8, 8, 8); - getContentPane().add(fCancel, cancelConstraints); - } - - public void checkEnableOK(ListSelectionEvent e) { - fOk.setEnabled(fList.getSelectedIndex() != -1); - } - - public void okSelected() { - fSelectedItem= (String)fList.getSelectedValue(); - dispose(); - } - - public boolean isEmpty() { - return fList.getModel().getSize() == 0; - } - - public void keySelectTestClass(char ch) { - ListModel model= fList.getModel(); - if (!Character.isJavaIdentifierStart(ch)) - return; - for (int i= 0; i < model.getSize(); i++) { - String s= (String)model.getElementAt(i); - if (TestCellRenderer.matchesKey(s, Character.toUpperCase(ch))) { - fList.setSelectedIndex(i); - fList.ensureIndexIsVisible(i); - return; - } - } - Toolkit.getDefaultToolkit().beep(); - } - - public String getSelectedItem() { - return fSelectedItem; - } - - private Vector createTestList(TestCollector collector) { - Enumeration each= collector.collectTests(); - Vector v= new Vector(200); - Vector displayVector= new Vector(v.size()); - while(each.hasMoreElements()) { - String s= (String)each.nextElement(); - v.addElement(s); - displayVector.addElement(TestCellRenderer.displayString(s)); - } - if (v.size() > 0) - Sorter.sortStrings(displayVector, 0, displayVector.size()-1, new ParallelSwapper(v)); - return v; - } - - private class ParallelSwapper implements Sorter.Swapper { - Vector fOther; - - ParallelSwapper(Vector other) { - fOther= other; - } - public void swap(Vector values, int left, int right) { - Object tmp= values.elementAt(left); - values.setElementAt(values.elementAt(right), left); - values.setElementAt(tmp, right); - Object tmp2= fOther.elementAt(left); - fOther.setElementAt(fOther.elementAt(right), left); - fOther.setElementAt(tmp2, right); - } - } -} \ No newline at end of file diff --git a/junit/swingui/TestSuitePanel.java b/junit/swingui/TestSuitePanel.java deleted file mode 100644 index d8902ad39cb2..000000000000 --- a/junit/swingui/TestSuitePanel.java +++ /dev/null @@ -1,172 +0,0 @@ -package junit.swingui; - -import java.awt.BorderLayout; -import java.awt.Component; -import java.awt.Dimension; -import java.util.Vector; - -import javax.swing.Icon; -import javax.swing.JComponent; -import javax.swing.JPanel; -import javax.swing.JScrollPane; -import javax.swing.JTree; -import javax.swing.SwingUtilities; -import javax.swing.ToolTipManager; -import javax.swing.tree.DefaultTreeCellRenderer; -import javax.swing.tree.TreeModel; -import javax.swing.tree.TreePath; - -import junit.framework.AssertionFailedError; -import junit.framework.Test; -import junit.framework.TestListener; - -/** - * A Panel showing a test suite as a tree. - */ -class TestSuitePanel extends JPanel implements TestListener { - private JTree fTree; - private JScrollPane fScrollTree; - private TestTreeModel fModel; - - static class TestTreeCellRenderer extends DefaultTreeCellRenderer { - private Icon fErrorIcon; - private Icon fOkIcon; - private Icon fFailureIcon; - - TestTreeCellRenderer() { - super(); - loadIcons(); - } - - void loadIcons() { - fErrorIcon= TestRunner.getIconResource(getClass(), "icons/error.gif"); - fOkIcon= TestRunner.getIconResource(getClass(), "icons/ok.gif"); - fFailureIcon= TestRunner.getIconResource(getClass(), "icons/failure.gif"); - } - - String stripParenthesis(Object o) { - String text= o.toString (); - int pos= text.indexOf('('); - if (pos < 1) - return text; - return text.substring (0, pos); - } - - public Component getTreeCellRendererComponent(JTree tree, Object value, - boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) { - - Component c= super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus); - TreeModel model= tree.getModel(); - if (model instanceof TestTreeModel) { - TestTreeModel testModel= (TestTreeModel)model; - Test t= (Test)value; - String s= ""; - if (testModel.isFailure(t)) { - if (fFailureIcon != null) - setIcon(fFailureIcon); - s= " - Failed"; - } - else if (testModel.isError(t)) { - if (fErrorIcon != null) - setIcon(fErrorIcon); - s= " - Error"; - } - else if (testModel.wasRun(t)) { - if (fOkIcon != null) - setIcon(fOkIcon); - s= " - Passed"; - } - if (c instanceof JComponent) - ((JComponent)c).setToolTipText(getText()+s); - } - setText(stripParenthesis(value)); - return c; - } - } - - public TestSuitePanel() { - super(new BorderLayout()); - setPreferredSize(new Dimension(300, 100)); - fTree= new JTree(); - fTree.setModel(null); - fTree.setRowHeight(20); - ToolTipManager.sharedInstance().registerComponent(fTree); - fTree.putClientProperty("JTree.lineStyle", "Angled"); - fScrollTree= new JScrollPane(fTree); - add(fScrollTree, BorderLayout.CENTER); - } - - public void addError(final Test test, final Throwable t) { - fModel.addError(test); - fireTestChanged(test, true); - } - - public void addFailure(final Test test, final AssertionFailedError t) { - fModel.addFailure(test); - fireTestChanged(test, true); - } - - /** - * A test ended. - */ - public void endTest(Test test) { - fModel.addRunTest(test); - fireTestChanged(test, false); - } - - /** - * A test started. - */ - public void startTest(Test test) { - } - - /** - * Returns the selected test or null if multiple or none is selected - */ - public Test getSelectedTest() { - TreePath[] paths= fTree.getSelectionPaths(); - if (paths != null && paths.length == 1) - return (Test)paths[0].getLastPathComponent(); - return null; - } - - /** - * Returns the Tree - */ - public JTree getTree() { - return fTree; - } - - /** - * Shows the test hierarchy starting at the given test - */ - public void showTestTree(Test root) { - fModel= new TestTreeModel(root); - fTree.setModel(fModel); - fTree.setCellRenderer(new TestTreeCellRenderer()); - } - - private void fireTestChanged(final Test test, final boolean expand) { - SwingUtilities.invokeLater( - new Runnable() { - public void run() { - Vector vpath= new Vector(); - int index= fModel.findTest(test, (Test)fModel.getRoot(), vpath); - if (index >= 0) { - Object[] path= new Object[vpath.size()]; - vpath.copyInto(path); - TreePath treePath= new TreePath(path); - fModel.fireNodeChanged(treePath, index); - if (expand) { - Object[] fullPath= new Object[vpath.size()+1]; - vpath.copyInto(fullPath); - fullPath[vpath.size()]= fModel.getChild(treePath.getLastPathComponent(), index);; - TreePath fullTreePath= new TreePath(fullPath); - fTree.scrollPathToVisible(fullTreePath); - } - } - } - } - ); - } -} \ No newline at end of file diff --git a/junit/swingui/TestTreeModel.java b/junit/swingui/TestTreeModel.java deleted file mode 100644 index 9f3b0d3ec0be..000000000000 --- a/junit/swingui/TestTreeModel.java +++ /dev/null @@ -1,190 +0,0 @@ -package junit.swingui; - -import java.util.Enumeration; -import java.util.Hashtable; -import java.util.Vector; - -import javax.swing.event.TreeModelEvent; -import javax.swing.event.TreeModelListener; -import javax.swing.tree.TreeModel; -import javax.swing.tree.TreePath; - -import junit.extensions.TestDecorator; -import junit.framework.Test; -import junit.framework.TestSuite; - -/** - * A tree model for a Test. - */ -class TestTreeModel implements TreeModel { - private Test fRoot; - private Vector fModelListeners= new Vector(); - private Hashtable fFailures= new Hashtable(); - private Hashtable fErrors= new Hashtable(); - private Hashtable fRunTests= new Hashtable(); - - /** - * Constructs a tree model with the given test as its root. - */ - public TestTreeModel(Test root) { - super(); - fRoot= root; - } - - /** - * adds a TreeModelListener - */ - public void addTreeModelListener(TreeModelListener l) { - if (!fModelListeners.contains(l)) - fModelListeners.addElement(l); - } - /** - * Removes a TestModelListener - */ - public void removeTreeModelListener(TreeModelListener l) { - fModelListeners.removeElement(l); - } - /** - * Finds the path to a test. Returns the index of the test in its - * parent test suite. - */ - public int findTest(Test target, Test node, Vector path) { - if (target.equals(node)) - return 0; - - TestSuite suite= isTestSuite(node); - for (int i= 0; i < getChildCount(node); i++) { - Test t= suite.testAt(i); - int index= findTest(target, t, path); - if (index >= 0) { - path.insertElementAt(node, 0); - if (path.size() == 1) - return i; - return index; - } - } - return -1; - } - /** - * Fires a node changed event - */ - public void fireNodeChanged(TreePath path, int index) { - int[] indices= {index}; - Object[] changedChildren= {getChild(path.getLastPathComponent(), index)}; - TreeModelEvent event= new TreeModelEvent(this, path, indices, changedChildren); - - Enumeration e= fModelListeners.elements(); - while (e.hasMoreElements()) { - TreeModelListener l= (TreeModelListener) e.nextElement(); - l.treeNodesChanged(event); - } - } - /** - * Gets the test at the given index - */ - public Object getChild(Object parent, int index) { - TestSuite suite= isTestSuite(parent); - if (suite != null) - return suite.testAt(index); - return null; - } - /** - * Gets the number of tests. - */ - public int getChildCount(Object parent) { - TestSuite suite= isTestSuite(parent); - if (suite != null) - return suite.testCount(); - return 0; - } - /** - * Gets the index of a test in a test suite - */ - public int getIndexOfChild(Object parent, Object child) { - TestSuite suite= isTestSuite(parent); - if (suite != null) { - int i= 0; - for (Enumeration e= suite.tests(); e.hasMoreElements(); i++) { - if (child.equals(e.nextElement())) - return i; - } - } - return -1; - } - /** - * Returns the root of the tree - */ - public Object getRoot() { - return fRoot; - } - /** - * Tests if the test is a leaf. - */ - public boolean isLeaf(Object node) { - return isTestSuite(node) == null; - } - /** - * Tests if the node is a TestSuite. - */ - TestSuite isTestSuite(Object node) { - if (node instanceof TestSuite) - return (TestSuite)node; - if (node instanceof TestDecorator) { - Test baseTest= ((TestDecorator)node).getTest(); - return isTestSuite(baseTest); - } - return null; - } - - /** - * Called when the value of the model object was changed in the view - */ - public void valueForPathChanged(TreePath path, Object newValue) { - // we don't support direct editing of the model - System.out.println("TreeModel.valueForPathChanged: not implemented"); - } - /** - * Remembers a test failure - */ - void addFailure(Test t) { - fFailures.put(t, t); - } - /** - * Remembers a test error - */ - void addError(Test t) { - fErrors.put(t, t); - } - /** - * Remembers that a test was run - */ - void addRunTest(Test t) { - fRunTests.put(t, t); - } - /** - * Returns whether a test was run - */ - boolean wasRun(Test t) { - return fRunTests.get(t) != null; - } - /** - * Tests whether a test was an error - */ - boolean isError(Test t) { - return (fErrors != null) && fErrors.get(t) != null; - } - /** - * Tests whether a test was a failure - */ - boolean isFailure(Test t) { - return (fFailures != null) && fFailures.get(t) != null; - } - /** - * Resets the test results - */ - void resetResults() { - fFailures= new Hashtable(); - fRunTests= new Hashtable(); - fErrors= new Hashtable(); - } -} \ No newline at end of file diff --git a/junit/swingui/icons/error.gif b/junit/swingui/icons/error.gif deleted file mode 100644 index fe13a6a58a3f..000000000000 Binary files a/junit/swingui/icons/error.gif and /dev/null differ diff --git a/junit/swingui/icons/failure.gif b/junit/swingui/icons/failure.gif deleted file mode 100644 index 156ecd68e333..000000000000 Binary files a/junit/swingui/icons/failure.gif and /dev/null differ diff --git a/junit/swingui/icons/hierarchy.gif b/junit/swingui/icons/hierarchy.gif deleted file mode 100644 index 9f05ed2c5b11..000000000000 Binary files a/junit/swingui/icons/hierarchy.gif and /dev/null differ diff --git a/junit/swingui/icons/ok.gif b/junit/swingui/icons/ok.gif deleted file mode 100644 index 034825b8132b..000000000000 Binary files a/junit/swingui/icons/ok.gif and /dev/null differ diff --git a/junit/tests/AllTests.java b/junit/tests/AllTests.java deleted file mode 100644 index 00bbe562a92f..000000000000 --- a/junit/tests/AllTests.java +++ /dev/null @@ -1,23 +0,0 @@ -package junit.tests; - -import junit.framework.Test; -import junit.framework.TestSuite; - -/** - * TestSuite that runs all the JUnit tests - * - */ -public class AllTests { - - public static void main(String[] args) { - junit.textui.TestRunner.run(suite()); - } - - public static Test suite() { - TestSuite suite= new TestSuite("Framework Tests"); - suite.addTest(junit.tests.framework.AllTests.suite()); - suite.addTest(junit.tests.runner.AllTests.suite()); - suite.addTest(junit.tests.extensions.AllTests.suite()); - return suite; - } -} \ No newline at end of file diff --git a/junit/tests/extensions/ActiveTestTest.java b/junit/tests/extensions/ActiveTestTest.java deleted file mode 100644 index dc7cb9866c31..000000000000 --- a/junit/tests/extensions/ActiveTestTest.java +++ /dev/null @@ -1,63 +0,0 @@ -package junit.tests.extensions; - -import junit.extensions.ActiveTestSuite; -import junit.extensions.RepeatedTest; -import junit.framework.Test; -import junit.framework.TestCase; -import junit.framework.TestResult; - -/** - * Testing the ActiveTest support - */ - -public class ActiveTestTest extends TestCase { - - public static class SuccessTest extends TestCase { - public void runTest() { - } - } - - public void testActiveTest() { - Test test= createActiveTestSuite(); - TestResult result= new TestResult(); - test.run(result); - assertEquals(100, result.runCount()); - assertEquals(0, result.failureCount()); - assertEquals(0, result.errorCount()); - } - - public void testActiveRepeatedTest() { - Test test= new RepeatedTest(createActiveTestSuite(), 5); - TestResult result= new TestResult(); - test.run(result); - assertEquals(500, result.runCount()); - assertEquals(0, result.failureCount()); - assertEquals(0, result.errorCount()); - } - - public void testActiveRepeatedTest0() { - Test test= new RepeatedTest(createActiveTestSuite(), 0); - TestResult result= new TestResult(); - test.run(result); - assertEquals(0, result.runCount()); - assertEquals(0, result.failureCount()); - assertEquals(0, result.errorCount()); - } - - public void testActiveRepeatedTest1() { - Test test= new RepeatedTest(createActiveTestSuite(), 1); - TestResult result= new TestResult(); - test.run(result); - assertEquals(100, result.runCount()); - assertEquals(0, result.failureCount()); - assertEquals(0, result.errorCount()); - } - - ActiveTestSuite createActiveTestSuite() { - ActiveTestSuite suite= new ActiveTestSuite(); - for (int i= 0; i < 100; i++) - suite.addTest(new SuccessTest()); - return suite; - } - -} \ No newline at end of file diff --git a/junit/tests/extensions/AllTests.java b/junit/tests/extensions/AllTests.java deleted file mode 100644 index 13083310715d..000000000000 --- a/junit/tests/extensions/AllTests.java +++ /dev/null @@ -1,24 +0,0 @@ -package junit.tests.extensions; - -import junit.framework.Test; -import junit.framework.TestSuite; - -/** - * TestSuite that runs all the extension tests - * - */ -public class AllTests { - - public static void main(String[] args) { - junit.textui.TestRunner.run(suite()); - } - - public static Test suite() { // Collect tests manually because we have to test class collection code - TestSuite suite= new TestSuite("Framework Tests"); - suite.addTestSuite(ExtensionTest.class); - suite.addTestSuite(ExceptionTestCaseTest.class); - suite.addTestSuite(ActiveTestTest.class); - suite.addTestSuite(RepeatedTestTest.class); - return suite; - } -} \ No newline at end of file diff --git a/junit/tests/extensions/ExceptionTestCaseTest.java b/junit/tests/extensions/ExceptionTestCaseTest.java deleted file mode 100644 index 134d639d1450..000000000000 --- a/junit/tests/extensions/ExceptionTestCaseTest.java +++ /dev/null @@ -1,64 +0,0 @@ -package junit.tests.extensions; - -import junit.extensions.ExceptionTestCase; -import junit.framework.TestResult; - -public class ExceptionTestCaseTest extends junit.framework.TestCase { - - static public class ThrowExceptionTestCase extends ExceptionTestCase { - public ThrowExceptionTestCase(String name, Class exception) { - super(name, exception); - } - public void test() { - throw new IndexOutOfBoundsException(); - } - } - - static public class ThrowRuntimeExceptionTestCase extends ExceptionTestCase { - public ThrowRuntimeExceptionTestCase(String name, Class exception) { - super(name, exception); - } - public void test() { - throw new RuntimeException(); - } - } - - static public class ThrowNoExceptionTestCase extends ExceptionTestCase { - public ThrowNoExceptionTestCase(String name, Class exception) { - super(name, exception); - } - public void test() { - } - } - - public void testExceptionSubclass() { - ExceptionTestCase test= new ThrowExceptionTestCase("test", IndexOutOfBoundsException.class); - TestResult result= test.run(); - assertEquals(1, result.runCount()); - assertTrue(result.wasSuccessful()); - } - public void testExceptionTest() { - ExceptionTestCase test= new ThrowExceptionTestCase("test", IndexOutOfBoundsException.class); - TestResult result= test.run(); - assertEquals(1, result.runCount()); - assertTrue(result.wasSuccessful()); - } - public void testFailure() { - ExceptionTestCase test= new ThrowRuntimeExceptionTestCase("test", IndexOutOfBoundsException.class); - TestResult result= test.run(); - assertEquals(1, result.runCount()); - assertEquals(1, result.errorCount()); - } - public void testNoException() { - ExceptionTestCase test= new ThrowNoExceptionTestCase("test", Exception.class); - TestResult result= test.run(); - assertEquals(1, result.runCount()); - assertEquals(1, result.failureCount()); - } - public void testWrongException() { - ExceptionTestCase test= new ThrowRuntimeExceptionTestCase("test", IndexOutOfBoundsException.class); - TestResult result= test.run(); - assertEquals(1, result.runCount()); - assertEquals(1, result.errorCount()); - } -} \ No newline at end of file diff --git a/junit/tests/extensions/ExtensionTest.java b/junit/tests/extensions/ExtensionTest.java deleted file mode 100644 index 0e59d8270327..000000000000 --- a/junit/tests/extensions/ExtensionTest.java +++ /dev/null @@ -1,92 +0,0 @@ -package junit.tests.extensions; - -import junit.extensions.TestSetup; -import junit.framework.Test; -import junit.framework.TestCase; -import junit.framework.TestResult; -import junit.framework.TestSuite; -import junit.tests.WasRun; - -/** - * A test case testing the extensions to the testing framework. - * - */ -public class ExtensionTest extends TestCase { - static class TornDown extends TestSetup { - boolean fTornDown= false; - - TornDown(Test test) { - super(test); - } - protected void tearDown() { - fTornDown= true; - } - } - public void testRunningErrorInTestSetup() { - TestCase test= new TestCase("failure") { - public void runTest() { - fail(); - } - }; - - TestSetup wrapper= new TestSetup(test); - - TestResult result= new TestResult(); - wrapper.run(result); - assertTrue(!result.wasSuccessful()); - } - public void testRunningErrorsInTestSetup() { - TestCase failure= new TestCase("failure") { - public void runTest() { - fail(); - } - }; - - TestCase error= new TestCase("error") { - public void runTest() { - throw new Error(); - } - }; - - TestSuite suite= new TestSuite(); - suite.addTest(failure); - suite.addTest(error); - - TestSetup wrapper= new TestSetup(suite); - - TestResult result= new TestResult(); - wrapper.run(result); - - assertEquals(1, result.failureCount()); - assertEquals(1, result.errorCount()); - } - public void testSetupErrorDontTearDown() { - WasRun test= new WasRun(); - - TornDown wrapper= new TornDown(test) { - public void setUp() { - fail(); - } - }; - - TestResult result= new TestResult(); - wrapper.run(result); - - assertTrue(!wrapper.fTornDown); - } - public void testSetupErrorInTestSetup() { - WasRun test= new WasRun(); - - TestSetup wrapper= new TestSetup(test) { - public void setUp() { - fail(); - } - }; - - TestResult result= new TestResult(); - wrapper.run(result); - - assertTrue(!test.fWasRun); - assertTrue(!result.wasSuccessful()); - } -} \ No newline at end of file diff --git a/junit/tests/extensions/RepeatedTestTest.java b/junit/tests/extensions/RepeatedTestTest.java deleted file mode 100644 index c47f0e24dc4d..000000000000 --- a/junit/tests/extensions/RepeatedTestTest.java +++ /dev/null @@ -1,61 +0,0 @@ -package junit.tests.extensions; - -import junit.extensions.RepeatedTest; -import junit.framework.Test; -import junit.framework.TestCase; -import junit.framework.TestResult; -import junit.framework.TestSuite; - -/** - * Testing the RepeatedTest support. - */ - -public class RepeatedTestTest extends TestCase { - private TestSuite fSuite; - - public static class SuccessTest extends TestCase { - - public void runTest() { - } - } - - public RepeatedTestTest(String name) { - super(name); - fSuite= new TestSuite(); - fSuite.addTest(new SuccessTest()); - fSuite.addTest(new SuccessTest()); - } - - public void testRepeatedOnce() { - Test test= new RepeatedTest(fSuite, 1); - assertEquals(2, test.countTestCases()); - TestResult result= new TestResult(); - test.run(result); - assertEquals(2, result.runCount()); - } - - public void testRepeatedMoreThanOnce() { - Test test= new RepeatedTest(fSuite, 3); - assertEquals(6, test.countTestCases()); - TestResult result= new TestResult(); - test.run(result); - assertEquals(6, result.runCount()); - } - - public void testRepeatedZero() { - Test test= new RepeatedTest(fSuite, 0); - assertEquals(0, test.countTestCases()); - TestResult result= new TestResult(); - test.run(result); - assertEquals(0, result.runCount()); - } - - public void testRepeatedNegative() { - try { - new RepeatedTest(fSuite, -1); - } catch (IllegalArgumentException e) { - return; - } - fail("Should throw an IllegalArgumentException"); - } -} \ No newline at end of file diff --git a/junit/tests/framework/AllTests.java b/junit/tests/framework/AllTests.java deleted file mode 100644 index 6b876afcd043..000000000000 --- a/junit/tests/framework/AllTests.java +++ /dev/null @@ -1,30 +0,0 @@ -package junit.tests.framework; - -import junit.framework.Test; -import junit.framework.TestSuite; - -/** - * TestSuite that runs all the sample tests - * - */ -public class AllTests { - - public static void main(String[] args) { - junit.textui.TestRunner.run(suite()); - } - - public static Test suite() { - TestSuite suite= new TestSuite("Framework Tests"); - suite.addTestSuite(TestCaseTest.class); - suite.addTest(SuiteTest.suite()); // Tests suite building, so can't use automatic test extraction - suite.addTestSuite(TestListenerTest.class); - suite.addTestSuite(AssertTest.class); - suite.addTestSuite(TestImplementorTest.class); - suite.addTestSuite(NoArgTestCaseTest.class); - suite.addTestSuite(ComparisonCompactorTest.class); - suite.addTestSuite(ComparisonFailureTest.class); - suite.addTestSuite(DoublePrecisionAssertTest.class); - return suite; - } - -} \ No newline at end of file diff --git a/junit/tests/framework/AssertTest.java b/junit/tests/framework/AssertTest.java deleted file mode 100644 index 27861b5cf9eb..000000000000 --- a/junit/tests/framework/AssertTest.java +++ /dev/null @@ -1,147 +0,0 @@ -package junit.tests.framework; - -import junit.framework.AssertionFailedError; -import junit.framework.ComparisonFailure; -import junit.framework.TestCase; - -public class AssertTest extends TestCase { - - /* In the tests that follow, we can't use standard formatting - * for exception tests: - * try { - * somethingThatShouldThrow(); - * fail(); - * catch (AssertionFailedError e) { - * } - * because fail() would never be reported. - */ - public void testFail() { - // Also, we are testing fail, so we can't rely on fail() working. - // We have to throw the exception manually, . - try { - fail(); - } catch (AssertionFailedError e) { - return; - } - throw new AssertionFailedError(); - } - - public void testAssertEquals() { - Object o= new Object(); - assertEquals(o, o); - try { - assertEquals(new Object(), new Object()); - } catch (AssertionFailedError e) { - return; - } - fail(); - } - - public void testAssertEqualsNull() { - assertEquals(null, null); - } - - public void testAssertStringEquals() { - assertEquals("a", "a"); - } - - public void testAssertNullNotEqualsString() { - try { - assertEquals(null, "foo"); - fail(); - } catch (ComparisonFailure e) { - } - } - - public void testAssertStringNotEqualsNull() { - try { - assertEquals("foo", null); - fail(); - } catch (ComparisonFailure e) { - e.getMessage(); // why no assertion? - } - } - - public void testAssertNullNotEqualsNull() { - try { - assertEquals(null, new Object()); - } catch (AssertionFailedError e) { - e.getMessage(); // why no assertion? - return; - } - fail(); - } - - public void testAssertNull() { - assertNull(null); - try { - assertNull(new Object()); - } catch (AssertionFailedError e) { - return; - } - fail(); - } - - public void testAssertNotNull() { - assertNotNull(new Object()); - try { - assertNotNull(null); - } catch (AssertionFailedError e) { - return; - } - fail(); - } - - public void testAssertTrue() { - assertTrue(true); - try { - assertTrue(false); - } catch (AssertionFailedError e) { - return; - } - fail(); - } - - public void testAssertFalse() { - assertFalse(false); - try { - assertFalse(true); - } catch (AssertionFailedError e) { - return; - } - fail(); - } - - public void testAssertSame() { - Object o= new Object(); - assertSame(o, o); - try { - assertSame(new Integer(1), new Integer(1)); - } catch (AssertionFailedError e) { - return; - } - fail(); - } - - public void testAssertNotSame() { - assertNotSame(new Integer(1), null); - assertNotSame(null, new Integer(1)); - assertNotSame(new Integer(1), new Integer(1)); - try { - Integer obj= new Integer(1); - assertNotSame(obj, obj); - } catch (AssertionFailedError e) { - return; - } - fail(); - } - - public void testAssertNotSameFailsNull() { - try { - assertNotSame(null, null); - } catch (AssertionFailedError e) { - return; - } - fail(); - } -} \ No newline at end of file diff --git a/junit/tests/framework/ComparisonCompactorTest.java b/junit/tests/framework/ComparisonCompactorTest.java deleted file mode 100644 index 6edaefe2c231..000000000000 --- a/junit/tests/framework/ComparisonCompactorTest.java +++ /dev/null @@ -1,102 +0,0 @@ -package junit.tests.framework; - -import junit.framework.ComparisonCompactor; -import junit.framework.TestCase; - -public class ComparisonCompactorTest extends TestCase { - - public void testMessage() { - String failure= new ComparisonCompactor(0, "b", "c").compact("a"); - assertTrue("a expected:<[b]> but was:<[c]>".equals(failure)); - } - - public void testStartSame() { - String failure= new ComparisonCompactor(1, "ba", "bc").compact(null); - assertEquals("expected: but was:", failure); - } - - public void testEndSame() { - String failure= new ComparisonCompactor(1, "ab", "cb").compact(null); - assertEquals("expected:<[a]b> but was:<[c]b>", failure); - } - - public void testSame() { - String failure= new ComparisonCompactor(1, "ab", "ab").compact(null); - assertEquals("expected: but was:", failure); - } - - public void testNoContextStartAndEndSame() { - String failure= new ComparisonCompactor(0, "abc", "adc").compact(null); - assertEquals("expected:<...[b]...> but was:<...[d]...>", failure); - } - - public void testStartAndEndContext() { - String failure= new ComparisonCompactor(1, "abc", "adc").compact(null); - assertEquals("expected: but was:", failure); - } - - public void testStartAndEndContextWithEllipses() { - String failure= new ComparisonCompactor(1, "abcde", "abfde").compact(null); - assertEquals("expected:<...b[c]d...> but was:<...b[f]d...>", failure); - } - - public void testComparisonErrorStartSameComplete() { - String failure= new ComparisonCompactor(2, "ab", "abc").compact(null); - assertEquals("expected: but was:", failure); - } - - public void testComparisonErrorEndSameComplete() { - String failure= new ComparisonCompactor(0, "bc", "abc").compact(null); - assertEquals("expected:<[]...> but was:<[a]...>", failure); - } - - public void testComparisonErrorEndSameCompleteContext() { - String failure= new ComparisonCompactor(2, "bc", "abc").compact(null); - assertEquals("expected:<[]bc> but was:<[a]bc>", failure); - } - - public void testComparisonErrorOverlapingMatches() { - String failure= new ComparisonCompactor(0, "abc", "abbc").compact(null); - assertEquals("expected:<...[]...> but was:<...[b]...>", failure); - } - - public void testComparisonErrorOverlapingMatchesContext() { - String failure= new ComparisonCompactor(2, "abc", "abbc").compact(null); - assertEquals("expected: but was:", failure); - } - - public void testComparisonErrorOverlapingMatches2() { - String failure= new ComparisonCompactor(0, "abcdde", "abcde").compact(null); - assertEquals("expected:<...[d]...> but was:<...[]...>", failure); - } - - public void testComparisonErrorOverlapingMatches2Context() { - String failure= new ComparisonCompactor(2, "abcdde", "abcde").compact(null); - assertEquals("expected:<...cd[d]e> but was:<...cd[]e>", failure); - } - - public void testComparisonErrorWithActualNull() { - String failure= new ComparisonCompactor(0, "a", null).compact(null); - assertEquals("expected: but was:", failure); - } - - public void testComparisonErrorWithActualNullContext() { - String failure= new ComparisonCompactor(2, "a", null).compact(null); - assertEquals("expected: but was:", failure); - } - - public void testComparisonErrorWithExpectedNull() { - String failure= new ComparisonCompactor(0, null, "a").compact(null); - assertEquals("expected: but was:", failure); - } - - public void testComparisonErrorWithExpectedNullContext() { - String failure= new ComparisonCompactor(2, null, "a").compact(null); - assertEquals("expected: but was:", failure); - } - - public void testBug609972() { - String failure= new ComparisonCompactor(10, "S&P500", "0").compact(null); - assertEquals("expected:<[S&P50]0> but was:<[]0>", failure); - } -} diff --git a/junit/tests/framework/ComparisonFailureTest.java b/junit/tests/framework/ComparisonFailureTest.java deleted file mode 100644 index 13c19b7a4ecd..000000000000 --- a/junit/tests/framework/ComparisonFailureTest.java +++ /dev/null @@ -1,23 +0,0 @@ -package junit.tests.framework; - -import junit.framework.ComparisonFailure; -import junit.framework.TestCase; - -public class ComparisonFailureTest extends TestCase { - - // Most of the tests are in ComparisonCompactorTest - public void testConnection() { - ComparisonFailure failure= new ComparisonFailure("warning", "Mary had a little lamb", "Mary had the little lamb"); - assertEquals("warning expected: but was:", failure.getMessage()); - } - - // This is like an instanceof test. - public void testThrowing() { - try { - assertEquals("a", "b"); - } catch (ComparisonFailure e) { - return; - } - fail(); - } -} diff --git a/junit/tests/framework/DoublePrecisionAssertTest.java b/junit/tests/framework/DoublePrecisionAssertTest.java deleted file mode 100644 index 0701e70b40e0..000000000000 --- a/junit/tests/framework/DoublePrecisionAssertTest.java +++ /dev/null @@ -1,59 +0,0 @@ -package junit.tests.framework; - -import junit.framework.AssertionFailedError; -import junit.framework.TestCase; - -public class DoublePrecisionAssertTest extends TestCase { - - /** - * Test for the special Double.NaN value. - */ - public void testAssertEqualsNaNFails() { - try { - assertEquals(1.234, Double.NaN, 0.0); - } catch (AssertionFailedError e) { - return; - } - fail(); - } - - public void testAssertNaNEqualsFails() { - try { - assertEquals(Double.NaN, 1.234, 0.0); - } catch (AssertionFailedError e) { - return; - } - fail(); - } - - public void testAssertNaNEqualsNaN() { - assertEquals(Double.NaN, Double.NaN, 0.0); - } - - public void testAssertPosInfinityNotEqualsNegInfinity() { - try { - assertEquals(Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY, 0.0); - } catch (AssertionFailedError e) { - return; - } - fail(); - } - - public void testAssertPosInfinityNotEquals() { - try { - assertEquals(Double.POSITIVE_INFINITY, 1.23, 0.0); - } catch (AssertionFailedError e) { - return; - } - fail(); - } - - public void testAssertPosInfinityEqualsInfinity() { - assertEquals(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, 0.0); - } - - public void testAssertNegInfinityEqualsInfinity() { - assertEquals(Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY, 0.0); - } - -} diff --git a/junit/tests/framework/InheritedTestCase.java b/junit/tests/framework/InheritedTestCase.java deleted file mode 100644 index f272d77e8a59..000000000000 --- a/junit/tests/framework/InheritedTestCase.java +++ /dev/null @@ -1,9 +0,0 @@ -package junit.tests.framework; - -/** - * Test class used in SuiteTest - */ -public class InheritedTestCase extends OneTestCase { - public void test2() { - } -} \ No newline at end of file diff --git a/junit/tests/framework/SuiteTest.java b/junit/tests/framework/SuiteTest.java deleted file mode 100644 index f363670f4031..000000000000 --- a/junit/tests/framework/SuiteTest.java +++ /dev/null @@ -1,98 +0,0 @@ -package junit.tests.framework; - -import junit.framework.Test; -import junit.framework.TestCase; -import junit.framework.TestResult; -import junit.framework.TestSuite; - -/** - * A fixture for testing the "auto" test suite feature. - * - */ -public class SuiteTest extends TestCase { - protected TestResult fResult; - public SuiteTest(String name) { - super(name); - } - protected void setUp() { - fResult= new TestResult(); - } - public static Test suite() { - TestSuite suite= new TestSuite("Suite Tests"); - // build the suite manually, because some of the suites are testing - // the functionality that automatically builds suites - suite.addTest(new SuiteTest("testNoTestCaseClass")); - suite.addTest(new SuiteTest("testNoTestCases")); - suite.addTest(new SuiteTest("testOneTestCase")); - suite.addTest(new SuiteTest("testNotPublicTestCase")); - suite.addTest(new SuiteTest("testNotVoidTestCase")); - suite.addTest(new SuiteTest("testNotExistingTestCase")); - suite.addTest(new SuiteTest("testInheritedTests")); - suite.addTest(new SuiteTest("testShadowedTests")); - suite.addTest(new SuiteTest("testAddTestSuite")); - suite.addTest(new SuiteTest("testCreateSuiteFromArray")); - - return suite; - } - public void testInheritedTests() { - TestSuite suite= new TestSuite(InheritedTestCase.class); - suite.run(fResult); - assertTrue(fResult.wasSuccessful()); - assertEquals(2, fResult.runCount()); - } - public void testNoTestCaseClass() { - Test t= new TestSuite(NoTestCaseClass.class); - t.run(fResult); - assertEquals(1, fResult.runCount()); // warning test - assertTrue(! fResult.wasSuccessful()); - } - public void testNoTestCases() { - Test t= new TestSuite(NoTestCases.class); - t.run(fResult); - assertTrue(fResult.runCount() == 1); // warning test - assertTrue(fResult.failureCount() == 1); - assertTrue(! fResult.wasSuccessful()); - } - public void testNotExistingTestCase() { - Test t= new SuiteTest("notExistingMethod"); - t.run(fResult); - assertTrue(fResult.runCount() == 1); - assertTrue(fResult.failureCount() == 1); - assertTrue(fResult.errorCount() == 0); - } - public void testNotPublicTestCase() { - TestSuite suite= new TestSuite(NotPublicTestCase.class); - // 1 public test case + 1 warning for the non-public test case - assertEquals(2, suite.countTestCases()); - } - public void testNotVoidTestCase() { - TestSuite suite= new TestSuite(NotVoidTestCase.class); - assertTrue(suite.countTestCases() == 1); - } - public void testOneTestCase() { - Test t= new TestSuite(OneTestCase.class); - t.run(fResult); - assertTrue(fResult.runCount() == 1); - assertTrue(fResult.failureCount() == 0); - assertTrue(fResult.errorCount() == 0); - assertTrue(fResult.wasSuccessful()); - } - public void testShadowedTests() { - TestSuite suite= new TestSuite(OverrideTestCase.class); - suite.run(fResult); - assertEquals(1, fResult.runCount()); - } - public void testAddTestSuite() { - TestSuite suite= new TestSuite(); - suite.addTestSuite(OneTestCase.class); - suite.run(fResult); - assertEquals(1, fResult.runCount()); - } - public void testCreateSuiteFromArray() { - Class[] testClassArray = { OneTestCase.class, DoublePrecisionAssertTest.class }; - TestSuite suite = new TestSuite(testClassArray); - assertEquals(2, suite.testCount()); - assertEquals("junit.tests.framework.DoublePrecisionAssertTest" , ((TestSuite)suite.testAt(1)).getName()); - assertEquals("junit.tests.framework.OneTestCase" , ((TestSuite)suite.testAt(0)).getName()); - } -} \ No newline at end of file diff --git a/junit/tests/framework/TestCaseTest.java b/junit/tests/framework/TestCaseTest.java deleted file mode 100644 index 5d40fa0a01ce..000000000000 --- a/junit/tests/framework/TestCaseTest.java +++ /dev/null @@ -1,179 +0,0 @@ -package junit.tests.framework; - -import junit.framework.AssertionFailedError; -import junit.framework.Test; -import junit.framework.TestCase; -import junit.framework.TestFailure; -import junit.framework.TestResult; -import junit.framework.TestSuite; -import junit.tests.WasRun; - -/** - * A test case testing the testing framework. - * - */ -public class TestCaseTest extends TestCase { - - static class TornDown extends TestCase { - boolean fTornDown= false; - - protected void tearDown() { - fTornDown= true; - } - protected void runTest() { - throw new Error("running"); - } - } - - public void testCaseToString() { - // This test wins the award for twisted snake tail eating while - // writing self tests. And you thought those weird anonymous - // inner classes were bad... - assertEquals("testCaseToString(junit.tests.framework.TestCaseTest)", toString()); - } - public void testError() { - TestCase error= new TestCase("error") { - protected void runTest() { - throw new Error(); - } - }; - verifyError(error); - } - public void testRunAndTearDownFails() { - TornDown fails= new TornDown() { - protected void tearDown() { - super.tearDown(); - throw new Error(); - } - protected void runTest() { - throw new Error(); - } - }; - verifyError(fails); - assertTrue(fails.fTornDown); - } - public void testSetupFails() { - TestCase fails= new TestCase("success") { - protected void setUp() { - throw new Error(); - } - protected void runTest() { - } - }; - verifyError(fails); - } - public void testSuccess() { - TestCase success= new TestCase("success") { - protected void runTest() { - } - }; - verifySuccess(success); - } - public void testFailure() { - TestCase failure= new TestCase("failure") { - protected void runTest() { - fail(); - } - }; - verifyFailure(failure); - } - - public void testTearDownAfterError() { - TornDown fails= new TornDown(); - verifyError(fails); - assertTrue(fails.fTornDown); - } - - public void testTearDownFails() { - TestCase fails= new TestCase("success") { - protected void tearDown() { - throw new Error(); - } - protected void runTest() { - } - }; - verifyError(fails); - } - public void testTearDownSetupFails() { - TornDown fails= new TornDown() { - protected void setUp() { - throw new Error(); - } - }; - verifyError(fails); - assertTrue(!fails.fTornDown); - } - public void testWasRun() { - WasRun test= new WasRun(); - test.run(); - assertTrue(test.fWasRun); - } - public void testExceptionRunningAndTearDown() { - // With 1.4, we should - // wrap the exception thrown while running with the exception thrown - // while tearing down - Test t= new TornDown() { - public void tearDown() { - throw new Error("tearingDown"); - } - }; - TestResult result= new TestResult(); - t.run(result); - TestFailure failure= (TestFailure) result.errors().nextElement(); - assertEquals("running", failure.thrownException().getMessage()); - } - - public void testErrorTearingDownDoesntMaskErrorRunning() { - final Exception running= new Exception("Running"); - TestCase t= new TestCase() { - protected void runTest() throws Throwable { - throw running; - } - protected void tearDown() throws Exception { - throw new Error("Tearing down"); - } - }; - try { - t.runBare(); - } catch (Throwable thrown) { - assertSame(running, thrown); - } - } - - public void testNoArgTestCasePasses() { - Test t= new TestSuite(NoArgTestCaseTest.class); - TestResult result= new TestResult(); - t.run(result); - assertTrue(result.runCount() == 1); - assertTrue(result.failureCount() == 0); - assertTrue(result.errorCount() == 0); - } - - public void testNamelessTestCase() { - TestCase t= new TestCase() {}; - try { - t.run(); - fail(); - } catch (AssertionFailedError e) { - } - } - - void verifyError(TestCase test) { - TestResult result= test.run(); - assertTrue(result.runCount() == 1); - assertTrue(result.failureCount() == 0); - assertTrue(result.errorCount() == 1); - } - void verifyFailure(TestCase test) { - TestResult result= test.run(); - assertTrue(result.runCount() == 1); - assertTrue(result.failureCount() == 1); - assertTrue(result.errorCount() == 0); - } - void verifySuccess(TestCase test) { - TestResult result= test.run(); - assertTrue(result.runCount() == 1); - assertTrue(result.failureCount() == 0); - assertTrue(result.errorCount() == 0); - } -} \ No newline at end of file diff --git a/junit/tests/framework/TestImplementorTest.java b/junit/tests/framework/TestImplementorTest.java deleted file mode 100644 index da7f80b0430f..000000000000 --- a/junit/tests/framework/TestImplementorTest.java +++ /dev/null @@ -1,53 +0,0 @@ -package junit.tests.framework; - -import junit.framework.Protectable; -import junit.framework.Test; -import junit.framework.TestCase; -import junit.framework.TestResult; - -/** - * Test an implementor of junit.framework.Test other than TestCase or TestSuite - */ -public class TestImplementorTest extends TestCase { - public static class DoubleTestCase implements Test { - private TestCase fTestCase; - - public DoubleTestCase(TestCase testCase) { - fTestCase= testCase; - } - - public int countTestCases() { - return 2; - } - - public void run(TestResult result) { - result.startTest(this); - Protectable p= new Protectable() { - public void protect() throws Throwable { - fTestCase.runBare(); - fTestCase.runBare(); - } - }; - result.runProtected(this, p); - result.endTest(this); - } - } - - private DoubleTestCase fTest; - - public TestImplementorTest() { - TestCase testCase= new TestCase() { - public void runTest() { - } - }; - fTest= new DoubleTestCase(testCase); - } - - public void testSuccessfulRun() { - TestResult result= new TestResult(); - fTest.run(result); - assertEquals(fTest.countTestCases(), result.runCount()); - assertEquals(0, result.errorCount()); - assertEquals(0, result.failureCount()); - } -} diff --git a/junit/tests/framework/TestListenerTest.java b/junit/tests/framework/TestListenerTest.java deleted file mode 100644 index 8f2092491b74..000000000000 --- a/junit/tests/framework/TestListenerTest.java +++ /dev/null @@ -1,68 +0,0 @@ -package junit.tests.framework; - -/** - * Test class used in SuiteTest - */ -import junit.framework.AssertionFailedError; -import junit.framework.Test; -import junit.framework.TestCase; -import junit.framework.TestListener; -import junit.framework.TestResult; - -public class TestListenerTest extends TestCase implements TestListener { - private TestResult fResult; - private int fStartCount; - private int fEndCount; - private int fFailureCount; - private int fErrorCount; - - public void addError(Test test, Throwable t) { - fErrorCount++; - } - public void addFailure(Test test, AssertionFailedError t) { - fFailureCount++; - } - public void endTest(Test test) { - fEndCount++; - } - protected void setUp() { - fResult= new TestResult(); - fResult.addListener(this); - - fStartCount= 0; - fEndCount= 0; - fFailureCount= 0; - } - public void startTest(Test test) { - fStartCount++; - } - public void testError() { - TestCase test= new TestCase("noop") { - public void runTest() { - throw new Error(); - } - }; - test.run(fResult); - assertEquals(1, fErrorCount); - assertEquals(1, fEndCount); - } - public void testFailure() { - TestCase test= new TestCase("noop") { - public void runTest() { - fail(); - } - }; - test.run(fResult); - assertEquals(1, fFailureCount); - assertEquals(1, fEndCount); - } - public void testStartStop() { - TestCase test= new TestCase("noop") { - public void runTest() { - } - }; - test.run(fResult); - assertEquals(1, fStartCount); - assertEquals(1, fEndCount); - } -} \ No newline at end of file diff --git a/junit/tests/runner/AllTests.java b/junit/tests/runner/AllTests.java deleted file mode 100644 index 49bcf9820ea8..000000000000 --- a/junit/tests/runner/AllTests.java +++ /dev/null @@ -1,37 +0,0 @@ -package junit.tests.runner; - -import junit.framework.Test; -import junit.framework.TestSuite; -import junit.runner.BaseTestRunner; - -/** - * TestSuite that runs all the sample tests - * - */ -public class AllTests { - - public static void main(String[] args) { - junit.textui.TestRunner.run(suite()); - } - - public static Test suite() { // Collect tests manually because we have to test class collection code - TestSuite suite= new TestSuite("Framework Tests"); - suite.addTestSuite(StackFilterTest.class); - suite.addTestSuite(SorterTest.class); - suite.addTestSuite(SimpleTestCollectorTest.class); - suite.addTestSuite(BaseTestRunnerTest.class); - suite.addTestSuite(TextFeedbackTest.class); - //suite.addTestSuite(TextRunnerSingleMethodTest.class); - if (!BaseTestRunner.inVAJava()) { - suite.addTestSuite(TextRunnerTest.class); - if (!isJDK11()) - suite.addTest(new TestSuite(TestCaseClassLoaderTest.class)); - } - return suite; - } - - static boolean isJDK11() { - String version= System.getProperty("java.version"); - return version.startsWith("1.1"); - } -} \ No newline at end of file diff --git a/junit/tests/runner/BaseTestRunnerTest.java b/junit/tests/runner/BaseTestRunnerTest.java deleted file mode 100644 index e59329355573..000000000000 --- a/junit/tests/runner/BaseTestRunnerTest.java +++ /dev/null @@ -1,35 +0,0 @@ - -package junit.tests.runner; - -import junit.framework.Test; -import junit.framework.TestCase; -import junit.runner.BaseTestRunner; - -public class BaseTestRunnerTest extends TestCase { - - public static class MockRunner extends BaseTestRunner { - protected void runFailed(String message) { - } - - public void testEnded(String testName) { - } - - public void testFailed(int status, Test test, Throwable t) { - } - - public void testStarted(String testName) { - } - } - - public static class NonStatic { - public Test suite() { - return null; - } - } - - - public void testInvokeNonStaticSuite() { - BaseTestRunner runner= new MockRunner(); - runner.getTest("junit.tests.runner.BaseTestRunnerTest$NonStatic"); // Used to throw NullPointerException - } -} diff --git a/junit/tests/runner/ClassLoaderTest.java b/junit/tests/runner/ClassLoaderTest.java deleted file mode 100644 index 307de4eb2cd5..000000000000 --- a/junit/tests/runner/ClassLoaderTest.java +++ /dev/null @@ -1,26 +0,0 @@ -package junit.tests.runner; - -/** - * Test class used in TestTestCaseClassLoader - */ -import junit.framework.Assert; -import junit.framework.TestCase; - -public class ClassLoaderTest extends Assert { - public ClassLoaderTest() { - } - public void verify() { - verifyApplicationClassLoadedByTestLoader(); - verifySystemClassNotLoadedByTestLoader(); - } - private boolean isTestCaseClassLoader(ClassLoader cl) { - return (cl != null && cl.getClass().getName().equals(junit.runner.TestCaseClassLoader.class.getName())); - } - private void verifyApplicationClassLoadedByTestLoader() { - assertTrue(isTestCaseClassLoader(getClass().getClassLoader())); - } - private void verifySystemClassNotLoadedByTestLoader() { - assertTrue(!isTestCaseClassLoader(Object.class.getClassLoader())); - assertTrue(!isTestCaseClassLoader(TestCase.class.getClassLoader())); - } -} \ No newline at end of file diff --git a/junit/tests/runner/LoadedFromJar.java b/junit/tests/runner/LoadedFromJar.java deleted file mode 100644 index 7dcf3d6aef4a..000000000000 --- a/junit/tests/runner/LoadedFromJar.java +++ /dev/null @@ -1,18 +0,0 @@ -package junit.tests.runner; - -/** - * Test class used in TestTestCaseClassLoader - */ -import junit.framework.Assert; - -public class LoadedFromJar extends Assert { - public void verify() { - verifyApplicationClassLoadedByTestLoader(); - } - private boolean isTestCaseClassLoader(ClassLoader cl) { - return (cl != null && cl.getClass().getName().equals(junit.runner.TestCaseClassLoader.class.getName())); - } - private void verifyApplicationClassLoadedByTestLoader() { - assertTrue(isTestCaseClassLoader(getClass().getClassLoader())); - } -} \ No newline at end of file diff --git a/junit/tests/runner/SimpleTestCollectorTest.java b/junit/tests/runner/SimpleTestCollectorTest.java deleted file mode 100644 index 85c93e58c2b5..000000000000 --- a/junit/tests/runner/SimpleTestCollectorTest.java +++ /dev/null @@ -1,14 +0,0 @@ -package junit.tests.runner; - -import junit.framework.TestCase; -import junit.runner.SimpleTestCollector; - -public class SimpleTestCollectorTest extends TestCase { - - public void testMissingDirectory() { - SimpleTestCollector collector= new SimpleTestCollector(); - assertFalse(collector.collectFilesInPath("foobar").elements().hasMoreElements()); - } - -} - diff --git a/junit/tests/runner/SorterTest.java b/junit/tests/runner/SorterTest.java deleted file mode 100644 index b8c385f6dee1..000000000000 --- a/junit/tests/runner/SorterTest.java +++ /dev/null @@ -1,28 +0,0 @@ -package junit.tests.runner; - -import java.util.Vector; - -import junit.framework.TestCase; -import junit.runner.Sorter; - -public class SorterTest extends TestCase { - - static class Swapper implements Sorter.Swapper { - public void swap(Vector values, int left, int right) { - Object tmp= values.elementAt(left); - values.setElementAt(values.elementAt(right), left); - values.setElementAt(tmp, right); - } - } - - public void testSort() throws Exception { - Vector v= new Vector(); - v.addElement("c"); - v.addElement("b"); - v.addElement("a"); - Sorter.sortStrings(v, 0, v.size()-1, new Swapper()); - assertEquals(v.elementAt(0), "a"); - assertEquals(v.elementAt(1), "b"); - assertEquals(v.elementAt(2), "c"); - } -} \ No newline at end of file diff --git a/junit/tests/runner/StackFilterTest.java b/junit/tests/runner/StackFilterTest.java deleted file mode 100644 index f5ddb79f38a5..000000000000 --- a/junit/tests/runner/StackFilterTest.java +++ /dev/null @@ -1,45 +0,0 @@ -package junit.tests.runner; - -import java.io.PrintWriter; -import java.io.StringWriter; - -import junit.framework.TestCase; -import junit.runner.BaseTestRunner; - -public class StackFilterTest extends TestCase { - String fFiltered; - String fUnfiltered; - - protected void setUp() { - StringWriter swin= new StringWriter(); - PrintWriter pwin= new PrintWriter(swin); - pwin.println("junit.framework.AssertionFailedError"); - pwin.println(" at junit.framework.Assert.fail(Assert.java:144)"); - pwin.println(" at junit.framework.Assert.assert(Assert.java:19)"); - pwin.println(" at junit.framework.Assert.assert(Assert.java:26)"); - pwin.println(" at MyTest.f(MyTest.java:13)"); - pwin.println(" at MyTest.testStackTrace(MyTest.java:8)"); - pwin.println(" at java.lang.reflect.Method.invoke(Native Method)"); - pwin.println(" at junit.framework.TestCase.runTest(TestCase.java:156)"); - pwin.println(" at junit.framework.TestCase.runBare(TestCase.java:130)"); - pwin.println(" at junit.framework.TestResult$1.protect(TestResult.java:100)"); - pwin.println(" at junit.framework.TestResult.runProtected(TestResult.java:118)"); - pwin.println(" at junit.framework.TestResult.run(TestResult.java:103)"); - pwin.println(" at junit.framework.TestCase.run(TestCase.java:121)"); - pwin.println(" at junit.framework.TestSuite.runTest(TestSuite.java:157)"); - pwin.println(" at junit.framework.TestSuite.run(TestSuite.java, Compiled Code)"); - pwin.println(" at junit.swingui.TestRunner$17.run(TestRunner.java:669)"); - fUnfiltered= swin.toString(); - - StringWriter swout= new StringWriter(); - PrintWriter pwout= new PrintWriter(swout); - pwout.println("junit.framework.AssertionFailedError"); - pwout.println(" at MyTest.f(MyTest.java:13)"); - pwout.println(" at MyTest.testStackTrace(MyTest.java:8)"); - fFiltered= swout.toString(); - } - - public void testFilter() { - assertEquals(fFiltered, BaseTestRunner.getFilteredTrace(fUnfiltered)); - } -} \ No newline at end of file diff --git a/junit/tests/runner/TestCaseClassLoaderTest.java b/junit/tests/runner/TestCaseClassLoaderTest.java deleted file mode 100644 index b7e66051c92f..000000000000 --- a/junit/tests/runner/TestCaseClassLoaderTest.java +++ /dev/null @@ -1,46 +0,0 @@ -package junit.tests.runner; - -import java.lang.reflect.Method; -import java.net.URL; - -import junit.framework.TestCase; -import junit.runner.TestCaseClassLoader; - -/** - * A TestCase for testing the TestCaseClassLoader - * - */ -public class TestCaseClassLoaderTest extends TestCase { - - public void testClassLoading() throws Exception { - TestCaseClassLoader loader= new TestCaseClassLoader(); - Class loadedClass= loader.loadClass("junit.tests.runner.ClassLoaderTest", true); - Object o= loadedClass.newInstance(); - // - // Invoke the assertClassLoaders method via reflection. - // We use reflection since the class is loaded by - // another class loader and we can't do a successful downcast to - // ClassLoaderTestCase. - // - Method method= loadedClass.getDeclaredMethod("verify", new Class[0]); - method.invoke(o, (Object[])new Class[0]); - } - - public void testJarClassLoading() throws Exception { - URL url= getClass().getResource("test.jar"); - if (url == null) - return; // This test only makes sense when run from Ant, so silently ignore - String path= url.getFile(); - TestCaseClassLoader loader= new TestCaseClassLoader(path); - Class loadedClass= loader.loadClass("junit.tests.runner.LoadedFromJar", true); - Object o= loadedClass.newInstance(); - // - // Invoke the assertClassLoaders method via reflection. - // We use reflection since the class is loaded by - // another class loader and we can't do a successfull downcast to - // ClassLoaderTestCase. - // - Method method= loadedClass.getDeclaredMethod("verify", new Class[0]); - method.invoke(o, (Object[])new Class[0]); - } -} \ No newline at end of file diff --git a/junit/tests/runner/TextFeedbackTest.java b/junit/tests/runner/TextFeedbackTest.java deleted file mode 100644 index 0a4bd15281f4..000000000000 --- a/junit/tests/runner/TextFeedbackTest.java +++ /dev/null @@ -1,100 +0,0 @@ - -package junit.tests.runner; - -import java.io.ByteArrayOutputStream; -import java.io.OutputStream; -import java.io.PrintStream; - -import junit.framework.AssertionFailedError; -import junit.framework.TestCase; -import junit.framework.TestResult; -import junit.framework.TestSuite; -import junit.textui.ResultPrinter; -import junit.textui.TestRunner; - -public class TextFeedbackTest extends TestCase { - OutputStream output; - TestRunner runner; - - static class TestResultPrinter extends ResultPrinter { - TestResultPrinter(PrintStream writer) { - super(writer); - } - - /* Spoof printing time so the tests are deterministic - */ - protected String elapsedTimeAsString(long runTime) { - return "0"; - } - } - - public static void main(String[] args) { - TestRunner.run(TextFeedbackTest.class); - } - - public void setUp() { - output= new ByteArrayOutputStream(); - runner= new TestRunner(new TestResultPrinter(new PrintStream(output))); - } - - public void testEmptySuite() { - String expected= expected(new String[]{"", "Time: 0", "", "OK (0 tests)", ""}); - runner.doRun(new TestSuite()); - assertEquals(expected, output.toString()); - } - - - public void testOneTest() { - String expected= expected(new String[]{".", "Time: 0", "", "OK (1 test)", ""}); - TestSuite suite = new TestSuite(); - suite.addTest(new TestCase() { public void runTest() {}}); - runner.doRun(suite); - assertEquals(expected, output.toString()); - } - - public void testTwoTests() { - String expected= expected(new String[]{"..", "Time: 0", "", "OK (2 tests)", ""}); - TestSuite suite = new TestSuite(); - suite.addTest(new TestCase() { public void runTest() {}}); - suite.addTest(new TestCase() { public void runTest() {}}); - runner.doRun(suite); - assertEquals(expected, output.toString()); - } - - public void testFailure() { - String expected= expected(new String[]{".F", "Time: 0", "Failures here", "", "FAILURES!!!", "Tests run: 1, Failures: 1, Errors: 0", ""}); - ResultPrinter printer= new TestResultPrinter(new PrintStream(output)) { - public void printFailures(TestResult result) { - getWriter().println("Failures here"); - } - }; - runner.setPrinter(printer); - TestSuite suite = new TestSuite(); - suite.addTest(new TestCase() { public void runTest() {throw new AssertionFailedError();}}); - runner.doRun(suite); - assertEquals(expected, output.toString()); - } - - public void testError() { - String expected= expected(new String[]{".E", "Time: 0", "Errors here", "", "FAILURES!!!", "Tests run: 1, Failures: 0, Errors: 1", ""}); - ResultPrinter printer= new TestResultPrinter(new PrintStream(output)) { - public void printErrors(TestResult result) { - getWriter().println("Errors here"); - } - }; - runner.setPrinter(printer); - TestSuite suite = new TestSuite(); - suite.addTest(new TestCase() { public void runTest() throws Exception {throw new Exception();}}); - runner.doRun(suite); - assertEquals(expected, output.toString()); - } - - private String expected(String[] lines) { - OutputStream expected= new ByteArrayOutputStream(); - PrintStream expectedWriter= new PrintStream(expected); - for (int i= 0; i < lines.length; i++) - expectedWriter.println(lines[i]); - return expected.toString(); - } - -} diff --git a/junit/tests/runner/TextRunnerSingleMethodTest.java b/junit/tests/runner/TextRunnerSingleMethodTest.java deleted file mode 100644 index d5dc87bb973e..000000000000 --- a/junit/tests/runner/TextRunnerSingleMethodTest.java +++ /dev/null @@ -1,74 +0,0 @@ -package junit.tests.runner; - -import java.io.PrintStream; -import java.util.Enumeration; -import junit.framework.*; -import junit.textui.*; - -/** - * Test invoking a single test method of a TestCase. - */ -public class TextRunnerSingleMethodTest extends TestCase { - private final class NullResultPrinter extends ResultPrinter { - private NullResultPrinter(PrintStream writer) { - super(writer); - } - public void addError(Test test, Throwable t) { - } - public void addFailure(Test test, AssertionFailedError t) { - } - protected String elapsedTimeAsString(long runTime) { - return null; - } - public void endTest(Test test) { - } - public PrintStream getWriter() { - return null; - } - synchronized void print(TestResult result, long runTime) { - } - public void printDefect(TestFailure failure, int count) { - } - protected void printDefectHeader(TestFailure failure, int count) { - } - protected void printDefects(Enumeration failure, int count, String type) { - } - protected void printDefectTrace(TestFailure failure) { - } - protected void printErrors(TestResult result) { - } - protected void printFailures(TestResult result) { - } - protected void printFooter(TestResult result) { - } - protected void printHeader(long runTime) { - } - void printWaitPrompt() { - } - public void startTest(Test test) { - } - } - - public static class InvocationTest extends TestCase { - - public void testWasInvoked() { - TextRunnerSingleMethodTest.fgWasInvoked= true; - } - - public void testNotInvoked() { - fail("Shouldn't get here."); - } - } - static boolean fgWasInvoked= false; - - public void testSingle() throws Exception { - TestRunner t= new TestRunner(new NullResultPrinter(null)); - String[] args= { - "-m", "junit.tests.runner.TextRunnerSingleMethodTest$InvocationTest.testWasInvoked" - }; - assertFalse(fgWasInvoked); - t.start(args); - assertTrue(fgWasInvoked); - } - -} \ No newline at end of file diff --git a/junit/tests/runner/TextRunnerTest.java b/junit/tests/runner/TextRunnerTest.java deleted file mode 100644 index 1cfd218517a2..000000000000 --- a/junit/tests/runner/TextRunnerTest.java +++ /dev/null @@ -1,60 +0,0 @@ -package junit.tests.runner; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.PrintStream; - -import junit.framework.TestCase; -import junit.framework.TestResult; -import junit.framework.TestSuite; - -public class TextRunnerTest extends TestCase { - - public void testFailure() throws Exception { - execTest("junit.tests.framework.Failure", false); - } - - public void testSuccess() throws Exception { - execTest("junit.tests.framework.Success", true); - } - - public void testError() throws Exception { - execTest("junit.tests.BogusDude", false); - } - - void execTest(String testClass, boolean success) throws Exception { - String java= System.getProperty("java.home")+File.separator+"bin"+File.separator+"java"; - String cp= System.getProperty("java.class.path"); - //use -classpath for JDK 1.1.7 compatibility - String [] cmd= { java, "-classpath", cp, "junit.textui.TestRunner", testClass}; - Process p= Runtime.getRuntime().exec(cmd); - InputStream i= p.getInputStream(); - while((i.read()) != -1) - ; //System.out.write(b); - assertTrue((p.waitFor() == 0) == success); - if (success) - assertTrue(p.exitValue() == 0); - else - assertFalse(p.exitValue() == 0); - } - - public void testRunReturnsResult() { - PrintStream oldOut= System.out; - System.setOut(new PrintStream ( - new OutputStream() { - public void write(int arg0) throws IOException { - } - } - )); - try { - TestResult result= junit.textui.TestRunner.run(new TestSuite()); - assertTrue(result.wasSuccessful()); - } finally { - System.setOut(oldOut); - } - } - - -} \ No newline at end of file diff --git a/junit/textui/ResultPrinter.java b/junit/textui/ResultPrinter.java deleted file mode 100644 index 1ebb7a1783a8..000000000000 --- a/junit/textui/ResultPrinter.java +++ /dev/null @@ -1,139 +0,0 @@ - -package junit.textui; - -import java.io.PrintStream; -import java.text.NumberFormat; -import java.util.Enumeration; - -import junit.framework.AssertionFailedError; -import junit.framework.Test; -import junit.framework.TestFailure; -import junit.framework.TestListener; -import junit.framework.TestResult; -import junit.runner.BaseTestRunner; - -public class ResultPrinter implements TestListener { - PrintStream fWriter; - int fColumn= 0; - - public ResultPrinter(PrintStream writer) { - fWriter= writer; - } - - /* API for use by textui.TestRunner - */ - - synchronized void print(TestResult result, long runTime) { - printHeader(runTime); - printErrors(result); - printFailures(result); - printFooter(result); - } - - void printWaitPrompt() { - getWriter().println(); - getWriter().println(" to continue"); - } - - /* Internal methods - */ - - protected void printHeader(long runTime) { - getWriter().println(); - getWriter().println("Time: "+elapsedTimeAsString(runTime)); - } - - protected void printErrors(TestResult result) { - printDefects(result.errors(), result.errorCount(), "error"); - } - - protected void printFailures(TestResult result) { - printDefects(result.failures(), result.failureCount(), "failure"); - } - - protected void printDefects(Enumeration booBoos, int count, String type) { - if (count == 0) return; - if (count == 1) - getWriter().println("There was " + count + " " + type + ":"); - else - getWriter().println("There were " + count + " " + type + "s:"); - for (int i= 1; booBoos.hasMoreElements(); i++) { - printDefect((TestFailure) booBoos.nextElement(), i); - } - } - - public void printDefect(TestFailure booBoo, int count) { // only public for testing purposes - printDefectHeader(booBoo, count); - printDefectTrace(booBoo); - } - - protected void printDefectHeader(TestFailure booBoo, int count) { - // I feel like making this a println, then adding a line giving the throwable a chance to print something - // before we get to the stack trace. - getWriter().print(count + ") " + booBoo.failedTest()); - } - - protected void printDefectTrace(TestFailure booBoo) { - getWriter().print(BaseTestRunner.getFilteredTrace(booBoo.trace())); - } - - protected void printFooter(TestResult result) { - if (result.wasSuccessful()) { - getWriter().println(); - getWriter().print("OK"); - getWriter().println (" (" + result.runCount() + " test" + (result.runCount() == 1 ? "": "s") + ")"); - - } else { - getWriter().println(); - getWriter().println("FAILURES!!!"); - getWriter().println("Tests run: "+result.runCount()+ - ", Failures: "+result.failureCount()+ - ", Errors: "+result.errorCount()); - } - getWriter().println(); - } - - - /** - * Returns the formatted string of the elapsed time. - * Duplicated from BaseTestRunner. Fix it. - */ - protected String elapsedTimeAsString(long runTime) { - return NumberFormat.getInstance().format((double)runTime/1000); - } - - public PrintStream getWriter() { - return fWriter; - } - /** - * @see junit.framework.TestListener#addError(Test, Throwable) - */ - public void addError(Test test, Throwable t) { - getWriter().print("E"); - } - - /** - * @see junit.framework.TestListener#addFailure(Test, AssertionFailedError) - */ - public void addFailure(Test test, AssertionFailedError t) { - getWriter().print("F"); - } - - /** - * @see junit.framework.TestListener#endTest(Test) - */ - public void endTest(Test test) { - } - - /** - * @see junit.framework.TestListener#startTest(Test) - */ - public void startTest(Test test) { - getWriter().print("."); - if (fColumn++ >= 40) { - getWriter().println(); - fColumn= 0; - } - } - -} diff --git a/junit/textui/TestRunner.java b/junit/textui/TestRunner.java deleted file mode 100644 index 01b9d6df9324..000000000000 --- a/junit/textui/TestRunner.java +++ /dev/null @@ -1,207 +0,0 @@ -package junit.textui; - - -import java.io.PrintStream; - -import junit.framework.Test; -import junit.framework.TestResult; -import junit.framework.TestSuite; -import junit.runner.BaseTestRunner; -import junit.runner.StandardTestSuiteLoader; -import junit.runner.TestSuiteLoader; -import junit.runner.Version; - -/** - * A command line based tool to run tests. - *
    - * java junit.textui.TestRunner [-wait] TestCaseClass
    - * 
    - * TestRunner expects the name of a TestCase class as argument. - * If this class defines a static suite method it - * will be invoked and the returned test is run. Otherwise all - * the methods starting with "test" having no arguments are run. - *

    - * When the wait command line argument is given TestRunner - * waits until the users types RETURN. - *

    - * TestRunner prints a trace as the tests are executed followed by a - * summary at the end. - */ -public class TestRunner extends BaseTestRunner { - private ResultPrinter fPrinter; - - public static final int SUCCESS_EXIT= 0; - public static final int FAILURE_EXIT= 1; - public static final int EXCEPTION_EXIT= 2; - - /** - * Constructs a TestRunner. - */ - public TestRunner() { - this(System.out); - } - - /** - * Constructs a TestRunner using the given stream for all the output - */ - public TestRunner(PrintStream writer) { - this(new ResultPrinter(writer)); - } - - /** - * Constructs a TestRunner using the given ResultPrinter all the output - */ - public TestRunner(ResultPrinter printer) { - fPrinter= printer; - } - - /** - * Runs a suite extracted from a TestCase subclass. - */ - static public void run(Class testClass) { - run(new TestSuite(testClass)); - } - - /** - * Runs a single test and collects its results. - * This method can be used to start a test run - * from your program. - *

    -	 * public static void main (String[] args) {
    -	 *     test.textui.TestRunner.run(suite());
    -	 * }
    -	 * 
    - */ - static public TestResult run(Test test) { - TestRunner runner= new TestRunner(); - return runner.doRun(test); - } - - /** - * Runs a single test and waits until the user - * types RETURN. - */ - static public void runAndWait(Test suite) { - TestRunner aTestRunner= new TestRunner(); - aTestRunner.doRun(suite, true); - } - - /** - * Always use the StandardTestSuiteLoader. Overridden from - * BaseTestRunner. - */ - public TestSuiteLoader getLoader() { - return new StandardTestSuiteLoader(); - } - - public void testFailed(int status, Test test, Throwable t) { - } - - public void testStarted(String testName) { - } - - public void testEnded(String testName) { - } - - /** - * Creates the TestResult to be used for the test run. - */ - protected TestResult createTestResult() { - return new TestResult(); - } - - public TestResult doRun(Test test) { - return doRun(test, false); - } - - public TestResult doRun(Test suite, boolean wait) { - TestResult result= createTestResult(); - result.addListener(fPrinter); - long startTime= System.currentTimeMillis(); - suite.run(result); - long endTime= System.currentTimeMillis(); - long runTime= endTime-startTime; - fPrinter.print(result, runTime); - - pause(wait); - return result; - } - - protected void pause(boolean wait) { - if (!wait) return; - fPrinter.printWaitPrompt(); - try { - System.in.read(); - } - catch(Exception e) { - } - } - - public static void main(String args[]) { - TestRunner aTestRunner= new TestRunner(); - try { - TestResult r= aTestRunner.start(args); - if (!r.wasSuccessful()) - System.exit(FAILURE_EXIT); - System.exit(SUCCESS_EXIT); - } catch(Exception e) { - System.err.println(e.getMessage()); - System.exit(EXCEPTION_EXIT); - } - } - - /** - * Starts a test run. Analyzes the command line arguments and runs the given - * test suite. - */ - public TestResult start(String args[]) throws Exception { - String testCase= ""; - String method= ""; - boolean wait= false; - - for (int i= 0; i < args.length; i++) { - if (args[i].equals("-wait")) - wait= true; - else if (args[i].equals("-c")) - testCase= extractClassName(args[++i]); - else if (args[i].equals("-m")) { - String arg= args[++i]; - int lastIndex= arg.lastIndexOf('.'); - testCase= arg.substring(0, lastIndex); - method= arg.substring(lastIndex + 1); - } else if (args[i].equals("-v")) - System.err.println("JUnit " + Version.id() + " by Kent Beck and Erich Gamma"); - else - testCase= args[i]; - } - - if (testCase.equals("")) - throw new Exception("Usage: TestRunner [-wait] testCaseName, where name is the name of the TestCase class"); - - try { - if (!method.equals("")) - return runSingleMethod(testCase, method, wait); - Test suite= getTest(testCase); - return doRun(suite, wait); - } catch (Exception e) { - throw new Exception("Could not create and run test suite: " + e); - } - } - - protected TestResult runSingleMethod(String testCase, String method, boolean wait) throws Exception { - Class testClass= loadSuiteClass(testCase); - Test test= TestSuite.createTest(testClass, method); - return doRun(test, wait); - } - - protected void runFailed(String message) { - System.err.println(message); - System.exit(FAILURE_EXIT); - } - - public void setPrinter(ResultPrinter printer) { - fPrinter= printer; - } - - -} \ No newline at end of file diff --git a/lib/hamcrest-core-1.3-sources.jar b/lib/hamcrest-core-1.3-sources.jar new file mode 100644 index 000000000000..c3c110b4dab6 Binary files /dev/null and b/lib/hamcrest-core-1.3-sources.jar differ diff --git a/lib/hamcrest-core-1.3.jar b/lib/hamcrest-core-1.3.jar new file mode 100644 index 000000000000..9d5fe16e3dd3 Binary files /dev/null and b/lib/hamcrest-core-1.3.jar differ diff --git a/mvnw b/mvnw new file mode 100755 index 000000000000..e96ccd5fbbb6 --- /dev/null +++ b/mvnw @@ -0,0 +1,227 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. +# ---------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------- +# Maven2 Start Up Batch script +# +# Required ENV vars: +# ------------------ +# JAVA_HOME - location of a JDK home dir +# +# Optional ENV vars +# ----------------- +# M2_HOME - location of maven2's installed home dir +# MAVEN_OPTS - parameters passed to the Java VM when running Maven +# e.g. to debug Maven itself, use +# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +# MAVEN_SKIP_RC - flag to disable loading of mavenrc files +# ---------------------------------------------------------------------------- + +if [ -z "$MAVEN_SKIP_RC" ] ; then + + if [ -f /etc/mavenrc ] ; then + . /etc/mavenrc + fi + + if [ -f "$HOME/.mavenrc" ] ; then + . "$HOME/.mavenrc" + fi + +fi + +# OS specific support. $var _must_ be set to either true or false. +cygwin=false; +darwin=false; +mingw=false +case "`uname`" in + CYGWIN*) cygwin=true ;; + MINGW*) mingw=true;; + Darwin*) darwin=true + # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home + # See https://developer.apple.com/library/mac/qa/qa1170/_index.html + if [ -z "$JAVA_HOME" ]; then + if [ -x "/usr/libexec/java_home" ]; then + export JAVA_HOME="`/usr/libexec/java_home`" + else + export JAVA_HOME="/Library/Java/Home" + fi + fi + ;; +esac + +if [ -z "$JAVA_HOME" ] ; then + if [ -r /etc/gentoo-release ] ; then + JAVA_HOME=`java-config --jre-home` + fi +fi + +if [ -z "$M2_HOME" ] ; then + ## resolve links - $0 may be a link to maven's home + PRG="$0" + + # need this for relative symlinks + while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG="`dirname "$PRG"`/$link" + fi + done + + saveddir=`pwd` + + M2_HOME=`dirname "$PRG"`/.. + + # make it fully qualified + M2_HOME=`cd "$M2_HOME" && pwd` + + cd "$saveddir" + # echo Using m2 at $M2_HOME +fi + +# For Cygwin, ensure paths are in UNIX format before anything is touched +if $cygwin ; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --unix "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --unix "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --unix "$CLASSPATH"` +fi + +# For Mingw, ensure paths are in UNIX format before anything is touched +if $mingw ; then + [ -n "$M2_HOME" ] && + M2_HOME="`(cd "$M2_HOME"; pwd)`" + [ -n "$JAVA_HOME" ] && + JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" + # TODO classpath? +fi + +if [ -z "$JAVA_HOME" ]; then + javaExecutable="`which javac`" + if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then + # readlink(1) is not available as standard on Solaris 10. + readLink=`which readlink` + if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then + if $darwin ; then + javaHome="`dirname \"$javaExecutable\"`" + javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" + else + javaExecutable="`readlink -f \"$javaExecutable\"`" + fi + javaHome="`dirname \"$javaExecutable\"`" + javaHome=`expr "$javaHome" : '\(.*\)/bin'` + JAVA_HOME="$javaHome" + export JAVA_HOME + fi + fi +fi + +if [ -z "$JAVACMD" ] ; then + if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + else + JAVACMD="`which java`" + fi +fi + +if [ ! -x "$JAVACMD" ] ; then + echo "Error: JAVA_HOME is not defined correctly." >&2 + echo " We cannot execute $JAVACMD" >&2 + exit 1 +fi + +if [ -z "$JAVA_HOME" ] ; then + echo "Warning: JAVA_HOME environment variable is not set." +fi + +CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher + +# traverses directory structure from process work directory to filesystem root +# first directory with .mvn subdirectory is considered project base directory +find_maven_basedir() { + + if [ -z "$1" ] + then + echo "Path not specified to find_maven_basedir" + return 1 + fi + + basedir="$1" + wdir="$1" + while [ "$wdir" != '/' ] ; do + if [ -d "$wdir"/.mvn ] ; then + basedir=$wdir + break + fi + # workaround for JBEAP-8937 (on Solaris 10/Sparc) + if [ -d "${wdir}" ]; then + wdir=`cd "$wdir/.."; pwd` + fi + # end of workaround + done + echo "${basedir}" +} + +# concatenates all lines of a file +concat_lines() { + if [ -f "$1" ]; then + echo "$(tr -s '\n' ' ' < "$1")" + fi +} + +BASE_DIR=`find_maven_basedir "$(pwd)"` +if [ -z "$BASE_DIR" ]; then + exit 1; +fi + +export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} +if [ "$MVNW_VERBOSE" = true ]; then + echo $MAVEN_PROJECTBASEDIR +fi +MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" + +# For Cygwin, switch paths to Windows format before running java +if $cygwin; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --path --windows "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --windows "$CLASSPATH"` + [ -n "$MAVEN_PROJECTBASEDIR" ] && + MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` +fi + +WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +exec "$JAVACMD" \ + $MAVEN_OPTS \ + -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ + "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ + ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/mvnw.cmd b/mvnw.cmd new file mode 100755 index 000000000000..019bd74d766e --- /dev/null +++ b/mvnw.cmd @@ -0,0 +1,143 @@ +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM http://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Maven2 Start Up Batch script +@REM +@REM Required ENV vars: +@REM JAVA_HOME - location of a JDK home dir +@REM +@REM Optional ENV vars +@REM M2_HOME - location of maven2's installed home dir +@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands +@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending +@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven +@REM e.g. to debug Maven itself, use +@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM ---------------------------------------------------------------------------- + +@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' +@echo off +@REM enable echoing my setting MAVEN_BATCH_ECHO to 'on' +@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% + +@REM set %HOME% to equivalent of $HOME +if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") + +@REM Execute a user defined script before this one +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre +@REM check for pre script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" +if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" +:skipRcPre + +@setlocal + +set ERROR_CODE=0 + +@REM To isolate internal variables from possible post scripts, we use another setlocal +@setlocal + +@REM ==== START VALIDATION ==== +if not "%JAVA_HOME%" == "" goto OkJHome + +echo. +echo Error: JAVA_HOME not found in your environment. >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +:OkJHome +if exist "%JAVA_HOME%\bin\java.exe" goto init + +echo. +echo Error: JAVA_HOME is set to an invalid directory. >&2 +echo JAVA_HOME = "%JAVA_HOME%" >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +@REM ==== END VALIDATION ==== + +:init + +@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". +@REM Fallback to current working directory if not found. + +set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% +IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir + +set EXEC_DIR=%CD% +set WDIR=%EXEC_DIR% +:findBaseDir +IF EXIST "%WDIR%"\.mvn goto baseDirFound +cd .. +IF "%WDIR%"=="%CD%" goto baseDirNotFound +set WDIR=%CD% +goto findBaseDir + +:baseDirFound +set MAVEN_PROJECTBASEDIR=%WDIR% +cd "%EXEC_DIR%" +goto endDetectBaseDir + +:baseDirNotFound +set MAVEN_PROJECTBASEDIR=%EXEC_DIR% +cd "%EXEC_DIR%" + +:endDetectBaseDir + +IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig + +@setlocal EnableExtensions EnableDelayedExpansion +for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a +@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% + +:endReadAdditionalConfig + +SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" + +set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" +set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* +if ERRORLEVEL 1 goto error +goto end + +:error +set ERROR_CODE=1 + +:end +@endlocal & set ERROR_CODE=%ERROR_CODE% + +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost +@REM check for post script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" +if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" +:skipRcPost + +@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' +if "%MAVEN_BATCH_PAUSE%" == "on" pause + +if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% + +exit /B %ERROR_CODE% diff --git a/pom.xml b/pom.xml new file mode 100644 index 000000000000..428715884b4e --- /dev/null +++ b/pom.xml @@ -0,0 +1,587 @@ + + + 4.0.0 + + junit + junit + 4.13.1 + + JUnit + JUnit is a unit testing framework for Java, created by Erich Gamma and Kent Beck. + http://junit.org + 2002 + + JUnit + http://www.junit.org + + + + Eclipse Public License 1.0 + http://www.eclipse.org/legal/epl-v10.html + repo + + + + + + dsaff + David Saff + david@saff.net + + + kcooney + Kevin Cooney + kcooney@google.com + + + stefanbirkner + Stefan Birkner + mail@stefan-birkner.de + + + marcphilipp + Marc Philipp + mail@marcphilipp.de + + + + + JUnit contributors + JUnit + team@junit.org + https://github.com/junit-team/junit4/graphs/contributors + + developers + + + + + + 3.0.4 + + + + scm:git:git://github.com/junit-team/junit4.git + scm:git:git@github.com:junit-team/junit4.git + https://github.com/junit-team/junit4 + r4.13.1 + + + github + https://github.com/junit-team/junit4/issues + + + travis + https://travis-ci.org/junit-team/junit4 + + + https://github.com/junit-team/junit4/wiki/Download-and-Install + + junit-snapshot-repo + Nexus Snapshot Repository + https://oss.sonatype.org/content/repositories/snapshots/ + + + junit-releases-repo + Nexus Release Repository + https://oss.sonatype.org/service/local/staging/deploy/maven2/ + + + junit.github.io + gitsite:git@github.com/junit-team/junit4.git + + + + + 1.5 + 2.19.1 + 1.3 + ISO-8859-1 + + 67893CC4 + + + + + org.hamcrest + hamcrest-core + ${hamcrestVersion} + + + + org.hamcrest + hamcrest-library + ${hamcrestVersion} + test + + + + + + + ${project.basedir}/src/main/resources + + + ${project.basedir} + + LICENSE-junit.txt + + + + + + + + maven-enforcer-plugin + 1.4 + + + enforce-versions + initialize + + enforce + + + true + + + + Current version of Maven ${maven.version} required to build the project + should be ${project.prerequisites.maven}, or higher! + + [${project.prerequisites.maven},) + + + Current JDK version ${java.version} should be ${jdkVersion}, or higher! + + ${jdkVersion} + + + Best Practice is to never define repositories in pom.xml (use a repository + manager instead). + + + + No Snapshots Dependencies Allowed! + + + + + + + + + com.google.code.maven-replacer-plugin + replacer + 1.5.3 + + + process-sources + + replace + + + + + false + ${project.build.sourceDirectory}/junit/runner/Version.java.template + ${project.build.sourceDirectory}/junit/runner/Version.java + false + @version@ + ${project.version} + + + + + maven-compiler-plugin + 3.3 + + ${project.build.sourceEncoding} + ${jdkVersion} + ${jdkVersion} + ${jdkVersion} + ${jdkVersion} + 1.5 + true + true + true + true + + -Xlint:unchecked + + 128m + + + + org.codehaus.mojo + animal-sniffer-maven-plugin + 1.14 + + + signature-check + test + + check + + + + org.codehaus.mojo.signature + java15 + 1.0 + + + + + + + + maven-surefire-plugin + ${surefireVersion} + + org/junit/tests/AllTests.java + true + false + + + + org.apache.maven.surefire + surefire-junit47 + ${surefireVersion} + + + + + + maven-source-plugin + 2.4 + + + + maven-javadoc-plugin + 2.10.3 + + ${basedir}/src/main/javadoc/stylesheet.css + protected + false + false + false + true + true + true + JUnit API + UTF-8 + en + ${jdkVersion} + + + api_${jdkVersion} + http://docs.oracle.com/javase/${jdkVersion}.0/docs/api/ + + + *.internal.* + true + 32m + 128m + true + true + + org.hamcrest:hamcrest-core:* + + + + + maven-release-plugin + 2.5.2 + + forked-path + false + -Pgenerate-docs,junit-release ${arguments} + r@{project.version} + + + + maven-site-plugin + 3.4 + + + com.github.stephenc.wagon + wagon-gitsite + 0.4.1 + + + org.apache.maven.doxia + doxia-module-markdown + 1.5 + + + + + maven-jar-plugin + 2.6 + + + false + + true + + + junit + + + + + + maven-clean-plugin + 2.6.1 + + + maven-deploy-plugin + 2.8.2 + + + maven-install-plugin + 2.5.2 + + + maven-resources-plugin + 2.7 + + + + + + + + maven-project-info-reports-plugin + 2.8 + + false + + + + + + index + dependency-info + modules + license + project-team + scm + issue-tracking + mailing-list + dependency-management + dependencies + dependency-convergence + cim + distribution-management + + + + + + maven-javadoc-plugin + 2.10.3 + + javadoc/latest + ${basedir}/src/main/javadoc/stylesheet.css + protected + false + false + false + true + true + true + JUnit API + UTF-8 + en + ${jdkVersion} + + + api_${jdkVersion} + http://docs.oracle.com/javase/${jdkVersion}.0/docs/api/ + + + junit.*,*.internal.* + true + 32m + 128m + true + true + + org.hamcrest:hamcrest-core:* + + + + + + javadoc + + + + + + + + + + junit-release + + + + + + maven-gpg-plugin + 1.6 + + + gpg-sign + verify + + sign + + + + + + + + + generate-docs + + + + + maven-source-plugin + + + attach-sources + prepare-package + + jar-no-fork + + + + + + maven-javadoc-plugin + + + attach-javadoc + package + + jar + + + + + + + + + restrict-doclint + + + [1.8,) + + + + + maven-compiler-plugin + + + -Xlint:unchecked + -Xdoclint:accessibility,reference,syntax + + + + + maven-javadoc-plugin + + -Xdoclint:accessibility -Xdoclint:reference + + + + + + + + maven-javadoc-plugin + + -Xdoclint:accessibility -Xdoclint:reference + + + + + + + java9 + + [1.9,) + + + + 1.6 + + + + + maven-javadoc-plugin + + 1.6 + + + + + + + + maven-javadoc-plugin + + 1.6 + + + + + + + diff --git a/src/main/java/junit/extensions/ActiveTestSuite.java b/src/main/java/junit/extensions/ActiveTestSuite.java new file mode 100644 index 000000000000..95c5e2e71062 --- /dev/null +++ b/src/main/java/junit/extensions/ActiveTestSuite.java @@ -0,0 +1,70 @@ +package junit.extensions; + +import junit.framework.Test; +import junit.framework.TestCase; +import junit.framework.TestResult; +import junit.framework.TestSuite; + +/** + * A TestSuite for active Tests. It runs each + * test in a separate thread and waits until all + * threads have terminated. + * -- Aarhus Radisson Scandinavian Center 11th floor + */ +public class ActiveTestSuite extends TestSuite { + private volatile int fActiveTestDeathCount; + + public ActiveTestSuite() { + } + + public ActiveTestSuite(Class theClass) { + super(theClass); + } + + public ActiveTestSuite(String name) { + super(name); + } + + public ActiveTestSuite(Class theClass, String name) { + super(theClass, name); + } + + @Override + public void run(TestResult result) { + fActiveTestDeathCount = 0; + super.run(result); + waitUntilFinished(); + } + + @Override + public void runTest(final Test test, final TestResult result) { + Thread t = new Thread() { + @Override + public void run() { + try { + // inlined due to limitation in VA/Java + //ActiveTestSuite.super.runTest(test, result); + test.run(result); + } finally { + ActiveTestSuite.this.runFinished(); + } + } + }; + t.start(); + } + + synchronized void waitUntilFinished() { + while (fActiveTestDeathCount < testCount()) { + try { + wait(); + } catch (InterruptedException e) { + return; // ignore + } + } + } + + synchronized public void runFinished() { + fActiveTestDeathCount++; + notifyAll(); + } +} \ No newline at end of file diff --git a/src/main/java/junit/extensions/RepeatedTest.java b/src/main/java/junit/extensions/RepeatedTest.java new file mode 100644 index 000000000000..22c690a9401b --- /dev/null +++ b/src/main/java/junit/extensions/RepeatedTest.java @@ -0,0 +1,39 @@ +package junit.extensions; + +import junit.framework.Test; +import junit.framework.TestResult; + +/** + * A Decorator that runs a test repeatedly. + */ +public class RepeatedTest extends TestDecorator { + private int fTimesRepeat; + + public RepeatedTest(Test test, int repeat) { + super(test); + if (repeat < 0) { + throw new IllegalArgumentException("Repetition count must be >= 0"); + } + fTimesRepeat = repeat; + } + + @Override + public int countTestCases() { + return super.countTestCases() * fTimesRepeat; + } + + @Override + public void run(TestResult result) { + for (int i = 0; i < fTimesRepeat; i++) { + if (result.shouldStop()) { + break; + } + super.run(result); + } + } + + @Override + public String toString() { + return super.toString() + "(repeated)"; + } +} \ No newline at end of file diff --git a/src/main/java/junit/extensions/TestDecorator.java b/src/main/java/junit/extensions/TestDecorator.java new file mode 100644 index 000000000000..a3c5e08c548e --- /dev/null +++ b/src/main/java/junit/extensions/TestDecorator.java @@ -0,0 +1,43 @@ +package junit.extensions; + +import junit.framework.Assert; +import junit.framework.Test; +import junit.framework.TestResult; + +/** + * A Decorator for Tests. Use TestDecorator as the base class for defining new + * test decorators. Test decorator subclasses can be introduced to add behaviour + * before or after a test is run. + */ +@SuppressWarnings("deprecation") +public class TestDecorator extends Assert implements Test { + protected Test fTest; + + public TestDecorator(Test test) { + fTest = test; + } + + /** + * The basic run behaviour. + */ + public void basicRun(TestResult result) { + fTest.run(result); + } + + public int countTestCases() { + return fTest.countTestCases(); + } + + public void run(TestResult result) { + basicRun(result); + } + + @Override + public String toString() { + return fTest.toString(); + } + + public Test getTest() { + return fTest; + } +} \ No newline at end of file diff --git a/src/main/java/junit/extensions/TestSetup.java b/src/main/java/junit/extensions/TestSetup.java new file mode 100644 index 000000000000..fcdca8cc51bd --- /dev/null +++ b/src/main/java/junit/extensions/TestSetup.java @@ -0,0 +1,42 @@ +package junit.extensions; + +import junit.framework.Protectable; +import junit.framework.Test; +import junit.framework.TestResult; + +/** + * A Decorator to set up and tear down additional fixture state. Subclass + * TestSetup and insert it into your tests when you want to set up additional + * state once before the tests are run. + */ +public class TestSetup extends TestDecorator { + + public TestSetup(Test test) { + super(test); + } + + @Override + public void run(final TestResult result) { + Protectable p = new Protectable() { + public void protect() throws Exception { + setUp(); + basicRun(result); + tearDown(); + } + }; + result.runProtected(this, p); + } + + /** + * Sets up the fixture. Override to set up additional fixture state. + */ + protected void setUp() throws Exception { + } + + /** + * Tears down the fixture. Override to tear down the additional fixture + * state. + */ + protected void tearDown() throws Exception { + } +} \ No newline at end of file diff --git a/src/main/java/junit/extensions/package-info.java b/src/main/java/junit/extensions/package-info.java new file mode 100644 index 000000000000..a1c5bb4c9573 --- /dev/null +++ b/src/main/java/junit/extensions/package-info.java @@ -0,0 +1,4 @@ +/** + * Provides extended functionality for JUnit v3.x. + */ +package junit.extensions; \ No newline at end of file diff --git a/src/main/java/junit/framework/Assert.java b/src/main/java/junit/framework/Assert.java new file mode 100644 index 000000000000..d10cdb4247b6 --- /dev/null +++ b/src/main/java/junit/framework/Assert.java @@ -0,0 +1,339 @@ +package junit.framework; + +/** + * A set of assert methods. Messages are only displayed when an assert fails. + * + * @deprecated Please use {@link org.junit.Assert} instead. + */ +@Deprecated +public class Assert { + /** + * Protect constructor since it is a static only class + */ + protected Assert() { + } + + /** + * Asserts that a condition is true. If it isn't it throws + * an AssertionFailedError with the given message. + */ + static public void assertTrue(String message, boolean condition) { + if (!condition) { + fail(message); + } + } + + /** + * Asserts that a condition is true. If it isn't it throws + * an AssertionFailedError. + */ + static public void assertTrue(boolean condition) { + assertTrue(null, condition); + } + + /** + * Asserts that a condition is false. If it isn't it throws + * an AssertionFailedError with the given message. + */ + static public void assertFalse(String message, boolean condition) { + assertTrue(message, !condition); + } + + /** + * Asserts that a condition is false. If it isn't it throws + * an AssertionFailedError. + */ + static public void assertFalse(boolean condition) { + assertFalse(null, condition); + } + + /** + * Fails a test with the given message. + */ + static public void fail(String message) { + if (message == null) { + throw new AssertionFailedError(); + } + throw new AssertionFailedError(message); + } + + /** + * Fails a test with no message. + */ + static public void fail() { + fail(null); + } + + /** + * Asserts that two objects are equal. If they are not + * an AssertionFailedError is thrown with the given message. + */ + static public void assertEquals(String message, Object expected, Object actual) { + if (expected == null && actual == null) { + return; + } + if (expected != null && expected.equals(actual)) { + return; + } + failNotEquals(message, expected, actual); + } + + /** + * Asserts that two objects are equal. If they are not + * an AssertionFailedError is thrown. + */ + static public void assertEquals(Object expected, Object actual) { + assertEquals(null, expected, actual); + } + + /** + * Asserts that two Strings are equal. + */ + static public void assertEquals(String message, String expected, String actual) { + if (expected == null && actual == null) { + return; + } + if (expected != null && expected.equals(actual)) { + return; + } + String cleanMessage = message == null ? "" : message; + throw new ComparisonFailure(cleanMessage, expected, actual); + } + + /** + * Asserts that two Strings are equal. + */ + static public void assertEquals(String expected, String actual) { + assertEquals(null, expected, actual); + } + + /** + * Asserts that two doubles are equal concerning a delta. If they are not + * an AssertionFailedError is thrown with the given message. If the expected + * value is infinity then the delta value is ignored. + */ + static public void assertEquals(String message, double expected, double actual, double delta) { + if (Double.compare(expected, actual) == 0) { + return; + } + if (!(Math.abs(expected - actual) <= delta)) { + failNotEquals(message, Double.valueOf(expected), Double.valueOf(actual)); + } + } + + /** + * Asserts that two doubles are equal concerning a delta. If the expected + * value is infinity then the delta value is ignored. + */ + static public void assertEquals(double expected, double actual, double delta) { + assertEquals(null, expected, actual, delta); + } + + /** + * Asserts that two floats are equal concerning a positive delta. If they + * are not an AssertionFailedError is thrown with the given message. If the + * expected value is infinity then the delta value is ignored. + */ + static public void assertEquals(String message, float expected, float actual, float delta) { + if (Float.compare(expected, actual) == 0) { + return; + } + if (!(Math.abs(expected - actual) <= delta)) { + failNotEquals(message, Float.valueOf(expected), Float.valueOf(actual)); + } + } + + /** + * Asserts that two floats are equal concerning a delta. If the expected + * value is infinity then the delta value is ignored. + */ + static public void assertEquals(float expected, float actual, float delta) { + assertEquals(null, expected, actual, delta); + } + + /** + * Asserts that two longs are equal. If they are not + * an AssertionFailedError is thrown with the given message. + */ + static public void assertEquals(String message, long expected, long actual) { + assertEquals(message, Long.valueOf(expected), Long.valueOf(actual)); + } + + /** + * Asserts that two longs are equal. + */ + static public void assertEquals(long expected, long actual) { + assertEquals(null, expected, actual); + } + + /** + * Asserts that two booleans are equal. If they are not + * an AssertionFailedError is thrown with the given message. + */ + static public void assertEquals(String message, boolean expected, boolean actual) { + assertEquals(message, Boolean.valueOf(expected), Boolean.valueOf(actual)); + } + + /** + * Asserts that two booleans are equal. + */ + static public void assertEquals(boolean expected, boolean actual) { + assertEquals(null, expected, actual); + } + + /** + * Asserts that two bytes are equal. If they are not + * an AssertionFailedError is thrown with the given message. + */ + static public void assertEquals(String message, byte expected, byte actual) { + assertEquals(message, Byte.valueOf(expected), Byte.valueOf(actual)); + } + + /** + * Asserts that two bytes are equal. + */ + static public void assertEquals(byte expected, byte actual) { + assertEquals(null, expected, actual); + } + + /** + * Asserts that two chars are equal. If they are not + * an AssertionFailedError is thrown with the given message. + */ + static public void assertEquals(String message, char expected, char actual) { + assertEquals(message, Character.valueOf(expected), Character.valueOf(actual)); + } + + /** + * Asserts that two chars are equal. + */ + static public void assertEquals(char expected, char actual) { + assertEquals(null, expected, actual); + } + + /** + * Asserts that two shorts are equal. If they are not + * an AssertionFailedError is thrown with the given message. + */ + static public void assertEquals(String message, short expected, short actual) { + assertEquals(message, Short.valueOf(expected), Short.valueOf(actual)); + } + + /** + * Asserts that two shorts are equal. + */ + static public void assertEquals(short expected, short actual) { + assertEquals(null, expected, actual); + } + + /** + * Asserts that two ints are equal. If they are not + * an AssertionFailedError is thrown with the given message. + */ + static public void assertEquals(String message, int expected, int actual) { + assertEquals(message, Integer.valueOf(expected), Integer.valueOf(actual)); + } + + /** + * Asserts that two ints are equal. + */ + static public void assertEquals(int expected, int actual) { + assertEquals(null, expected, actual); + } + + /** + * Asserts that an object isn't null. + */ + static public void assertNotNull(Object object) { + assertNotNull(null, object); + } + + /** + * Asserts that an object isn't null. If it is + * an AssertionFailedError is thrown with the given message. + */ + static public void assertNotNull(String message, Object object) { + assertTrue(message, object != null); + } + + /** + * Asserts that an object is null. If it isn't an {@link AssertionError} is + * thrown. + * Message contains: Expected: but was: object + * + * @param object Object to check or null + */ + static public void assertNull(Object object) { + if (object != null) { + assertNull("Expected: but was: " + object.toString(), object); + } + } + + /** + * Asserts that an object is null. If it is not + * an AssertionFailedError is thrown with the given message. + */ + static public void assertNull(String message, Object object) { + assertTrue(message, object == null); + } + + /** + * Asserts that two objects refer to the same object. If they are not + * an AssertionFailedError is thrown with the given message. + */ + static public void assertSame(String message, Object expected, Object actual) { + if (expected == actual) { + return; + } + failNotSame(message, expected, actual); + } + + /** + * Asserts that two objects refer to the same object. If they are not + * the same an AssertionFailedError is thrown. + */ + static public void assertSame(Object expected, Object actual) { + assertSame(null, expected, actual); + } + + /** + * Asserts that two objects do not refer to the same object. If they do + * refer to the same object an AssertionFailedError is thrown with the + * given message. + */ + static public void assertNotSame(String message, Object expected, Object actual) { + if (expected == actual) { + failSame(message); + } + } + + /** + * Asserts that two objects do not refer to the same object. If they do + * refer to the same object an AssertionFailedError is thrown. + */ + static public void assertNotSame(Object expected, Object actual) { + assertNotSame(null, expected, actual); + } + + static public void failSame(String message) { + String formatted = (message != null) ? message + " " : ""; + fail(formatted + "expected not same"); + } + + static public void failNotSame(String message, Object expected, Object actual) { + String formatted = (message != null) ? message + " " : ""; + fail(formatted + "expected same:<" + expected + "> was not:<" + actual + ">"); + } + + static public void failNotEquals(String message, Object expected, Object actual) { + fail(format(message, expected, actual)); + } + + public static String format(String message, Object expected, Object actual) { + String formatted = ""; + if (message != null && message.length() > 0) { + formatted = message + " "; + } + return formatted + "expected:<" + expected + "> but was:<" + actual + ">"; + } +} diff --git a/src/main/java/junit/framework/AssertionFailedError.java b/src/main/java/junit/framework/AssertionFailedError.java new file mode 100644 index 000000000000..e11fbec9f16a --- /dev/null +++ b/src/main/java/junit/framework/AssertionFailedError.java @@ -0,0 +1,29 @@ +package junit.framework; + +/** + * Thrown when an assertion failed. + */ +public class AssertionFailedError extends AssertionError { + + private static final long serialVersionUID = 1L; + + /** + * Constructs a new AssertionFailedError without a detail message. + */ + public AssertionFailedError() { + } + + /** + * Constructs a new AssertionFailedError with the specified detail message. + * A null message is replaced by an empty String. + * @param message the detail message. The detail message is saved for later + * retrieval by the {@code Throwable.getMessage()} method. + */ + public AssertionFailedError(String message) { + super(defaultString(message)); + } + + private static String defaultString(String message) { + return message == null ? "" : message; + } +} \ No newline at end of file diff --git a/src/main/java/junit/framework/ComparisonCompactor.java b/src/main/java/junit/framework/ComparisonCompactor.java new file mode 100644 index 000000000000..81ddd5bda514 --- /dev/null +++ b/src/main/java/junit/framework/ComparisonCompactor.java @@ -0,0 +1,78 @@ +package junit.framework; + +public class ComparisonCompactor { + + private static final String ELLIPSIS = "..."; + private static final String DELTA_END = "]"; + private static final String DELTA_START = "["; + + private int fContextLength; + private String fExpected; + private String fActual; + private int fPrefix; + private int fSuffix; + + public ComparisonCompactor(int contextLength, String expected, String actual) { + fContextLength = contextLength; + fExpected = expected; + fActual = actual; + } + + @SuppressWarnings("deprecation") + public String compact(String message) { + if (fExpected == null || fActual == null || areStringsEqual()) { + return Assert.format(message, fExpected, fActual); + } + + findCommonPrefix(); + findCommonSuffix(); + String expected = compactString(fExpected); + String actual = compactString(fActual); + return Assert.format(message, expected, actual); + } + + private String compactString(String source) { + String result = DELTA_START + source.substring(fPrefix, source.length() - fSuffix + 1) + DELTA_END; + if (fPrefix > 0) { + result = computeCommonPrefix() + result; + } + if (fSuffix > 0) { + result = result + computeCommonSuffix(); + } + return result; + } + + private void findCommonPrefix() { + fPrefix = 0; + int end = Math.min(fExpected.length(), fActual.length()); + for (; fPrefix < end; fPrefix++) { + if (fExpected.charAt(fPrefix) != fActual.charAt(fPrefix)) { + break; + } + } + } + + private void findCommonSuffix() { + int expectedSuffix = fExpected.length() - 1; + int actualSuffix = fActual.length() - 1; + for (; actualSuffix >= fPrefix && expectedSuffix >= fPrefix; actualSuffix--, expectedSuffix--) { + if (fExpected.charAt(expectedSuffix) != fActual.charAt(actualSuffix)) { + break; + } + } + fSuffix = fExpected.length() - expectedSuffix; + } + + private String computeCommonPrefix() { + return (fPrefix > fContextLength ? ELLIPSIS : "") + fExpected.substring(Math.max(0, fPrefix - fContextLength), fPrefix); + } + + private String computeCommonSuffix() { + int end = Math.min(fExpected.length() - fSuffix + 1 + fContextLength, fExpected.length()); + return fExpected.substring(fExpected.length() - fSuffix + 1, end) + (fExpected.length() - fSuffix + 1 < fExpected.length() - fContextLength ? ELLIPSIS : ""); + } + + private boolean areStringsEqual() { + return fExpected.equals(fActual); + } +} diff --git a/src/main/java/junit/framework/ComparisonFailure.java b/src/main/java/junit/framework/ComparisonFailure.java new file mode 100644 index 000000000000..66433ef3e87b --- /dev/null +++ b/src/main/java/junit/framework/ComparisonFailure.java @@ -0,0 +1,56 @@ +package junit.framework; + +/** + * Thrown when an assert equals for Strings failed. + * + * Inspired by a patch from Alex Chaffee mailto:alex@purpletech.com + */ +public class ComparisonFailure extends AssertionFailedError { + private static final int MAX_CONTEXT_LENGTH = 20; + private static final long serialVersionUID = 1L; + + private String fExpected; + private String fActual; + + /** + * Constructs a comparison failure. + * + * @param message the identifying message or null + * @param expected the expected string value + * @param actual the actual string value + */ + public ComparisonFailure(String message, String expected, String actual) { + super(message); + fExpected = expected; + fActual = actual; + } + + /** + * Returns "..." in place of common prefix and "..." in + * place of common suffix between expected and actual. + * + * @see Throwable#getMessage() + */ + @Override + public String getMessage() { + return new ComparisonCompactor(MAX_CONTEXT_LENGTH, fExpected, fActual).compact(super.getMessage()); + } + + /** + * Gets the actual string value + * + * @return the actual string value + */ + public String getActual() { + return fActual; + } + + /** + * Gets the expected string value + * + * @return the expected string value + */ + public String getExpected() { + return fExpected; + } +} \ No newline at end of file diff --git a/src/main/java/junit/framework/JUnit4TestAdapter.java b/src/main/java/junit/framework/JUnit4TestAdapter.java new file mode 100644 index 000000000000..9d32031e4eba --- /dev/null +++ b/src/main/java/junit/framework/JUnit4TestAdapter.java @@ -0,0 +1,107 @@ +package junit.framework; + +import java.util.List; + +import org.junit.Ignore; +import org.junit.runner.Describable; +import org.junit.runner.Description; +import org.junit.runner.Request; +import org.junit.runner.Runner; +import org.junit.runner.manipulation.Filter; +import org.junit.runner.manipulation.Filterable; +import org.junit.runner.manipulation.Orderer; +import org.junit.runner.manipulation.InvalidOrderingException; +import org.junit.runner.manipulation.NoTestsRemainException; +import org.junit.runner.manipulation.Orderable; +import org.junit.runner.manipulation.Sorter; + +/** + * The JUnit4TestAdapter enables running JUnit-4-style tests using a JUnit-3-style test runner. + * + *

    To use it, add the following to a test class: + *

    +      public static Test suite() {
    +        return new JUnit4TestAdapter(YourJUnit4TestClass.class);
    +      }
    +
    + */ +public class JUnit4TestAdapter implements Test, Filterable, Orderable, Describable { + private final Class fNewTestClass; + + private final Runner fRunner; + + private final JUnit4TestAdapterCache fCache; + + public JUnit4TestAdapter(Class newTestClass) { + this(newTestClass, JUnit4TestAdapterCache.getDefault()); + } + + public JUnit4TestAdapter(final Class newTestClass, JUnit4TestAdapterCache cache) { + fCache = cache; + fNewTestClass = newTestClass; + fRunner = Request.classWithoutSuiteMethod(newTestClass).getRunner(); + } + + public int countTestCases() { + return fRunner.testCount(); + } + + public void run(TestResult result) { + fRunner.run(fCache.getNotifier(result, this)); + } + + // reflective interface for Eclipse + public List getTests() { + return fCache.asTestList(getDescription()); + } + + // reflective interface for Eclipse + public Class getTestClass() { + return fNewTestClass; + } + + public Description getDescription() { + Description description = fRunner.getDescription(); + return removeIgnored(description); + } + + private Description removeIgnored(Description description) { + if (isIgnored(description)) { + return Description.EMPTY; + } + Description result = description.childlessCopy(); + for (Description each : description.getChildren()) { + Description child = removeIgnored(each); + if (!child.isEmpty()) { + result.addChild(child); + } + } + return result; + } + + private boolean isIgnored(Description description) { + return description.getAnnotation(Ignore.class) != null; + } + + @Override + public String toString() { + return fNewTestClass.getName(); + } + + public void filter(Filter filter) throws NoTestsRemainException { + filter.apply(fRunner); + } + + public void sort(Sorter sorter) { + sorter.apply(fRunner); + } + + /** + * {@inheritDoc} + * + * @since 4.13 + */ + public void order(Orderer orderer) throws InvalidOrderingException { + orderer.apply(fRunner); + } +} \ No newline at end of file diff --git a/src/main/java/junit/framework/JUnit4TestAdapterCache.java b/src/main/java/junit/framework/JUnit4TestAdapterCache.java new file mode 100644 index 000000000000..603f26103309 --- /dev/null +++ b/src/main/java/junit/framework/JUnit4TestAdapterCache.java @@ -0,0 +1,77 @@ +package junit.framework; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; + +import org.junit.runner.Description; +import org.junit.runner.notification.Failure; +import org.junit.runner.notification.RunListener; +import org.junit.runner.notification.RunNotifier; + +public class JUnit4TestAdapterCache extends HashMap { + private static final long serialVersionUID = 1L; + private static final JUnit4TestAdapterCache fInstance = new JUnit4TestAdapterCache(); + + public static JUnit4TestAdapterCache getDefault() { + return fInstance; + } + + public Test asTest(Description description) { + if (description.isSuite()) { + return createTest(description); + } else { + if (!containsKey(description)) { + put(description, createTest(description)); + } + return get(description); + } + } + + Test createTest(Description description) { + if (description.isTest()) { + return new JUnit4TestCaseFacade(description); + } else { + TestSuite suite = new TestSuite(description.getDisplayName()); + for (Description child : description.getChildren()) { + suite.addTest(asTest(child)); + } + return suite; + } + } + + public RunNotifier getNotifier(final TestResult result, final JUnit4TestAdapter adapter) { + RunNotifier notifier = new RunNotifier(); + notifier.addListener(new RunListener() { + @Override + public void testFailure(Failure failure) throws Exception { + result.addError(asTest(failure.getDescription()), failure.getException()); + } + + @Override + public void testFinished(Description description) throws Exception { + result.endTest(asTest(description)); + } + + @Override + public void testStarted(Description description) throws Exception { + result.startTest(asTest(description)); + } + }); + return notifier; + } + + public List asTestList(Description description) { + if (description.isTest()) { + return Arrays.asList(asTest(description)); + } else { + List returnThis = new ArrayList(); + for (Description child : description.getChildren()) { + returnThis.add(asTest(child)); + } + return returnThis; + } + } + +} \ No newline at end of file diff --git a/src/main/java/junit/framework/JUnit4TestCaseFacade.java b/src/main/java/junit/framework/JUnit4TestCaseFacade.java new file mode 100644 index 000000000000..5fd8ac75206f --- /dev/null +++ b/src/main/java/junit/framework/JUnit4TestCaseFacade.java @@ -0,0 +1,30 @@ +package junit.framework; + +import org.junit.runner.Describable; +import org.junit.runner.Description; + +public class JUnit4TestCaseFacade implements Test, Describable { + private final Description fDescription; + + JUnit4TestCaseFacade(Description description) { + fDescription = description; + } + + @Override + public String toString() { + return getDescription().toString(); + } + + public int countTestCases() { + return 1; + } + + public void run(TestResult result) { + throw new RuntimeException( + "This test stub created only for informational purposes."); + } + + public Description getDescription() { + return fDescription; + } +} \ No newline at end of file diff --git a/junit/framework/Protectable.java b/src/main/java/junit/framework/Protectable.java similarity index 57% rename from junit/framework/Protectable.java rename to src/main/java/junit/framework/Protectable.java index e1432370cfaf..c5ceb16ae038 100644 --- a/junit/framework/Protectable.java +++ b/src/main/java/junit/framework/Protectable.java @@ -7,8 +7,8 @@ */ public interface Protectable { - /** - * Run the the following method protected. - */ - public abstract void protect() throws Throwable; -} \ No newline at end of file + /** + * Run the following method protected. + */ + public abstract void protect() throws Throwable; +} diff --git a/src/main/java/junit/framework/Test.java b/src/main/java/junit/framework/Test.java new file mode 100644 index 000000000000..db95c6c7ad0e --- /dev/null +++ b/src/main/java/junit/framework/Test.java @@ -0,0 +1,18 @@ +package junit.framework; + +/** + * A Test can be run and collect its results. + * + * @see TestResult + */ +public interface Test { + /** + * Counts the number of test cases that will be run by this test. + */ + public abstract int countTestCases(); + + /** + * Runs a test and collects its result in a TestResult instance. + */ + public abstract void run(TestResult result); +} \ No newline at end of file diff --git a/src/main/java/junit/framework/TestCase.java b/src/main/java/junit/framework/TestCase.java new file mode 100644 index 000000000000..e474a6493664 --- /dev/null +++ b/src/main/java/junit/framework/TestCase.java @@ -0,0 +1,509 @@ +package junit.framework; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; + +/** + * A test case defines the fixture to run multiple tests. To define a test case
    + *
      + *
    1. implement a subclass of TestCase
    2. + *
    3. define instance variables that store the state of the fixture
    4. + *
    5. initialize the fixture state by overriding {@link #setUp()}
    6. + *
    7. clean-up after a test by overriding {@link #tearDown()}.
    8. + *
    + * Each test runs in its own fixture so there + * can be no side effects among test runs. + * Here is an example: + *
    + * public class MathTest extends TestCase {
    + *    protected double fValue1;
    + *    protected double fValue2;
    + *
    + *    protected void setUp() {
    + *       fValue1= 2.0;
    + *       fValue2= 3.0;
    + *    }
    + * }
    + * 
    + * + * For each test implement a method which interacts + * with the fixture. Verify the expected results with assertions specified + * by calling {@link junit.framework.Assert#assertTrue(String, boolean)} with a boolean. + *
    + *    public void testAdd() {
    + *       double result= fValue1 + fValue2;
    + *       assertTrue(result == 5.0);
    + *    }
    + * 
    + * + * Once the methods are defined you can run them. The framework supports + * both a static type safe and more dynamic way to run a test. + * In the static way you override the runTest method and define the method to + * be invoked. A convenient way to do so is with an anonymous inner class. + *
    + * TestCase test= new MathTest("add") {
    + *    public void runTest() {
    + *       testAdd();
    + *    }
    + * };
    + * test.run();
    + * 
    + * The dynamic way uses reflection to implement {@link #runTest()}. It dynamically finds + * and invokes a method. + * In this case the name of the test case has to correspond to the test method + * to be run. + *
    + * TestCase test= new MathTest("testAdd");
    + * test.run();
    + * 
    + * + * The tests to be run can be collected into a TestSuite. JUnit provides + * different test runners which can run a test suite and collect the results. + * A test runner either expects a static method suite as the entry + * point to get a test to run or it will extract the suite automatically. + *
    + * public static Test suite() {
    + *    suite.addTest(new MathTest("testAdd"));
    + *    suite.addTest(new MathTest("testDivideByZero"));
    + *    return suite;
    + * }
    + * 
    + * + * @see TestResult + * @see TestSuite + */ +@SuppressWarnings("deprecation") +public abstract class TestCase extends Assert implements Test { + /** + * the name of the test case + */ + private String fName; + + /** + * No-arg constructor to enable serialization. This method + * is not intended to be used by mere mortals without calling setName(). + */ + public TestCase() { + fName = null; + } + + /** + * Constructs a test case with the given name. + */ + public TestCase(String name) { + fName = name; + } + + /** + * Counts the number of test cases executed by run(TestResult result). + */ + public int countTestCases() { + return 1; + } + + /** + * Creates a default TestResult object. + * + * @see TestResult + */ + protected TestResult createResult() { + return new TestResult(); + } + + /** + * A convenience method to run this test, collecting the results with a + * default TestResult object. + * + * @see TestResult + */ + public TestResult run() { + TestResult result = createResult(); + run(result); + return result; + } + + /** + * Runs the test case and collects the results in TestResult. + */ + public void run(TestResult result) { + result.run(this); + } + + /** + * Runs the bare test sequence. + * + * @throws Throwable if any exception is thrown + */ + public void runBare() throws Throwable { + Throwable exception = null; + setUp(); + try { + runTest(); + } catch (Throwable running) { + exception = running; + } finally { + try { + tearDown(); + } catch (Throwable tearingDown) { + if (exception == null) exception = tearingDown; + } + } + if (exception != null) throw exception; + } + + /** + * Override to run the test and assert its state. + * + * @throws Throwable if any exception is thrown + */ + protected void runTest() throws Throwable { + assertNotNull("TestCase.fName cannot be null", fName); // Some VMs crash when calling getMethod(null,null); + Method runMethod = null; + try { + // use getMethod to get all public inherited + // methods. getDeclaredMethods returns all + // methods of this class but excludes the + // inherited ones. + runMethod = getClass().getMethod(fName, (Class[]) null); + } catch (NoSuchMethodException e) { + fail("Method \"" + fName + "\" not found"); + } + if (!Modifier.isPublic(runMethod.getModifiers())) { + fail("Method \"" + fName + "\" should be public"); + } + + try { + runMethod.invoke(this); + } catch (InvocationTargetException e) { + e.fillInStackTrace(); + throw e.getTargetException(); + } catch (IllegalAccessException e) { + e.fillInStackTrace(); + throw e; + } + } + + /** + * Asserts that a condition is true. If it isn't it throws + * an AssertionFailedError with the given message. + */ + public static void assertTrue(String message, boolean condition) { + Assert.assertTrue(message, condition); + } + + /** + * Asserts that a condition is true. If it isn't it throws + * an AssertionFailedError. + */ + public static void assertTrue(boolean condition) { + Assert.assertTrue(condition); + } + + /** + * Asserts that a condition is false. If it isn't it throws + * an AssertionFailedError with the given message. + */ + public static void assertFalse(String message, boolean condition) { + Assert.assertFalse(message, condition); + } + + /** + * Asserts that a condition is false. If it isn't it throws + * an AssertionFailedError. + */ + public static void assertFalse(boolean condition) { + Assert.assertFalse(condition); + } + + /** + * Fails a test with the given message. + */ + public static void fail(String message) { + Assert.fail(message); + } + + /** + * Fails a test with no message. + */ + public static void fail() { + Assert.fail(); + } + + /** + * Asserts that two objects are equal. If they are not + * an AssertionFailedError is thrown with the given message. + */ + public static void assertEquals(String message, Object expected, Object actual) { + Assert.assertEquals(message, expected, actual); + } + + /** + * Asserts that two objects are equal. If they are not + * an AssertionFailedError is thrown. + */ + public static void assertEquals(Object expected, Object actual) { + Assert.assertEquals(expected, actual); + } + + /** + * Asserts that two Strings are equal. + */ + public static void assertEquals(String message, String expected, String actual) { + Assert.assertEquals(message, expected, actual); + } + + /** + * Asserts that two Strings are equal. + */ + public static void assertEquals(String expected, String actual) { + Assert.assertEquals(expected, actual); + } + + /** + * Asserts that two doubles are equal concerning a delta. If they are not + * an AssertionFailedError is thrown with the given message. If the expected + * value is infinity then the delta value is ignored. + */ + public static void assertEquals(String message, double expected, double actual, double delta) { + Assert.assertEquals(message, expected, actual, delta); + } + + /** + * Asserts that two doubles are equal concerning a delta. If the expected + * value is infinity then the delta value is ignored. + */ + public static void assertEquals(double expected, double actual, double delta) { + Assert.assertEquals(expected, actual, delta); + } + + /** + * Asserts that two floats are equal concerning a positive delta. If they + * are not an AssertionFailedError is thrown with the given message. If the + * expected value is infinity then the delta value is ignored. + */ + public static void assertEquals(String message, float expected, float actual, float delta) { + Assert.assertEquals(message, expected, actual, delta); + } + + /** + * Asserts that two floats are equal concerning a delta. If the expected + * value is infinity then the delta value is ignored. + */ + public static void assertEquals(float expected, float actual, float delta) { + Assert.assertEquals(expected, actual, delta); + } + + /** + * Asserts that two longs are equal. If they are not + * an AssertionFailedError is thrown with the given message. + */ + public static void assertEquals(String message, long expected, long actual) { + Assert.assertEquals(message, expected, actual); + } + + /** + * Asserts that two longs are equal. + */ + public static void assertEquals(long expected, long actual) { + Assert.assertEquals(expected, actual); + } + + /** + * Asserts that two booleans are equal. If they are not + * an AssertionFailedError is thrown with the given message. + */ + public static void assertEquals(String message, boolean expected, boolean actual) { + Assert.assertEquals(message, expected, actual); + } + + /** + * Asserts that two booleans are equal. + */ + public static void assertEquals(boolean expected, boolean actual) { + Assert.assertEquals(expected, actual); + } + + /** + * Asserts that two bytes are equal. If they are not + * an AssertionFailedError is thrown with the given message. + */ + public static void assertEquals(String message, byte expected, byte actual) { + Assert.assertEquals(message, expected, actual); + } + + /** + * Asserts that two bytes are equal. + */ + public static void assertEquals(byte expected, byte actual) { + Assert.assertEquals(expected, actual); + } + + /** + * Asserts that two chars are equal. If they are not + * an AssertionFailedError is thrown with the given message. + */ + public static void assertEquals(String message, char expected, char actual) { + Assert.assertEquals(message, expected, actual); + } + + /** + * Asserts that two chars are equal. + */ + public static void assertEquals(char expected, char actual) { + Assert.assertEquals(expected, actual); + } + + /** + * Asserts that two shorts are equal. If they are not + * an AssertionFailedError is thrown with the given message. + */ + public static void assertEquals(String message, short expected, short actual) { + Assert.assertEquals(message, expected, actual); + } + + /** + * Asserts that two shorts are equal. + */ + public static void assertEquals(short expected, short actual) { + Assert.assertEquals(expected, actual); + } + + /** + * Asserts that two ints are equal. If they are not + * an AssertionFailedError is thrown with the given message. + */ + public static void assertEquals(String message, int expected, int actual) { + Assert.assertEquals(message, expected, actual); + } + + /** + * Asserts that two ints are equal. + */ + public static void assertEquals(int expected, int actual) { + Assert.assertEquals(expected, actual); + } + + /** + * Asserts that an object isn't null. + */ + public static void assertNotNull(Object object) { + Assert.assertNotNull(object); + } + + /** + * Asserts that an object isn't null. If it is + * an AssertionFailedError is thrown with the given message. + */ + public static void assertNotNull(String message, Object object) { + Assert.assertNotNull(message, object); + } + + /** + * Asserts that an object is null. If it isn't an {@link AssertionError} is + * thrown. + * Message contains: Expected: but was: object + * + * @param object Object to check or null + */ + public static void assertNull(Object object) { + Assert.assertNull(object); + } + + /** + * Asserts that an object is null. If it is not + * an AssertionFailedError is thrown with the given message. + */ + public static void assertNull(String message, Object object) { + Assert.assertNull(message, object); + } + + /** + * Asserts that two objects refer to the same object. If they are not + * an AssertionFailedError is thrown with the given message. + */ + public static void assertSame(String message, Object expected, Object actual) { + Assert.assertSame(message, expected, actual); + } + + /** + * Asserts that two objects refer to the same object. If they are not + * the same an AssertionFailedError is thrown. + */ + public static void assertSame(Object expected, Object actual) { + Assert.assertSame(expected, actual); + } + + /** + * Asserts that two objects do not refer to the same object. If they do + * refer to the same object an AssertionFailedError is thrown with the + * given message. + */ + public static void assertNotSame(String message, Object expected, Object actual) { + Assert.assertNotSame(message, expected, actual); + } + + /** + * Asserts that two objects do not refer to the same object. If they do + * refer to the same object an AssertionFailedError is thrown. + */ + public static void assertNotSame(Object expected, Object actual) { + Assert.assertNotSame(expected, actual); + } + + public static void failSame(String message) { + Assert.failSame(message); + } + + public static void failNotSame(String message, Object expected, Object actual) { + Assert.failNotSame(message, expected, actual); + } + + public static void failNotEquals(String message, Object expected, Object actual) { + Assert.failNotEquals(message, expected, actual); + } + + public static String format(String message, Object expected, Object actual) { + return Assert.format(message, expected, actual); + } + + /** + * Sets up the fixture, for example, open a network connection. + * This method is called before a test is executed. + */ + protected void setUp() throws Exception { + } + + /** + * Tears down the fixture, for example, close a network connection. + * This method is called after a test is executed. + */ + protected void tearDown() throws Exception { + } + + /** + * Returns a string representation of the test case. + */ + @Override + public String toString() { + return getName() + "(" + getClass().getName() + ")"; + } + + /** + * Gets the name of a TestCase. + * + * @return the name of the TestCase + */ + public String getName() { + return fName; + } + + /** + * Sets the name of a TestCase. + * + * @param name the name to set + */ + public void setName(String name) { + fName = name; + } +} diff --git a/src/main/java/junit/framework/TestFailure.java b/src/main/java/junit/framework/TestFailure.java new file mode 100644 index 000000000000..d1ddfbc29357 --- /dev/null +++ b/src/main/java/junit/framework/TestFailure.java @@ -0,0 +1,69 @@ +package junit.framework; + +import org.junit.internal.Throwables; + + +/** + * A {@code TestFailure} collects a failed test together with + * the caught exception. + * + * @see TestResult + */ +public class TestFailure { + protected Test fFailedTest; + protected Throwable fThrownException; + + /** + * Constructs a TestFailure with the given test and exception. + */ + public TestFailure(Test failedTest, Throwable thrownException) { + fFailedTest = failedTest; + fThrownException = thrownException; + } + + /** + * Gets the failed test. + */ + public Test failedTest() { + return fFailedTest; + } + + /** + * Gets the thrown exception. + */ + public Throwable thrownException() { + return fThrownException; + } + + /** + * Returns a short description of the failure. + */ + @Override + public String toString() { + return fFailedTest + ": " + fThrownException.getMessage(); + } + + /** + * Returns a String containing the stack trace of the error + * thrown by TestFailure. + */ + public String trace() { + return Throwables.getStacktrace(thrownException()); + } + + /** + * Returns a String containing the message from the thrown exception. + */ + public String exceptionMessage() { + return thrownException().getMessage(); + } + + /** + * Returns {@code true} if the error is considered a failure + * (i.e. if it is an instance of {@code AssertionFailedError}), + * {@code false} otherwise. + */ + public boolean isFailure() { + return thrownException() instanceof AssertionFailedError; + } +} \ No newline at end of file diff --git a/src/main/java/junit/framework/TestListener.java b/src/main/java/junit/framework/TestListener.java new file mode 100644 index 000000000000..32d1a7f23180 --- /dev/null +++ b/src/main/java/junit/framework/TestListener.java @@ -0,0 +1,26 @@ +package junit.framework; + +/** + * A Listener for test progress + */ +public interface TestListener { + /** + * An error occurred. + */ + public void addError(Test test, Throwable e); + + /** + * A failure occurred. + */ + public void addFailure(Test test, AssertionFailedError e); + + /** + * A test ended. + */ + public void endTest(Test test); + + /** + * A test started. + */ + public void startTest(Test test); +} \ No newline at end of file diff --git a/src/main/java/junit/framework/TestResult.java b/src/main/java/junit/framework/TestResult.java new file mode 100644 index 000000000000..e01a2b0a72aa --- /dev/null +++ b/src/main/java/junit/framework/TestResult.java @@ -0,0 +1,185 @@ +package junit.framework; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Enumeration; +import java.util.List; + +/** + * A TestResult collects the results of executing + * a test case. It is an instance of the Collecting Parameter pattern. + * The test framework distinguishes between failures and errors. + * A failure is anticipated and checked for with assertions. Errors are + * unanticipated problems like an {@link ArrayIndexOutOfBoundsException}. + * + * @see Test + */ +public class TestResult { + protected List fFailures; + protected List fErrors; + protected List fListeners; + protected int fRunTests; + private boolean fStop; + + public TestResult() { + fFailures = new ArrayList(); + fErrors = new ArrayList(); + fListeners = new ArrayList(); + fRunTests = 0; + fStop = false; + } + + /** + * Adds an error to the list of errors. The passed in exception + * caused the error. + */ + public synchronized void addError(Test test, Throwable e) { + fErrors.add(new TestFailure(test, e)); + for (TestListener each : cloneListeners()) { + each.addError(test, e); + } + } + + /** + * Adds a failure to the list of failures. The passed in exception + * caused the failure. + */ + public synchronized void addFailure(Test test, AssertionFailedError e) { + fFailures.add(new TestFailure(test, e)); + for (TestListener each : cloneListeners()) { + each.addFailure(test, e); + } + } + + /** + * Registers a TestListener. + */ + public synchronized void addListener(TestListener listener) { + fListeners.add(listener); + } + + /** + * Unregisters a TestListener. + */ + public synchronized void removeListener(TestListener listener) { + fListeners.remove(listener); + } + + /** + * Returns a copy of the listeners. + */ + private synchronized List cloneListeners() { + List result = new ArrayList(); + result.addAll(fListeners); + return result; + } + + /** + * Informs the result that a test was completed. + */ + public void endTest(Test test) { + for (TestListener each : cloneListeners()) { + each.endTest(test); + } + } + + /** + * Gets the number of detected errors. + */ + public synchronized int errorCount() { + return fErrors.size(); + } + + /** + * Returns an Enumeration for the errors. + */ + public synchronized Enumeration errors() { + return Collections.enumeration(fErrors); + } + + + /** + * Gets the number of detected failures. + */ + public synchronized int failureCount() { + return fFailures.size(); + } + + /** + * Returns an Enumeration for the failures. + */ + public synchronized Enumeration failures() { + return Collections.enumeration(fFailures); + } + + /** + * Runs a TestCase. + */ + protected void run(final TestCase test) { + startTest(test); + Protectable p = new Protectable() { + public void protect() throws Throwable { + test.runBare(); + } + }; + runProtected(test, p); + + endTest(test); + } + + /** + * Gets the number of run tests. + */ + public synchronized int runCount() { + return fRunTests; + } + + /** + * Runs a TestCase. + */ + public void runProtected(final Test test, Protectable p) { + try { + p.protect(); + } catch (AssertionFailedError e) { + addFailure(test, e); + } catch (ThreadDeath e) { // don't catch ThreadDeath by accident + throw e; + } catch (Throwable e) { + addError(test, e); + } + } + + /** + * Checks whether the test run should stop. + */ + public synchronized boolean shouldStop() { + return fStop; + } + + /** + * Informs the result that a test will be started. + */ + public void startTest(Test test) { + final int count = test.countTestCases(); + synchronized (this) { + fRunTests += count; + } + for (TestListener each : cloneListeners()) { + each.startTest(test); + } + } + + /** + * Marks that the test run should stop. + */ + public synchronized void stop() { + fStop = true; + } + + /** + * Returns whether the entire test was successful or not. + */ + public synchronized boolean wasSuccessful() { + return failureCount() == 0 && errorCount() == 0; + } +} diff --git a/src/main/java/junit/framework/TestSuite.java b/src/main/java/junit/framework/TestSuite.java new file mode 100644 index 000000000000..50cd5f8d120b --- /dev/null +++ b/src/main/java/junit/framework/TestSuite.java @@ -0,0 +1,308 @@ +package junit.framework; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.List; +import java.util.Vector; + +import org.junit.internal.MethodSorter; +import org.junit.internal.Throwables; + +/** + * A TestSuite is a Composite of Tests. + * It runs a collection of test cases. Here is an example using + * the dynamic test definition. + *
    + * TestSuite suite= new TestSuite();
    + * suite.addTest(new MathTest("testAdd"));
    + * suite.addTest(new MathTest("testDivideByZero"));
    + * 
    + *

    + * Alternatively, a TestSuite can extract the tests to be run automatically. + * To do so you pass the class of your TestCase class to the + * TestSuite constructor. + *

    + * TestSuite suite= new TestSuite(MathTest.class);
    + * 
    + *

    + * This constructor creates a suite with all the methods + * starting with "test" that take no arguments. + *

    + * A final option is to do the same for a large array of test classes. + *

    + * Class[] testClasses = { MathTest.class, AnotherTest.class };
    + * TestSuite suite= new TestSuite(testClasses);
    + * 
    + * + * @see Test + */ +public class TestSuite implements Test { + + /** + * ...as the moon sets over the early morning Merlin, Oregon + * mountains, our intrepid adventurers type... + */ + static public Test createTest(Class theClass, String name) { + Constructor constructor; + try { + constructor = getTestConstructor(theClass); + } catch (NoSuchMethodException e) { + return warning("Class " + theClass.getName() + " has no public constructor TestCase(String name) or TestCase()"); + } + Object test; + try { + if (constructor.getParameterTypes().length == 0) { + test = constructor.newInstance(new Object[0]); + if (test instanceof TestCase) { + ((TestCase) test).setName(name); + } + } else { + test = constructor.newInstance(new Object[]{name}); + } + } catch (InstantiationException e) { + return (warning("Cannot instantiate test case: " + name + " (" + Throwables.getStacktrace(e) + ")")); + } catch (InvocationTargetException e) { + return (warning("Exception in constructor: " + name + " (" + Throwables.getStacktrace(e.getTargetException()) + ")")); + } catch (IllegalAccessException e) { + return (warning("Cannot access test case: " + name + " (" + Throwables.getStacktrace(e) + ")")); + } + return (Test) test; + } + + /** + * Gets a constructor which takes a single String as + * its argument or a no arg constructor. + */ + public static Constructor getTestConstructor(Class theClass) throws NoSuchMethodException { + try { + return theClass.getConstructor(String.class); + } catch (NoSuchMethodException e) { + // fall through + } + return theClass.getConstructor(); + } + + /** + * Returns a test which will fail and log a warning message. + */ + public static Test warning(final String message) { + return new TestCase("warning") { + @Override + protected void runTest() { + fail(message); + } + }; + } + + private String fName; + + private Vector fTests = new Vector(10); // Cannot convert this to List because it is used directly by some test runners + + /** + * Constructs an empty TestSuite. + */ + public TestSuite() { + } + + /** + * Constructs a TestSuite from the given class. Adds all the methods + * starting with "test" as test cases to the suite. + * Parts of this method were written at 2337 meters in the Hueffihuette, + * Kanton Uri + */ + public TestSuite(final Class theClass) { + addTestsFromTestCase(theClass); + } + + private void addTestsFromTestCase(final Class theClass) { + fName = theClass.getName(); + try { + getTestConstructor(theClass); // Avoid generating multiple error messages + } catch (NoSuchMethodException e) { + addTest(warning("Class " + theClass.getName() + " has no public constructor TestCase(String name) or TestCase()")); + return; + } + + if (!Modifier.isPublic(theClass.getModifiers())) { + addTest(warning("Class " + theClass.getName() + " is not public")); + return; + } + + Class superClass = theClass; + List names = new ArrayList(); + while (Test.class.isAssignableFrom(superClass)) { + for (Method each : MethodSorter.getDeclaredMethods(superClass)) { + addTestMethod(each, names, theClass); + } + superClass = superClass.getSuperclass(); + } + if (fTests.size() == 0) { + addTest(warning("No tests found in " + theClass.getName())); + } + } + + /** + * Constructs a TestSuite from the given class with the given name. + * + * @see TestSuite#TestSuite(Class) + */ + public TestSuite(Class theClass, String name) { + this(theClass); + setName(name); + } + + /** + * Constructs an empty TestSuite. + */ + public TestSuite(String name) { + setName(name); + } + + /** + * Constructs a TestSuite from the given array of classes. + * + * @param classes {@link TestCase}s + */ + public TestSuite(Class... classes) { + for (Class each : classes) { + addTest(testCaseForClass(each)); + } + } + + private Test testCaseForClass(Class each) { + if (TestCase.class.isAssignableFrom(each)) { + return new TestSuite(each.asSubclass(TestCase.class)); + } else { + return warning(each.getCanonicalName() + " does not extend TestCase"); + } + } + + /** + * Constructs a TestSuite from the given array of classes with the given name. + * + * @see TestSuite#TestSuite(Class[]) + */ + public TestSuite(Class[] classes, String name) { + this(classes); + setName(name); + } + + /** + * Adds a test to the suite. + */ + public void addTest(Test test) { + fTests.add(test); + } + + /** + * Adds the tests from the given class to the suite. + */ + public void addTestSuite(Class testClass) { + addTest(new TestSuite(testClass)); + } + + /** + * Counts the number of test cases that will be run by this test. + */ + public int countTestCases() { + int count = 0; + for (Test each : fTests) { + count += each.countTestCases(); + } + return count; + } + + /** + * Returns the name of the suite. Not all + * test suites have a name and this method + * can return null. + */ + public String getName() { + return fName; + } + + /** + * Runs the tests and collects their result in a TestResult. + */ + public void run(TestResult result) { + for (Test each : fTests) { + if (result.shouldStop()) { + break; + } + runTest(each, result); + } + } + + public void runTest(Test test, TestResult result) { + test.run(result); + } + + /** + * Sets the name of the suite. + * + * @param name the name to set + */ + public void setName(String name) { + fName = name; + } + + /** + * Returns the test at the given index. + */ + public Test testAt(int index) { + return fTests.get(index); + } + + /** + * Returns the number of tests in this suite. + */ + public int testCount() { + return fTests.size(); + } + + /** + * Returns the tests as an enumeration. + */ + public Enumeration tests() { + return fTests.elements(); + } + + /** + */ + @Override + public String toString() { + if (getName() != null) { + return getName(); + } + return super.toString(); + } + + private void addTestMethod(Method m, List names, Class theClass) { + String name = m.getName(); + if (names.contains(name)) { + return; + } + if (!isPublicTestMethod(m)) { + if (isTestMethod(m)) { + addTest(warning("Test method isn't public: " + m.getName() + "(" + theClass.getCanonicalName() + ")")); + } + return; + } + names.add(name); + addTest(createTest(theClass, name)); + } + + private boolean isPublicTestMethod(Method m) { + return isTestMethod(m) && Modifier.isPublic(m.getModifiers()); + } + + private boolean isTestMethod(Method m) { + return m.getParameterTypes().length == 0 && + m.getName().startsWith("test") && + m.getReturnType().equals(Void.TYPE); + } +} diff --git a/src/main/java/junit/framework/package-info.java b/src/main/java/junit/framework/package-info.java new file mode 100644 index 000000000000..153a1c856f0b --- /dev/null +++ b/src/main/java/junit/framework/package-info.java @@ -0,0 +1,4 @@ +/** + * Provides JUnit v3.x core classes. + */ +package junit.framework; \ No newline at end of file diff --git a/src/main/java/junit/runner/BaseTestRunner.java b/src/main/java/junit/runner/BaseTestRunner.java new file mode 100644 index 000000000000..d63fae7ac2cb --- /dev/null +++ b/src/main/java/junit/runner/BaseTestRunner.java @@ -0,0 +1,326 @@ +package junit.runner; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.PrintWriter; +import java.io.StringReader; +import java.io.StringWriter; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.text.NumberFormat; +import java.util.Properties; + +import junit.framework.AssertionFailedError; +import junit.framework.Test; +import junit.framework.TestListener; +import junit.framework.TestSuite; + +import org.junit.internal.Throwables; + +/** + * Base class for all test runners. + * This class was born live on stage in Sardinia during XP2000. + */ +public abstract class BaseTestRunner implements TestListener { + public static final String SUITE_METHODNAME = "suite"; + + private static Properties fPreferences; + static int fgMaxMessageLength = 500; + static boolean fgFilterStack = true; + boolean fLoading = true; + + /* + * Implementation of TestListener + */ + public synchronized void startTest(Test test) { + testStarted(test.toString()); + } + + protected static void setPreferences(Properties preferences) { + fPreferences = preferences; + } + + protected static Properties getPreferences() { + if (fPreferences == null) { + fPreferences = new Properties(); + fPreferences.put("loading", "true"); + fPreferences.put("filterstack", "true"); + readPreferences(); + } + return fPreferences; + } + + public static void savePreferences() throws IOException { + FileOutputStream fos = new FileOutputStream(getPreferencesFile()); + try { + getPreferences().store(fos, ""); + } finally { + fos.close(); + } + } + + public static void setPreference(String key, String value) { + getPreferences().put(key, value); + } + + public synchronized void endTest(Test test) { + testEnded(test.toString()); + } + + public synchronized void addError(final Test test, final Throwable e) { + testFailed(TestRunListener.STATUS_ERROR, test, e); + } + + public synchronized void addFailure(final Test test, final AssertionFailedError e) { + testFailed(TestRunListener.STATUS_FAILURE, test, e); + } + + // TestRunListener implementation + + public abstract void testStarted(String testName); + + public abstract void testEnded(String testName); + + public abstract void testFailed(int status, Test test, Throwable e); + + /** + * Returns the Test corresponding to the given suite. This is + * a template method, subclasses override runFailed(), clearStatus(). + */ + public Test getTest(String suiteClassName) { + if (suiteClassName.length() <= 0) { + clearStatus(); + return null; + } + Class testClass = null; + try { + testClass = loadSuiteClass(suiteClassName); + } catch (ClassNotFoundException e) { + String clazz = e.getMessage(); + if (clazz == null) { + clazz = suiteClassName; + } + runFailed("Class not found \"" + clazz + "\""); + return null; + } catch (Exception e) { + runFailed("Error: " + e.toString()); + return null; + } + Method suiteMethod = null; + try { + suiteMethod = testClass.getMethod(SUITE_METHODNAME); + } catch (Exception e) { + // try to extract a test suite automatically + clearStatus(); + return new TestSuite(testClass); + } + if (!Modifier.isStatic(suiteMethod.getModifiers())) { + runFailed("Suite() method must be static"); + return null; + } + Test test = null; + try { + test = (Test) suiteMethod.invoke(null); // static method + if (test == null) { + return test; + } + } catch (InvocationTargetException e) { + runFailed("Failed to invoke suite():" + e.getTargetException().toString()); + return null; + } catch (IllegalAccessException e) { + runFailed("Failed to invoke suite():" + e.toString()); + return null; + } + + clearStatus(); + return test; + } + + /** + * Returns the formatted string of the elapsed time. + */ + public String elapsedTimeAsString(long runTime) { + return NumberFormat.getInstance().format((double) runTime / 1000); + } + + /** + * Processes the command line arguments and + * returns the name of the suite class to run or null + */ + protected String processArguments(String[] args) { + String suiteName = null; + for (int i = 0; i < args.length; i++) { + if (args[i].equals("-noloading")) { + setLoading(false); + } else if (args[i].equals("-nofilterstack")) { + fgFilterStack = false; + } else if (args[i].equals("-c")) { + if (args.length > i + 1) { + suiteName = extractClassName(args[i + 1]); + } else { + System.out.println("Missing Test class name"); + } + i++; + } else { + suiteName = args[i]; + } + } + return suiteName; + } + + /** + * Sets the loading behaviour of the test runner + */ + public void setLoading(boolean enable) { + fLoading = enable; + } + + /** + * Extract the class name from a String in VA/Java style + */ + public String extractClassName(String className) { + if (className.startsWith("Default package for")) { + return className.substring(className.lastIndexOf(".") + 1); + } + return className; + } + + /** + * Truncates a String to the maximum length. + */ + public static String truncate(String s) { + if (fgMaxMessageLength != -1 && s.length() > fgMaxMessageLength) { + s = s.substring(0, fgMaxMessageLength) + "..."; + } + return s; + } + + /** + * Override to define how to handle a failed loading of + * a test suite. + */ + protected abstract void runFailed(String message); + + /** + * Returns the loaded Class for a suite name. + */ + protected Class loadSuiteClass(String suiteClassName) throws ClassNotFoundException { + return Class.forName(suiteClassName); + } + + /** + * Clears the status message. + */ + protected void clearStatus() { // Belongs in the GUI TestRunner class + } + + protected boolean useReloadingTestSuiteLoader() { + return getPreference("loading").equals("true") && fLoading; + } + + private static File getPreferencesFile() { + String home = System.getProperty("user.home"); + return new File(home, "junit.properties"); + } + + private static void readPreferences() { + InputStream is = null; + try { + is = new FileInputStream(getPreferencesFile()); + setPreferences(new Properties(getPreferences())); + getPreferences().load(is); + } catch (IOException ignored) { + } catch (SecurityException ignored) { + } finally { + try { + if (is != null) { + is.close(); + } + } catch (IOException e1) { + } + } + } + + public static String getPreference(String key) { + return getPreferences().getProperty(key); + } + + public static int getPreference(String key, int dflt) { + String value = getPreference(key); + int intValue = dflt; + if (value == null) { + return intValue; + } + try { + intValue = Integer.parseInt(value); + } catch (NumberFormatException ne) { + } + return intValue; + } + + /** + * Returns a filtered stack trace + */ + public static String getFilteredTrace(Throwable e) { + return BaseTestRunner.getFilteredTrace(Throwables.getStacktrace(e)); + } + + /** + * Filters stack frames from internal JUnit classes + */ + public static String getFilteredTrace(String stack) { + if (showStackRaw()) { + return stack; + } + + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + StringReader sr = new StringReader(stack); + BufferedReader br = new BufferedReader(sr); + + String line; + try { + while ((line = br.readLine()) != null) { + if (!filterLine(line)) { + pw.println(line); + } + } + } catch (Exception IOException) { + return stack; // return the stack unfiltered + } + return sw.toString(); + } + + protected static boolean showStackRaw() { + return !getPreference("filterstack").equals("true") || fgFilterStack == false; + } + + static boolean filterLine(String line) { + String[] patterns = new String[]{ + "junit.framework.TestCase", + "junit.framework.TestResult", + "junit.framework.TestSuite", + "junit.framework.Assert.", // don't filter AssertionFailure + "junit.swingui.TestRunner", + "junit.awtui.TestRunner", + "junit.textui.TestRunner", + "java.lang.reflect.Method.invoke(" + }; + for (int i = 0; i < patterns.length; i++) { + if (line.indexOf(patterns[i]) > 0) { + return true; + } + } + return false; + } + + static { + fgMaxMessageLength = getPreference("maxmessage", fgMaxMessageLength); + } + +} diff --git a/src/main/java/junit/runner/TestRunListener.java b/src/main/java/junit/runner/TestRunListener.java new file mode 100644 index 000000000000..ce5b3d5920a2 --- /dev/null +++ b/src/main/java/junit/runner/TestRunListener.java @@ -0,0 +1,25 @@ +package junit.runner; + +/** + * A listener interface for observing the + * execution of a test run. Unlike TestListener, + * this interface using only primitive objects, + * making it suitable for remote test execution. + */ +public interface TestRunListener { + /* test status constants*/ + int STATUS_ERROR = 1; + int STATUS_FAILURE = 2; + + void testRunStarted(String testSuiteName, int testCount); + + void testRunEnded(long elapsedTime); + + void testRunStopped(long elapsedTime); + + void testStarted(String testName); + + void testEnded(String testName); + + void testFailed(int status, String testName, String trace); +} diff --git a/src/main/java/junit/runner/Version.java b/src/main/java/junit/runner/Version.java new file mode 100644 index 000000000000..9f263840e40f --- /dev/null +++ b/src/main/java/junit/runner/Version.java @@ -0,0 +1,18 @@ +package junit.runner; + +/** + * This class defines the current version of JUnit + */ +public class Version { + private Version() { + // don't instantiate + } + + public static String id() { + return "4.13.1-SNAPSHOT"; + } + + public static void main(String[] args) { + System.out.println(id()); + } +} diff --git a/junit/runner/Version.java b/src/main/java/junit/runner/Version.java.template similarity index 100% rename from junit/runner/Version.java rename to src/main/java/junit/runner/Version.java.template diff --git a/src/main/java/junit/runner/package-info.java b/src/main/java/junit/runner/package-info.java new file mode 100644 index 000000000000..b746185f333e --- /dev/null +++ b/src/main/java/junit/runner/package-info.java @@ -0,0 +1,4 @@ +/** + * Provides JUnit v3.x test runners. + */ +package junit.runner; \ No newline at end of file diff --git a/src/main/java/junit/textui/ResultPrinter.java b/src/main/java/junit/textui/ResultPrinter.java new file mode 100644 index 000000000000..95f10f447950 --- /dev/null +++ b/src/main/java/junit/textui/ResultPrinter.java @@ -0,0 +1,137 @@ +package junit.textui; + +import java.io.PrintStream; +import java.text.NumberFormat; +import java.util.Enumeration; + +import junit.framework.AssertionFailedError; +import junit.framework.Test; +import junit.framework.TestFailure; +import junit.framework.TestListener; +import junit.framework.TestResult; +import junit.runner.BaseTestRunner; + +public class ResultPrinter implements TestListener { + PrintStream fWriter; + int fColumn = 0; + + public ResultPrinter(PrintStream writer) { + fWriter = writer; + } + + /* API for use by textui.TestRunner */ + + synchronized void print(TestResult result, long runTime) { + printHeader(runTime); + printErrors(result); + printFailures(result); + printFooter(result); + } + + void printWaitPrompt() { + getWriter().println(); + getWriter().println(" to continue"); + } + + /* Internal methods */ + + protected void printHeader(long runTime) { + getWriter().println(); + getWriter().println("Time: " + elapsedTimeAsString(runTime)); + } + + protected void printErrors(TestResult result) { + printDefects(result.errors(), result.errorCount(), "error"); + } + + protected void printFailures(TestResult result) { + printDefects(result.failures(), result.failureCount(), "failure"); + } + + protected void printDefects(Enumeration booBoos, int count, String type) { + if (count == 0) return; + if (count == 1) { + getWriter().println("There was " + count + " " + type + ":"); + } else { + getWriter().println("There were " + count + " " + type + "s:"); + } + for (int i = 1; booBoos.hasMoreElements(); i++) { + printDefect(booBoos.nextElement(), i); + } + } + + public void printDefect(TestFailure booBoo, int count) { // only public for testing purposes + printDefectHeader(booBoo, count); + printDefectTrace(booBoo); + } + + protected void printDefectHeader(TestFailure booBoo, int count) { + // I feel like making this a println, then adding a line giving the throwable a chance to print something + // before we get to the stack trace. + getWriter().print(count + ") " + booBoo.failedTest()); + } + + protected void printDefectTrace(TestFailure booBoo) { + getWriter().print(BaseTestRunner.getFilteredTrace(booBoo.trace())); + } + + protected void printFooter(TestResult result) { + if (result.wasSuccessful()) { + getWriter().println(); + getWriter().print("OK"); + getWriter().println(" (" + result.runCount() + " test" + (result.runCount() == 1 ? "" : "s") + ")"); + + } else { + getWriter().println(); + getWriter().println("FAILURES!!!"); + getWriter().println("Tests run: " + result.runCount() + + ", Failures: " + result.failureCount() + + ", Errors: " + result.errorCount()); + } + getWriter().println(); + } + + /** + * Returns the formatted string of the elapsed time. + * Duplicated from BaseTestRunner. Fix it. + */ + protected String elapsedTimeAsString(long runTime) { + return NumberFormat.getInstance().format((double) runTime / 1000); + } + + public PrintStream getWriter() { + return fWriter; + } + + /** + * @see junit.framework.TestListener#addError(Test, Throwable) + */ + public void addError(Test test, Throwable e) { + getWriter().print("E"); + } + + /** + * @see junit.framework.TestListener#addFailure(Test, AssertionFailedError) + */ + public void addFailure(Test test, AssertionFailedError t) { + getWriter().print("F"); + } + + /** + * @see junit.framework.TestListener#endTest(Test) + */ + public void endTest(Test test) { + } + + /** + * @see junit.framework.TestListener#startTest(Test) + */ + public void startTest(Test test) { + getWriter().print("."); + if (fColumn++ >= 40) { + getWriter().println(); + fColumn = 0; + } + } + +} diff --git a/src/main/java/junit/textui/TestRunner.java b/src/main/java/junit/textui/TestRunner.java new file mode 100644 index 000000000000..913020af6b77 --- /dev/null +++ b/src/main/java/junit/textui/TestRunner.java @@ -0,0 +1,206 @@ +package junit.textui; + + +import java.io.PrintStream; + +import junit.framework.Test; +import junit.framework.TestCase; +import junit.framework.TestResult; +import junit.framework.TestSuite; +import junit.runner.BaseTestRunner; +import junit.runner.Version; + +/** + * A command line based tool to run tests. + *
    + * java junit.textui.TestRunner [-wait] TestCaseClass
    + * 
    + *

    + * TestRunner expects the name of a TestCase class as argument. + * If this class defines a static suite method it + * will be invoked and the returned test is run. Otherwise all + * the methods starting with "test" having no arguments are run. + *

    + * When the wait command line argument is given TestRunner + * waits until the users types RETURN. + *

    + * TestRunner prints a trace as the tests are executed followed by a + * summary at the end. + */ +public class TestRunner extends BaseTestRunner { + private ResultPrinter fPrinter; + + public static final int SUCCESS_EXIT = 0; + public static final int FAILURE_EXIT = 1; + public static final int EXCEPTION_EXIT = 2; + + /** + * Constructs a TestRunner. + */ + public TestRunner() { + this(System.out); + } + + /** + * Constructs a TestRunner using the given stream for all the output + */ + public TestRunner(PrintStream writer) { + this(new ResultPrinter(writer)); + } + + /** + * Constructs a TestRunner using the given ResultPrinter all the output + */ + public TestRunner(ResultPrinter printer) { + fPrinter = printer; + } + + /** + * Runs a suite extracted from a TestCase subclass. + */ + static public void run(Class testClass) { + run(new TestSuite(testClass)); + } + + /** + * Runs a single test and collects its results. + * This method can be used to start a test run + * from your program. + *

    +     * public static void main (String[] args) {
    +     *    test.textui.TestRunner.run(suite());
    +     * }
    +     * 
    + */ + static public TestResult run(Test test) { + TestRunner runner = new TestRunner(); + return runner.doRun(test); + } + + /** + * Runs a single test and waits until the user + * types RETURN. + */ + static public void runAndWait(Test suite) { + TestRunner aTestRunner = new TestRunner(); + aTestRunner.doRun(suite, true); + } + + @Override + public void testFailed(int status, Test test, Throwable e) { + } + + @Override + public void testStarted(String testName) { + } + + @Override + public void testEnded(String testName) { + } + + /** + * Creates the TestResult to be used for the test run. + */ + protected TestResult createTestResult() { + return new TestResult(); + } + + public TestResult doRun(Test test) { + return doRun(test, false); + } + + public TestResult doRun(Test suite, boolean wait) { + TestResult result = createTestResult(); + result.addListener(fPrinter); + long startTime = System.currentTimeMillis(); + suite.run(result); + long endTime = System.currentTimeMillis(); + long runTime = endTime - startTime; + fPrinter.print(result, runTime); + + pause(wait); + return result; + } + + protected void pause(boolean wait) { + if (!wait) return; + fPrinter.printWaitPrompt(); + try { + System.in.read(); + } catch (Exception e) { + } + } + + public static void main(String[] args) { + TestRunner aTestRunner = new TestRunner(); + try { + TestResult r = aTestRunner.start(args); + if (!r.wasSuccessful()) { + System.exit(FAILURE_EXIT); + } + System.exit(SUCCESS_EXIT); + } catch (Exception e) { + System.err.println(e.getMessage()); + System.exit(EXCEPTION_EXIT); + } + } + + /** + * Starts a test run. Analyzes the command line arguments and runs the given + * test suite. + */ + public TestResult start(String[] args) throws Exception { + String testCase = ""; + String method = ""; + boolean wait = false; + + for (int i = 0; i < args.length; i++) { + if (args[i].equals("-wait")) { + wait = true; + } else if (args[i].equals("-c")) { + testCase = extractClassName(args[++i]); + } else if (args[i].equals("-m")) { + String arg = args[++i]; + int lastIndex = arg.lastIndexOf('.'); + testCase = arg.substring(0, lastIndex); + method = arg.substring(lastIndex + 1); + } else if (args[i].equals("-v")) { + System.err.println("JUnit " + Version.id() + " by Kent Beck and Erich Gamma"); + } else { + testCase = args[i]; + } + } + + if (testCase.equals("")) { + throw new Exception("Usage: TestRunner [-wait] testCaseName, where name is the name of the TestCase class"); + } + + try { + if (!method.equals("")) { + return runSingleMethod(testCase, method, wait); + } + Test suite = getTest(testCase); + return doRun(suite, wait); + } catch (Exception e) { + throw new Exception("Could not create and run test suite: " + e); + } + } + + protected TestResult runSingleMethod(String testCase, String method, boolean wait) throws Exception { + Class testClass = loadSuiteClass(testCase).asSubclass(TestCase.class); + Test test = TestSuite.createTest(testClass, method); + return doRun(test, wait); + } + + @Override + protected void runFailed(String message) { + System.err.println(message); + System.exit(FAILURE_EXIT); + } + + public void setPrinter(ResultPrinter printer) { + fPrinter = printer; + } + + +} \ No newline at end of file diff --git a/src/main/java/junit/textui/package-info.java b/src/main/java/junit/textui/package-info.java new file mode 100644 index 000000000000..2aa5176db775 --- /dev/null +++ b/src/main/java/junit/textui/package-info.java @@ -0,0 +1,4 @@ +/** + * Provides JUnit v3.x command line based tool to run tests. + */ +package junit.textui; \ No newline at end of file diff --git a/src/main/java/org/junit/After.java b/src/main/java/org/junit/After.java new file mode 100644 index 000000000000..eae7e3abf4c6 --- /dev/null +++ b/src/main/java/org/junit/After.java @@ -0,0 +1,41 @@ +package org.junit; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * If you allocate external resources in a {@link org.junit.Before} method you need to release them + * after the test runs. Annotating a public void method + * with @After causes that method to be run after the {@link org.junit.Test} method. All @After + * methods are guaranteed to run even if a {@link org.junit.Before} or {@link org.junit.Test} method throws an + * exception. The @After methods declared in superclasses will be run after those of the current + * class, unless they are overridden in the current class. + *

    + * Here is a simple example: + *

    + * public class Example {
    + *    File output;
    + *    @Before public void createOutputFile() {
    + *          output= new File(...);
    + *    }
    + *    @Test public void something() {
    + *          ...
    + *    }
    + *    @After public void deleteOutputFile() {
    + *          output.delete();
    + *    }
    + * }
    + * 
    + * + * @see org.junit.Before + * @see org.junit.Test + * @since 4.0 + */ + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface After { +} + diff --git a/src/main/java/org/junit/AfterClass.java b/src/main/java/org/junit/AfterClass.java new file mode 100644 index 000000000000..dba4109ba257 --- /dev/null +++ b/src/main/java/org/junit/AfterClass.java @@ -0,0 +1,42 @@ +package org.junit; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * If you allocate expensive external resources in a {@link org.junit.BeforeClass} method you need to release them + * after all the tests in the class have run. Annotating a public static void method + * with @AfterClass causes that method to be run after all the tests in the class have been run. All @AfterClass + * methods are guaranteed to run even if a {@link org.junit.BeforeClass} method throws an + * exception. The @AfterClass methods declared in superclasses will be run after those of the current + * class, unless they are shadowed in the current class. + *

    + * Here is a simple example: + *

    + * public class Example {
    + *    private static DatabaseConnection database;
    + *    @BeforeClass public static void login() {
    + *          database= ...;
    + *    }
    + *    @Test public void something() {
    + *          ...
    + *    }
    + *    @Test public void somethingElse() {
    + *          ...
    + *    }
    + *    @AfterClass public static void logout() {
    + *          database.logout();
    + *    }
    + * }
    + * 
    + * + * @see org.junit.BeforeClass + * @see org.junit.Test + * @since 4.0 + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface AfterClass { +} diff --git a/src/main/java/org/junit/Assert.java b/src/main/java/org/junit/Assert.java new file mode 100644 index 000000000000..65bbc9d3f7ff --- /dev/null +++ b/src/main/java/org/junit/Assert.java @@ -0,0 +1,1034 @@ +package org.junit; + +import org.hamcrest.Matcher; +import org.hamcrest.MatcherAssert; +import org.junit.function.ThrowingRunnable; +import org.junit.internal.ArrayComparisonFailure; +import org.junit.internal.ExactComparisonCriteria; +import org.junit.internal.InexactComparisonCriteria; + +/** + * A set of assertion methods useful for writing tests. Only failed assertions + * are recorded. These methods can be used directly: + * Assert.assertEquals(...), however, they read better if they + * are referenced through static import: + * + *
    + * import static org.junit.Assert.*;
    + *    ...
    + *    assertEquals(...);
    + * 
    + * + * @see AssertionError + * @since 4.0 + */ +public class Assert { + /** + * Protect constructor since it is a static only class + */ + protected Assert() { + } + + /** + * Asserts that a condition is true. If it isn't it throws an + * {@link AssertionError} with the given message. + * + * @param message the identifying message for the {@link AssertionError} (null + * okay) + * @param condition condition to be checked + */ + public static void assertTrue(String message, boolean condition) { + if (!condition) { + fail(message); + } + } + + /** + * Asserts that a condition is true. If it isn't it throws an + * {@link AssertionError} without a message. + * + * @param condition condition to be checked + */ + public static void assertTrue(boolean condition) { + assertTrue(null, condition); + } + + /** + * Asserts that a condition is false. If it isn't it throws an + * {@link AssertionError} with the given message. + * + * @param message the identifying message for the {@link AssertionError} (null + * okay) + * @param condition condition to be checked + */ + public static void assertFalse(String message, boolean condition) { + assertTrue(message, !condition); + } + + /** + * Asserts that a condition is false. If it isn't it throws an + * {@link AssertionError} without a message. + * + * @param condition condition to be checked + */ + public static void assertFalse(boolean condition) { + assertFalse(null, condition); + } + + /** + * Fails a test with the given message. + * + * @param message the identifying message for the {@link AssertionError} (null + * okay) + * @see AssertionError + */ + public static void fail(String message) { + if (message == null) { + throw new AssertionError(); + } + throw new AssertionError(message); + } + + /** + * Fails a test with no message. + */ + public static void fail() { + fail(null); + } + + /** + * Asserts that two objects are equal. If they are not, an + * {@link AssertionError} is thrown with the given message. If + * expected and actual are null, + * they are considered equal. + * + * @param message the identifying message for the {@link AssertionError} (null + * okay) + * @param expected expected value + * @param actual actual value + */ + public static void assertEquals(String message, Object expected, + Object actual) { + if (equalsRegardingNull(expected, actual)) { + return; + } + if (expected instanceof String && actual instanceof String) { + String cleanMessage = message == null ? "" : message; + throw new ComparisonFailure(cleanMessage, (String) expected, + (String) actual); + } else { + failNotEquals(message, expected, actual); + } + } + + private static boolean equalsRegardingNull(Object expected, Object actual) { + if (expected == null) { + return actual == null; + } + + return isEquals(expected, actual); + } + + private static boolean isEquals(Object expected, Object actual) { + return expected.equals(actual); + } + + /** + * Asserts that two objects are equal. If they are not, an + * {@link AssertionError} without a message is thrown. If + * expected and actual are null, + * they are considered equal. + * + * @param expected expected value + * @param actual the value to check against expected + */ + public static void assertEquals(Object expected, Object actual) { + assertEquals(null, expected, actual); + } + + /** + * Asserts that two objects are not equals. If they are, an + * {@link AssertionError} is thrown with the given message. If + * unexpected and actual are null, + * they are considered equal. + * + * @param message the identifying message for the {@link AssertionError} (null + * okay) + * @param unexpected unexpected value to check + * @param actual the value to check against unexpected + */ + public static void assertNotEquals(String message, Object unexpected, + Object actual) { + if (equalsRegardingNull(unexpected, actual)) { + failEquals(message, actual); + } + } + + /** + * Asserts that two objects are not equals. If they are, an + * {@link AssertionError} without a message is thrown. If + * unexpected and actual are null, + * they are considered equal. + * + * @param unexpected unexpected value to check + * @param actual the value to check against unexpected + */ + public static void assertNotEquals(Object unexpected, Object actual) { + assertNotEquals(null, unexpected, actual); + } + + private static void failEquals(String message, Object actual) { + String formatted = "Values should be different. "; + if (message != null) { + formatted = message + ". "; + } + + formatted += "Actual: " + actual; + fail(formatted); + } + + /** + * Asserts that two longs are not equals. If they are, an + * {@link AssertionError} is thrown with the given message. + * + * @param message the identifying message for the {@link AssertionError} (null + * okay) + * @param unexpected unexpected value to check + * @param actual the value to check against unexpected + */ + public static void assertNotEquals(String message, long unexpected, long actual) { + if (unexpected == actual) { + failEquals(message, Long.valueOf(actual)); + } + } + + /** + * Asserts that two longs are not equals. If they are, an + * {@link AssertionError} without a message is thrown. + * + * @param unexpected unexpected value to check + * @param actual the value to check against unexpected + */ + public static void assertNotEquals(long unexpected, long actual) { + assertNotEquals(null, unexpected, actual); + } + + /** + * Asserts that two doubles are not equal to within a positive delta. + * If they are, an {@link AssertionError} is thrown with the given + * message. If the unexpected value is infinity then the delta value is + * ignored. NaNs are considered equal: + * assertNotEquals(Double.NaN, Double.NaN, *) fails + * + * @param message the identifying message for the {@link AssertionError} (null + * okay) + * @param unexpected unexpected value + * @param actual the value to check against unexpected + * @param delta the maximum delta between unexpected and + * actual for which both numbers are still + * considered equal. + */ + public static void assertNotEquals(String message, double unexpected, + double actual, double delta) { + if (!doubleIsDifferent(unexpected, actual, delta)) { + failEquals(message, Double.valueOf(actual)); + } + } + + /** + * Asserts that two doubles are not equal to within a positive delta. + * If they are, an {@link AssertionError} is thrown. If the unexpected + * value is infinity then the delta value is ignored.NaNs are considered + * equal: assertNotEquals(Double.NaN, Double.NaN, *) fails + * + * @param unexpected unexpected value + * @param actual the value to check against unexpected + * @param delta the maximum delta between unexpected and + * actual for which both numbers are still + * considered equal. + */ + public static void assertNotEquals(double unexpected, double actual, double delta) { + assertNotEquals(null, unexpected, actual, delta); + } + + /** + * Asserts that two floats are not equal to within a positive delta. + * If they are, an {@link AssertionError} is thrown. If the unexpected + * value is infinity then the delta value is ignored.NaNs are considered + * equal: assertNotEquals(Float.NaN, Float.NaN, *) fails + * + * @param unexpected unexpected value + * @param actual the value to check against unexpected + * @param delta the maximum delta between unexpected and + * actual for which both numbers are still + * considered equal. + */ + public static void assertNotEquals(float unexpected, float actual, float delta) { + assertNotEquals(null, unexpected, actual, delta); + } + + /** + * Asserts that two object arrays are equal. If they are not, an + * {@link AssertionError} is thrown with the given message. If + * expecteds and actuals are null, + * they are considered equal. + * + * @param message the identifying message for the {@link AssertionError} (null + * okay) + * @param expecteds Object array or array of arrays (multi-dimensional array) with + * expected values. + * @param actuals Object array or array of arrays (multi-dimensional array) with + * actual values + */ + public static void assertArrayEquals(String message, Object[] expecteds, + Object[] actuals) throws ArrayComparisonFailure { + internalArrayEquals(message, expecteds, actuals); + } + + /** + * Asserts that two object arrays are equal. If they are not, an + * {@link AssertionError} is thrown. If expected and + * actual are null, they are considered + * equal. + * + * @param expecteds Object array or array of arrays (multi-dimensional array) with + * expected values + * @param actuals Object array or array of arrays (multi-dimensional array) with + * actual values + */ + public static void assertArrayEquals(Object[] expecteds, Object[] actuals) { + assertArrayEquals(null, expecteds, actuals); + } + + /** + * Asserts that two boolean arrays are equal. If they are not, an + * {@link AssertionError} is thrown with the given message. If + * expecteds and actuals are null, + * they are considered equal. + * + * @param message the identifying message for the {@link AssertionError} (null + * okay) + * @param expecteds boolean array with expected values. + * @param actuals boolean array with expected values. + */ + public static void assertArrayEquals(String message, boolean[] expecteds, + boolean[] actuals) throws ArrayComparisonFailure { + internalArrayEquals(message, expecteds, actuals); + } + + /** + * Asserts that two boolean arrays are equal. If they are not, an + * {@link AssertionError} is thrown. If expected and + * actual are null, they are considered + * equal. + * + * @param expecteds boolean array with expected values. + * @param actuals boolean array with expected values. + */ + public static void assertArrayEquals(boolean[] expecteds, boolean[] actuals) { + assertArrayEquals(null, expecteds, actuals); + } + + /** + * Asserts that two byte arrays are equal. If they are not, an + * {@link AssertionError} is thrown with the given message. + * + * @param message the identifying message for the {@link AssertionError} (null + * okay) + * @param expecteds byte array with expected values. + * @param actuals byte array with actual values + */ + public static void assertArrayEquals(String message, byte[] expecteds, + byte[] actuals) throws ArrayComparisonFailure { + internalArrayEquals(message, expecteds, actuals); + } + + /** + * Asserts that two byte arrays are equal. If they are not, an + * {@link AssertionError} is thrown. + * + * @param expecteds byte array with expected values. + * @param actuals byte array with actual values + */ + public static void assertArrayEquals(byte[] expecteds, byte[] actuals) { + assertArrayEquals(null, expecteds, actuals); + } + + /** + * Asserts that two char arrays are equal. If they are not, an + * {@link AssertionError} is thrown with the given message. + * + * @param message the identifying message for the {@link AssertionError} (null + * okay) + * @param expecteds char array with expected values. + * @param actuals char array with actual values + */ + public static void assertArrayEquals(String message, char[] expecteds, + char[] actuals) throws ArrayComparisonFailure { + internalArrayEquals(message, expecteds, actuals); + } + + /** + * Asserts that two char arrays are equal. If they are not, an + * {@link AssertionError} is thrown. + * + * @param expecteds char array with expected values. + * @param actuals char array with actual values + */ + public static void assertArrayEquals(char[] expecteds, char[] actuals) { + assertArrayEquals(null, expecteds, actuals); + } + + /** + * Asserts that two short arrays are equal. If they are not, an + * {@link AssertionError} is thrown with the given message. + * + * @param message the identifying message for the {@link AssertionError} (null + * okay) + * @param expecteds short array with expected values. + * @param actuals short array with actual values + */ + public static void assertArrayEquals(String message, short[] expecteds, + short[] actuals) throws ArrayComparisonFailure { + internalArrayEquals(message, expecteds, actuals); + } + + /** + * Asserts that two short arrays are equal. If they are not, an + * {@link AssertionError} is thrown. + * + * @param expecteds short array with expected values. + * @param actuals short array with actual values + */ + public static void assertArrayEquals(short[] expecteds, short[] actuals) { + assertArrayEquals(null, expecteds, actuals); + } + + /** + * Asserts that two int arrays are equal. If they are not, an + * {@link AssertionError} is thrown with the given message. + * + * @param message the identifying message for the {@link AssertionError} (null + * okay) + * @param expecteds int array with expected values. + * @param actuals int array with actual values + */ + public static void assertArrayEquals(String message, int[] expecteds, + int[] actuals) throws ArrayComparisonFailure { + internalArrayEquals(message, expecteds, actuals); + } + + /** + * Asserts that two int arrays are equal. If they are not, an + * {@link AssertionError} is thrown. + * + * @param expecteds int array with expected values. + * @param actuals int array with actual values + */ + public static void assertArrayEquals(int[] expecteds, int[] actuals) { + assertArrayEquals(null, expecteds, actuals); + } + + /** + * Asserts that two long arrays are equal. If they are not, an + * {@link AssertionError} is thrown with the given message. + * + * @param message the identifying message for the {@link AssertionError} (null + * okay) + * @param expecteds long array with expected values. + * @param actuals long array with actual values + */ + public static void assertArrayEquals(String message, long[] expecteds, + long[] actuals) throws ArrayComparisonFailure { + internalArrayEquals(message, expecteds, actuals); + } + + /** + * Asserts that two long arrays are equal. If they are not, an + * {@link AssertionError} is thrown. + * + * @param expecteds long array with expected values. + * @param actuals long array with actual values + */ + public static void assertArrayEquals(long[] expecteds, long[] actuals) { + assertArrayEquals(null, expecteds, actuals); + } + + /** + * Asserts that two double arrays are equal. If they are not, an + * {@link AssertionError} is thrown with the given message. + * + * @param message the identifying message for the {@link AssertionError} (null + * okay) + * @param expecteds double array with expected values. + * @param actuals double array with actual values + * @param delta the maximum delta between expecteds[i] and + * actuals[i] for which both numbers are still + * considered equal. + */ + public static void assertArrayEquals(String message, double[] expecteds, + double[] actuals, double delta) throws ArrayComparisonFailure { + new InexactComparisonCriteria(delta).arrayEquals(message, expecteds, actuals); + } + + /** + * Asserts that two double arrays are equal. If they are not, an + * {@link AssertionError} is thrown. + * + * @param expecteds double array with expected values. + * @param actuals double array with actual values + * @param delta the maximum delta between expecteds[i] and + * actuals[i] for which both numbers are still + * considered equal. + */ + public static void assertArrayEquals(double[] expecteds, double[] actuals, double delta) { + assertArrayEquals(null, expecteds, actuals, delta); + } + + /** + * Asserts that two float arrays are equal. If they are not, an + * {@link AssertionError} is thrown with the given message. + * + * @param message the identifying message for the {@link AssertionError} (null + * okay) + * @param expecteds float array with expected values. + * @param actuals float array with actual values + * @param delta the maximum delta between expecteds[i] and + * actuals[i] for which both numbers are still + * considered equal. + */ + public static void assertArrayEquals(String message, float[] expecteds, + float[] actuals, float delta) throws ArrayComparisonFailure { + new InexactComparisonCriteria(delta).arrayEquals(message, expecteds, actuals); + } + + /** + * Asserts that two float arrays are equal. If they are not, an + * {@link AssertionError} is thrown. + * + * @param expecteds float array with expected values. + * @param actuals float array with actual values + * @param delta the maximum delta between expecteds[i] and + * actuals[i] for which both numbers are still + * considered equal. + */ + public static void assertArrayEquals(float[] expecteds, float[] actuals, float delta) { + assertArrayEquals(null, expecteds, actuals, delta); + } + + /** + * Asserts that two object arrays are equal. If they are not, an + * {@link AssertionError} is thrown with the given message. If + * expecteds and actuals are null, + * they are considered equal. + * + * @param message the identifying message for the {@link AssertionError} (null + * okay) + * @param expecteds Object array or array of arrays (multi-dimensional array) with + * expected values. + * @param actuals Object array or array of arrays (multi-dimensional array) with + * actual values + */ + private static void internalArrayEquals(String message, Object expecteds, + Object actuals) throws ArrayComparisonFailure { + new ExactComparisonCriteria().arrayEquals(message, expecteds, actuals); + } + + /** + * Asserts that two doubles are equal to within a positive delta. + * If they are not, an {@link AssertionError} is thrown with the given + * message. If the expected value is infinity then the delta value is + * ignored. NaNs are considered equal: + * assertEquals(Double.NaN, Double.NaN, *) passes + * + * @param message the identifying message for the {@link AssertionError} (null + * okay) + * @param expected expected value + * @param actual the value to check against expected + * @param delta the maximum delta between expected and + * actual for which both numbers are still + * considered equal. + */ + public static void assertEquals(String message, double expected, + double actual, double delta) { + if (doubleIsDifferent(expected, actual, delta)) { + failNotEquals(message, Double.valueOf(expected), Double.valueOf(actual)); + } + } + + /** + * Asserts that two floats are equal to within a positive delta. + * If they are not, an {@link AssertionError} is thrown with the given + * message. If the expected value is infinity then the delta value is + * ignored. NaNs are considered equal: + * assertEquals(Float.NaN, Float.NaN, *) passes + * + * @param message the identifying message for the {@link AssertionError} (null + * okay) + * @param expected expected value + * @param actual the value to check against expected + * @param delta the maximum delta between expected and + * actual for which both numbers are still + * considered equal. + */ + public static void assertEquals(String message, float expected, + float actual, float delta) { + if (floatIsDifferent(expected, actual, delta)) { + failNotEquals(message, Float.valueOf(expected), Float.valueOf(actual)); + } + } + + /** + * Asserts that two floats are not equal to within a positive delta. + * If they are, an {@link AssertionError} is thrown with the given + * message. If the unexpected value is infinity then the delta value is + * ignored. NaNs are considered equal: + * assertNotEquals(Float.NaN, Float.NaN, *) fails + * + * @param message the identifying message for the {@link AssertionError} (null + * okay) + * @param unexpected unexpected value + * @param actual the value to check against unexpected + * @param delta the maximum delta between unexpected and + * actual for which both numbers are still + * considered equal. + */ + public static void assertNotEquals(String message, float unexpected, + float actual, float delta) { + if (!floatIsDifferent(unexpected, actual, delta)) { + failEquals(message, Float.valueOf(actual)); + } + } + + private static boolean doubleIsDifferent(double d1, double d2, double delta) { + if (Double.compare(d1, d2) == 0) { + return false; + } + if ((Math.abs(d1 - d2) <= delta)) { + return false; + } + + return true; + } + + private static boolean floatIsDifferent(float f1, float f2, float delta) { + if (Float.compare(f1, f2) == 0) { + return false; + } + if ((Math.abs(f1 - f2) <= delta)) { + return false; + } + + return true; + } + + /** + * Asserts that two longs are equal. If they are not, an + * {@link AssertionError} is thrown. + * + * @param expected expected long value. + * @param actual actual long value + */ + public static void assertEquals(long expected, long actual) { + assertEquals(null, expected, actual); + } + + /** + * Asserts that two longs are equal. If they are not, an + * {@link AssertionError} is thrown with the given message. + * + * @param message the identifying message for the {@link AssertionError} (null + * okay) + * @param expected long expected value. + * @param actual long actual value + */ + public static void assertEquals(String message, long expected, long actual) { + if (expected != actual) { + failNotEquals(message, Long.valueOf(expected), Long.valueOf(actual)); + } + } + + /** + * @deprecated Use + * assertEquals(double expected, double actual, double delta) + * instead + */ + @Deprecated + public static void assertEquals(double expected, double actual) { + assertEquals(null, expected, actual); + } + + /** + * @deprecated Use + * assertEquals(String message, double expected, double actual, double delta) + * instead + */ + @Deprecated + public static void assertEquals(String message, double expected, + double actual) { + fail("Use assertEquals(expected, actual, delta) to compare floating-point numbers"); + } + + /** + * Asserts that two doubles are equal to within a positive delta. + * If they are not, an {@link AssertionError} is thrown. If the expected + * value is infinity then the delta value is ignored.NaNs are considered + * equal: assertEquals(Double.NaN, Double.NaN, *) passes + * + * @param expected expected value + * @param actual the value to check against expected + * @param delta the maximum delta between expected and + * actual for which both numbers are still + * considered equal. + */ + public static void assertEquals(double expected, double actual, double delta) { + assertEquals(null, expected, actual, delta); + } + + /** + * Asserts that two floats are equal to within a positive delta. + * If they are not, an {@link AssertionError} is thrown. If the expected + * value is infinity then the delta value is ignored. NaNs are considered + * equal: assertEquals(Float.NaN, Float.NaN, *) passes + * + * @param expected expected value + * @param actual the value to check against expected + * @param delta the maximum delta between expected and + * actual for which both numbers are still + * considered equal. + */ + public static void assertEquals(float expected, float actual, float delta) { + assertEquals(null, expected, actual, delta); + } + + /** + * Asserts that an object isn't null. If it is an {@link AssertionError} is + * thrown with the given message. + * + * @param message the identifying message for the {@link AssertionError} (null + * okay) + * @param object Object to check or null + */ + public static void assertNotNull(String message, Object object) { + assertTrue(message, object != null); + } + + /** + * Asserts that an object isn't null. If it is an {@link AssertionError} is + * thrown. + * + * @param object Object to check or null + */ + public static void assertNotNull(Object object) { + assertNotNull(null, object); + } + + /** + * Asserts that an object is null. If it is not, an {@link AssertionError} + * is thrown with the given message. + * + * @param message the identifying message for the {@link AssertionError} (null + * okay) + * @param object Object to check or null + */ + public static void assertNull(String message, Object object) { + if (object == null) { + return; + } + failNotNull(message, object); + } + + /** + * Asserts that an object is null. If it isn't an {@link AssertionError} is + * thrown. + * + * @param object Object to check or null + */ + public static void assertNull(Object object) { + assertNull(null, object); + } + + private static void failNotNull(String message, Object actual) { + String formatted = ""; + if (message != null) { + formatted = message + " "; + } + fail(formatted + "expected null, but was:<" + actual + ">"); + } + + /** + * Asserts that two objects refer to the same object. If they are not, an + * {@link AssertionError} is thrown with the given message. + * + * @param message the identifying message for the {@link AssertionError} (null + * okay) + * @param expected the expected object + * @param actual the object to compare to expected + */ + public static void assertSame(String message, Object expected, Object actual) { + if (expected == actual) { + return; + } + failNotSame(message, expected, actual); + } + + /** + * Asserts that two objects refer to the same object. If they are not the + * same, an {@link AssertionError} without a message is thrown. + * + * @param expected the expected object + * @param actual the object to compare to expected + */ + public static void assertSame(Object expected, Object actual) { + assertSame(null, expected, actual); + } + + /** + * Asserts that two objects do not refer to the same object. If they do + * refer to the same object, an {@link AssertionError} is thrown with the + * given message. + * + * @param message the identifying message for the {@link AssertionError} (null + * okay) + * @param unexpected the object you don't expect + * @param actual the object to compare to unexpected + */ + public static void assertNotSame(String message, Object unexpected, + Object actual) { + if (unexpected == actual) { + failSame(message); + } + } + + /** + * Asserts that two objects do not refer to the same object. If they do + * refer to the same object, an {@link AssertionError} without a message is + * thrown. + * + * @param unexpected the object you don't expect + * @param actual the object to compare to unexpected + */ + public static void assertNotSame(Object unexpected, Object actual) { + assertNotSame(null, unexpected, actual); + } + + private static void failSame(String message) { + String formatted = ""; + if (message != null) { + formatted = message + " "; + } + fail(formatted + "expected not same"); + } + + private static void failNotSame(String message, Object expected, + Object actual) { + String formatted = ""; + if (message != null) { + formatted = message + " "; + } + fail(formatted + "expected same:<" + expected + "> was not:<" + actual + + ">"); + } + + private static void failNotEquals(String message, Object expected, + Object actual) { + fail(format(message, expected, actual)); + } + + static String format(String message, Object expected, Object actual) { + String formatted = ""; + if (message != null && !"".equals(message)) { + formatted = message + " "; + } + String expectedString = String.valueOf(expected); + String actualString = String.valueOf(actual); + if (equalsRegardingNull(expectedString, actualString)) { + return formatted + "expected: " + + formatClassAndValue(expected, expectedString) + + " but was: " + formatClassAndValue(actual, actualString); + } else { + return formatted + "expected:<" + expectedString + "> but was:<" + + actualString + ">"; + } + } + + private static String formatClass(Class value) { + String className = value.getCanonicalName(); + return className == null ? value.getName() : className; + } + + private static String formatClassAndValue(Object value, String valueString) { + String className = value == null ? "null" : value.getClass().getName(); + return className + "<" + valueString + ">"; + } + + /** + * Asserts that two object arrays are equal. If they are not, an + * {@link AssertionError} is thrown with the given message. If + * expecteds and actuals are null, + * they are considered equal. + * + * @param message the identifying message for the {@link AssertionError} (null + * okay) + * @param expecteds Object array or array of arrays (multi-dimensional array) with + * expected values. + * @param actuals Object array or array of arrays (multi-dimensional array) with + * actual values + * @deprecated use assertArrayEquals + */ + @Deprecated + public static void assertEquals(String message, Object[] expecteds, + Object[] actuals) { + assertArrayEquals(message, expecteds, actuals); + } + + /** + * Asserts that two object arrays are equal. If they are not, an + * {@link AssertionError} is thrown. If expected and + * actual are null, they are considered + * equal. + * + * @param expecteds Object array or array of arrays (multi-dimensional array) with + * expected values + * @param actuals Object array or array of arrays (multi-dimensional array) with + * actual values + * @deprecated use assertArrayEquals + */ + @Deprecated + public static void assertEquals(Object[] expecteds, Object[] actuals) { + assertArrayEquals(expecteds, actuals); + } + + /** + * Asserts that actual satisfies the condition specified by + * matcher. If not, an {@link AssertionError} is thrown with + * information about the matcher and failing value. Example: + * + *
    +     *   assertThat(0, is(1)); // fails:
    +     *     // failure message:
    +     *     // expected: is <1>
    +     *     // got value: <0>
    +     *   assertThat(0, is(not(1))) // passes
    +     * 
    + * + * org.hamcrest.Matcher does not currently document the meaning + * of its type parameter T. This method assumes that a matcher + * typed as Matcher<T> can be meaningfully applied only + * to values that could be assigned to a variable of type T. + * + * @param the static type accepted by the matcher (this can flag obvious + * compile-time problems such as {@code assertThat(1, is("a"))} + * @param actual the computed value being compared + * @param matcher an expression, built of {@link Matcher}s, specifying allowed + * values + * @see org.hamcrest.CoreMatchers + * @deprecated use {@code org.hamcrest.MatcherAssert.assertThat()} + */ + @Deprecated + public static void assertThat(T actual, Matcher matcher) { + assertThat("", actual, matcher); + } + + /** + * Asserts that actual satisfies the condition specified by + * matcher. If not, an {@link AssertionError} is thrown with + * the reason and information about the matcher and failing value. Example: + * + *
    +     *   assertThat("Help! Integers don't work", 0, is(1)); // fails:
    +     *     // failure message:
    +     *     // Help! Integers don't work
    +     *     // expected: is <1>
    +     *     // got value: <0>
    +     *   assertThat("Zero is one", 0, is(not(1))) // passes
    +     * 
    + * + * org.hamcrest.Matcher does not currently document the meaning + * of its type parameter T. This method assumes that a matcher + * typed as Matcher<T> can be meaningfully applied only + * to values that could be assigned to a variable of type T. + * + * @param reason additional information about the error + * @param the static type accepted by the matcher (this can flag obvious + * compile-time problems such as {@code assertThat(1, is("a"))} + * @param actual the computed value being compared + * @param matcher an expression, built of {@link Matcher}s, specifying allowed + * values + * @see org.hamcrest.CoreMatchers + * @deprecated use {@code org.hamcrest.MatcherAssert.assertThat()} + */ + @Deprecated + public static void assertThat(String reason, T actual, + Matcher matcher) { + MatcherAssert.assertThat(reason, actual, matcher); + } + + /** + * Asserts that {@code runnable} throws an exception of type {@code expectedThrowable} when + * executed. If it does, the exception object is returned. If it does not throw an exception, an + * {@link AssertionError} is thrown. If it throws the wrong type of exception, an {@code + * AssertionError} is thrown describing the mismatch; the exception that was actually thrown can + * be obtained by calling {@link AssertionError#getCause}. + * + * @param expectedThrowable the expected type of the exception + * @param runnable a function that is expected to throw an exception when executed + * @return the exception thrown by {@code runnable} + * @since 4.13 + */ + public static T assertThrows(Class expectedThrowable, + ThrowingRunnable runnable) { + return assertThrows(null, expectedThrowable, runnable); + } + + /** + * Asserts that {@code runnable} throws an exception of type {@code expectedThrowable} when + * executed. If it does, the exception object is returned. If it does not throw an exception, an + * {@link AssertionError} is thrown. If it throws the wrong type of exception, an {@code + * AssertionError} is thrown describing the mismatch; the exception that was actually thrown can + * be obtained by calling {@link AssertionError#getCause}. + * + * @param message the identifying message for the {@link AssertionError} (null + * okay) + * @param expectedThrowable the expected type of the exception + * @param runnable a function that is expected to throw an exception when executed + * @return the exception thrown by {@code runnable} + * @since 4.13 + */ + public static T assertThrows(String message, Class expectedThrowable, + ThrowingRunnable runnable) { + try { + runnable.run(); + } catch (Throwable actualThrown) { + if (expectedThrowable.isInstance(actualThrown)) { + @SuppressWarnings("unchecked") T retVal = (T) actualThrown; + return retVal; + } else { + String expected = formatClass(expectedThrowable); + Class actualThrowable = actualThrown.getClass(); + String actual = formatClass(actualThrowable); + if (expected.equals(actual)) { + // There must be multiple class loaders. Add the identity hash code so the message + // doesn't say "expected: java.lang.String ..." + expected += "@" + Integer.toHexString(System.identityHashCode(expectedThrowable)); + actual += "@" + Integer.toHexString(System.identityHashCode(actualThrowable)); + } + String mismatchMessage = buildPrefix(message) + + format("unexpected exception type thrown;", expected, actual); + + // The AssertionError(String, Throwable) ctor is only available on JDK7. + AssertionError assertionError = new AssertionError(mismatchMessage); + assertionError.initCause(actualThrown); + throw assertionError; + } + } + String notThrownMessage = buildPrefix(message) + String + .format("expected %s to be thrown, but nothing was thrown", + formatClass(expectedThrowable)); + throw new AssertionError(notThrownMessage); + } + + private static String buildPrefix(String message) { + return message != null && message.length() != 0 ? message + ": " : ""; + } +} diff --git a/src/main/java/org/junit/Assume.java b/src/main/java/org/junit/Assume.java new file mode 100644 index 000000000000..29b705be6988 --- /dev/null +++ b/src/main/java/org/junit/Assume.java @@ -0,0 +1,169 @@ +package org.junit; + +import static java.util.Arrays.asList; +import static org.hamcrest.CoreMatchers.everyItem; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.hamcrest.CoreMatchers.nullValue; + +import org.hamcrest.Matcher; + +/** + * A set of methods useful for stating assumptions about the conditions in which a test is meaningful. + * A failed assumption does not mean the code is broken, but that the test provides no useful information. Assume + * basically means "don't run this test if these conditions don't apply". The default JUnit runner skips tests with + * failing assumptions. Custom runners may behave differently. + *

    + * A good example of using assumptions is in Theories where they are needed to exclude certain datapoints that aren't suitable or allowed for a certain test case. + *

    + * Failed assumptions are usually not logged, because there may be many tests that don't apply to certain + * configurations. + * + *

    + * These methods can be used directly: Assume.assumeTrue(...), however, they + * read better if they are referenced through static import:
    + *

    + * import static org.junit.Assume.*;
    + *    ...
    + *    assumeTrue(...);
    + * 
    + *

    + * + * @see Theories + * + * @since 4.4 + */ +public class Assume { + + /** + * Do not instantiate. + * @deprecated since 4.13. + */ + @Deprecated + public Assume() { + } + + /** + * If called with an expression evaluating to {@code false}, the test will halt and be ignored. + */ + public static void assumeTrue(boolean b) { + assumeThat(b, is(true)); + } + + /** + * The inverse of {@link #assumeTrue(boolean)}. + */ + public static void assumeFalse(boolean b) { + assumeThat(b, is(false)); + } + + /** + * If called with an expression evaluating to {@code false}, the test will halt and be ignored. + * + * @param b If false, the method will attempt to stop the test and ignore it by + * throwing {@link AssumptionViolatedException}. + * @param message A message to pass to {@link AssumptionViolatedException}. + */ + public static void assumeTrue(String message, boolean b) { + if (!b) throw new AssumptionViolatedException(message); + } + + /** + * The inverse of {@link #assumeTrue(String, boolean)}. + */ + public static void assumeFalse(String message, boolean b) { + assumeTrue(message, !b); + } + + /** + * If called with a {@code null} array or one or more {@code null} elements in {@code objects}, + * the test will halt and be ignored. + */ + public static void assumeNotNull(Object... objects) { + assumeThat(objects, notNullValue()); + assumeThat(asList(objects), everyItem(notNullValue())); + } + + /** + * Call to assume that actual satisfies the condition specified by matcher. + * If not, the test halts and is ignored. + * Example: + *
    :
    +     *   assumeThat(1, is(1)); // passes
    +     *   foo(); // will execute
    +     *   assumeThat(0, is(1)); // assumption failure! test halts
    +     *   int x = 1 / 0; // will never execute
    +     * 
    + * + * @param the static type accepted by the matcher (this can flag obvious compile-time problems such as {@code assumeThat(1, is("a"))} + * @param actual the computed value being compared + * @param matcher an expression, built of {@link Matcher}s, specifying allowed values + * @see org.hamcrest.CoreMatchers + * @see org.junit.matchers.JUnitMatchers + */ + public static void assumeThat(T actual, Matcher matcher) { + if (!matcher.matches(actual)) { + throw new AssumptionViolatedException(actual, matcher); + } + } + + /** + * Call to assume that actual satisfies the condition specified by matcher. + * If not, the test halts and is ignored. + * Example: + *
    :
    +     *   assumeThat("alwaysPasses", 1, is(1)); // passes
    +     *   foo(); // will execute
    +     *   assumeThat("alwaysFails", 0, is(1)); // assumption failure! test halts
    +     *   int x = 1 / 0; // will never execute
    +     * 
    + * + * @param the static type accepted by the matcher (this can flag obvious compile-time problems such as {@code assumeThat(1, is("a"))} + * @param actual the computed value being compared + * @param matcher an expression, built of {@link Matcher}s, specifying allowed values + * @see org.hamcrest.CoreMatchers + * @see org.junit.matchers.JUnitMatchers + */ + public static void assumeThat(String message, T actual, Matcher matcher) { + if (!matcher.matches(actual)) { + throw new AssumptionViolatedException(message, actual, matcher); + } + } + + /** + * Use to assume that an operation completes normally. If {@code e} is non-null, the test will halt and be ignored. + * + * For example: + *
    +     * \@Test public void parseDataFile() {
    +     *   DataFile file;
    +     *   try {
    +     *     file = DataFile.open("sampledata.txt");
    +     *   } catch (IOException e) {
    +     *     // stop test and ignore if data can't be opened
    +     *     assumeNoException(e);
    +     *   }
    +     *   // ...
    +     * }
    +     * 
    + * + * @param e if non-null, the offending exception + */ + public static void assumeNoException(Throwable e) { + assumeThat(e, nullValue()); + } + + /** + * Attempts to halt the test and ignore it if Throwable e is + * not null. Similar to {@link #assumeNoException(Throwable)}, + * but provides an additional message that can explain the details + * concerning the assumption. + * + * @param e if non-null, the offending exception + * @param message Additional message to pass to {@link AssumptionViolatedException}. + * @see #assumeNoException(Throwable) + */ + public static void assumeNoException(String message, Throwable e) { + assumeThat(message, e, nullValue()); + } +} diff --git a/src/main/java/org/junit/AssumptionViolatedException.java b/src/main/java/org/junit/AssumptionViolatedException.java new file mode 100644 index 000000000000..1d62190a2315 --- /dev/null +++ b/src/main/java/org/junit/AssumptionViolatedException.java @@ -0,0 +1,46 @@ +package org.junit; + +import org.hamcrest.Matcher; + +/** + * An exception class used to implement assumptions (state in which a given test + * is meaningful and should or should not be executed). A test for which an assumption + * fails should not generate a test case failure. + * + * @see org.junit.Assume + * @since 4.12 + */ +@SuppressWarnings("deprecation") +public class AssumptionViolatedException extends org.junit.internal.AssumptionViolatedException { + private static final long serialVersionUID = 1L; + + /** + * An assumption exception with the given actual value and a matcher describing + * the expectation that failed. + */ + public AssumptionViolatedException(T actual, Matcher matcher) { + super(actual, matcher); + } + + /** + * An assumption exception with a message with the given actual value and a + * matcher describing the expectation that failed. + */ + public AssumptionViolatedException(String message, T expected, Matcher matcher) { + super(message, expected, matcher); + } + + /** + * An assumption exception with the given message only. + */ + public AssumptionViolatedException(String message) { + super(message); + } + + /** + * An assumption exception with the given message and a cause. + */ + public AssumptionViolatedException(String message, Throwable t) { + super(message, t); + } +} diff --git a/src/main/java/org/junit/Before.java b/src/main/java/org/junit/Before.java new file mode 100644 index 000000000000..def8adb47ad6 --- /dev/null +++ b/src/main/java/org/junit/Before.java @@ -0,0 +1,39 @@ +package org.junit; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * When writing tests, it is common to find that several tests need similar + * objects created before they can run. Annotating a public void method + * with @Before causes that method to be run before the {@link org.junit.Test} method. + * The @Before methods of superclasses will be run before those of the current class, + * unless they are overridden in the current class. No other ordering is defined. + *

    + * Here is a simple example: + *

    + * public class Example {
    + *    List empty;
    + *    @Before public void initialize() {
    + *       empty= new ArrayList();
    + *    }
    + *    @Test public void size() {
    + *       ...
    + *    }
    + *    @Test public void remove() {
    + *       ...
    + *    }
    + * }
    + * 
    + * + * @see org.junit.BeforeClass + * @see org.junit.After + * @since 4.0 + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface Before { +} + diff --git a/src/main/java/org/junit/BeforeClass.java b/src/main/java/org/junit/BeforeClass.java new file mode 100644 index 000000000000..8183fa0f0a14 --- /dev/null +++ b/src/main/java/org/junit/BeforeClass.java @@ -0,0 +1,37 @@ +package org.junit; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Sometimes several tests need to share computationally expensive setup + * (like logging into a database). While this can compromise the independence of + * tests, sometimes it is a necessary optimization. Annotating a public static void no-arg method + * with @BeforeClass causes it to be run once before any of + * the test methods in the class. The @BeforeClass methods of superclasses + * will be run before those of the current class, unless they are shadowed in the current class. + *

    + * For example: + *

    + * public class Example {
    + *    @BeforeClass public static void onlyOnce() {
    + *       ...
    + *    }
    + *    @Test public void one() {
    + *       ...
    + *    }
    + *    @Test public void two() {
    + *       ...
    + *    }
    + * }
    + * 
    + * + * @see org.junit.AfterClass + * @since 4.0 + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface BeforeClass { +} diff --git a/src/main/java/org/junit/ClassRule.java b/src/main/java/org/junit/ClassRule.java new file mode 100644 index 000000000000..94ee29f9f51d --- /dev/null +++ b/src/main/java/org/junit/ClassRule.java @@ -0,0 +1,118 @@ +package org.junit; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Annotates static fields that reference rules or methods that return them. A field must be public, + * static, and a subtype of {@link org.junit.rules.TestRule}. A method must be public static, and return + * a subtype of {@link org.junit.rules.TestRule}. + *

    + * The {@link org.junit.runners.model.Statement} passed + * to the {@link org.junit.rules.TestRule} will run any {@link BeforeClass} methods, + * then the entire body of the test class (all contained methods, if it is + * a standard JUnit test class, or all contained classes, if it is a + * {@link org.junit.runners.Suite}), and finally any {@link AfterClass} methods. + *

    + * The statement passed to the {@link org.junit.rules.TestRule} will never throw an exception, + * and throwing an exception from the {@link org.junit.rules.TestRule} will result in undefined + * behavior. This means that some {@link org.junit.rules.TestRule}s, such as + * {@link org.junit.rules.ErrorCollector}, + * {@link org.junit.rules.ExpectedException}, + * and {@link org.junit.rules.Timeout}, + * have undefined behavior when used as {@link ClassRule}s. + *

    + * If there are multiple + * annotated {@link ClassRule}s on a class, they will be applied in an order + * that depends on your JVM's implementation of the reflection API, which is + * undefined, in general. However, Rules defined by fields will always be applied + * after Rules defined by methods, i.e. the Statements returned by the former will + * be executed around those returned by the latter. + * + *

    Usage

    + *

    + * For example, here is a test suite that connects to a server once before + * all the test classes run, and disconnects after they are finished: + *

    + * @RunWith(Suite.class)
    + * @SuiteClasses({A.class, B.class, C.class})
    + * public class UsesExternalResource {
    + *     public static Server myServer= new Server();
    + *
    + *     @ClassRule
    + *     public static ExternalResource resource= new ExternalResource() {
    + *       @Override
    + *       protected void before() throws Throwable {
    + *          myServer.connect();
    + *      }
    + *
    + *      @Override
    + *      protected void after() {
    + * 	        myServer.disconnect();
    + *      }
    + *   };
    + * }
    + * 
    + *

    + * and the same using a method + *

    + * @RunWith(Suite.class)
    + * @SuiteClasses({A.class, B.class, C.class})
    + * public class UsesExternalResource {
    + *     public static Server myServer= new Server();
    + *
    + *     @ClassRule
    + *     public static ExternalResource getResource() {
    + *         return new ExternalResource() {
    + *             @Override
    + *             protected void before() throws Throwable {
    + *                 myServer.connect();
    + *             }
    + *
    + *             @Override
    + *             protected void after() {
    + *                 myServer.disconnect();
    + *             }
    + *         };
    + *     }
    + * }
    + * 
    + *

    + * For more information and more examples, see {@link org.junit.rules.TestRule}. + * + *

    Ordering

    + *

    + * You can use {@link #order()} if you want to have control over the order in + * which the Rules are applied. + * + *

    + * public class ThreeClassRules {
    + *     @ClassRule(order = 0)
    + *     public static LoggingRule outer = new LoggingRule("outer rule");
    + *
    + *     @ClassRule(order = 1)
    + *     public static LoggingRule middle = new LoggingRule("middle rule");
    + *
    + *     @ClassRule(order = 2)
    + *     public static LoggingRule inner = new LoggingRule("inner rule");
    + *
    + *     // ...
    + * }
    + * 
    + * + * @since 4.9 + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.FIELD, ElementType.METHOD}) +public @interface ClassRule { + + /** + * Specifies the order in which rules are applied. The rules with a higher value are inner. + * + * @since 4.13 + */ + int order() default Rule.DEFAULT_ORDER; + +} diff --git a/src/main/java/org/junit/ComparisonFailure.java b/src/main/java/org/junit/ComparisonFailure.java new file mode 100644 index 000000000000..d1daa863c3f3 --- /dev/null +++ b/src/main/java/org/junit/ComparisonFailure.java @@ -0,0 +1,171 @@ +package org.junit; + +/** + * Thrown when an {@link org.junit.Assert#assertEquals(Object, Object) assertEquals(String, String)} fails. + * Create and throw a ComparisonFailure manually if you want to show users the + * difference between two complex strings. + *

    + * Inspired by a patch from Alex Chaffee (alex@purpletech.com) + * + * @since 4.0 + */ +public class ComparisonFailure extends AssertionError { + /** + * The maximum length for expected and actual strings. If it is exceeded, the strings should be shortened. + * + * @see ComparisonCompactor + */ + private static final int MAX_CONTEXT_LENGTH = 20; + private static final long serialVersionUID = 1L; + + /* + * We have to use the f prefix until the next major release to ensure + * serialization compatibility. + * See https://github.com/junit-team/junit4/issues/976 + */ + private String fExpected; + private String fActual; + + /** + * Constructs a comparison failure. + * + * @param message the identifying message or null + * @param expected the expected string value + * @param actual the actual string value + */ + public ComparisonFailure(String message, String expected, String actual) { + super(message); + this.fExpected = expected; + this.fActual = actual; + } + + /** + * Returns "..." in place of common prefix and "..." in place of common suffix between expected and actual. + * + * @see Throwable#getMessage() + */ + @Override + public String getMessage() { + return new ComparisonCompactor(MAX_CONTEXT_LENGTH, fExpected, fActual).compact(super.getMessage()); + } + + /** + * Returns the actual string value + * + * @return the actual string value + */ + public String getActual() { + return fActual; + } + + /** + * Returns the expected string value + * + * @return the expected string value + */ + public String getExpected() { + return fExpected; + } + + private static class ComparisonCompactor { + private static final String ELLIPSIS = "..."; + private static final String DIFF_END = "]"; + private static final String DIFF_START = "["; + + /** + * The maximum length for expected and actual strings to show. When + * contextLength is exceeded, the Strings are shortened. + */ + private final int contextLength; + private final String expected; + private final String actual; + + /** + * @param contextLength the maximum length of context surrounding the difference between the compared strings. + * When context length is exceeded, the prefixes and suffixes are compacted. + * @param expected the expected string value + * @param actual the actual string value + */ + public ComparisonCompactor(int contextLength, String expected, String actual) { + this.contextLength = contextLength; + this.expected = expected; + this.actual = actual; + } + + public String compact(String message) { + if (expected == null || actual == null || expected.equals(actual)) { + return Assert.format(message, expected, actual); + } else { + DiffExtractor extractor = new DiffExtractor(); + String compactedPrefix = extractor.compactPrefix(); + String compactedSuffix = extractor.compactSuffix(); + return Assert.format(message, + compactedPrefix + extractor.expectedDiff() + compactedSuffix, + compactedPrefix + extractor.actualDiff() + compactedSuffix); + } + } + + private String sharedPrefix() { + int end = Math.min(expected.length(), actual.length()); + for (int i = 0; i < end; i++) { + if (expected.charAt(i) != actual.charAt(i)) { + return expected.substring(0, i); + } + } + return expected.substring(0, end); + } + + private String sharedSuffix(String prefix) { + int suffixLength = 0; + int maxSuffixLength = Math.min(expected.length() - prefix.length(), + actual.length() - prefix.length()) - 1; + for (; suffixLength <= maxSuffixLength; suffixLength++) { + if (expected.charAt(expected.length() - 1 - suffixLength) + != actual.charAt(actual.length() - 1 - suffixLength)) { + break; + } + } + return expected.substring(expected.length() - suffixLength); + } + + private class DiffExtractor { + private final String sharedPrefix; + private final String sharedSuffix; + + /** + * Can not be instantiated outside {@link org.junit.ComparisonFailure.ComparisonCompactor}. + */ + private DiffExtractor() { + sharedPrefix = sharedPrefix(); + sharedSuffix = sharedSuffix(sharedPrefix); + } + + public String expectedDiff() { + return extractDiff(expected); + } + + public String actualDiff() { + return extractDiff(actual); + } + + public String compactPrefix() { + if (sharedPrefix.length() <= contextLength) { + return sharedPrefix; + } + return ELLIPSIS + sharedPrefix.substring(sharedPrefix.length() - contextLength); + } + + public String compactSuffix() { + if (sharedSuffix.length() <= contextLength) { + return sharedSuffix; + } + return sharedSuffix.substring(0, contextLength) + ELLIPSIS; + } + + private String extractDiff(String source) { + return DIFF_START + source.substring(sharedPrefix.length(), source.length() - sharedSuffix.length()) + + DIFF_END; + } + } + } +} diff --git a/src/main/java/org/junit/FixMethodOrder.java b/src/main/java/org/junit/FixMethodOrder.java new file mode 100644 index 000000000000..aaa0313e710c --- /dev/null +++ b/src/main/java/org/junit/FixMethodOrder.java @@ -0,0 +1,41 @@ +package org.junit; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.junit.runners.MethodSorters; + +/** + * This class allows the user to choose the order of execution of the methods within a test class. + * + *

    The default order of execution of JUnit tests within a class is deterministic but not predictable. + * The order of execution is not guaranteed for Java 7 (and some previous versions), and can even change + * from run to run, so the order of execution was changed to be deterministic (in JUnit 4.11) + * + *

    It is recommended that test methods be written so that they are independent of the order that they are executed. + * However, there may be a number of dependent tests either through error or by design. + * This class allows the user to specify the order of execution of test methods. + * + *

    For possibilities, see {@link MethodSorters} + * + * Here is an example: + * + *

    + * @FixMethodOrder(MethodSorters.NAME_ASCENDING)
    + * public class MyTest {
    + * }
    + * 
    + * + * @see org.junit.runners.MethodSorters + * @since 4.11 + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.TYPE}) +public @interface FixMethodOrder { + /** + * Optionally specify value to have the methods executed in a particular order + */ + MethodSorters value() default MethodSorters.DEFAULT; +} diff --git a/src/main/java/org/junit/Ignore.java b/src/main/java/org/junit/Ignore.java new file mode 100644 index 000000000000..db23581073bd --- /dev/null +++ b/src/main/java/org/junit/Ignore.java @@ -0,0 +1,40 @@ +package org.junit; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Sometimes you want to temporarily disable a test or a group of tests. Methods annotated with + * {@link org.junit.Test} that are also annotated with @Ignore will not be executed as tests. + * Also, you can annotate a class containing test methods with @Ignore and none of the containing + * tests will be executed. Native JUnit 4 test runners should report the number of ignored tests along with the + * number of tests that ran and the number of tests that failed. + * + *

    For example: + *

    + *    @Ignore @Test public void something() { ...
    + * 
    + * @Ignore takes an optional default parameter if you want to record why a test is being ignored: + *
    + *    @Ignore("not ready yet") @Test public void something() { ...
    + * 
    + * @Ignore can also be applied to the test class: + *
    + *      @Ignore public class IgnoreMe {
    + *          @Test public void test1() { ... }
    + *          @Test public void test2() { ... }
    + *         }
    + * 
    + * + * @since 4.0 + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.METHOD, ElementType.TYPE}) +public @interface Ignore { + /** + * The optional reason why the test is ignored. + */ + String value() default ""; +} diff --git a/src/main/java/org/junit/Rule.java b/src/main/java/org/junit/Rule.java new file mode 100644 index 000000000000..9370e94f51fc --- /dev/null +++ b/src/main/java/org/junit/Rule.java @@ -0,0 +1,101 @@ +package org.junit; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Annotates fields that reference rules or methods that return a rule. A field must be public, not + * static, and a subtype of {@link org.junit.rules.TestRule} (preferred) or + * {@link org.junit.rules.MethodRule}. A method must be public, not static, + * and must return a subtype of {@link org.junit.rules.TestRule} (preferred) or + * {@link org.junit.rules.MethodRule}. + *

    + * The {@link org.junit.runners.model.Statement} passed + * to the {@link org.junit.rules.TestRule} will run any {@link Before} methods, + * then the {@link Test} method, and finally any {@link After} methods, + * throwing an exception if any of these fail. If there are multiple + * annotated {@link Rule}s on a class, they will be applied in order of methods first, then fields. + * However, if there are multiple fields (or methods) they will be applied in an order + * that depends on your JVM's implementation of the reflection API, which is + * undefined, in general. Rules defined by fields will always be applied + * after Rules defined by methods, i.e. the Statements returned by the former will + * be executed around those returned by the latter. + * + *

    Usage

    + *

    + * For example, here is a test class that creates a temporary folder before + * each test method, and deletes it after each: + *

    + * public static class HasTempFolder {
    + *     @Rule
    + *     public TemporaryFolder folder= new TemporaryFolder();
    + *
    + *     @Test
    + *     public void testUsingTempFolder() throws IOException {
    + *         File createdFile= folder.newFile("myfile.txt");
    + *         File createdFolder= folder.newFolder("subfolder");
    + *         // ...
    + *     }
    + * }
    + * 
    + *

    + * And the same using a method. + *

    + * public static class HasTempFolder {
    + *     private TemporaryFolder folder= new TemporaryFolder();
    + *
    + *     @Rule
    + *     public TemporaryFolder getFolder() {
    + *         return folder;
    + *     }
    + *
    + *     @Test
    + *     public void testUsingTempFolder() throws IOException {
    + *         File createdFile= folder.newFile("myfile.txt");
    + *         File createdFolder= folder.newFolder("subfolder");
    + *         // ...
    + *     }
    + * }
    + * 
    + *

    + * For more information and more examples, see + * {@link org.junit.rules.TestRule}. + * + *

    Ordering

    + *

    + * You can use {@link #order()} if you want to have control over the order in + * which the Rules are applied. + * + *

    + * public class ThreeRules {
    + *     @Rule(order = 0)
    + *     public LoggingRule outer = new LoggingRule("outer rule");
    + *
    + *     @Rule(order = 1)
    + *     public LoggingRule middle = new LoggingRule("middle rule");
    + *
    + *     @Rule(order = 2)
    + *     public LoggingRule inner = new LoggingRule("inner rule");
    + *
    + *     // ...
    + * }
    + * 
    + * + * @since 4.7 + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.FIELD, ElementType.METHOD}) +public @interface Rule { + + int DEFAULT_ORDER = -1; + + /** + * Specifies the order in which rules are applied. The rules with a higher value are inner. + * + * @since 4.13 + */ + int order() default DEFAULT_ORDER; + +} diff --git a/src/main/java/org/junit/Test.java b/src/main/java/org/junit/Test.java new file mode 100644 index 000000000000..1db6fc7ab073 --- /dev/null +++ b/src/main/java/org/junit/Test.java @@ -0,0 +1,117 @@ +package org.junit; + +import org.junit.function.ThrowingRunnable; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * The Test annotation tells JUnit that the public void method + * to which it is attached can be run as a test case. To run the method, + * JUnit first constructs a fresh instance of the class then invokes the + * annotated method. Any exceptions thrown by the test will be reported + * by JUnit as a failure. If no exceptions are thrown, the test is assumed + * to have succeeded. + *

    + * A simple test looks like this: + *

    + * public class Example {
    + *    @Test
    + *    public void method() {
    + *       org.junit.Assert.assertTrue( new ArrayList().isEmpty() );
    + *    }
    + * }
    + * 
    + *

    + * The Test annotation supports two optional parameters for + * exception testing and for limiting test execution time. + * + *

    Exception Testing

    + *

    + * The parameter expected declares that a test method should throw + * an exception. If it doesn't throw an exception or if it throws a different exception + * than the one declared, the test fails. For example, the following test succeeds: + *

    + *    @Test(expected=IndexOutOfBoundsException.class)
    + *    public void outOfBounds() {
    + *       new ArrayList<Object>().get(1);
    + *    }
    + * 
    + * + * Using the parameter expected for exception testing comes with + * some limitations: only the exception's type can be checked and it is not + * possible to precisely specify the code that throws the exception. Therefore + * JUnit 4 has improved its support for exception testing with + * {@link Assert#assertThrows(Class, ThrowingRunnable)} and the + * {@link org.junit.rules.ExpectedException ExpectedException} rule. + * With assertThrows the code that throws the exception can be + * precisely specified. If the exception's message or one of its properties + * should be verified, the ExpectedException rule can be used. Further + * information about exception testing can be found at the + * JUnit Wiki. + * + *

    Timeout

    + *

    + * The parameter timeout causes a test to fail if it takes + * longer than a specified amount of clock time (measured in milliseconds). The following test fails: + *

    + *    @Test(timeout=100)
    + *    public void infinity() {
    + *       while(true);
    + *    }
    + * 
    + * Warning: while timeout is useful to catch and terminate + * infinite loops, it should not be considered deterministic. The + * following test may or may not fail depending on how the operating system + * schedules threads: + *
    + *    @Test(timeout=100)
    + *    public void sleep100() {
    + *       Thread.sleep(100);
    + *    }
    + * 
    + * THREAD SAFETY WARNING: Test methods with a timeout parameter are run in a thread other than the + * thread which runs the fixture's @Before and @After methods. This may yield different behavior for + * code that is not thread safe when compared to the same test method without a timeout parameter. + * Consider using the {@link org.junit.rules.Timeout} rule instead, which ensures a test method is run on the + * same thread as the fixture's @Before and @After methods. + * + * @since 4.0 + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.METHOD}) +public @interface Test { + + /** + * Default empty exception. + */ + static class None extends Throwable { + private static final long serialVersionUID = 1L; + + private None() { + } + } + + /** + * Optionally specify expected, a Throwable, to cause a test method to succeed if + * and only if an exception of the specified class is thrown by the method. If the Throwable's + * message or one of its properties should be verified, the + * {@link org.junit.rules.ExpectedException ExpectedException} rule can be used instead. + */ + Class expected() default None.class; + + /** + * Optionally specify timeout in milliseconds to cause a test method to fail if it + * takes longer than that number of milliseconds. + *

    + * THREAD SAFETY WARNING: Test methods with a timeout parameter are run in a thread other than the + * thread which runs the fixture's @Before and @After methods. This may yield different behavior for + * code that is not thread safe when compared to the same test method without a timeout parameter. + * Consider using the {@link org.junit.rules.Timeout} rule instead, which ensures a test method is run on the + * same thread as the fixture's @Before and @After methods. + *

    + */ + long timeout() default 0L; +} diff --git a/src/main/java/org/junit/TestCouldNotBeSkippedException.java b/src/main/java/org/junit/TestCouldNotBeSkippedException.java new file mode 100644 index 000000000000..4804493290ef --- /dev/null +++ b/src/main/java/org/junit/TestCouldNotBeSkippedException.java @@ -0,0 +1,19 @@ +package org.junit; + +/** + * Indicates that a test that indicated that it should be skipped could not be skipped. + * This can be thrown if a test uses the methods in {@link Assume} to indicate that + * it should be skipped, but before processing of the test was completed, other failures + * occured. + * + * @see org.junit.Assume + * @since 4.13 + */ +public class TestCouldNotBeSkippedException extends RuntimeException { + private static final long serialVersionUID = 1L; + + /** Creates an instance using the given assumption failure. */ + public TestCouldNotBeSkippedException(org.junit.internal.AssumptionViolatedException cause) { + super("Test could not be skipped due to other failures", cause); + } +} diff --git a/src/main/java/org/junit/experimental/ParallelComputer.java b/src/main/java/org/junit/experimental/ParallelComputer.java new file mode 100644 index 000000000000..97da0f759f48 --- /dev/null +++ b/src/main/java/org/junit/experimental/ParallelComputer.java @@ -0,0 +1,67 @@ +package org.junit.experimental; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +import org.junit.runner.Computer; +import org.junit.runner.Runner; +import org.junit.runners.ParentRunner; +import org.junit.runners.model.InitializationError; +import org.junit.runners.model.RunnerBuilder; +import org.junit.runners.model.RunnerScheduler; + +public class ParallelComputer extends Computer { + private final boolean classes; + + private final boolean methods; + + public ParallelComputer(boolean classes, boolean methods) { + this.classes = classes; + this.methods = methods; + } + + public static Computer classes() { + return new ParallelComputer(true, false); + } + + public static Computer methods() { + return new ParallelComputer(false, true); + } + + private static Runner parallelize(Runner runner) { + if (runner instanceof ParentRunner) { + ((ParentRunner) runner).setScheduler(new RunnerScheduler() { + private final ExecutorService fService = Executors.newCachedThreadPool(); + + public void schedule(Runnable childStatement) { + fService.submit(childStatement); + } + + public void finished() { + try { + fService.shutdown(); + fService.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS); + } catch (InterruptedException e) { + e.printStackTrace(System.err); + } + } + }); + } + return runner; + } + + @Override + public Runner getSuite(RunnerBuilder builder, java.lang.Class[] classes) + throws InitializationError { + Runner suite = super.getSuite(builder, classes); + return this.classes ? parallelize(suite) : suite; + } + + @Override + protected Runner getRunner(RunnerBuilder builder, Class testClass) + throws Throwable { + Runner runner = super.getRunner(builder, testClass); + return methods ? parallelize(runner) : runner; + } +} diff --git a/src/main/java/org/junit/experimental/categories/Categories.java b/src/main/java/org/junit/experimental/categories/Categories.java new file mode 100644 index 000000000000..0c73ed82afff --- /dev/null +++ b/src/main/java/org/junit/experimental/categories/Categories.java @@ -0,0 +1,375 @@ +package org.junit.experimental.categories; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.Set; + +import org.junit.runner.Description; +import org.junit.runner.manipulation.Filter; +import org.junit.runner.manipulation.NoTestsRemainException; +import org.junit.runners.Suite; +import org.junit.runners.model.InitializationError; +import org.junit.runners.model.RunnerBuilder; + +/** + * From a given set of test classes, runs only the classes and methods that are + * annotated with either the category given with the @IncludeCategory + * annotation, or a subtype of that category. + *

    + * Note that, for now, annotating suites with {@code @Category} has no effect. + * Categories must be annotated on the direct method or class. + *

    + * Example: + *

    + * public interface FastTests {
    + * }
    + *
    + * public interface SlowTests {
    + * }
    + *
    + * public interface SmokeTests
    + * }
    + *
    + * public static class A {
    + *     @Test
    + *     public void a() {
    + *         fail();
    + *     }
    + *
    + *     @Category(SlowTests.class)
    + *     @Test
    + *     public void b() {
    + *     }
    + *
    + *     @Category({FastTests.class, SmokeTests.class})
    + *     @Test
    + *     public void c() {
    + *     }
    + * }
    + *
    + * @Category({SlowTests.class, FastTests.class})
    + * public static class B {
    + *     @Test
    + *     public void d() {
    + *     }
    + * }
    + *
    + * @RunWith(Categories.class)
    + * @IncludeCategory(SlowTests.class)
    + * @SuiteClasses({A.class, B.class})
    + * // Note that Categories is a kind of Suite
    + * public static class SlowTestSuite {
    + *     // Will run A.b and B.d, but not A.a and A.c
    + * }
    + * 
    + *

    + * Example to run multiple categories: + *

    + * @RunWith(Categories.class)
    + * @IncludeCategory({FastTests.class, SmokeTests.class})
    + * @SuiteClasses({A.class, B.class})
    + * public static class FastOrSmokeTestSuite {
    + *     // Will run A.c and B.d, but not A.b because it is not any of FastTests or SmokeTests
    + * }
    + * 
    + * + * @version 4.12 + * @see Categories at JUnit wiki + */ +public class Categories extends Suite { + + @Retention(RetentionPolicy.RUNTIME) + public @interface IncludeCategory { + /** + * Determines the tests to run that are annotated with categories specified in + * the value of this annotation or their subtypes unless excluded with {@link ExcludeCategory}. + */ + Class[] value() default {}; + + /** + * If true, runs tests annotated with any of the categories in + * {@link IncludeCategory#value()}. Otherwise, runs tests only if annotated with all of the categories. + */ + boolean matchAny() default true; + } + + @Retention(RetentionPolicy.RUNTIME) + public @interface ExcludeCategory { + /** + * Determines the tests which do not run if they are annotated with categories specified in the + * value of this annotation or their subtypes regardless of being included in {@link IncludeCategory#value()}. + */ + Class[] value() default {}; + + /** + * If true, the tests annotated with any of the categories in {@link ExcludeCategory#value()} + * do not run. Otherwise, the tests do not run if and only if annotated with all categories. + */ + boolean matchAny() default true; + } + + public static class CategoryFilter extends Filter { + private final Set> included; + private final Set> excluded; + private final boolean includedAny; + private final boolean excludedAny; + + public static CategoryFilter include(boolean matchAny, Class... categories) { + return new CategoryFilter(matchAny, categories, true, null); + } + + public static CategoryFilter include(Class category) { + return include(true, category); + } + + public static CategoryFilter include(Class... categories) { + return include(true, categories); + } + + public static CategoryFilter exclude(boolean matchAny, Class... categories) { + return new CategoryFilter(true, null, matchAny, categories); + } + + public static CategoryFilter exclude(Class category) { + return exclude(true, category); + } + + public static CategoryFilter exclude(Class... categories) { + return exclude(true, categories); + } + + public static CategoryFilter categoryFilter(boolean matchAnyInclusions, Set> inclusions, + boolean matchAnyExclusions, Set> exclusions) { + return new CategoryFilter(matchAnyInclusions, inclusions, matchAnyExclusions, exclusions); + } + + @Deprecated + public CategoryFilter(Class includedCategory, Class excludedCategory) { + includedAny = true; + excludedAny = true; + included = nullableClassToSet(includedCategory); + excluded = nullableClassToSet(excludedCategory); + } + + protected CategoryFilter(boolean matchAnyIncludes, Set> includes, + boolean matchAnyExcludes, Set> excludes) { + includedAny = matchAnyIncludes; + excludedAny = matchAnyExcludes; + included = copyAndRefine(includes); + excluded = copyAndRefine(excludes); + } + + private CategoryFilter(boolean matchAnyIncludes, Class[] inclusions, + boolean matchAnyExcludes, Class[] exclusions) { + includedAny = matchAnyIncludes; + excludedAny = matchAnyExcludes; + included = createSet(inclusions); + excluded = createSet(exclusions); + } + + /** + * @see #toString() + */ + @Override + public String describe() { + return toString(); + } + + /** + * Returns string in the form "[included categories] - [excluded categories]", where both + * sets have comma separated names of categories. + * + * @return string representation for the relative complement of excluded categories set + * in the set of included categories. Examples: + *
      + *
    • "categories [all]" for all included categories and no excluded ones; + *
    • "categories [all] - [A, B]" for all included categories and given excluded ones; + *
    • "categories [A, B] - [C, D]" for given included categories and given excluded ones. + *
    + * @see Class#toString() name of category + */ + @Override public String toString() { + StringBuilder description= new StringBuilder("categories ") + .append(included.isEmpty() ? "[all]" : included); + if (!excluded.isEmpty()) { + description.append(" - ").append(excluded); + } + return description.toString(); + } + + @Override + public boolean shouldRun(Description description) { + if (hasCorrectCategoryAnnotation(description)) { + return true; + } + + for (Description each : description.getChildren()) { + if (shouldRun(each)) { + return true; + } + } + + return false; + } + + private boolean hasCorrectCategoryAnnotation(Description description) { + final Set> childCategories= categories(description); + + // If a child has no categories, immediately return. + if (childCategories.isEmpty()) { + return included.isEmpty(); + } + + if (!excluded.isEmpty()) { + if (excludedAny) { + if (matchesAnyParentCategories(childCategories, excluded)) { + return false; + } + } else { + if (matchesAllParentCategories(childCategories, excluded)) { + return false; + } + } + } + + if (included.isEmpty()) { + // Couldn't be excluded, and with no suite's included categories treated as should run. + return true; + } else { + if (includedAny) { + return matchesAnyParentCategories(childCategories, included); + } else { + return matchesAllParentCategories(childCategories, included); + } + } + } + + /** + * @return true if at least one (any) parent category match a child, otherwise false. + * If empty parentCategories, returns false. + */ + private boolean matchesAnyParentCategories(Set> childCategories, Set> parentCategories) { + for (Class parentCategory : parentCategories) { + if (hasAssignableTo(childCategories, parentCategory)) { + return true; + } + } + return false; + } + + /** + * @return false if at least one parent category does not match children, otherwise true. + * If empty parentCategories, returns true. + */ + private boolean matchesAllParentCategories(Set> childCategories, Set> parentCategories) { + for (Class parentCategory : parentCategories) { + if (!hasAssignableTo(childCategories, parentCategory)) { + return false; + } + } + return true; + } + + private static Set> categories(Description description) { + Set> categories= new HashSet>(); + Collections.addAll(categories, directCategories(description)); + Collections.addAll(categories, directCategories(parentDescription(description))); + return categories; + } + + private static Description parentDescription(Description description) { + Class testClass= description.getTestClass(); + return testClass == null ? null : Description.createSuiteDescription(testClass); + } + + private static Class[] directCategories(Description description) { + if (description == null) { + return new Class[0]; + } + + Category annotation= description.getAnnotation(Category.class); + return annotation == null ? new Class[0] : annotation.value(); + } + + private static Set> copyAndRefine(Set> classes) { + Set> c= new LinkedHashSet>(); + if (classes != null) { + c.addAll(classes); + } + c.remove(null); + return c; + } + } + + public Categories(Class klass, RunnerBuilder builder) throws InitializationError { + super(klass, builder); + try { + Set> included= getIncludedCategory(klass); + Set> excluded= getExcludedCategory(klass); + boolean isAnyIncluded= isAnyIncluded(klass); + boolean isAnyExcluded= isAnyExcluded(klass); + + filter(CategoryFilter.categoryFilter(isAnyIncluded, included, isAnyExcluded, excluded)); + } catch (NoTestsRemainException e) { + throw new InitializationError(e); + } + } + + private static Set> getIncludedCategory(Class klass) { + IncludeCategory annotation= klass.getAnnotation(IncludeCategory.class); + return createSet(annotation == null ? null : annotation.value()); + } + + private static boolean isAnyIncluded(Class klass) { + IncludeCategory annotation= klass.getAnnotation(IncludeCategory.class); + return annotation == null || annotation.matchAny(); + } + + private static Set> getExcludedCategory(Class klass) { + ExcludeCategory annotation= klass.getAnnotation(ExcludeCategory.class); + return createSet(annotation == null ? null : annotation.value()); + } + + private static boolean isAnyExcluded(Class klass) { + ExcludeCategory annotation= klass.getAnnotation(ExcludeCategory.class); + return annotation == null || annotation.matchAny(); + } + + private static boolean hasAssignableTo(Set> assigns, Class to) { + for (final Class from : assigns) { + if (to.isAssignableFrom(from)) { + return true; + } + } + return false; + } + + private static Set> createSet(Class[] classes) { + // Not throwing a NPE if t is null is a bad idea, but it's the behavior from JUnit 4.12 + // for include(boolean, Class...) and exclude(boolean, Class...) + if (classes == null || classes.length == 0) { + return Collections.emptySet(); + } + for (Class category : classes) { + if (category == null) { + throw new NullPointerException("has null category"); + } + } + + return classes.length == 1 + ? Collections.>singleton(classes[0]) + : new LinkedHashSet>(Arrays.asList(classes)); + } + + private static Set> nullableClassToSet(Class nullableClass) { + // Not throwing a NPE if t is null is a bad idea, but it's the behavior from JUnit 4.11 + // for CategoryFilter(Class includedCategory, Class excludedCategory) + return nullableClass == null + ? Collections.>emptySet() + : Collections.>singleton(nullableClass); + } +} diff --git a/src/main/java/org/junit/experimental/categories/Category.java b/src/main/java/org/junit/experimental/categories/Category.java new file mode 100644 index 000000000000..8eae83677c94 --- /dev/null +++ b/src/main/java/org/junit/experimental/categories/Category.java @@ -0,0 +1,48 @@ +package org.junit.experimental.categories; + +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +import org.junit.validator.ValidateWith; + +/** + * Marks a test class or test method as belonging to one or more categories of tests. + * The value is an array of arbitrary classes. + * + * This annotation is only interpreted by the Categories runner (at present). + * + * For example: + *
    + * public interface FastTests {}
    + * public interface SlowTests {}
    + *
    + * public static class A {
    + * @Test
    + * public void a() {
    + * fail();
    + * }
    + *
    + * @Category(SlowTests.class)
    + * @Test
    + * public void b() {
    + * }
    + * }
    + *
    + * @Category({SlowTests.class, FastTests.class})
    + * public static class B {
    + * @Test
    + * public void c() {
    + *
    + * }
    + * }
    + * 
    + * + * For more usage, see code example on {@link Categories}. + */ +@Retention(RetentionPolicy.RUNTIME) +@Inherited +@ValidateWith(CategoryValidator.class) +public @interface Category { + Class[] value(); +} \ No newline at end of file diff --git a/src/main/java/org/junit/experimental/categories/CategoryFilterFactory.java b/src/main/java/org/junit/experimental/categories/CategoryFilterFactory.java new file mode 100644 index 000000000000..e9bdab77e502 --- /dev/null +++ b/src/main/java/org/junit/experimental/categories/CategoryFilterFactory.java @@ -0,0 +1,51 @@ +package org.junit.experimental.categories; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.internal.Classes; +import org.junit.runner.FilterFactory; +import org.junit.runner.FilterFactoryParams; +import org.junit.runner.manipulation.Filter; + +/** + * Implementation of FilterFactory for Category filtering. + */ +abstract class CategoryFilterFactory implements FilterFactory { + /** + * Creates a {@link org.junit.experimental.categories.Categories.CategoryFilter} given a + * {@link FilterFactoryParams} argument. + * + * @param params Parameters needed to create the {@link Filter} + */ + public Filter createFilter(FilterFactoryParams params) throws FilterNotCreatedException { + try { + return createFilter(parseCategories(params.getArgs())); + } catch (ClassNotFoundException e) { + throw new FilterNotCreatedException(e); + } + } + + /** + * Creates a {@link org.junit.experimental.categories.Categories.CategoryFilter} given an array of classes. + * + * @param categories Category classes. + */ + protected abstract Filter createFilter(List> categories); + + private List> parseCategories(String categories) throws ClassNotFoundException { + List> categoryClasses = new ArrayList>(); + + for (String category : categories.split(",")) { + /* + * Load the category class using the context class loader. + * If there is no context class loader, use the class loader for this class. + */ + Class categoryClass = Classes.getClass(category, getClass()); + + categoryClasses.add(categoryClass); + } + + return categoryClasses; + } +} diff --git a/src/main/java/org/junit/experimental/categories/CategoryValidator.java b/src/main/java/org/junit/experimental/categories/CategoryValidator.java new file mode 100644 index 000000000000..491d8accb586 --- /dev/null +++ b/src/main/java/org/junit/experimental/categories/CategoryValidator.java @@ -0,0 +1,62 @@ +package org.junit.experimental.categories; + +import static java.util.Arrays.asList; +import static java.util.Collections.unmodifiableList; +import static java.util.Collections.unmodifiableSet; + +import java.lang.annotation.Annotation; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.runners.model.FrameworkMethod; +import org.junit.validator.AnnotationValidator; + +/** + * Validates that there are no errors in the use of the {@code Category} + * annotation. If there is, a {@code Throwable} object will be added to the list + * of errors. + * + * @since 4.12 + */ +public final class CategoryValidator extends AnnotationValidator { + + @SuppressWarnings("unchecked") + private static final Set> INCOMPATIBLE_ANNOTATIONS = unmodifiableSet(new HashSet>( + asList(BeforeClass.class, AfterClass.class, Before.class, After.class))); + + /** + * Adds to {@code errors} a throwable for each problem detected. Looks for + * {@code BeforeClass}, {@code AfterClass}, {@code Before} and {@code After} + * annotations. + * + * @param method the method that is being validated + * @return A list of exceptions detected + * + * @since 4.12 + */ + @Override + public List validateAnnotatedMethod(FrameworkMethod method) { + List errors = new ArrayList(); + Annotation[] annotations = method.getAnnotations(); + for (Annotation annotation : annotations) { + for (Class clazz : INCOMPATIBLE_ANNOTATIONS) { + if (annotation.annotationType().isAssignableFrom(clazz)) { + addErrorMessage(errors, clazz); + } + } + } + return unmodifiableList(errors); + } + + private void addErrorMessage(List errors, Class clazz) { + String message = String.format("@%s can not be combined with @Category", + clazz.getSimpleName()); + errors.add(new Exception(message)); + } +} diff --git a/src/main/java/org/junit/experimental/categories/ExcludeCategories.java b/src/main/java/org/junit/experimental/categories/ExcludeCategories.java new file mode 100644 index 000000000000..8ccb6b5eec04 --- /dev/null +++ b/src/main/java/org/junit/experimental/categories/ExcludeCategories.java @@ -0,0 +1,52 @@ +package org.junit.experimental.categories; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.junit.experimental.categories.Categories.CategoryFilter; +import org.junit.runner.manipulation.Filter; + +/** + * {@link org.junit.runner.FilterFactory} to exclude categories. + * + * The {@link Filter} that is created will filter out tests that are categorized with any of the + * given categories. + * + * Usage from command line: + * + * --filter=org.junit.experimental.categories.ExcludeCategories=pkg.of.Cat1,pkg.of.Cat2 + * + * + * Usage from API: + * + * new ExcludeCategories().createFilter(Cat1.class, Cat2.class); + * + */ +public final class ExcludeCategories extends CategoryFilterFactory { + /** + * Creates a {@link Filter} which is only passed by tests that are + * not categorized with any of the specified categories. + * + * @param categories Category classes. + */ + @Override + protected Filter createFilter(List> categories) { + return new ExcludesAny(categories); + } + + private static class ExcludesAny extends CategoryFilter { + public ExcludesAny(List> categories) { + this(new HashSet>(categories)); + } + + public ExcludesAny(Set> categories) { + super(true, null, true, categories); + } + + @Override + public String describe() { + return "excludes " + super.describe(); + } + } +} diff --git a/src/main/java/org/junit/experimental/categories/IncludeCategories.java b/src/main/java/org/junit/experimental/categories/IncludeCategories.java new file mode 100644 index 000000000000..38eb6934c812 --- /dev/null +++ b/src/main/java/org/junit/experimental/categories/IncludeCategories.java @@ -0,0 +1,52 @@ +package org.junit.experimental.categories; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.junit.experimental.categories.Categories.CategoryFilter; +import org.junit.runner.manipulation.Filter; + +/** + * {@link org.junit.runner.FilterFactory} to include categories. + * + * The {@link Filter} that is created will filter out tests that are categorized with any of the + * given categories. + * + * Usage from command line: + * + * --filter=org.junit.experimental.categories.IncludeCategories=pkg.of.Cat1,pkg.of.Cat2 + * + * + * Usage from API: + * + * new IncludeCategories().createFilter(Cat1.class, Cat2.class); + * + */ +public final class IncludeCategories extends CategoryFilterFactory { + /** + * Creates a {@link Filter} which is only passed by tests that are + * categorized with any of the specified categories. + * + * @param categories Category classes. + */ + @Override + protected Filter createFilter(List> categories) { + return new IncludesAny(categories); + } + + private static class IncludesAny extends CategoryFilter { + public IncludesAny(List> categories) { + this(new HashSet>(categories)); + } + + public IncludesAny(Set> categories) { + super(true, categories, true, null); + } + + @Override + public String describe() { + return "includes " + super.describe(); + } + } +} diff --git a/src/main/java/org/junit/experimental/max/CouldNotReadCoreException.java b/src/main/java/org/junit/experimental/max/CouldNotReadCoreException.java new file mode 100644 index 000000000000..116d7559d049 --- /dev/null +++ b/src/main/java/org/junit/experimental/max/CouldNotReadCoreException.java @@ -0,0 +1,15 @@ +package org.junit.experimental.max; + +/** + * Thrown when Max cannot read the MaxCore serialization + */ +public class CouldNotReadCoreException extends Exception { + private static final long serialVersionUID = 1L; + + /** + * Constructs + */ + public CouldNotReadCoreException(Throwable e) { + super(e); + } +} diff --git a/src/main/java/org/junit/experimental/max/MaxCore.java b/src/main/java/org/junit/experimental/max/MaxCore.java new file mode 100644 index 000000000000..625cade5b1ea --- /dev/null +++ b/src/main/java/org/junit/experimental/max/MaxCore.java @@ -0,0 +1,181 @@ +package org.junit.experimental.max; + +import java.io.File; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import junit.framework.TestSuite; +import org.junit.internal.requests.SortingRequest; +import org.junit.internal.runners.ErrorReportingRunner; +import org.junit.internal.runners.JUnit38ClassRunner; +import org.junit.runner.Description; +import org.junit.runner.JUnitCore; +import org.junit.runner.Request; +import org.junit.runner.Result; +import org.junit.runner.Runner; +import org.junit.runners.Suite; +import org.junit.runners.model.InitializationError; + +/** + * A replacement for JUnitCore, which keeps track of runtime and failure history, and reorders tests + * to maximize the chances that a failing test occurs early in the test run. + * + * The rules for sorting are: + *
      + *
    1. Never-run tests first, in arbitrary order + *
    2. Group remaining tests by the date at which they most recently failed. + *
    3. Sort groups such that the most recent failure date is first, and never-failing tests are at the end. + *
    4. Within a group, run the fastest tests first. + *
    + */ +public class MaxCore { + private static final String MALFORMED_JUNIT_3_TEST_CLASS_PREFIX = "malformed JUnit 3 test class: "; + + /** + * Create a new MaxCore from a serialized file stored at storedResults + * + * @deprecated use storedLocally() + */ + @Deprecated + public static MaxCore forFolder(String folderName) { + return storedLocally(new File(folderName)); + } + + /** + * Create a new MaxCore from a serialized file stored at storedResults + */ + public static MaxCore storedLocally(File storedResults) { + return new MaxCore(storedResults); + } + + private final MaxHistory history; + + private MaxCore(File storedResults) { + history = MaxHistory.forFolder(storedResults); + } + + /** + * Run all the tests in class. + * + * @return a {@link Result} describing the details of the test run and the failed tests. + */ + public Result run(Class testClass) { + return run(Request.aClass(testClass)); + } + + /** + * Run all the tests contained in request. + * + * @param request the request describing tests + * @return a {@link Result} describing the details of the test run and the failed tests. + */ + public Result run(Request request) { + return run(request, new JUnitCore()); + } + + /** + * Run all the tests contained in request. + * + * This variant should be used if {@code core} has attached listeners that this + * run should notify. + * + * @param request the request describing tests + * @param core a JUnitCore to delegate to. + * @return a {@link Result} describing the details of the test run and the failed tests. + */ + public Result run(Request request, JUnitCore core) { + core.addListener(history.listener()); + return core.run(sortRequest(request).getRunner()); + } + + /** + * @return a new Request, which contains all of the same tests, but in a new order. + */ + public Request sortRequest(Request request) { + if (request instanceof SortingRequest) { + // We'll pay big karma points for this + return request; + } + List leaves = findLeaves(request); + Collections.sort(leaves, history.testComparator()); + return constructLeafRequest(leaves); + } + + private Request constructLeafRequest(List leaves) { + final List runners = new ArrayList(); + for (Description each : leaves) { + runners.add(buildRunner(each)); + } + return new Request() { + @Override + public Runner getRunner() { + try { + return new Suite((Class) null, runners) { + }; + } catch (InitializationError e) { + return new ErrorReportingRunner(null, e); + } + } + }; + } + + private Runner buildRunner(Description each) { + if (each.toString().equals("TestSuite with 0 tests")) { + return Suite.emptySuite(); + } + if (each.toString().startsWith(MALFORMED_JUNIT_3_TEST_CLASS_PREFIX)) { + // This is cheating, because it runs the whole class + // to get the warning for this method, but we can't do better, + // because JUnit 3.8's + // thrown away which method the warning is for. + return new JUnit38ClassRunner(new TestSuite(getMalformedTestClass(each))); + } + Class type = each.getTestClass(); + if (type == null) { + throw new RuntimeException("Can't build a runner from description [" + each + "]"); + } + String methodName = each.getMethodName(); + if (methodName == null) { + return Request.aClass(type).getRunner(); + } + return Request.method(type, methodName).getRunner(); + } + + private Class getMalformedTestClass(Description each) { + try { + return Class.forName(each.toString().replace(MALFORMED_JUNIT_3_TEST_CLASS_PREFIX, "")); + } catch (ClassNotFoundException e) { + return null; + } + } + + /** + * @param request a request to run + * @return a list of method-level tests to run, sorted in the order + * specified in the class comment. + */ + public List sortedLeavesForTest(Request request) { + return findLeaves(sortRequest(request)); + } + + private List findLeaves(Request request) { + List results = new ArrayList(); + findLeaves(null, request.getRunner().getDescription(), results); + return results; + } + + private void findLeaves(Description parent, Description description, List results) { + if (description.getChildren().isEmpty()) { + if (description.toString().equals("warning(junit.framework.TestSuite$1)")) { + results.add(Description.createSuiteDescription(MALFORMED_JUNIT_3_TEST_CLASS_PREFIX + parent)); + } else { + results.add(description); + } + } else { + for (Description each : description.getChildren()) { + findLeaves(description, each, results); + } + } + } +} \ No newline at end of file diff --git a/src/main/java/org/junit/experimental/max/MaxHistory.java b/src/main/java/org/junit/experimental/max/MaxHistory.java new file mode 100644 index 000000000000..ab7443f38535 --- /dev/null +++ b/src/main/java/org/junit/experimental/max/MaxHistory.java @@ -0,0 +1,178 @@ +package org.junit.experimental.max; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.util.Comparator; +import java.util.HashMap; +import java.util.Map; + +import org.junit.runner.Description; +import org.junit.runner.Result; +import org.junit.runner.notification.Failure; +import org.junit.runner.notification.RunListener; + +/** + * Stores a subset of the history of each test: + *
      + *
    • Last failure timestamp + *
    • Duration of last execution + *
    + */ +public class MaxHistory implements Serializable { + private static final long serialVersionUID = 1L; + + /** + * Loads a {@link MaxHistory} from {@code file}, or generates a new one that + * will be saved to {@code file}. + */ + public static MaxHistory forFolder(File file) { + if (file.exists()) { + try { + return readHistory(file); + } catch (CouldNotReadCoreException e) { + e.printStackTrace(); + file.delete(); + } + } + return new MaxHistory(file); + } + + private static MaxHistory readHistory(File storedResults) + throws CouldNotReadCoreException { + try { + FileInputStream file = new FileInputStream(storedResults); + try { + ObjectInputStream stream = new ObjectInputStream(file); + try { + return (MaxHistory) stream.readObject(); + } finally { + stream.close(); + } + } finally { + file.close(); + } + } catch (Exception e) { + throw new CouldNotReadCoreException(e); + } + } + + /* + * We have to use the f prefix until the next major release to ensure + * serialization compatibility. + * See https://github.com/junit-team/junit4/issues/976 + */ + private final Map fDurations = new HashMap(); + private final Map fFailureTimestamps = new HashMap(); + private final File fHistoryStore; + + private MaxHistory(File storedResults) { + fHistoryStore = storedResults; + } + + private void save() throws IOException { + ObjectOutputStream stream = null; + try { + stream = new ObjectOutputStream(new FileOutputStream(fHistoryStore)); + stream.writeObject(this); + } finally { + if (stream != null) { + stream.close(); + } + } + } + + Long getFailureTimestamp(Description key) { + return fFailureTimestamps.get(key.toString()); + } + + void putTestFailureTimestamp(Description key, long end) { + fFailureTimestamps.put(key.toString(), end); + } + + boolean isNewTest(Description key) { + return !fDurations.containsKey(key.toString()); + } + + Long getTestDuration(Description key) { + return fDurations.get(key.toString()); + } + + void putTestDuration(Description description, long duration) { + fDurations.put(description.toString(), duration); + } + + private final class RememberingListener extends RunListener { + private long overallStart = System.currentTimeMillis(); + + private Map starts = new HashMap(); + + @Override + public void testStarted(Description description) throws Exception { + starts.put(description, System.nanoTime()); // Get most accurate + // possible time + } + + @Override + public void testFinished(Description description) throws Exception { + long end = System.nanoTime(); + long start = starts.get(description); + putTestDuration(description, end - start); + } + + @Override + public void testFailure(Failure failure) throws Exception { + putTestFailureTimestamp(failure.getDescription(), overallStart); + } + + @Override + public void testRunFinished(Result result) throws Exception { + save(); + } + } + + private class TestComparator implements Comparator { + public int compare(Description o1, Description o2) { + // Always prefer new tests + if (isNewTest(o1)) { + return -1; + } + if (isNewTest(o2)) { + return 1; + } + // Then most recently failed first + int result = getFailure(o2).compareTo(getFailure(o1)); + return result != 0 ? result + // Then shorter tests first + : getTestDuration(o1).compareTo(getTestDuration(o2)); + } + + private Long getFailure(Description key) { + Long result = getFailureTimestamp(key); + if (result == null) { + return 0L; // 0 = "never failed (that I know about)" + } + return result; + } + } + + /** + * @return a listener that will update this history based on the test + * results reported. + */ + public RunListener listener() { + return new RememberingListener(); + } + + /** + * @return a comparator that ranks tests based on the JUnit Max sorting + * rules, as described in the {@link MaxCore} class comment. + */ + public Comparator testComparator() { + return new TestComparator(); + } +} diff --git a/src/main/java/org/junit/experimental/results/FailureList.java b/src/main/java/org/junit/experimental/results/FailureList.java new file mode 100644 index 000000000000..e02eeae6a439 --- /dev/null +++ b/src/main/java/org/junit/experimental/results/FailureList.java @@ -0,0 +1,28 @@ +package org.junit.experimental.results; + +import java.util.List; + +import org.junit.runner.Result; +import org.junit.runner.notification.Failure; +import org.junit.runner.notification.RunListener; + +class FailureList { + private final List failures; + + public FailureList(List failures) { + this.failures = failures; + } + + public Result result() { + Result result = new Result(); + RunListener listener = result.createListener(); + for (Failure failure : failures) { + try { + listener.testFailure(failure); + } catch (Exception e) { + throw new RuntimeException("I can't believe this happened"); + } + } + return result; + } +} \ No newline at end of file diff --git a/src/main/java/org/junit/experimental/results/PrintableResult.java b/src/main/java/org/junit/experimental/results/PrintableResult.java new file mode 100644 index 000000000000..0f67766f9141 --- /dev/null +++ b/src/main/java/org/junit/experimental/results/PrintableResult.java @@ -0,0 +1,72 @@ +package org.junit.experimental.results; + +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; +import java.util.List; + +import org.junit.internal.TextListener; +import org.junit.runner.JUnitCore; +import org.junit.runner.Request; +import org.junit.runner.Result; +import org.junit.runner.notification.Failure; + +/** + * A test result that prints nicely in error messages. + * This is only intended to be used in JUnit self-tests. + * For example: + * + *
    + *    assertThat(testResult(HasExpectedException.class), isSuccessful());
    + * 
    + */ +public class PrintableResult { + private Result result; + + /** + * The result of running JUnit on {@code type} + */ + public static PrintableResult testResult(Class type) { + return testResult(Request.aClass(type)); + } + + /** + * The result of running JUnit on Request {@code request} + */ + public static PrintableResult testResult(Request request) { + return new PrintableResult(new JUnitCore().run(request)); + } + + /** + * A result that includes the given {@code failures} + */ + public PrintableResult(List failures) { + this(new FailureList(failures).result()); + } + + private PrintableResult(Result result) { + this.result = result; + } + + /** + * Returns the number of failures in this result. + */ + public int failureCount() { + return result.getFailures().size(); + } + + /** + * Returns the failures in this result. + * + * @since 4.13 + */ + public List failures() { + return result.getFailures(); + } + + @Override + public String toString() { + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + new TextListener(new PrintStream(stream)).testRunFinished(result); + return stream.toString(); + } +} \ No newline at end of file diff --git a/src/main/java/org/junit/experimental/results/ResultMatchers.java b/src/main/java/org/junit/experimental/results/ResultMatchers.java new file mode 100644 index 000000000000..e111093150c1 --- /dev/null +++ b/src/main/java/org/junit/experimental/results/ResultMatchers.java @@ -0,0 +1,100 @@ +package org.junit.experimental.results; + +import org.hamcrest.BaseMatcher; +import org.hamcrest.Description; +import org.hamcrest.Matcher; +import org.hamcrest.TypeSafeMatcher; +import org.junit.runner.notification.Failure; + +/** + * Matchers on a PrintableResult, to enable JUnit self-tests. + * For example: + * + *
    + * assertThat(testResult(HasExpectedException.class), isSuccessful());
    + * 
    + */ +public class ResultMatchers { + + /** + * Do not instantiate. + * @deprecated will be private soon. + */ + @Deprecated + public ResultMatchers() { + } + + /** + * Matches if the tests are all successful + */ + public static Matcher isSuccessful() { + return failureCountIs(0); + } + + /** + * Matches if there are {@code count} failures + */ + public static Matcher failureCountIs(final int count) { + return new TypeSafeMatcher() { + public void describeTo(Description description) { + description.appendText("has " + count + " failures"); + } + + @Override + public boolean matchesSafely(PrintableResult item) { + return item.failureCount() == count; + } + }; + } + + /** + * Matches if the result has exactly one failure, and it contains {@code string} + */ + public static Matcher hasSingleFailureContaining(final String string) { + return new BaseMatcher() { + public boolean matches(Object item) { + return item.toString().contains(string) && failureCountIs(1).matches(item); + } + + public void describeTo(Description description) { + description.appendText("has single failure containing " + string); + } + }; + } + + /** + * Matches if the result has exactly one failure matching the given matcher. + * + * @since 4.13 + */ + public static Matcher hasSingleFailureMatching(final Matcher matcher) { + return new TypeSafeMatcher() { + @Override + public boolean matchesSafely(PrintableResult item) { + return item.failureCount() == 1 && matcher.matches(item.failures().get(0).getException()); + } + + public void describeTo(Description description) { + description.appendText("has failure with exception matching "); + matcher.describeTo(description); + } + }; + } + + /** + * Matches if the result has one or more failures, and at least one of them + * contains {@code string} + */ + public static Matcher hasFailureContaining(final String string) { + return new TypeSafeMatcher() { + @Override + public boolean matchesSafely(PrintableResult item) { + return item.failureCount() > 0 && item.toString().contains(string); + } + + public void describeTo(Description description) { + description.appendText("has failure containing " + string); + } + }; + } +} diff --git a/src/main/java/org/junit/experimental/runners/Enclosed.java b/src/main/java/org/junit/experimental/runners/Enclosed.java new file mode 100644 index 000000000000..610b97066897 --- /dev/null +++ b/src/main/java/org/junit/experimental/runners/Enclosed.java @@ -0,0 +1,45 @@ +package org.junit.experimental.runners; + +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.List; + +import org.junit.runners.Suite; +import org.junit.runners.model.RunnerBuilder; + +/** + * If you put tests in inner classes, Ant, for example, won't find them. By running the outer class + * with Enclosed, the tests in the inner classes will be run. You might put tests in inner classes + * to group them for convenience or to share constants. Abstract inner classes are ignored. + *

    + * So, for example: + *

    + * @RunWith(Enclosed.class)
    + * public class ListTests {
    + *     ...useful shared stuff...
    + *     public static class OneKindOfListTest {...}
    + *     public static class AnotherKind {...}
    + *     abstract public static class Ignored {...}
    + * }
    + * 
    + */ +public class Enclosed extends Suite { + /** + * Only called reflectively. Do not use programmatically. + */ + public Enclosed(Class klass, RunnerBuilder builder) throws Throwable { + super(builder, klass, filterAbstractClasses(klass.getClasses())); + } + + private static Class[] filterAbstractClasses(final Class[] classes) { + final List> filteredList= new ArrayList>(classes.length); + + for (final Class clazz : classes) { + if (!Modifier.isAbstract(clazz.getModifiers())) { + filteredList.add(clazz); + } + } + + return filteredList.toArray(new Class[filteredList.size()]); + } +} diff --git a/src/main/java/org/junit/experimental/theories/DataPoint.java b/src/main/java/org/junit/experimental/theories/DataPoint.java new file mode 100644 index 000000000000..0a017bb5631e --- /dev/null +++ b/src/main/java/org/junit/experimental/theories/DataPoint.java @@ -0,0 +1,56 @@ +package org.junit.experimental.theories; + +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.ElementType.METHOD; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Annotating an field or method with @DataPoint will cause the field value + * or the value returned by the method to be used as a potential parameter for + * theories in that class, when run with the + * {@link org.junit.experimental.theories.Theories Theories} runner. + *

    + * A DataPoint is only considered as a potential value for parameters for + * which its type is assignable. When multiple {@code DataPoint}s exist + * with overlapping types more control can be obtained by naming each DataPoint + * using the value of this annotation, e.g. with + * @DataPoint({"dataset1", "dataset2"}), and then specifying + * which named set to consider as potential values for each parameter using the + * {@link org.junit.experimental.theories.FromDataPoints @FromDataPoints} + * annotation. + *

    + * Parameters with no specified source (i.e. without @FromDataPoints or + * other {@link org.junit.experimental.theories.ParametersSuppliedBy + * @ParameterSuppliedBy} annotations) will use all {@code DataPoint}s that are + * assignable to the parameter type as potential values, including named sets of + * {@code DataPoint}s. + * + *

    + * @DataPoint
    + * public static String dataPoint = "value";
    + * 
    + * @DataPoint("generated")
    + * public static String generatedDataPoint() {
    + *     return "generated value";
    + * }
    + * 
    + * @Theory
    + * public void theoryMethod(String param) {
    + *     ...
    + * }
    + * 
    + * + * @see org.junit.experimental.theories.Theories + * @see org.junit.experimental.theories.Theory + * @see org.junit.experimental.theories.DataPoint + * @see org.junit.experimental.theories.FromDataPoints + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({FIELD, METHOD}) +public @interface DataPoint { + String[] value() default {}; + Class[] ignoredExceptions() default {}; +} \ No newline at end of file diff --git a/src/main/java/org/junit/experimental/theories/DataPoints.java b/src/main/java/org/junit/experimental/theories/DataPoints.java new file mode 100644 index 000000000000..b47461b388cd --- /dev/null +++ b/src/main/java/org/junit/experimental/theories/DataPoints.java @@ -0,0 +1,64 @@ +package org.junit.experimental.theories; + +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.ElementType.METHOD; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Annotating an array or iterable-typed field or method with @DataPoints + * will cause the values in the array or iterable given to be used as potential + * parameters for theories in that class when run with the + * {@link org.junit.experimental.theories.Theories Theories} runner. + *

    + * DataPoints will only be considered as potential values for parameters for + * which their types are assignable. When multiple sets of DataPoints exist with + * overlapping types more control can be obtained by naming the DataPoints using + * the value of this annotation, e.g. with + * @DataPoints({"dataset1", "dataset2"}), and then specifying + * which named set to consider as potential values for each parameter using the + * {@link org.junit.experimental.theories.FromDataPoints @FromDataPoints} + * annotation. + *

    + * Parameters with no specified source (i.e. without @FromDataPoints or + * other {@link org.junit.experimental.theories.ParametersSuppliedBy + * @ParameterSuppliedBy} annotations) will use all DataPoints that are + * assignable to the parameter type as potential values, including named sets of + * DataPoints. + *

    + * DataPoints methods whose array types aren't assignable from the target + * parameter type (and so can't possibly return relevant values) will not be + * called when generating values for that parameter. Iterable-typed datapoints + * methods must always be called though, as this information is not available + * here after generic type erasure, so expensive methods returning iterable + * datapoints are a bad idea. + * + *

    + * @DataPoints
    + * public static String[] dataPoints = new String[] { ... };
    + * 
    + * @DataPoints
    + * public static String[] generatedDataPoints() {
    + *     return new String[] { ... };
    + * }
    + * 
    + * @Theory
    + * public void theoryMethod(String param) {
    + *     ...
    + * }
    + * 
    + * + * @see org.junit.experimental.theories.Theories + * @see org.junit.experimental.theories.Theory + * @see org.junit.experimental.theories.DataPoint + * @see org.junit.experimental.theories.FromDataPoints + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ FIELD, METHOD }) +public @interface DataPoints { + String[] value() default {}; + + Class[] ignoredExceptions() default {}; +} diff --git a/src/main/java/org/junit/experimental/theories/FromDataPoints.java b/src/main/java/org/junit/experimental/theories/FromDataPoints.java new file mode 100644 index 000000000000..2b149cae9cf1 --- /dev/null +++ b/src/main/java/org/junit/experimental/theories/FromDataPoints.java @@ -0,0 +1,54 @@ +package org.junit.experimental.theories; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.junit.experimental.theories.internal.SpecificDataPointsSupplier; + +/** + * Annotating a parameter of a {@link org.junit.experimental.theories.Theory + * @Theory} method with @FromDataPoints will limit the + * datapoints considered as potential values for that parameter to just the + * {@link org.junit.experimental.theories.DataPoints DataPoints} with the given + * name. DataPoint names can be given as the value parameter of the + * @DataPoints annotation. + *

    + * DataPoints without names will not be considered as values for any parameters + * annotated with @FromDataPoints. + *

    + * @DataPoints
    + * public static String[] unnamed = new String[] { ... };
    + * 
    + * @DataPoints("regexes")
    + * public static String[] regexStrings = new String[] { ... };
    + * 
    + * @DataPoints({"forMatching", "alphanumeric"})
    + * public static String[] testStrings = new String[] { ... }; 
    + * 
    + * @Theory
    + * public void stringTheory(String param) {
    + *     // This will be called with every value in 'regexStrings',
    + *     // 'testStrings' and 'unnamed'.
    + * }
    + * 
    + * @Theory
    + * public void regexTheory(@FromDataPoints("regexes") String regex,
    + *                         @FromDataPoints("forMatching") String value) {
    + *     // This will be called with only the values in 'regexStrings' as 
    + *     // regex, only the values in 'testStrings' as value, and none 
    + *     // of the values in 'unnamed'.
    + * }
    + * 
    + * + * @see org.junit.experimental.theories.Theory + * @see org.junit.experimental.theories.DataPoint + * @see org.junit.experimental.theories.DataPoints + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.PARAMETER) +@ParametersSuppliedBy(SpecificDataPointsSupplier.class) +public @interface FromDataPoints { + String value(); +} diff --git a/src/main/java/org/junit/experimental/theories/ParameterSignature.java b/src/main/java/org/junit/experimental/theories/ParameterSignature.java new file mode 100644 index 000000000000..cf225835e5b4 --- /dev/null +++ b/src/main/java/org/junit/experimental/theories/ParameterSignature.java @@ -0,0 +1,134 @@ +package org.junit.experimental.theories; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class ParameterSignature { + + private static final Map, Class> CONVERTABLE_TYPES_MAP = buildConvertableTypesMap(); + + private static Map, Class> buildConvertableTypesMap() { + Map, Class> map = new HashMap, Class>(); + + putSymmetrically(map, boolean.class, Boolean.class); + putSymmetrically(map, byte.class, Byte.class); + putSymmetrically(map, short.class, Short.class); + putSymmetrically(map, char.class, Character.class); + putSymmetrically(map, int.class, Integer.class); + putSymmetrically(map, long.class, Long.class); + putSymmetrically(map, float.class, Float.class); + putSymmetrically(map, double.class, Double.class); + + return Collections.unmodifiableMap(map); + } + + private static void putSymmetrically(Map map, T a, T b) { + map.put(a, b); + map.put(b, a); + } + + public static ArrayList signatures(Method method) { + return signatures(method.getParameterTypes(), method + .getParameterAnnotations()); + } + + public static List signatures(Constructor constructor) { + return signatures(constructor.getParameterTypes(), constructor + .getParameterAnnotations()); + } + + private static ArrayList signatures( + Class[] parameterTypes, Annotation[][] parameterAnnotations) { + ArrayList sigs = new ArrayList(); + for (int i = 0; i < parameterTypes.length; i++) { + sigs.add(new ParameterSignature(parameterTypes[i], + parameterAnnotations[i])); + } + return sigs; + } + + private final Class type; + + private final Annotation[] annotations; + + private ParameterSignature(Class type, Annotation[] annotations) { + this.type = type; + this.annotations = annotations; + } + + public boolean canAcceptValue(Object candidate) { + return (candidate == null) ? !type.isPrimitive() : canAcceptType(candidate.getClass()); + } + + public boolean canAcceptType(Class candidate) { + return type.isAssignableFrom(candidate) || + isAssignableViaTypeConversion(type, candidate); + } + + public boolean canPotentiallyAcceptType(Class candidate) { + return candidate.isAssignableFrom(type) || + isAssignableViaTypeConversion(candidate, type) || + canAcceptType(candidate); + } + + private boolean isAssignableViaTypeConversion(Class targetType, Class candidate) { + if (CONVERTABLE_TYPES_MAP.containsKey(candidate)) { + Class wrapperClass = CONVERTABLE_TYPES_MAP.get(candidate); + return targetType.isAssignableFrom(wrapperClass); + } else { + return false; + } + } + + public Class getType() { + return type; + } + + public List getAnnotations() { + return Arrays.asList(annotations); + } + + public boolean hasAnnotation(Class type) { + return getAnnotation(type) != null; + } + + public T findDeepAnnotation(Class annotationType) { + Annotation[] annotations2 = annotations; + return findDeepAnnotation(annotations2, annotationType, 3); + } + + private T findDeepAnnotation( + Annotation[] annotations, Class annotationType, int depth) { + if (depth == 0) { + return null; + } + for (Annotation each : annotations) { + if (annotationType.isInstance(each)) { + return annotationType.cast(each); + } + Annotation candidate = findDeepAnnotation(each.annotationType() + .getAnnotations(), annotationType, depth - 1); + if (candidate != null) { + return annotationType.cast(candidate); + } + } + + return null; + } + + public T getAnnotation(Class annotationType) { + for (Annotation each : getAnnotations()) { + if (annotationType.isInstance(each)) { + return annotationType.cast(each); + } + } + return null; + } +} \ No newline at end of file diff --git a/src/main/java/org/junit/experimental/theories/ParameterSupplier.java b/src/main/java/org/junit/experimental/theories/ParameterSupplier.java new file mode 100644 index 000000000000..bac8b34282e2 --- /dev/null +++ b/src/main/java/org/junit/experimental/theories/ParameterSupplier.java @@ -0,0 +1,43 @@ +package org.junit.experimental.theories; + +import java.util.List; + +/** + * Abstract parent class for suppliers of input data points for theories. Extend this class to customize how {@link + * org.junit.experimental.theories.Theories Theories} runner + * finds accepted data points. Then use your class together with @ParametersSuppliedBy on input + * parameters for theories. + * + *

    + * For example, here is a supplier for values between two integers, and an annotation that references it: + * + *

    + *     @Retention(RetentionPolicy.RUNTIME)
    + *     @ParametersSuppliedBy(BetweenSupplier.class)
    + *     public @interface Between {
    + *         int first();
    + *
    + *         int last();
    + *     }
    + *
    + *     public static class BetweenSupplier extends ParameterSupplier {
    + *         @Override
    + *         public List<PotentialAssignment> getValueSources(ParameterSignature sig) {
    + *             List<PotentialAssignment> list = new ArrayList<PotentialAssignment>();
    + *             Between annotation = (Between) sig.getSupplierAnnotation();
    + *
    + *             for (int i = annotation.first(); i <= annotation.last(); i++)
    + *                 list.add(PotentialAssignment.forValue("ints", i));
    + *             return list;
    + *         }
    + *     }
    + * 
    + *

    + * + * @see org.junit.experimental.theories.ParametersSuppliedBy + * @see org.junit.experimental.theories.Theories + * @see org.junit.experimental.theories.FromDataPoints + */ +public abstract class ParameterSupplier { + public abstract List getValueSources(ParameterSignature sig) throws Throwable; +} diff --git a/src/main/java/org/junit/experimental/theories/ParametersSuppliedBy.java b/src/main/java/org/junit/experimental/theories/ParametersSuppliedBy.java new file mode 100644 index 000000000000..846a39e46339 --- /dev/null +++ b/src/main/java/org/junit/experimental/theories/ParametersSuppliedBy.java @@ -0,0 +1,48 @@ +package org.junit.experimental.theories; + +import static java.lang.annotation.ElementType.ANNOTATION_TYPE; +import static java.lang.annotation.ElementType.PARAMETER; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Annotating a {@link org.junit.experimental.theories.Theory Theory} method + * parameter with @ParametersSuppliedBy causes it to be supplied with + * values from the named + * {@link org.junit.experimental.theories.ParameterSupplier ParameterSupplier} + * when run as a theory by the {@link org.junit.experimental.theories.Theories + * Theories} runner. + * + * In addition, annotations themselves can be annotated with + * @ParametersSuppliedBy, and then used similarly. ParameterSuppliedBy + * annotations on parameters are detected by searching up this hierarchy such + * that these act as syntactic sugar, making: + * + *
    + * @ParametersSuppliedBy(Supplier.class)
    + * public @interface SpecialParameter { }
    + * 
    + * @Theory
    + * public void theoryMethod(@SpecialParameter String param) {
    + *   ...
    + * }
    + * 
    + * + * equivalent to: + * + *
    + * @Theory
    + * public void theoryMethod(@ParametersSuppliedBy(Supplier.class) String param) {
    + *   ...
    + * }
    + * 
    + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ ANNOTATION_TYPE, PARAMETER }) +public @interface ParametersSuppliedBy { + + Class value(); + +} diff --git a/src/main/java/org/junit/experimental/theories/PotentialAssignment.java b/src/main/java/org/junit/experimental/theories/PotentialAssignment.java new file mode 100644 index 000000000000..18ca07a4044d --- /dev/null +++ b/src/main/java/org/junit/experimental/theories/PotentialAssignment.java @@ -0,0 +1,52 @@ +package org.junit.experimental.theories; + +import static java.lang.String.format; + +public abstract class PotentialAssignment { + public static class CouldNotGenerateValueException extends Exception { + private static final long serialVersionUID = 1L; + + public CouldNotGenerateValueException() { + } + + public CouldNotGenerateValueException(Throwable e) { + super(e); + } + } + + public static PotentialAssignment forValue(final String name, final Object value) { + return new PotentialAssignment() { + @Override + public Object getValue() { + return value; + } + + @Override + public String toString() { + return format("[%s]", value); + } + + @Override + public String getDescription() { + String valueString; + + if (value == null) { + valueString = "null"; + } else { + try { + valueString = format("\"%s\"", value); + } catch (Throwable e) { + valueString = format("[toString() threw %s: %s]", + e.getClass().getSimpleName(), e.getMessage()); + } + } + + return format("%s ", valueString, name); + } + }; + } + + public abstract Object getValue() throws CouldNotGenerateValueException; + + public abstract String getDescription() throws CouldNotGenerateValueException; +} \ No newline at end of file diff --git a/src/main/java/org/junit/experimental/theories/Theories.java b/src/main/java/org/junit/experimental/theories/Theories.java new file mode 100644 index 000000000000..ac88a364a670 --- /dev/null +++ b/src/main/java/org/junit/experimental/theories/Theories.java @@ -0,0 +1,310 @@ +package org.junit.experimental.theories; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.List; + +import org.junit.Assert; +import org.junit.Assume; +import org.junit.experimental.theories.internal.Assignments; +import org.junit.experimental.theories.internal.ParameterizedAssertionError; +import org.junit.internal.AssumptionViolatedException; +import org.junit.runners.BlockJUnit4ClassRunner; +import org.junit.runners.model.FrameworkMethod; +import org.junit.runners.model.InitializationError; +import org.junit.runners.model.Statement; +import org.junit.runners.model.TestClass; + +/** + * The Theories runner allows to test a certain functionality against a subset of an infinite set of data points. + *

    + * A Theory is a piece of functionality (a method) that is executed against several data inputs called data points. + * To make a test method a theory you mark it with @Theory. To create a data point you create a public + * field in your test class and mark it with @DataPoint. The Theories runner then executes your test + * method as many times as the number of data points declared, providing a different data point as + * the input argument on each invocation. + *

    + *

    + * A Theory differs from standard test method in that it captures some aspect of the intended behavior in possibly + * infinite numbers of scenarios which corresponds to the number of data points declared. Using assumptions and + * assertions properly together with covering multiple scenarios with different data points can make your tests more + * flexible and bring them closer to scientific theories (hence the name). + *

    + *

    + * For example: + *

    + *
    + * @RunWith(Theories.class)
    + * public class UserTest {
    + *      @DataPoint
    + *      public static String GOOD_USERNAME = "optimus";
    + *      @DataPoint
    + *      public static String USERNAME_WITH_SLASH = "optimus/prime";
    + *
    + *      @Theory
    + *      public void filenameIncludesUsername(String username) {
    + *          assumeThat(username, not(containsString("/")));
    + *          assertThat(new User(username).configFileName(), containsString(username));
    + *      }
    + * }
    + * 
    + * This makes it clear that the username should be included in the config file name, + * only if it doesn't contain a slash. Another test or theory might define what happens when a username does contain + * a slash. UserTest will attempt to run filenameIncludesUsername on every compatible data + * point defined in the class. If any of the assumptions fail, the data point is silently ignored. If all of the + * assumptions pass, but an assertion fails, the test fails. If no parameters can be found that satisfy all assumptions, the test fails. + *

    + * Defining general statements as theories allows data point reuse across a bunch of functionality tests and also + * allows automated tools to search for new, unexpected data points that expose bugs. + *

    + *

    + * The support for Theories has been absorbed from the Popper project, and more complete documentation can be found + * from that projects archived documentation. + *

    + * + * @see Archived Popper project documentation + * @see Paper on Theories + */ +public class Theories extends BlockJUnit4ClassRunner { + public Theories(Class klass) throws InitializationError { + super(klass); + } + + /** @since 4.13 */ + protected Theories(TestClass testClass) throws InitializationError { + super(testClass); + } + + @Override + protected void collectInitializationErrors(List errors) { + super.collectInitializationErrors(errors); + validateDataPointFields(errors); + validateDataPointMethods(errors); + } + + private void validateDataPointFields(List errors) { + Field[] fields = getTestClass().getJavaClass().getDeclaredFields(); + + for (Field field : fields) { + if (field.getAnnotation(DataPoint.class) == null && field.getAnnotation(DataPoints.class) == null) { + continue; + } + if (!Modifier.isStatic(field.getModifiers())) { + errors.add(new Error("DataPoint field " + field.getName() + " must be static")); + } + if (!Modifier.isPublic(field.getModifiers())) { + errors.add(new Error("DataPoint field " + field.getName() + " must be public")); + } + } + } + + private void validateDataPointMethods(List errors) { + Method[] methods = getTestClass().getJavaClass().getDeclaredMethods(); + + for (Method method : methods) { + if (method.getAnnotation(DataPoint.class) == null && method.getAnnotation(DataPoints.class) == null) { + continue; + } + if (!Modifier.isStatic(method.getModifiers())) { + errors.add(new Error("DataPoint method " + method.getName() + " must be static")); + } + if (!Modifier.isPublic(method.getModifiers())) { + errors.add(new Error("DataPoint method " + method.getName() + " must be public")); + } + } + } + + @Override + protected void validateConstructor(List errors) { + validateOnlyOneConstructor(errors); + } + + @Override + protected void validateTestMethods(List errors) { + for (FrameworkMethod each : computeTestMethods()) { + if (each.getAnnotation(Theory.class) != null) { + each.validatePublicVoid(false, errors); + each.validateNoTypeParametersOnArgs(errors); + } else { + each.validatePublicVoidNoArg(false, errors); + } + + for (ParameterSignature signature : ParameterSignature.signatures(each.getMethod())) { + ParametersSuppliedBy annotation = signature.findDeepAnnotation(ParametersSuppliedBy.class); + if (annotation != null) { + validateParameterSupplier(annotation.value(), errors); + } + } + } + } + + private void validateParameterSupplier(Class supplierClass, List errors) { + Constructor[] constructors = supplierClass.getConstructors(); + + if (constructors.length != 1) { + errors.add(new Error("ParameterSupplier " + supplierClass.getName() + + " must have only one constructor (either empty or taking only a TestClass)")); + } else { + Class[] paramTypes = constructors[0].getParameterTypes(); + if (!(paramTypes.length == 0) && !paramTypes[0].equals(TestClass.class)) { + errors.add(new Error("ParameterSupplier " + supplierClass.getName() + + " constructor must take either nothing or a single TestClass instance")); + } + } + } + + @Override + protected List computeTestMethods() { + List testMethods = new ArrayList(super.computeTestMethods()); + List theoryMethods = getTestClass().getAnnotatedMethods(Theory.class); + testMethods.removeAll(theoryMethods); + testMethods.addAll(theoryMethods); + return testMethods; + } + + @Override + public Statement methodBlock(final FrameworkMethod method) { + return new TheoryAnchor(method, getTestClass()); + } + + public static class TheoryAnchor extends Statement { + private int successes = 0; + + private final FrameworkMethod testMethod; + private final TestClass testClass; + + private List fInvalidParameters = new ArrayList(); + + public TheoryAnchor(FrameworkMethod testMethod, TestClass testClass) { + this.testMethod = testMethod; + this.testClass = testClass; + } + + private TestClass getTestClass() { + return testClass; + } + + @Override + public void evaluate() throws Throwable { + runWithAssignment(Assignments.allUnassigned( + testMethod.getMethod(), getTestClass())); + + //if this test method is not annotated with Theory, then no successes is a valid case + boolean hasTheoryAnnotation = testMethod.getAnnotation(Theory.class) != null; + if (successes == 0 && hasTheoryAnnotation) { + Assert + .fail("Never found parameters that satisfied method assumptions. Violated assumptions: " + + fInvalidParameters); + } + } + + protected void runWithAssignment(Assignments parameterAssignment) + throws Throwable { + if (!parameterAssignment.isComplete()) { + runWithIncompleteAssignment(parameterAssignment); + } else { + runWithCompleteAssignment(parameterAssignment); + } + } + + protected void runWithIncompleteAssignment(Assignments incomplete) + throws Throwable { + for (PotentialAssignment source : incomplete + .potentialsForNextUnassigned()) { + runWithAssignment(incomplete.assignNext(source)); + } + } + + protected void runWithCompleteAssignment(final Assignments complete) + throws Throwable { + new BlockJUnit4ClassRunner(getTestClass()) { + @Override + protected void collectInitializationErrors( + List errors) { + // do nothing + } + + @Override + public Statement methodBlock(FrameworkMethod method) { + final Statement statement = super.methodBlock(method); + return new Statement() { + @Override + public void evaluate() throws Throwable { + try { + statement.evaluate(); + handleDataPointSuccess(); + } catch (AssumptionViolatedException e) { + handleAssumptionViolation(e); + } catch (Throwable e) { + reportParameterizedError(e, complete + .getArgumentStrings(nullsOk())); + } + } + + }; + } + + @Override + protected Statement methodInvoker(FrameworkMethod method, Object test) { + return methodCompletesWithParameters(method, complete, test); + } + + @Override + public Object createTest() throws Exception { + Object[] params = complete.getConstructorArguments(); + + if (!nullsOk()) { + Assume.assumeNotNull(params); + } + + return getTestClass().getOnlyConstructor().newInstance(params); + } + }.methodBlock(testMethod).evaluate(); + } + + private Statement methodCompletesWithParameters( + final FrameworkMethod method, final Assignments complete, final Object freshInstance) { + return new Statement() { + @Override + public void evaluate() throws Throwable { + final Object[] values = complete.getMethodArguments(); + + if (!nullsOk()) { + Assume.assumeNotNull(values); + } + + method.invokeExplosively(freshInstance, values); + } + }; + } + + protected void handleAssumptionViolation(AssumptionViolatedException e) { + fInvalidParameters.add(e); + } + + protected void reportParameterizedError(Throwable e, Object... params) + throws Throwable { + if (params.length == 0) { + throw e; + } + throw new ParameterizedAssertionError(e, testMethod.getName(), + params); + } + + private boolean nullsOk() { + Theory annotation = testMethod.getMethod().getAnnotation( + Theory.class); + if (annotation == null) { + return false; + } + return annotation.nullsAccepted(); + } + + protected void handleDataPointSuccess() { + successes++; + } + } +} diff --git a/src/main/java/org/junit/experimental/theories/Theory.java b/src/main/java/org/junit/experimental/theories/Theory.java new file mode 100644 index 000000000000..0b9f2c4121fe --- /dev/null +++ b/src/main/java/org/junit/experimental/theories/Theory.java @@ -0,0 +1,18 @@ +package org.junit.experimental.theories; + +import static java.lang.annotation.ElementType.METHOD; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Marks test methods that should be read as theories by the {@link org.junit.experimental.theories.Theories Theories} runner. + * + * @see org.junit.experimental.theories.Theories + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(METHOD) +public @interface Theory { + boolean nullsAccepted() default true; +} \ No newline at end of file diff --git a/src/main/java/org/junit/experimental/theories/internal/AllMembersSupplier.java b/src/main/java/org/junit/experimental/theories/internal/AllMembersSupplier.java new file mode 100644 index 000000000000..f15fb288e4a6 --- /dev/null +++ b/src/main/java/org/junit/experimental/theories/internal/AllMembersSupplier.java @@ -0,0 +1,204 @@ +package org.junit.experimental.theories.internal; + +import java.lang.reflect.Array; +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; + +import org.junit.Assume; +import org.junit.experimental.theories.DataPoint; +import org.junit.experimental.theories.DataPoints; +import org.junit.experimental.theories.ParameterSignature; +import org.junit.experimental.theories.ParameterSupplier; +import org.junit.experimental.theories.PotentialAssignment; +import org.junit.runners.model.FrameworkField; +import org.junit.runners.model.FrameworkMethod; +import org.junit.runners.model.TestClass; + +/** + * Supplies Theory parameters based on all public members of the target class. + */ +public class AllMembersSupplier extends ParameterSupplier { + static class MethodParameterValue extends PotentialAssignment { + private final FrameworkMethod method; + + private MethodParameterValue(FrameworkMethod dataPointMethod) { + method = dataPointMethod; + } + + @Override + public Object getValue() throws CouldNotGenerateValueException { + try { + return method.invokeExplosively(null); + } catch (IllegalArgumentException e) { + throw new RuntimeException( + "unexpected: argument length is checked"); + } catch (IllegalAccessException e) { + throw new RuntimeException( + "unexpected: getMethods returned an inaccessible method"); + } catch (Throwable throwable) { + DataPoint annotation = method.getAnnotation(DataPoint.class); + Assume.assumeTrue(annotation == null || !isAssignableToAnyOf(annotation.ignoredExceptions(), throwable)); + + throw new CouldNotGenerateValueException(throwable); + } + } + + @Override + public String getDescription() throws CouldNotGenerateValueException { + return method.getName(); + } + } + + private final TestClass clazz; + + /** + * Constructs a new supplier for {@code type} + */ + public AllMembersSupplier(TestClass type) { + clazz = type; + } + + @Override + public List getValueSources(ParameterSignature sig) throws Throwable { + List list = new ArrayList(); + + addSinglePointFields(sig, list); + addMultiPointFields(sig, list); + addSinglePointMethods(sig, list); + addMultiPointMethods(sig, list); + + return list; + } + + private void addMultiPointMethods(ParameterSignature sig, List list) throws Throwable { + for (FrameworkMethod dataPointsMethod : getDataPointsMethods(sig)) { + Class returnType = dataPointsMethod.getReturnType(); + + if ((returnType.isArray() && sig.canPotentiallyAcceptType(returnType.getComponentType())) || + Iterable.class.isAssignableFrom(returnType)) { + try { + addDataPointsValues(returnType, sig, dataPointsMethod.getName(), list, + dataPointsMethod.invokeExplosively(null)); + } catch (Throwable throwable) { + DataPoints annotation = dataPointsMethod.getAnnotation(DataPoints.class); + if (annotation != null && isAssignableToAnyOf(annotation.ignoredExceptions(), throwable)) { + return; + } else { + throw throwable; + } + } + } + } + } + + private void addSinglePointMethods(ParameterSignature sig, List list) { + for (FrameworkMethod dataPointMethod : getSingleDataPointMethods(sig)) { + if (sig.canAcceptType(dataPointMethod.getType())) { + list.add(new MethodParameterValue(dataPointMethod)); + } + } + } + + private void addMultiPointFields(ParameterSignature sig, List list) { + for (final Field field : getDataPointsFields(sig)) { + Class type = field.getType(); + addDataPointsValues(type, sig, field.getName(), list, getStaticFieldValue(field)); + } + } + + private void addSinglePointFields(ParameterSignature sig, List list) { + for (final Field field : getSingleDataPointFields(sig)) { + Object value = getStaticFieldValue(field); + + if (sig.canAcceptValue(value)) { + list.add(PotentialAssignment.forValue(field.getName(), value)); + } + } + } + + private void addDataPointsValues(Class type, ParameterSignature sig, String name, + List list, Object value) { + if (type.isArray()) { + addArrayValues(sig, name, list, value); + } + else if (Iterable.class.isAssignableFrom(type)) { + addIterableValues(sig, name, list, (Iterable) value); + } + } + + private void addArrayValues(ParameterSignature sig, String name, List list, Object array) { + for (int i = 0; i < Array.getLength(array); i++) { + Object value = Array.get(array, i); + if (sig.canAcceptValue(value)) { + list.add(PotentialAssignment.forValue(name + "[" + i + "]", value)); + } + } + } + + private void addIterableValues(ParameterSignature sig, String name, List list, Iterable iterable) { + Iterator iterator = iterable.iterator(); + int i = 0; + while (iterator.hasNext()) { + Object value = iterator.next(); + if (sig.canAcceptValue(value)) { + list.add(PotentialAssignment.forValue(name + "[" + i + "]", value)); + } + i += 1; + } + } + + private Object getStaticFieldValue(final Field field) { + try { + return field.get(null); + } catch (IllegalArgumentException e) { + throw new RuntimeException( + "unexpected: field from getClass doesn't exist on object"); + } catch (IllegalAccessException e) { + throw new RuntimeException( + "unexpected: getFields returned an inaccessible field"); + } + } + + private static boolean isAssignableToAnyOf(Class[] typeArray, Object target) { + for (Class type : typeArray) { + if (type.isAssignableFrom(target.getClass())) { + return true; + } + } + return false; + } + + protected Collection getDataPointsMethods(ParameterSignature sig) { + return clazz.getAnnotatedMethods(DataPoints.class); + } + + protected Collection getSingleDataPointFields(ParameterSignature sig) { + List fields = clazz.getAnnotatedFields(DataPoint.class); + Collection validFields = new ArrayList(); + + for (FrameworkField frameworkField : fields) { + validFields.add(frameworkField.getField()); + } + + return validFields; + } + + protected Collection getDataPointsFields(ParameterSignature sig) { + List fields = clazz.getAnnotatedFields(DataPoints.class); + Collection validFields = new ArrayList(); + + for (FrameworkField frameworkField : fields) { + validFields.add(frameworkField.getField()); + } + + return validFields; + } + + protected Collection getSingleDataPointMethods(ParameterSignature sig) { + return clazz.getAnnotatedMethods(DataPoint.class); + } + +} \ No newline at end of file diff --git a/src/main/java/org/junit/experimental/theories/internal/Assignments.java b/src/main/java/org/junit/experimental/theories/internal/Assignments.java new file mode 100644 index 000000000000..6626797ef089 --- /dev/null +++ b/src/main/java/org/junit/experimental/theories/internal/Assignments.java @@ -0,0 +1,153 @@ +package org.junit.experimental.theories.internal; + +import static java.util.Collections.emptyList; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; + +import org.junit.experimental.theories.ParameterSignature; +import org.junit.experimental.theories.ParameterSupplier; +import org.junit.experimental.theories.ParametersSuppliedBy; +import org.junit.experimental.theories.PotentialAssignment; +import org.junit.experimental.theories.PotentialAssignment.CouldNotGenerateValueException; +import org.junit.runners.model.TestClass; + +/** + * A potentially incomplete list of value assignments for a method's formal + * parameters + */ +public class Assignments { + private final List assigned; + + private final List unassigned; + + private final TestClass clazz; + + private Assignments(List assigned, + List unassigned, TestClass clazz) { + this.unassigned = unassigned; + this.assigned = assigned; + this.clazz = clazz; + } + + /** + * Returns a new assignment list for {@code testMethod}, with no params + * assigned. + */ + public static Assignments allUnassigned(Method testMethod, + TestClass testClass) { + List signatures; + signatures = ParameterSignature.signatures(testClass + .getOnlyConstructor()); + signatures.addAll(ParameterSignature.signatures(testMethod)); + return new Assignments(new ArrayList(), + signatures, testClass); + } + + public boolean isComplete() { + return unassigned.isEmpty(); + } + + public ParameterSignature nextUnassigned() { + return unassigned.get(0); + } + + public Assignments assignNext(PotentialAssignment source) { + List potentialAssignments = new ArrayList(assigned); + potentialAssignments.add(source); + + return new Assignments(potentialAssignments, unassigned.subList(1, + unassigned.size()), clazz); + } + + public Object[] getActualValues(int start, int stop) + throws CouldNotGenerateValueException { + Object[] values = new Object[stop - start]; + for (int i = start; i < stop; i++) { + values[i - start] = assigned.get(i).getValue(); + } + return values; + } + + public List potentialsForNextUnassigned() + throws Throwable { + ParameterSignature unassigned = nextUnassigned(); + List assignments = getSupplier(unassigned).getValueSources(unassigned); + + if (assignments.isEmpty()) { + assignments = generateAssignmentsFromTypeAlone(unassigned); + } + + return assignments; + } + + private List generateAssignmentsFromTypeAlone(ParameterSignature unassigned) { + Class paramType = unassigned.getType(); + + if (paramType.isEnum()) { + return new EnumSupplier(paramType).getValueSources(unassigned); + } else if (paramType.equals(Boolean.class) || paramType.equals(boolean.class)) { + return new BooleanSupplier().getValueSources(unassigned); + } else { + return emptyList(); + } + } + + private ParameterSupplier getSupplier(ParameterSignature unassigned) + throws Exception { + ParametersSuppliedBy annotation = unassigned + .findDeepAnnotation(ParametersSuppliedBy.class); + + if (annotation != null) { + return buildParameterSupplierFromClass(annotation.value()); + } else { + return new AllMembersSupplier(clazz); + } + } + + private ParameterSupplier buildParameterSupplierFromClass( + Class cls) throws Exception { + Constructor[] supplierConstructors = cls.getConstructors(); + + for (Constructor constructor : supplierConstructors) { + Class[] parameterTypes = constructor.getParameterTypes(); + if (parameterTypes.length == 1 + && parameterTypes[0].equals(TestClass.class)) { + return (ParameterSupplier) constructor.newInstance(clazz); + } + } + + return cls.newInstance(); + } + + public Object[] getConstructorArguments() + throws CouldNotGenerateValueException { + return getActualValues(0, getConstructorParameterCount()); + } + + public Object[] getMethodArguments() throws CouldNotGenerateValueException { + return getActualValues(getConstructorParameterCount(), assigned.size()); + } + + public Object[] getAllArguments() throws CouldNotGenerateValueException { + return getActualValues(0, assigned.size()); + } + + private int getConstructorParameterCount() { + List signatures = ParameterSignature + .signatures(clazz.getOnlyConstructor()); + int constructorParameterCount = signatures.size(); + return constructorParameterCount; + } + + public Object[] getArgumentStrings(boolean nullsOk) + throws CouldNotGenerateValueException { + Object[] values = new Object[assigned.size()]; + for (int i = 0; i < values.length; i++) { + values[i] = assigned.get(i).getDescription(); + } + return values; + } +} \ No newline at end of file diff --git a/src/main/java/org/junit/experimental/theories/internal/BooleanSupplier.java b/src/main/java/org/junit/experimental/theories/internal/BooleanSupplier.java new file mode 100644 index 000000000000..5f7032fde739 --- /dev/null +++ b/src/main/java/org/junit/experimental/theories/internal/BooleanSupplier.java @@ -0,0 +1,18 @@ +package org.junit.experimental.theories.internal; + +import java.util.Arrays; +import java.util.List; + +import org.junit.experimental.theories.ParameterSignature; +import org.junit.experimental.theories.ParameterSupplier; +import org.junit.experimental.theories.PotentialAssignment; + +public class BooleanSupplier extends ParameterSupplier { + + @Override + public List getValueSources(ParameterSignature sig) { + return Arrays.asList(PotentialAssignment.forValue("true", true), + PotentialAssignment.forValue("false", false)); + } + +} diff --git a/src/main/java/org/junit/experimental/theories/internal/EnumSupplier.java b/src/main/java/org/junit/experimental/theories/internal/EnumSupplier.java new file mode 100644 index 000000000000..1f3ab90844b3 --- /dev/null +++ b/src/main/java/org/junit/experimental/theories/internal/EnumSupplier.java @@ -0,0 +1,30 @@ +package org.junit.experimental.theories.internal; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.experimental.theories.ParameterSignature; +import org.junit.experimental.theories.ParameterSupplier; +import org.junit.experimental.theories.PotentialAssignment; + +public class EnumSupplier extends ParameterSupplier { + + private Class enumType; + + public EnumSupplier(Class enumType) { + this.enumType = enumType; + } + + @Override + public List getValueSources(ParameterSignature sig) { + Object[] enumValues = enumType.getEnumConstants(); + + List assignments = new ArrayList(); + for (Object value : enumValues) { + assignments.add(PotentialAssignment.forValue(value.toString(), value)); + } + + return assignments; + } + +} diff --git a/src/main/java/org/junit/experimental/theories/internal/ParameterizedAssertionError.java b/src/main/java/org/junit/experimental/theories/internal/ParameterizedAssertionError.java new file mode 100644 index 000000000000..5b9e9473f894 --- /dev/null +++ b/src/main/java/org/junit/experimental/theories/internal/ParameterizedAssertionError.java @@ -0,0 +1,50 @@ +package org.junit.experimental.theories.internal; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Iterator; + +public class ParameterizedAssertionError extends AssertionError { + private static final long serialVersionUID = 1L; + + public ParameterizedAssertionError(Throwable targetException, + String methodName, Object... params) { + super(String.format("%s(%s)", methodName, join(", ", params))); + this.initCause(targetException); + } + + @Override + public boolean equals(Object obj) { + return obj instanceof ParameterizedAssertionError && toString().equals(obj.toString()); + } + + @Override + public int hashCode() { + return toString().hashCode(); + } + + public static String join(String delimiter, Object... params) { + return join(delimiter, Arrays.asList(params)); + } + + public static String join(String delimiter, Collection values) { + StringBuilder sb = new StringBuilder(); + Iterator iter = values.iterator(); + while (iter.hasNext()) { + Object next = iter.next(); + sb.append(stringValueOf(next)); + if (iter.hasNext()) { + sb.append(delimiter); + } + } + return sb.toString(); + } + + private static String stringValueOf(Object next) { + try { + return String.valueOf(next); + } catch (Throwable e) { + return "[toString failed]"; + } + } +} \ No newline at end of file diff --git a/src/main/java/org/junit/experimental/theories/internal/SpecificDataPointsSupplier.java b/src/main/java/org/junit/experimental/theories/internal/SpecificDataPointsSupplier.java new file mode 100644 index 000000000000..7b571e335941 --- /dev/null +++ b/src/main/java/org/junit/experimental/theories/internal/SpecificDataPointsSupplier.java @@ -0,0 +1,90 @@ +package org.junit.experimental.theories.internal; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; + +import org.junit.experimental.theories.DataPoint; +import org.junit.experimental.theories.DataPoints; +import org.junit.experimental.theories.FromDataPoints; +import org.junit.experimental.theories.ParameterSignature; +import org.junit.runners.model.FrameworkMethod; +import org.junit.runners.model.TestClass; + +public class SpecificDataPointsSupplier extends AllMembersSupplier { + + public SpecificDataPointsSupplier(TestClass testClass) { + super(testClass); + } + + @Override + protected Collection getSingleDataPointFields(ParameterSignature sig) { + Collection fields = super.getSingleDataPointFields(sig); + String requestedName = sig.getAnnotation(FromDataPoints.class).value(); + + List fieldsWithMatchingNames = new ArrayList(); + + for (Field field : fields) { + String[] fieldNames = field.getAnnotation(DataPoint.class).value(); + if (Arrays.asList(fieldNames).contains(requestedName)) { + fieldsWithMatchingNames.add(field); + } + } + + return fieldsWithMatchingNames; + } + + @Override + protected Collection getDataPointsFields(ParameterSignature sig) { + Collection fields = super.getDataPointsFields(sig); + String requestedName = sig.getAnnotation(FromDataPoints.class).value(); + + List fieldsWithMatchingNames = new ArrayList(); + + for (Field field : fields) { + String[] fieldNames = field.getAnnotation(DataPoints.class).value(); + if (Arrays.asList(fieldNames).contains(requestedName)) { + fieldsWithMatchingNames.add(field); + } + } + + return fieldsWithMatchingNames; + } + + @Override + protected Collection getSingleDataPointMethods(ParameterSignature sig) { + Collection methods = super.getSingleDataPointMethods(sig); + String requestedName = sig.getAnnotation(FromDataPoints.class).value(); + + List methodsWithMatchingNames = new ArrayList(); + + for (FrameworkMethod method : methods) { + String[] methodNames = method.getAnnotation(DataPoint.class).value(); + if (Arrays.asList(methodNames).contains(requestedName)) { + methodsWithMatchingNames.add(method); + } + } + + return methodsWithMatchingNames; + } + + @Override + protected Collection getDataPointsMethods(ParameterSignature sig) { + Collection methods = super.getDataPointsMethods(sig); + String requestedName = sig.getAnnotation(FromDataPoints.class).value(); + + List methodsWithMatchingNames = new ArrayList(); + + for (FrameworkMethod method : methods) { + String[] methodNames = method.getAnnotation(DataPoints.class).value(); + if (Arrays.asList(methodNames).contains(requestedName)) { + methodsWithMatchingNames.add(method); + } + } + + return methodsWithMatchingNames; + } + +} diff --git a/src/main/java/org/junit/experimental/theories/suppliers/TestedOn.java b/src/main/java/org/junit/experimental/theories/suppliers/TestedOn.java new file mode 100644 index 000000000000..a19f20a5d0b6 --- /dev/null +++ b/src/main/java/org/junit/experimental/theories/suppliers/TestedOn.java @@ -0,0 +1,31 @@ +package org.junit.experimental.theories.suppliers; + +import static java.lang.annotation.ElementType.PARAMETER; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.junit.experimental.theories.ParametersSuppliedBy; + +/** + * Annotating a {@link org.junit.experimental.theories.Theory Theory} method int + * parameter with @TestedOn causes it to be supplied with values from the + * ints array given when run as a theory by the + * {@link org.junit.experimental.theories.Theories Theories} runner. For + * example, the below method would be called three times by the Theories runner, + * once with each of the int parameters specified. + * + *
    + * @Theory
    + * public void shouldPassForSomeInts(@TestedOn(ints={1, 2, 3}) int param) {
    + *     ...
    + * }
    + * 
    + */ +@ParametersSuppliedBy(TestedOnSupplier.class) +@Retention(RetentionPolicy.RUNTIME) +@Target(PARAMETER) +public @interface TestedOn { + int[] ints(); +} diff --git a/src/main/java/org/junit/experimental/theories/suppliers/TestedOnSupplier.java b/src/main/java/org/junit/experimental/theories/suppliers/TestedOnSupplier.java new file mode 100644 index 000000000000..dc3d0c9ce326 --- /dev/null +++ b/src/main/java/org/junit/experimental/theories/suppliers/TestedOnSupplier.java @@ -0,0 +1,25 @@ +package org.junit.experimental.theories.suppliers; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.experimental.theories.ParameterSignature; +import org.junit.experimental.theories.ParameterSupplier; +import org.junit.experimental.theories.PotentialAssignment; + +/** + * @see org.junit.experimental.theories.suppliers.TestedOn + * @see org.junit.experimental.theories.ParameterSupplier + */ +public class TestedOnSupplier extends ParameterSupplier { + @Override + public List getValueSources(ParameterSignature sig) { + List list = new ArrayList(); + TestedOn testedOn = sig.getAnnotation(TestedOn.class); + int[] ints = testedOn.ints(); + for (final int i : ints) { + list.add(PotentialAssignment.forValue("ints", i)); + } + return list; + } +} diff --git a/src/main/java/org/junit/function/ThrowingRunnable.java b/src/main/java/org/junit/function/ThrowingRunnable.java new file mode 100644 index 000000000000..d0eb782ccd30 --- /dev/null +++ b/src/main/java/org/junit/function/ThrowingRunnable.java @@ -0,0 +1,14 @@ +package org.junit.function; + +/** + * This interface facilitates the use of + * {@link org.junit.Assert#assertThrows(Class, ThrowingRunnable)} from Java 8. It allows method + * references to void methods (that declare checked exceptions) to be passed directly into + * {@code assertThrows} + * without wrapping. It is not meant to be implemented directly. + * + * @since 4.13 + */ +public interface ThrowingRunnable { + void run() throws Throwable; +} diff --git a/src/main/java/org/junit/internal/ArrayComparisonFailure.java b/src/main/java/org/junit/internal/ArrayComparisonFailure.java new file mode 100644 index 000000000000..d300e7e5866b --- /dev/null +++ b/src/main/java/org/junit/internal/ArrayComparisonFailure.java @@ -0,0 +1,74 @@ +package org.junit.internal; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.Assert; + +/** + * Thrown when two array elements differ + * + * @see Assert#assertArrayEquals(String, Object[], Object[]) + */ +public class ArrayComparisonFailure extends AssertionError { + + private static final long serialVersionUID = 1L; + + /* + * We have to use the f prefix until the next major release to ensure + * serialization compatibility. + * See https://github.com/junit-team/junit4/issues/976 + */ + private final List fIndices = new ArrayList(); + private final String fMessage; + private final AssertionError fCause; + + /** + * Construct a new ArrayComparisonFailure with an error text and the array's + * dimension that was not equal + * + * @param cause the exception that caused the array's content to fail the assertion test + * @param index the array position of the objects that are not equal. + * @see Assert#assertArrayEquals(String, Object[], Object[]) + */ + public ArrayComparisonFailure(String message, AssertionError cause, int index) { + this.fMessage = message; + this.fCause = cause; + initCause(fCause); + addDimension(index); + } + + public void addDimension(int index) { + fIndices.add(0, index); + } + + @Override + public synchronized Throwable getCause() { + return super.getCause() == null ? fCause : super.getCause(); + } + + @Override + public String getMessage() { + StringBuilder sb = new StringBuilder(); + if (fMessage != null) { + sb.append(fMessage); + } + sb.append("arrays first differed at element "); + for (int each : fIndices) { + sb.append("["); + sb.append(each); + sb.append("]"); + } + sb.append("; "); + sb.append(getCause().getMessage()); + return sb.toString(); + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + return getMessage(); + } +} diff --git a/src/main/java/org/junit/internal/AssumptionViolatedException.java b/src/main/java/org/junit/internal/AssumptionViolatedException.java new file mode 100644 index 000000000000..15c27af1b279 --- /dev/null +++ b/src/main/java/org/junit/internal/AssumptionViolatedException.java @@ -0,0 +1,111 @@ +package org.junit.internal; + +import org.hamcrest.Description; +import org.hamcrest.Matcher; +import org.hamcrest.SelfDescribing; +import org.hamcrest.StringDescription; + +/** + * An exception class used to implement assumptions (state in which a given test + * is meaningful and should or should not be executed). A test for which an assumption + * fails should not generate a test case failure. + * + * @see org.junit.Assume + */ +public class AssumptionViolatedException extends RuntimeException implements SelfDescribing { + private static final long serialVersionUID = 2L; + + /* + * We have to use the f prefix until the next major release to ensure + * serialization compatibility. + * See https://github.com/junit-team/junit4/issues/976 + */ + private final String fAssumption; + private final boolean fValueMatcher; + private final Object fValue; + private final Matcher fMatcher; + + /** + * @deprecated Please use {@link org.junit.AssumptionViolatedException} instead. + */ + @Deprecated + public AssumptionViolatedException(String assumption, boolean hasValue, Object value, Matcher matcher) { + this.fAssumption = assumption; + this.fValue = value; + this.fMatcher = matcher; + this.fValueMatcher = hasValue; + + if (value instanceof Throwable) { + initCause((Throwable) value); + } + } + + /** + * An assumption exception with the given value (String or + * Throwable) and an additional failing {@link Matcher}. + * + * @deprecated Please use {@link org.junit.AssumptionViolatedException} instead. + */ + @Deprecated + public AssumptionViolatedException(Object value, Matcher matcher) { + this(null, true, value, matcher); + } + + /** + * An assumption exception with the given value (String or + * Throwable) and an additional failing {@link Matcher}. + * + * @deprecated Please use {@link org.junit.AssumptionViolatedException} instead. + */ + @Deprecated + public AssumptionViolatedException(String assumption, Object value, Matcher matcher) { + this(assumption, true, value, matcher); + } + + /** + * An assumption exception with the given message only. + * + * @deprecated Please use {@link org.junit.AssumptionViolatedException} instead. + */ + @Deprecated + public AssumptionViolatedException(String assumption) { + this(assumption, false, null, null); + } + + /** + * An assumption exception with the given message and a cause. + * + * @deprecated Please use {@link org.junit.AssumptionViolatedException} instead. + */ + @Deprecated + public AssumptionViolatedException(String assumption, Throwable e) { + this(assumption, false, null, null); + initCause(e); + } + + @Override + public String getMessage() { + return StringDescription.asString(this); + } + + public void describeTo(Description description) { + if (fAssumption != null) { + description.appendText(fAssumption); + } + + if (fValueMatcher) { + // a value was passed in when this instance was constructed; print it + if (fAssumption != null) { + description.appendText(": "); + } + + description.appendText("got: "); + description.appendValue(fValue); + + if (fMatcher != null) { + description.appendText(", expected: "); + description.appendDescriptionOf(fMatcher); + } + } + } +} diff --git a/src/main/java/org/junit/internal/Checks.java b/src/main/java/org/junit/internal/Checks.java new file mode 100644 index 000000000000..9724947f9977 --- /dev/null +++ b/src/main/java/org/junit/internal/Checks.java @@ -0,0 +1,37 @@ +package org.junit.internal; + +/** @since 4.13 */ +public final class Checks { + + private Checks() {} + + /** + * Checks that the given value is not {@code null}. + * + * @param value object reference to check + * @return the passed-in value, if not {@code null} + * @throws NullPointerException if {@code value} is {@code null} + */ + public static T notNull(T value) { + if (value == null) { + throw new NullPointerException(); + } + return value; + } + + /** + * Checks that the given value is not {@code null}, using the given message + * as the exception message if an exception is thrown. + * + * @param value object reference to check + * @param message message to use if {@code value} is {@code null} + * @return the passed-in value, if not {@code null} + * @throws NullPointerException if {@code value} is {@code null} + */ + public static T notNull(T value, String message) { + if (value == null) { + throw new NullPointerException(message); + } + return value; + } +} diff --git a/src/main/java/org/junit/internal/Classes.java b/src/main/java/org/junit/internal/Classes.java new file mode 100644 index 000000000000..e8404f685504 --- /dev/null +++ b/src/main/java/org/junit/internal/Classes.java @@ -0,0 +1,44 @@ +package org.junit.internal; + +import static java.lang.Thread.currentThread; + +/** + * Miscellaneous functions dealing with classes. + */ +public class Classes { + + /** + * Do not instantiate. + * @deprecated will be private soon. + */ + @Deprecated + public Classes() { + } + + /** + * Returns Class.forName for {@code className} using the current thread's class loader. + * If the current thread does not have a class loader, falls back to the class loader for + * {@link Classes}. + * + * @param className Name of the class. + * @throws ClassNotFoundException + */ + public static Class getClass(String className) throws ClassNotFoundException { + return getClass(className, Classes.class); + } + + /** + * Returns Class.forName for {@code className} using the current thread's class loader. + * If the current thread does not have a class loader, falls back to the class loader for the + * passed-in class. + * + * @param className Name of the class. + * @param callingClass Class that is requesting a the class + * @throws ClassNotFoundException + * @since 4.13 + */ + public static Class getClass(String className, Class callingClass) throws ClassNotFoundException { + ClassLoader classLoader = currentThread().getContextClassLoader(); + return Class.forName(className, true, classLoader == null ? callingClass.getClassLoader() : classLoader); + } +} diff --git a/src/main/java/org/junit/internal/ComparisonCriteria.java b/src/main/java/org/junit/internal/ComparisonCriteria.java new file mode 100644 index 000000000000..ed1c674907cb --- /dev/null +++ b/src/main/java/org/junit/internal/ComparisonCriteria.java @@ -0,0 +1,132 @@ +package org.junit.internal; + +import java.lang.reflect.Array; +import java.util.Arrays; + +import org.junit.Assert; + +/** + * Defines criteria for finding two items "equal enough". Concrete subclasses + * may demand exact equality, or, for example, equality within a given delta. + */ +public abstract class ComparisonCriteria { + /** + * Asserts that two arrays are equal, according to the criteria defined by + * the concrete subclass. If they are not, an {@link AssertionError} is + * thrown with the given message. If expecteds and + * actuals are null, they are considered equal. + * + * @param message the identifying message for the {@link AssertionError} ( + * null okay) + * @param expecteds Object array or array of arrays (multi-dimensional array) with + * expected values. + * @param actuals Object array or array of arrays (multi-dimensional array) with + * actual values + */ + public void arrayEquals(String message, Object expecteds, Object actuals) + throws ArrayComparisonFailure { + arrayEquals(message, expecteds, actuals, true); + } + + private void arrayEquals(String message, Object expecteds, Object actuals, boolean outer) + throws ArrayComparisonFailure { + if (expecteds == actuals + || Arrays.deepEquals(new Object[] {expecteds}, new Object[] {actuals})) { + // The reflection-based loop below is potentially very slow, especially for primitive + // arrays. The deepEquals check allows us to circumvent it in the usual case where + // the arrays are exactly equal. + return; + } + String header = message == null ? "" : message + ": "; + + // Only include the user-provided message in the outer exception. + String exceptionMessage = outer ? header : ""; + + if (expecteds == null) { + Assert.fail(exceptionMessage + "expected array was null"); + } + if (actuals == null) { + Assert.fail(exceptionMessage + "actual array was null"); + } + + int actualsLength = Array.getLength(actuals); + int expectedsLength = Array.getLength(expecteds); + if (actualsLength != expectedsLength) { + header += "array lengths differed, expected.length=" + + expectedsLength + " actual.length=" + actualsLength + "; "; + } + int prefixLength = Math.min(actualsLength, expectedsLength); + + for (int i = 0; i < prefixLength; i++) { + Object expected = Array.get(expecteds, i); + Object actual = Array.get(actuals, i); + + if (isArray(expected) && isArray(actual)) { + try { + arrayEquals(message, expected, actual, false); + } catch (ArrayComparisonFailure e) { + e.addDimension(i); + throw e; + } catch (AssertionError e) { + // Array lengths differed. + throw new ArrayComparisonFailure(header, e, i); + } + } else { + try { + assertElementsEqual(expected, actual); + } catch (AssertionError e) { + throw new ArrayComparisonFailure(header, e, i); + } + } + } + + if (actualsLength != expectedsLength) { + Object expected = getToStringableArrayElement(expecteds, expectedsLength, prefixLength); + Object actual = getToStringableArrayElement(actuals, actualsLength, prefixLength); + try { + Assert.assertEquals(expected, actual); + } catch (AssertionError e) { + throw new ArrayComparisonFailure(header, e, prefixLength); + } + } + } + + private static final Object END_OF_ARRAY_SENTINEL = objectWithToString("end of array"); + + private Object getToStringableArrayElement(Object array, int length, int index) { + if (index < length) { + Object element = Array.get(array, index); + if (isArray(element)) { + return objectWithToString(componentTypeName(element.getClass()) + "[" + Array.getLength(element) + "]"); + } else { + return element; + } + } else { + return END_OF_ARRAY_SENTINEL; + } + } + + private static Object objectWithToString(final String string) { + return new Object() { + @Override + public String toString() { + return string; + } + }; + } + + private String componentTypeName(Class arrayClass) { + Class componentType = arrayClass.getComponentType(); + if (componentType.isArray()) { + return componentTypeName(componentType) + "[]"; + } else { + return componentType.getName(); + } + } + + private boolean isArray(Object expected) { + return expected != null && expected.getClass().isArray(); + } + + protected abstract void assertElementsEqual(Object expected, Object actual); +} diff --git a/src/main/java/org/junit/internal/ExactComparisonCriteria.java b/src/main/java/org/junit/internal/ExactComparisonCriteria.java new file mode 100644 index 000000000000..a267f7fe285d --- /dev/null +++ b/src/main/java/org/junit/internal/ExactComparisonCriteria.java @@ -0,0 +1,10 @@ +package org.junit.internal; + +import org.junit.Assert; + +public class ExactComparisonCriteria extends ComparisonCriteria { + @Override + protected void assertElementsEqual(Object expected, Object actual) { + Assert.assertEquals(expected, actual); + } +} diff --git a/src/main/java/org/junit/internal/InexactComparisonCriteria.java b/src/main/java/org/junit/internal/InexactComparisonCriteria.java new file mode 100644 index 000000000000..16e804b9450f --- /dev/null +++ b/src/main/java/org/junit/internal/InexactComparisonCriteria.java @@ -0,0 +1,24 @@ +package org.junit.internal; + +import org.junit.Assert; + +public class InexactComparisonCriteria extends ComparisonCriteria { + public Object fDelta; + + public InexactComparisonCriteria(double delta) { + fDelta = delta; + } + + public InexactComparisonCriteria(float delta) { + fDelta = delta; + } + + @Override + protected void assertElementsEqual(Object expected, Object actual) { + if (expected instanceof Double) { + Assert.assertEquals((Double) expected, (Double) actual, (Double) fDelta); + } else { + Assert.assertEquals((Float) expected, (Float) actual, (Float) fDelta); + } + } +} \ No newline at end of file diff --git a/src/main/java/org/junit/internal/JUnitSystem.java b/src/main/java/org/junit/internal/JUnitSystem.java new file mode 100644 index 000000000000..cf0f2c055243 --- /dev/null +++ b/src/main/java/org/junit/internal/JUnitSystem.java @@ -0,0 +1,14 @@ +package org.junit.internal; + +import java.io.PrintStream; + +public interface JUnitSystem { + + /** + * Will be removed in the next major release + */ + @Deprecated + void exit(int code); + + PrintStream out(); +} diff --git a/src/main/java/org/junit/internal/MethodSorter.java b/src/main/java/org/junit/internal/MethodSorter.java new file mode 100644 index 000000000000..d8e661aa8824 --- /dev/null +++ b/src/main/java/org/junit/internal/MethodSorter.java @@ -0,0 +1,72 @@ +package org.junit.internal; + +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.Comparator; + +import org.junit.FixMethodOrder; + +public class MethodSorter { + /** + * DEFAULT sort order + */ + public static final Comparator DEFAULT = new Comparator() { + public int compare(Method m1, Method m2) { + int i1 = m1.getName().hashCode(); + int i2 = m2.getName().hashCode(); + if (i1 != i2) { + return i1 < i2 ? -1 : 1; + } + return NAME_ASCENDING.compare(m1, m2); + } + }; + + /** + * Method name ascending lexicographic sort order, with {@link Method#toString()} as a tiebreaker + */ + public static final Comparator NAME_ASCENDING = new Comparator() { + public int compare(Method m1, Method m2) { + final int comparison = m1.getName().compareTo(m2.getName()); + if (comparison != 0) { + return comparison; + } + return m1.toString().compareTo(m2.toString()); + } + }; + + /** + * Gets declared methods of a class in a predictable order, unless @FixMethodOrder(MethodSorters.JVM) is specified. + * + * Using the JVM order is unwise since the Java platform does not + * specify any particular order, and in fact JDK 7 returns a more or less + * random order; well-written test code would not assume any order, but some + * does, and a predictable failure is better than a random failure on + * certain platforms. By default, uses an unspecified but deterministic order. + * + * @param clazz a class + * @return same as {@link Class#getDeclaredMethods} but sorted + * @see JDK + * (non-)bug #7023180 + */ + public static Method[] getDeclaredMethods(Class clazz) { + Comparator comparator = getSorter(clazz.getAnnotation(FixMethodOrder.class)); + + Method[] methods = clazz.getDeclaredMethods(); + if (comparator != null) { + Arrays.sort(methods, comparator); + } + + return methods; + } + + private MethodSorter() { + } + + private static Comparator getSorter(FixMethodOrder fixMethodOrder) { + if (fixMethodOrder == null) { + return DEFAULT; + } + + return fixMethodOrder.value().getComparator(); + } +} diff --git a/src/main/java/org/junit/internal/RealSystem.java b/src/main/java/org/junit/internal/RealSystem.java new file mode 100644 index 000000000000..e64e1fe6aa61 --- /dev/null +++ b/src/main/java/org/junit/internal/RealSystem.java @@ -0,0 +1,19 @@ +package org.junit.internal; + +import java.io.PrintStream; + +public class RealSystem implements JUnitSystem { + + /** + * Will be removed in the next major release + */ + @Deprecated + public void exit(int code) { + System.exit(code); + } + + public PrintStream out() { + return System.out; + } + +} diff --git a/src/main/java/org/junit/internal/TextListener.java b/src/main/java/org/junit/internal/TextListener.java new file mode 100644 index 000000000000..d548aeb26e99 --- /dev/null +++ b/src/main/java/org/junit/internal/TextListener.java @@ -0,0 +1,101 @@ +package org.junit.internal; + +import java.io.PrintStream; +import java.text.NumberFormat; +import java.util.List; + +import org.junit.runner.Description; +import org.junit.runner.Result; +import org.junit.runner.notification.Failure; +import org.junit.runner.notification.RunListener; + +public class TextListener extends RunListener { + + private final PrintStream writer; + + public TextListener(JUnitSystem system) { + this(system.out()); + } + + public TextListener(PrintStream writer) { + this.writer = writer; + } + + @Override + public void testRunFinished(Result result) { + printHeader(result.getRunTime()); + printFailures(result); + printFooter(result); + } + + @Override + public void testStarted(Description description) { + writer.append('.'); + } + + @Override + public void testFailure(Failure failure) { + writer.append('E'); + } + + @Override + public void testIgnored(Description description) { + writer.append('I'); + } + + /* + * Internal methods + */ + + private PrintStream getWriter() { + return writer; + } + + protected void printHeader(long runTime) { + getWriter().println(); + getWriter().println("Time: " + elapsedTimeAsString(runTime)); + } + + protected void printFailures(Result result) { + List failures = result.getFailures(); + if (failures.isEmpty()) { + return; + } + if (failures.size() == 1) { + getWriter().println("There was " + failures.size() + " failure:"); + } else { + getWriter().println("There were " + failures.size() + " failures:"); + } + int i = 1; + for (Failure each : failures) { + printFailure(each, "" + i++); + } + } + + protected void printFailure(Failure each, String prefix) { + getWriter().println(prefix + ") " + each.getTestHeader()); + getWriter().print(each.getTrimmedTrace()); + } + + protected void printFooter(Result result) { + if (result.wasSuccessful()) { + getWriter().println(); + getWriter().print("OK"); + getWriter().println(" (" + result.getRunCount() + " test" + (result.getRunCount() == 1 ? "" : "s") + ")"); + + } else { + getWriter().println(); + getWriter().println("FAILURES!!!"); + getWriter().println("Tests run: " + result.getRunCount() + ", Failures: " + result.getFailureCount()); + } + getWriter().println(); + } + + /** + * Returns the formatted string of the elapsed time. Duplicated from + * BaseTestRunner. Fix it. + */ + protected String elapsedTimeAsString(long runTime) { + return NumberFormat.getInstance().format((double) runTime / 1000); + } +} diff --git a/src/main/java/org/junit/internal/Throwables.java b/src/main/java/org/junit/internal/Throwables.java new file mode 100644 index 000000000000..67d6b2bc06ec --- /dev/null +++ b/src/main/java/org/junit/internal/Throwables.java @@ -0,0 +1,270 @@ +package org.junit.internal; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.PrintWriter; +import java.io.StringReader; +import java.io.StringWriter; +import java.lang.reflect.Method; +import java.util.AbstractList; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +/** + * Miscellaneous functions dealing with {@code Throwable}. + * + * @author kcooney@google.com (Kevin Cooney) + * @since 4.12 + */ +public final class Throwables { + + private Throwables() { + } + + /** + * Rethrows the given {@code Throwable}, allowing the caller to + * declare that it throws {@code Exception}. This is useful when + * your callers have nothing reasonable they can do when a + * {@code Throwable} is thrown. This is declared to return {@code Exception} + * so it can be used in a {@code throw} clause: + *
    +     * try {
    +     *   doSomething();
    +     * } catch (Throwable e} {
    +     *   throw Throwables.rethrowAsException(e);
    +     * }
    +     * doSomethingLater();
    +     * 
    + * + * @param e exception to rethrow + * @return does not return anything + * @since 4.12 + */ + public static Exception rethrowAsException(Throwable e) throws Exception { + Throwables.rethrow(e); + return null; // we never get here + } + + @SuppressWarnings("unchecked") + private static void rethrow(Throwable e) throws T { + throw (T) e; + } + + /** + * Returns the stacktrace of the given Throwable as a String. + * + * @since 4.13 + */ + public static String getStacktrace(Throwable exception) { + StringWriter stringWriter = new StringWriter(); + PrintWriter writer = new PrintWriter(stringWriter); + exception.printStackTrace(writer); + return stringWriter.toString(); + } + + /** + * Gets a trimmed version of the stack trace of the given exception. Stack trace + * elements that are below the test method are filtered out. + * + * @return a trimmed stack trace, or the original trace if trimming wasn't possible + */ + public static String getTrimmedStackTrace(Throwable exception) { + List trimmedStackTraceLines = getTrimmedStackTraceLines(exception); + if (trimmedStackTraceLines.isEmpty()) { + return getFullStackTrace(exception); + } + + StringBuilder result = new StringBuilder(exception.toString()); + appendStackTraceLines(trimmedStackTraceLines, result); + appendStackTraceLines(getCauseStackTraceLines(exception), result); + return result.toString(); + } + + private static List getTrimmedStackTraceLines(Throwable exception) { + List stackTraceElements = Arrays.asList(exception.getStackTrace()); + int linesToInclude = stackTraceElements.size(); + + State state = State.PROCESSING_OTHER_CODE; + for (StackTraceElement stackTraceElement : asReversedList(stackTraceElements)) { + state = state.processStackTraceElement(stackTraceElement); + if (state == State.DONE) { + List trimmedLines = new ArrayList(linesToInclude + 2); + trimmedLines.add(""); + for (StackTraceElement each : stackTraceElements.subList(0, linesToInclude)) { + trimmedLines.add("\tat " + each); + } + if (exception.getCause() != null) { + trimmedLines.add("\t... " + (stackTraceElements.size() - trimmedLines.size()) + " trimmed"); + } + return trimmedLines; + } + linesToInclude--; + } + return Collections.emptyList(); + } + + private static final Method getSuppressed = initGetSuppressed(); + + private static Method initGetSuppressed() { + try { + return Throwable.class.getMethod("getSuppressed"); + } catch (Throwable e) { + return null; + } + } + + private static boolean hasSuppressed(Throwable exception) { + if (getSuppressed == null) { + return false; + } + try { + Throwable[] suppressed = (Throwable[]) getSuppressed.invoke(exception); + return suppressed.length != 0; + } catch (Throwable e) { + return false; + } + } + + private static List getCauseStackTraceLines(Throwable exception) { + if (exception.getCause() != null || hasSuppressed(exception)) { + String fullTrace = getFullStackTrace(exception); + BufferedReader reader = new BufferedReader( + new StringReader(fullTrace.substring(exception.toString().length()))); + List causedByLines = new ArrayList(); + + try { + String line; + while ((line = reader.readLine()) != null) { + if (line.startsWith("Caused by: ") || line.trim().startsWith("Suppressed: ")) { + causedByLines.add(line); + while ((line = reader.readLine()) != null) { + causedByLines.add(line); + } + return causedByLines; + } + } + } catch (IOException e) { + // We should never get here, because we are reading from a StringReader + } + } + + return Collections.emptyList(); + } + + private static String getFullStackTrace(Throwable exception) { + StringWriter stringWriter = new StringWriter(); + PrintWriter writer = new PrintWriter(stringWriter); + exception.printStackTrace(writer); + return stringWriter.toString(); + } + + private static void appendStackTraceLines( + List stackTraceLines, StringBuilder destBuilder) { + for (String stackTraceLine : stackTraceLines) { + destBuilder.append(String.format("%s%n", stackTraceLine)); + } + } + + private static List asReversedList(final List list) { + return new AbstractList() { + + @Override + public T get(int index) { + return list.get(list.size() - index - 1); + } + + @Override + public int size() { + return list.size(); + } + }; + } + + private enum State { + PROCESSING_OTHER_CODE { + @Override public State processLine(String methodName) { + if (isTestFrameworkMethod(methodName)) { + return PROCESSING_TEST_FRAMEWORK_CODE; + } + return this; + } + }, + PROCESSING_TEST_FRAMEWORK_CODE { + @Override public State processLine(String methodName) { + if (isReflectionMethod(methodName)) { + return PROCESSING_REFLECTION_CODE; + } else if (isTestFrameworkMethod(methodName)) { + return this; + } + return PROCESSING_OTHER_CODE; + } + }, + PROCESSING_REFLECTION_CODE { + @Override public State processLine(String methodName) { + if (isReflectionMethod(methodName)) { + return this; + } else if (isTestFrameworkMethod(methodName)) { + // This is here to handle TestCase.runBare() calling TestCase.runTest(). + return PROCESSING_TEST_FRAMEWORK_CODE; + } + return DONE; + } + }, + DONE { + @Override public State processLine(String methodName) { + return this; + } + }; + + /** Processes a stack trace element method name, possibly moving to a new state. */ + protected abstract State processLine(String methodName); + + /** Processes a stack trace element, possibly moving to a new state. */ + public final State processStackTraceElement(StackTraceElement element) { + return processLine(element.getClassName() + "." + element.getMethodName() + "()"); + } + } + + private static final String[] TEST_FRAMEWORK_METHOD_NAME_PREFIXES = { + "org.junit.runner.", + "org.junit.runners.", + "org.junit.experimental.runners.", + "org.junit.internal.", + "junit.", + }; + + private static final String[] TEST_FRAMEWORK_TEST_METHOD_NAME_PREFIXES = { + "org.junit.internal.StackTracesTest", + }; + + private static boolean isTestFrameworkMethod(String methodName) { + return isMatchingMethod(methodName, TEST_FRAMEWORK_METHOD_NAME_PREFIXES) && + !isMatchingMethod(methodName, TEST_FRAMEWORK_TEST_METHOD_NAME_PREFIXES); + } + + private static final String[] REFLECTION_METHOD_NAME_PREFIXES = { + "sun.reflect.", + "java.lang.reflect.", + "jdk.internal.reflect.", + "org.junit.rules.RunRules.(", + "org.junit.rules.RunRules.applyAll(", // calls TestRules + "org.junit.runners.RuleContainer.apply(", // calls MethodRules & TestRules + "junit.framework.TestCase.runBare(", // runBare() directly calls setUp() and tearDown() + }; + + private static boolean isReflectionMethod(String methodName) { + return isMatchingMethod(methodName, REFLECTION_METHOD_NAME_PREFIXES); + } + + private static boolean isMatchingMethod(String methodName, String[] methodNamePrefixes) { + for (String methodNamePrefix : methodNamePrefixes) { + if (methodName.startsWith(methodNamePrefix)) { + return true; + } + } + + return false; + } +} diff --git a/src/main/java/org/junit/internal/builders/AllDefaultPossibilitiesBuilder.java b/src/main/java/org/junit/internal/builders/AllDefaultPossibilitiesBuilder.java new file mode 100644 index 000000000000..8704a546b5f2 --- /dev/null +++ b/src/main/java/org/junit/internal/builders/AllDefaultPossibilitiesBuilder.java @@ -0,0 +1,67 @@ +package org.junit.internal.builders; + +import java.util.Arrays; +import java.util.List; + +import org.junit.runner.Runner; +import org.junit.runners.model.RunnerBuilder; + +public class AllDefaultPossibilitiesBuilder extends RunnerBuilder { + private final boolean canUseSuiteMethod; + + /** + * @since 4.13 + */ + public AllDefaultPossibilitiesBuilder() { + canUseSuiteMethod = true; + } + + /** + * @deprecated used {@link #AllDefaultPossibilitiesBuilder()}. + */ + @Deprecated + public AllDefaultPossibilitiesBuilder(boolean canUseSuiteMethod) { + this.canUseSuiteMethod = canUseSuiteMethod; + } + + @Override + public Runner runnerForClass(Class testClass) throws Throwable { + List builders = Arrays.asList( + ignoredBuilder(), + annotatedBuilder(), + suiteMethodBuilder(), + junit3Builder(), + junit4Builder()); + + for (RunnerBuilder each : builders) { + Runner runner = each.safeRunnerForClass(testClass); + if (runner != null) { + return runner; + } + } + return null; + } + + protected JUnit4Builder junit4Builder() { + return new JUnit4Builder(); + } + + protected JUnit3Builder junit3Builder() { + return new JUnit3Builder(); + } + + protected AnnotatedBuilder annotatedBuilder() { + return new AnnotatedBuilder(this); + } + + protected IgnoredBuilder ignoredBuilder() { + return new IgnoredBuilder(); + } + + protected RunnerBuilder suiteMethodBuilder() { + if (canUseSuiteMethod) { + return new SuiteMethodBuilder(); + } + return new NullBuilder(); + } +} \ No newline at end of file diff --git a/src/main/java/org/junit/internal/builders/AnnotatedBuilder.java b/src/main/java/org/junit/internal/builders/AnnotatedBuilder.java new file mode 100644 index 000000000000..04d7a683652f --- /dev/null +++ b/src/main/java/org/junit/internal/builders/AnnotatedBuilder.java @@ -0,0 +1,116 @@ +package org.junit.internal.builders; + +import org.junit.runner.RunWith; +import org.junit.runner.Runner; +import org.junit.runners.model.InitializationError; +import org.junit.runners.model.RunnerBuilder; + +import java.lang.reflect.Modifier; + + +/** + * The {@code AnnotatedBuilder} is a strategy for constructing runners for test class that have been annotated with the + * {@code @RunWith} annotation. All tests within this class will be executed using the runner that was specified within + * the annotation. + *

    + * If a runner supports inner member classes, the member classes will inherit the runner from the enclosing class, e.g.: + *

    + * @RunWith(MyRunner.class)
    + * public class MyTest {
    + *     // some tests might go here
    + *
    + *     public class MyMemberClass {
    + *         @Test
    + *         public void thisTestRunsWith_MyRunner() {
    + *             // some test logic
    + *         }
    + *
    + *         // some more tests might go here
    + *     }
    + *
    + *     @RunWith(AnotherRunner.class)
    + *     public class AnotherMemberClass {
    + *         // some tests might go here
    + *
    + *         public class DeepInnerClass {
    + *             @Test
    + *             public void thisTestRunsWith_AnotherRunner() {
    + *                 // some test logic
    + *             }
    + *         }
    + *
    + *         public class DeepInheritedClass extends SuperTest {
    + *             @Test
    + *             public void thisTestRunsWith_SuperRunner() {
    + *                 // some test logic
    + *             }
    + *         }
    + *     }
    + * }
    + *
    + * @RunWith(SuperRunner.class)
    + * public class SuperTest {
    + *     // some tests might go here
    + * }
    + * 
    + * The key points to note here are: + *
      + *
    • If there is no RunWith annotation, no runner will be created.
    • + *
    • The resolve step is inside-out, e.g. the closest RunWith annotation wins
    • + *
    • RunWith annotations are inherited and work as if the class was annotated itself.
    • + *
    • The default JUnit runner does not support inner member classes, + * so this is only valid for custom runners that support inner member classes.
    • + *
    • Custom runners with support for inner classes may or may not support RunWith annotations for member + * classes. Please refer to the custom runner documentation.
    • + *
    + * + * @see org.junit.runners.model.RunnerBuilder + * @see org.junit.runner.RunWith + * @since 4.0 + */ +public class AnnotatedBuilder extends RunnerBuilder { + private static final String CONSTRUCTOR_ERROR_FORMAT = "Custom runner class %s should have a public constructor with signature %s(Class testClass)"; + + private final RunnerBuilder suiteBuilder; + + public AnnotatedBuilder(RunnerBuilder suiteBuilder) { + this.suiteBuilder = suiteBuilder; + } + + @Override + public Runner runnerForClass(Class testClass) throws Exception { + for (Class currentTestClass = testClass; currentTestClass != null; + currentTestClass = getEnclosingClassForNonStaticMemberClass(currentTestClass)) { + RunWith annotation = currentTestClass.getAnnotation(RunWith.class); + if (annotation != null) { + return buildRunner(annotation.value(), testClass); + } + } + + return null; + } + + private Class getEnclosingClassForNonStaticMemberClass(Class currentTestClass) { + if (currentTestClass.isMemberClass() && !Modifier.isStatic(currentTestClass.getModifiers())) { + return currentTestClass.getEnclosingClass(); + } else { + return null; + } + } + + public Runner buildRunner(Class runnerClass, + Class testClass) throws Exception { + try { + return runnerClass.getConstructor(Class.class).newInstance(testClass); + } catch (NoSuchMethodException e) { + try { + return runnerClass.getConstructor(Class.class, + RunnerBuilder.class).newInstance(testClass, suiteBuilder); + } catch (NoSuchMethodException e2) { + String simpleName = runnerClass.getSimpleName(); + throw new InitializationError(String.format( + CONSTRUCTOR_ERROR_FORMAT, simpleName, simpleName)); + } + } + } +} \ No newline at end of file diff --git a/src/main/java/org/junit/internal/builders/IgnoredBuilder.java b/src/main/java/org/junit/internal/builders/IgnoredBuilder.java new file mode 100644 index 000000000000..71940c87fb44 --- /dev/null +++ b/src/main/java/org/junit/internal/builders/IgnoredBuilder.java @@ -0,0 +1,15 @@ +package org.junit.internal.builders; + +import org.junit.Ignore; +import org.junit.runner.Runner; +import org.junit.runners.model.RunnerBuilder; + +public class IgnoredBuilder extends RunnerBuilder { + @Override + public Runner runnerForClass(Class testClass) { + if (testClass.getAnnotation(Ignore.class) != null) { + return new IgnoredClassRunner(testClass); + } + return null; + } +} \ No newline at end of file diff --git a/src/main/java/org/junit/internal/builders/IgnoredClassRunner.java b/src/main/java/org/junit/internal/builders/IgnoredClassRunner.java new file mode 100644 index 000000000000..7c8926b7fb79 --- /dev/null +++ b/src/main/java/org/junit/internal/builders/IgnoredClassRunner.java @@ -0,0 +1,23 @@ +package org.junit.internal.builders; + +import org.junit.runner.Description; +import org.junit.runner.Runner; +import org.junit.runner.notification.RunNotifier; + +public class IgnoredClassRunner extends Runner { + private final Class clazz; + + public IgnoredClassRunner(Class testClass) { + clazz = testClass; + } + + @Override + public void run(RunNotifier notifier) { + notifier.fireTestIgnored(getDescription()); + } + + @Override + public Description getDescription() { + return Description.createSuiteDescription(clazz); + } +} \ No newline at end of file diff --git a/src/main/java/org/junit/internal/builders/JUnit3Builder.java b/src/main/java/org/junit/internal/builders/JUnit3Builder.java new file mode 100644 index 000000000000..8b6b37145533 --- /dev/null +++ b/src/main/java/org/junit/internal/builders/JUnit3Builder.java @@ -0,0 +1,19 @@ +package org.junit.internal.builders; + +import org.junit.internal.runners.JUnit38ClassRunner; +import org.junit.runner.Runner; +import org.junit.runners.model.RunnerBuilder; + +public class JUnit3Builder extends RunnerBuilder { + @Override + public Runner runnerForClass(Class testClass) throws Throwable { + if (isPre4Test(testClass)) { + return new JUnit38ClassRunner(testClass); + } + return null; + } + + boolean isPre4Test(Class testClass) { + return junit.framework.TestCase.class.isAssignableFrom(testClass); + } +} \ No newline at end of file diff --git a/src/main/java/org/junit/internal/builders/JUnit4Builder.java b/src/main/java/org/junit/internal/builders/JUnit4Builder.java new file mode 100644 index 000000000000..7959e75239db --- /dev/null +++ b/src/main/java/org/junit/internal/builders/JUnit4Builder.java @@ -0,0 +1,12 @@ +package org.junit.internal.builders; + +import org.junit.runner.Runner; +import org.junit.runners.JUnit4; +import org.junit.runners.model.RunnerBuilder; + +public class JUnit4Builder extends RunnerBuilder { + @Override + public Runner runnerForClass(Class testClass) throws Throwable { + return new JUnit4(testClass); + } +} diff --git a/src/main/java/org/junit/internal/builders/NullBuilder.java b/src/main/java/org/junit/internal/builders/NullBuilder.java new file mode 100644 index 000000000000..c8d306e03dc5 --- /dev/null +++ b/src/main/java/org/junit/internal/builders/NullBuilder.java @@ -0,0 +1,11 @@ +package org.junit.internal.builders; + +import org.junit.runner.Runner; +import org.junit.runners.model.RunnerBuilder; + +public class NullBuilder extends RunnerBuilder { + @Override + public Runner runnerForClass(Class each) throws Throwable { + return null; + } +} \ No newline at end of file diff --git a/src/main/java/org/junit/internal/builders/SuiteMethodBuilder.java b/src/main/java/org/junit/internal/builders/SuiteMethodBuilder.java new file mode 100644 index 000000000000..953e6cfd5474 --- /dev/null +++ b/src/main/java/org/junit/internal/builders/SuiteMethodBuilder.java @@ -0,0 +1,24 @@ +package org.junit.internal.builders; + +import org.junit.internal.runners.SuiteMethod; +import org.junit.runner.Runner; +import org.junit.runners.model.RunnerBuilder; + +public class SuiteMethodBuilder extends RunnerBuilder { + @Override + public Runner runnerForClass(Class each) throws Throwable { + if (hasSuiteMethod(each)) { + return new SuiteMethod(each); + } + return null; + } + + public boolean hasSuiteMethod(Class testClass) { + try { + testClass.getMethod("suite"); + } catch (NoSuchMethodException e) { + return false; + } + return true; + } +} \ No newline at end of file diff --git a/src/main/java/org/junit/internal/management/FakeRuntimeMXBean.java b/src/main/java/org/junit/internal/management/FakeRuntimeMXBean.java new file mode 100644 index 000000000000..477b1509ce45 --- /dev/null +++ b/src/main/java/org/junit/internal/management/FakeRuntimeMXBean.java @@ -0,0 +1,21 @@ +package org.junit.internal.management; + +import java.util.Collections; +import java.util.List; + +/** + * No-op implementation of RuntimeMXBean when the platform doesn't provide it. + */ +class FakeRuntimeMXBean implements RuntimeMXBean { + + /** + * {@inheritDoc} + * + *

    Always returns an empty list. + */ + public List getInputArguments() { + return Collections.emptyList(); + } + +} + diff --git a/src/main/java/org/junit/internal/management/FakeThreadMXBean.java b/src/main/java/org/junit/internal/management/FakeThreadMXBean.java new file mode 100644 index 000000000000..893f2e3ea583 --- /dev/null +++ b/src/main/java/org/junit/internal/management/FakeThreadMXBean.java @@ -0,0 +1,27 @@ +package org.junit.internal.management; + +/** + * No-op implementation of ThreadMXBean when the platform doesn't provide it. + */ +final class FakeThreadMXBean implements ThreadMXBean { + + /** + * {@inheritDoc} + * + *

    Always throws an {@link UnsupportedOperationException} + */ + public long getThreadCpuTime(long id) { + throw new UnsupportedOperationException(); + } + + /** + * {@inheritDoc} + * + *

    Always returns false. + */ + public boolean isThreadCpuTimeSupported() { + return false; + } + +} + diff --git a/src/main/java/org/junit/internal/management/ManagementFactory.java b/src/main/java/org/junit/internal/management/ManagementFactory.java new file mode 100644 index 000000000000..5be1447532e9 --- /dev/null +++ b/src/main/java/org/junit/internal/management/ManagementFactory.java @@ -0,0 +1,77 @@ +package org.junit.internal.management; + +import org.junit.internal.Classes; + +import java.lang.reflect.InvocationTargetException; + +/** + * Reflective wrapper around {@link java.lang.management.ManagementFactory} + */ +public class ManagementFactory { + private static final class FactoryHolder { + private static final Class MANAGEMENT_FACTORY_CLASS; + + static { + Class managementFactoryClass = null; + try { + managementFactoryClass = Classes.getClass("java.lang.management.ManagementFactory"); + } catch (ClassNotFoundException e) { + // do nothing, managementFactoryClass will be none on failure + } + MANAGEMENT_FACTORY_CLASS = managementFactoryClass; + } + + static Object getBeanObject(String methodName) { + if (MANAGEMENT_FACTORY_CLASS != null) { + try { + return MANAGEMENT_FACTORY_CLASS.getMethod(methodName).invoke(null); + } catch (IllegalAccessException e) { + // fallthrough + } catch (IllegalArgumentException e) { + // fallthrough + } catch (InvocationTargetException e) { + // fallthrough + } catch (NoSuchMethodException e) { + // fallthrough + } catch (SecurityException e) { + // fallthrough + } + } + return null; + } + } + + private static final class RuntimeHolder { + private static final RuntimeMXBean RUNTIME_MX_BEAN = + getBean(FactoryHolder.getBeanObject("getRuntimeMXBean")); + + private static final RuntimeMXBean getBean(Object runtimeMxBean) { + return runtimeMxBean != null + ? new ReflectiveRuntimeMXBean(runtimeMxBean) : new FakeRuntimeMXBean(); + } + } + + private static final class ThreadHolder { + private static final ThreadMXBean THREAD_MX_BEAN = + getBean(FactoryHolder.getBeanObject("getThreadMXBean")); + + private static final ThreadMXBean getBean(Object threadMxBean) { + return threadMxBean != null + ? new ReflectiveThreadMXBean(threadMxBean) : new FakeThreadMXBean(); + } + } + + /** + * @see java.lang.management.ManagementFactory#getRuntimeMXBean() + */ + public static RuntimeMXBean getRuntimeMXBean() { + return RuntimeHolder.RUNTIME_MX_BEAN; + } + + /** + * @see java.lang.management.ManagementFactory#getThreadMXBean() + */ + public static ThreadMXBean getThreadMXBean() { + return ThreadHolder.THREAD_MX_BEAN; + } +} diff --git a/src/main/java/org/junit/internal/management/ReflectiveRuntimeMXBean.java b/src/main/java/org/junit/internal/management/ReflectiveRuntimeMXBean.java new file mode 100644 index 000000000000..289587a44776 --- /dev/null +++ b/src/main/java/org/junit/internal/management/ReflectiveRuntimeMXBean.java @@ -0,0 +1,61 @@ +package org.junit.internal.management; + +import org.junit.internal.Classes; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Collections; +import java.util.List; + +/** + * Implementation of {@link RuntimeMXBean} using the JVM reflectively. + */ +final class ReflectiveRuntimeMXBean implements RuntimeMXBean { + private final Object runtimeMxBean; + + private static final class Holder { + private static final Method getInputArgumentsMethod; + static { + Method inputArguments = null; + try { + Class threadMXBeanClass = Classes.getClass("java.lang.management.RuntimeMXBean"); + inputArguments = threadMXBeanClass.getMethod("getInputArguments"); + } catch (ClassNotFoundException e) { + // do nothing, input arguments will be null on failure + } catch (NoSuchMethodException e) { + // do nothing, input arguments will be null on failure + } catch (SecurityException e) { + // do nothing, input arguments will be null on failure + } + getInputArgumentsMethod = inputArguments; + } + } + + ReflectiveRuntimeMXBean(Object runtimeMxBean) { + super(); + this.runtimeMxBean = runtimeMxBean; + } + + /** + * {@inheritDoc} + */ + @SuppressWarnings("unchecked") + public List getInputArguments() { + if (Holder.getInputArgumentsMethod != null) { + try { + return (List) Holder.getInputArgumentsMethod.invoke(runtimeMxBean); + } catch (ClassCastException e) { // no multi-catch with source level 6 + // fallthrough + } catch (IllegalAccessException e) { + // fallthrough + } catch (IllegalArgumentException e) { + // fallthrough + } catch (InvocationTargetException e) { + // fallthrough + } + } + return Collections.emptyList(); + } + +} + diff --git a/src/main/java/org/junit/internal/management/ReflectiveThreadMXBean.java b/src/main/java/org/junit/internal/management/ReflectiveThreadMXBean.java new file mode 100644 index 000000000000..bc741bec8e61 --- /dev/null +++ b/src/main/java/org/junit/internal/management/ReflectiveThreadMXBean.java @@ -0,0 +1,92 @@ +package org.junit.internal.management; + +import org.junit.internal.Classes; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +/** + * Implementation of {@link ThreadMXBean} using the JVM reflectively. + */ +final class ReflectiveThreadMXBean implements ThreadMXBean { + private final Object threadMxBean; + + + private static final class Holder { + static final Method getThreadCpuTimeMethod; + static final Method isThreadCpuTimeSupportedMethod; + + private static final String FAILURE_MESSAGE = "Unable to access ThreadMXBean"; + + static { + Method threadCpuTime = null; + Method threadCpuTimeSupported = null; + try { + Class threadMXBeanClass = Classes.getClass("java.lang.management.ThreadMXBean"); + threadCpuTime = threadMXBeanClass.getMethod("getThreadCpuTime", long.class); + threadCpuTimeSupported = threadMXBeanClass.getMethod("isThreadCpuTimeSupported"); + } catch (ClassNotFoundException e) { + // do nothing, the methods will be null on failure + } catch (NoSuchMethodException e) { + // do nothing, the methods will be null on failure + } catch (SecurityException e) { + // do nothing, the methods will be null on failure + } + getThreadCpuTimeMethod = threadCpuTime; + isThreadCpuTimeSupportedMethod = threadCpuTimeSupported; + } + } + + ReflectiveThreadMXBean(Object threadMxBean) { + super(); + this.threadMxBean = threadMxBean; + } + + /** + * {@inheritDoc} + */ + public long getThreadCpuTime(long id) { + if (Holder.getThreadCpuTimeMethod != null) { + Exception error = null; + try { + return (Long) Holder.getThreadCpuTimeMethod.invoke(threadMxBean, id); + } catch (ClassCastException e) { + error = e; + // fallthrough + } catch (IllegalAccessException e) { + error = e; + // fallthrough + } catch (IllegalArgumentException e) { + error = e; + // fallthrough + } catch (InvocationTargetException e) { + error = e; + // fallthrough + } + throw new UnsupportedOperationException(Holder.FAILURE_MESSAGE, error); + } + throw new UnsupportedOperationException(Holder.FAILURE_MESSAGE); + } + + /** + * {@inheritDoc} + */ + public boolean isThreadCpuTimeSupported() { + if (Holder.isThreadCpuTimeSupportedMethod != null) { + try { + return (Boolean) Holder.isThreadCpuTimeSupportedMethod.invoke(threadMxBean); + } catch (ClassCastException e) { + // fallthrough + } catch (IllegalAccessException e) { + // fallthrough + } catch (IllegalArgumentException e) { + // fallthrough + } catch (InvocationTargetException e) { + // fallthrough + } + } + return false; + } + +} + diff --git a/src/main/java/org/junit/internal/management/RuntimeMXBean.java b/src/main/java/org/junit/internal/management/RuntimeMXBean.java new file mode 100644 index 000000000000..84f8861f2fed --- /dev/null +++ b/src/main/java/org/junit/internal/management/RuntimeMXBean.java @@ -0,0 +1,14 @@ +package org.junit.internal.management; + +import java.util.List; + +/** + * Wrapper for {@link java.lang.management.RuntimeMXBean}. + */ +public interface RuntimeMXBean { + + /** + * @see java.lang.management.RuntimeMXBean#getInputArguments() + */ + List getInputArguments(); +} diff --git a/src/main/java/org/junit/internal/management/ThreadMXBean.java b/src/main/java/org/junit/internal/management/ThreadMXBean.java new file mode 100644 index 000000000000..f9225c9fb888 --- /dev/null +++ b/src/main/java/org/junit/internal/management/ThreadMXBean.java @@ -0,0 +1,17 @@ +package org.junit.internal.management; + +/** + * Wrapper for {@link java.lang.management.ThreadMXBean}. + */ +public interface ThreadMXBean { + /** + * @see java.lang.management.ThreadMXBean#getThreadCpuTime(long) + */ + long getThreadCpuTime(long id); + + /** + * @see java.lang.management.ThreadMXBean#isThreadCpuTimeSupported() + */ + boolean isThreadCpuTimeSupported(); +} + diff --git a/src/main/java/org/junit/internal/matchers/StacktracePrintingMatcher.java b/src/main/java/org/junit/internal/matchers/StacktracePrintingMatcher.java new file mode 100644 index 000000000000..93a6827678d0 --- /dev/null +++ b/src/main/java/org/junit/internal/matchers/StacktracePrintingMatcher.java @@ -0,0 +1,53 @@ +package org.junit.internal.matchers; + +import org.hamcrest.Description; +import org.hamcrest.Factory; +import org.hamcrest.Matcher; + +import org.junit.internal.Throwables; + +/** + * A matcher that delegates to throwableMatcher and in addition appends the + * stacktrace of the actual Throwable in case of a mismatch. + */ +public class StacktracePrintingMatcher extends + org.hamcrest.TypeSafeMatcher { + + private final Matcher throwableMatcher; + + public StacktracePrintingMatcher(Matcher throwableMatcher) { + this.throwableMatcher = throwableMatcher; + } + + public void describeTo(Description description) { + throwableMatcher.describeTo(description); + } + + @Override + protected boolean matchesSafely(T item) { + return throwableMatcher.matches(item); + } + + @Override + protected void describeMismatchSafely(T item, Description description) { + throwableMatcher.describeMismatch(item, description); + description.appendText("\nStacktrace was: "); + description.appendText(readStacktrace(item)); + } + + private String readStacktrace(Throwable throwable) { + return Throwables.getStacktrace(throwable); + } + + @Factory + public static Matcher isThrowable( + Matcher throwableMatcher) { + return new StacktracePrintingMatcher(throwableMatcher); + } + + @Factory + public static Matcher isException( + Matcher exceptionMatcher) { + return new StacktracePrintingMatcher(exceptionMatcher); + } +} diff --git a/src/main/java/org/junit/internal/matchers/ThrowableCauseMatcher.java b/src/main/java/org/junit/internal/matchers/ThrowableCauseMatcher.java new file mode 100644 index 000000000000..6e2ff5e3d565 --- /dev/null +++ b/src/main/java/org/junit/internal/matchers/ThrowableCauseMatcher.java @@ -0,0 +1,50 @@ +package org.junit.internal.matchers; + +import org.hamcrest.Description; +import org.hamcrest.Factory; +import org.hamcrest.Matcher; +import org.hamcrest.TypeSafeMatcher; + +/** + * A matcher that applies a delegate matcher to the cause of the current Throwable, returning the result of that + * match. + * + * @param the type of the throwable being matched + */ +public class ThrowableCauseMatcher extends + TypeSafeMatcher { + + private final Matcher causeMatcher; + + public ThrowableCauseMatcher(Matcher causeMatcher) { + this.causeMatcher = causeMatcher; + } + + public void describeTo(Description description) { + description.appendText("exception with cause "); + description.appendDescriptionOf(causeMatcher); + } + + @Override + protected boolean matchesSafely(T item) { + return causeMatcher.matches(item.getCause()); + } + + @Override + protected void describeMismatchSafely(T item, Description description) { + description.appendText("cause "); + causeMatcher.describeMismatch(item.getCause(), description); + } + + /** + * Returns a matcher that verifies that the outer exception has a cause for which the supplied matcher + * evaluates to true. + * + * @param matcher to apply to the cause of the outer exception + * @param type of the outer exception + */ + @Factory + public static Matcher hasCause(final Matcher matcher) { + return new ThrowableCauseMatcher(matcher); + } +} \ No newline at end of file diff --git a/src/main/java/org/junit/internal/matchers/ThrowableMessageMatcher.java b/src/main/java/org/junit/internal/matchers/ThrowableMessageMatcher.java new file mode 100644 index 000000000000..74386a862115 --- /dev/null +++ b/src/main/java/org/junit/internal/matchers/ThrowableMessageMatcher.java @@ -0,0 +1,37 @@ +package org.junit.internal.matchers; + +import org.hamcrest.Description; +import org.hamcrest.Factory; +import org.hamcrest.Matcher; +import org.hamcrest.TypeSafeMatcher; + +public class ThrowableMessageMatcher extends + TypeSafeMatcher { + + private final Matcher matcher; + + public ThrowableMessageMatcher(Matcher matcher) { + this.matcher = matcher; + } + + public void describeTo(Description description) { + description.appendText("exception with message "); + description.appendDescriptionOf(matcher); + } + + @Override + protected boolean matchesSafely(T item) { + return matcher.matches(item.getMessage()); + } + + @Override + protected void describeMismatchSafely(T item, Description description) { + description.appendText("message "); + matcher.describeMismatch(item.getMessage(), description); + } + + @Factory + public static Matcher hasMessage(final Matcher matcher) { + return new ThrowableMessageMatcher(matcher); + } +} \ No newline at end of file diff --git a/src/main/java/org/junit/internal/matchers/TypeSafeMatcher.java b/src/main/java/org/junit/internal/matchers/TypeSafeMatcher.java new file mode 100644 index 000000000000..fb25982bbd4d --- /dev/null +++ b/src/main/java/org/junit/internal/matchers/TypeSafeMatcher.java @@ -0,0 +1,63 @@ +package org.junit.internal.matchers; + +import java.lang.reflect.Method; + +import org.hamcrest.BaseMatcher; +import org.junit.internal.MethodSorter; + +/** + * Convenient base class for Matchers that require a non-null value of a specific type. + * This simply implements the null check, checks the type and then casts. + * + * @author Joe Walnes + * @deprecated Please use {@link org.hamcrest.TypeSafeMatcher}. + */ +@Deprecated +public abstract class TypeSafeMatcher extends BaseMatcher { + + private Class expectedType; + + /** + * Subclasses should implement this. The item will already have been checked for + * the specific type and will never be null. + */ + public abstract boolean matchesSafely(T item); + + protected TypeSafeMatcher() { + expectedType = findExpectedType(getClass()); + } + + private static Class findExpectedType(Class fromClass) { + for (Class c = fromClass; c != Object.class; c = c.getSuperclass()) { + for (Method method : MethodSorter.getDeclaredMethods(c)) { + if (isMatchesSafelyMethod(method)) { + return method.getParameterTypes()[0]; + } + } + } + + throw new Error("Cannot determine correct type for matchesSafely() method."); + } + + private static boolean isMatchesSafelyMethod(Method method) { + return "matchesSafely".equals(method.getName()) + && method.getParameterTypes().length == 1 + && !method.isSynthetic(); + } + + protected TypeSafeMatcher(Class expectedType) { + this.expectedType = expectedType; + } + + /** + * Method made final to prevent accidental override. + * If you need to override this, there's no point on extending TypeSafeMatcher. + * Instead, extend the {@link BaseMatcher}. + */ + @SuppressWarnings({"unchecked"}) + public final boolean matches(Object item) { + return item != null + && expectedType.isInstance(item) + && matchesSafely((T) item); + } +} diff --git a/src/main/java/org/junit/internal/requests/ClassRequest.java b/src/main/java/org/junit/internal/requests/ClassRequest.java new file mode 100644 index 000000000000..d60e36062d81 --- /dev/null +++ b/src/main/java/org/junit/internal/requests/ClassRequest.java @@ -0,0 +1,54 @@ +package org.junit.internal.requests; + +import org.junit.internal.builders.AllDefaultPossibilitiesBuilder; +import org.junit.internal.builders.SuiteMethodBuilder; +import org.junit.runner.Runner; +import org.junit.runners.model.RunnerBuilder; + +public class ClassRequest extends MemoizingRequest { + /* + * We have to use the f prefix, because IntelliJ's JUnit4IdeaTestRunner uses + * reflection to access this field. See + * https://github.com/junit-team/junit4/issues/960 + */ + private final Class fTestClass; + private final boolean canUseSuiteMethod; + + public ClassRequest(Class testClass, boolean canUseSuiteMethod) { + this.fTestClass = testClass; + this.canUseSuiteMethod = canUseSuiteMethod; + } + + public ClassRequest(Class testClass) { + this(testClass, true); + } + + @Override + protected Runner createRunner() { + return new CustomAllDefaultPossibilitiesBuilder().safeRunnerForClass(fTestClass); + } + + private class CustomAllDefaultPossibilitiesBuilder extends AllDefaultPossibilitiesBuilder { + + @Override + protected RunnerBuilder suiteMethodBuilder() { + return new CustomSuiteMethodBuilder(); + } + } + + /* + * Customization of {@link SuiteMethodBuilder} that prevents use of the + * suite method when creating a runner for fTestClass when canUseSuiteMethod + * is false. + */ + private class CustomSuiteMethodBuilder extends SuiteMethodBuilder { + + @Override + public Runner runnerForClass(Class testClass) throws Throwable { + if (testClass == fTestClass && !canUseSuiteMethod) { + return null; + } + return super.runnerForClass(testClass); + } + } +} \ No newline at end of file diff --git a/src/main/java/org/junit/internal/requests/FilterRequest.java b/src/main/java/org/junit/internal/requests/FilterRequest.java new file mode 100644 index 000000000000..5f00399557c2 --- /dev/null +++ b/src/main/java/org/junit/internal/requests/FilterRequest.java @@ -0,0 +1,45 @@ +package org.junit.internal.requests; + +import org.junit.internal.runners.ErrorReportingRunner; +import org.junit.runner.Request; +import org.junit.runner.Runner; +import org.junit.runner.manipulation.Filter; +import org.junit.runner.manipulation.NoTestsRemainException; + +/** + * A filtered {@link Request}. + */ +public final class FilterRequest extends Request { + private final Request request; + /* + * We have to use the f prefix, because IntelliJ's JUnit4IdeaTestRunner uses + * reflection to access this field. See + * https://github.com/junit-team/junit4/issues/960 + */ + private final Filter fFilter; + + /** + * Creates a filtered Request + * + * @param request a {@link Request} describing your Tests + * @param filter {@link Filter} to apply to the Tests described in + * request + */ + public FilterRequest(Request request, Filter filter) { + this.request = request; + this.fFilter = filter; + } + + @Override + public Runner getRunner() { + try { + Runner runner = request.getRunner(); + fFilter.apply(runner); + return runner; + } catch (NoTestsRemainException e) { + return new ErrorReportingRunner(Filter.class, new Exception(String + .format("No tests found matching %s from %s", fFilter + .describe(), request.toString()))); + } + } +} \ No newline at end of file diff --git a/src/main/java/org/junit/internal/requests/MemoizingRequest.java b/src/main/java/org/junit/internal/requests/MemoizingRequest.java new file mode 100644 index 000000000000..191c23022536 --- /dev/null +++ b/src/main/java/org/junit/internal/requests/MemoizingRequest.java @@ -0,0 +1,30 @@ +package org.junit.internal.requests; + +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +import org.junit.runner.Request; +import org.junit.runner.Runner; + +abstract class MemoizingRequest extends Request { + private final Lock runnerLock = new ReentrantLock(); + private volatile Runner runner; + + @Override + public final Runner getRunner() { + if (runner == null) { + runnerLock.lock(); + try { + if (runner == null) { + runner = createRunner(); + } + } finally { + runnerLock.unlock(); + } + } + return runner; + } + + /** Creates the {@link Runner} to return from {@link #getRunner()}. Called at most once. */ + protected abstract Runner createRunner(); +} diff --git a/src/main/java/org/junit/internal/requests/OrderingRequest.java b/src/main/java/org/junit/internal/requests/OrderingRequest.java new file mode 100644 index 000000000000..441e595a3680 --- /dev/null +++ b/src/main/java/org/junit/internal/requests/OrderingRequest.java @@ -0,0 +1,29 @@ +package org.junit.internal.requests; + +import org.junit.internal.runners.ErrorReportingRunner; +import org.junit.runner.Request; +import org.junit.runner.Runner; +import org.junit.runner.manipulation.InvalidOrderingException; +import org.junit.runner.manipulation.Ordering; + +/** @since 4.13 */ +public class OrderingRequest extends MemoizingRequest { + private final Request request; + private final Ordering ordering; + + public OrderingRequest(Request request, Ordering ordering) { + this.request = request; + this.ordering = ordering; + } + + @Override + protected Runner createRunner() { + Runner runner = request.getRunner(); + try { + ordering.apply(runner); + } catch (InvalidOrderingException e) { + return new ErrorReportingRunner(ordering.getClass(), e); + } + return runner; + } +} diff --git a/src/main/java/org/junit/internal/requests/SortingRequest.java b/src/main/java/org/junit/internal/requests/SortingRequest.java new file mode 100644 index 000000000000..77061da27d5c --- /dev/null +++ b/src/main/java/org/junit/internal/requests/SortingRequest.java @@ -0,0 +1,25 @@ +package org.junit.internal.requests; + +import java.util.Comparator; + +import org.junit.runner.Description; +import org.junit.runner.Request; +import org.junit.runner.Runner; +import org.junit.runner.manipulation.Sorter; + +public class SortingRequest extends Request { + private final Request request; + private final Comparator comparator; + + public SortingRequest(Request request, Comparator comparator) { + this.request = request; + this.comparator = comparator; + } + + @Override + public Runner getRunner() { + Runner runner = request.getRunner(); + new Sorter(comparator).apply(runner); + return runner; + } +} diff --git a/src/main/java/org/junit/internal/requests/package-info.java b/src/main/java/org/junit/internal/requests/package-info.java new file mode 100644 index 000000000000..66d2928344d2 --- /dev/null +++ b/src/main/java/org/junit/internal/requests/package-info.java @@ -0,0 +1,6 @@ +/** + * Provides implementations of {@link org.junit.runner.Request}. + * + * @since 4.0 + */ +package org.junit.internal.requests; \ No newline at end of file diff --git a/src/main/java/org/junit/internal/runners/ClassRoadie.java b/src/main/java/org/junit/internal/runners/ClassRoadie.java new file mode 100644 index 000000000000..df1b45349ca6 --- /dev/null +++ b/src/main/java/org/junit/internal/runners/ClassRoadie.java @@ -0,0 +1,81 @@ +package org.junit.internal.runners; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.List; + +import org.junit.internal.AssumptionViolatedException; +import org.junit.runner.Description; +import org.junit.runner.notification.Failure; +import org.junit.runner.notification.RunNotifier; +import org.junit.runners.BlockJUnit4ClassRunner; + +/** + * @deprecated Included for backwards compatibility with JUnit 4.4. Will be + * removed in the next major release. Please use + * {@link BlockJUnit4ClassRunner} in place of {@link JUnit4ClassRunner}. + */ +@Deprecated +public class ClassRoadie { + private RunNotifier notifier; + private TestClass testClass; + private Description description; + private final Runnable runnable; + + public ClassRoadie(RunNotifier notifier, TestClass testClass, + Description description, Runnable runnable) { + this.notifier = notifier; + this.testClass = testClass; + this.description = description; + this.runnable = runnable; + } + + protected void runUnprotected() { + runnable.run(); + } + + protected void addFailure(Throwable targetException) { + notifier.fireTestFailure(new Failure(description, targetException)); + } + + public void runProtected() { + try { + runBefores(); + runUnprotected(); + } catch (FailedBefore e) { + } finally { + runAfters(); + } + } + + private void runBefores() throws FailedBefore { + try { + try { + List befores = testClass.getBefores(); + for (Method before : befores) { + before.invoke(null); + } + } catch (InvocationTargetException e) { + throw e.getTargetException(); + } + } catch (AssumptionViolatedException e) { + throw new FailedBefore(); + } catch (Throwable e) { + addFailure(e); + throw new FailedBefore(); + } + } + + private void runAfters() { + List afters = testClass.getAfters(); + for (Method after : afters) { + try { + after.invoke(null); + } catch (InvocationTargetException e) { + addFailure(e.getTargetException()); + } catch (Throwable e) { + addFailure(e); // Untested, but seems impossible + } + } + } +} diff --git a/src/main/java/org/junit/internal/runners/ErrorReportingRunner.java b/src/main/java/org/junit/internal/runners/ErrorReportingRunner.java new file mode 100644 index 000000000000..f52abab69439 --- /dev/null +++ b/src/main/java/org/junit/internal/runners/ErrorReportingRunner.java @@ -0,0 +1,92 @@ +package org.junit.internal.runners; + +import java.lang.reflect.InvocationTargetException; +import java.util.List; + +import org.junit.runner.Description; +import org.junit.runner.Runner; +import org.junit.runner.notification.Failure; +import org.junit.runner.notification.RunNotifier; +import org.junit.runners.model.InvalidTestClassError; +import org.junit.runners.model.InitializationError; + +import static java.util.Collections.singletonList; + +public class ErrorReportingRunner extends Runner { + private final List causes; + + private final String classNames; + + public ErrorReportingRunner(Class testClass, Throwable cause) { + this(cause, testClass); + } + + public ErrorReportingRunner(Throwable cause, Class... testClasses) { + if (testClasses == null || testClasses.length == 0) { + throw new NullPointerException("Test classes cannot be null or empty"); + } + for (Class testClass : testClasses) { + if (testClass == null) { + throw new NullPointerException("Test class cannot be null"); + } + } + classNames = getClassNames(testClasses); + causes = getCauses(cause); + } + + @Override + public Description getDescription() { + Description description = Description.createSuiteDescription(classNames); + for (Throwable each : causes) { + description.addChild(describeCause()); + } + return description; + } + + @Override + public void run(RunNotifier notifier) { + for (Throwable each : causes) { + runCause(each, notifier); + } + } + + private String getClassNames(Class... testClasses) { + final StringBuilder builder = new StringBuilder(); + for (Class testClass : testClasses) { + if (builder.length() != 0) { + builder.append(", "); + } + builder.append(testClass.getName()); + } + return builder.toString(); + } + + @SuppressWarnings("deprecation") + private List getCauses(Throwable cause) { + if (cause instanceof InvocationTargetException) { + return getCauses(cause.getCause()); + } + if (cause instanceof InvalidTestClassError) { + return singletonList(cause); + } + if (cause instanceof InitializationError) { + return ((InitializationError) cause).getCauses(); + } + if (cause instanceof org.junit.internal.runners.InitializationError) { + return ((org.junit.internal.runners.InitializationError) cause) + .getCauses(); + } + return singletonList(cause); + } + + private Description describeCause() { + return Description.createTestDescription(classNames, "initializationError"); + } + + private void runCause(Throwable child, RunNotifier notifier) { + Description description = describeCause(); + notifier.fireTestStarted(description); + notifier.fireTestFailure(new Failure(description, child)); + notifier.fireTestFinished(description); + } +} diff --git a/src/main/java/org/junit/internal/runners/FailedBefore.java b/src/main/java/org/junit/internal/runners/FailedBefore.java new file mode 100644 index 000000000000..1036cb69bf0a --- /dev/null +++ b/src/main/java/org/junit/internal/runners/FailedBefore.java @@ -0,0 +1,13 @@ +package org.junit.internal.runners; + +import org.junit.runners.BlockJUnit4ClassRunner; + +/** + * @deprecated Included for backwards compatibility with JUnit 4.4. Will be + * removed in the next major release. Please use + * {@link BlockJUnit4ClassRunner} in place of {@link JUnit4ClassRunner}. + */ +@Deprecated +class FailedBefore extends Exception { + private static final long serialVersionUID = 1L; +} \ No newline at end of file diff --git a/src/main/java/org/junit/internal/runners/InitializationError.java b/src/main/java/org/junit/internal/runners/InitializationError.java new file mode 100644 index 000000000000..484f58d26d69 --- /dev/null +++ b/src/main/java/org/junit/internal/runners/InitializationError.java @@ -0,0 +1,37 @@ +package org.junit.internal.runners; + +import java.util.Arrays; +import java.util.List; + +/** + * Use the published version: + * {@link org.junit.runners.model.InitializationError} + * This may disappear as soon as 1 April 2009 + */ +@Deprecated +public class InitializationError extends Exception { + private static final long serialVersionUID = 1L; + + /* + * We have to use the f prefix until the next major release to ensure + * serialization compatibility. + * See https://github.com/junit-team/junit4/issues/976 + */ + private final List fErrors; + + public InitializationError(List errors) { + this.fErrors = errors; + } + + public InitializationError(Throwable... errors) { + this(Arrays.asList(errors)); + } + + public InitializationError(String string) { + this(new Exception(string)); + } + + public List getCauses() { + return fErrors; + } +} diff --git a/src/main/java/org/junit/internal/runners/JUnit38ClassRunner.java b/src/main/java/org/junit/internal/runners/JUnit38ClassRunner.java new file mode 100644 index 000000000000..0d51541adcf8 --- /dev/null +++ b/src/main/java/org/junit/internal/runners/JUnit38ClassRunner.java @@ -0,0 +1,196 @@ +package org.junit.internal.runners; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; + +import junit.extensions.TestDecorator; +import junit.framework.AssertionFailedError; +import junit.framework.Test; +import junit.framework.TestCase; +import junit.framework.TestListener; +import junit.framework.TestResult; +import junit.framework.TestSuite; +import org.junit.runner.Describable; +import org.junit.runner.Description; +import org.junit.runner.Runner; +import org.junit.runner.manipulation.Filter; +import org.junit.runner.manipulation.Filterable; +import org.junit.runner.manipulation.Orderer; +import org.junit.runner.manipulation.InvalidOrderingException; +import org.junit.runner.manipulation.NoTestsRemainException; +import org.junit.runner.manipulation.Orderable; +import org.junit.runner.manipulation.Sortable; +import org.junit.runner.manipulation.Sorter; +import org.junit.runner.notification.Failure; +import org.junit.runner.notification.RunNotifier; + +public class JUnit38ClassRunner extends Runner implements Filterable, Orderable { + private static final class OldTestClassAdaptingListener implements + TestListener { + private final RunNotifier notifier; + + private OldTestClassAdaptingListener(RunNotifier notifier) { + this.notifier = notifier; + } + + public void endTest(Test test) { + notifier.fireTestFinished(asDescription(test)); + } + + public void startTest(Test test) { + notifier.fireTestStarted(asDescription(test)); + } + + // Implement junit.framework.TestListener + public void addError(Test test, Throwable e) { + Failure failure = new Failure(asDescription(test), e); + notifier.fireTestFailure(failure); + } + + private Description asDescription(Test test) { + if (test instanceof Describable) { + Describable facade = (Describable) test; + return facade.getDescription(); + } + return Description.createTestDescription(getEffectiveClass(test), getName(test)); + } + + private Class getEffectiveClass(Test test) { + return test.getClass(); + } + + private String getName(Test test) { + if (test instanceof TestCase) { + return ((TestCase) test).getName(); + } else { + return test.toString(); + } + } + + public void addFailure(Test test, AssertionFailedError t) { + addError(test, t); + } + } + + private volatile Test test; + + public JUnit38ClassRunner(Class klass) { + this(new TestSuite(klass.asSubclass(TestCase.class))); + } + + public JUnit38ClassRunner(Test test) { + super(); + setTest(test); + } + + @Override + public void run(RunNotifier notifier) { + TestResult result = new TestResult(); + result.addListener(createAdaptingListener(notifier)); + getTest().run(result); + } + + public TestListener createAdaptingListener(final RunNotifier notifier) { + return new OldTestClassAdaptingListener(notifier); + } + + @Override + public Description getDescription() { + return makeDescription(getTest()); + } + + private static Description makeDescription(Test test) { + if (test instanceof TestCase) { + TestCase tc = (TestCase) test; + return Description.createTestDescription(tc.getClass(), tc.getName(), + getAnnotations(tc)); + } else if (test instanceof TestSuite) { + TestSuite ts = (TestSuite) test; + String name = ts.getName() == null ? createSuiteDescription(ts) : ts.getName(); + Description description = Description.createSuiteDescription(name); + int n = ts.testCount(); + for (int i = 0; i < n; i++) { + Description made = makeDescription(ts.testAt(i)); + description.addChild(made); + } + return description; + } else if (test instanceof Describable) { + Describable adapter = (Describable) test; + return adapter.getDescription(); + } else if (test instanceof TestDecorator) { + TestDecorator decorator = (TestDecorator) test; + return makeDescription(decorator.getTest()); + } else { + // This is the best we can do in this case + return Description.createSuiteDescription(test.getClass()); + } + } + + /** + * Get the annotations associated with given TestCase. + * @param test the TestCase. + */ + private static Annotation[] getAnnotations(TestCase test) { + try { + Method m = test.getClass().getMethod(test.getName()); + return m.getDeclaredAnnotations(); + } catch (SecurityException e) { + } catch (NoSuchMethodException e) { + } + return new Annotation[0]; + } + + private static String createSuiteDescription(TestSuite ts) { + int count = ts.countTestCases(); + String example = count == 0 ? "" : String.format(" [example: %s]", ts.testAt(0)); + return String.format("TestSuite with %s tests%s", count, example); + } + + public void filter(Filter filter) throws NoTestsRemainException { + if (getTest() instanceof Filterable) { + Filterable adapter = (Filterable) getTest(); + adapter.filter(filter); + } else if (getTest() instanceof TestSuite) { + TestSuite suite = (TestSuite) getTest(); + TestSuite filtered = new TestSuite(suite.getName()); + int n = suite.testCount(); + for (int i = 0; i < n; i++) { + Test test = suite.testAt(i); + if (filter.shouldRun(makeDescription(test))) { + filtered.addTest(test); + } + } + setTest(filtered); + if (filtered.testCount() == 0) { + throw new NoTestsRemainException(); + } + } + } + + public void sort(Sorter sorter) { + if (getTest() instanceof Sortable) { + Sortable adapter = (Sortable) getTest(); + adapter.sort(sorter); + } + } + + /** + * {@inheritDoc} + * + * @since 4.13 + */ + public void order(Orderer orderer) throws InvalidOrderingException { + if (getTest() instanceof Orderable) { + Orderable adapter = (Orderable) getTest(); + adapter.order(orderer); + } + } + + private void setTest(Test test) { + this.test = test; + } + + private Test getTest() { + return test; + } +} diff --git a/src/main/java/org/junit/internal/runners/JUnit4ClassRunner.java b/src/main/java/org/junit/internal/runners/JUnit4ClassRunner.java new file mode 100644 index 000000000000..69a23c448ccd --- /dev/null +++ b/src/main/java/org/junit/internal/runners/JUnit4ClassRunner.java @@ -0,0 +1,147 @@ +package org.junit.internal.runners; + +import java.lang.annotation.Annotation; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Collections; +import java.util.Comparator; +import java.util.Iterator; +import java.util.List; + +import org.junit.runner.Description; +import org.junit.runner.Runner; +import org.junit.runner.manipulation.Filter; +import org.junit.runner.manipulation.Filterable; +import org.junit.runner.manipulation.NoTestsRemainException; +import org.junit.runner.manipulation.Sortable; +import org.junit.runner.manipulation.Sorter; +import org.junit.runner.notification.Failure; +import org.junit.runner.notification.RunNotifier; +import org.junit.runners.BlockJUnit4ClassRunner; + +/** + * @deprecated Included for backwards compatibility with JUnit 4.4. Will be + * removed in the next major release. Please use + * {@link BlockJUnit4ClassRunner} in place of {@link JUnit4ClassRunner}. + */ +@Deprecated +public class JUnit4ClassRunner extends Runner implements Filterable, Sortable { + private final List testMethods; + private TestClass testClass; + + public JUnit4ClassRunner(Class klass) throws InitializationError { + testClass = new TestClass(klass); + testMethods = getTestMethods(); + validate(); + } + + protected List getTestMethods() { + return testClass.getTestMethods(); + } + + protected void validate() throws InitializationError { + MethodValidator methodValidator = new MethodValidator(testClass); + methodValidator.validateMethodsForDefaultRunner(); + methodValidator.assertValid(); + } + + @Override + public void run(final RunNotifier notifier) { + new ClassRoadie(notifier, testClass, getDescription(), new Runnable() { + public void run() { + runMethods(notifier); + } + }).runProtected(); + } + + protected void runMethods(final RunNotifier notifier) { + for (Method method : testMethods) { + invokeTestMethod(method, notifier); + } + } + + @Override + public Description getDescription() { + Description spec = Description.createSuiteDescription(getName(), classAnnotations()); + List testMethods = this.testMethods; + for (Method method : testMethods) { + spec.addChild(methodDescription(method)); + } + return spec; + } + + protected Annotation[] classAnnotations() { + return testClass.getJavaClass().getAnnotations(); + } + + protected String getName() { + return getTestClass().getName(); + } + + protected Object createTest() throws Exception { + return getTestClass().getConstructor().newInstance(); + } + + protected void invokeTestMethod(Method method, RunNotifier notifier) { + Description description = methodDescription(method); + Object test; + try { + test = createTest(); + } catch (InvocationTargetException e) { + testAborted(notifier, description, e.getCause()); + return; + } catch (Exception e) { + testAborted(notifier, description, e); + return; + } + TestMethod testMethod = wrapMethod(method); + new MethodRoadie(test, testMethod, notifier, description).run(); + } + + private void testAborted(RunNotifier notifier, Description description, + Throwable e) { + notifier.fireTestStarted(description); + notifier.fireTestFailure(new Failure(description, e)); + notifier.fireTestFinished(description); + } + + protected TestMethod wrapMethod(Method method) { + return new TestMethod(method, testClass); + } + + protected String testName(Method method) { + return method.getName(); + } + + protected Description methodDescription(Method method) { + return Description.createTestDescription(getTestClass().getJavaClass(), testName(method), testAnnotations(method)); + } + + protected Annotation[] testAnnotations(Method method) { + return method.getAnnotations(); + } + + public void filter(Filter filter) throws NoTestsRemainException { + for (Iterator iter = testMethods.iterator(); iter.hasNext(); ) { + Method method = iter.next(); + if (!filter.shouldRun(methodDescription(method))) { + iter.remove(); + } + } + if (testMethods.isEmpty()) { + throw new NoTestsRemainException(); + } + } + + public void sort(final Sorter sorter) { + Collections.sort(testMethods, new Comparator() { + public int compare(Method o1, Method o2) { + return sorter.compare(methodDescription(o1), methodDescription(o2)); + } + }); + } + + protected TestClass getTestClass() { + return testClass; + } +} \ No newline at end of file diff --git a/src/main/java/org/junit/internal/runners/MethodRoadie.java b/src/main/java/org/junit/internal/runners/MethodRoadie.java new file mode 100644 index 000000000000..01a476bd7341 --- /dev/null +++ b/src/main/java/org/junit/internal/runners/MethodRoadie.java @@ -0,0 +1,163 @@ +package org.junit.internal.runners; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.List; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +import org.junit.internal.AssumptionViolatedException; +import org.junit.runner.Description; +import org.junit.runner.notification.Failure; +import org.junit.runner.notification.RunNotifier; +import org.junit.runners.BlockJUnit4ClassRunner; +import org.junit.runners.model.TestTimedOutException; + +/** + * @deprecated Included for backwards compatibility with JUnit 4.4. Will be + * removed in the next major release. Please use + * {@link BlockJUnit4ClassRunner} in place of {@link JUnit4ClassRunner}. + */ +@Deprecated +public class MethodRoadie { + private final Object test; + private final RunNotifier notifier; + private final Description description; + private TestMethod testMethod; + + public MethodRoadie(Object test, TestMethod method, RunNotifier notifier, Description description) { + this.test = test; + this.notifier = notifier; + this.description = description; + testMethod = method; + } + + public void run() { + if (testMethod.isIgnored()) { + notifier.fireTestIgnored(description); + return; + } + notifier.fireTestStarted(description); + try { + long timeout = testMethod.getTimeout(); + if (timeout > 0) { + runWithTimeout(timeout); + } else { + runTest(); + } + } finally { + notifier.fireTestFinished(description); + } + } + + private void runWithTimeout(final long timeout) { + runBeforesThenTestThenAfters(new Runnable() { + + public void run() { + ExecutorService service = Executors.newSingleThreadExecutor(); + Callable callable = new Callable() { + public Object call() throws Exception { + runTestMethod(); + return null; + } + }; + Future result = service.submit(callable); + service.shutdown(); + try { + boolean terminated = service.awaitTermination(timeout, + TimeUnit.MILLISECONDS); + if (!terminated) { + service.shutdownNow(); + } + result.get(0, TimeUnit.MILLISECONDS); // throws the exception if one occurred during the invocation + } catch (TimeoutException e) { + addFailure(new TestTimedOutException(timeout, TimeUnit.MILLISECONDS)); + } catch (Exception e) { + addFailure(e); + } + } + }); + } + + public void runTest() { + runBeforesThenTestThenAfters(new Runnable() { + public void run() { + runTestMethod(); + } + }); + } + + public void runBeforesThenTestThenAfters(Runnable test) { + try { + runBefores(); + test.run(); + } catch (FailedBefore e) { + } catch (Exception e) { + throw new RuntimeException("test should never throw an exception to this level"); + } finally { + runAfters(); + } + } + + protected void runTestMethod() { + try { + testMethod.invoke(test); + if (testMethod.expectsException()) { + addFailure(new AssertionError("Expected exception: " + testMethod.getExpectedException().getName())); + } + } catch (InvocationTargetException e) { + Throwable actual = e.getTargetException(); + if (actual instanceof AssumptionViolatedException) { + return; + } else if (!testMethod.expectsException()) { + addFailure(actual); + } else if (testMethod.isUnexpected(actual)) { + String message = "Unexpected exception, expected<" + testMethod.getExpectedException().getName() + "> but was<" + + actual.getClass().getName() + ">"; + addFailure(new Exception(message, actual)); + } + } catch (Throwable e) { + addFailure(e); + } + } + + private void runBefores() throws FailedBefore { + try { + try { + List befores = testMethod.getBefores(); + for (Method before : befores) { + before.invoke(test); + } + } catch (InvocationTargetException e) { + throw e.getTargetException(); + } + } catch (AssumptionViolatedException e) { + throw new FailedBefore(); + } catch (Throwable e) { + addFailure(e); + throw new FailedBefore(); + } + } + + private void runAfters() { + List afters = testMethod.getAfters(); + for (Method after : afters) { + try { + after.invoke(test); + } catch (InvocationTargetException e) { + addFailure(e.getTargetException()); + } catch (Throwable e) { + addFailure(e); // Untested, but seems impossible + } + } + } + + protected void addFailure(Throwable e) { + notifier.fireTestFailure(new Failure(description, e)); + } +} + diff --git a/src/main/java/org/junit/internal/runners/MethodValidator.java b/src/main/java/org/junit/internal/runners/MethodValidator.java new file mode 100644 index 000000000000..e656ee50efea --- /dev/null +++ b/src/main/java/org/junit/internal/runners/MethodValidator.java @@ -0,0 +1,97 @@ +package org.junit.internal.runners; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.List; + +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runners.BlockJUnit4ClassRunner; + +/** + * @deprecated Included for backwards compatibility with JUnit 4.4. Will be + * removed in the next major release. Please use + * {@link BlockJUnit4ClassRunner} in place of {@link JUnit4ClassRunner}. + */ +@Deprecated +public class MethodValidator { + + private final List errors = new ArrayList(); + + private TestClass testClass; + + public MethodValidator(TestClass testClass) { + this.testClass = testClass; + } + + public void validateInstanceMethods() { + validateTestMethods(After.class, false); + validateTestMethods(Before.class, false); + validateTestMethods(Test.class, false); + + List methods = testClass.getAnnotatedMethods(Test.class); + if (methods.size() == 0) { + errors.add(new Exception("No runnable methods")); + } + } + + public void validateStaticMethods() { + validateTestMethods(BeforeClass.class, true); + validateTestMethods(AfterClass.class, true); + } + + public List validateMethodsForDefaultRunner() { + validateNoArgConstructor(); + validateStaticMethods(); + validateInstanceMethods(); + return errors; + } + + public void assertValid() throws InitializationError { + if (!errors.isEmpty()) { + throw new InitializationError(errors); + } + } + + public void validateNoArgConstructor() { + try { + testClass.getConstructor(); + } catch (Exception e) { + errors.add(new Exception("Test class should have public zero-argument constructor", e)); + } + } + + private void validateTestMethods(Class annotation, + boolean isStatic) { + List methods = testClass.getAnnotatedMethods(annotation); + + for (Method each : methods) { + if (Modifier.isStatic(each.getModifiers()) != isStatic) { + String state = isStatic ? "should" : "should not"; + errors.add(new Exception("Method " + each.getName() + "() " + + state + " be static")); + } + if (!Modifier.isPublic(each.getDeclaringClass().getModifiers())) { + errors.add(new Exception("Class " + each.getDeclaringClass().getName() + + " should be public")); + } + if (!Modifier.isPublic(each.getModifiers())) { + errors.add(new Exception("Method " + each.getName() + + " should be public")); + } + if (each.getReturnType() != Void.TYPE) { + errors.add(new Exception("Method " + each.getName() + + "should have a return type of void")); + } + if (each.getParameterTypes().length != 0) { + errors.add(new Exception("Method " + each.getName() + + " should have no parameters")); + } + } + } +} diff --git a/src/main/java/org/junit/internal/runners/SuiteMethod.java b/src/main/java/org/junit/internal/runners/SuiteMethod.java new file mode 100644 index 000000000000..e336983caa80 --- /dev/null +++ b/src/main/java/org/junit/internal/runners/SuiteMethod.java @@ -0,0 +1,41 @@ +package org.junit.internal.runners; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; + +import junit.framework.Test; + +/** + * Runner for use with JUnit 3.8.x-style AllTests classes + * (those that only implement a static suite() + * method). For example: + *
    + * @RunWith(AllTests.class)
    + * public class ProductTests {
    + *    public static junit.framework.Test suite() {
    + *       ...
    + *    }
    + * }
    + * 
    + */ +public class SuiteMethod extends JUnit38ClassRunner { + public SuiteMethod(Class klass) throws Throwable { + super(testFromSuiteMethod(klass)); + } + + public static Test testFromSuiteMethod(Class klass) throws Throwable { + Method suiteMethod = null; + Test suite = null; + try { + suiteMethod = klass.getMethod("suite"); + if (!Modifier.isStatic(suiteMethod.getModifiers())) { + throw new Exception(klass.getName() + ".suite() must be static"); + } + suite = (Test) suiteMethod.invoke(null); // static method + } catch (InvocationTargetException e) { + throw e.getCause(); + } + return suite; + } +} diff --git a/src/main/java/org/junit/internal/runners/TestClass.java b/src/main/java/org/junit/internal/runners/TestClass.java new file mode 100644 index 000000000000..6d24f4fb05af --- /dev/null +++ b/src/main/java/org/junit/internal/runners/TestClass.java @@ -0,0 +1,109 @@ +package org.junit.internal.runners; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.internal.MethodSorter; +import org.junit.runners.BlockJUnit4ClassRunner; + +/** + * @deprecated Included for backwards compatibility with JUnit 4.4. Will be + * removed in the next major release. Please use + * {@link BlockJUnit4ClassRunner} in place of {@link JUnit4ClassRunner}. + */ +@Deprecated +public class TestClass { + private final Class klass; + + public TestClass(Class klass) { + this.klass = klass; + } + + public List getTestMethods() { + return getAnnotatedMethods(Test.class); + } + + List getBefores() { + return getAnnotatedMethods(BeforeClass.class); + } + + List getAfters() { + return getAnnotatedMethods(AfterClass.class); + } + + public List getAnnotatedMethods(Class annotationClass) { + List results = new ArrayList(); + for (Class eachClass : getSuperClasses(klass)) { + Method[] methods = MethodSorter.getDeclaredMethods(eachClass); + for (Method eachMethod : methods) { + Annotation annotation = eachMethod.getAnnotation(annotationClass); + if (annotation != null && !isShadowed(eachMethod, results)) { + results.add(eachMethod); + } + } + } + if (runsTopToBottom(annotationClass)) { + Collections.reverse(results); + } + return results; + } + + private boolean runsTopToBottom(Class annotation) { + return annotation.equals(Before.class) || annotation.equals(BeforeClass.class); + } + + private boolean isShadowed(Method method, List results) { + for (Method each : results) { + if (isShadowed(method, each)) { + return true; + } + } + return false; + } + + private boolean isShadowed(Method current, Method previous) { + if (!previous.getName().equals(current.getName())) { + return false; + } + if (previous.getParameterTypes().length != current.getParameterTypes().length) { + return false; + } + for (int i = 0; i < previous.getParameterTypes().length; i++) { + if (!previous.getParameterTypes()[i].equals(current.getParameterTypes()[i])) { + return false; + } + } + return true; + } + + private List> getSuperClasses(Class testClass) { + List> results = new ArrayList>(); + Class current = testClass; + while (current != null) { + results.add(current); + current = current.getSuperclass(); + } + return results; + } + + public Constructor getConstructor() throws SecurityException, NoSuchMethodException { + return klass.getConstructor(); + } + + public Class getJavaClass() { + return klass; + } + + public String getName() { + return klass.getName(); + } + +} diff --git a/src/main/java/org/junit/internal/runners/TestMethod.java b/src/main/java/org/junit/internal/runners/TestMethod.java new file mode 100644 index 000000000000..821e193d53af --- /dev/null +++ b/src/main/java/org/junit/internal/runners/TestMethod.java @@ -0,0 +1,71 @@ +package org.junit.internal.runners; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.List; + +import org.junit.After; +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Test; +import org.junit.Test.None; +import org.junit.runners.BlockJUnit4ClassRunner; + +/** + * @deprecated Included for backwards compatibility with JUnit 4.4. Will be + * removed in the next major release. Please use + * {@link BlockJUnit4ClassRunner} in place of {@link JUnit4ClassRunner}. + */ +@Deprecated +public class TestMethod { + private final Method method; + private TestClass testClass; + + public TestMethod(Method method, TestClass testClass) { + this.method = method; + this.testClass = testClass; + } + + public boolean isIgnored() { + return method.getAnnotation(Ignore.class) != null; + } + + public long getTimeout() { + Test annotation = method.getAnnotation(Test.class); + if (annotation == null) { + return 0; + } + long timeout = annotation.timeout(); + return timeout; + } + + protected Class getExpectedException() { + Test annotation = method.getAnnotation(Test.class); + if (annotation == null || annotation.expected() == None.class) { + return null; + } else { + return annotation.expected(); + } + } + + boolean isUnexpected(Throwable exception) { + return !getExpectedException().isAssignableFrom(exception.getClass()); + } + + boolean expectsException() { + return getExpectedException() != null; + } + + List getBefores() { + return testClass.getAnnotatedMethods(Before.class); + } + + List getAfters() { + return testClass.getAnnotatedMethods(After.class); + } + + public void invoke(Object test) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException { + method.invoke(test); + } + +} diff --git a/src/main/java/org/junit/internal/runners/model/EachTestNotifier.java b/src/main/java/org/junit/internal/runners/model/EachTestNotifier.java new file mode 100644 index 000000000000..c5a0764e6a47 --- /dev/null +++ b/src/main/java/org/junit/internal/runners/model/EachTestNotifier.java @@ -0,0 +1,71 @@ +package org.junit.internal.runners.model; + +import org.junit.internal.AssumptionViolatedException; +import org.junit.runner.Description; +import org.junit.runner.notification.Failure; +import org.junit.runner.notification.RunNotifier; +import org.junit.runners.model.MultipleFailureException; + +public class EachTestNotifier { + private final RunNotifier notifier; + + private final Description description; + + public EachTestNotifier(RunNotifier notifier, Description description) { + this.notifier = notifier; + this.description = description; + } + + public void addFailure(Throwable targetException) { + if (targetException instanceof MultipleFailureException) { + addMultipleFailureException((MultipleFailureException) targetException); + } else { + notifier.fireTestFailure(new Failure(description, targetException)); + } + } + + private void addMultipleFailureException(MultipleFailureException mfe) { + for (Throwable each : mfe.getFailures()) { + addFailure(each); + } + } + + public void addFailedAssumption(AssumptionViolatedException e) { + notifier.fireTestAssumptionFailed(new Failure(description, e)); + } + + public void fireTestFinished() { + notifier.fireTestFinished(description); + } + + public void fireTestStarted() { + notifier.fireTestStarted(description); + } + + public void fireTestIgnored() { + notifier.fireTestIgnored(description); + } + + /** + * Calls {@link RunNotifier#fireTestSuiteStarted(Description)}, passing the + * {@link Description} that was passed to the {@code EachTestNotifier} constructor. + * This should be called when a test suite is about to be started. + * @see RunNotifier#fireTestSuiteStarted(Description) + * @since 4.13 + */ + public void fireTestSuiteStarted() { + notifier.fireTestSuiteStarted(description); + } + + /** + * Calls {@link RunNotifier#fireTestSuiteFinished(Description)}, passing the + * {@link Description} that was passed to the {@code EachTestNotifier} constructor. + * This should be called when a test suite has finished, whether the test suite succeeds + * or fails. + * @see RunNotifier#fireTestSuiteFinished(Description) + * @since 4.13 + */ + public void fireTestSuiteFinished() { + notifier.fireTestSuiteFinished(description); + } +} \ No newline at end of file diff --git a/src/main/java/org/junit/internal/runners/model/MultipleFailureException.java b/src/main/java/org/junit/internal/runners/model/MultipleFailureException.java new file mode 100644 index 000000000000..054f0428b4bc --- /dev/null +++ b/src/main/java/org/junit/internal/runners/model/MultipleFailureException.java @@ -0,0 +1,12 @@ +package org.junit.internal.runners.model; + +import java.util.List; + +@Deprecated +public class MultipleFailureException extends org.junit.runners.model.MultipleFailureException { + private static final long serialVersionUID = 1L; + + public MultipleFailureException(List errors) { + super(errors); + } +} diff --git a/src/main/java/org/junit/internal/runners/model/ReflectiveCallable.java b/src/main/java/org/junit/internal/runners/model/ReflectiveCallable.java new file mode 100644 index 000000000000..79d5c05f3af7 --- /dev/null +++ b/src/main/java/org/junit/internal/runners/model/ReflectiveCallable.java @@ -0,0 +1,19 @@ +package org.junit.internal.runners.model; + +import java.lang.reflect.InvocationTargetException; + +/** + * When invoked, throws the exception from the reflected method, rather than + * wrapping it in an InvocationTargetException. + */ +public abstract class ReflectiveCallable { + public Object run() throws Throwable { + try { + return runReflectiveCall(); + } catch (InvocationTargetException e) { + throw e.getTargetException(); + } + } + + protected abstract Object runReflectiveCall() throws Throwable; +} \ No newline at end of file diff --git a/src/main/java/org/junit/internal/runners/package-info.java b/src/main/java/org/junit/internal/runners/package-info.java new file mode 100644 index 000000000000..5ab7e7bd42f1 --- /dev/null +++ b/src/main/java/org/junit/internal/runners/package-info.java @@ -0,0 +1,6 @@ +/** + * Provides implementations of {@link org.junit.runner.Runner} + * + * @since 4.0 + */ +package org.junit.internal.runners; \ No newline at end of file diff --git a/src/main/java/org/junit/internal/runners/rules/RuleMemberValidator.java b/src/main/java/org/junit/internal/runners/rules/RuleMemberValidator.java new file mode 100644 index 000000000000..36de4f106297 --- /dev/null +++ b/src/main/java/org/junit/internal/runners/rules/RuleMemberValidator.java @@ -0,0 +1,279 @@ +package org.junit.internal.runners.rules; + +import org.junit.ClassRule; +import org.junit.Rule; +import org.junit.rules.MethodRule; +import org.junit.rules.TestRule; +import org.junit.runners.model.FrameworkMember; +import org.junit.runners.model.TestClass; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.List; + +/** + * A RuleMemberValidator validates the rule fields/methods of a + * {@link org.junit.runners.model.TestClass}. All reasons for rejecting the + * {@code TestClass} are written to a list of errors. + * + *

    There are four slightly different validators. The {@link #CLASS_RULE_VALIDATOR} + * validates fields with a {@link ClassRule} annotation and the + * {@link #RULE_VALIDATOR} validates fields with a {@link Rule} annotation.

    + * + *

    The {@link #CLASS_RULE_METHOD_VALIDATOR} + * validates methods with a {@link ClassRule} annotation and the + * {@link #RULE_METHOD_VALIDATOR} validates methods with a {@link Rule} annotation.

    + */ +public class RuleMemberValidator { + /** + * Validates fields with a {@link ClassRule} annotation. + */ + public static final RuleMemberValidator CLASS_RULE_VALIDATOR = + classRuleValidatorBuilder() + .withValidator(new DeclaringClassMustBePublic()) + .withValidator(new MemberMustBeStatic()) + .withValidator(new MemberMustBePublic()) + .withValidator(new FieldMustBeATestRule()) + .build(); + /** + * Validates fields with a {@link Rule} annotation. + */ + public static final RuleMemberValidator RULE_VALIDATOR = + testRuleValidatorBuilder() + .withValidator(new MemberMustBeNonStaticOrAlsoClassRule()) + .withValidator(new MemberMustBePublic()) + .withValidator(new FieldMustBeARule()) + .build(); + /** + * Validates methods with a {@link ClassRule} annotation. + */ + public static final RuleMemberValidator CLASS_RULE_METHOD_VALIDATOR = + classRuleValidatorBuilder() + .forMethods() + .withValidator(new DeclaringClassMustBePublic()) + .withValidator(new MemberMustBeStatic()) + .withValidator(new MemberMustBePublic()) + .withValidator(new MethodMustBeATestRule()) + .build(); + + /** + * Validates methods with a {@link Rule} annotation. + */ + public static final RuleMemberValidator RULE_METHOD_VALIDATOR = + testRuleValidatorBuilder() + .forMethods() + .withValidator(new MemberMustBeNonStaticOrAlsoClassRule()) + .withValidator(new MemberMustBePublic()) + .withValidator(new MethodMustBeARule()) + .build(); + + private final Class annotation; + private final boolean methods; + private final List validatorStrategies; + + RuleMemberValidator(Builder builder) { + this.annotation = builder.annotation; + this.methods = builder.methods; + this.validatorStrategies = builder.validators; + } + + /** + * Validate the {@link org.junit.runners.model.TestClass} and adds reasons + * for rejecting the class to a list of errors. + * + * @param target the {@code TestClass} to validate. + * @param errors the list of errors. + */ + public void validate(TestClass target, List errors) { + List> members = methods ? target.getAnnotatedMethods(annotation) + : target.getAnnotatedFields(annotation); + + for (FrameworkMember each : members) { + validateMember(each, errors); + } + } + + private void validateMember(FrameworkMember member, List errors) { + for (RuleValidator strategy : validatorStrategies) { + strategy.validate(member, annotation, errors); + } + } + + private static Builder classRuleValidatorBuilder() { + return new Builder(ClassRule.class); + } + + private static Builder testRuleValidatorBuilder() { + return new Builder(Rule.class); + } + + private static class Builder { + private final Class annotation; + private boolean methods; + private final List validators; + + private Builder(Class annotation) { + this.annotation = annotation; + this.methods = false; + this.validators = new ArrayList(); + } + + Builder forMethods() { + methods = true; + return this; + } + + Builder withValidator(RuleValidator validator) { + validators.add(validator); + return this; + } + + RuleMemberValidator build() { + return new RuleMemberValidator(this); + } + } + + private static boolean isRuleType(FrameworkMember member) { + return isMethodRule(member) || isTestRule(member); + } + + private static boolean isTestRule(FrameworkMember member) { + return TestRule.class.isAssignableFrom(member.getType()); + } + + private static boolean isMethodRule(FrameworkMember member) { + return MethodRule.class.isAssignableFrom(member.getType()); + } + + /** + * Encapsulates a single piece of validation logic, used to determine if {@link org.junit.Rule} and + * {@link org.junit.ClassRule} annotations have been used correctly + */ + interface RuleValidator { + /** + * Examine the given member and add any violations of the strategy's validation logic to the given list of errors + * @param member The member (field or member) to examine + * @param annotation The type of rule annotation on the member + * @param errors The list of errors to add validation violations to + */ + void validate(FrameworkMember member, Class annotation, List errors); + } + + /** + * Requires the validated member to be non-static + */ + private static final class MemberMustBeNonStaticOrAlsoClassRule implements RuleValidator { + public void validate(FrameworkMember member, Class annotation, List errors) { + boolean isMethodRuleMember = isMethodRule(member); + boolean isClassRuleAnnotated = (member.getAnnotation(ClassRule.class) != null); + + // We disallow: + // - static MethodRule members + // - static @Rule annotated members + // - UNLESS they're also @ClassRule annotated + // Note that MethodRule cannot be annotated with @ClassRule + if (member.isStatic() && (isMethodRuleMember || !isClassRuleAnnotated)) { + String message; + if (isMethodRule(member)) { + message = "must not be static."; + } else { + message = "must not be static or it must be annotated with @ClassRule."; + } + errors.add(new ValidationError(member, annotation, message)); + } + } + } + + /** + * Requires the member to be static + */ + private static final class MemberMustBeStatic implements RuleValidator { + public void validate(FrameworkMember member, Class annotation, List errors) { + if (!member.isStatic()) { + errors.add(new ValidationError(member, annotation, + "must be static.")); + } + } + } + + /** + * Requires the member's declaring class to be public + */ + private static final class DeclaringClassMustBePublic implements RuleValidator { + public void validate(FrameworkMember member, Class annotation, List errors) { + if (!isDeclaringClassPublic(member)) { + errors.add(new ValidationError(member, annotation, + "must be declared in a public class.")); + } + } + + private boolean isDeclaringClassPublic(FrameworkMember member) { + return Modifier.isPublic(member.getDeclaringClass().getModifiers()); + } + } + + /** + * Requires the member to be public + */ + private static final class MemberMustBePublic implements RuleValidator { + public void validate(FrameworkMember member, Class annotation, List errors) { + if (!member.isPublic()) { + errors.add(new ValidationError(member, annotation, + "must be public.")); + } + } + } + + /** + * Requires the member is a field implementing {@link org.junit.rules.MethodRule} or {@link org.junit.rules.TestRule} + */ + private static final class FieldMustBeARule implements RuleValidator { + public void validate(FrameworkMember member, Class annotation, List errors) { + if (!isRuleType(member)) { + errors.add(new ValidationError(member, annotation, + "must implement MethodRule or TestRule.")); + } + } + } + + /** + * Require the member to return an implementation of {@link org.junit.rules.MethodRule} or + * {@link org.junit.rules.TestRule} + */ + private static final class MethodMustBeARule implements RuleValidator { + public void validate(FrameworkMember member, Class annotation, List errors) { + if (!isRuleType(member)) { + errors.add(new ValidationError(member, annotation, + "must return an implementation of MethodRule or TestRule.")); + } + } + } + + /** + * Require the member to return an implementation of {@link org.junit.rules.TestRule} + */ + private static final class MethodMustBeATestRule implements RuleValidator { + public void validate(FrameworkMember member, + Class annotation, List errors) { + if (!isTestRule(member)) { + errors.add(new ValidationError(member, annotation, + "must return an implementation of TestRule.")); + } + } + } + + /** + * Requires the member is a field implementing {@link org.junit.rules.TestRule} + */ + private static final class FieldMustBeATestRule implements RuleValidator { + + public void validate(FrameworkMember member, + Class annotation, List errors) { + if (!isTestRule(member)) { + errors.add(new ValidationError(member, annotation, + "must implement TestRule.")); + } + } + } +} diff --git a/src/main/java/org/junit/internal/runners/rules/ValidationError.java b/src/main/java/org/junit/internal/runners/rules/ValidationError.java new file mode 100644 index 000000000000..31bd66019e09 --- /dev/null +++ b/src/main/java/org/junit/internal/runners/rules/ValidationError.java @@ -0,0 +1,14 @@ +package org.junit.internal.runners.rules; + +import org.junit.runners.model.FrameworkMember; + +import java.lang.annotation.Annotation; + +class ValidationError extends Exception { + + private static final long serialVersionUID = 3176511008672645574L; + + public ValidationError(FrameworkMember member, Class annotation, String suffix) { + super(String.format("The @%s '%s' %s", annotation.getSimpleName(), member.getName(), suffix)); + } +} diff --git a/src/main/java/org/junit/internal/runners/statements/ExpectException.java b/src/main/java/org/junit/internal/runners/statements/ExpectException.java new file mode 100644 index 000000000000..9a2a952858a3 --- /dev/null +++ b/src/main/java/org/junit/internal/runners/statements/ExpectException.java @@ -0,0 +1,38 @@ +package org.junit.internal.runners.statements; + +import org.junit.internal.AssumptionViolatedException; +import org.junit.runners.model.Statement; + +public class ExpectException extends Statement { + private final Statement next; + private final Class expected; + + public ExpectException(Statement next, Class expected) { + this.next = next; + this.expected = expected; + } + + @Override + public void evaluate() throws Exception { + boolean complete = false; + try { + next.evaluate(); + complete = true; + } catch (AssumptionViolatedException e) { + if (!expected.isAssignableFrom(e.getClass())) { + throw e; + } + } catch (Throwable e) { + if (!expected.isAssignableFrom(e.getClass())) { + String message = "Unexpected exception, expected<" + + expected.getName() + "> but was<" + + e.getClass().getName() + ">"; + throw new Exception(message, e); + } + } + if (complete) { + throw new AssertionError("Expected exception: " + + expected.getName()); + } + } +} \ No newline at end of file diff --git a/src/main/java/org/junit/internal/runners/statements/Fail.java b/src/main/java/org/junit/internal/runners/statements/Fail.java new file mode 100644 index 000000000000..e55875c14659 --- /dev/null +++ b/src/main/java/org/junit/internal/runners/statements/Fail.java @@ -0,0 +1,16 @@ +package org.junit.internal.runners.statements; + +import org.junit.runners.model.Statement; + +public class Fail extends Statement { + private final Throwable error; + + public Fail(Throwable e) { + error = e; + } + + @Override + public void evaluate() throws Throwable { + throw error; + } +} diff --git a/src/main/java/org/junit/internal/runners/statements/FailOnTimeout.java b/src/main/java/org/junit/internal/runners/statements/FailOnTimeout.java new file mode 100644 index 000000000000..94c12e6e9770 --- /dev/null +++ b/src/main/java/org/junit/internal/runners/statements/FailOnTimeout.java @@ -0,0 +1,301 @@ +package org.junit.internal.runners.statements; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.Callable; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.FutureTask; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +import org.junit.internal.management.ManagementFactory; +import org.junit.internal.management.ThreadMXBean; +import org.junit.runners.model.MultipleFailureException; +import org.junit.runners.model.Statement; +import org.junit.runners.model.TestTimedOutException; + +public class FailOnTimeout extends Statement { + private final Statement originalStatement; + private final TimeUnit timeUnit; + private final long timeout; + private final boolean lookForStuckThread; + + /** + * Returns a new builder for building an instance. + * + * @since 4.12 + */ + public static Builder builder() { + return new Builder(); + } + + /** + * Creates an instance wrapping the given statement with the given timeout in milliseconds. + * + * @param statement the statement to wrap + * @param timeoutMillis the timeout in milliseconds + * @deprecated use {@link #builder()} instead. + */ + @Deprecated + public FailOnTimeout(Statement statement, long timeoutMillis) { + this(builder().withTimeout(timeoutMillis, TimeUnit.MILLISECONDS), statement); + } + + private FailOnTimeout(Builder builder, Statement statement) { + originalStatement = statement; + timeout = builder.timeout; + timeUnit = builder.unit; + lookForStuckThread = builder.lookForStuckThread; + } + + /** + * Builder for {@link FailOnTimeout}. + * + * @since 4.12 + */ + public static class Builder { + private boolean lookForStuckThread = false; + private long timeout = 0; + private TimeUnit unit = TimeUnit.SECONDS; + + private Builder() { + } + + /** + * Specifies the time to wait before timing out the test. + * + *

    If this is not called, or is called with a {@code timeout} of + * {@code 0}, the returned {@code Statement} will wait forever for the + * test to complete, however the test will still launch from a separate + * thread. This can be useful for disabling timeouts in environments + * where they are dynamically set based on some property. + * + * @param timeout the maximum time to wait + * @param unit the time unit of the {@code timeout} argument + * @return {@code this} for method chaining. + */ + public Builder withTimeout(long timeout, TimeUnit unit) { + if (timeout < 0) { + throw new IllegalArgumentException("timeout must be non-negative"); + } + if (unit == null) { + throw new NullPointerException("TimeUnit cannot be null"); + } + this.timeout = timeout; + this.unit = unit; + return this; + } + + /** + * Specifies whether to look for a stuck thread. If a timeout occurs and this + * feature is enabled, the test will look for a thread that appears to be stuck + * and dump its backtrace. This feature is experimental. Behavior may change + * after the 4.12 release in response to feedback. + * + * @param enable {@code true} to enable the feature + * @return {@code this} for method chaining. + */ + public Builder withLookingForStuckThread(boolean enable) { + this.lookForStuckThread = enable; + return this; + } + + /** + * Builds a {@link FailOnTimeout} instance using the values in this builder, + * wrapping the given statement. + * + * @param statement + */ + public FailOnTimeout build(Statement statement) { + if (statement == null) { + throw new NullPointerException("statement cannot be null"); + } + return new FailOnTimeout(this, statement); + } + } + + @Override + public void evaluate() throws Throwable { + CallableStatement callable = new CallableStatement(); + FutureTask task = new FutureTask(callable); + ThreadGroup threadGroup = new ThreadGroup("FailOnTimeoutGroup"); + Thread thread = new Thread(threadGroup, task, "Time-limited test"); + try { + thread.setDaemon(true); + thread.start(); + callable.awaitStarted(); + Throwable throwable = getResult(task, thread); + if (throwable != null) { + throw throwable; + } + } finally { + try { + thread.join(1); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + try { + threadGroup.destroy(); + } catch (IllegalThreadStateException e) { + // If a thread from the group is still alive, the ThreadGroup cannot be destroyed. + // Swallow the exception to keep the same behavior prior to this change. + } + } + } + + /** + * Wait for the test task, returning the exception thrown by the test if the + * test failed, an exception indicating a timeout if the test timed out, or + * {@code null} if the test passed. + */ + private Throwable getResult(FutureTask task, Thread thread) { + try { + if (timeout > 0) { + return task.get(timeout, timeUnit); + } else { + return task.get(); + } + } catch (InterruptedException e) { + return e; // caller will re-throw; no need to call Thread.interrupt() + } catch (ExecutionException e) { + // test failed; have caller re-throw the exception thrown by the test + return e.getCause(); + } catch (TimeoutException e) { + return createTimeoutException(thread); + } + } + + private Exception createTimeoutException(Thread thread) { + StackTraceElement[] stackTrace = thread.getStackTrace(); + final Thread stuckThread = lookForStuckThread ? getStuckThread(thread) : null; + Exception currThreadException = new TestTimedOutException(timeout, timeUnit); + if (stackTrace != null) { + currThreadException.setStackTrace(stackTrace); + thread.interrupt(); + } + if (stuckThread != null) { + Exception stuckThreadException = + new Exception("Appears to be stuck in thread " + + stuckThread.getName()); + stuckThreadException.setStackTrace(getStackTrace(stuckThread)); + return new MultipleFailureException( + Arrays.asList(currThreadException, stuckThreadException)); + } else { + return currThreadException; + } + } + + /** + * Retrieves the stack trace for a given thread. + * @param thread The thread whose stack is to be retrieved. + * @return The stack trace; returns a zero-length array if the thread has + * terminated or the stack cannot be retrieved for some other reason. + */ + private StackTraceElement[] getStackTrace(Thread thread) { + try { + return thread.getStackTrace(); + } catch (SecurityException e) { + return new StackTraceElement[0]; + } + } + + /** + * Determines whether the test appears to be stuck in some thread other than + * the "main thread" (the one created to run the test). This feature is experimental. + * Behavior may change after the 4.12 release in response to feedback. + * @param mainThread The main thread created by {@code evaluate()} + * @return The thread which appears to be causing the problem, if different from + * {@code mainThread}, or {@code null} if the main thread appears to be the + * problem or if the thread cannot be determined. The return value is never equal + * to {@code mainThread}. + */ + private Thread getStuckThread(Thread mainThread) { + List threadsInGroup = getThreadsInGroup(mainThread.getThreadGroup()); + if (threadsInGroup.isEmpty()) { + return null; + } + + // Now that we have all the threads in the test's thread group: Assume that + // any thread we're "stuck" in is RUNNABLE. Look for all RUNNABLE threads. + // If just one, we return that (unless it equals threadMain). If there's more + // than one, pick the one that's using the most CPU time, if this feature is + // supported. + Thread stuckThread = null; + long maxCpuTime = 0; + for (Thread thread : threadsInGroup) { + if (thread.getState() == Thread.State.RUNNABLE) { + long threadCpuTime = cpuTime(thread); + if (stuckThread == null || threadCpuTime > maxCpuTime) { + stuckThread = thread; + maxCpuTime = threadCpuTime; + } + } + } + return (stuckThread == mainThread) ? null : stuckThread; + } + + /** + * Returns all active threads belonging to a thread group. + * @param group The thread group. + * @return The active threads in the thread group. The result should be a + * complete list of the active threads at some point in time. Returns an empty list + * if this cannot be determined, e.g. because new threads are being created at an + * extremely fast rate. + */ + private List getThreadsInGroup(ThreadGroup group) { + final int activeThreadCount = group.activeCount(); // this is just an estimate + int threadArraySize = Math.max(activeThreadCount * 2, 100); + for (int loopCount = 0; loopCount < 5; loopCount++) { + Thread[] threads = new Thread[threadArraySize]; + int enumCount = group.enumerate(threads); + if (enumCount < threadArraySize) { + return Arrays.asList(threads).subList(0, enumCount); + } + // if there are too many threads to fit into the array, enumerate's result + // is >= the array's length; therefore we can't trust that it returned all + // the threads. Try again. + threadArraySize += 100; + } + // threads are proliferating too fast for us. Bail before we get into + // trouble. + return Collections.emptyList(); + } + + /** + * Returns the CPU time used by a thread, if possible. + * @param thr The thread to query. + * @return The CPU time used by {@code thr}, or 0 if it cannot be determined. + */ + private long cpuTime(Thread thr) { + ThreadMXBean mxBean = ManagementFactory.getThreadMXBean(); + if (mxBean.isThreadCpuTimeSupported()) { + try { + return mxBean.getThreadCpuTime(thr.getId()); + } catch (UnsupportedOperationException e) { + } + } + return 0; + } + + private class CallableStatement implements Callable { + private final CountDownLatch startLatch = new CountDownLatch(1); + + public Throwable call() throws Exception { + try { + startLatch.countDown(); + originalStatement.evaluate(); + } catch (Exception e) { + throw e; + } catch (Throwable e) { + return e; + } + return null; + } + + public void awaitStarted() throws InterruptedException { + startLatch.await(); + } + } +} diff --git a/src/main/java/org/junit/internal/runners/statements/InvokeMethod.java b/src/main/java/org/junit/internal/runners/statements/InvokeMethod.java new file mode 100644 index 000000000000..68c0545b1422 --- /dev/null +++ b/src/main/java/org/junit/internal/runners/statements/InvokeMethod.java @@ -0,0 +1,19 @@ +package org.junit.internal.runners.statements; + +import org.junit.runners.model.FrameworkMethod; +import org.junit.runners.model.Statement; + +public class InvokeMethod extends Statement { + private final FrameworkMethod testMethod; + private final Object target; + + public InvokeMethod(FrameworkMethod testMethod, Object target) { + this.testMethod = testMethod; + this.target = target; + } + + @Override + public void evaluate() throws Throwable { + testMethod.invokeExplosively(target); + } +} \ No newline at end of file diff --git a/src/main/java/org/junit/internal/runners/statements/RunAfters.java b/src/main/java/org/junit/internal/runners/statements/RunAfters.java new file mode 100644 index 000000000000..5e56c3350ac1 --- /dev/null +++ b/src/main/java/org/junit/internal/runners/statements/RunAfters.java @@ -0,0 +1,48 @@ +package org.junit.internal.runners.statements; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.runners.model.FrameworkMethod; +import org.junit.runners.model.MultipleFailureException; +import org.junit.runners.model.Statement; + +public class RunAfters extends Statement { + private final Statement next; + + private final Object target; + + private final List afters; + + public RunAfters(Statement next, List afters, Object target) { + this.next = next; + this.afters = afters; + this.target = target; + } + + @Override + public void evaluate() throws Throwable { + List errors = new ArrayList(); + try { + next.evaluate(); + } catch (Throwable e) { + errors.add(e); + } finally { + for (FrameworkMethod each : afters) { + try { + invokeMethod(each); + } catch (Throwable e) { + errors.add(e); + } + } + } + MultipleFailureException.assertEmpty(errors); + } + + /** + * @since 4.13 + */ + protected void invokeMethod(FrameworkMethod method) throws Throwable { + method.invokeExplosively(target); + } +} \ No newline at end of file diff --git a/src/main/java/org/junit/internal/runners/statements/RunBefores.java b/src/main/java/org/junit/internal/runners/statements/RunBefores.java new file mode 100644 index 000000000000..bd835c772530 --- /dev/null +++ b/src/main/java/org/junit/internal/runners/statements/RunBefores.java @@ -0,0 +1,35 @@ +package org.junit.internal.runners.statements; + +import java.util.List; + +import org.junit.runners.model.FrameworkMethod; +import org.junit.runners.model.Statement; + +public class RunBefores extends Statement { + private final Statement next; + + private final Object target; + + private final List befores; + + public RunBefores(Statement next, List befores, Object target) { + this.next = next; + this.befores = befores; + this.target = target; + } + + @Override + public void evaluate() throws Throwable { + for (FrameworkMethod before : befores) { + invokeMethod(before); + } + next.evaluate(); + } + + /** + * @since 4.13 + */ + protected void invokeMethod(FrameworkMethod method) throws Throwable { + method.invokeExplosively(target); + } +} \ No newline at end of file diff --git a/src/main/java/org/junit/matchers/JUnitMatchers.java b/src/main/java/org/junit/matchers/JUnitMatchers.java new file mode 100644 index 000000000000..13407cc05217 --- /dev/null +++ b/src/main/java/org/junit/matchers/JUnitMatchers.java @@ -0,0 +1,113 @@ +package org.junit.matchers; + +import org.hamcrest.CoreMatchers; +import org.hamcrest.Matcher; +import org.hamcrest.core.CombinableMatcher.CombinableBothMatcher; +import org.hamcrest.core.CombinableMatcher.CombinableEitherMatcher; +import org.junit.internal.matchers.StacktracePrintingMatcher; + +/** + * Convenience import class: these are useful matchers for use with the assertThat method, but they are + * not currently included in the basic CoreMatchers class from hamcrest. + * + * @since 4.4 + */ +public class JUnitMatchers { + /** + * @return A matcher matching any collection containing element + * @deprecated Please use {@link CoreMatchers#hasItem(Object)} instead. + */ + @Deprecated + public static Matcher> hasItem(T element) { + return CoreMatchers.hasItem(element); + } + + /** + * @return A matcher matching any collection containing an element matching elementMatcher + * @deprecated Please use {@link CoreMatchers#hasItem(Matcher)} instead. + */ + @Deprecated + public static Matcher> hasItem(Matcher elementMatcher) { + return CoreMatchers.hasItem(elementMatcher); + } + + /** + * @return A matcher matching any collection containing every element in elements + * @deprecated Please use {@link CoreMatchers#hasItems(Object...)} instead. + */ + @Deprecated + public static Matcher> hasItems(T... elements) { + return CoreMatchers.hasItems(elements); + } + + /** + * @return A matcher matching any collection containing at least one element that matches + * each matcher in elementMatcher (this may be one element matching all matchers, + * or different elements matching each matcher) + * @deprecated Please use {@link CoreMatchers#hasItems(Matcher...)} instead. + */ + @Deprecated + public static Matcher> hasItems(Matcher... elementMatchers) { + return CoreMatchers.hasItems(elementMatchers); + } + + /** + * @return A matcher matching any collection in which every element matches elementMatcher + * @deprecated Please use {@link CoreMatchers#everyItem(Matcher)} instead. + */ + @Deprecated + public static Matcher> everyItem(final Matcher elementMatcher) { + return CoreMatchers.everyItem(elementMatcher); + } + + /** + * @return a matcher matching any string that contains substring + * @deprecated Please use {@link CoreMatchers#containsString(String)} instead. + */ + @Deprecated + public static Matcher containsString(java.lang.String substring) { + return CoreMatchers.containsString(substring); + } + + /** + * This is useful for fluently combining matchers that must both pass. For example: + *

    +     *   assertThat(string, both(containsString("a")).and(containsString("b")));
    +     * 
    + * + * @deprecated Please use {@link CoreMatchers#both(Matcher)} instead. + */ + @Deprecated + public static CombinableBothMatcher both(Matcher matcher) { + return CoreMatchers.both(matcher); + } + + /** + * This is useful for fluently combining matchers where either may pass, for example: + *
    +     *   assertThat(string, either(containsString("a")).or(containsString("b")));
    +     * 
    + * + * @deprecated Please use {@link CoreMatchers#either(Matcher)} instead. + */ + @Deprecated + public static CombinableEitherMatcher either(Matcher matcher) { + return CoreMatchers.either(matcher); + } + + /** + * @return A matcher that delegates to throwableMatcher and in addition + * appends the stacktrace of the actual Throwable in case of a mismatch. + */ + public static Matcher isThrowable(Matcher throwableMatcher) { + return StacktracePrintingMatcher.isThrowable(throwableMatcher); + } + + /** + * @return A matcher that delegates to exceptionMatcher and in addition + * appends the stacktrace of the actual Exception in case of a mismatch. + */ + public static Matcher isException(Matcher exceptionMatcher) { + return StacktracePrintingMatcher.isException(exceptionMatcher); + } +} diff --git a/src/main/java/org/junit/matchers/package-info.java b/src/main/java/org/junit/matchers/package-info.java new file mode 100644 index 000000000000..71aca349009a --- /dev/null +++ b/src/main/java/org/junit/matchers/package-info.java @@ -0,0 +1,9 @@ +/** + * Provides useful additional {@link org.hamcrest.Matcher}s for use with + * the {@link org.junit.Assert#assertThat(Object, org.hamcrest.Matcher)} + * statement + * + * @since 4.0 + * @see org.junit.matchers.JUnitMatchers + */ +package org.junit.matchers; \ No newline at end of file diff --git a/src/main/java/org/junit/package-info.java b/src/main/java/org/junit/package-info.java new file mode 100644 index 000000000000..fb12f2598f0b --- /dev/null +++ b/src/main/java/org/junit/package-info.java @@ -0,0 +1,8 @@ +/** + * Provides JUnit core classes and annotations. + * + * Corresponds to junit.framework in Junit 3.x. + * + * @since 4.0 + */ +package org.junit; \ No newline at end of file diff --git a/src/main/java/org/junit/rules/DisableOnDebug.java b/src/main/java/org/junit/rules/DisableOnDebug.java new file mode 100644 index 000000000000..3bca103ed5a4 --- /dev/null +++ b/src/main/java/org/junit/rules/DisableOnDebug.java @@ -0,0 +1,125 @@ +package org.junit.rules; + +import java.util.List; + +import org.junit.internal.management.ManagementFactory; +import org.junit.internal.management.RuntimeMXBean; +import org.junit.runner.Description; +import org.junit.runners.model.Statement; + +/** + * The {@code DisableOnDebug} Rule allows you to label certain rules to be + * disabled when debugging. + *

    + * The most illustrative use case is for tests that make use of the + * {@link Timeout} rule, when ran in debug mode the test may terminate on + * timeout abruptly during debugging. Developers may disable the timeout, or + * increase the timeout by making a code change on tests that need debugging and + * remember revert the change afterwards or rules such as {@link Timeout} that + * may be disabled during debugging may be wrapped in a {@code DisableOnDebug}. + *

    + * The important benefit of this feature is that you can disable such rules + * without any making any modifications to your test class to remove them during + * debugging. + *

    + * This does nothing to tackle timeouts or time sensitive code under test when + * debugging and may make this less useful in such circumstances. + *

    + * Example usage: + * + *

    + * public static class DisableTimeoutOnDebugSampleTest {
    + * 
    + *     @Rule
    + *     public TestRule timeout = new DisableOnDebug(new Timeout(20));
    + * 
    + *     @Test
    + *     public void myTest() {
    + *         int i = 0;
    + *         assertEquals(0, i); // suppose you had a break point here to inspect i
    + *     }
    + * }
    + * 
    + * + * @since 4.12 + */ +public class DisableOnDebug implements TestRule { + private final TestRule rule; + private final boolean debugging; + + /** + * Create a {@code DisableOnDebug} instance with the timeout specified in + * milliseconds. + * + * @param rule to disable during debugging + */ + public DisableOnDebug(TestRule rule) { + this(rule, ManagementFactory.getRuntimeMXBean() + .getInputArguments()); + } + + /** + * Visible for testing purposes only. + * + * @param rule the rule to disable during debugging + * @param inputArguments + * arguments provided to the Java runtime + */ + DisableOnDebug(TestRule rule, List inputArguments) { + this.rule = rule; + debugging = isDebugging(inputArguments); + } + + /** + * @see TestRule#apply(Statement, Description) + */ + public Statement apply(Statement base, Description description) { + if (debugging) { + return base; + } else { + return rule.apply(base, description); + } + } + + /** + * Parses arguments passed to the runtime environment for debug flags + *

    + * Options specified in: + *