Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'tests/junit/framework')
-rw-r--r--tests/junit/framework/org.eclipse.papyrus.junit.framework/.classpath7
-rw-r--r--tests/junit/framework/org.eclipse.papyrus.junit.framework/.project52
-rw-r--r--tests/junit/framework/org.eclipse.papyrus.junit.framework/.settings/org.eclipse.core.resources.prefs2
-rw-r--r--tests/junit/framework/org.eclipse.papyrus.junit.framework/.settings/org.eclipse.core.runtime.prefs2
-rw-r--r--tests/junit/framework/org.eclipse.papyrus.junit.framework/.settings/org.eclipse.jdt.core.prefs291
-rw-r--r--tests/junit/framework/org.eclipse.papyrus.junit.framework/.settings/org.eclipse.jdt.ui.prefs68
-rw-r--r--tests/junit/framework/org.eclipse.papyrus.junit.framework/.settings/org.eclipse.pde.api.tools.prefs98
-rw-r--r--tests/junit/framework/org.eclipse.papyrus.junit.framework/META-INF/MANIFEST.MF18
-rw-r--r--tests/junit/framework/org.eclipse.papyrus.junit.framework/about.html28
-rw-r--r--tests/junit/framework/org.eclipse.papyrus.junit.framework/build.properties6
-rw-r--r--tests/junit/framework/org.eclipse.papyrus.junit.framework/pom.xml14
-rw-r--r--tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/classification/ClassificationConfig.java325
-rw-r--r--tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/classification/ClassificationRunner.java102
-rw-r--r--tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/classification/ClassificationRunnerImpl.java346
-rw-r--r--tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/classification/ClassificationRunnerWithParameters.java102
-rw-r--r--tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/classification/ClassificationRunnerWithParametersFactory.java45
-rw-r--r--tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/classification/ClassificationSuite.java295
-rw-r--r--tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/classification/ExpensiveTest.java39
-rw-r--r--tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/classification/FailingTest.java39
-rw-r--r--tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/classification/GeneratedTest.java41
-rw-r--r--tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/classification/InteractiveTest.java38
-rw-r--r--tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/classification/InvalidTest.java38
-rw-r--r--tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/classification/NotImplemented.java39
-rw-r--r--tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/classification/TestCategory.java73
-rw-r--r--tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/classification/rules/Condition.java33
-rw-r--r--tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/classification/rules/ConditionRule.java147
-rw-r--r--tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/classification/rules/Conditional.java41
-rw-r--r--tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/classification/rules/MemoryLeakRule.java304
-rw-r--r--tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/classification/tests/AbstractPapyrusTest.java28
-rw-r--r--tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/runner/AllTestsRunner.java96
-rw-r--r--tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/runner/FragmentTestSuiteClass.java71
-rw-r--r--tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/runner/Headless.java31
-rw-r--r--tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/runner/ITestSuiteClass.java50
-rw-r--r--tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/runner/IgnoreRunner.java64
-rw-r--r--tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/runner/PluginTestSuiteClass.java46
-rw-r--r--tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/runner/Scenario.java34
-rw-r--r--tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/runner/ScenarioRunner.java419
-rw-r--r--tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/runner/SuiteSpot.java29
-rw-r--r--tests/junit/framework/org.eclipse.papyrus.junit.utils/.classpath7
-rw-r--r--tests/junit/framework/org.eclipse.papyrus.junit.utils/.project52
-rw-r--r--tests/junit/framework/org.eclipse.papyrus.junit.utils/.settings/org.eclipse.core.resources.prefs2
-rw-r--r--tests/junit/framework/org.eclipse.papyrus.junit.utils/.settings/org.eclipse.core.runtime.prefs2
-rw-r--r--tests/junit/framework/org.eclipse.papyrus.junit.utils/.settings/org.eclipse.jdt.core.prefs291
-rw-r--r--tests/junit/framework/org.eclipse.papyrus.junit.utils/.settings/org.eclipse.jdt.ui.prefs68
-rw-r--r--tests/junit/framework/org.eclipse.papyrus.junit.utils/.settings/org.eclipse.pde.api.tools.prefs98
-rw-r--r--tests/junit/framework/org.eclipse.papyrus.junit.utils/META-INF/MANIFEST.MF32
-rw-r--r--tests/junit/framework/org.eclipse.papyrus.junit.utils/OSGI-INF/l10n/bundle.properties3
-rw-r--r--tests/junit/framework/org.eclipse.papyrus.junit.utils/about.html28
-rw-r--r--tests/junit/framework/org.eclipse.papyrus.junit.utils/build.properties8
-rw-r--r--tests/junit/framework/org.eclipse.papyrus.junit.utils/plugin.properties12
-rw-r--r--tests/junit/framework/org.eclipse.papyrus.junit.utils/pom.xml12
-rw-r--r--tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/matchers/DiagramMatchers.java104
-rw-r--r--tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/matchers/MoreMatchers.java175
-rw-r--r--tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/Activator.java83
-rw-r--r--tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/DiagramUtils.java172
-rw-r--r--tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/DisplayUtils.java38
-rw-r--r--tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/Duck.java255
-rw-r--r--tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/EditorUtils.java109
-rw-r--r--tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/FilesUtils.java48
-rw-r--r--tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/GenericUtils.java64
-rw-r--r--tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/HandlerUtils.java95
-rw-r--r--tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/JUnitUtils.java159
-rw-r--r--tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/LogTracker.java132
-rw-r--r--tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/ModelExplorerUtils.java214
-rw-r--r--tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/ModelUtils.java110
-rw-r--r--tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/PackageExplorerUtils.java91
-rw-r--r--tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/PapyrusProjectUtils.java93
-rw-r--r--tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/PrintingProgressMonitor.java137
-rw-r--r--tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/ProjectUtils.java68
-rw-r--r--tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/SynchronousExecutorService.java188
-rw-r--r--tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/TableUtils.java82
-rw-r--r--tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/resources/ChangeCapture.java84
-rw-r--r--tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/resources/EcoreModel.java82
-rw-r--r--tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/resources/WorkspaceModificationAssertion.java128
-rw-r--r--tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/AbstractHouseKeeperRule.java723
-rwxr-xr-xtests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/AbstractModelFixture.java649
-rw-r--r--tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/ActiveDiagram.java33
-rwxr-xr-xtests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/ActiveTable.java33
-rw-r--r--tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/AnnotationRule.java152
-rw-r--r--tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/ExecutorRule.java56
-rw-r--r--tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/HideViewRule.java72
-rw-r--r--tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/HouseKeeper.java143
-rw-r--r--tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/JavaResource.java32
-rw-r--r--tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/ModelSetFixture.java127
-rw-r--r--tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/NoTransactionFixture.java95
-rw-r--r--tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/NoTransactionRule.java59
-rw-r--r--tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/PapyrusEditorFixture.java1415
-rw-r--r--tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/PluginResource.java36
-rw-r--r--tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/ProjectFixture.java256
-rw-r--r--tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/ResourceSetFixture.java34
-rw-r--r--tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/RuleUtil.java132
-rw-r--r--tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/ServiceRegistryModelSetFixture.java41
-rw-r--r--tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/ShowView.java74
-rw-r--r--tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/ShowViewRule.java72
-rw-r--r--tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/StandaloneResourceSetFixture.java179
-rw-r--r--tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/UIThread.java31
-rw-r--r--tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/UIThreadRule.java94
-rw-r--r--tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/tests/AbstractEMFResourceTest.java57
-rw-r--r--tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/tests/AbstractEditorTest.java244
-rwxr-xr-xtests/junit/framework/pom.xml21
100 files changed, 11687 insertions, 0 deletions
diff --git a/tests/junit/framework/org.eclipse.papyrus.junit.framework/.classpath b/tests/junit/framework/org.eclipse.papyrus.junit.framework/.classpath
new file mode 100644
index 00000000000..eca7bdba8f0
--- /dev/null
+++ b/tests/junit/framework/org.eclipse.papyrus.junit.framework/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/tests/junit/framework/org.eclipse.papyrus.junit.framework/.project b/tests/junit/framework/org.eclipse.papyrus.junit.framework/.project
new file mode 100644
index 00000000000..633f2786909
--- /dev/null
+++ b/tests/junit/framework/org.eclipse.papyrus.junit.framework/.project
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.eclipse.papyrus.junit.framework</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.oomph.version.VersionBuilder</name>
+ <arguments>
+ <dictionary>
+ <key>check.maven.pom</key>
+ <value>true</value>
+ </dictionary>
+ <dictionary>
+ <key>ignore.lower.bound.dependency.ranges</key>
+ <value>true</value>
+ </dictionary>
+ <dictionary>
+ <key>release.path</key>
+ <value>/org.eclipse.papyrus.releng.dev.release/release.xml</value>
+ </dictionary>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.api.tools.apiAnalysisBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ <nature>org.eclipse.oomph.version.VersionNature</nature>
+ <nature>org.eclipse.pde.api.tools.apiAnalysisNature</nature>
+ </natures>
+</projectDescription>
diff --git a/tests/junit/framework/org.eclipse.papyrus.junit.framework/.settings/org.eclipse.core.resources.prefs b/tests/junit/framework/org.eclipse.papyrus.junit.framework/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 00000000000..896a9a53a53
--- /dev/null
+++ b/tests/junit/framework/org.eclipse.papyrus.junit.framework/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+encoding/<project>=UTF-8 \ No newline at end of file
diff --git a/tests/junit/framework/org.eclipse.papyrus.junit.framework/.settings/org.eclipse.core.runtime.prefs b/tests/junit/framework/org.eclipse.papyrus.junit.framework/.settings/org.eclipse.core.runtime.prefs
new file mode 100644
index 00000000000..5a0ad22d2a7
--- /dev/null
+++ b/tests/junit/framework/org.eclipse.papyrus.junit.framework/.settings/org.eclipse.core.runtime.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+line.separator=\n
diff --git a/tests/junit/framework/org.eclipse.papyrus.junit.framework/.settings/org.eclipse.jdt.core.prefs b/tests/junit/framework/org.eclipse.papyrus.junit.framework/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 00000000000..b3aa6d60f94
--- /dev/null
+++ b/tests/junit/framework/org.eclipse.papyrus.junit.framework/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,291 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
+org.eclipse.jdt.core.compiler.compliance=1.8
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.8
+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_annotation=0
+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_method_declaration=0
+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_resources_in_try=80
+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.alignment_for_union_type_in_multicatch=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=0
+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_lambda_body=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_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_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=260
+org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=true
+org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true
+org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=false
+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.disabling_tag=@formatter\:off
+org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on
+org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false
+org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=true
+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_on_field=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_method=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=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_annotation_on_type=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_label=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_after_type_annotation=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_lambda_arrow=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_try=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_semicolon_in_try_resources=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_try=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_lambda_arrow=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_try=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_semicolon_in_try_resources=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.join_lines_in_comments=false
+org.eclipse.jdt.core.formatter.join_wrapped_lines=false
+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=260
+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=5
+org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true
+org.eclipse.jdt.core.formatter.tabulation.char=tab
+org.eclipse.jdt.core.formatter.tabulation.size=4
+org.eclipse.jdt.core.formatter.use_on_off_tags=false
+org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false
+org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true
+org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true
diff --git a/tests/junit/framework/org.eclipse.papyrus.junit.framework/.settings/org.eclipse.jdt.ui.prefs b/tests/junit/framework/org.eclipse.papyrus.junit.framework/.settings/org.eclipse.jdt.ui.prefs
new file mode 100644
index 00000000000..954281dbc31
--- /dev/null
+++ b/tests/junit/framework/org.eclipse.papyrus.junit.framework/.settings/org.eclipse.jdt.ui.prefs
@@ -0,0 +1,68 @@
+cleanup.add_default_serial_version_id=true
+cleanup.add_generated_serial_version_id=false
+cleanup.add_missing_annotations=true
+cleanup.add_missing_deprecated_annotations=true
+cleanup.add_missing_methods=false
+cleanup.add_missing_nls_tags=false
+cleanup.add_missing_override_annotations=true
+cleanup.add_missing_override_annotations_interface_methods=true
+cleanup.add_serial_version_id=false
+cleanup.always_use_blocks=true
+cleanup.always_use_parentheses_in_expressions=false
+cleanup.always_use_this_for_non_static_field_access=false
+cleanup.always_use_this_for_non_static_method_access=false
+cleanup.convert_functional_interfaces=false
+cleanup.convert_to_enhanced_for_loop=false
+cleanup.correct_indentation=false
+cleanup.format_source_code=false
+cleanup.format_source_code_changes_only=false
+cleanup.insert_inferred_type_arguments=false
+cleanup.make_local_variable_final=true
+cleanup.make_parameters_final=false
+cleanup.make_private_fields_final=true
+cleanup.make_type_abstract_if_missing_method=false
+cleanup.make_variable_declarations_final=false
+cleanup.never_use_blocks=false
+cleanup.never_use_parentheses_in_expressions=true
+cleanup.organize_imports=false
+cleanup.qualify_static_field_accesses_with_declaring_class=false
+cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true
+cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=true
+cleanup.qualify_static_member_accesses_with_declaring_class=true
+cleanup.qualify_static_method_accesses_with_declaring_class=false
+cleanup.remove_private_constructors=true
+cleanup.remove_redundant_type_arguments=true
+cleanup.remove_trailing_whitespaces=true
+cleanup.remove_trailing_whitespaces_all=true
+cleanup.remove_trailing_whitespaces_ignore_empty=false
+cleanup.remove_unnecessary_casts=true
+cleanup.remove_unnecessary_nls_tags=true
+cleanup.remove_unused_imports=true
+cleanup.remove_unused_local_variables=false
+cleanup.remove_unused_private_fields=true
+cleanup.remove_unused_private_members=false
+cleanup.remove_unused_private_methods=true
+cleanup.remove_unused_private_types=true
+cleanup.sort_members=false
+cleanup.sort_members_all=false
+cleanup.use_anonymous_class_creation=false
+cleanup.use_blocks=true
+cleanup.use_blocks_only_for_return_and_throw=false
+cleanup.use_lambda=true
+cleanup.use_parentheses_in_expressions=false
+cleanup.use_this_for_non_static_field_access=false
+cleanup.use_this_for_non_static_field_access_only_if_necessary=true
+cleanup.use_this_for_non_static_method_access=false
+cleanup.use_this_for_non_static_method_access_only_if_necessary=true
+cleanup.use_type_arguments=false
+cleanup_profile=_Papyrus
+cleanup_settings_version=2
+eclipse.preferences.version=1
+formatter_profile=_Papyrus
+formatter_settings_version=12
+org.eclipse.jdt.ui.ignorelowercasenames=true
+org.eclipse.jdt.ui.importorder=java;javax;org;com;
+org.eclipse.jdt.ui.javadoc=true
+org.eclipse.jdt.ui.ondemandthreshold=99
+org.eclipse.jdt.ui.staticondemandthreshold=99
+org.eclipse.jdt.ui.text.custom_code_templates=<?xml version\="1.0" encoding\="UTF-8" standalone\="no"?><templates><template autoinsert\="true" context\="gettercomment_context" deleted\="false" description\="Comment for getter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.gettercomment" name\="gettercomment">/**\n * @return the ${bare_field_name}\n */</template><template autoinsert\="true" context\="settercomment_context" deleted\="false" description\="Comment for setter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.settercomment" name\="settercomment">/**\n * @param ${param} the ${bare_field_name} to set\n */</template><template autoinsert\="false" context\="constructorcomment_context" deleted\="false" description\="Comment for created constructors" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorcomment" name\="constructorcomment">/**\n * Constructor.\n *\n * ${tags}\n */</template><template autoinsert\="false" context\="filecomment_context" deleted\="false" description\="Comment for created Java files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.filecomment" name\="filecomment">/*****************************************************************************\n * Copyright (c) ${year} CEA LIST and others.\n * \n * All rights reserved. This program and the accompanying materials\n * are made available under the terms of the Eclipse Public License v1.0\n * which accompanies this distribution, and is available at\n * http\://www.eclipse.org/legal/epl-v10.html\n *\n * Contributors\:\n * CEA LIST - Initial API and implementation\n * \n *****************************************************************************/\n</template><template autoinsert\="true" context\="typecomment_context" deleted\="false" description\="Comment for created types" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.typecomment" name\="typecomment">/**\n * @author ${user}\n *\n * ${tags}\n */</template><template autoinsert\="true" context\="fieldcomment_context" deleted\="false" description\="Comment for fields" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.fieldcomment" name\="fieldcomment">/**\n * \n */</template><template autoinsert\="true" context\="methodcomment_context" deleted\="false" description\="Comment for non-overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodcomment" name\="methodcomment">/**\n * ${tags}\n */</template><template autoinsert\="false" context\="overridecomment_context" deleted\="false" description\="Comment for overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.overridecomment" name\="overridecomment">/**\n * ${see_to_overridden}\n *\n * ${tags}\n */</template><template autoinsert\="false" context\="delegatecomment_context" deleted\="false" description\="Comment for delegate methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.delegatecomment" name\="delegatecomment">/**\n * ${see_to_target}\n *\n * ${tags}\n */</template><template autoinsert\="true" context\="newtype_context" deleted\="false" description\="Newly created files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.newtype" name\="newtype">${filecomment}\n${package_declaration}\n\n${typecomment}\n${type_declaration}</template><template autoinsert\="true" context\="classbody_context" deleted\="false" description\="Code in new class type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.classbody" name\="classbody">\n</template><template autoinsert\="true" context\="interfacebody_context" deleted\="false" description\="Code in new interface type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.interfacebody" name\="interfacebody">\n</template><template autoinsert\="true" context\="enumbody_context" deleted\="false" description\="Code in new enum type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.enumbody" name\="enumbody">\n</template><template autoinsert\="true" context\="annotationbody_context" deleted\="false" description\="Code in new annotation type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.annotationbody" name\="annotationbody">\n</template><template autoinsert\="true" context\="catchblock_context" deleted\="false" description\="Code in new catch blocks" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.catchblock" name\="catchblock">// ${todo} Auto-generated catch block\n${exception_var}.printStackTrace();</template><template autoinsert\="true" context\="methodbody_context" deleted\="false" description\="Code in created method stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodbody" name\="methodbody">// ${todo} Auto-generated method stub\n${body_statement}</template><template autoinsert\="true" context\="constructorbody_context" deleted\="false" description\="Code in created constructor stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorbody" name\="constructorbody">${body_statement}\n// ${todo} Auto-generated constructor stub</template><template autoinsert\="true" context\="getterbody_context" deleted\="false" description\="Code in created getters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.getterbody" name\="getterbody">return ${field};</template><template autoinsert\="true" context\="setterbody_context" deleted\="false" description\="Code in created setters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.setterbody" name\="setterbody">${field} \= ${param};</template></templates>
diff --git a/tests/junit/framework/org.eclipse.papyrus.junit.framework/.settings/org.eclipse.pde.api.tools.prefs b/tests/junit/framework/org.eclipse.papyrus.junit.framework/.settings/org.eclipse.pde.api.tools.prefs
new file mode 100644
index 00000000000..23fb95e120f
--- /dev/null
+++ b/tests/junit/framework/org.eclipse.papyrus.junit.framework/.settings/org.eclipse.pde.api.tools.prefs
@@ -0,0 +1,98 @@
+ANNOTATION_ELEMENT_TYPE_ADDED_METHOD_WITHOUT_DEFAULT_VALUE=Error
+ANNOTATION_ELEMENT_TYPE_CHANGED_TYPE_CONVERSION=Error
+ANNOTATION_ELEMENT_TYPE_REMOVED_FIELD=Error
+ANNOTATION_ELEMENT_TYPE_REMOVED_METHOD=Error
+ANNOTATION_ELEMENT_TYPE_REMOVED_TYPE_MEMBER=Error
+API_COMPONENT_ELEMENT_TYPE_REMOVED_API_TYPE=Error
+API_COMPONENT_ELEMENT_TYPE_REMOVED_REEXPORTED_API_TYPE=Error
+API_COMPONENT_ELEMENT_TYPE_REMOVED_REEXPORTED_TYPE=Error
+API_COMPONENT_ELEMENT_TYPE_REMOVED_TYPE=Error
+API_USE_SCAN_FIELD_SEVERITY=Error
+API_USE_SCAN_METHOD_SEVERITY=Error
+API_USE_SCAN_TYPE_SEVERITY=Error
+CLASS_ELEMENT_TYPE_ADDED_METHOD=Error
+CLASS_ELEMENT_TYPE_ADDED_RESTRICTIONS=Error
+CLASS_ELEMENT_TYPE_ADDED_TYPE_PARAMETER=Error
+CLASS_ELEMENT_TYPE_CHANGED_CONTRACTED_SUPERINTERFACES_SET=Error
+CLASS_ELEMENT_TYPE_CHANGED_DECREASE_ACCESS=Error
+CLASS_ELEMENT_TYPE_CHANGED_NON_ABSTRACT_TO_ABSTRACT=Error
+CLASS_ELEMENT_TYPE_CHANGED_NON_FINAL_TO_FINAL=Error
+CLASS_ELEMENT_TYPE_CHANGED_TYPE_CONVERSION=Error
+CLASS_ELEMENT_TYPE_REMOVED_CONSTRUCTOR=Error
+CLASS_ELEMENT_TYPE_REMOVED_FIELD=Error
+CLASS_ELEMENT_TYPE_REMOVED_METHOD=Error
+CLASS_ELEMENT_TYPE_REMOVED_SUPERCLASS=Error
+CLASS_ELEMENT_TYPE_REMOVED_TYPE_MEMBER=Error
+CLASS_ELEMENT_TYPE_REMOVED_TYPE_PARAMETER=Error
+CONSTRUCTOR_ELEMENT_TYPE_ADDED_TYPE_PARAMETER=Error
+CONSTRUCTOR_ELEMENT_TYPE_CHANGED_DECREASE_ACCESS=Error
+CONSTRUCTOR_ELEMENT_TYPE_CHANGED_VARARGS_TO_ARRAY=Error
+CONSTRUCTOR_ELEMENT_TYPE_REMOVED_TYPE_PARAMETER=Error
+ENUM_ELEMENT_TYPE_CHANGED_CONTRACTED_SUPERINTERFACES_SET=Error
+ENUM_ELEMENT_TYPE_CHANGED_TYPE_CONVERSION=Error
+ENUM_ELEMENT_TYPE_REMOVED_ENUM_CONSTANT=Error
+ENUM_ELEMENT_TYPE_REMOVED_FIELD=Error
+ENUM_ELEMENT_TYPE_REMOVED_METHOD=Error
+ENUM_ELEMENT_TYPE_REMOVED_TYPE_MEMBER=Error
+FIELD_ELEMENT_TYPE_ADDED_VALUE=Error
+FIELD_ELEMENT_TYPE_CHANGED_DECREASE_ACCESS=Error
+FIELD_ELEMENT_TYPE_CHANGED_FINAL_TO_NON_FINAL_STATIC_CONSTANT=Error
+FIELD_ELEMENT_TYPE_CHANGED_NON_FINAL_TO_FINAL=Error
+FIELD_ELEMENT_TYPE_CHANGED_NON_STATIC_TO_STATIC=Error
+FIELD_ELEMENT_TYPE_CHANGED_STATIC_TO_NON_STATIC=Error
+FIELD_ELEMENT_TYPE_CHANGED_TYPE=Error
+FIELD_ELEMENT_TYPE_CHANGED_VALUE=Error
+FIELD_ELEMENT_TYPE_REMOVED_TYPE_ARGUMENT=Error
+FIELD_ELEMENT_TYPE_REMOVED_VALUE=Error
+ILLEGAL_EXTEND=Warning
+ILLEGAL_IMPLEMENT=Warning
+ILLEGAL_INSTANTIATE=Warning
+ILLEGAL_OVERRIDE=Warning
+ILLEGAL_REFERENCE=Warning
+INTERFACE_ELEMENT_TYPE_ADDED_FIELD=Ignore
+INTERFACE_ELEMENT_TYPE_ADDED_METHOD=Error
+INTERFACE_ELEMENT_TYPE_ADDED_RESTRICTIONS=Error
+INTERFACE_ELEMENT_TYPE_ADDED_SUPER_INTERFACE_WITH_METHODS=Error
+INTERFACE_ELEMENT_TYPE_ADDED_TYPE_PARAMETER=Error
+INTERFACE_ELEMENT_TYPE_CHANGED_CONTRACTED_SUPERINTERFACES_SET=Error
+INTERFACE_ELEMENT_TYPE_CHANGED_TYPE_CONVERSION=Error
+INTERFACE_ELEMENT_TYPE_REMOVED_FIELD=Error
+INTERFACE_ELEMENT_TYPE_REMOVED_METHOD=Error
+INTERFACE_ELEMENT_TYPE_REMOVED_TYPE_MEMBER=Error
+INTERFACE_ELEMENT_TYPE_REMOVED_TYPE_PARAMETER=Error
+INVALID_ANNOTATION=Ignore
+INVALID_JAVADOC_TAG=Ignore
+INVALID_REFERENCE_IN_SYSTEM_LIBRARIES=Ignore
+LEAK_EXTEND=Warning
+LEAK_FIELD_DECL=Warning
+LEAK_IMPLEMENT=Warning
+LEAK_METHOD_PARAM=Warning
+LEAK_METHOD_RETURN_TYPE=Warning
+METHOD_ELEMENT_TYPE_ADDED_RESTRICTIONS=Error
+METHOD_ELEMENT_TYPE_ADDED_TYPE_PARAMETER=Error
+METHOD_ELEMENT_TYPE_CHANGED_DECREASE_ACCESS=Error
+METHOD_ELEMENT_TYPE_CHANGED_NON_ABSTRACT_TO_ABSTRACT=Error
+METHOD_ELEMENT_TYPE_CHANGED_NON_FINAL_TO_FINAL=Error
+METHOD_ELEMENT_TYPE_CHANGED_NON_STATIC_TO_STATIC=Error
+METHOD_ELEMENT_TYPE_CHANGED_STATIC_TO_NON_STATIC=Error
+METHOD_ELEMENT_TYPE_CHANGED_VARARGS_TO_ARRAY=Error
+METHOD_ELEMENT_TYPE_REMOVED_ANNOTATION_DEFAULT_VALUE=Error
+METHOD_ELEMENT_TYPE_REMOVED_TYPE_PARAMETER=Error
+MISSING_EE_DESCRIPTIONS=Error
+TYPE_PARAMETER_ELEMENT_TYPE_ADDED_CLASS_BOUND=Error
+TYPE_PARAMETER_ELEMENT_TYPE_ADDED_INTERFACE_BOUND=Error
+TYPE_PARAMETER_ELEMENT_TYPE_CHANGED_CLASS_BOUND=Error
+TYPE_PARAMETER_ELEMENT_TYPE_CHANGED_INTERFACE_BOUND=Error
+TYPE_PARAMETER_ELEMENT_TYPE_REMOVED_CLASS_BOUND=Error
+TYPE_PARAMETER_ELEMENT_TYPE_REMOVED_INTERFACE_BOUND=Error
+UNUSED_PROBLEM_FILTERS=Warning
+automatically_removed_unused_problem_filters=Enabled
+eclipse.preferences.version=1
+incompatible_api_component_version=Error
+incompatible_api_component_version_include_major_without_breaking_change=Disabled
+incompatible_api_component_version_include_minor_without_api_change=Disabled
+invalid_since_tag_version=Error
+malformed_since_tag=Error
+missing_since_tag=Warning
+report_api_breakage_when_major_version_incremented=Disabled
+report_resolution_errors_api_component=Warning
diff --git a/tests/junit/framework/org.eclipse.papyrus.junit.framework/META-INF/MANIFEST.MF b/tests/junit/framework/org.eclipse.papyrus.junit.framework/META-INF/MANIFEST.MF
new file mode 100644
index 00000000000..b57b622c6d5
--- /dev/null
+++ b/tests/junit/framework/org.eclipse.papyrus.junit.framework/META-INF/MANIFEST.MF
@@ -0,0 +1,18 @@
+Manifest-Version: 1.0
+Export-Package: org.eclipse.papyrus.junit.framework.classification,
+ org.eclipse.papyrus.junit.framework.classification.rules,
+ org.eclipse.papyrus.junit.framework.classification.tests,
+ org.eclipse.papyrus.junit.framework.runner
+Require-Bundle: org.junit;bundle-version="[4.12.0,5.0.0)";visibility:=reexport,
+ org.eclipse.papyrus.infra.tools;bundle-version="[3.0.0,4.0.0)",
+ org.eclipse.emf.edit;bundle-version="[2.12.0,3.0.0)",
+ org.eclipse.ui;bundle-version="[3.107.0,4.0.0)"
+Bundle-Vendor: Eclipse Modeling Project
+Bundle-Version: 1.2.0.qualifier
+Bundle-Name: Conditional Junit Annotations
+Bundle-ManifestVersion: 2
+Bundle-SymbolicName: org.eclipse.papyrus.junit.framework;singleton:=true
+Bundle-RequiredExecutionEnvironment: JavaSE-1.8
+Import-Package: com.google.common.base;version="21.0.0",
+ com.google.common.cache;version="21.0.0",
+ com.google.common.collect;version="21.0.0"
diff --git a/tests/junit/framework/org.eclipse.papyrus.junit.framework/about.html b/tests/junit/framework/org.eclipse.papyrus.junit.framework/about.html
new file mode 100644
index 00000000000..dd3c089a94c
--- /dev/null
+++ b/tests/junit/framework/org.eclipse.papyrus.junit.framework/about.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"/>
+<title>About</title>
+</head>
+<body lang="EN-US">
+<h2>About This Content</h2>
+
+<p>November 14, 2008</p>
+<h3>License</h3>
+
+<p>The Eclipse Foundation makes available all content in this plug-in (&quot;Content&quot;). Unless otherwise
+indicated below, the Content is provided to you under the terms and conditions of the
+Eclipse Public License Version 1.0 (&quot;EPL&quot;). A copy of the EPL is available
+at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>.
+For purposes of the EPL, &quot;Program&quot; will mean the Content.</p>
+
+<p>If you did not receive this Content directly from the Eclipse Foundation, the Content is
+being redistributed by another party (&quot;Redistributor&quot;) and different terms and conditions may
+apply to your use of any object code in the Content. Check the Redistributor's license that was
+provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise
+indicated below, the terms and conditions of the EPL still apply to any source code in the Content
+and such source code may be obtained at <a href="http://www.eclipse.org">http://www.eclipse.org</a>.</p>
+
+</body>
+</html> \ No newline at end of file
diff --git a/tests/junit/framework/org.eclipse.papyrus.junit.framework/build.properties b/tests/junit/framework/org.eclipse.papyrus.junit.framework/build.properties
new file mode 100644
index 00000000000..9cbab3c135e
--- /dev/null
+++ b/tests/junit/framework/org.eclipse.papyrus.junit.framework/build.properties
@@ -0,0 +1,6 @@
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+ .,\
+ about.html
+src.includes = about.html
diff --git a/tests/junit/framework/org.eclipse.papyrus.junit.framework/pom.xml b/tests/junit/framework/org.eclipse.papyrus.junit.framework/pom.xml
new file mode 100644
index 00000000000..66494890b42
--- /dev/null
+++ b/tests/junit/framework/org.eclipse.papyrus.junit.framework/pom.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.eclipse.papyrus.tests</groupId>
+ <artifactId>org.eclipse.papyrus.tests.junit-framework</artifactId>
+ <version>0.0.1-SNAPSHOT</version>
+ </parent>
+ <groupId>org.eclipse.papyrus</groupId>
+ <artifactId>org.eclipse.papyrus.junit.framework</artifactId>
+ <version>1.2.0-SNAPSHOT</version>
+ <packaging>eclipse-plugin</packaging>
+</project>
diff --git a/tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/classification/ClassificationConfig.java b/tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/classification/ClassificationConfig.java
new file mode 100644
index 00000000000..ebf8ee588d3
--- /dev/null
+++ b/tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/classification/ClassificationConfig.java
@@ -0,0 +1,325 @@
+/*****************************************************************************
+ * Copyright (c) 2014, 2016 CEA LIST, Christian W. Damus, and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Initial API and implementation
+ * Christian W. Damus - bug 451230
+ * Christian W. Damus - bug 464647
+ * Christian W. Damus - bug 480812
+ * Christian W. Damus - bug 485156
+ *****************************************************************************/
+package org.eclipse.papyrus.junit.framework.classification;
+
+import static org.eclipse.papyrus.junit.framework.classification.TestCategory.ExpensiveTest;
+import static org.eclipse.papyrus.junit.framework.classification.TestCategory.FailingTest;
+import static org.eclipse.papyrus.junit.framework.classification.TestCategory.GeneratedTest;
+import static org.eclipse.papyrus.junit.framework.classification.TestCategory.InteractiveTest;
+import static org.eclipse.papyrus.junit.framework.classification.TestCategory.InvalidTest;
+import static org.eclipse.papyrus.junit.framework.classification.TestCategory.NotImplemented;
+import static org.eclipse.papyrus.junit.framework.classification.TestCategory.Standard;
+
+import java.lang.annotation.Annotation;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.papyrus.infra.tools.util.ListHelper;
+import org.junit.Ignore;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Suite;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Sets;
+
+
+/**
+ * <p>
+ * This class is used to configure the Classification Annotations which should be excluded from a test job. A classification configuration is an immutable set of {@linkplain TestCategory test categories} that are included in the test configuration.
+ * </p>
+ * <p>
+ * Usage:
+ * </p>
+ *
+ * <pre>
+ * ClassificationConfig.setExcludedTestCategories(TestCategory.InvalidTest, TestCategory.NotImplemented);
+ *
+ * // or
+ *
+ * ClassificationConfig.setIncludedTestCategories(TestCategory.Standard, TestCategory.NotImplemented);
+ *
+ * // or
+ *
+ * ClassificationConfig.setExcludedTestCategories(ClassificationConfig.FAILING_TESTS_CONFIG);
+ *
+ * // or
+ *
+ * ClassificationConfig.setIncludedTestCategories(ClassificationConfig.FULL_CI_TESTS_CONFIG);
+ *
+ * // or
+ *
+ * ClassificationConfig.setTestsConfiguration(ClassificationConfig.CI_TESTS_CONFIG);
+ * </pre>
+ *
+ * @author Camille Letavernier
+ *
+ * @see {@link TestCategory}
+ * @see {@link ClassificationRunner}
+ *
+ */
+public enum ClassificationConfig implements Set<TestCategory> {
+
+ /**
+ * Default tests configuration for Continuous Integration (Hudson): Excludes the tests which are
+ * identified as failing, as well as the interactive tests
+ *
+ * This configuration may require a couple of hours to run
+ */
+ CI_TESTS_CONFIG(NotImplemented, InvalidTest, FailingTest, InteractiveTest, GeneratedTest),
+
+ /**
+ * This tests configuration runs all tests which are already identified as failing.
+ * If one test from this configuration passes, this might mean that the annotation should be removed
+ *
+ * InteractiveTests are excluded as well, as this configuration is supposed to be executed on Hudson
+ */
+ FAILING_TESTS_CONFIG(Standard, InteractiveTest, GeneratedTest, ExpensiveTest),
+
+ /**
+ * This tests configuration is expected to run in ~15 minutes. This is useful for quick testing,
+ * and validation through Gerrit
+ */
+ LIGTHWEIGHT_TESTS_CONFIG(InteractiveTest, NotImplemented, FailingTest, InvalidTest, ExpensiveTest, GeneratedTest),
+
+ /**
+ * This test configuration runs all generated diagram tests only.
+ *
+ * @since 1.2
+ */
+ GENERATED_TESTS_CONFIG(InteractiveTest, NotImplemented, FailingTest, InvalidTest, ExpensiveTest, Standard),
+
+ /**
+ * This tests configuration is meant to execute all tests in an automated environment
+ * It includes all tests which are known to be failing, but excludes tests which
+ * require a user interaction
+ */
+ FULL_CI_TESTS_CONFIG(InteractiveTest),
+
+ /**
+ * Executes all tests
+ */
+ FULL_TESTS_CONFIG();
+
+ public static final Set<TestCategory> excludedTestCategories = new HashSet<TestCategory>();
+
+ private final Set<TestCategory> categories;
+
+ static {
+ // Default on Hudson: exclude everything which is already identified as an issue (i.e. is not a (new) regression)
+ setTestsConfiguration(CI_TESTS_CONFIG);
+
+ // Check whether identified regressions are still failing
+ // setIncludedTestCategories(FailingTest);
+
+ for (String arg : Platform.getApplicationArgs()) {
+ if (arg.contains("-testConfig=")) {
+ String configName = arg.substring("-testConfig=".length());
+ Set<TestCategory> testsConfig = ClassificationConfig.valueOf(configName);
+ if (testsConfig != null) {
+ setTestsConfiguration(testsConfig);
+ }
+ break;
+ }
+ }
+ }
+
+ private ClassificationConfig(TestCategory... exclusions) {
+ Set<TestCategory> categories = Sets.newHashSet(TestCategory.values());
+ categories.removeAll(Arrays.asList(exclusions));
+ this.categories = ImmutableSet.copyOf(categories);
+ }
+
+ // Same as setExcludedTestsCategories, but renamed for clarity (To be used with predefined configurations)
+ public static void setTestsConfiguration(Set<TestCategory> predefinedConfiguration) {
+ setIncludedTestCategories(predefinedConfiguration);
+ }
+
+ /**
+ * Define the test categories which should be excluded from the TestSuite
+ *
+ * @param categoriesToInclude
+ */
+ public static void setExcludedTestCategories(TestCategory... categories) {
+ setExcludedTestCategories(Arrays.asList(categories));
+ }
+
+ /**
+ * Define the test categories which should be included in the TestSuite
+ *
+ * @param categoriesToInclude
+ */
+ public static void setIncludedTestCategories(TestCategory... categories) {
+ setIncludedTestCategories(Arrays.asList(categories));
+ }
+
+ /**
+ * Define the test categories which should be excluded from the TestSuite
+ *
+ * @param categoriesToInclude
+ */
+ public static void setExcludedTestCategories(Collection<TestCategory> categoriesToExclude) {
+ excludedTestCategories.clear();
+ excludedTestCategories.addAll(categoriesToExclude);
+ }
+
+ /**
+ * Define the test categories which should be included in the TestSuite
+ *
+ * @param categoriesToInclude
+ */
+ public static void setIncludedTestCategories(Collection<TestCategory> categoriesToInclude) {
+ excludedTestCategories.clear();
+ List<TestCategory> categoriesToExclude = ListHelper.asList(TestCategory.values());
+ categoriesToExclude.removeAll(categoriesToInclude);
+ excludedTestCategories.addAll(categoriesToExclude);
+ }
+
+ /**
+ * Tests whether a method containing the given set of Annotations should be executed
+ *
+ * @param annotations
+ * The annotations applied to the Method
+ * @return
+ * True if the test method should be executed, false if it should be ignored
+ */
+ public static boolean shouldRun(Annotation[] annotations) {
+ for (Annotation annotation : annotations) {
+ Class<? extends Annotation> annotationClass = annotation.annotationType();
+
+ // Support the usual @Ignore annotation, too, of course
+ if ((annotationClass == Ignore.class) || isExcluded(annotationClass)) {
+ return false;
+ }
+ }
+
+ if (excludedTestCategories.contains(TestCategory.Standard)) {
+ // If it's just a test suite, then let the execution of its children be filtered
+ for (Annotation annotation : annotations) {
+ if (RunWith.class.isInstance(annotation)) {
+ RunWith runWith = (RunWith) annotation;
+ Class<?> runner = runWith.value();
+ if (Suite.class.isAssignableFrom(runner) && !Parameterized.class.isAssignableFrom(runner)) {
+ return true;
+ }
+ }
+ }
+
+ for (TestCategory testCategory : TestCategory.values()) {
+ if (testCategory == TestCategory.Standard) {
+ continue;
+ }
+
+ for (Annotation annotation : annotations) {
+ if (testCategory.match(annotation.annotationType())) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Tests whether the given Annotation should be excluded
+ *
+ * @param annotationClass
+ * @return
+ */
+ public static boolean isExcluded(Class<? extends Annotation> annotationClass) {
+ for (TestCategory testCategory : excludedTestCategories) {
+ if (testCategory.match(annotationClass)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ @Override
+ public int size() {
+ return categories.size();
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return categories.isEmpty();
+ }
+
+ @Override
+ public boolean contains(Object o) {
+ return categories.contains(o);
+ }
+
+ @Override
+ public boolean containsAll(Collection<?> c) {
+ return categories.containsAll(c);
+ }
+
+ @Override
+ public Iterator<TestCategory> iterator() {
+ return categories.iterator();
+ }
+
+ @Override
+ public Object[] toArray() {
+ return categories.toArray();
+ }
+
+ @Override
+ public <T> T[] toArray(T[] a) {
+ return categories.toArray(a);
+ }
+
+ @Override
+ public boolean add(TestCategory e) {
+ throw new UnsupportedOperationException("add"); //$NON-NLS-1$
+ }
+
+ @Override
+ public boolean remove(Object o) {
+ throw new UnsupportedOperationException("remove"); //$NON-NLS-1$
+ }
+
+ @Override
+ public boolean addAll(Collection<? extends TestCategory> c) {
+ throw new UnsupportedOperationException("addAll"); //$NON-NLS-1$
+ }
+
+ @Override
+ public boolean retainAll(Collection<?> c) {
+ throw new UnsupportedOperationException("retainAll"); //$NON-NLS-1$
+ }
+
+ @Override
+ public boolean removeAll(Collection<?> c) {
+ throw new UnsupportedOperationException("removeAll"); //$NON-NLS-1$
+ }
+
+ @Override
+ public void clear() {
+ throw new UnsupportedOperationException("clear"); //$NON-NLS-1$
+ }
+
+}
diff --git a/tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/classification/ClassificationRunner.java b/tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/classification/ClassificationRunner.java
new file mode 100644
index 00000000000..89ee5d7dcef
--- /dev/null
+++ b/tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/classification/ClassificationRunner.java
@@ -0,0 +1,102 @@
+/*****************************************************************************
+ * Copyright (c) 2014, 2016 CEA LIST, Christian W. Damus, and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Initial API and implementation
+ * Christian W. Damus (CEA) - add support for conditional tests
+ * Christian W. Damus (CEA) - bug 432813
+ * Christian W. Damus (CEA) - bug 434993
+ * Christian W. Damus (CEA) - bug 436047
+ * Christian W. Damus - bug 485156
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.junit.framework.classification;
+
+import java.util.List;
+
+import org.eclipse.papyrus.junit.framework.classification.rules.Conditional;
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runner.notification.RunNotifier;
+import org.junit.runners.BlockJUnit4ClassRunner;
+import org.junit.runners.model.FrameworkMethod;
+import org.junit.runners.model.InitializationError;
+import org.junit.runners.model.Statement;
+
+/**
+ * A Test Runner which is aware of Classification-related annotations and {@link Conditional @Conditional} tests.
+ *
+ * It ignores the test methods according to their annotations, and the policy defined
+ * in {@link ClassificationConfig}
+ *
+ *
+ * @see {@link ClassificationConfig}
+ * @see {@link TestCategory}
+ * @see Conditional
+ *
+ * @author Camille Letavernier
+ *
+ */
+public class ClassificationRunner extends BlockJUnit4ClassRunner {
+
+ private final ClassificationRunnerImpl impl;
+
+ public ClassificationRunner(Class<?> klass) throws InitializationError {
+ super(klass);
+
+ this.impl = new ClassificationRunnerImpl(new ClassificationRunnerImpl.Delegate() {
+
+ @Override
+ public void runChild(FrameworkMethod method, RunNotifier notifier) {
+ ClassificationRunner.super.runChild(method, notifier);
+ }
+
+ @Override
+ public Description describeChild(FrameworkMethod method) {
+ return ClassificationRunner.super.describeChild(method);
+ }
+
+ @Override
+ public Object createTest() throws Exception {
+ return ClassificationRunner.super.createTest();
+ }
+
+ @Override
+ public List<TestRule> getTestRules(Object target) {
+ return ClassificationRunner.super.getTestRules(target);
+ }
+
+ @Override
+ public Statement classBlock(RunNotifier notifier) {
+ return ClassificationRunner.super.classBlock(notifier);
+ }
+
+ });
+ }
+
+ @Override
+ protected void runChild(FrameworkMethod method, RunNotifier notifier) {
+ impl.runChild(method, notifier);
+ }
+
+ @Override
+ protected Object createTest() throws Exception {
+ return impl.createTest();
+ }
+
+ @Override
+ protected List<TestRule> getTestRules(Object target) {
+ return impl.getTestRules(target);
+ }
+
+ @Override
+ protected Statement classBlock(RunNotifier notifier) {
+ return impl.classBlock(notifier);
+ }
+
+}
diff --git a/tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/classification/ClassificationRunnerImpl.java b/tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/classification/ClassificationRunnerImpl.java
new file mode 100644
index 00000000000..f83dd28819e
--- /dev/null
+++ b/tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/classification/ClassificationRunnerImpl.java
@@ -0,0 +1,346 @@
+/*****************************************************************************
+ * Copyright (c) 2014, 2016 CEA LIST, Christian W. Damus, and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Initial API and implementation
+ * Christian W. Damus (CEA) - add support for conditional tests
+ * Christian W. Damus (CEA) - bug 432813
+ * Christian W. Damus (CEA) - bug 434993
+ * Christian W. Damus (CEA) - bug 436047
+ * Christian W. Damus - bug 485156
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.junit.framework.classification;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Field;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.core.commands.operations.DefaultOperationHistory;
+import org.eclipse.core.runtime.ListenerList;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.jface.viewers.BaseLabelProvider;
+import org.eclipse.jface.viewers.IBaseLabelProvider;
+import org.eclipse.jface.viewers.ILabelProviderListener;
+import org.eclipse.jface.viewers.LabelProviderChangedEvent;
+import org.eclipse.papyrus.infra.tools.util.ListHelper;
+import org.eclipse.papyrus.junit.framework.classification.rules.ConditionRule;
+import org.eclipse.papyrus.junit.framework.classification.rules.Conditional;
+import org.eclipse.papyrus.junit.framework.classification.rules.MemoryLeakRule;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+import org.junit.rules.TestRule;
+import org.junit.rules.TestWatcher;
+import org.junit.runner.Description;
+import org.junit.runner.notification.RunNotifier;
+import org.junit.runners.BlockJUnit4ClassRunner;
+import org.junit.runners.model.FrameworkMethod;
+import org.junit.runners.model.InitializationError;
+import org.junit.runners.model.Statement;
+
+import com.google.common.base.Predicates;
+import com.google.common.base.Supplier;
+import com.google.common.base.Suppliers;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Sets;
+
+/**
+ * Internal implementation of the common classification-sensitive behaviour
+ * of the {@link ClassificationRunner} and {@link ClassificationRunnerWithParameters}
+ * test runners.
+ *
+ * @author Camille Letavernier
+ */
+class ClassificationRunnerImpl {
+
+ private final static long EVENT_LOOP_TIMEOUT = 2L * 60L * 1000L; // 2 minutes in millis
+
+ private final static long ONE_MB = 1024L * 1024L; // a megabyte, in bytes
+
+ private static final Supplier<TestRule> uiFlusherRuleSupplier = createUIFlusherRuleSupplier();
+
+ private final ThreadLocal<Object> preparedTest = new ThreadLocal<Object>();
+
+ private final Delegate delegate;
+
+ ClassificationRunnerImpl(Delegate delegate) throws InitializationError {
+ super();
+
+ this.delegate = delegate;
+ }
+
+ final void runChild(FrameworkMethod method, RunNotifier notifier) {
+ List<Annotation> allAnnotations = ListHelper.asList(method.getAnnotations());
+ allAnnotations.addAll(Arrays.asList(method.getMethod().getDeclaringClass().getAnnotations()));
+ if (ClassificationConfig.shouldRun(allAnnotations.toArray(new Annotation[allAnnotations.size()])) && conditionSatisfied(method)) {
+ delegate.runChild(method, notifier);
+ } else {
+ Description description = delegate.describeChild(method);
+ notifier.fireTestIgnored(description);
+ }
+ }
+
+ final Object createTest() throws Exception {
+ // Look for a prepared test instance
+ Object result = preparedTest.get();
+ if (result != null) {
+ // We won't need this test instance again
+ clearPreparedTest();
+ } else {
+ result = delegate.createTest();
+ }
+
+ return result;
+ }
+
+ final Object prepareTest() throws Exception {
+ // Prepare the test instance and stash it to return on the next invocation
+ Object result = delegate.createTest();
+ preparedTest.set(result);
+ return result;
+ }
+
+ final void clearPreparedTest() {
+ preparedTest.remove();
+ }
+
+ private boolean conditionSatisfied(FrameworkMethod method) {
+ boolean result = true;
+
+ // Does this test declare some precondition?
+ Conditional conditional = method.getAnnotation(Conditional.class);
+ if (conditional != null) {
+ try {
+ // We need the test instance to invoke the condition on it, so prepare it now
+ Object test = prepareTest();
+ result = ConditionRule.testCondition(method.getMethod().getDeclaringClass(), conditional, test);
+ } catch (Throwable t) {
+ // If we couldn't create the test, then we should just ignore it
+ result = false;
+ } finally {
+ if (!result) {
+ // We won't be running the test, so forget the prepared instance (if any)
+ clearPreparedTest();
+ }
+ }
+ }
+
+ return result;
+ }
+
+ List<TestRule> getTestRules(Object target) {
+ // MemoryLeakRules must be the outer-most rules, because leak assertions must only happen after all possible tear-down actions have run
+ return reorderForMemoryLeakRules(delegate.getTestRules(target));
+ }
+
+ private List<TestRule> reorderForMemoryLeakRules(List<TestRule> rules) {
+ // Quick scan for memory rules
+ if (!rules.isEmpty()) {
+ int memoryRuleCount = Iterables.size(Iterables.filter(rules, Predicates.instanceOf(MemoryLeakRule.class)));
+ if (memoryRuleCount > 0) {
+ // Bubble the memory rules to the end
+ int limit = rules.size() - memoryRuleCount;
+
+ for (int i = 0; i < limit; i++) {
+ if (rules.get(i) instanceof MemoryLeakRule) {
+ // Move the rule to the end and take a step back to get the next element
+ rules.add(rules.remove(i--));
+ }
+ }
+ }
+ }
+
+ return rules;
+ }
+
+ Statement classBlock(RunNotifier notifier) {
+ Statement result = delegate.classBlock(notifier);
+
+ // Wrap the class suite in a rule that flushes the UI thread to release memory referenced by UI runnables
+ TestRule uiFlusher = uiFlusherRuleSupplier.get();
+ if (uiFlusher != null) {
+ // This rule doesn't need any actual test description
+ result = uiFlusher.apply(result, Description.EMPTY);
+ }
+
+ return result;
+ }
+
+ private static Supplier<TestRule> createUIFlusherRuleSupplier() {
+ Supplier<TestRule> result = Suppliers.ofInstance(null);
+
+ try {
+ if (PlatformUI.isWorkbenchRunning()) {
+ result = Suppliers.memoize(new Supplier<TestRule>() {
+
+ @Override
+ public TestRule get() {
+ if (Display.getCurrent() != null) {
+ return new TestWatcher() {
+
+ @Override
+ protected void finished(Description description) {
+ final Display display = Display.getCurrent();
+ if (display == null) {
+ // Can't do UI manipulations and history listener hacking except on the UI thread
+ return;
+ }
+
+ flushUIEventQueue(display);
+
+ purgeZombieHistoryListeners();
+
+ clearDecorationScheduler();
+ }
+ };
+ }
+
+ return null;
+ }
+ });
+ }
+ } catch (LinkageError e) {
+ // Not running in Eclipse UI context. Fine
+ }
+
+ return result;
+ }
+
+ private static void flushUIEventQueue(Display display) {
+ long base = System.currentTimeMillis();
+ long timeout = EVENT_LOOP_TIMEOUT;
+
+ // Flush the UI thread's pending events
+ while (!display.isDisposed()) {
+ try {
+ if (!display.readAndDispatch()) {
+ break;
+ }
+ } catch (Exception e) {
+ // Ignore it
+ }
+
+ long now = System.currentTimeMillis();
+ if ((now - base) > timeout) {
+ // This seems to be taking a really long time. What's up?
+ base = now;
+ timeout = timeout * 3L / 2L; // Exponential back-off to avoid over-reporting
+ int freeMB = (int) (Runtime.getRuntime().freeMemory() / ONE_MB);
+ System.err.printf("========%nUI event queue clean-up seems to be running long.%nCurrent free memory: %d MB%n========%n%n", freeMB);
+ }
+ }
+ }
+
+ private static void purgeZombieHistoryListeners() {
+ // If there are no editors open any longer, then all of the action handlers currently
+ // listening to the operation history are leaked, so remove them. This ensures that we
+ // do not end up wasting time in notifying thousands of dead/broken/useless listeners
+ // every time a test case executes an operation on the history (which happens *a lot*)
+ IWorkbench bench = PlatformUI.getWorkbench();
+ IWorkbenchWindow window = (bench == null) ? null : bench.getActiveWorkbenchWindow();
+ if ((window == null) && (bench != null) && (bench.getWorkbenchWindowCount() > 0)) {
+ window = bench.getWorkbenchWindows()[0];
+ }
+ if (window != null && window.getActivePage().getEditorReferences().length == 0) {
+ final ListenerList historyListeners = OperationHistoryHelper.getOperationHistoryListeners();
+ final Object[] listeners = historyListeners.getListeners();
+ for (int i = 0; i < listeners.length; i++) {
+ if (OperationHistoryHelper.shouldRemoveHistoryListener(listeners[i])) {
+ historyListeners.remove(listeners[i]);
+ }
+ }
+ }
+ }
+
+ private static void clearDecorationScheduler() {
+ IWorkbench bench = PlatformUI.getWorkbench();
+ if (bench != null) {
+ IBaseLabelProvider bogusProvider = new BaseLabelProvider();
+
+ try {
+ // The DecoratorManager is a label-provider listener and
+ // it clears the scheduler on label-provider change events
+ ((ILabelProviderListener) bench.getDecoratorManager()).labelProviderChanged(new LabelProviderChangedEvent(bogusProvider));
+ } finally {
+ bogusProvider.dispose();
+ }
+ }
+ }
+
+ //
+ // Nested types
+ //
+
+ static class OperationHistoryHelper {
+
+ static final Field listenersField;
+
+ static final Set<Class<?>> historyListenerClasses;
+
+ static {
+ try {
+ listenersField = DefaultOperationHistory.class.getDeclaredField("listeners");
+ listenersField.setAccessible(true);
+
+ historyListenerClasses = Sets.<Class<?>> newHashSet( //
+ Platform.getBundle("org.eclipse.gmf.runtime.diagram.ui.actions").loadClass("org.eclipse.gmf.runtime.diagram.ui.actions.internal.PropertyChangeContributionItem"), //
+ Platform.getBundle("org.eclipse.ui.workbench").loadClass("org.eclipse.ui.operations.OperationHistoryActionHandler$HistoryListener"));
+ } catch (Exception e) {
+ throw new ExceptionInInitializerError(e);
+ }
+ }
+
+ static ListenerList getOperationHistoryListeners() {
+ try {
+ return (ListenerList) listenersField.get(PlatformUI.getWorkbench().getOperationSupport().getOperationHistory());
+ } catch (Exception e) {
+ org.junit.Assert.fail(e.getLocalizedMessage());
+ return null; // Unreachable
+ }
+ }
+
+ static boolean shouldRemoveHistoryListener(Object listener) {
+ boolean result = historyListenerClasses.contains(listener.getClass().getName());
+
+ if (!result) {
+ // Maybe it's a subclass
+ for (Class<?> next : historyListenerClasses) {
+ if (next.isInstance(listener)) {
+ // Remember this
+ historyListenerClasses.add(listener.getClass());
+ result = true;
+ break;
+ }
+ }
+ }
+
+ return result;
+ }
+ }
+
+ /**
+ * Protocol for a delegate that provides the default test framework behaviour
+ * for the classification runner. These methods are as specified by the
+ * corresponding APIs of the {@link BlockJUnit4ClassRunner} class.
+ */
+ interface Delegate {
+ void runChild(FrameworkMethod method, RunNotifier notifier);
+
+ Description describeChild(FrameworkMethod method);
+
+ Object createTest() throws Exception;
+
+ List<TestRule> getTestRules(Object target);
+
+ Statement classBlock(RunNotifier notifier);
+ }
+}
diff --git a/tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/classification/ClassificationRunnerWithParameters.java b/tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/classification/ClassificationRunnerWithParameters.java
new file mode 100644
index 00000000000..ca3079f3052
--- /dev/null
+++ b/tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/classification/ClassificationRunnerWithParameters.java
@@ -0,0 +1,102 @@
+/*****************************************************************************
+ * Copyright (c) 2016 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.junit.framework.classification;
+
+import java.util.List;
+
+import org.eclipse.papyrus.junit.framework.classification.rules.Conditional;
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runner.notification.RunNotifier;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+import org.junit.runners.Parameterized.UseParametersRunnerFactory;
+import org.junit.runners.model.FrameworkMethod;
+import org.junit.runners.model.InitializationError;
+import org.junit.runners.model.Statement;
+import org.junit.runners.parameterized.BlockJUnit4ClassRunnerWithParameters;
+import org.junit.runners.parameterized.TestWithParameters;
+
+/**
+ * A Test Runner which is aware of Classification-related annotations and {@link Conditional @Conditional} tests,
+ * for use with test {@link Parameters}.
+ *
+ * It ignores the test methods according to their annotations, and the policy defined
+ * in {@link ClassificationConfig}.
+ *
+ * @see Parameterized
+ * @see UseParametersRunnerFactory
+ * @see ClassificationRunnerWithParametersFactory
+ * @see ClassificationConfig
+ * @see TestCategory
+ * @see Conditional
+ *
+ */
+public class ClassificationRunnerWithParameters extends BlockJUnit4ClassRunnerWithParameters {
+
+ private final ClassificationRunnerImpl impl;
+
+ public ClassificationRunnerWithParameters(TestWithParameters test) throws InitializationError {
+ super(test);
+
+ this.impl = new ClassificationRunnerImpl(new ClassificationRunnerImpl.Delegate() {
+
+ @Override
+ public void runChild(FrameworkMethod method, RunNotifier notifier) {
+ ClassificationRunnerWithParameters.super.runChild(method, notifier);
+ }
+
+ @Override
+ public Description describeChild(FrameworkMethod method) {
+ return ClassificationRunnerWithParameters.super.describeChild(method);
+ }
+
+ @Override
+ public Object createTest() throws Exception {
+ return ClassificationRunnerWithParameters.super.createTest();
+ }
+
+ @Override
+ public List<TestRule> getTestRules(Object target) {
+ return ClassificationRunnerWithParameters.super.getTestRules(target);
+ }
+
+ @Override
+ public Statement classBlock(RunNotifier notifier) {
+ return ClassificationRunnerWithParameters.super.classBlock(notifier);
+ }
+
+ });
+ }
+
+ @Override
+ protected void runChild(FrameworkMethod method, RunNotifier notifier) {
+ impl.runChild(method, notifier);
+ }
+
+ @Override
+ public Object createTest() throws Exception {
+ return impl.createTest();
+ }
+
+ @Override
+ protected List<TestRule> getTestRules(Object target) {
+ return impl.getTestRules(target);
+ }
+
+ @Override
+ protected Statement classBlock(RunNotifier notifier) {
+ return impl.classBlock(notifier);
+ }
+
+}
diff --git a/tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/classification/ClassificationRunnerWithParametersFactory.java b/tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/classification/ClassificationRunnerWithParametersFactory.java
new file mode 100644
index 00000000000..bfb7a29468b
--- /dev/null
+++ b/tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/classification/ClassificationRunnerWithParametersFactory.java
@@ -0,0 +1,45 @@
+/*****************************************************************************
+ * Copyright (c) 2016 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.junit.framework.classification;
+
+import org.junit.runner.RunWith;
+import org.junit.runner.Runner;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.UseParametersRunnerFactory;
+import org.junit.runners.model.InitializationError;
+import org.junit.runners.parameterized.ParametersRunnerFactory;
+import org.junit.runners.parameterized.TestWithParameters;
+
+/**
+ * Factory for classification-sensitive parameterized test suites.
+ * Specify this factory in the {@literal @}{@link UseParametersRunnerFactory}
+ * annotation on your <tt>{@literal @}{@link RunWith}({@link Parameterized}.class)</tt>
+ * test class to support the classfication and condition annotations of the Papyrus
+ * test framework.
+ *
+ * @see Parameterized
+ * @see UseParametersRunnerFactory
+ * @since 1.2
+ */
+public class ClassificationRunnerWithParametersFactory implements ParametersRunnerFactory {
+
+ public ClassificationRunnerWithParametersFactory() {
+ super();
+ }
+
+ @Override
+ public Runner createRunnerForTestWithParameters(TestWithParameters test) throws InitializationError {
+ return new ClassificationRunnerWithParameters(test);
+ }
+}
diff --git a/tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/classification/ClassificationSuite.java b/tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/classification/ClassificationSuite.java
new file mode 100644
index 00000000000..a7bf1c0d3b3
--- /dev/null
+++ b/tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/classification/ClassificationSuite.java
@@ -0,0 +1,295 @@
+/*****************************************************************************
+ * Copyright (c) 2015 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.junit.framework.classification;
+
+import java.lang.annotation.Annotation;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.util.ArrayDeque;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Deque;
+import java.util.Iterator;
+import java.util.List;
+
+import org.junit.runner.Description;
+import org.junit.runner.Runner;
+import org.junit.runner.notification.RunNotifier;
+import org.junit.runners.Suite;
+import org.junit.runners.model.InitializationError;
+import org.junit.runners.model.RunnerBuilder;
+import org.junit.runners.model.Statement;
+
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.CacheLoader;
+import com.google.common.cache.LoadingCache;
+import com.google.common.collect.AbstractIterator;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+import com.google.common.collect.ObjectArrays;
+
+/**
+ * A specialized Test {@linkplain Suite Suite} runner that recognizes the Papyrus-specific
+ * {@link ClassificationConfig classification} annotations on the suite as a whole. It also
+ * supports a dynamic specification of test suites to include via the {@literal @}{@link DynamicClasses}
+ * annotation, especially useful for generated tests that may or may not have been generated at
+ * the time of test execution (or at least of compilation of the test suite class).
+ */
+public class ClassificationSuite extends Suite {
+
+ /**
+ * Mapping of whether any tests at all in a suite tree are statically enabled, according to
+ * their annotations.
+ */
+ private static final LoadingCache<Description, Boolean> enabledSuites = CacheBuilder.newBuilder().build(
+ CacheLoader.from(ClassificationSuite::isEnabled));
+
+ private Description description;
+
+ public ClassificationSuite(Class<?> klass, RunnerBuilder builder) throws InitializationError {
+ this(builder, klass, getAnnotatedClasses(klass));
+ }
+
+ public ClassificationSuite(Class<?> klass, Class<?>[] suiteClasses) throws InitializationError {
+ super(klass, withDynamicSuites(klass, suiteClasses));
+ }
+
+ public ClassificationSuite(RunnerBuilder builder, Class<?> klass, Class<?>[] suiteClasses) throws InitializationError {
+ super(builder, klass, withDynamicSuites(klass, suiteClasses));
+ }
+
+ private static Class<?>[] getAnnotatedClasses(Class<?> class_) throws InitializationError {
+ SuiteClasses annotation = class_.getAnnotation(SuiteClasses.class);
+ if (annotation == null) {
+ throw new InitializationError(String.format("class '%s' must have a SuiteClasses annotation", class_.getName()));
+ }
+ return annotation.value();
+ }
+
+ private static Class<?>[] withDynamicSuites(Class<?> suiteClass, Class<?>[] staticSuites) {
+ Class<?>[] result = staticSuites;
+
+ Class<?>[] dynamicSuites = getDynamicSuites(suiteClass);
+ if (dynamicSuites.length > 0) {
+ result = ObjectArrays.concat(staticSuites, dynamicSuites, Class.class);
+ }
+
+ return result;
+ }
+
+ private static Class<?>[] getDynamicSuites(Class<?> suiteClass) {
+ List<Class<?>> result;
+
+ DynamicClasses dynclasses = suiteClass.getAnnotation(DynamicClasses.class);
+ if (dynclasses == null) {
+ result = Collections.emptyList();
+ } else {
+ result = Lists.newArrayListWithCapacity(dynclasses.value().length);
+ for (String classname : dynclasses.value()) {
+ try {
+ result.add(suiteClass.getClassLoader().loadClass(classname));
+ } catch (Exception e) {
+ // OK. It's not there, so we just ignore it
+ }
+ }
+ }
+
+ return Iterables.toArray(result, Class.class);
+ }
+
+ @Override
+ protected List<Runner> getChildren() {
+ // If I don't match the current configuration, none of my tests will run, so don't even provide them
+ // because they just inflate the size of the progress meter
+ if (ClassificationConfig.shouldRun(getRunnerAnnotations())) {
+ return super.getChildren();
+ } else {
+ return Collections.emptyList();
+ }
+ }
+
+ @Override
+ public void run(RunNotifier notifier) {
+ // If I don't match the current configuration, none of my tests should be run
+ if (ClassificationConfig.shouldRun(getRunnerAnnotations())) {
+ super.run(notifier);
+ } else {
+ Description description = getDescription();
+ notifier.fireTestIgnored(description);
+ }
+ }
+
+ @Override
+ protected Statement classBlock(final RunNotifier notifier) {
+ // We never throw in these lazy calculations
+ return enabledSuites.getUnchecked(getDescription())
+ // Include the @BeforeClass, @AfterClass, and @ClassRule steps
+ ? super.classBlock(notifier)
+ // Just the bare bones to record everything that is skipped
+ : skipAll(notifier);
+ }
+
+ @Override
+ public Description getDescription() {
+ if (description == null) {
+ description = super.getDescription();
+ }
+ return description;
+ }
+
+ /**
+ * Creates a statement that simply skips all of the tests in my suite, recursively.
+ *
+ * @param notifier
+ * tracks the execution (or, rather, skipping) of the tests
+ *
+ * @return the all-skipping statement
+ */
+ protected Statement skipAll(RunNotifier notifier) {
+ return new Statement() {
+ @Override
+ public void evaluate() {
+ skipAll(getDescription(), notifier);
+ }
+ };
+ }
+
+ /**
+ * Skips all of the tests in the given {@code suite}, recursively.
+ *
+ * @param suite
+ * a test suite to skip
+ * @param notifier
+ * tracks the execution (or, rather, skipping) of the tests
+ */
+ protected void skipAll(Description suite, RunNotifier notifier) {
+ for (Description next : suite.getChildren()) {
+ if (next.isSuite()) {
+ skipAll(next, notifier);
+ } else {
+ notifier.fireTestIgnored(next);
+ }
+ }
+
+ notifier.fireTestIgnored(suite);
+ }
+
+ /**
+ * Queries whether a given {@code suite} will run any tests at all.
+ *
+ * @param suite
+ * a test suite
+ * @return whether it has any leaf tests that will not be ignored for some reason
+ */
+ static boolean isEnabled(Description suite) {
+ boolean result = false;
+
+ for (Description leaf : getLeafTests(suite)) {
+ Iterable<Annotation> annotations = Iterables.concat(
+ leaf.getAnnotations(),
+ Arrays.asList(leaf.getTestClass().getAnnotations()));
+
+ if (ClassificationConfig.shouldRun(Iterables.toArray(annotations, Annotation.class))) {
+ result = true;
+ break;
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * Obtains an iteration of all of the leaf-level tests in a {@code suite}, in depth-first order.
+ *
+ * @param suite
+ * a test suite to iterate
+ *
+ * @return all of its leaf-level tests
+ */
+ static Iterable<Description> getLeafTests(Description suite) {
+ return new Iterable<Description>() {
+
+ @Override
+ public Iterator<Description> iterator() {
+ return new AbstractIterator<Description>() {
+ Deque<Iterator<Description>> stack = new ArrayDeque<>();
+ Iterator<Description> current = suite.getChildren().iterator();
+
+ // Advance the tractor
+ Iterator<Description> feed() {
+ while (!current.hasNext()) {
+ current = stack.pollLast();
+
+ if (current == null) {
+ current = Collections.emptyIterator();
+ break;
+ }
+ }
+
+ return current;
+ }
+
+ void push(Description suite) {
+ stack.addLast(current);
+ current = suite.getChildren().iterator();
+ }
+
+ @Override
+ protected Description computeNext() {
+ Description result = null;
+
+ while ((result == null) && feed().hasNext()) {
+ Description next = feed().next();
+
+ if (next.isTest() && (next.getTestClass() != null)) {
+ result = next;
+ } else if (next.isSuite()) {
+ // Push this suite onto the stack
+ push(next);
+ } else {
+ // Otherwise it's a weird test without a class?!?
+ System.err.println("Leaf test without a class: " + next);
+ }
+ }
+
+ if (result == null) {
+ result = endOfData();
+ }
+
+ return result;
+ }
+ };
+ }
+ };
+ }
+
+ //
+ // Nested types
+ //
+
+ /**
+ * An annotation like the {@literal @}{@link SuiteClasses} that specifies, by name, test suite classes
+ * to find and include dynamically. Any that are not available are simply ignored.
+ */
+ @Retention(RetentionPolicy.RUNTIME)
+ @Target(ElementType.TYPE)
+ public @interface DynamicClasses {
+ /**
+ * Names of test suite classes to optionally include in the test suite.
+ */
+ String[] value();
+ }
+}
diff --git a/tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/classification/ExpensiveTest.java b/tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/classification/ExpensiveTest.java
new file mode 100644
index 00000000000..2abeedb12ed
--- /dev/null
+++ b/tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/classification/ExpensiveTest.java
@@ -0,0 +1,39 @@
+/*****************************************************************************
+ * Copyright (c) 2014 CEA LIST.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Initial API and implementation
+ *****************************************************************************/
+package org.eclipse.papyrus.junit.framework.classification;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+
+/**
+ * Indicates that a test is expensive, and should be excluded from a Lightweight test job (e.g. Gerrit)
+ *
+ *
+ * This annotation must be used with the {@link ClassificationRule}
+ *
+ * @author Camille Letavernier
+ *
+ */
+@Target({ ElementType.METHOD, ElementType.TYPE })
+@Retention(RetentionPolicy.RUNTIME)
+public @interface ExpensiveTest {
+
+ /**
+ * A description
+ *
+ * @return
+ */
+ String value() default "";
+}
diff --git a/tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/classification/FailingTest.java b/tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/classification/FailingTest.java
new file mode 100644
index 00000000000..d528a7048d8
--- /dev/null
+++ b/tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/classification/FailingTest.java
@@ -0,0 +1,39 @@
+/*****************************************************************************
+ * Copyright (c) 2014 CEA LIST.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Initial API and implementation
+ *****************************************************************************/
+package org.eclipse.papyrus.junit.framework.classification;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+
+/**
+ * Indicates that a test currently fails. It can be used to sort new (unidentified) regressions
+ * from known (reported) issues.
+ *
+ * This annotation must be used with the {@link ClassificationRule}
+ *
+ * @author Camille Letavernier
+ *
+ */
+@Target({ ElementType.METHOD, ElementType.TYPE })
+@Retention(RetentionPolicy.RUNTIME)
+public @interface FailingTest {
+
+ /**
+ * A specific message explaining why this test is failing
+ *
+ * @return
+ */
+ String value() default "";
+}
diff --git a/tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/classification/GeneratedTest.java b/tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/classification/GeneratedTest.java
new file mode 100644
index 00000000000..7f1737a053f
--- /dev/null
+++ b/tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/classification/GeneratedTest.java
@@ -0,0 +1,41 @@
+/*****************************************************************************
+ * Copyright (c) 2014 CEA LIST.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Initial API and implementation
+ *****************************************************************************/
+package org.eclipse.papyrus.junit.framework.classification;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+
+/**
+ * Indicates that this test has been generated with the Papyrus Test Generation Framework
+ * (see https://wiki.eclipse.org/Papyrus_Developer_Guide/Automatic_Test_Generation_for_Diagram_Editors)
+ *
+ *
+ * This annotation must be used with the {@link ClassificationRule}
+ *
+ * @author Camille Letavernier
+ * @since 1.2
+ *
+ */
+@Target({ ElementType.METHOD, ElementType.TYPE })
+@Retention(RetentionPolicy.RUNTIME)
+public @interface GeneratedTest {
+
+ /**
+ * A description
+ *
+ * @return
+ */
+ String value() default "";
+}
diff --git a/tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/classification/InteractiveTest.java b/tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/classification/InteractiveTest.java
new file mode 100644
index 00000000000..5f941503360
--- /dev/null
+++ b/tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/classification/InteractiveTest.java
@@ -0,0 +1,38 @@
+/*****************************************************************************
+ * Copyright (c) 2014 CEA LIST.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Initial API and implementation
+ *****************************************************************************/
+package org.eclipse.papyrus.junit.framework.classification;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Indicates that a test is interactive, e.g. it opens a user dialog. Such tests cannot be run
+ * automatically and should be disabled on Hudson
+ *
+ * This annotation must be used with the {@link ClassificationRule}
+ *
+ * @author Camille Letavernier
+ *
+ */
+@Target({ ElementType.METHOD, ElementType.TYPE })
+@Retention(RetentionPolicy.RUNTIME)
+public @interface InteractiveTest {
+
+ /**
+ * A specific message explaining why this test is failing
+ *
+ * @return
+ */
+ String value() default "";
+}
diff --git a/tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/classification/InvalidTest.java b/tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/classification/InvalidTest.java
new file mode 100644
index 00000000000..b11dc8588d1
--- /dev/null
+++ b/tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/classification/InvalidTest.java
@@ -0,0 +1,38 @@
+/*****************************************************************************
+ * Copyright (c) 2014 CEA LIST.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Initial API and implementation
+ *****************************************************************************/
+package org.eclipse.papyrus.junit.framework.classification;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Indicates that a test may fail because it is not properly implemented
+ * (e.g. not compatible with Hudson, because it opens some blocking dialogs)
+ *
+ * This annotation must be used with the {@link ClassificationRule}
+ *
+ * @author Camille Letavernier
+ *
+ */
+@Target({ ElementType.METHOD, ElementType.TYPE })
+@Retention(RetentionPolicy.RUNTIME)
+public @interface InvalidTest {
+
+ /**
+ * A specific message explaining why this test may be invalid
+ *
+ * @return
+ */
+ String value() default "";
+}
diff --git a/tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/classification/NotImplemented.java b/tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/classification/NotImplemented.java
new file mode 100644
index 00000000000..f4a98258268
--- /dev/null
+++ b/tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/classification/NotImplemented.java
@@ -0,0 +1,39 @@
+/*****************************************************************************
+ * Copyright (c) 2014 CEA LIST.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Initial API and implementation
+ *****************************************************************************/
+package org.eclipse.papyrus.junit.framework.classification;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Indicates that a test may fail because the tested feature
+ * is not yet implemented (Test-driven development)
+ *
+ * This annotation must be used with the {@link ClassificationRule}
+ *
+ * @author Camille Letavernier
+ *
+ */
+@Target({ ElementType.METHOD, ElementType.TYPE })
+@Retention(RetentionPolicy.RUNTIME)
+public @interface NotImplemented {
+
+ /**
+ * A specific message explaining what needs to be implemented
+ * for this test to run
+ *
+ * @return
+ */
+ String value() default "";
+}
diff --git a/tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/classification/TestCategory.java b/tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/classification/TestCategory.java
new file mode 100644
index 00000000000..aee739aa5ec
--- /dev/null
+++ b/tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/classification/TestCategory.java
@@ -0,0 +1,73 @@
+/*****************************************************************************
+ * Copyright (c) 2014 CEA LIST.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Initial API and implementation
+ *****************************************************************************/
+package org.eclipse.papyrus.junit.framework.classification;
+
+import java.lang.annotation.Annotation;
+
+/**
+ * Enumerates all available TestCategories
+ *
+ * @author Camille Letavernier
+ *
+ */
+public enum TestCategory {
+
+ /**
+ * Test methods annotated with {@link NotImplemented}
+ */
+ NotImplemented(NotImplemented.class),
+
+ /**
+ * Test methods annotated with {@link InvalidTest}
+ */
+ InvalidTest(InvalidTest.class),
+
+ /**
+ * Test methods annotated with {@link FailingTest}
+ */
+ FailingTest(FailingTest.class),
+
+ /**
+ * Test methods annotated with {@link InteractiveTest}
+ */
+ InteractiveTest(InteractiveTest.class),
+
+ /**
+ * Test methods annotated with {@link GeneratedTest}
+ */
+ GeneratedTest(GeneratedTest.class),
+
+ /**
+ * Test methods annotated with {@link ExpensiveTest}
+ */
+ ExpensiveTest(ExpensiveTest.class),
+
+ /**
+ * Test methods without any classification-related annotation
+ */
+ Standard();
+
+ private Class<? extends Annotation> annotationClass;
+
+ private TestCategory() {
+ //Empty constructor for Standard
+ }
+
+ private TestCategory(Class<? extends Annotation> annotationClass) {
+ this.annotationClass = annotationClass;
+ }
+
+ public boolean match(Class<? extends Annotation> annotationClass) {
+ return annotationClass == this.annotationClass;
+ }
+
+}
diff --git a/tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/classification/rules/Condition.java b/tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/classification/rules/Condition.java
new file mode 100644
index 00000000000..27ac6215098
--- /dev/null
+++ b/tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/classification/rules/Condition.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2014 CEA and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus (CEA) - Initial API and implementation
+ *
+ */
+package org.eclipse.papyrus.junit.framework.classification.rules;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+
+/**
+ * An annotation on a boolean-valued field or method that implements a condition to test for {@linkplain Conditional conditional execution} of test
+ * cases. The {@link #key() key} is optional; the implicit key is the field or method name.
+ *
+ * @see Conditional
+ * @see ConditionRule
+ */
+@Target({ ElementType.METHOD, ElementType.FIELD })
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Condition {
+
+ String key() default "";
+}
diff --git a/tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/classification/rules/ConditionRule.java b/tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/classification/rules/ConditionRule.java
new file mode 100644
index 00000000000..d7db493547f
--- /dev/null
+++ b/tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/classification/rules/ConditionRule.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2014 CEA and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus (CEA) - Initial API and implementation
+ *
+ */
+package org.eclipse.papyrus.junit.framework.classification.rules;
+
+import static org.junit.Assert.fail;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Member;
+import java.lang.reflect.Method;
+
+import org.eclipse.papyrus.junit.framework.classification.ClassificationRunner;
+import org.junit.Assume;
+import org.junit.Rule;
+import org.junit.rules.MethodRule;
+import org.junit.runners.model.FrameworkMethod;
+import org.junit.runners.model.Statement;
+
+
+/**
+ * <p>
+ * A JUnit {@linkplain Rule rule} that skips tests annotated as {@linkplain Conditional @Conditional} when their {@linkplain Condition conditions} are
+ * not satisfied. This model is compatible with the JUnit execution and reporting in the Papyrus Hudson build, which does not understand
+ * {@linkplain Assume#assumeThat(Object, org.hamcrest.Matcher) assumption failures} and reports them as test failures.
+ * </p>
+ * <p>
+ * <b>Note</b> that this is not ideal, as tests will be reported in the JDT's JUnit view as passes, when in fact they should be reported as skipped.
+ * It is better to use the {@link ClassificationRunner} if possible (such as when not using some other test runner).
+ * </p>
+ *
+ * @see Conditional
+ * @see Condition
+ * @see Rule
+ * @see ClassificationRunner
+ */
+public class ConditionRule implements MethodRule {
+
+ public ConditionRule() {
+ super();
+ }
+
+ public Statement apply(final Statement base, final FrameworkMethod method, final Object target) {
+ return new Statement() {
+
+ @Override
+ public void evaluate() throws Throwable {
+ if(testCondition(method.getMethod().getDeclaringClass(), method.getAnnotation(Conditional.class), target)) {
+ base.evaluate();
+ }
+ }
+ };
+ }
+
+ public static boolean testCondition(Class<?> testClass, Conditional conditional, Object test) {
+ boolean result = true;
+
+ if(conditional != null) {
+ Method conditionMethod = findConditionMethod(testClass, conditional);
+ if(conditionMethod != null) {
+ result = evaluateCondition(conditionMethod, test);
+ } else {
+ Field conditionField = findConditionField(testClass, conditional);
+ if(conditionField != null) {
+ result = evaluateCondition(conditionField, test);
+ } else {
+ fail("Condition not found: " + conditional.key());
+ }
+ }
+ }
+
+ return result;
+ }
+
+ static Method findConditionMethod(Class<?> testClass, Conditional conditional) {
+ Method result = null;
+
+ for(Method next : testClass.getDeclaredMethods()) {
+ Condition condition = next.getAnnotation(Condition.class);
+ if((condition != null) && match(conditional.key(), condition, next)) {
+ result = next;
+ break;
+ }
+ }
+
+ return result;
+ }
+
+ static Field findConditionField(Class<?> testClass, Conditional conditional) {
+ Field result = null;
+
+ for(Field next : testClass.getDeclaredFields()) {
+ Condition condition = next.getAnnotation(Condition.class);
+ if((condition != null) && match(conditional.key(), condition, next)) {
+ result = next;
+ break;
+ }
+ }
+
+ return result;
+ }
+
+ static boolean evaluateCondition(Method conditionMethod, Object test) {
+ boolean result = true;
+
+ try {
+ result = (Boolean)conditionMethod.invoke(test);
+ } catch (InvocationTargetException e) {
+ e.getTargetException().printStackTrace();
+ fail("Condition method evaluation failed: " + e.getTargetException().getLocalizedMessage());
+ } catch (Exception e) {
+ fail(String.format("Condition method must be public, accept no arguments, and return a boolean result: %s::%s()", conditionMethod.getDeclaringClass().getSimpleName(), conditionMethod.getName()));
+ }
+
+ return result;
+ }
+
+ static boolean evaluateCondition(Field conditionField, Object test) {
+ boolean result = true;
+
+ try {
+ result = (Boolean)conditionField.get(test);
+ } catch (Exception e) {
+ fail(String.format("Condition field must be public and boolean-valued: %s::%s", conditionField.getDeclaringClass().getSimpleName(), conditionField.getName()));
+ }
+
+ return result;
+ }
+
+ static boolean match(String conditionKey, Condition condition, Member conditionMember) {
+ String match = condition.key();
+ if((match == null) || match.equals("")) {
+ match = conditionMember.getName();
+ }
+
+ return match.equals(conditionKey);
+ }
+}
diff --git a/tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/classification/rules/Conditional.java b/tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/classification/rules/Conditional.java
new file mode 100644
index 00000000000..a8c4dc0153d
--- /dev/null
+++ b/tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/classification/rules/Conditional.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2014 CEA and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus (CEA) - Initial API and implementation
+ *
+ */
+package org.eclipse.papyrus.junit.framework.classification.rules;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import org.junit.Test;
+
+
+/**
+ * An annotation for {@linkplain Test test methods} that are to be executed conditionally. The {@link #key() key} indicates a field or method
+ * annotated with {@link Condition @Condition}. If the condition evaluates {@code false}, the test case is skipped.
+ *
+ * @see Condition
+ * @see ConditionRule
+ */
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Conditional {
+
+ /**
+ * Identifies a condition field or method annotated with {@link Condition @Condition}, which either specifies an explicit
+ * {@linkplain Condition#key() key} or implicit by field/method name.
+ *
+ * @return the key of the condition to evaluate
+ */
+ String key();
+}
diff --git a/tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/classification/rules/MemoryLeakRule.java b/tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/classification/rules/MemoryLeakRule.java
new file mode 100644
index 00000000000..6fbd9611fad
--- /dev/null
+++ b/tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/classification/rules/MemoryLeakRule.java
@@ -0,0 +1,304 @@
+/*
+ * Copyright (c) 2014, 2015 CEA, Christian W. Damus, and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus (CEA) - Initial API and implementation
+ * Christian W. Damus - bug 451013
+ * Christian W. Damus - bug 483721
+ *
+ */
+package org.eclipse.papyrus.junit.framework.classification.rules;
+
+import static org.hamcrest.CoreMatchers.notNullValue;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.fail;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.lang.ref.Reference;
+import java.lang.ref.ReferenceQueue;
+import java.lang.ref.SoftReference;
+import java.lang.ref.WeakReference;
+import java.util.List;
+import java.util.Map;
+import java.util.WeakHashMap;
+
+import org.eclipse.emf.ecore.EAttribute;
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.EStructuralFeature;
+import org.junit.rules.TestWatcher;
+import org.junit.runner.Description;
+import org.junit.runner.JUnitCore;
+import org.junit.runner.Request;
+
+import com.google.common.base.Function;
+import com.google.common.base.Joiner;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+
+
+/**
+ * A simple JUnit rule for tracking memory leaks. Simply {@linkplain #add(Object) add objects} during your test execution, make assertions if desired,
+ * and on successful completion of the body of the test, this rule verifies that none of the tracked objects have leaked.
+ * Tests that are sensitive to references being retained temporarily via {@link SoftReference}s should be annotated as {@link SoftReferenceSensitive
+ * &#x40;SoftReferenceSensitive} so that the rule may employ extra measures to ensure that soft references are cleared.
+ *
+ * @see SoftReferenceSensitive
+ */
+public class MemoryLeakRule extends TestWatcher {
+ private static final boolean DEBUG = Boolean.getBoolean("MemoryLeakRule.debug");
+
+ private static final int DEQUEUE_REF_ITERATIONS = 3;
+
+ private static final int DEQUEUE_REF_TIMEOUT = 1000; // Millis
+
+ private static final int GC_ITERATIONS = 10;
+
+ private static final int CLEAR_SOFT_REFS_ITERATIONS = 3;
+
+ private static final Map<Class<?>, Boolean> WARMED_UP_SUITES = new WeakHashMap<Class<?>, Boolean>();
+
+ private static boolean warmingUp;
+
+ private ReferenceQueue<Object> queue;
+
+ private List<WeakReference<Object>> tracker;
+
+ private String testName;
+
+ private Class<?> testClass;
+
+ private boolean isSoftReferenceSensitive;
+
+ public MemoryLeakRule() {
+ super();
+ }
+
+ public void add(Object leak) {
+ assertThat("Cannot track null references for memory leaks.", leak, notNullValue());
+
+ if (queue == null) {
+ queue = new ReferenceQueue<Object>();
+ tracker = Lists.newArrayList();
+ }
+
+ tracker.add(new WeakReference<Object>(leak, queue));
+ }
+
+ public String getTestName() {
+ return testName;
+ }
+
+ @Override
+ protected void starting(Description description) {
+ testName = description.getMethodName();
+ testClass = description.getTestClass();
+
+ isSoftReferenceSensitive = description.getAnnotation(SoftReferenceSensitive.class) != null;
+
+ if (isSoftReferenceSensitive && !isWarmedUp() && !warmingUp) {
+ // Warm up the soft-reference sensitive tests by running this one up-front, first,
+ // because the first such test to execute always results in a spurious failure
+ // (at least, such is the case on the Mac build of JRE 1.6)
+ warmingUp = true;
+ try {
+ warmUp();
+ } finally {
+ warmingUp = false;
+ }
+ }
+ }
+
+ @Override
+ protected void succeeded(Description description) {
+ // If the test's assertions (if any) all succeeded, then check for leaks on the way out
+ if (tracker == null) {
+ // No leaks to assert
+ return;
+ }
+
+ // Assert that our tracked objects are now all unreachable
+ while (!tracker.isEmpty()) {
+ Reference<?> ref = dequeueTracker();
+
+ for (int i = 0; ((ref == null) && isSoftReferenceSensitive) && (i < CLEAR_SOFT_REFS_ITERATIONS); i++) {
+ // Maybe there are soft references retaining our objects? Desperation move.
+ // On some platforms, our simulated OOME doesn't actually purge all soft
+ // references (contrary to Java spec!), so we have to repeat
+ forceClearSoftReferenceCaches();
+
+ // Try once more
+ ref = dequeueTracker();
+ }
+
+ if (!tracker.remove(ref) && !tracker.isEmpty()) {
+ // The remaining tracked elements are leaked
+ final String leaks = Joiner.on('\n').join(Iterables.transform(tracker, label()));
+ if (warmingUp) {
+ debug("Warm-up detected leaks: %s%n", leaks.replace('\n', ' '));
+ }
+ fail("One or more objects leaked:\n" + leaks);
+ break; // Unreachable
+ }
+ }
+ }
+
+ @Override
+ protected void finished(Description description) {
+ // Clean up
+ tracker = null;
+ queue = null;
+ }
+
+ Reference<?> dequeueTracker() {
+ Reference<?> result = null;
+
+ try {
+ for (int i = 0; (result == null) && (i < DEQUEUE_REF_ITERATIONS); i++) {
+ // Try to force GC
+ collectGarbage();
+
+ result = queue.remove(DEQUEUE_REF_TIMEOUT);
+ }
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ fail("JUnit was interrupted");
+ }
+
+ return result;
+ }
+
+ Function<WeakReference<?>, String> label() {
+ return new Function<WeakReference<?>, String>() {
+
+ @Override
+ public String apply(WeakReference<?> input) {
+ return label(input.get());
+ }
+ };
+ }
+
+ String label(Object input) {
+ String result = null;
+
+ if (!(input instanceof EObject)) {
+ result = String.valueOf(input);
+ } else {
+ EObject object = (EObject) input;
+ EClass eclass = object.eClass();
+ String label = null;
+
+ EStructuralFeature nameFeature = eclass.getEStructuralFeature("name"); //$NON-NLS-1$
+ if (nameFeature != null) {
+ label = String.valueOf(object.eGet(nameFeature));
+ } else {
+ // Look for anything label-like
+ for (EAttribute next : eclass.getEAllAttributes()) {
+ if (!next.isMany() && next.getEAttributeType().getInstanceClass() == String.class) {
+ label = (String) object.eGet(next);
+ if ((label != null) && !label.isEmpty()) {
+ break;
+ }
+ }
+ }
+ }
+
+ result = String.format("<%s> %s", eclass.getName(), label);
+ }
+
+ return result;
+ }
+
+ void collectGarbage() {
+ // Try a few times to decrease the amount of used heap space
+ final Runtime rt = Runtime.getRuntime();
+
+ Long usedMem = rt.totalMemory() - rt.freeMemory();
+ Long prevUsedMem = usedMem;
+
+ for (int i = 0; (prevUsedMem <= usedMem) && (i < GC_ITERATIONS); i++) {
+ rt.gc();
+ Thread.yield();
+
+ prevUsedMem = usedMem;
+ usedMem = rt.totalMemory() - rt.freeMemory();
+ }
+ }
+
+ void forceClearSoftReferenceCaches() {
+ // There are components in the Eclipse workbench that maintain soft references to objects for
+ // performance caches. For example, the the Common Navigator Framework used by Model Explorer
+ // caches mappings of elements in the tree to the content extensions that provided them using
+ // EvalutationReferences [sic] that are SoftReferences
+
+ // This is a really gross HACK and runs the risk that some other thread(s) also may see OOMEs!
+ try {
+ List<Object[]> hog = Lists.newLinkedList();
+ for (;;) {
+ hog.add(new Object[getLargeMemorySize()]);
+ }
+ } catch (OutOfMemoryError e) {
+ // Good! The JVM guarantees that all soft references are cleared before throwing OOME,
+ // so we can be assured that they are now cleared
+ } finally {
+ if (warmingUp) {
+ // We have successfully warmed up the soft-references hack
+ WARMED_UP_SUITES.put(testClass, true);
+ }
+ }
+ }
+
+ private static int getLargeMemorySize() {
+ // These 64 megs are multiplied by the size of a pointer!
+ return 64 * 1024 * 1024;
+ }
+
+ private boolean isWarmedUp() {
+ return Boolean.TRUE.equals(WARMED_UP_SUITES.get(testClass));
+ }
+
+ private void warmUp() {
+ // The first test that relies on the soft-reference clearing hack will
+ // always fail, so run such a test once up-front. Call this a metahack
+
+ try {
+ debug("Warming up test suite: %s (%s)%n", testClass.getName(), testName);
+ new JUnitCore().run(Request.method(testClass, testName));
+ } catch (Exception e) {
+ // Fine, so the warm-up didn't work
+ e.printStackTrace();
+ }
+ }
+
+ private static void debug(String format, Object... args) {
+ if (DEBUG) {
+ System.err.printf("[MEM] " + format, args);
+ }
+ }
+
+ //
+ // Nested types
+ //
+
+ /**
+ * Annotates a test that is sensitive to references being cached by {@link SoftReference}s.
+ * Such tests will take additional drastic measures to try to force the JVM to clear soft
+ * reference caches in order to release all possible references to objects tracked for leaks.
+ * Because the first such test is expected always to result in a spurious failure (at least,
+ * such is the case on the Mac OS X build of J2SE 1.6), the rule "warms up" the test suite
+ * by running one such test in isolation before running any others.
+ */
+ @Target(ElementType.METHOD)
+ @Retention(RetentionPolicy.RUNTIME)
+ public static @interface SoftReferenceSensitive {
+ // Empty annotation
+ }
+}
diff --git a/tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/classification/tests/AbstractPapyrusTest.java b/tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/classification/tests/AbstractPapyrusTest.java
new file mode 100644
index 00000000000..f77b5076241
--- /dev/null
+++ b/tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/classification/tests/AbstractPapyrusTest.java
@@ -0,0 +1,28 @@
+/*****************************************************************************
+ * Copyright (c) 2014 CEA LIST.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Initial API and implementation
+ *****************************************************************************/
+package org.eclipse.papyrus.junit.framework.classification.tests;
+
+import org.eclipse.papyrus.junit.framework.classification.ClassificationRunner;
+import org.junit.runner.RunWith;
+
+/**
+ * An abstract class which should be extended by all Papyrus tests
+ *
+ * It provides generic support for papyrus-specific annotations (e.g. ClassificationRunner)
+ *
+ * @author Camille Letavernier
+ *
+ */
+@RunWith(ClassificationRunner.class)
+public abstract class AbstractPapyrusTest {
+ //Abstract test class for using the Classification Runner
+}
diff --git a/tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/runner/AllTestsRunner.java b/tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/runner/AllTestsRunner.java
new file mode 100644
index 00000000000..f7b32e833a5
--- /dev/null
+++ b/tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/runner/AllTestsRunner.java
@@ -0,0 +1,96 @@
+/*****************************************************************************
+ * Copyright (c) 2010, 2015 CEA LIST, Christian W. Damus, and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Remi Schnekenburger (CEA LIST) remi.schnekenburger@cea.fr - Initial API and implementation
+ * Christian W. Damus (CEA) - bugs 402525, 323802, 431953, 433310, 434993
+ * Christian W. Damus - bug 399859
+ * Christian W. Damus - bug 451230
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.junit.framework.runner;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+import org.junit.runners.Suite;
+import org.junit.runners.model.FrameworkField;
+import org.junit.runners.model.InitializationError;
+import org.junit.runners.model.TestClass;
+
+/**
+ * Finds and runs tests.
+ */
+public class AllTestsRunner extends Suite {
+
+ /**
+ * Constructor.
+ *
+ * @param clazz
+ * the suite class � AllTests2
+ * @throws InitializationError
+ * if there's a problem
+ * @throws org.junit.runners.model.InitializationError
+ */
+ public AllTestsRunner(final Class<?> clazz) throws InitializationError {
+ super(clazz, getSuites(clazz));
+ }
+
+ /**
+ * Returns the list of test classes
+ *
+ * @return the list of test classes
+ */
+ static Class<?>[] getSuites(final Class<?> clazz) {
+ // retrieve all test suites.
+ final Collection<Class<?>> suites = new ArrayList<Class<?>>();
+
+ TestClass testClass = new TestClass(clazz);
+ List<ITestSuiteClass> suiteClassSpecs = new ArrayList<ITestSuiteClass>();
+ List<FrameworkField> suiteSpots = testClass.getAnnotatedFields(SuiteSpot.class);
+ for (FrameworkField spot : suiteSpots) {
+ if (spot.isStatic()) {
+ try {
+ Object value = spot.get(null);
+ Iterable<?> listValue;
+ if (value instanceof Object[]) {
+ listValue = Arrays.asList((Object[]) value);
+ } else if (value instanceof Iterable<?>) {
+ listValue = (Iterable<?>) value;
+ } else {
+ listValue = Collections.emptyList();
+ }
+ for (Object next : listValue) {
+ if (next instanceof ITestSuiteClass) {
+ suiteClassSpecs.add((ITestSuiteClass) next);
+ }
+ }
+ } catch (IllegalAccessException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ if (suiteClassSpecs.isEmpty()) {
+ System.err.println("No suite classes specified in class " + clazz.getName());
+ } else {
+ for (final ITestSuiteClass testSuiteClass : suiteClassSpecs) {
+ final Class<?> class_ = testSuiteClass.getMainTestSuiteClass();
+ if (class_ != null) {
+ suites.add(class_);
+ } else {
+ System.err.println(testSuiteClass + " does not give a correct test suite class");
+ }
+ }
+ }
+ return suites.toArray(new Class<?>[] {});
+ }
+}
diff --git a/tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/runner/FragmentTestSuiteClass.java b/tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/runner/FragmentTestSuiteClass.java
new file mode 100644
index 00000000000..8f1e3ed6e93
--- /dev/null
+++ b/tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/runner/FragmentTestSuiteClass.java
@@ -0,0 +1,71 @@
+/*****************************************************************************
+ * Copyright (c) 2010, 2016 CEA LIST, Christian W. Damus, and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Remi Schnekenburger (CEA LIST) remi.schnekenburger@cea.fr - Initial API and implementation
+ * Christian W. Damus - bugs 451230, 488791
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.junit.framework.runner;
+
+import org.eclipse.core.runtime.Platform;
+import org.osgi.framework.Bundle;
+
+
+/**
+ * Test Suite class entry for a test fragment.
+ *
+ * @deprecated As of 2.0, All test suites should be plug-in bundles, not fragment bundles.
+ */
+@Deprecated
+public class FragmentTestSuiteClass implements ITestSuiteClass {
+
+ /** unique identifier of the bundle host */
+ private final String hostBundleId;
+
+ /** qualified name of the test suite class */
+ private final String classQualifiedName;
+
+ /**
+ * Constructor.
+ *
+ * @param hostBundleId
+ * unique identifier of the bundle host
+ * @param classQualifiedName
+ * qualified name of the test suite class
+ */
+ public FragmentTestSuiteClass(String hostBundleId, String classQualifiedName) {
+ this.hostBundleId = hostBundleId;
+ this.classQualifiedName = classQualifiedName;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Class<?> getMainTestSuiteClass() {
+ Bundle bundle = Platform.getBundle(hostBundleId);
+ if (bundle == null) {
+ System.err.println("Impossible to find bundle: " + hostBundleId);
+ } else {
+ try {
+ Class<?> class_ = bundle.loadClass(classQualifiedName);
+ return class_;
+ } catch (ClassNotFoundException e) {
+ e.printStackTrace();
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("FragmentTestSuite %s/%s", hostBundleId, classQualifiedName);
+ }
+
+}
diff --git a/tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/runner/Headless.java b/tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/runner/Headless.java
new file mode 100644
index 00000000000..d3411958e2b
--- /dev/null
+++ b/tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/runner/Headless.java
@@ -0,0 +1,31 @@
+/*****************************************************************************
+ * Copyright (c) 2016 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.junit.framework.runner;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Marker annotation for test suites that can (and should be) run in "headless mode"
+ * (without the Eclipse Workbench).
+ *
+ * @since 1.2
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ ElementType.TYPE, ElementType.PACKAGE })
+public @interface Headless {
+ // Empty
+}
diff --git a/tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/runner/ITestSuiteClass.java b/tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/runner/ITestSuiteClass.java
new file mode 100644
index 00000000000..17043f3bbd5
--- /dev/null
+++ b/tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/runner/ITestSuiteClass.java
@@ -0,0 +1,50 @@
+/*****************************************************************************
+ * Copyright (c) 2010, 2016 CEA LIST, Christian W. Damus, and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Remi Schnekenburger (CEA LIST) remi.schnekenburger@cea.fr - Initial API and implementation
+ * Christian W. Damus - bugs 451230, 485220
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.junit.framework.runner;
+
+
+/**
+ * Interface for all suite classes.
+ */
+public interface ITestSuiteClass {
+
+ /**
+ * Returns the main test suite class for this entry
+ *
+ * @return the main test suite class for this entry
+ */
+ public Class<?> getMainTestSuiteClass();
+
+ /**
+ * Queries whether the test suite runs in "headless mode" (without the Eclipse Workbench).
+ *
+ * @return whether I am an headless test suite
+ * @since 1.2
+ */
+ default boolean isHeadless() {
+ Class<?> main = getMainTestSuiteClass();
+ return (main != null) && main.isAnnotationPresent(Headless.class);
+ }
+
+ /**
+ * Queries whether the test suite runs in "UI mode" (in an Eclipse Workbench).
+ *
+ * @return whether I am an UI test suite
+ * @since 1.2
+ */
+ default boolean isUI() {
+ Class<?> main = getMainTestSuiteClass();
+ return (main != null) && !main.isAnnotationPresent(Headless.class);
+ }
+}
diff --git a/tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/runner/IgnoreRunner.java b/tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/runner/IgnoreRunner.java
new file mode 100644
index 00000000000..26a6bdf9f80
--- /dev/null
+++ b/tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/runner/IgnoreRunner.java
@@ -0,0 +1,64 @@
+/*****************************************************************************
+ * Copyright (c) 2015 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.junit.framework.runner;
+
+import java.util.Iterator;
+
+import org.eclipse.emf.common.util.AbstractTreeIterator;
+import org.eclipse.emf.common.util.TreeIterator;
+import org.junit.runner.Description;
+import org.junit.runner.Runner;
+import org.junit.runner.notification.RunNotifier;
+
+/**
+ * A JUnit runner that just ignores all of the leaves of its {@link #getDescription() description} tree.
+ */
+public class IgnoreRunner extends Runner {
+ private final Description description;
+
+ /**
+ * Initializes me with the test suite that I ignore.
+ */
+ public IgnoreRunner(Description testSuite) {
+ super();
+
+ this.description = testSuite;
+ }
+
+ @Override
+ public Description getDescription() {
+ return description;
+ }
+
+ @Override
+ public void run(RunNotifier notifier) {
+ for (Iterator<Description> iter = iterator(); iter.hasNext();) {
+ Description next = iter.next();
+ if (next.isTest()) {
+ notifier.fireTestIgnored(next);
+ }
+ }
+ }
+
+ TreeIterator<Description> iterator() {
+ return new AbstractTreeIterator<Description>(getDescription()) {
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ protected Iterator<? extends Description> getChildren(Object object) {
+ return ((Description) object).getChildren().iterator();
+ }
+ };
+ }
+}
diff --git a/tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/runner/PluginTestSuiteClass.java b/tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/runner/PluginTestSuiteClass.java
new file mode 100644
index 00000000000..c7f16a20f7d
--- /dev/null
+++ b/tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/runner/PluginTestSuiteClass.java
@@ -0,0 +1,46 @@
+/*****************************************************************************
+ * Copyright (c) 2010, 2015 CEA LIST, Christian W. Damus, and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Remi Schnekenburger (CEA LIST) remi.schnekenburger@cea.fr - Initial API and implementation
+ * Christian W. Damus - bug 451230
+ *****************************************************************************/
+package org.eclipse.papyrus.junit.framework.runner;
+
+
+/**
+ * Entry for a test suite in a test plugin
+ */
+public class PluginTestSuiteClass implements ITestSuiteClass {
+
+ /** main test suite class */
+ private final Class<?> testClass;
+
+ /**
+ * Constructor.
+ *
+ * @param testClass
+ * the main test suite class
+ */
+ public PluginTestSuiteClass(Class<?> testClass) {
+ this.testClass = testClass;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Class<?> getMainTestSuiteClass() {
+ return testClass;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("PluginTestSuite %s", testClass);
+ }
+
+}
diff --git a/tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/runner/Scenario.java b/tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/runner/Scenario.java
new file mode 100644
index 00000000000..6a21299ad24
--- /dev/null
+++ b/tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/runner/Scenario.java
@@ -0,0 +1,34 @@
+/*****************************************************************************
+ * Copyright (c) 2015 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.junit.framework.runner;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation on a public instance method that defines a test scenario having multiple distinct
+ * and potentially independent verification points.
+ *
+ * @see ScenarioRunner
+ */
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Scenario {
+ /**
+ * Specifies the labels of the verification points in the scenario, in order.
+ */
+ String[] value();
+}
diff --git a/tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/runner/ScenarioRunner.java b/tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/runner/ScenarioRunner.java
new file mode 100644
index 00000000000..5f3142832bf
--- /dev/null
+++ b/tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/runner/ScenarioRunner.java
@@ -0,0 +1,419 @@
+/*****************************************************************************
+ * Copyright (c) 2015, 2016 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.junit.framework.runner;
+
+import java.lang.annotation.Annotation;
+import java.util.ArrayDeque;
+import java.util.Arrays;
+import java.util.Deque;
+import java.util.List;
+
+import org.eclipse.papyrus.junit.framework.classification.ClassificationConfig;
+import org.junit.Ignore;
+import org.junit.Test;
+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.runner.notification.StoppedByUserException;
+import org.junit.runners.BlockJUnit4ClassRunner;
+import org.junit.runners.ParentRunner;
+import org.junit.runners.model.FrameworkMethod;
+import org.junit.runners.model.InitializationError;
+import org.junit.runners.model.RunnerBuilder;
+import org.junit.runners.model.Statement;
+
+import com.google.common.base.Function;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Iterators;
+import com.google.common.collect.Lists;
+
+/**
+ * <p>
+ * A scenario-based test runner. A method annotated with {@link Scenario @Scenario} lays out a scenario and at various places where something is to be verified, calls this class's static {@link #verificationPoint()} method as an {@code if} condition to guard a
+ * block of assertion statements. The {@link Scenario @Scenario} annotation provides the labels of the verification points, in the order in which they appear. Each verification point is surfaced as a separate test, which may pass or fail independently of the
+ * others.
+ * </p>
+ * <p>
+ * Classic {@link Test @Test} methods are supported by this runner, also. They are run in the usual way, not as scenarios with multiple verification points.
+ * </p>
+ *
+ * @see Scenario
+ * @see #verificationPoint()
+ */
+public class ScenarioRunner extends ParentRunner<Runner> {
+
+ private static final Deque<VerificationPointsRunner> runnerStack = new ArrayDeque<VerificationPointsRunner>();
+
+ public ScenarioRunner(Class<?> testClass) throws InitializationError {
+ super(testClass);
+ }
+
+ @Override
+ protected List<Runner> getChildren() {
+ Iterable<FrameworkMethod> methods = Iterables.concat(
+ getTestClass().getAnnotatedMethods(Test.class),
+ getTestClass().getAnnotatedMethods(Scenario.class));
+ return ImmutableList.copyOf(Iterables.transform(methods, new Function<FrameworkMethod, Runner>() {
+ @Override
+ public Runner apply(FrameworkMethod input) {
+ return new VerificationPointsRunnerBuilder(input).build();
+ }
+ }));
+ }
+
+ @Override
+ protected Description describeChild(Runner child) {
+ return child.getDescription();
+ }
+
+ @Override
+ protected void runChild(Runner child, RunNotifier notifier) {
+ if (!(child instanceof VerificationPointsRunner)) {
+ // Probably the error-reporting runner
+ child.run(notifier);
+ } else {
+ VerificationPointsRunner points = (VerificationPointsRunner) child;
+
+ pushRunner(points);
+ points.start();
+
+ try {
+ points.run(notifier);
+ } finally {
+ points.finish();
+ popRunner();
+ }
+ }
+ }
+
+ /**
+ * Declares the next verification point in the scenario. Use as the condition of an {@code if} block
+ * enclosing the verification point's assertion statements. There must be one verification-point
+ * block per verification-point label declared in the {@link Scenario @Scenario} annotation. e.g.,
+ *
+ * <pre>
+ * import static org.eclipse.papyrus.junit.framework.runners.ScenarioRunner.verificationPoint;
+ *
+ * // ...
+ *
+ * &#64;Scenario({ "first", "second" })
+ * public void myLongAndIntricateScenario() {
+ * // Setup stuff ...
+ *
+ * if (verificationPoint()) {
+ * // Assertions here
+ * }
+ *
+ * // More stuff ...
+ *
+ * if (verificationPoint()) {
+ * // More assertions here
+ * }
+ * }
+ * </pre>
+ */
+ public static boolean verificationPoint() {
+ return currentRunner().verificationPoint();
+ }
+
+ private static VerificationPointsRunner currentRunner() {
+ return runnerStack.getLast();
+ }
+
+ private static VerificationPointsRunner popRunner() {
+ return runnerStack.removeLast();
+ }
+
+ private static void pushRunner(VerificationPointsRunner runner) {
+ runnerStack.addLast(runner);
+ }
+
+ /**
+ * Queries whether a test's annotations indicate that it is to be ignored in the
+ * current run. That may is if any of the annotations is the {@code @Ignore} annotation
+ * or if none of the {@link ClassificationConfig} annotations match the current run.
+ *
+ * @param testAnnotations
+ * a test's annotations (including those inherited from its class)
+ *
+ * @return whether the test should be skipped
+ */
+ static boolean isIgnored(Annotation[] testAnnotations) {
+ boolean result = !ClassificationConfig.shouldRun(testAnnotations);
+
+ if (!result) {
+ // Look for the @Ignore annotation
+ result = Iterators.filter(Arrays.asList(testAnnotations).iterator(), Ignore.class).hasNext();
+ }
+
+ return result;
+ }
+
+ //
+ // Nested types
+ //
+
+ private class VerificationPointsRunnerBuilder extends RunnerBuilder {
+ private final FrameworkMethod scenarioMethod;
+
+ VerificationPointsRunnerBuilder(FrameworkMethod scenarioMethod) {
+ super();
+
+ this.scenarioMethod = scenarioMethod;
+
+ }
+
+ @Override
+ public Runner runnerForClass(Class<?> testClass) throws Throwable {
+ Runner result;
+
+ if (scenarioMethod.getAnnotation(Scenario.class) != null) {
+ result = new VerificationPointsRunner(scenarioMethod);
+ } else {
+ // It's just an @Test method
+ result = new JUnitAccess(testClass).classicTest(scenarioMethod);
+ }
+
+ List<Annotation> allAnnotations = Lists.newArrayList(scenarioMethod.getAnnotations());
+ allAnnotations.addAll(Arrays.asList(scenarioMethod.getMethod().getDeclaringClass().getAnnotations()));
+ if (isIgnored(Iterables.toArray(allAnnotations, Annotation.class))) {
+ result = new IgnoreRunner(result.getDescription());
+ }
+
+ return result;
+ }
+
+ public Runner build() {
+ return safeRunnerForClass(scenarioMethod.getMethod().getDeclaringClass());
+ }
+ }
+
+ private class VerificationPointsRunner extends ParentRunner<String> {
+ private final FrameworkMethod scenarioMethod;
+ private final Scenario scenario;
+ private final JUnitAccess junit;
+
+ private List<String> verpts = Lists.newArrayList();
+ private int nextVerificationPoint;
+ private Failure lastFailure;
+
+ VerificationPointsRunner(FrameworkMethod scenarioMethod) throws InitializationError {
+ super(scenarioMethod.getMethod().getDeclaringClass());
+
+ this.scenarioMethod = scenarioMethod;
+ this.scenario = scenarioMethod.getAnnotation(Scenario.class);
+ this.junit = new JUnitAccess(scenarioMethod.getMethod().getDeclaringClass());
+ }
+
+ @Override
+ public Description getDescription() {
+ Description result = Description.createSuiteDescription(scenarioMethod.getName(), scenarioMethod.getAnnotations());
+ for (Description child : super.getDescription().getChildren()) {
+ result.addChild(child);
+ }
+ return result;
+ }
+
+ @Override
+ protected List<String> getChildren() {
+ return Arrays.asList(scenario.value());
+ }
+
+ @Override
+ protected Description describeChild(String child) {
+ return Description.createTestDescription(getTestClass().getJavaClass(), scenarioMethod.getName() + ":" + child);
+ }
+
+ @Override
+ protected void runChild(String child, RunNotifier notifier) {
+ Description description = describeChild(child);
+
+ if (verpts.contains(child)) {
+ if (verpts.get(0).equals(child)) {
+ // This is the first verification point. It needs to run the scenario method.
+ // If all verification points pass, this will be the only execution of that
+ // method. Otherwise, if some verification point fails, the next one (if
+ // any) will run the scenario again, skipping all verifications before it.
+ if (!runScenario(child, description, notifier)) {
+ // This run failed, so run again from the beginning of the scenario
+ nextVerificationPoint = 0;
+ }
+ } else {
+ // This test failed in a previous execution
+ Throwable last = (lastFailure == null)
+ ? new AssertionError("Previous execution failed")
+ : lastFailure.getException();
+ notifier.fireTestStarted(description);
+ notifier.fireTestFailure(new Failure(description, last));
+ lastFailure = null;
+ notifier.fireTestFinished(description);
+ }
+ } else if (failedLastTime(child)) {
+ // This test failed in a previous execution
+ notifier.fireTestStarted(description);
+ notifier.fireTestFailure(new Failure(description, lastFailure.getException()));
+ lastFailure = null;
+ notifier.fireTestFinished(description);
+ } else {
+ // This verification point passed in a previous execution of the scenario
+ notifier.fireTestStarted(description);
+ notifier.fireTestFinished(description);
+ }
+ }
+
+ void start() {
+ verpts.addAll(getChildren());
+ nextVerificationPoint = 0;
+ }
+
+ boolean verificationPoint() {
+ final String[] points = scenario.value();
+
+ boolean result = ((nextVerificationPoint < points.length)
+ && verpts.contains(points[nextVerificationPoint]));
+
+ nextVerificationPoint++;
+
+ int limit = Math.min(nextVerificationPoint, points.length);
+
+ // We have passed all verifications up to this point
+ for (int i = 0; i < limit; i++) {
+ verpts.remove(points[i]);
+ }
+
+ return result;
+ }
+
+ String currentVerificationPoint() {
+ final String[] points = scenario.value();
+ int index = Math.max(0, Math.min(nextVerificationPoint - 1, points.length - 1));
+
+ return points[index];
+ }
+
+ boolean failedLastTime(String child) {
+ boolean result = lastFailure != null;
+
+ if (result) {
+ final String[] points = scenario.value();
+ // If there are no verification points remaining, then is this the last one
+ // and it failed in the previous run?
+ if (verpts.isEmpty()) {
+ result = points[points.length - 1].equals(child);
+ } else {
+ int successor = Math.max(Arrays.asList(points).indexOf(child) + 1, points.length - 1);
+ result = verpts.contains(points[successor]);
+ }
+ }
+
+ return result;
+ }
+
+ void finish() {
+ verpts.clear();
+ nextVerificationPoint = scenario.value().length;
+ lastFailure = null;
+ }
+
+ private boolean runScenario(final String child, Description description, final RunNotifier notifier) {
+ final boolean[] result = { true };
+
+ RunNotifier notifierWrapper = new RunNotifier() {
+ @Override
+ public void fireTestFailure(Failure failure) {
+ result[0] = false;
+
+ if (child.equals(currentVerificationPoint())) {
+ // This verification point failed
+ notifier.fireTestFailure(failure);
+ } else {
+ // A subsequent verification point failed. This one passed
+ lastFailure = failure;
+ }
+ }
+
+ @Override
+ public void fireTestAssumptionFailed(Failure failure) {
+ result[0] = false;
+
+ if (child.equals(currentVerificationPoint())) {
+ // This verification point failed
+ notifier.fireTestAssumptionFailed(failure);
+ } else {
+ // A subsequent verification point failed. This one passed
+ lastFailure = failure;
+ }
+ }
+
+ @Override
+ public void fireTestIgnored(Description description) {
+ notifier.fireTestIgnored(description);
+ }
+
+ @Override
+ public void fireTestStarted(Description description) throws StoppedByUserException {
+ notifier.fireTestStarted(description);
+ }
+
+ @Override
+ public void fireTestFinished(Description description) {
+ notifier.fireTestFinished(description);
+ }
+ };
+
+ runLeaf(junit.methodBlock(scenarioMethod), description, notifierWrapper);
+
+ return result[0];
+ }
+ }
+
+ static class JUnitAccess extends BlockJUnit4ClassRunner {
+ public JUnitAccess(Class<?> testClass) throws InitializationError {
+ super(testClass);
+ }
+
+ @Override
+ protected Statement methodBlock(FrameworkMethod method) {
+ return super.methodBlock(method);
+ }
+
+ // Our test methods are annotated with @Scenario or @Test
+ @Override
+ protected List<FrameworkMethod> computeTestMethods() {
+ List<FrameworkMethod> result = Lists.newArrayList(getTestClass().getAnnotatedMethods(Scenario.class));
+ result.addAll(getTestClass().getAnnotatedMethods(Test.class));
+ return result;
+ }
+
+ Runner classicTest(final FrameworkMethod testMethod) {
+ return new Runner() {
+
+ @Override
+ public void run(RunNotifier notifier) {
+ runLeaf(methodBlock(testMethod), getDescription(), notifier);
+ }
+
+ @Override
+ public Description getDescription() {
+ return Description.createTestDescription(
+ getTestClass().getJavaClass(),
+ testMethod.getName(),
+ testMethod.getAnnotations());
+ }
+ };
+ }
+ }
+}
diff --git a/tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/runner/SuiteSpot.java b/tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/runner/SuiteSpot.java
new file mode 100644
index 00000000000..a745af89a16
--- /dev/null
+++ b/tests/junit/framework/org.eclipse.papyrus.junit.framework/src/org/eclipse/papyrus/junit/framework/runner/SuiteSpot.java
@@ -0,0 +1,29 @@
+/*****************************************************************************
+ * Copyright (c) 2015 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.junit.framework.runner;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation on a static field of an all-tests suite class using the {@link AllTestsRunner} that
+ * provides a collection or array of {@link ITestSuiteClass}es to run.
+ */
+@Target(ElementType.FIELD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface SuiteSpot {
+ // Empty annotation
+}
diff --git a/tests/junit/framework/org.eclipse.papyrus.junit.utils/.classpath b/tests/junit/framework/org.eclipse.papyrus.junit.utils/.classpath
new file mode 100644
index 00000000000..eca7bdba8f0
--- /dev/null
+++ b/tests/junit/framework/org.eclipse.papyrus.junit.utils/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/tests/junit/framework/org.eclipse.papyrus.junit.utils/.project b/tests/junit/framework/org.eclipse.papyrus.junit.utils/.project
new file mode 100644
index 00000000000..9dc44b8018e
--- /dev/null
+++ b/tests/junit/framework/org.eclipse.papyrus.junit.utils/.project
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.eclipse.papyrus.junit.utils</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.oomph.version.VersionBuilder</name>
+ <arguments>
+ <dictionary>
+ <key>check.maven.pom</key>
+ <value>true</value>
+ </dictionary>
+ <dictionary>
+ <key>ignore.lower.bound.dependency.ranges</key>
+ <value>true</value>
+ </dictionary>
+ <dictionary>
+ <key>release.path</key>
+ <value>/org.eclipse.papyrus.releng.dev.release/release.xml</value>
+ </dictionary>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.api.tools.apiAnalysisBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ <nature>org.eclipse.oomph.version.VersionNature</nature>
+ <nature>org.eclipse.pde.api.tools.apiAnalysisNature</nature>
+ </natures>
+</projectDescription>
diff --git a/tests/junit/framework/org.eclipse.papyrus.junit.utils/.settings/org.eclipse.core.resources.prefs b/tests/junit/framework/org.eclipse.papyrus.junit.utils/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 00000000000..896a9a53a53
--- /dev/null
+++ b/tests/junit/framework/org.eclipse.papyrus.junit.utils/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+encoding/<project>=UTF-8 \ No newline at end of file
diff --git a/tests/junit/framework/org.eclipse.papyrus.junit.utils/.settings/org.eclipse.core.runtime.prefs b/tests/junit/framework/org.eclipse.papyrus.junit.utils/.settings/org.eclipse.core.runtime.prefs
new file mode 100644
index 00000000000..5a0ad22d2a7
--- /dev/null
+++ b/tests/junit/framework/org.eclipse.papyrus.junit.utils/.settings/org.eclipse.core.runtime.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+line.separator=\n
diff --git a/tests/junit/framework/org.eclipse.papyrus.junit.utils/.settings/org.eclipse.jdt.core.prefs b/tests/junit/framework/org.eclipse.papyrus.junit.utils/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 00000000000..b3aa6d60f94
--- /dev/null
+++ b/tests/junit/framework/org.eclipse.papyrus.junit.utils/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,291 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
+org.eclipse.jdt.core.compiler.compliance=1.8
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.8
+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_annotation=0
+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_method_declaration=0
+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_resources_in_try=80
+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.alignment_for_union_type_in_multicatch=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=0
+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_lambda_body=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_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_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=260
+org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=true
+org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true
+org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=false
+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.disabling_tag=@formatter\:off
+org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on
+org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false
+org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=true
+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_on_field=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_method=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=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_annotation_on_type=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_label=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_after_type_annotation=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_lambda_arrow=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_try=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_semicolon_in_try_resources=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_try=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_lambda_arrow=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_try=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_semicolon_in_try_resources=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.join_lines_in_comments=false
+org.eclipse.jdt.core.formatter.join_wrapped_lines=false
+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=260
+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=5
+org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true
+org.eclipse.jdt.core.formatter.tabulation.char=tab
+org.eclipse.jdt.core.formatter.tabulation.size=4
+org.eclipse.jdt.core.formatter.use_on_off_tags=false
+org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false
+org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true
+org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true
diff --git a/tests/junit/framework/org.eclipse.papyrus.junit.utils/.settings/org.eclipse.jdt.ui.prefs b/tests/junit/framework/org.eclipse.papyrus.junit.utils/.settings/org.eclipse.jdt.ui.prefs
new file mode 100644
index 00000000000..954281dbc31
--- /dev/null
+++ b/tests/junit/framework/org.eclipse.papyrus.junit.utils/.settings/org.eclipse.jdt.ui.prefs
@@ -0,0 +1,68 @@
+cleanup.add_default_serial_version_id=true
+cleanup.add_generated_serial_version_id=false
+cleanup.add_missing_annotations=true
+cleanup.add_missing_deprecated_annotations=true
+cleanup.add_missing_methods=false
+cleanup.add_missing_nls_tags=false
+cleanup.add_missing_override_annotations=true
+cleanup.add_missing_override_annotations_interface_methods=true
+cleanup.add_serial_version_id=false
+cleanup.always_use_blocks=true
+cleanup.always_use_parentheses_in_expressions=false
+cleanup.always_use_this_for_non_static_field_access=false
+cleanup.always_use_this_for_non_static_method_access=false
+cleanup.convert_functional_interfaces=false
+cleanup.convert_to_enhanced_for_loop=false
+cleanup.correct_indentation=false
+cleanup.format_source_code=false
+cleanup.format_source_code_changes_only=false
+cleanup.insert_inferred_type_arguments=false
+cleanup.make_local_variable_final=true
+cleanup.make_parameters_final=false
+cleanup.make_private_fields_final=true
+cleanup.make_type_abstract_if_missing_method=false
+cleanup.make_variable_declarations_final=false
+cleanup.never_use_blocks=false
+cleanup.never_use_parentheses_in_expressions=true
+cleanup.organize_imports=false
+cleanup.qualify_static_field_accesses_with_declaring_class=false
+cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true
+cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=true
+cleanup.qualify_static_member_accesses_with_declaring_class=true
+cleanup.qualify_static_method_accesses_with_declaring_class=false
+cleanup.remove_private_constructors=true
+cleanup.remove_redundant_type_arguments=true
+cleanup.remove_trailing_whitespaces=true
+cleanup.remove_trailing_whitespaces_all=true
+cleanup.remove_trailing_whitespaces_ignore_empty=false
+cleanup.remove_unnecessary_casts=true
+cleanup.remove_unnecessary_nls_tags=true
+cleanup.remove_unused_imports=true
+cleanup.remove_unused_local_variables=false
+cleanup.remove_unused_private_fields=true
+cleanup.remove_unused_private_members=false
+cleanup.remove_unused_private_methods=true
+cleanup.remove_unused_private_types=true
+cleanup.sort_members=false
+cleanup.sort_members_all=false
+cleanup.use_anonymous_class_creation=false
+cleanup.use_blocks=true
+cleanup.use_blocks_only_for_return_and_throw=false
+cleanup.use_lambda=true
+cleanup.use_parentheses_in_expressions=false
+cleanup.use_this_for_non_static_field_access=false
+cleanup.use_this_for_non_static_field_access_only_if_necessary=true
+cleanup.use_this_for_non_static_method_access=false
+cleanup.use_this_for_non_static_method_access_only_if_necessary=true
+cleanup.use_type_arguments=false
+cleanup_profile=_Papyrus
+cleanup_settings_version=2
+eclipse.preferences.version=1
+formatter_profile=_Papyrus
+formatter_settings_version=12
+org.eclipse.jdt.ui.ignorelowercasenames=true
+org.eclipse.jdt.ui.importorder=java;javax;org;com;
+org.eclipse.jdt.ui.javadoc=true
+org.eclipse.jdt.ui.ondemandthreshold=99
+org.eclipse.jdt.ui.staticondemandthreshold=99
+org.eclipse.jdt.ui.text.custom_code_templates=<?xml version\="1.0" encoding\="UTF-8" standalone\="no"?><templates><template autoinsert\="true" context\="gettercomment_context" deleted\="false" description\="Comment for getter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.gettercomment" name\="gettercomment">/**\n * @return the ${bare_field_name}\n */</template><template autoinsert\="true" context\="settercomment_context" deleted\="false" description\="Comment for setter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.settercomment" name\="settercomment">/**\n * @param ${param} the ${bare_field_name} to set\n */</template><template autoinsert\="false" context\="constructorcomment_context" deleted\="false" description\="Comment for created constructors" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorcomment" name\="constructorcomment">/**\n * Constructor.\n *\n * ${tags}\n */</template><template autoinsert\="false" context\="filecomment_context" deleted\="false" description\="Comment for created Java files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.filecomment" name\="filecomment">/*****************************************************************************\n * Copyright (c) ${year} CEA LIST and others.\n * \n * All rights reserved. This program and the accompanying materials\n * are made available under the terms of the Eclipse Public License v1.0\n * which accompanies this distribution, and is available at\n * http\://www.eclipse.org/legal/epl-v10.html\n *\n * Contributors\:\n * CEA LIST - Initial API and implementation\n * \n *****************************************************************************/\n</template><template autoinsert\="true" context\="typecomment_context" deleted\="false" description\="Comment for created types" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.typecomment" name\="typecomment">/**\n * @author ${user}\n *\n * ${tags}\n */</template><template autoinsert\="true" context\="fieldcomment_context" deleted\="false" description\="Comment for fields" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.fieldcomment" name\="fieldcomment">/**\n * \n */</template><template autoinsert\="true" context\="methodcomment_context" deleted\="false" description\="Comment for non-overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodcomment" name\="methodcomment">/**\n * ${tags}\n */</template><template autoinsert\="false" context\="overridecomment_context" deleted\="false" description\="Comment for overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.overridecomment" name\="overridecomment">/**\n * ${see_to_overridden}\n *\n * ${tags}\n */</template><template autoinsert\="false" context\="delegatecomment_context" deleted\="false" description\="Comment for delegate methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.delegatecomment" name\="delegatecomment">/**\n * ${see_to_target}\n *\n * ${tags}\n */</template><template autoinsert\="true" context\="newtype_context" deleted\="false" description\="Newly created files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.newtype" name\="newtype">${filecomment}\n${package_declaration}\n\n${typecomment}\n${type_declaration}</template><template autoinsert\="true" context\="classbody_context" deleted\="false" description\="Code in new class type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.classbody" name\="classbody">\n</template><template autoinsert\="true" context\="interfacebody_context" deleted\="false" description\="Code in new interface type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.interfacebody" name\="interfacebody">\n</template><template autoinsert\="true" context\="enumbody_context" deleted\="false" description\="Code in new enum type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.enumbody" name\="enumbody">\n</template><template autoinsert\="true" context\="annotationbody_context" deleted\="false" description\="Code in new annotation type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.annotationbody" name\="annotationbody">\n</template><template autoinsert\="true" context\="catchblock_context" deleted\="false" description\="Code in new catch blocks" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.catchblock" name\="catchblock">// ${todo} Auto-generated catch block\n${exception_var}.printStackTrace();</template><template autoinsert\="true" context\="methodbody_context" deleted\="false" description\="Code in created method stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodbody" name\="methodbody">// ${todo} Auto-generated method stub\n${body_statement}</template><template autoinsert\="true" context\="constructorbody_context" deleted\="false" description\="Code in created constructor stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorbody" name\="constructorbody">${body_statement}\n// ${todo} Auto-generated constructor stub</template><template autoinsert\="true" context\="getterbody_context" deleted\="false" description\="Code in created getters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.getterbody" name\="getterbody">return ${field};</template><template autoinsert\="true" context\="setterbody_context" deleted\="false" description\="Code in created setters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.setterbody" name\="setterbody">${field} \= ${param};</template></templates>
diff --git a/tests/junit/framework/org.eclipse.papyrus.junit.utils/.settings/org.eclipse.pde.api.tools.prefs b/tests/junit/framework/org.eclipse.papyrus.junit.utils/.settings/org.eclipse.pde.api.tools.prefs
new file mode 100644
index 00000000000..23fb95e120f
--- /dev/null
+++ b/tests/junit/framework/org.eclipse.papyrus.junit.utils/.settings/org.eclipse.pde.api.tools.prefs
@@ -0,0 +1,98 @@
+ANNOTATION_ELEMENT_TYPE_ADDED_METHOD_WITHOUT_DEFAULT_VALUE=Error
+ANNOTATION_ELEMENT_TYPE_CHANGED_TYPE_CONVERSION=Error
+ANNOTATION_ELEMENT_TYPE_REMOVED_FIELD=Error
+ANNOTATION_ELEMENT_TYPE_REMOVED_METHOD=Error
+ANNOTATION_ELEMENT_TYPE_REMOVED_TYPE_MEMBER=Error
+API_COMPONENT_ELEMENT_TYPE_REMOVED_API_TYPE=Error
+API_COMPONENT_ELEMENT_TYPE_REMOVED_REEXPORTED_API_TYPE=Error
+API_COMPONENT_ELEMENT_TYPE_REMOVED_REEXPORTED_TYPE=Error
+API_COMPONENT_ELEMENT_TYPE_REMOVED_TYPE=Error
+API_USE_SCAN_FIELD_SEVERITY=Error
+API_USE_SCAN_METHOD_SEVERITY=Error
+API_USE_SCAN_TYPE_SEVERITY=Error
+CLASS_ELEMENT_TYPE_ADDED_METHOD=Error
+CLASS_ELEMENT_TYPE_ADDED_RESTRICTIONS=Error
+CLASS_ELEMENT_TYPE_ADDED_TYPE_PARAMETER=Error
+CLASS_ELEMENT_TYPE_CHANGED_CONTRACTED_SUPERINTERFACES_SET=Error
+CLASS_ELEMENT_TYPE_CHANGED_DECREASE_ACCESS=Error
+CLASS_ELEMENT_TYPE_CHANGED_NON_ABSTRACT_TO_ABSTRACT=Error
+CLASS_ELEMENT_TYPE_CHANGED_NON_FINAL_TO_FINAL=Error
+CLASS_ELEMENT_TYPE_CHANGED_TYPE_CONVERSION=Error
+CLASS_ELEMENT_TYPE_REMOVED_CONSTRUCTOR=Error
+CLASS_ELEMENT_TYPE_REMOVED_FIELD=Error
+CLASS_ELEMENT_TYPE_REMOVED_METHOD=Error
+CLASS_ELEMENT_TYPE_REMOVED_SUPERCLASS=Error
+CLASS_ELEMENT_TYPE_REMOVED_TYPE_MEMBER=Error
+CLASS_ELEMENT_TYPE_REMOVED_TYPE_PARAMETER=Error
+CONSTRUCTOR_ELEMENT_TYPE_ADDED_TYPE_PARAMETER=Error
+CONSTRUCTOR_ELEMENT_TYPE_CHANGED_DECREASE_ACCESS=Error
+CONSTRUCTOR_ELEMENT_TYPE_CHANGED_VARARGS_TO_ARRAY=Error
+CONSTRUCTOR_ELEMENT_TYPE_REMOVED_TYPE_PARAMETER=Error
+ENUM_ELEMENT_TYPE_CHANGED_CONTRACTED_SUPERINTERFACES_SET=Error
+ENUM_ELEMENT_TYPE_CHANGED_TYPE_CONVERSION=Error
+ENUM_ELEMENT_TYPE_REMOVED_ENUM_CONSTANT=Error
+ENUM_ELEMENT_TYPE_REMOVED_FIELD=Error
+ENUM_ELEMENT_TYPE_REMOVED_METHOD=Error
+ENUM_ELEMENT_TYPE_REMOVED_TYPE_MEMBER=Error
+FIELD_ELEMENT_TYPE_ADDED_VALUE=Error
+FIELD_ELEMENT_TYPE_CHANGED_DECREASE_ACCESS=Error
+FIELD_ELEMENT_TYPE_CHANGED_FINAL_TO_NON_FINAL_STATIC_CONSTANT=Error
+FIELD_ELEMENT_TYPE_CHANGED_NON_FINAL_TO_FINAL=Error
+FIELD_ELEMENT_TYPE_CHANGED_NON_STATIC_TO_STATIC=Error
+FIELD_ELEMENT_TYPE_CHANGED_STATIC_TO_NON_STATIC=Error
+FIELD_ELEMENT_TYPE_CHANGED_TYPE=Error
+FIELD_ELEMENT_TYPE_CHANGED_VALUE=Error
+FIELD_ELEMENT_TYPE_REMOVED_TYPE_ARGUMENT=Error
+FIELD_ELEMENT_TYPE_REMOVED_VALUE=Error
+ILLEGAL_EXTEND=Warning
+ILLEGAL_IMPLEMENT=Warning
+ILLEGAL_INSTANTIATE=Warning
+ILLEGAL_OVERRIDE=Warning
+ILLEGAL_REFERENCE=Warning
+INTERFACE_ELEMENT_TYPE_ADDED_FIELD=Ignore
+INTERFACE_ELEMENT_TYPE_ADDED_METHOD=Error
+INTERFACE_ELEMENT_TYPE_ADDED_RESTRICTIONS=Error
+INTERFACE_ELEMENT_TYPE_ADDED_SUPER_INTERFACE_WITH_METHODS=Error
+INTERFACE_ELEMENT_TYPE_ADDED_TYPE_PARAMETER=Error
+INTERFACE_ELEMENT_TYPE_CHANGED_CONTRACTED_SUPERINTERFACES_SET=Error
+INTERFACE_ELEMENT_TYPE_CHANGED_TYPE_CONVERSION=Error
+INTERFACE_ELEMENT_TYPE_REMOVED_FIELD=Error
+INTERFACE_ELEMENT_TYPE_REMOVED_METHOD=Error
+INTERFACE_ELEMENT_TYPE_REMOVED_TYPE_MEMBER=Error
+INTERFACE_ELEMENT_TYPE_REMOVED_TYPE_PARAMETER=Error
+INVALID_ANNOTATION=Ignore
+INVALID_JAVADOC_TAG=Ignore
+INVALID_REFERENCE_IN_SYSTEM_LIBRARIES=Ignore
+LEAK_EXTEND=Warning
+LEAK_FIELD_DECL=Warning
+LEAK_IMPLEMENT=Warning
+LEAK_METHOD_PARAM=Warning
+LEAK_METHOD_RETURN_TYPE=Warning
+METHOD_ELEMENT_TYPE_ADDED_RESTRICTIONS=Error
+METHOD_ELEMENT_TYPE_ADDED_TYPE_PARAMETER=Error
+METHOD_ELEMENT_TYPE_CHANGED_DECREASE_ACCESS=Error
+METHOD_ELEMENT_TYPE_CHANGED_NON_ABSTRACT_TO_ABSTRACT=Error
+METHOD_ELEMENT_TYPE_CHANGED_NON_FINAL_TO_FINAL=Error
+METHOD_ELEMENT_TYPE_CHANGED_NON_STATIC_TO_STATIC=Error
+METHOD_ELEMENT_TYPE_CHANGED_STATIC_TO_NON_STATIC=Error
+METHOD_ELEMENT_TYPE_CHANGED_VARARGS_TO_ARRAY=Error
+METHOD_ELEMENT_TYPE_REMOVED_ANNOTATION_DEFAULT_VALUE=Error
+METHOD_ELEMENT_TYPE_REMOVED_TYPE_PARAMETER=Error
+MISSING_EE_DESCRIPTIONS=Error
+TYPE_PARAMETER_ELEMENT_TYPE_ADDED_CLASS_BOUND=Error
+TYPE_PARAMETER_ELEMENT_TYPE_ADDED_INTERFACE_BOUND=Error
+TYPE_PARAMETER_ELEMENT_TYPE_CHANGED_CLASS_BOUND=Error
+TYPE_PARAMETER_ELEMENT_TYPE_CHANGED_INTERFACE_BOUND=Error
+TYPE_PARAMETER_ELEMENT_TYPE_REMOVED_CLASS_BOUND=Error
+TYPE_PARAMETER_ELEMENT_TYPE_REMOVED_INTERFACE_BOUND=Error
+UNUSED_PROBLEM_FILTERS=Warning
+automatically_removed_unused_problem_filters=Enabled
+eclipse.preferences.version=1
+incompatible_api_component_version=Error
+incompatible_api_component_version_include_major_without_breaking_change=Disabled
+incompatible_api_component_version_include_minor_without_api_change=Disabled
+invalid_since_tag_version=Error
+malformed_since_tag=Error
+missing_since_tag=Warning
+report_api_breakage_when_major_version_incremented=Disabled
+report_resolution_errors_api_component=Warning
diff --git a/tests/junit/framework/org.eclipse.papyrus.junit.utils/META-INF/MANIFEST.MF b/tests/junit/framework/org.eclipse.papyrus.junit.utils/META-INF/MANIFEST.MF
new file mode 100644
index 00000000000..8912e80c081
--- /dev/null
+++ b/tests/junit/framework/org.eclipse.papyrus.junit.utils/META-INF/MANIFEST.MF
@@ -0,0 +1,32 @@
+Manifest-Version: 1.0
+Require-Bundle: org.eclipse.jdt.ui;bundle-version="[3.12.0,4.0.0)";visibility:=reexport,
+ org.eclipse.papyrus.views.modelexplorer;bundle-version="[3.0.0,4.0.0)",
+ org.eclipse.papyrus.infra.gmfdiag.common;bundle-version="[3.0.0,4.0.0)",
+ org.eclipse.papyrus.uml.tools;bundle-version="[4.0.0,5.0.0)",
+ org.eclipse.papyrus.editor;bundle-version="[2.0.0,3.0.0)",
+ org.eclipse.e4.ui.workbench;bundle-version="[1.4.0,2.0.0)",
+ org.eclipse.e4.ui.model.workbench;bundle-version="[1.2.0,3.0.0)",
+ org.eclipse.e4.core.contexts;bundle-version="[1.5.0,2.0.0)",
+ org.eclipse.papyrus.junit.framework;bundle-version="[1.2.0,2.0.0)";visibility:=reexport,
+ org.eclipse.papyrus.infra.nattable.common;bundle-version="[4.0.0,5.0.0)";visibility:=reexport,
+ org.eclipse.papyrus.infra.internationalization.common;bundle-version="[1.0.0,2.0.0)",
+ org.eclipse.papyrus.infra.internationalization;bundle-version="[1.0.0,2.0.0)"
+Export-Package: org.eclipse.papyrus.junit.matchers,
+ org.eclipse.papyrus.junit.utils,
+ org.eclipse.papyrus.junit.utils.resources,
+ org.eclipse.papyrus.junit.utils.rules,
+ org.eclipse.papyrus.junit.utils.tests
+Bundle-Vendor: %Bundle-Vendor
+Bundle-ActivationPolicy: lazy
+Bundle-Version: 2.1.100.qualifier
+Bundle-Name: %Bundle-Name
+Bundle-ManifestVersion: 2
+Bundle-Activator: org.eclipse.papyrus.junit.utils.Activator
+Bundle-Description: %pluginDescription
+Bundle-SymbolicName: org.eclipse.papyrus.junit.utils;singleton:=true
+Bundle-RequiredExecutionEnvironment: JavaSE-1.8
+Import-Package: com.google.common.base;version="21.0.0",
+ com.google.common.cache;version="21.0.0",
+ com.google.common.collect;version="21.0.0",
+ com.google.common.io;version="21.0.0",
+ com.google.common.primitives;version="21.0.0"
diff --git a/tests/junit/framework/org.eclipse.papyrus.junit.utils/OSGI-INF/l10n/bundle.properties b/tests/junit/framework/org.eclipse.papyrus.junit.utils/OSGI-INF/l10n/bundle.properties
new file mode 100644
index 00000000000..fbed29c7002
--- /dev/null
+++ b/tests/junit/framework/org.eclipse.papyrus.junit.utils/OSGI-INF/l10n/bundle.properties
@@ -0,0 +1,3 @@
+#Properties file for org.eclipse.papyrus.junit.utils
+Bundle-Vendor = Eclipse Modeling Project
+Bundle-Name = Utils classes for JUnit tests \ No newline at end of file
diff --git a/tests/junit/framework/org.eclipse.papyrus.junit.utils/about.html b/tests/junit/framework/org.eclipse.papyrus.junit.utils/about.html
new file mode 100644
index 00000000000..dd3c089a94c
--- /dev/null
+++ b/tests/junit/framework/org.eclipse.papyrus.junit.utils/about.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"/>
+<title>About</title>
+</head>
+<body lang="EN-US">
+<h2>About This Content</h2>
+
+<p>November 14, 2008</p>
+<h3>License</h3>
+
+<p>The Eclipse Foundation makes available all content in this plug-in (&quot;Content&quot;). Unless otherwise
+indicated below, the Content is provided to you under the terms and conditions of the
+Eclipse Public License Version 1.0 (&quot;EPL&quot;). A copy of the EPL is available
+at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>.
+For purposes of the EPL, &quot;Program&quot; will mean the Content.</p>
+
+<p>If you did not receive this Content directly from the Eclipse Foundation, the Content is
+being redistributed by another party (&quot;Redistributor&quot;) and different terms and conditions may
+apply to your use of any object code in the Content. Check the Redistributor's license that was
+provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise
+indicated below, the terms and conditions of the EPL still apply to any source code in the Content
+and such source code may be obtained at <a href="http://www.eclipse.org">http://www.eclipse.org</a>.</p>
+
+</body>
+</html> \ No newline at end of file
diff --git a/tests/junit/framework/org.eclipse.papyrus.junit.utils/build.properties b/tests/junit/framework/org.eclipse.papyrus.junit.utils/build.properties
new file mode 100644
index 00000000000..bafbbb53ba0
--- /dev/null
+++ b/tests/junit/framework/org.eclipse.papyrus.junit.utils/build.properties
@@ -0,0 +1,8 @@
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+ .,\
+ OSGI-INF/,\
+ about.html,\
+ build.properties
+src.includes = about.html
diff --git a/tests/junit/framework/org.eclipse.papyrus.junit.utils/plugin.properties b/tests/junit/framework/org.eclipse.papyrus.junit.utils/plugin.properties
new file mode 100644
index 00000000000..57cdbe5fa4b
--- /dev/null
+++ b/tests/junit/framework/org.eclipse.papyrus.junit.utils/plugin.properties
@@ -0,0 +1,12 @@
+#################################################################################
+# Copyright (c) 2015 CEA LIST.
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+# Benoit Maggi (CEA LIST) benoit.maggi@cea.fr - initial API and implementation
+##################################################################################)
+
+pluginDescription=This plugin provides useful methods for the JUnit tests \ No newline at end of file
diff --git a/tests/junit/framework/org.eclipse.papyrus.junit.utils/pom.xml b/tests/junit/framework/org.eclipse.papyrus.junit.utils/pom.xml
new file mode 100644
index 00000000000..fc9d6273c58
--- /dev/null
+++ b/tests/junit/framework/org.eclipse.papyrus.junit.utils/pom.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.eclipse.papyrus.tests</groupId>
+ <artifactId>org.eclipse.papyrus.tests.junit-framework</artifactId>
+ <version>0.0.1-SNAPSHOT</version>
+ </parent>
+ <groupId>org.eclipse.papyrus</groupId>
+ <artifactId>org.eclipse.papyrus.junit.utils</artifactId>
+ <version>2.1.100-SNAPSHOT</version>
+ <packaging>eclipse-plugin</packaging>
+</project> \ No newline at end of file
diff --git a/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/matchers/DiagramMatchers.java b/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/matchers/DiagramMatchers.java
new file mode 100644
index 00000000000..b78720e078a
--- /dev/null
+++ b/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/matchers/DiagramMatchers.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2014 CEA and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus (CEA) - Initial API and implementation
+ *
+ */
+package org.eclipse.papyrus.junit.matchers;
+
+import org.eclipse.gef.EditPart;
+import org.eclipse.gef.EditPartViewer;
+import org.eclipse.gef.palette.PaletteDrawer;
+import org.eclipse.gef.ui.palette.PaletteViewer;
+import org.hamcrest.BaseMatcher;
+import org.hamcrest.Description;
+import org.hamcrest.Matcher;
+
+
+/**
+ * Hamcrest matchers for assertions on GMF diagrams.
+ */
+public class DiagramMatchers {
+
+ private DiagramMatchers() {
+ super();
+ }
+
+ /**
+ * Match an edit part that is selected in its viewer.
+ */
+ public static Matcher<EditPart> editPartSelected() {
+ return EditPartSelected.INSTANCE;
+ }
+
+ /**
+ * Match a drawer that is expanded in the specified {@code viewer}.
+ */
+ public static Matcher<PaletteDrawer> expandedIn(PaletteViewer viewer) {
+ return new DrawerExpansion(viewer, true);
+ }
+
+ /**
+ * Match a drawer that is collapsed (closed) in the specified {@code viewer}.
+ */
+ public static Matcher<PaletteDrawer> collapsedIn(PaletteViewer viewer) {
+ return new DrawerExpansion(viewer, false);
+ }
+
+ //
+ // Nested types
+ //
+
+ static class EditPartSelected extends BaseMatcher<EditPart> {
+
+ private static final EditPartSelected INSTANCE = new EditPartSelected();
+
+ private EditPartSelected() {
+ super();
+ }
+
+ public void describeTo(Description description) {
+ description.appendText("edit-part is selected");
+ }
+
+ public boolean matches(Object item) {
+ return (item instanceof EditPart) && isSelected((EditPart)item);
+ }
+
+ boolean isSelected(EditPart editPart) {
+ EditPartViewer viewer = editPart.getViewer();
+ return (viewer != null) && viewer.getSelectedEditParts().contains(editPart);
+ }
+ }
+
+ static class DrawerExpansion extends BaseMatcher<PaletteDrawer> {
+
+ private final PaletteViewer viewer;
+
+ private final boolean expanded;
+
+ DrawerExpansion(PaletteViewer viewer, boolean expanded) {
+ this.viewer = viewer;
+ this.expanded = expanded;
+ }
+
+ public void describeTo(Description description) {
+ description.appendText("drawer is ");
+ description.appendText(expanded ? "expanded" : "collapsed");
+ }
+
+ public boolean matches(Object item) {
+ return (item instanceof PaletteDrawer) && (isExpanded((PaletteDrawer)item) == expanded);
+ }
+
+ boolean isExpanded(PaletteDrawer drawer) {
+ return viewer.isExpanded(drawer);
+ }
+ }
+}
diff --git a/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/matchers/MoreMatchers.java b/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/matchers/MoreMatchers.java
new file mode 100644
index 00000000000..9765f99db05
--- /dev/null
+++ b/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/matchers/MoreMatchers.java
@@ -0,0 +1,175 @@
+/*****************************************************************************
+ * Copyright (c) 2014, 2015 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.junit.matchers;
+
+import java.util.regex.Pattern;
+
+import org.eclipse.core.runtime.IStatus;
+import org.hamcrest.BaseMatcher;
+import org.hamcrest.Description;
+import org.hamcrest.Matcher;
+import org.hamcrest.core.CombinableMatcher;
+
+import com.google.common.base.Strings;
+import com.google.common.collect.Iterables;
+
+/**
+ * Some useful matchers that Hamcrest doesn't provide.
+ */
+public class MoreMatchers {
+
+ private MoreMatchers() {
+ super();
+ }
+
+ public static <N extends Number & Comparable<N>> Matcher<N> greaterThan(final N minimum) {
+ return new BaseMatcher<N>() {
+ @Override
+ public void describeTo(Description description) {
+ description.appendText("greater than ").appendValue(minimum);
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public boolean matches(Object item) {
+ return ((N) item).compareTo(minimum) > 0;
+ }
+ };
+ }
+
+ public static <N extends Number & Comparable<N>> Matcher<N> lessThan(final N maximum) {
+ return new BaseMatcher<N>() {
+ @Override
+ public void describeTo(Description description) {
+ description.appendText("less than ").appendValue(maximum);
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public boolean matches(Object item) {
+ return ((N) item).compareTo(maximum) < 0;
+ }
+ };
+ }
+
+ /**
+ * Match empty iterables of any kind.
+ *
+ * @see #emptyIterable()
+ */
+ public static Matcher<Iterable<?>> isEmpty() {
+ return new BaseMatcher<Iterable<?>>() {
+ @Override
+ public void describeTo(Description description) {
+ description.appendText("is empty");
+ }
+
+ @Override
+ public boolean matches(Object item) {
+ return Iterables.isEmpty((Iterable<?>) item);
+ }
+ };
+ }
+
+ /**
+ * The {@link CombinableMatcher}s of Hamcrest require matching generic signatures,
+ * for which the wildcard of the {@link #isEmpty()} matcher doesn't work very well,
+ * so this equivalent matcher may be used instead in those cases.
+ *
+ * @see #isEmpty()
+ */
+ public static <E> Matcher<Iterable<E>> emptyIterable() {
+ return new BaseMatcher<Iterable<E>>() {
+ @Override
+ public void describeTo(Description description) {
+ description.appendText("is empty");
+ }
+
+ @Override
+ public boolean matches(Object item) {
+ return Iterables.isEmpty((Iterable<?>) item);
+ }
+ };
+ }
+
+ public static Matcher<String> regexMatches(final String pattern) {
+ return new BaseMatcher<String>() {
+ @Override
+ public void describeTo(Description description) {
+ description.appendText("matches /").appendText(pattern).appendText("/");
+ }
+
+ @Override
+ public boolean matches(Object item) {
+ String string = (String) item;
+ return !Strings.isNullOrEmpty(string) && string.matches(pattern);
+ }
+ };
+ }
+
+ public static Matcher<String> regexContains(final String pattern) {
+ final Pattern regex = Pattern.compile(pattern);
+
+ return new BaseMatcher<String>() {
+ @Override
+ public void describeTo(Description description) {
+ description.appendText("contains /").appendText(pattern).appendText("/");
+ }
+
+ @Override
+ public boolean matches(Object item) {
+ String string = (String) item;
+ return !Strings.isNullOrEmpty(string) && regex.matcher(string).find();
+ }
+ };
+ }
+
+ public static Matcher<IStatus> statusWithMessage(final Matcher<? super String> matcher) {
+ return new BaseMatcher<IStatus>() {
+ @Override
+ public void describeTo(Description description) {
+ description.appendText("status with message ").appendDescriptionOf(matcher);
+ }
+
+ @Override
+ public boolean matches(Object item) {
+ boolean result = false;
+ if (item instanceof IStatus) {
+ IStatus status = (IStatus) item;
+ result = matcher.matches(status.getMessage());
+ }
+ return result;
+ }
+ };
+ }
+
+ public static Matcher<IStatus> statusWithException(final Matcher<?> matcher) {
+ return new BaseMatcher<IStatus>() {
+ @Override
+ public void describeTo(Description description) {
+ description.appendText("status with exception ").appendDescriptionOf(matcher);
+ }
+
+ @Override
+ public boolean matches(Object item) {
+ boolean result = false;
+ if (item instanceof IStatus) {
+ IStatus status = (IStatus) item;
+ result = matcher.matches(status.getException());
+ }
+ return result;
+ }
+ };
+ }
+}
diff --git a/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/Activator.java b/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/Activator.java
new file mode 100644
index 00000000000..3f1a9deceb6
--- /dev/null
+++ b/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/Activator.java
@@ -0,0 +1,83 @@
+/*****************************************************************************
+ * Copyright (c) 2012, 2015 CEA LIST, Christian W. Damus, and others.
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Vincent Lorenzo (CEA LIST) Vincent.Lorenzo@cea.fr - Initial API and implementation
+ * Christian W. Damus - bug 433206
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.junit.utils;
+
+import org.eclipse.papyrus.infra.core.log.LogHelper;
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.application.ApplicationHandle;
+
+/**
+ * The activator class controls the plug-in life cycle
+ */
+public class Activator extends AbstractUIPlugin {
+
+ // The plug-in ID
+ public static final String PLUGIN_ID = "org.eclipse.papyrus.junit.utils"; //$NON-NLS-1$
+
+ // The shared instance
+ private static Activator plugin;
+
+ public static LogHelper log;
+
+ private String runningApplicationID;
+
+ /**
+ * The constructor
+ */
+ public Activator() {
+ }
+
+ @Override
+ public void start(BundleContext context) throws Exception {
+ super.start(context);
+ plugin = this;
+ log = new LogHelper(this);
+
+ // Get the running application ID
+ ServiceReference<ApplicationHandle> appRef = context.getServiceReference(ApplicationHandle.class);
+ if (appRef != null) {
+ ApplicationHandle appHandle = context.getService(appRef);
+ if (appHandle != null) {
+ try {
+ runningApplicationID = appHandle.getApplicationDescriptor().getApplicationId();
+ } finally {
+ context.ungetService(appRef);
+ }
+ }
+ }
+ }
+
+ @Override
+ public void stop(BundleContext context) throws Exception {
+ plugin = null;
+ super.stop(context);
+ }
+
+ /**
+ * Returns the shared instance
+ *
+ * @return the shared instance
+ */
+ public static Activator getDefault() {
+ return plugin;
+ }
+
+ public String getRunningApplicationID() {
+ return (runningApplicationID == null) ? "" : runningApplicationID; //$NON-NLS-1$
+ }
+
+}
diff --git a/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/DiagramUtils.java b/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/DiagramUtils.java
new file mode 100644
index 00000000000..a44656558aa
--- /dev/null
+++ b/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/DiagramUtils.java
@@ -0,0 +1,172 @@
+/*****************************************************************************
+ * Copyright (c) 2014 CEA LIST.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * CEA LIST - Initial API and implementation
+ *****************************************************************************/
+package org.eclipse.papyrus.junit.utils;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.gef.EditPart;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.DiagramEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart;
+import org.eclipse.gmf.runtime.notation.Diagram;
+import org.eclipse.gmf.runtime.notation.Edge;
+import org.eclipse.gmf.runtime.notation.Shape;
+import org.eclipse.gmf.runtime.notation.View;
+import org.eclipse.papyrus.infra.core.resource.AbstractBaseModel;
+import org.eclipse.papyrus.infra.core.resource.IModel;
+import org.eclipse.papyrus.infra.core.resource.ModelSet;
+import org.eclipse.papyrus.infra.gmfdiag.common.model.NotationModel;
+import org.eclipse.papyrus.infra.ui.editor.IMultiDiagramEditor;
+import org.eclipse.swt.graphics.RGB;
+import org.eclipse.uml2.uml.NamedElement;
+import org.junit.Assert;
+
+/**
+ * Utility class for diagrams
+ */
+public class DiagramUtils {
+
+ public static IGraphicalEditPart findEditPartforView(IMultiDiagramEditor papyrusEditor, View view, Class<? extends EditPart> editPartClass) {
+ DiagramEditPart diagramEditPart = findDiagramEditPart(papyrusEditor);
+ Object part = diagramEditPart.getViewer().getEditPartRegistry().get(view);
+ Assert.assertNotNull("Cannot find the edit part", part);
+ Assert.assertNotNull("part has not the right class", editPartClass.isAssignableFrom(part.getClass()));
+ return (IGraphicalEditPart) part;
+ }
+
+ public static DiagramEditPart findDiagramEditPart(IMultiDiagramEditor papyrusEditor) {
+ DiagramEditPart diagramEditPart = (DiagramEditPart) papyrusEditor.getAdapter(DiagramEditPart.class);
+ Assert.assertNotNull("Cannot find the Diagram edit part", diagramEditPart);
+ return diagramEditPart;
+ }
+
+ /**
+ * Search and returns the first view in the specified container view with the given name
+ *
+ * @param container
+ * the view container of the searched view
+ * @param elementName
+ * the name of the element represented by the search view
+ * @return the found view or <code>null</code> if none was found
+ */
+ public static Shape findShape(View container, String elementName) {
+ for (Object viewObject : container.getChildren()) {
+ View view = (View) viewObject;
+ if (view instanceof Shape && view.getElement() instanceof NamedElement) {
+ NamedElement element = (NamedElement) view.getElement();
+ if (elementName.equals(element.getName())) {
+ return (Shape) view;
+ }
+ }
+ }
+
+
+ // Assert.fail("Cannot find the view associated to " + elementName);
+ return null;
+ }
+
+
+
+ /**
+ * Search and returns the first view in the specified container view with the given name
+ *
+ * @param container
+ * the container
+ * @param elementName
+ * the element name
+ * @return the edge
+ */
+ public static Edge findEdge(View container, String elementName) {
+ for (Object viewObject : container.eContents()) {
+ if (viewObject instanceof View) {
+ View view = (View) viewObject;
+ if (view instanceof Edge && view.getElement() instanceof NamedElement) {
+ NamedElement element = (NamedElement) view.getElement();
+ if (elementName.equals(element.getName())) {
+ return (Edge) view;
+ }
+ }
+ }
+ }
+
+
+ // Assert.fail("Cannot find the view associated to " + elementName);
+ return null;
+ }
+
+
+ /**
+ * Returns the int corresponding to the given tuple
+ *
+ * @param red
+ * @param green
+ * @param blue
+ * @return
+ */
+ public static int rgb(int red, int green, int blue) {
+ return red | green << 8 | blue << 16;
+ }
+
+ public static RGB integerToRGB(int value) {
+ int blue = value & 255;
+ int green = (value >> 8) & 255;
+ int red = (value >> 16) & 255;
+ return new RGB(red, green, blue);
+ }
+
+ public static String integerToRGBString(int value) {
+ RGB rgb = integerToRGB(value);
+ return rgb.toString();
+
+ }
+
+ public static Diagram getNotationDiagram(ModelSet modelSet, String string) {
+ IModel notationModel = modelSet.getModel(NotationModel.MODEL_ID);
+
+ AbstractBaseModel notationBaseModel = null;
+ if (notationModel instanceof AbstractBaseModel) {
+ notationBaseModel = (AbstractBaseModel) notationModel;
+ } else {
+ Assert.fail("notation model is not an abstract base model"); //$NON-NLS-1$
+ return null;
+ }
+ Assert.assertTrue("notation resource contains nothing", notationBaseModel.getResource().getContents().size() >= 1); //$NON-NLS-1$
+ for (EObject object : notationBaseModel.getResource().getContents()) {
+ if (object instanceof Diagram && string.equals(((Diagram) object).getName())) {
+ return (Diagram) object;
+ }
+ }
+ return null;
+ }
+
+ public static Collection<Diagram> getAllNotationDiagram(ModelSet modelSet, String string) {
+ IModel notationModel = modelSet.getModel(NotationModel.MODEL_ID);
+ Collection<Diagram> arrayList = new ArrayList<Diagram>();
+ AbstractBaseModel notationBaseModel = null;
+ if (notationModel instanceof AbstractBaseModel) {
+ notationBaseModel = (AbstractBaseModel) notationModel;
+ } else {
+ Assert.fail("notation model is not an abstract base model");
+ return null;
+ }
+ Assert.assertTrue("notation resource contains nothing", notationBaseModel.getResource().getContents().size() >= 1);
+ for (EObject object : notationBaseModel.getResource().getContents()) {
+ if (object instanceof Diagram && string.equals(((Diagram) object).getName())) {
+ arrayList.add((Diagram) object);
+ }
+ }
+ return arrayList;
+ }
+
+
+}
diff --git a/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/DisplayUtils.java b/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/DisplayUtils.java
new file mode 100644
index 00000000000..e9ff430657d
--- /dev/null
+++ b/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/DisplayUtils.java
@@ -0,0 +1,38 @@
+/*****************************************************************************
+ * Copyright (c) 2014 CEA LIST.
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Vincent Lorenzo (CEA LIST) Vincent.Lorenzo@cea.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.junit.utils;
+
+import org.eclipse.swt.widgets.Display;
+
+
+public class DisplayUtils {
+
+ /** Processes all events waiting in the Display's event loop and then returns. */
+ public static void flushEventLoop() {
+ final Display display = Display.getDefault();
+ display.syncExec(new Runnable() {
+
+ public void run() {
+ try {
+ while(display.readAndDispatch()) {
+ // nothing
+ }
+ } catch (Exception ex) {
+ //Do not fail the test for invalid runnables
+ }
+ }
+ });
+ }
+
+}
diff --git a/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/Duck.java b/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/Duck.java
new file mode 100644
index 00000000000..6da762ab6d7
--- /dev/null
+++ b/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/Duck.java
@@ -0,0 +1,255 @@
+/*
+ * Copyright (c) 2014, 2016 CEA, Christian W. Damus, and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus (CEA) - Initial API and implementation
+ * Christian W. Damus - bug 485214
+ *
+ */
+package org.eclipse.papyrus.junit.utils;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.eclipse.emf.common.util.WrappedException;
+
+import com.google.common.primitives.Primitives;
+
+
+/**
+ * A clumsy Java implementation of <em>Duck Typing</em>, in which objects are manipulated reflectively according to their public interface (the
+ * operations they provide) rather than their types.
+ */
+public class Duck {
+
+ private final Object target;
+
+ /**
+ * Wraps an object as a duck.
+ *
+ * @param target
+ * the object to wrap. Must not be {@code null}
+ *
+ * @throws NullPointerException
+ * on attempt to duck-wrap a {@code null}
+ */
+ public Duck(Object target) {
+ super();
+
+ if (target == null) {
+ throw new NullPointerException();
+ }
+
+ this.target = target;
+ }
+
+ /**
+ * Queries whether the duck understands the named message (implying that it can {@linkplain #quack(String, Object...) quack} it.
+ * This accounts for signature overloading by finding the first method that accepts the given arguments.
+ *
+ * @param methodName
+ * the method name
+ * @param arg
+ * the arguments to the method
+ * @return whether I can invoke the named method with these arguments
+ */
+ public boolean understands(String methodName, Object... arg) {
+ return lookup(methodName, null, arg) != null;
+ }
+
+ /**
+ * Queries whether the duck understands a message matching the given regex(implying that it can {@linkplain #quackp(String, Object...) quack} it.
+ * This accounts for signature overloading by finding the first method that accepts the given arguments.
+ *
+ * @param methodPattern
+ * the method name pattern
+ * @param arg
+ * the arguments to the method
+ * @return whether I can invoke the indicated method with these arguments
+ */
+ public boolean understandsp(String methodPattern, Object... arg) {
+ return lookup(Pattern.compile(methodPattern), null, arg) != null;
+ }
+
+ /**
+ * Reflectively invokes a method by name. This accounts for signature overloading by finding the first method that accepts the given arguments.
+ *
+ * @param methodName
+ * the method name
+ * @param arg
+ * the arguments to the method
+ * @return the method result, which would be {@code null} in the case of a {@code void} method
+ */
+ public <T> T quack(String methodName, Object... arg) {
+ return invoke(lookup(methodName, null, arg), arg);
+ }
+
+ /**
+ * Reflectively invokes a method by regex (matching the method name). This accounts for signature overloading by finding the first method that
+ * accepts the given arguments.
+ *
+ * @param methodPattern
+ * the method name pattern
+ * @param arg
+ * the arguments to the method
+ * @return the method result, which would be {@code null} in the case of a {@code void} method
+ */
+ public <T> T quackp(String methodPattern, Object... arg) {
+ return invoke(lookup(Pattern.compile(methodPattern), null, arg), arg);
+ }
+
+ /**
+ * Reflectively invokes a method by name {@code returning} a type conforming to the given type. This accounts for signature overloading by finding
+ * the first method that accepts the given arguments.
+ *
+ * @param methodName
+ * the method name
+ * @param returning
+ * the required return type, or {@code null} if the return type doesn't matter
+ * @param arg
+ * the arguments to the method
+ * @return the method result, which would be {@code null} in the case of a {@code void} method
+ */
+ public <T> T quack(String methodName, Class<T> returning, Object... arg) {
+ return invoke(lookup(methodName, returning, arg), arg);
+ }
+
+ /**
+ * Reflectively invokes a method by regex (matching the method name) {@code returning} a type conforming to the given type. This accounts for
+ * signature overloading by finding the first method that
+ * accepts the given arguments.
+ *
+ * @param methodPattern
+ * the method name pattern
+ * @param returning
+ * the required return type, or {@code null} if the return type doesn't matter
+ * @param arg
+ * the arguments to the method
+ * @return the method result, which would be {@code null} in the case of a {@code void} method
+ */
+ public <T> T quackp(String methodPattern, Class<T> returning, Object... arg) {
+ return invoke(lookup(Pattern.compile(methodPattern), returning, arg), arg);
+ }
+
+ @SuppressWarnings("unchecked")
+ private <T> T invoke(Method method, Object[] args) {
+ try {
+ return (method == null) ? null : (T) method.invoke(target, args);
+ } catch (IllegalAccessException e) {
+ throw new WrappedException(e);
+ } catch (InvocationTargetException e) {
+ Throwable toThrow = e.getTargetException();
+ if (toThrow instanceof Error) {
+ throw (Error) toThrow;
+ }
+ throw new WrappedException((Exception) toThrow);
+ }
+ }
+
+ private Method lookup(String methodName, Class<?> returning, Object[] args) {
+ Method result = null;
+ final Class<?>[] signature = signature(args);
+
+ Method[] scope = target.getClass().getMethods();
+ for (int i = 0; (result == null) && (i < scope.length); i++) {
+ Method next = scope[i];
+ if (next.getName().equals(methodName) && matchReturn(next.getReturnType(), returning) && match(next, signature)) {
+ result = next;
+ }
+ }
+
+ return result;
+ }
+
+ private Method lookup(Pattern methodPattern, Class<?> returning, Object[] args) {
+ final Matcher m = methodPattern.matcher(""); //$NON-NLS-1$
+
+ Method result = null;
+ final Class<?>[] signature = signature(args);
+
+ Method[] scope = target.getClass().getMethods();
+ for (int i = 0; (result == null) && (i < scope.length); i++) {
+ Method next = scope[i];
+ m.reset(next.getName());
+ if (m.matches() && matchReturn(next.getReturnType(), returning) && match(next, signature)) {
+ result = next;
+ }
+ }
+
+ return result;
+ }
+
+ private static boolean match(Method method, Class<?>[] signature) {
+ Class<?>[] params = method.getParameterTypes();
+ boolean result = params.length == signature.length;
+
+ if (result) {
+ for (int i = 0; result && (i < signature.length); i++) {
+ result = matchParameter(params[i], signature[i]);
+ }
+ }
+
+ return result;
+ }
+
+ private static boolean matchReturn(Class<?> returnType, Class<?> expectedType) {
+ boolean result;
+
+ if (expectedType == null) {
+ // Wildcard: take any method
+ result = true;
+ } else if ((returnType == void.class) || (returnType == Void.class)) {
+ // Handle void methods
+ result = (expectedType == void.class) || (expectedType == Void.class);
+ } else {
+ // Compare the unwrapped primitive types
+ result = Primitives.unwrap(expectedType).isAssignableFrom(Primitives.unwrap(returnType));
+ }
+
+ return result;
+ }
+
+ private static boolean matchParameter(Class<?> paramType, Class<?> argType) {
+ boolean result;
+
+ if (argType == Void.class) {
+ // Handle null arguments: null is assignable to any object type (not primitive)
+ result = !paramType.isPrimitive();
+ } else if (paramType.isPrimitive()) {
+ // Compare the wrapper type
+ result = Primitives.wrap(paramType).isAssignableFrom(argType);
+ } else {
+ // Straight-forward object types
+ result = paramType.isAssignableFrom(argType);
+ }
+
+ return result;
+ }
+
+ private static Class<?>[] signature(Object[] args) {
+ Class<?>[] result = new Class<?>[args.length];
+
+ for (int i = 0; i < args.length; i++) {
+ result[i] = (args[i] == null) ? Void.class : args[i].getClass();
+ }
+
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return (obj instanceof Duck) && target.equals(((Duck) obj).target);
+ }
+
+ @Override
+ public int hashCode() {
+ return target.hashCode();
+ }
+}
diff --git a/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/EditorUtils.java b/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/EditorUtils.java
new file mode 100644
index 00000000000..b388df6b639
--- /dev/null
+++ b/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/EditorUtils.java
@@ -0,0 +1,109 @@
+/*****************************************************************************
+ * Copyright (c) 2012, 2015 CEA LIST, Christian W. Damus, and others.
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Vincent Lorenzo (CEA LIST) Vincent.Lorenzo@cea.fr - Initial API and implementation
+ * Christian W. Damus - bug 434983
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.junit.utils;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.papyrus.editor.PapyrusMultiDiagramEditor;
+import org.eclipse.papyrus.infra.ui.editor.IMultiDiagramEditor;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.ide.IDE;
+import org.junit.Assert;
+
+/**
+ *
+ * useful methods for Editors
+ *
+ */
+public class EditorUtils {
+
+ private EditorUtils() {
+ // to prevent instanciation
+ }
+
+ /**
+ *
+ * @param file
+ * a file
+ * @return
+ * the opened editor for this file
+ * @throws PartInitException
+ */
+ public static final IEditorPart openEditor(final IFile file) throws PartInitException {
+ return withoutLayoutStoragePopup(() -> {
+ GenericUtils.closeIntroPart();
+ final IWorkbenchPage activePage = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
+ IEditorPart editor = null;
+ editor = IDE.openEditor(activePage, file);
+ Assert.assertNotNull(editor);
+ return editor;
+ });
+ }
+
+ /**
+ * Opens the file with the Papyrus Editor
+ *
+ * @param file
+ * @return
+ * @throws PartInitException
+ */
+ public static final IMultiDiagramEditor openPapyrusEditor(final IFile file) throws PartInitException {
+ return withoutLayoutStoragePopup(() -> {
+ GenericUtils.closeIntroPart();
+ final IWorkbenchPage activePage = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
+ IEditorPart editor = null;
+ editor = IDE.openEditor(activePage, file, PapyrusMultiDiagramEditor.EDITOR_ID);
+ Assert.assertNotNull(editor);
+ return (IMultiDiagramEditor) editor;
+ });
+ }
+
+ /**
+ * Opens an editor without the possibility of it showing a prompt dialog to convert
+ * DI-file storage of the page layout to private sash-file storage.
+ */
+ @SuppressWarnings("restriction")
+ private static <E extends IEditorPart> E withoutLayoutStoragePopup(EditorOpener<E> editorOpener) throws PartInitException {
+ E result;
+ boolean posted = false;
+
+ org.eclipse.papyrus.infra.ui.internal.preferences.YesNo originalPreference = org.eclipse.papyrus.infra.ui.internal.preferences.EditorPreferences.getInstance().getConvertSharedPageLayoutToPrivate();
+ org.eclipse.papyrus.infra.ui.internal.preferences.EditorPreferences.getInstance().setConvertSharedPageLayoutToPrivate(org.eclipse.papyrus.infra.ui.internal.preferences.YesNo.NO);
+
+ try {
+ result = editorOpener.openEditor();
+ result.getSite().getShell().getDisplay().asyncExec(() -> org.eclipse.papyrus.infra.ui.internal.preferences.EditorPreferences.getInstance().setConvertSharedPageLayoutToPrivate(originalPreference));
+ posted = true;
+ } finally {
+ if (!posted) {
+ // Revert now because the editor failed to open and we won't be reverting asynchronously
+ org.eclipse.papyrus.infra.ui.internal.preferences.EditorPreferences.getInstance().setConvertSharedPageLayoutToPrivate(originalPreference);
+ }
+ }
+
+ return result;
+ }
+
+ //
+ // Nested types
+ //
+
+ @FunctionalInterface
+ private interface EditorOpener<E extends IEditorPart> {
+ E openEditor() throws PartInitException;
+ }
+}
diff --git a/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/FilesUtils.java b/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/FilesUtils.java
new file mode 100644
index 00000000000..f3ba910ea0b
--- /dev/null
+++ b/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/FilesUtils.java
@@ -0,0 +1,48 @@
+/*****************************************************************************
+ * Copyright (c) 2012 CEA LIST.
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Vincent Lorenzo (CEA LIST) Vincent.Lorenzo@cea.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.junit.utils;
+
+import java.io.IOException;
+import java.net.URL;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.NullProgressMonitor;
+
+/**
+ *
+ * Useful methods to manipulate files
+ *
+ */
+public class FilesUtils {
+
+ /**
+ *
+ * @param testProject
+ * the destination projecr
+ * @param newFilename
+ * the new name of the copied file
+ * @param fileURL
+ * the URl of the file to copy
+ * @throws IOException
+ * @throws CoreException
+ */
+ public static final void copyFiles(final IProject testProject, final String newFilename, final URL fileURL) throws CoreException, IOException {
+ // Copy EmptyModel from bundle to the test project
+ final IFile emptyModel = testProject.getFile(newFilename);
+ emptyModel.create(fileURL.openStream(), true, new NullProgressMonitor());
+
+ }
+}
diff --git a/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/GenericUtils.java b/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/GenericUtils.java
new file mode 100644
index 00000000000..fd3c865820a
--- /dev/null
+++ b/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/GenericUtils.java
@@ -0,0 +1,64 @@
+/*****************************************************************************
+ * Copyright (c) 2012 CEA LIST.
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Vincent Lorenzo (CEA LIST) Vincent.Lorenzo@cea.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.junit.utils;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IWorkspace;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.intro.IIntroPart;
+
+/**
+ *
+ Some useful methods for Tests
+ *
+ */
+public class GenericUtils {
+
+ private GenericUtils() {
+ //to prevent instanciation
+ }
+
+ /**
+ * close the Intro part
+ */
+ public static final void closeIntroPart() {
+ final IIntroPart introPart = PlatformUI.getWorkbench().getIntroManager().getIntro();
+ PlatformUI.getWorkbench().getIntroManager().closeIntro(introPart);
+ }
+
+ /**
+ * Close all the editors
+ */
+ public static final void closeAllEditors() {
+ PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().closeAllEditors(false);
+ }
+
+ /**
+ * Clean the workspace
+ *
+ * @throws CoreException
+ */
+ public static final void cleanWorkspace() throws CoreException {
+ // we clean the workspace and create a new project to test the handlers
+ final IWorkspace workspace = ResourcesPlugin.getWorkspace();
+ for(final IProject project : workspace.getRoot().getProjects()) {
+
+ project.delete(true, new NullProgressMonitor());
+
+ }
+ }
+}
diff --git a/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/HandlerUtils.java b/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/HandlerUtils.java
new file mode 100644
index 00000000000..681c3fa9539
--- /dev/null
+++ b/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/HandlerUtils.java
@@ -0,0 +1,95 @@
+/*****************************************************************************
+ * Copyright (c) 2012 CEA LIST.
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Vincent Lorenzo (CEA LIST) Vincent.Lorenzo@cea.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.junit.utils;
+
+import org.eclipse.core.commands.Command;
+import org.eclipse.core.commands.IHandler;
+import org.eclipse.core.commands.ParameterizedCommand;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.commands.ICommandService;
+import org.eclipse.ui.handlers.IHandlerService;
+import org.junit.Assert;
+
+/**
+ *
+ * Useful methods for the handlers and the Eclipse commands
+ *
+ */
+public class HandlerUtils {
+
+ /**
+ * Warning : you should be sure that the correct Editor/partView... has the focus to test the enablement if the handler!
+ *
+ * @param commandId
+ * the command id
+ * @return
+ * the current handler for this command
+ */
+ public static final IHandler getActiveHandlerFor(final String commandId) {
+ return HandlerUtils.getCommand(commandId).getHandler();
+ }
+
+ /**
+ *
+ * @param commandId
+ * the commandId
+ * @return
+ * the real handler for the command
+ */
+ public static final IHandler getRealHandlerFor(final String commandId) {
+ //commented because it works only on Eclipse4
+ //imports to add :
+ // - org.eclipse.e4.ui.model.application.MApplication;
+ // - org.eclipse.e4.core.contexts.IEclipseContext
+ // - org.eclipse.e4.core.commands.internal.HandlerServiceImpl
+ // - org.eclipse.ui.internal.handlers.E4HandlerProxy
+ // MApplication appl = (MApplication)PlatformUI.getWorkbench().getActiveWorkbenchWindow().getService(MApplication.class);
+ // IEclipseContext context = appl.getContext();
+ // E4HandlerProxy handler = HandlerServiceImpl.lookUpHandler(context, commandId);
+ // return handler.getHandler();
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ *
+ * @param commandId
+ * the command id
+ * @return
+ * the command object for this command id
+ */
+ public static final Command getCommand(final String commandId) {
+ final ICommandService commandService = (ICommandService)PlatformUI.getWorkbench().getActiveWorkbenchWindow().getService(ICommandService.class);
+ commandService.refreshElements(commandId, null);
+ Assert.assertNotNull("CommandService can't be found", commandService);
+ Command cmd = commandService.getCommand(commandId);
+ Assert.assertNotNull("Command can't be found", cmd);
+ return cmd;
+ }
+
+ /**
+ * Execute the command
+ *
+ * @param cmd
+ * a command
+ */
+ public static final void executeCommand(final Command cmd) throws Exception {
+ IHandlerService handlerService = (IHandlerService)PlatformUI.getWorkbench().getService(IHandlerService.class);
+ Assert.assertNotNull("Impossible to find handler service", handlerService);
+ final ParameterizedCommand parameterizedCommand = new ParameterizedCommand(cmd, null);
+ Assert.assertEquals("Command is not executable as expected", cmd.isEnabled(), true);
+ //execute the command
+ handlerService.executeCommand(parameterizedCommand, null);
+ }
+
+}
diff --git a/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/JUnitUtils.java b/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/JUnitUtils.java
new file mode 100644
index 00000000000..aaaac0121a3
--- /dev/null
+++ b/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/JUnitUtils.java
@@ -0,0 +1,159 @@
+/*****************************************************************************
+ * Copyright (c) 2015 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.junit.utils;
+
+import java.lang.annotation.Annotation;
+import java.util.Map;
+
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+
+import com.google.common.collect.Maps;
+
+/**
+ * Utilities for working with the JUnit data model and execution environment.
+ */
+public class JUnitUtils {
+
+ /**
+ * Not instantiable by clients.
+ */
+ private JUnitUtils() {
+ super();
+ }
+
+ /**
+ * Obtains the test class implied by a {@code description} that is supplied to a {@link TestRule}.
+ *
+ * @param description
+ * a rule's owning description, which generally would be a test method or a test class
+ * (as these are the contexts in which rules are invoked)
+ *
+ * @return the test class, or {@code null} in the unlikely event that none can be found
+ */
+ public static Class<?> getTestClass(Description description) {
+ Class<?> result = description.getTestClass();
+
+ if (result == null) {
+ for (Description child : description.getChildren()) {
+ result = getTestClass(child);
+ if (result != null) {
+ break;
+ }
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * Obtains the annotations applied to a {@code description} that is supplied to a {@link TestRule}.
+ * If the description is for a test method, the annotations of its owning class are included,
+ * excepting annotations of the same type applied to the method.
+ *
+ * @param description
+ * a rule's owning description, which generally would be a test method or a test class
+ * (as these are the contexts in which rules are invoked)
+ *
+ * @return all of the annotations applied to the test description
+ */
+ public static Iterable<Annotation> getAnnotations(Description description) {
+ Map<Class<? extends Annotation>, Annotation> result = Maps.newLinkedHashMap();
+
+ for (Annotation next : description.getAnnotations()) {
+ result.put(next.annotationType(), next);
+ }
+
+ if (description.getTestClass() != null) {
+ for (Annotation next : description.getTestClass().getAnnotations()) {
+ if (!result.containsKey(next.annotationType())) {
+ result.put(next.annotationType(), next);
+ }
+ }
+ }
+
+ return result.values();
+ }
+
+ /**
+ * Obtains the annotation of the specified {@code type} applicable to a {@code description} that is supplied to a {@link TestRule}.
+ * If the description is for a test method, then if that method doesn't have the requested annotation, its owning class is searched
+ * for the annotation.
+ *
+ * @param description
+ * a rule's owning description, which generally would be a test method or a test class
+ * (as these are the contexts in which rules are invoked)
+ * @param type
+ * the annotation type to look for
+ *
+ * @return the requested annotation, or {@code null} if none was found
+ */
+ public static <A extends Annotation> A getAnnotation(Description description, Class<A> type) {
+ A result = description.getAnnotation(type);
+
+ if ((result == null) && (description.getTestClass() != null)) {
+ result = description.getTestClass().getAnnotation(type);
+ }
+
+ return result;
+ }
+
+ /**
+ * Obtains the annotation of any one of the specified {@code types} applicable to a {@code description} that is supplied to a {@link TestRule}.
+ * If the description is for a test method, then if that method doesn't have any of the requested annotations, its owning class is searched
+ * for the annotations.
+ *
+ * @param description
+ * a rule's owning description, which generally would be a test method or a test class
+ * (as these are the contexts in which rules are invoked)
+ * @param types
+ * the annotation types to look for
+ *
+ * @return the first available of the requested annotations, or {@code null} if none was found
+ */
+ @SafeVarargs
+ public static Annotation getAnyAnnotation(Description description, final Class<? extends Annotation>... types) {
+ Annotation result = null;
+
+ for (Class<? extends Annotation> next : types) {
+ result = description.getAnnotation(next);
+ if (result != null) {
+ break;
+ }
+ }
+
+ if (result == null) {
+ out: for (Class<?> testClass = description.getTestClass(); testClass != null; testClass = testClass.getSuperclass()) {
+ for (Class<? extends Annotation> next : types) {
+ result = testClass.getAnnotation(next);
+ if (result != null) {
+ break out;
+ }
+ }
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * Queries whether the current JUnit test execution is running in the automated build environment
+ * (whether actually on the build server or not; users can run local builds on their development systems, too).
+ *
+ * @return whether the tests are running in the automated build environment
+ */
+ public static boolean isAutomatedBuildExecution() {
+ return Activator.getDefault().getRunningApplicationID().startsWith("org.eclipse.tycho."); //$NON-NLS-1$
+ }
+}
diff --git a/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/LogTracker.java b/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/LogTracker.java
new file mode 100644
index 00000000000..36ee26cc460
--- /dev/null
+++ b/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/LogTracker.java
@@ -0,0 +1,132 @@
+/*****************************************************************************
+ * Copyright (c) 2015 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.junit.utils;
+
+import static org.hamcrest.CoreMatchers.both;
+import static org.hamcrest.CoreMatchers.either;
+import static org.hamcrest.CoreMatchers.everyItem;
+import static org.hamcrest.CoreMatchers.not;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+import java.util.List;
+
+import org.eclipse.core.runtime.ILog;
+import org.eclipse.core.runtime.ILogListener;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.papyrus.junit.matchers.MoreMatchers;
+import org.hamcrest.Matcher;
+
+import com.google.common.base.Predicate;
+import com.google.common.base.Predicates;
+import com.google.common.collect.Lists;
+
+/**
+ * A configurable log listener to help tests to make assertions about the
+ * messages that are logged.
+ */
+public class LogTracker implements ILogListener {
+
+ private String bundle;
+
+ private Predicate<? super IStatus> filter;
+
+ private ILog log;
+
+ private final List<IStatus> messages = Lists.newArrayList();
+
+ public LogTracker() {
+ super();
+ }
+
+ /**
+ * Start tracking the specified {@code bundle}'s log.
+ *
+ * @param bundle
+ * the symbolic name of the bundle whose log is to be tracked
+ */
+ public void start(String bundle) {
+ start(bundle, null);
+ }
+
+ /**
+ * Start tracking the specified {@code bundle}'s log for particular messages.
+ *
+ * @param bundle
+ * the symbolic name of the bundle whose log is to be tracked
+ * @param filter
+ * a filter matching messages that should be recorded, or {@code null} to record all messages
+ */
+ public void start(String bundle, Predicate<? super IStatus> filter) {
+ if (filter == null) {
+ filter = Predicates.alwaysTrue();
+ }
+
+ this.bundle = bundle;
+ this.filter = filter;
+ this.log = Platform.getLog(Platform.getBundle(bundle));
+
+ // Individual ILog instances don't notify listeners
+ Platform.addLogListener(this);
+ }
+
+ public void dispose() {
+ if (log != null) {
+ Platform.removeLogListener(this);
+ log = null;
+
+ clear();
+ bundle = null;
+ filter = null;
+ }
+ }
+
+ public void clear() {
+ messages.clear();
+ }
+
+ @Override
+ public void logging(IStatus status, String plugin) {
+ if ((plugin.equals(bundle) || status.getPlugin().equals(bundle)) && filter.apply(status)) {
+ messages.add(status);
+ }
+ }
+
+ /**
+ * Assert that either there were no messages recorded, or they all satisfy an {@code assertion}.
+ */
+ public void assertAll(Matcher<? super IStatus> assertion) {
+ @SuppressWarnings("unchecked")
+ Matcher<IStatus> hamcrestSignatureWorkaround = (Matcher<IStatus>) assertion;
+ assertThat(messages, either(MoreMatchers.<IStatus> emptyIterable()).or(everyItem(hamcrestSignatureWorkaround)));
+ }
+
+ /**
+ * Assert at least one message was recorded, and all recorded messages satisfy an {@code assertion}.
+ */
+ public void assertExistAll(Matcher<? super IStatus> assertion) {
+ @SuppressWarnings("unchecked")
+ Matcher<IStatus> hamcrestSignatureWorkaround = (Matcher<IStatus>) assertion;
+ assertThat(messages, both(not(MoreMatchers.<IStatus> emptyIterable())).and(everyItem(hamcrestSignatureWorkaround)));
+ }
+
+ /**
+ * Assert that either there were no messages recorded, or they all satisfy an {@code assertion}.
+ */
+ public void assertNone(Matcher<? super IStatus> assertion) {
+ @SuppressWarnings("unchecked")
+ Matcher<IStatus> hamcrestSignatureWorkaround = (Matcher<IStatus>) assertion;
+ assertThat(messages, everyItem(not(hamcrestSignatureWorkaround)));
+ }
+}
diff --git a/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/ModelExplorerUtils.java b/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/ModelExplorerUtils.java
new file mode 100644
index 00000000000..e52615587ce
--- /dev/null
+++ b/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/ModelExplorerUtils.java
@@ -0,0 +1,214 @@
+/*****************************************************************************
+ * Copyright (c) 2012, 2014 CEA LIST and others.
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Vincent Lorenzo (CEA LIST) Vincent.Lorenzo@cea.fr - Initial API and implementation
+ * Christian W. Damus (CEA) - bug 386118
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.junit.utils;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.Command;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.commands.IHandler;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.transaction.RunnableWithResult;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.papyrus.infra.emf.utils.EMFHelper;
+import org.eclipse.papyrus.infra.ui.editor.IMultiDiagramEditor;
+import org.eclipse.papyrus.views.modelexplorer.ModelExplorerPage;
+import org.eclipse.papyrus.views.modelexplorer.ModelExplorerPageBookView;
+import org.eclipse.papyrus.views.modelexplorer.ModelExplorerView;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IViewPart;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.commands.ICommandService;
+import org.eclipse.ui.part.IPage;
+import org.junit.Assert;
+
+/**
+ * Useful methods for the ModelExplorer view
+ */
+public class ModelExplorerUtils {
+
+ /**
+ * the ID of the ModelExplorerView
+ */
+ private static final String ModelExplorerViewId = "org.eclipse.papyrus.views.modelexplorer.modelexplorer"; //$NON-NLS-1$
+
+ private ModelExplorerUtils() {
+ // to prevent instanciation
+ }
+
+ /**
+ *
+ * @return
+ * the opened modelexplorer. Warning, it should be better that Papyrus was opened yet
+ * @throws PartInitException
+ */
+ public static ModelExplorerView openModelExplorerView() throws PartInitException {
+ IViewPart modelexplorer = null;
+ modelexplorer = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().showView(ModelExplorerViewId);
+ final ModelExplorerPageBookView view = (ModelExplorerPageBookView)modelexplorer;
+ final IPage currentPage = view.getCurrentPage();
+ final ModelExplorerPage page = (ModelExplorerPage)currentPage;
+ final IViewPart viewer = page.getViewer();
+ Assert.assertNotNull(viewer);
+ viewer.setFocus();
+ return (ModelExplorerView)viewer;
+ }
+
+ /**
+ *
+ * @param view
+ * the modelexplorer to manipulate
+ * @param elements
+ * the elements to select
+ */
+ public static void setSelectionInTheModelexplorer(final ModelExplorerView view, List<?> elements) {
+ view.revealSemanticElement(elements);
+ final List<?> currentSelection = getCurrentSelectionInTheModelExplorer();
+ Assert.assertTrue("The current selection is not the wanted selection", elements.containsAll(currentSelection)); //$NON-NLS-1$
+ Assert.assertTrue("The current selection is not the wanted selection", currentSelection.containsAll(elements)); //$NON-NLS-1$
+ }
+
+ /**
+ *
+ * @return
+ * the object selected in the ModelExplorer
+ * //TODO : should be moved in the ModelExplorer
+ */
+ public static List<?> getCurrentSelectionInTheModelExplorer() {
+ final List<Object> selection = new ArrayList<Object>();
+ IWorkbenchWindow activeWorkbenchWindow = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
+ if (activeWorkbenchWindow!=null){
+ final IStructuredSelection currentSelection = (IStructuredSelection)activeWorkbenchWindow.getSelectionService().getSelection(ModelExplorerViewId);
+ final Iterator<?> iter = currentSelection.iterator();
+ while(iter.hasNext()) {
+ final Object current = iter.next();
+ EObject eObject = EMFHelper.getEObject(current);
+ if(eObject != null) {
+ selection.add(eObject);
+ } else {
+ selection.add(current);
+ }
+ }
+ }
+ return selection;
+ }
+
+ /**
+ *
+ * @param view
+ * the ModelExplorerView
+ * @return
+ * the root of the Model
+ * //TODO : should be moved in the ModelExplorer
+ */
+ public static final EObject getRootInModelExplorer(final ModelExplorerView view) {
+ view.getCommonViewer().expandToLevel(2);
+
+ // store the root of the model
+ final Object[] visibleElement = view.getCommonViewer().getVisibleExpandedElements();
+ EObject modelRoot = null;
+ if(visibleElement.length > 0) {
+ modelRoot = EMFHelper.getEObject(visibleElement[0]);
+ }
+ Assert.assertNotNull(modelRoot);
+ while(modelRoot.eContainer() != null) {
+ modelRoot = modelRoot.eContainer();
+ }
+ return modelRoot;
+ }
+
+ /**
+ *
+ * @param actionContext
+ * the creation context
+ * @param wantedResult
+ * the wanted result
+ */
+ public static final void testHandlerStatusInModelExplorer(final ModelExplorerView view, final String commandToTest, final EObject actionContext, boolean wantedResult) {
+ setSelectionInTheModelexplorer(view, Collections.singletonList(actionContext));
+ ICommandService commandService = (ICommandService)PlatformUI.getWorkbench().getService(ICommandService.class);
+ Command cmd = commandService.getCommand(commandToTest);
+ IHandler handler = cmd.getHandler();
+ if(handler instanceof AbstractHandler) {
+ ((AbstractHandler)handler).setEnabled(commandToTest);
+ }
+ boolean res = handler.isEnabled();
+ Assert.assertEquals(wantedResult, res);
+ }
+
+ /**
+ * Execute an editor command creation and returns the current papyrus nested editor (you must verify that it is the correct editor to be sure of
+ * the command execution)
+ *
+ * @param currentPapyrusEditor
+ * the current PapyrusEditor
+ * @param view
+ * the model explorer view
+ * @param commandToExecute
+ * the command to execute
+ * @param actionContext
+ * the context used for the commadn (the selected elements)
+ * @param bundelID
+ * the bundle id
+ *
+ * @return
+ * the current papyrus nested editor (you must verify that it is the correct editor to be sure of
+ * the command execution)
+ */
+ public static final Object executeCreateNestedEditorHandlerInModelExplorer(final IMultiDiagramEditor currentPapyrusEditor, final ModelExplorerView view, final String commandToExecute, final EObject actionContext, final String bundelID) {
+ setSelectionInTheModelexplorer(view, Collections.singletonList(actionContext));
+ ICommandService commandService = (ICommandService)PlatformUI.getWorkbench().getService(ICommandService.class);
+ final Command cmd = commandService.getCommand(commandToExecute);
+ final IHandler handler = cmd.getHandler();
+ if(handler instanceof AbstractHandler) {
+ ((AbstractHandler)handler).setEnabled(commandToExecute);
+ }
+ final RunnableWithResult<?> runnableWithResult = new RunnableWithResult.Impl<Object>() {
+
+ public void run() {
+ try {
+ handler.execute(new ExecutionEvent(cmd, Collections.emptyMap(), null, null));
+ } catch (ExecutionException e) {
+ setStatus(new Status(IStatus.ERROR, bundelID, e.getMessage()));
+ }
+
+ IWorkbenchPage activePage = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
+ IEditorPart activeEditor = activePage.getActiveEditor();
+ if(currentPapyrusEditor != activeEditor) {
+ setStatus(new Status(IStatus.ERROR, bundelID, "The current active editor is not the wanted Papyrus Editor")); //$NON-NLS-1$
+ }
+
+ setResult(currentPapyrusEditor.getActiveEditor());
+ setStatus(Status.OK_STATUS);
+ }
+ };
+ Display.getDefault().syncExec(runnableWithResult);
+ Assert.assertEquals(runnableWithResult.getStatus().getMessage(), IStatus.OK, runnableWithResult.getStatus().getSeverity());
+ Object result = runnableWithResult.getResult();
+ Assert.assertNotNull(result);
+ return result;
+ }
+}
diff --git a/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/ModelUtils.java b/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/ModelUtils.java
new file mode 100644
index 00000000000..b5113e57722
--- /dev/null
+++ b/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/ModelUtils.java
@@ -0,0 +1,110 @@
+/*****************************************************************************
+ * Copyright (c) 2013, 2014 CEA LIST and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Initial API and implementation
+ * Christian W. Damus (CEA) - bug 437052
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.junit.utils;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+
+import java.lang.reflect.Field;
+import java.util.Map;
+
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.ecore.util.EcoreUtil;
+import org.eclipse.emf.transaction.TransactionalEditingDomain;
+import org.eclipse.papyrus.infra.core.resource.IReadOnlyHandler2;
+import org.eclipse.papyrus.infra.core.resource.ModelMultiException;
+import org.eclipse.papyrus.infra.core.resource.ModelSet;
+import org.eclipse.papyrus.infra.core.resource.ReadOnlyAxis;
+import org.eclipse.papyrus.infra.core.utils.DiResourceSet;
+
+/**
+ * Helper class for manipulating Papyrus ModelSets
+ *
+ * @author Camille Letavernier
+ *
+ */
+public class ModelUtils {
+
+ /**
+ * Loads a ModelSet and associates a TransactionalEditingDomain to it
+ *
+ * Use {@link #getEditingDomain(ModelSet)} to retrieve the EditingDomain
+ *
+ * @param uri
+ * @param resolveAll
+ * @return
+ * @throws ModelMultiException
+ */
+ public static ModelSet loadModelSet(URI uri, boolean resolveAll) throws ModelMultiException {
+ ModelSet modelSet = new DiResourceSet();
+ TransactionalEditingDomain.Factory.INSTANCE.createEditingDomain(modelSet);
+
+ modelSet.loadModels(uri);
+
+ if(resolveAll) {
+ EcoreUtil.resolveAll(modelSet);
+ }
+
+ return modelSet;
+ }
+
+ public static ModelSet loadModelSet(IPath workspacePath, boolean resolveAll) throws ModelMultiException {
+ URI workspaceURI = URI.createPlatformResourceURI(workspacePath.toString(), true);
+ return loadModelSet(workspaceURI, resolveAll);
+ }
+
+ public static TransactionalEditingDomain getEditingDomain(ModelSet modelSet) {
+ return TransactionalEditingDomain.Factory.INSTANCE.getEditingDomain(modelSet);
+ }
+
+ /**
+ * Attempts to set the specified resource URIs as writable according to the referenced-model handler.
+ *
+ * @param modelSet
+ * a model set
+ * @param uri
+ * referenced-model resource URIs to make writable
+ */
+ public static void makeReferencedModelsWritable(ModelSet modelSet, URI... uris) {
+ IReadOnlyHandler2 handler = modelSet.getReadOnlyHandler();
+ if(handler != null) {
+ try {
+ // It will have this field if it's a ReadOnlyManager
+ Field orderedHandlersByAxisField = handler.getClass().getDeclaredField("orderedHandlersByAxis"); //$NON-NLS-1$
+ orderedHandlersByAxisField.setAccessible(true);
+
+ // Find the referenced-model handler and make it non-interactive so that we don't attempt to pop up a user dialog
+ @SuppressWarnings("unchecked")
+ Map<ReadOnlyAxis, IReadOnlyHandler2[]> orderedHandlersByAxis = (Map<ReadOnlyAxis, IReadOnlyHandler2[]>)orderedHandlersByAxisField.get(handler);
+ for(IReadOnlyHandler2 next : orderedHandlersByAxis.get(ReadOnlyAxis.DISCRETION)) {
+ // If this handler supports user interaction, try to suppress it
+ Duck nextHandler = new Duck(next);
+ if(nextHandler.understands("setInteractive", false)) {
+ nextHandler.quack("setInteractive", false);
+ }
+
+ // And make the resources writable in this handler
+ if(next.canMakeWritable(ReadOnlyAxis.discretionAxes(), uris).or(false)) {
+ next.makeWritable(ReadOnlyAxis.discretionAxes(), uris);
+ }
+ }
+ } catch (Exception e) {
+ // OK, didn't work. Fine. It's expected for non-ReadOnlyManager
+ }
+
+ assertThat("Could not make referenced models writable: " + uris, handler.anyReadOnly(ReadOnlyAxis.discretionAxes(), uris).or(true), is(false));
+ }
+ }
+}
diff --git a/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/PackageExplorerUtils.java b/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/PackageExplorerUtils.java
new file mode 100644
index 00000000000..cb3e3f1b8c6
--- /dev/null
+++ b/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/PackageExplorerUtils.java
@@ -0,0 +1,91 @@
+/*****************************************************************************
+ * Copyright (c) 2012 CEA LIST.
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Vincent Lorenzo (CEA LIST) Vincent.Lorenzo@cea.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.junit.utils;
+
+import java.util.List;
+
+import org.eclipse.jdt.ui.IPackagesViewPart;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.ui.IViewPart;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.PlatformUI;
+import org.junit.Assert;
+
+/**
+ *
+ * Utils Methods for the Package Explorer
+ *
+ */
+public class PackageExplorerUtils {
+
+ /** ID of the Package Explorer View */
+ private static final String PACKAGE_EXPLORER_VIEW_ID = "org.eclipse.jdt.ui.PackageExplorer"; //$NON-NLS-1$
+
+ /**
+ * This methods opens the PackageExplorerView, and give it the focus
+ *
+ * @throws PartInitException
+ */
+ public static final IPackagesViewPart openPackageExplorerView() throws PartInitException {
+ final IWorkbenchWindow activeWorkbenchWindow = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
+ IPackagesViewPart pack = null;
+ IViewPart packageExplorer = activeWorkbenchWindow.getActivePage().showView(PACKAGE_EXPLORER_VIEW_ID);
+ pack = (IPackagesViewPart)packageExplorer;
+ Assert.assertNotNull(pack);
+ pack.setFocus();
+ return pack;
+
+ }
+
+ /**
+ * Set the selection in the PackageExplorer
+ *
+ * @param packageExplorer
+ * the package explorer
+ * @param newSelection
+ * the new selection
+ */
+ public static final void setSelectionInPackageExplorerView(final IPackagesViewPart packageExplorer, final IStructuredSelection newSelection) {
+ packageExplorer.getTreeViewer().expandAll();
+ packageExplorer.getTreeViewer().setSelection(newSelection);
+ //we verify that the current selection is correct in the PackageExplorer
+ IStructuredSelection currentSelection = (IStructuredSelection)packageExplorer.getTreeViewer().getSelection();
+ Assert.assertEquals("Package Explorer: The current selection is not the same as the wanted selection", currentSelection.toList(), newSelection.toList()); //$NON-NLS-1$
+
+ //we verify that the current selection is correct using the selection service
+ currentSelection = getCurrentSelectionInPackageExplorerView();
+ Assert.assertEquals("Package Explorer: The SelectionService doesn't return the wanted selection", currentSelection.toList(), newSelection.toList()); //$NON-NLS-1$
+ }
+
+ /**
+ *
+ * @return
+ * the current selection in the PackageExplorer
+ */
+ public static final IStructuredSelection getCurrentSelectionInPackageExplorerView() {
+ return (IStructuredSelection)PlatformUI.getWorkbench().getActiveWorkbenchWindow().getSelectionService().getSelection(PACKAGE_EXPLORER_VIEW_ID);
+ }
+
+ /**
+ *
+ * @return
+ * the current selection in the PackageExplorer as List
+ */
+ public static final List<?> getCurrentSelectionAsListInPackageExplorerView() {
+ final IStructuredSelection selection = (IStructuredSelection)PlatformUI.getWorkbench().getActiveWorkbenchWindow().getSelectionService().getSelection(PACKAGE_EXPLORER_VIEW_ID);
+ final List<?> list = selection.toList();
+ return list;
+ }
+}
diff --git a/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/PapyrusProjectUtils.java b/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/PapyrusProjectUtils.java
new file mode 100644
index 00000000000..b7208951f4a
--- /dev/null
+++ b/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/PapyrusProjectUtils.java
@@ -0,0 +1,93 @@
+/*****************************************************************************
+ * Copyright (c) 2012 CEA LIST.
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Vincent Lorenzo (CEA LIST) Vincent.Lorenzo@cea.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.junit.utils;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.Locale;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IFolder;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.papyrus.infra.core.resource.sasheditor.DiModel;
+import org.eclipse.papyrus.infra.gmfdiag.common.model.NotationModel;
+import org.eclipse.papyrus.infra.internationalization.utils.PropertiesFilesUtils;
+import org.eclipse.papyrus.uml.tools.model.UmlModel;
+import org.junit.Assert;
+import org.osgi.framework.Bundle;
+
+public class PapyrusProjectUtils {
+
+ private PapyrusProjectUtils() {
+ //to prevent instanciation
+ }
+
+ /**
+ *
+ * @param project
+ * @param bundle
+ * @param sourcePath
+ * should be something like /model/
+ * @param fileRootName
+ * @throws IOException
+ * @throws CoreException
+ */
+ public static final IFile copyPapyrusModel(final IProject project, final Bundle bundle, final String sourcePath, final String fileRootName) throws CoreException, IOException {
+
+ String diSourcePath = sourcePath + fileRootName + "." + DiModel.MODEL_FILE_EXTENSION;
+ String notationSourcePath = sourcePath + fileRootName + "." + NotationModel.NOTATION_FILE_EXTENSION;
+ String umlSourcePath = sourcePath + fileRootName + "." + UmlModel.UML_FILE_EXTENSION;
+
+ final IFile emptyModel_di = copyIFile(diSourcePath, bundle, project, fileRootName + "." + DiModel.MODEL_FILE_EXTENSION);
+ copyIFile(notationSourcePath, bundle, project, fileRootName + "." + NotationModel.NOTATION_FILE_EXTENSION);
+ copyIFile(umlSourcePath, bundle, project, fileRootName + "." + UmlModel.UML_FILE_EXTENSION);
+
+ // Load existing properties files
+ for(final Locale locale : Locale.getAvailableLocales()){
+ String propertiesSourcePath = sourcePath + fileRootName + "_" + locale.toString() + "." + PropertiesFilesUtils.PROPERTIES_FILE_EXTENSION;
+ final URL bundleResource = bundle.getResource(propertiesSourcePath);
+ if(null != bundleResource){
+ copyIFile(propertiesSourcePath, bundle, project, fileRootName + "_" + locale.toString() + "." + PropertiesFilesUtils.PROPERTIES_FILE_EXTENSION);
+ }
+ }
+
+ return emptyModel_di;
+ }
+
+ public static IFile copyIFile(String sourcePath, Bundle sourceBundle, IProject targetProject, String targetFileName) throws CoreException, IOException {
+ final IFile createdFile = targetProject.getFile(targetFileName);
+ if(createdFile.getParent() instanceof IFolder) {
+ createRecursiveFolder((IFolder)createdFile.getParent());
+ }
+ URL bundleResource = sourceBundle.getResource(sourcePath);
+ Assert.assertNotNull("Cannot find bundle resource: " + sourcePath, bundleResource);
+ InputStream bundleResourceStream = bundleResource.openStream();
+ createdFile.create(bundleResourceStream, true, new NullProgressMonitor());
+ return createdFile;
+ }
+
+ public static void createRecursiveFolder(IFolder folderToCreate) throws CoreException {
+ if(folderToCreate.exists()) {
+ return;
+ }
+
+ if(folderToCreate.getParent() instanceof IFolder) {
+ createRecursiveFolder((IFolder)folderToCreate.getParent());
+ }
+ folderToCreate.create(true, true, new NullProgressMonitor());
+ }
+}
diff --git a/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/PrintingProgressMonitor.java b/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/PrintingProgressMonitor.java
new file mode 100644
index 00000000000..e2ca54127c3
--- /dev/null
+++ b/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/PrintingProgressMonitor.java
@@ -0,0 +1,137 @@
+/*****************************************************************************
+ * Copyright (c) 2015 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.junit.utils;
+
+import java.io.PrintStream;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.core.runtime.ProgressMonitorWrapper;
+
+import com.google.common.base.Predicate;
+import com.google.common.base.Predicates;
+
+/**
+ * A progress monitor that prints progress to standard output or some other
+ * {@link PrintStream}, optionally wrapping some other monitor.
+ */
+public class PrintingProgressMonitor extends ProgressMonitorWrapper {
+ private final PrintStream printTo;
+
+ private boolean first;
+
+ private Predicate<String> filter = Predicates.alwaysTrue();
+
+ /**
+ * Initializes me to print to standard output.
+ */
+ public PrintingProgressMonitor() {
+ this(System.out, new NullProgressMonitor());
+ }
+
+ /**
+ * Initializes me to print to some stream.
+ */
+ public PrintingProgressMonitor(PrintStream printTo) {
+ this(printTo, new NullProgressMonitor());
+ }
+
+ /**
+ * Initializes me to print to some stream and wrap another {@code monitor).
+ */
+ public PrintingProgressMonitor(PrintStream printTo, IProgressMonitor monitor) {
+ super(monitor);
+
+ this.printTo = printTo;
+ }
+
+ /**
+ * Adds a filter regular expression that matches task messages to exclude from
+ * the output (to promote quieter progress when appropriate).
+ *
+ * @param pattern
+ * a regular expression pattern for task messages to suppress
+ *
+ * @return myself, for the convenience of call chaining
+ */
+ public PrintingProgressMonitor filter(String pattern) {
+ Pattern regex = Pattern.compile(pattern);
+ final Matcher m = regex.matcher(""); //$NON-NLS-1$
+
+ Predicate<String> filter = new Predicate<String>() {
+ @Override
+ public boolean apply(String input) {
+ m.reset(input);
+ return !m.find();
+ }
+ };
+
+ this.filter = Predicates.and(filter, this.filter);
+
+ return this;
+ }
+
+ private void echo(boolean dashN, String text) {
+ echo(true, false, text);
+ }
+
+ private void echo(boolean initialNewline, boolean terminalNewline, String text) {
+ if (filter.apply(text)) {
+ if (first) {
+ first = false;
+ } else if (initialNewline) {
+ printTo.println();
+ }
+
+ printTo.print(text);
+
+ if (terminalNewline) {
+ printTo.println();
+ }
+ }
+ }
+
+ @Override
+ public void beginTask(String name, int totalWork) {
+ echo(true, name);
+ super.beginTask(name, totalWork);
+ }
+
+ @Override
+ public void setTaskName(String name) {
+ echo(true, name);
+ super.setTaskName(name);
+ }
+
+ @Override
+ public void subTask(String name) {
+ echo(true, name);
+ super.subTask(name);
+ }
+
+ @Override
+ public void worked(int work) {
+ echo(false, false, ".");
+ super.worked(work);
+ }
+
+ @Override
+ public void done() {
+ echo(false, true, " Done.");
+ super.done();
+ }
+
+}
diff --git a/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/ProjectUtils.java b/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/ProjectUtils.java
new file mode 100644
index 00000000000..19bbcbf7309
--- /dev/null
+++ b/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/ProjectUtils.java
@@ -0,0 +1,68 @@
+/*****************************************************************************
+ * Copyright (c) 2012 CEA LIST.
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Vincent Lorenzo (CEA LIST) Vincent.Lorenzo@cea.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.junit.utils;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IWorkspace;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.junit.Assert;
+
+/**
+ *
+ * Useful methods for projects
+ *
+ */
+public class ProjectUtils {
+
+ private ProjectUtils() {
+ // to prevent instanciation
+ }
+
+ /**
+ *
+ * @param projectName
+ * the name of the projecy
+ * @return
+ * the created project
+ * @throws CoreException
+ */
+ public static final IProject createProject(final String projectName) throws CoreException {
+ final IWorkspace workspace = ResourcesPlugin.getWorkspace();
+ final IProject testProject = workspace.getRoot().getProject(projectName);
+
+ if(testProject.exists()) {
+ testProject.delete(true, new NullProgressMonitor());
+ }
+ testProject.create(new NullProgressMonitor());
+ testProject.open(new NullProgressMonitor());
+
+ Assert.assertNotNull(testProject);
+ return testProject;
+ }
+
+ /**
+ * Remove all the projects in a workspace
+ *
+ * @throws CoreException
+ */
+ public static final void removeAllProjectFromTheWorkspace() throws CoreException {
+ IWorkspace workspace = ResourcesPlugin.getWorkspace();
+ for(IProject project : workspace.getRoot().getProjects()) {
+ project.delete(true, new NullProgressMonitor());
+ }
+ }
+
+}
diff --git a/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/SynchronousExecutorService.java b/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/SynchronousExecutorService.java
new file mode 100644
index 00000000000..a6cddd29d97
--- /dev/null
+++ b/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/SynchronousExecutorService.java
@@ -0,0 +1,188 @@
+/*****************************************************************************
+ * Copyright (c) 2014 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.junit.utils;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.AbstractExecutorService;
+import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.FutureTask;
+import java.util.concurrent.RejectedExecutionException;
+import java.util.concurrent.RunnableFuture;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Status;
+
+import com.google.common.collect.ImmutableList;
+
+/**
+ * A convenient {@link ExecutorService} implementation for test cases where we want to control
+ * when asynchronous tasks run.
+ */
+public class SynchronousExecutorService extends AbstractExecutorService {
+
+ /**
+ * A runnable to post to me to cause me to run all pending tasks. This lets the caller
+ * synchronize with me, to run and/or wait for all tasks up to that point.
+ *
+ * @see #flush()
+ */
+ public static final Runnable FLUSH = new Runnable() {
+ public void run() {
+ // Pass
+ }
+ };
+
+ private final AtomicBoolean isShutdown = new AtomicBoolean();
+ private final ConcurrentLinkedQueue<Runnable> queue = new ConcurrentLinkedQueue<Runnable>();
+
+ private final Lock lock = new ReentrantLock();
+ private final Condition done = lock.newCondition();
+
+ /**
+ * Constructor.
+ */
+ public SynchronousExecutorService() {
+ super();
+ }
+
+ public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException {
+ lock.lockInterruptibly();
+ try {
+ long now = System.currentTimeMillis();
+ long deadline = now + unit.toMillis(timeout);
+ while (!isTerminated()) {
+ if (done.await(deadline - now, TimeUnit.MILLISECONDS)) {
+ break;
+ }
+ now = System.currentTimeMillis();
+ if (now >= deadline) {
+ break;
+ }
+ }
+ } finally {
+ lock.unlock();
+ }
+
+ return isTerminated();
+ }
+
+ public boolean isShutdown() {
+ return isShutdown.get();
+ }
+
+ public boolean isTerminated() {
+ return isShutdown() && queue.isEmpty();
+ }
+
+ public void shutdown() {
+ if (isShutdown.compareAndSet(false, true)) {
+ queue.clear();
+ }
+ }
+
+ public List<Runnable> shutdownNow() {
+ List<Runnable> result;
+
+ lock.lock();
+ try {
+ if (isShutdown.compareAndSet(false, true)) {
+ result = ImmutableList.copyOf(queue);
+ queue.clear();
+ done.signalAll();
+ } else {
+ result = Collections.emptyList();
+ }
+ } finally {
+ lock.unlock();
+ }
+
+ return result;
+ }
+
+ public void execute(Runnable command) {
+ final boolean flush = isFlush(command);
+
+ lock.lock();
+ try {
+ if (isShutdown()) {
+ throw new RejectedExecutionException("executor is shut down");
+ }
+
+ // Even if it's FLUSH, enqueue it because somebody may be synchronizing on a Future wrapping it
+ queue.add(command);
+ } finally {
+ lock.unlock();
+ }
+
+ if (flush) {
+ flush();
+ }
+ }
+
+ public void flush() {
+ lock.lock();
+ try {
+ for (Runnable next = queue.poll(); next != null; next = queue.poll()) {
+ lock.unlock();
+
+ try {
+ next.run();
+ } catch (Exception e) {
+ final String bsn = "org.eclipse.papyrus.junit.utils";
+ IStatus status = new Status(IStatus.ERROR, bsn, "Uncaught exception in async runnable.", e);
+ Platform.getLog(Platform.getBundle(bsn)).log(status);
+ } finally {
+ lock.lock();
+ }
+ }
+
+ if (isShutdown()) {
+ done.signalAll();
+ }
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ @Override
+ protected <T> RunnableFuture<T> newTaskFor(Runnable task, T value) {
+ return new MyFutureTask<T>(task, value);
+ }
+
+ boolean isFlush(Runnable task) {
+ return (task == FLUSH) || ((task instanceof MyFutureTask<?>) && ((MyFutureTask<?>) task).task == FLUSH);
+ }
+
+ //
+ // Nested types
+ //
+
+ private static class MyFutureTask<V> extends FutureTask<V> {
+ final Runnable task;
+
+ MyFutureTask(Runnable task, V value) {
+ super(task, value);
+
+ this.task = task;
+ }
+ }
+}
diff --git a/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/TableUtils.java b/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/TableUtils.java
new file mode 100644
index 00000000000..bec37f68246
--- /dev/null
+++ b/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/TableUtils.java
@@ -0,0 +1,82 @@
+/*****************************************************************************
+ * Copyright (c) 2014 CEA LIST.
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Benoit Maggi (CEA LIST) benoit.maggi@cea.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.junit.utils;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.papyrus.infra.core.resource.AbstractBaseModel;
+import org.eclipse.papyrus.infra.core.resource.IModel;
+import org.eclipse.papyrus.infra.core.resource.ModelSet;
+import org.eclipse.papyrus.infra.gmfdiag.common.model.NotationModel;
+import org.eclipse.papyrus.infra.nattable.model.nattable.Table;
+import org.junit.Assert;
+
+/**
+ * Utility class for diagrams
+ */
+public class TableUtils {
+
+ /**
+ * Return the first table found with the specified name
+ * @param modelSet
+ * @param tableName
+ * @return
+ */
+ public static Table getNotationFirstTable(ModelSet modelSet, String tableName) {
+ IModel notationModel = modelSet.getModel(NotationModel.MODEL_ID);
+
+ AbstractBaseModel notationBaseModel = null;
+ if (notationModel instanceof AbstractBaseModel) {
+ notationBaseModel = (AbstractBaseModel) notationModel;
+ } else {
+ Assert.fail("notation model is not an abstract base model");
+ return null;
+ }
+ Assert.assertTrue("notation resource contains nothing", notationBaseModel.getResource().getContents().size() >= 1);
+ for (EObject eObject : notationBaseModel.getResource().getContents()) {
+ if (eObject instanceof Table && tableName.equals(((Table) eObject).getName())) {
+ return (Table) eObject;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Return the all tables found with the specified name
+ * @param modelSet
+ * @param tableName
+ * @return
+ */
+ public static Collection<Table> getAllNotationTable(ModelSet modelSet, String tableName) {
+ IModel notationModel = modelSet.getModel(NotationModel.MODEL_ID);
+ Collection<Table> tableList = new ArrayList<Table>();
+ AbstractBaseModel notationBaseModel = null;
+ if (notationModel instanceof AbstractBaseModel) {
+ notationBaseModel = (AbstractBaseModel) notationModel;
+ } else {
+ Assert.fail("notation model is not an abstract base model");
+ return null;
+ }
+ Assert.assertTrue("notation resource contains nothing", notationBaseModel.getResource().getContents().size() >= 1);
+ for (EObject eObject : notationBaseModel.getResource().getContents()) {
+ if (eObject instanceof Table && tableName.equals(((Table) eObject).getName())) {
+ tableList.add((Table) eObject);
+ }
+ }
+ return tableList;
+ }
+
+}
diff --git a/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/resources/ChangeCapture.java b/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/resources/ChangeCapture.java
new file mode 100644
index 00000000000..c8d99f3f537
--- /dev/null
+++ b/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/resources/ChangeCapture.java
@@ -0,0 +1,84 @@
+/*****************************************************************************
+ * Copyright (c) 2015 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.junit.utils.resources;
+
+import org.eclipse.emf.ecore.change.ChangeDescription;
+import org.eclipse.emf.transaction.NotificationFilter;
+import org.eclipse.emf.transaction.ResourceSetChangeEvent;
+import org.eclipse.emf.transaction.ResourceSetListenerImpl;
+import org.eclipse.emf.transaction.Transaction;
+import org.eclipse.emf.transaction.TransactionalEditingDomain;
+
+/**
+ * A listener that captures the {@link ChangeDescription}s of EMF {@link Transaction}s.
+ * it is {@link AutoCloseable} for convenience of ensuring that it is removed from the editing domain
+ * when no longer needed.
+ *
+ * @see #getChangeDescription()
+ */
+public class ChangeCapture extends ResourceSetListenerImpl implements AutoCloseable {
+
+ private TransactionalEditingDomain domain;
+
+ private ChangeDescription changeDescription;
+
+ /**
+ * Initializes me with my editing {@code domain}, to which I immediately begin listening for transactions
+ * (there is no need to add me as a listener explicitly). I only capture the changes of a transaction
+ * that actually makes non-read-only-compatible changes.
+ *
+ * @param domain
+ * my editing domain
+ */
+ public ChangeCapture(TransactionalEditingDomain domain) {
+ super(NotificationFilter.NOT_TOUCH);
+
+ this.domain = domain;
+ domain.addResourceSetListener(this);
+ }
+
+ @Override
+ public boolean isPostcommitOnly() {
+ return true;
+ }
+
+ @Override
+ public void resourceSetChanged(ResourceSetChangeEvent event) {
+ // Ignore unbatched (non-transactional) changes
+ if (event.getTransaction() != null) {
+ this.changeDescription = event.getTransaction().getChangeDescription();
+ }
+ }
+
+ /**
+ * Obtains the change description of the last committed transaction, if any.
+ *
+ * @return the last transaction's changes, or {@code null} if none
+ */
+ public ChangeDescription getChangeDescription() {
+ return changeDescription;
+ }
+
+ /**
+ * Detaches me from my editing domain.
+ */
+ @Override
+ public void close() {
+ if (domain != null) {
+ domain.removeResourceSetListener(this);
+ domain = null;
+ }
+ }
+
+}
diff --git a/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/resources/EcoreModel.java b/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/resources/EcoreModel.java
new file mode 100644
index 00000000000..bf36fb787a5
--- /dev/null
+++ b/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/resources/EcoreModel.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2014, 2016 CEA, Christian W. Damus, and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus (CEA) - Initial API and implementation
+ * Christian W. Damus - bug 485220
+ *
+ */
+package org.eclipse.papyrus.junit.utils.resources;
+
+import static org.junit.Assert.fail;
+
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.EPackage;
+import org.eclipse.emf.ecore.EcoreFactory;
+import org.eclipse.emf.ecore.EcorePackage;
+import org.eclipse.emf.ecore.util.EcoreUtil;
+import org.eclipse.papyrus.infra.core.resource.EMFLogicalModel;
+import org.eclipse.papyrus.infra.core.resource.IModel;
+import org.eclipse.papyrus.infra.core.resource.ModelSet;
+import org.eclipse.papyrus.infra.core.utils.TransactionHelper;
+
+
+/**
+ * An {@link IModel} implementation for Ecore models that test cases may add to their {@link ModelSet}s for cases where it is expedient to
+ * work with models that are not UML.
+ */
+public class EcoreModel extends EMFLogicalModel {
+
+ public EcoreModel() {
+ super();
+ }
+
+ @Override
+ public String getIdentifier() {
+ return "test.ecore";
+ }
+
+ @Override
+ public String getModelFileExtension() {
+ return "ecore";
+ }
+
+ public EPackage getRoot() {
+ return (EPackage) EcoreUtil.getObjectByType(getResource().getContents(), EcorePackage.Literals.EPACKAGE);
+ }
+
+ @Override
+ public void createModel(URI uri) {
+ resourceURI = uri.appendFileExtension(getModelFileExtension());
+ resource = getResourceSet().createResource(resourceURI, EcorePackage.eCONTENT_TYPE);
+
+ final EPackage ePackage = EcoreFactory.eINSTANCE.createEPackage();
+ ePackage.setName("package1");
+ ePackage.setNsPrefix("pkg1");
+ ePackage.setNsURI("http://www.eclipse.org/papyrus/test/fakemodel/ecore/package1");
+
+ try {
+ TransactionHelper.run(getModelManager().getTransactionalEditingDomain(), new Runnable() {
+
+ @Override
+ public void run() {
+ resource.getContents().add(ePackage);
+ }
+ });
+ } catch (Exception e) {
+ e.printStackTrace();
+ fail("Creation of Ecore model failed: " + e.getLocalizedMessage());
+ }
+ }
+
+ @Override
+ protected boolean isSupportedRoot(EObject object) {
+ return EcorePackage.Literals.EPACKAGE.isInstance(object);
+ }
+}
diff --git a/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/resources/WorkspaceModificationAssertion.java b/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/resources/WorkspaceModificationAssertion.java
new file mode 100644
index 00000000000..7bc8e6257e7
--- /dev/null
+++ b/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/resources/WorkspaceModificationAssertion.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2014 CEA and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus (CEA) - Initial API and implementation
+ *
+ */
+package org.eclipse.papyrus.junit.utils.resources;
+
+import static org.hamcrest.CoreMatchers.anything;
+import static org.hamcrest.CoreMatchers.hasItem;
+import static org.hamcrest.CoreMatchers.not;
+import static org.hamcrest.CoreMatchers.nullValue;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+import java.io.IOException;
+import java.util.Set;
+
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.IResourceChangeEvent;
+import org.eclipse.core.resources.IResourceChangeListener;
+import org.eclipse.core.resources.IResourceDelta;
+import org.eclipse.core.resources.IResourceDeltaVisitor;
+import org.eclipse.core.resources.IWorkspace;
+import org.eclipse.core.resources.IWorkspaceRunnable;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.papyrus.infra.core.resource.ModelSet;
+import org.eclipse.papyrus.junit.utils.rules.AbstractHouseKeeperRule;
+import org.hamcrest.CoreMatchers;
+
+import com.google.common.collect.Sets;
+
+/**
+ * A simple fixture for making assertions on the workspace resource changes made (or not) by {@link ModelSet}s upon saving.
+ */
+public class WorkspaceModificationAssertion implements IResourceChangeListener {
+
+ private final IWorkspace ws = ResourcesPlugin.getWorkspace();
+
+ private final Set<URI> requireChange = Sets.newHashSet();
+
+ private final Set<URI> requireNoChange = Sets.newHashSet();
+
+ private final Set<URI> changed = Sets.newHashSet();
+
+ private CoreException exception;
+
+ public WorkspaceModificationAssertion(AbstractHouseKeeperRule houseKeeper) {
+ ws.addResourceChangeListener(this);
+ houseKeeper.cleanUpLater(this);
+ }
+
+ public void dispose() {
+ ws.removeResourceChangeListener(this);
+ reset();
+ }
+
+ public void requireChange(URI uri) {
+ assertThat("conflicting change requirement for " + uri, requireNoChange, not(hasItem(uri)));
+ requireChange.add(uri);
+ }
+
+ public void requireNoChange(URI uri) {
+ assertThat("conflicting change requirement for " + uri, requireChange, not(hasItem(uri)));
+ requireNoChange.add(uri);
+ }
+
+ public void resourceChanged(IResourceChangeEvent event) {
+ try {
+ event.getDelta().accept(new IResourceDeltaVisitor() {
+
+ public boolean visit(IResourceDelta delta) throws CoreException {
+ if(delta.getResource().getType() == IResource.FILE) {
+ changed.add(URI.createPlatformResourceURI(delta.getFullPath().toString(), true));
+ }
+ return true;
+ }
+ });
+ } catch (CoreException e) {
+ e.printStackTrace();
+ exception = e;
+ }
+ }
+
+ public void reset() {
+ requireChange.clear();
+ requireNoChange.clear();
+ changed.clear();
+ exception = null;
+ }
+
+ public void save(final ModelSet modelSet) {
+ try {
+ try {
+ ws.run(new IWorkspaceRunnable() {
+
+ public void run(IProgressMonitor monitor) throws CoreException {
+ try {
+ modelSet.save(monitor);
+ } catch (IOException e) {
+ throw new CoreException(new Status(IStatus.ERROR, "org.eclipse.papyrus.junit.utils", "Save failed.", e));
+ }
+ }
+ }, new NullProgressMonitor());
+ } catch (CoreException e) {
+ e.printStackTrace();
+ exception = e;
+ }
+
+ assertThat("Resource(s) saved that should not have been", Sets.intersection(requireNoChange, changed), not(CoreMatchers.<URI> hasItem(anything())));
+ assertThat("Resource(s) not saved that should have been", Sets.difference(requireChange, changed), not(CoreMatchers.<URI> hasItem(anything())));
+ assertThat("Save assertion failed with an exception", exception, nullValue());
+ } finally {
+ reset();
+ }
+ }
+}
diff --git a/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/AbstractHouseKeeperRule.java b/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/AbstractHouseKeeperRule.java
new file mode 100644
index 00000000000..13d90e49f78
--- /dev/null
+++ b/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/AbstractHouseKeeperRule.java
@@ -0,0 +1,723 @@
+/*
+ * Copyright (c) 2014, 2015 CEA, Christian W. Damus, and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus (CEA) - Initial API and implementation
+ * Christian W. Damus - bug 476683
+ *
+ */
+package org.eclipse.papyrus.junit.utils.rules;
+
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.notNullValue;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.fail;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.eclipse.core.commands.operations.IUndoableOperation;
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.emf.common.command.Command;
+import org.eclipse.emf.common.util.WrappedException;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.emf.ecore.resource.ResourceSet;
+import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
+import org.eclipse.emf.edit.domain.EditingDomain;
+import org.eclipse.emf.transaction.TransactionalEditingDomain;
+import org.eclipse.gef.EditPart;
+import org.eclipse.gmf.runtime.common.core.command.ICommand;
+import org.eclipse.papyrus.infra.core.resource.ModelSet;
+import org.eclipse.papyrus.infra.emf.utils.EMFHelper;
+import org.eclipse.papyrus.infra.ui.editor.IMultiDiagramEditor;
+import org.eclipse.papyrus.junit.utils.Duck;
+import org.eclipse.papyrus.junit.utils.EditorUtils;
+import org.eclipse.papyrus.junit.utils.PapyrusProjectUtils;
+import org.eclipse.papyrus.junit.utils.ProjectUtils;
+import org.eclipse.papyrus.junit.utils.rules.HouseKeeper.Disposer;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IWorkbenchPage;
+import org.osgi.framework.FrameworkUtil;
+
+import com.google.common.base.Function;
+import com.google.common.base.Functions;
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.CacheLoader;
+import com.google.common.cache.LoadingCache;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+
+public abstract class AbstractHouseKeeperRule {
+
+ private static final LoadingCache<Class<?>, Field[]> leakProneInstanceFields = CacheBuilder.newBuilder().maximumSize(128).build(fieldCacheLoader(false));
+
+ private static final LoadingCache<Class<?>, Field[]> leakProneStaticFields = CacheBuilder.newBuilder().maximumSize(128).build(fieldCacheLoader(true));
+
+ private static final Function<Object, Disposer<Object>> DISPOSER_FUNCTION;
+
+ Object test;
+
+ String testName;
+
+ private List<Runnable> cleanUpActions;
+
+ static {
+ final Map<Class<?>, Function<Object, Disposer<?>>> disposers = Maps.newLinkedHashMap();
+
+ ResourceSetDisposer.register(disposers);
+ TransactionalEditingDomainDisposer.register(disposers);
+ WorkspaceResourceDisposer.register(disposers);
+ EditorDisposer.register(disposers);
+ CollectionDisposer.register(disposers);
+ MapDisposer.register(disposers);
+
+ // This one must be last because it matches any object
+ ReflectiveDisposer.register(disposers);
+
+ DISPOSER_FUNCTION = new Function<Object, Disposer<Object>>() {
+
+ private final Function<Object, Disposer<?>> nullFunction = Functions.constant(null);
+
+ @Override
+ public Disposer<Object> apply(Object input) {
+ Function<Object, Disposer<?>> resultFunction = nullFunction;
+
+ for (Map.Entry<Class<?>, Function<Object, Disposer<?>>> next : disposers.entrySet()) {
+ if (next.getKey().isInstance(input)) {
+ resultFunction = next.getValue();
+ break;
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ Disposer<Object> result = (Disposer<Object>) resultFunction.apply(input);
+ return result;
+ }
+ };
+ }
+
+ AbstractHouseKeeperRule() {
+ super();
+ }
+
+ /**
+ * Obtains the test name (may as well provide it, since we are a test rule).
+ *
+ * @return the current test name
+ */
+ public final String getTestName() {
+ return testName;
+ }
+
+ /**
+ * Adds an {@code object} to clean up later, with a {@code disposer} method that is invoked reflectively to do the cleaning up.
+ *
+ * @param object
+ * an object to dispose after the test has completed
+ * @param disposer
+ * the disposal method name
+ * @param arg
+ * arguments (if any) to the {@code disposer} method
+ *
+ * @return the {@code object}, for convenience
+ */
+ public <T> T cleanUpLater(T object, String disposer, Object... arg) {
+ assertThat("No such disposal method", new Duck(object).understands(disposer, arg), is(true));
+ return cleanUpLater(object, new ReflectiveDisposer(disposer, arg));
+ }
+
+ /**
+ * Adds an {@code object} to clean up later, with a {@code disposer} that does the cleaning up.
+ *
+ * @param object
+ * an object to dispose after the test has completed
+ * @param disposer
+ * the disposal behaviour
+ *
+ * @return the {@code object}, for convenience
+ */
+ public <T> T cleanUpLater(T object, Disposer<? super T> disposer) {
+ if (cleanUpActions == null) {
+ cleanUpActions = Lists.newLinkedList();
+ }
+
+ // Clean up in reverse order to best manage dependencies between cleaned-up objects
+ cleanUpActions.add(0, new CleanUpAction(object, disposer));
+ return object;
+ }
+
+ /**
+ * Adds an {@code object} to clean up later, using the appropriate built-in disposer.
+ * Fails if the {@code object} does not have a corresponding built-in disposer.
+ *
+ * @param object
+ * an object to dispose after the test has completed
+ *
+ * @return the {@code object}, for convenience
+ */
+ public <T> T cleanUpLater(T object) {
+ @SuppressWarnings("unchecked")
+ Disposer<T> disposer = (Disposer<T>) DISPOSER_FUNCTION.apply(object);
+ assertThat("No built-in disposer available", disposer, notNullValue());
+ return cleanUpLater(object, disposer);
+ }
+
+ /**
+ * Obtains a new resource set that will be disposed of automatically after the test completes.
+ *
+ * @return the new resource set
+ */
+ public ResourceSet createResourceSet() {
+ return cleanUpLater(new ResourceSetImpl(), ResourceSetDisposer.INSTANCE);
+ }
+
+ /**
+ * Creates a new editing domain that will be disposed of automatically after the test completes.
+ *
+ * @return the editing domain
+ */
+ public TransactionalEditingDomain createSimpleEditingDomain() {
+ return createSimpleEditingDomain(null);
+ }
+
+ /**
+ * Creates a new editing domain that will be disposed of automatically after the test completes.
+ *
+ * @param resourceSet
+ * the resource set on which to create the editing domain (or {@code null} to create a default one)
+ *
+ * @return the editing domain
+ */
+ public TransactionalEditingDomain createSimpleEditingDomain(ResourceSet resourceSet) {
+ if (resourceSet == null) {
+ resourceSet = createResourceSet();
+ }
+
+ return cleanUpLater(TransactionalEditingDomain.Factory.INSTANCE.createEditingDomain(resourceSet), TransactionalEditingDomainDisposer.INSTANCE);
+ }
+
+ /**
+ * Creates a project that will be disposed of automatically after the test completes.
+ *
+ * @param name
+ * the name of the project
+ *
+ * @return the project
+ */
+ public IProject createProject(String name) {
+ try {
+ return cleanUpLater(ProjectUtils.createProject(name), WorkspaceResourceDisposer.INSTANCE);
+ } catch (Exception e) {
+ fail(e.getMessage());
+ return null; // Unreachable
+ }
+ }
+
+ /**
+ * Creates a file in the specified {@code project} with the given {@code fileName}, initialized by copying a
+ * template resource from the test class's originating bundle.
+ *
+ * @param project
+ * the test project in which to create the file
+ * @param fileName
+ * the name of the file to create
+ * @param templatePath
+ * the path in the test bundle of the template file to copy
+ *
+ * @return the new file
+ */
+ public IFile createFile(IProject project, String fileName, String templatePath) {
+ Class<?> testClass = (test instanceof Class<?>) ? (Class<?>) test : test.getClass();
+
+ try {
+ return cleanUpLater(PapyrusProjectUtils.copyIFile(templatePath, FrameworkUtil.getBundle(testClass), project, fileName), //
+ WorkspaceResourceDisposer.INSTANCE);
+ } catch (Exception e) {
+ fail(e.getMessage());
+ return null; // Unreachable
+ }
+ }
+
+ /**
+ * Opens the default editor on the given {@code file} and ensures that it will be closed after the test terminates.
+ *
+ * @param file
+ * the file to open in its editor
+ *
+ * @return the editor
+ */
+ public IEditorPart openEditor(final IFile file) {
+ final IEditorPart[] result = { null };
+
+ Display.getDefault().syncExec(new Runnable() {
+
+ @Override
+ public void run() {
+ try {
+ result[0] = cleanUpLater(EditorUtils.openEditor(file), EditorDisposer.INSTANCE);
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+ }
+ });
+
+ return result[0];
+ }
+
+ /**
+ * Opens the Papyrus editor on the given {@code file} and ensures that it will be closed after the test terminates.
+ *
+ * @param file
+ * the file to open in the Papyrus editor
+ *
+ * @return the editor
+ */
+ public IMultiDiagramEditor openPapyrusEditor(final IFile file) throws Exception {
+ final IMultiDiagramEditor[] result = { null };
+ final AtomicReference<Exception> syncExecException = new AtomicReference<Exception>();
+
+ Display.getDefault().syncExec(new Runnable() {
+
+ @Override
+ public void run() {
+ try {
+ result[0] = cleanUpLater(EditorUtils.openPapyrusEditor(file), EditorDisposer.INSTANCE);
+ } catch (Exception ex) {
+ syncExecException.set(ex);
+ }
+ }
+ });
+
+ if (syncExecException.get() != null) {
+ throw syncExecException.get();
+ }
+
+ return result[0];
+ }
+
+ /**
+ * Obtains the value of the named field of the test instance and ensures that it will be automatically cleared after the test completes.
+ *
+ * @param fieldName
+ * the field to access now and clear later
+ *
+ * @return the value of the field
+ *
+ * @deprecated Use the {@link CleanUp @CleanUp} annotation on the field and access it directly.
+ */
+ @Deprecated
+ public <T> T getField(String fieldName) {
+ try {
+ Field field = field(fieldName);
+
+ @SuppressWarnings("unchecked")
+ T result = (T) field.get(test);
+ cleanUpLater(field, new FieldDisposer());
+
+ return result;
+ } catch (Exception e) {
+ e.printStackTrace();
+ fail(String.format("Could not access field %s of test instance.", fieldName));
+ return null; // Unreachable
+ }
+ }
+
+ Field field(String fieldName) {
+ Field result = null;
+
+ for (Class<?> next = getTestClass(); (result == null) && (next != null) && (next != Object.class); next = next.getSuperclass()) {
+ try {
+ result = next.getDeclaredField(fieldName);
+ if (result != null) {
+ result.setAccessible(true);
+ }
+ } catch (Exception e) {
+ // Keep looking
+ result = null;
+ }
+ }
+
+ assertThat(String.format("Could not access field %s of test instance.", fieldName), result, notNullValue());
+ assertThat(String.format("Field is not %sstatic", isStatic() ? "" : "non-"), Modifier.isStatic(result.getModifiers()), is(isStatic()));
+
+ return result;
+ }
+
+ /**
+ * Sets the value of the named field of the test instance and ensures that it will be automatically cleared after the test completes.
+ *
+ * @param fieldName
+ * the field to access now and clear later
+ * @param value
+ * the value to set
+ *
+ * @return the new value of the field
+ *
+ * @deprecated Use the {@link CleanUp @CleanUp} annotation on the field and access it directly.
+ */
+ @Deprecated
+ public <T> T setField(String fieldName, T value) {
+ try {
+ Field field = field(fieldName);
+ field.set(test, value);
+ cleanUpLater(field, new FieldDisposer());
+ } catch (Exception e) {
+ e.printStackTrace();
+ fail(String.format("Could not access field %s of test instance.", fieldName));
+ }
+
+ return value;
+ }
+
+ abstract boolean isStatic();
+
+ abstract Class<?> getTestClass();
+
+
+ void registerAutoCleanups() {
+ try {
+ final boolean staticFields = isStatic();
+
+ // Get all inherited fields, too
+ for (Class<?> next = getTestClass(); (next != null) && (next != Object.class); next = next.getSuperclass()) {
+ for (Field field : next.getDeclaredFields()) {
+ CleanUp cleanUp = field.getAnnotation(CleanUp.class);
+
+ if ((cleanUp != null) && (Modifier.isStatic(field.getModifiers()) == staticFields) && !Modifier.isFinal(field.getModifiers())) {
+ try {
+ field.setAccessible(true);
+
+ Class<? extends Disposer<?>> disposerClass = cleanUp.value();
+ if (disposerClass == FieldDisposer.class) {
+ // Default case
+ cleanUpLater(field, new FieldDisposer());
+ } else {
+ // Custom case
+
+ // Handle inner classes
+ Constructor<? extends Disposer<?>> ctor;
+ Object[] args;
+ if (disposerClass.getDeclaringClass() != null && ((disposerClass.getModifiers() & Modifier.STATIC) == 0)) {
+ ctor = disposerClass.getDeclaredConstructor(disposerClass.getDeclaringClass());
+ args = new Object[] { this };
+ } else {
+ ctor = disposerClass.getConstructor();
+ args = new Object[0];
+ }
+ ctor.setAccessible(true);
+
+ @SuppressWarnings("unchecked")
+ Disposer<Object> disposer = (Disposer<Object>) ctor.newInstance(args);
+ cleanUpLater(field.get(test), disposer);
+ }
+ } catch (Exception e) {
+ // Can't make it accessible? Then it's of no use.
+ // Likewise any problem in creating the disposer
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+ } catch (Exception e) {
+ // We tried our best. Don't propagate as a test failure because the test didn't ask for this
+ }
+ }
+
+ void cleanUp() throws Exception {
+ cleanUpLeakProneFields();
+
+ if (cleanUpActions != null) {
+ Exception toThrow = null;
+
+ for (Runnable next : cleanUpActions) {
+ try {
+ next.run();
+ } catch (Exception e) {
+ // Unwrap
+ if (e instanceof WrappedException) {
+ e = ((WrappedException) e).exception();
+ }
+
+ e.printStackTrace();
+ if (toThrow == null) {
+ toThrow = e;
+ }
+ }
+ }
+
+ cleanUpActions = null;
+
+ if (toThrow != null) {
+ throw toThrow;
+ }
+ }
+ }
+
+ /**
+ * Automatically clear all fields of the test instance that are of some {@link EObject} type.
+ */
+ private void cleanUpLeakProneFields() {
+ try {
+ final Field[] fields = isStatic() ? leakProneStaticFields.get(getTestClass()) : leakProneInstanceFields.get(getTestClass());
+
+ for (int i = 0; i < fields.length; i++) {
+ fields[i].set(test, null);
+ }
+ } catch (Exception e) {
+ // We tried our best. Don't propagate as a test failure because the test didn't ask for this
+ }
+ }
+
+ private static CacheLoader<Class<?>, Field[]> fieldCacheLoader(final boolean staticFields) {
+ return new CacheLoader<Class<?>, Field[]>() {
+
+ @Override
+ public Field[] load(Class<?> key) {
+ List<Field> result = Lists.newArrayList();
+
+ // Get all inherited fields, too
+ for (Class<?> next = key; (next != null) && (next != Object.class); next = next.getSuperclass()) {
+ for (Field field : next.getDeclaredFields()) {
+ if ((Modifier.isStatic(field.getModifiers()) == staticFields) && !Modifier.isFinal(field.getModifiers()) && isLeakProne(field)) {
+ try {
+ field.setAccessible(true);
+ result.add(field);
+ } catch (Exception e) {
+ // Can't make it accessible? Then it's of no use
+ }
+ }
+ }
+ }
+
+ return Iterables.toArray(result, Field.class);
+ }
+ };
+ }
+
+ private static boolean isLeakProne(Field field) {
+ Class<?> type = field.getType();
+ return EObject.class.isAssignableFrom(type) || Resource.class.isAssignableFrom(type) //
+ || ResourceSet.class.isAssignableFrom(type) || EditingDomain.class.isAssignableFrom(type) //
+ || EditPart.class.isAssignableFrom(type) //
+ || Command.class.isAssignableFrom(type) || org.eclipse.gef.commands.Command.class.isAssignableFrom(type) //
+ || IUndoableOperation.class.isAssignableFrom(type) || ICommand.class.isAssignableFrom(type);
+ }
+
+ //
+ // Nested types
+ //
+
+ /**
+ * Annotates fields for automatic clean-up.
+ */
+ @Retention(RUNTIME)
+ @Target(FIELD)
+ public @interface CleanUp {
+ /**
+ * Optionally specifies a disposer class to instantiate to clean
+ * up the annotated field. By default, the field is simply
+ * cleared to {@code null}.
+ */
+ Class<? extends Disposer<?>>value() default FieldDisposer.class;
+ }
+
+ private static final class CleanUpAction implements Runnable {
+
+ private final Object target;
+
+ private final Disposer<Object> disposer;
+
+ @SuppressWarnings("unchecked")
+ <T> CleanUpAction(T object, Disposer<? super T> disposer) {
+ this.target = object;
+ this.disposer = (Disposer<Object>) disposer;
+ }
+
+ @Override
+ public void run() {
+ try {
+ disposer.dispose(target);
+ } catch (Exception e) {
+ throw new WrappedException(e);
+ }
+ }
+ }
+
+ private static final class ResourceSetDisposer implements Disposer<ResourceSet> {
+
+ static final ResourceSetDisposer INSTANCE = new ResourceSetDisposer();
+
+ private ResourceSetDisposer() {
+ super();
+ }
+
+ static void register(Map<Class<?>, Function<Object, Disposer<?>>> disposers) {
+ disposers.put(ResourceSet.class, Functions.<Disposer<?>> constant(INSTANCE));
+ }
+
+ @Override
+ public void dispose(ResourceSet object) {
+ if (object instanceof ModelSet) {
+ ((ModelSet) object).unload();
+ }
+
+ // No harm in hitting a ModelSet again
+ EMFHelper.unload(object);
+ }
+ }
+
+ private static final class TransactionalEditingDomainDisposer implements Disposer<TransactionalEditingDomain> {
+
+ static final TransactionalEditingDomainDisposer INSTANCE = new TransactionalEditingDomainDisposer();
+
+ private TransactionalEditingDomainDisposer() {
+ super();
+ }
+
+ static void register(Map<Class<?>, Function<Object, Disposer<?>>> disposers) {
+ disposers.put(TransactionalEditingDomain.class, Functions.<Disposer<?>> constant(INSTANCE));
+ }
+
+ @Override
+ public void dispose(TransactionalEditingDomain object) {
+ object.dispose();
+ }
+ }
+
+ private final class FieldDisposer implements Disposer<Field> {
+
+ @Override
+ public void dispose(Field object) throws Exception {
+ object.set(test, null);
+ }
+ }
+
+ private static final class WorkspaceResourceDisposer implements Disposer<IResource> {
+
+ static final WorkspaceResourceDisposer INSTANCE = new WorkspaceResourceDisposer();
+
+ static void register(Map<Class<?>, Function<Object, Disposer<?>>> disposers) {
+ disposers.put(IResource.class, Functions.<Disposer<?>> constant(INSTANCE));
+ }
+
+ @Override
+ public void dispose(IResource object) throws Exception {
+ switch (object.getType()) {
+ case IResource.PROJECT:
+ case IResource.FOLDER:
+ case IResource.FILE:
+ object.delete(true, null);
+ break;
+ default:
+ // Delete the workspace? No, I don't think so
+ fail("Cannot delete resource " + object);
+ break;
+ }
+ }
+ }
+
+ private static final class EditorDisposer implements Disposer<IEditorPart> {
+
+ static final EditorDisposer INSTANCE = new EditorDisposer();
+
+ static void register(Map<Class<?>, Function<Object, Disposer<?>>> disposers) {
+ disposers.put(IEditorPart.class, Functions.<Disposer<?>> constant(INSTANCE));
+ }
+
+ @Override
+ public void dispose(final IEditorPart object) throws Exception {
+ Display.getDefault().syncExec(new Runnable() {
+
+ @Override
+ public void run() {
+ IWorkbenchPage page = (object.getSite() == null) ? null : object.getSite().getPage();
+ if (page != null) {
+ try {
+ page.closeEditor(object, false);
+ } catch (Exception e) {
+ // Best effort
+ }
+ }
+ }
+ });
+ }
+ }
+
+ private static final class CollectionDisposer implements Disposer<Collection<?>> {
+
+ static final CollectionDisposer INSTANCE = new CollectionDisposer();
+
+ static void register(Map<Class<?>, Function<Object, Disposer<?>>> disposers) {
+ disposers.put(Collection.class, Functions.<Disposer<?>> constant(INSTANCE));
+ }
+
+ @Override
+ public void dispose(final Collection<?> object) throws Exception {
+ object.clear();
+ }
+ }
+
+ private static final class MapDisposer implements Disposer<Map<?, ?>> {
+
+ static final MapDisposer INSTANCE = new MapDisposer();
+
+ static void register(Map<Class<?>, Function<Object, Disposer<?>>> disposers) {
+ disposers.put(Map.class, Functions.<Disposer<?>> constant(INSTANCE));
+ }
+
+ @Override
+ public void dispose(final Map<?, ?> object) throws Exception {
+ object.clear();
+ }
+ }
+
+ private static final class ReflectiveDisposer implements Disposer<Object> {
+
+ static final ReflectiveDisposer INSTANCE = new ReflectiveDisposer("dispose"); //$NON-NLS-1$
+
+ private final String disposeMethod;
+
+ private final Object[] arguments;
+
+ ReflectiveDisposer(String methodName, Object... arguments) {
+ this.disposeMethod = methodName;
+ this.arguments = arguments;
+ }
+
+ static void register(Map<Class<?>, Function<Object, Disposer<?>>> disposers) {
+ disposers.put(Object.class, new Function<Object, Disposer<?>>() {
+
+ @Override
+ public Disposer<?> apply(Object input) {
+ Duck duck = new Duck(input);
+
+ return duck.understands(INSTANCE.disposeMethod, INSTANCE.arguments) ? INSTANCE : null;
+ }
+ });
+ }
+
+ @Override
+ public void dispose(Object object) throws Exception {
+ new Duck(object).quack(disposeMethod, arguments);
+ }
+ }
+}
diff --git a/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/AbstractModelFixture.java b/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/AbstractModelFixture.java
new file mode 100755
index 00000000000..f220d1d9088
--- /dev/null
+++ b/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/AbstractModelFixture.java
@@ -0,0 +1,649 @@
+/*
+ * Copyright (c) 2014, 2016 CEA, Christian W. Damus, and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus (CEA) - Initial API and implementation
+ * Christian W. Damus - bugs 399859, 451230, 458685, 469188, 485220, 496299
+ *
+ */
+package org.eclipse.papyrus.junit.utils.rules;
+
+import static org.hamcrest.CoreMatchers.instanceOf;
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.notNullValue;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.fail;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.lang.annotation.Annotation;
+import java.net.URL;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Queue;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.stream.Stream;
+
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.commands.operations.IUndoableOperation;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.emf.common.command.Command;
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.emf.ecore.resource.ResourceSet;
+import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
+import org.eclipse.emf.ecore.util.EcoreUtil;
+import org.eclipse.emf.ecore.xmi.XMLResource;
+import org.eclipse.emf.ecore.xml.type.AnyType;
+import org.eclipse.emf.edit.domain.EditingDomain;
+import org.eclipse.emf.transaction.TransactionalEditingDomain;
+import org.eclipse.emf.workspace.IWorkspaceCommandStack;
+import org.eclipse.papyrus.infra.core.resource.ModelMultiException;
+import org.eclipse.papyrus.infra.core.resource.ModelSet;
+import org.eclipse.papyrus.infra.core.resource.sasheditor.DiModel;
+import org.eclipse.papyrus.infra.emf.utils.EMFHelper;
+import org.eclipse.papyrus.infra.gmfdiag.common.model.NotationModel;
+import org.eclipse.papyrus.infra.tools.util.TypeUtils;
+import org.eclipse.papyrus.junit.utils.JUnitUtils;
+import org.eclipse.papyrus.uml.tools.model.UmlModel;
+import org.eclipse.uml2.uml.Package;
+import org.eclipse.uml2.uml.Profile;
+import org.eclipse.uml2.uml.UMLPackage;
+import org.junit.Rule;
+import org.junit.rules.TestWatcher;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.FrameworkUtil;
+
+import com.google.common.base.Charsets;
+import com.google.common.base.Predicates;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+import com.google.common.io.ByteSource;
+import com.google.common.io.ByteStreams;
+import com.google.common.io.CharStreams;
+import com.google.common.io.Resources;
+
+
+/**
+ * Abstract superclass for JUnit test fixture rules that provide:
+ * <ul>
+ * <li>an editing domain of some kind (subclasses must create it)</li>
+ * <li>a test project in the workspace, exposed via a nested {@link ProjectFixture} rule</li>
+ * <li>a test {@link Package} loaded from a resource in the plug-in and saved as <tt>model.uml</tt> in the test project. This model is specified using an annotation on the test, as described below</li>
+ * </ul>
+ * The test model template to load into the editing domain and project must be specified by one of the following annotations:
+ * <ul>
+ * <li>{@link JavaResource @JavaResource}: specifies the path to a resource to be loaded from the test class's classpath, using the {@link Class#getResource(String)} API</li>
+ * <li>{@link PluginResource @PluginResource}: specifies a path relative to the root of the OSGi bundle containing the test class, to be loaded via the {@link Bundle#getEntry(String)} API</li>
+ * </ul>
+ * The resource annotation may be specified either on the test method, in which case it applies to that test case, or on the test
+ * class, in which case it applies to all test methods in the class that do not have a resource annotation of their own (method
+ * annotations take precedence over the class annotation).
+ */
+public abstract class AbstractModelFixture<T extends EditingDomain> extends TestWatcher {
+
+ private final ProjectFixture project = new ProjectFixture();
+
+ private T domain;
+
+ private EObject root;
+
+ private Package model;
+
+ private Class<?> testClass;
+
+ private Iterable<URI> initialResourceURIs;
+
+ public AbstractModelFixture() {
+ super();
+ }
+
+ @Override
+ public Statement apply(Statement base, Description description) {
+ testClass = JUnitUtils.getTestClass(description);
+
+ // Wrap myself in the project rule so that the project exists when I start
+ Statement result = super.apply(base, description);
+ result = project.apply(result, description);
+ return result;
+ }
+
+ /**
+ * Obtains the nested project fixture rule. If stored in a field of the test class, it must not be annotated as a {@link Rule @Rule} because that
+ * would result in double initialization of the rule.
+ *
+ * @return the nested project fixture
+ */
+ public ProjectFixture getProject() {
+ return project;
+ }
+
+ public T getEditingDomain() {
+ return domain;
+ }
+
+ public void execute(Command command) {
+ assertThat("Command not executable", command.canExecute(), is(true));
+ getEditingDomain().getCommandStack().execute(command);
+ }
+
+ public IStatus execute(IUndoableOperation operation, IProgressMonitor monitor, IAdaptable info) {
+ assertThat("Operation not executable", operation.canExecute(), is(true));
+ assertThat("No operation history available", getEditingDomain().getCommandStack(), instanceOf(IWorkspaceCommandStack.class));
+
+ try {
+ IWorkspaceCommandStack stack = (IWorkspaceCommandStack) getEditingDomain().getCommandStack();
+ operation.addContext(stack.getDefaultUndoContext());
+ return stack.getOperationHistory().execute(operation, monitor, info);
+ } catch (ExecutionException e) {
+ e.printStackTrace();
+ fail("Command execution failed: " + e.getLocalizedMessage());
+ return null; // Unreachable
+ }
+ }
+
+ public IStatus execute(IUndoableOperation operation) {
+ return execute(operation, null, null);
+ }
+
+ public boolean canUndo() {
+ return getEditingDomain().getCommandStack().canUndo();
+ }
+
+ public void undo() {
+ assertThat("Cannot undo", canUndo(), is(true));
+ getEditingDomain().getCommandStack().undo();
+ }
+
+ public boolean canRedo() {
+ return getEditingDomain().getCommandStack().canRedo();
+ }
+
+ public void redo() {
+ assertThat("Cannot redo", canRedo(), is(true));
+ getEditingDomain().getCommandStack().redo();
+ }
+
+ public ResourceSet getResourceSet() {
+ EditingDomain domain = getEditingDomain();
+ return (domain == null) ? null : domain.getResourceSet();
+ }
+
+ /**
+ * Obtains the first root of the main test resource.
+ *
+ * @return the first test resource root
+ */
+ public EObject getRoot() {
+ return root;
+ }
+
+ /**
+ * Obtains the test model, which is resident in the <tt>model.uml</tt> file in the test project (as indicated by its {@linkplain #getModelResourceURI() URI}).
+ *
+ * @return the test model
+ */
+ public Package getModel() {
+ return model;
+ }
+
+ public Resource getModelResource() {
+ return getRoot().eResource();
+ }
+
+ public URI getModelResourceURI() {
+ return getModelResource().getURI();
+ }
+
+ public URI getModelURI() {
+ return EcoreUtil.getURI(getRoot());
+ }
+
+ protected abstract T createEditingDomain();
+
+ @Override
+ protected void starting(Description description) {
+ domain = createEditingDomain();
+
+ Resource main = Iterables.getFirst(initModelResources(description), null);
+ assertThat("No main UML resource in model fixture", main, notNullValue());
+
+ root = main.getContents().get(0);
+ if (root instanceof Package) {
+ model = (Package) root;
+ }
+
+ // We have finished initializing
+ initialResourceURIs = null;
+
+ didLoadResourceSet();
+ }
+
+ protected void didLoadResourceSet() {
+ // Pass
+ }
+
+ protected Iterable<Resource> initModelResources(Description description) {
+ List<Resource> result;
+
+ // Don't initialize the resources more than once (subclasses such as PapyrusEditorFixture can repeat this)
+ if (initialResourceURIs == null) {
+ Annotation resourceAnnotation = getResourceAnnotation(description);
+ ResourceKind kind = ResourceKind.getResourceKind(resourceAnnotation);
+
+ final String[] paths = kind.getResourcePaths(resourceAnnotation);
+ result = Lists.newArrayListWithCapacity(paths.length);
+
+ for (String path : paths) {
+ // Ensure that the bundle ID prefix, if any, is taken as the "device"
+ result.add(initModelResource(Path.forWindows(path), kind));
+ }
+
+ List<URI> uris = Lists.newArrayListWithCapacity(result.size());
+ for (Resource next : result) {
+ uris.add(next.getURI());
+ }
+ initialResourceURIs = uris;
+
+ // Ensure that the ModelSet's IModels are started
+ ModelSet modelSet = TypeUtils.as(getResourceSet(), ModelSet.class);
+ if (modelSet != null) {
+ // It doesn't matter that the resource is already loaded
+ try {
+ modelSet.loadModels(result.get(0).getURI());
+ } catch (ModelMultiException e) {
+ // Continue with the test as well as we can
+ e.printStackTrace();
+ }
+ }
+ } else {
+ ResourceSet rset = getResourceSet();
+ boolean bootstrapResourceSet = rset == null;
+ if (bootstrapResourceSet) {
+ // Bootstrap the initialization of the test model with a plain resource set
+ rset = new ResourceSetImpl();
+ rset.getLoadOptions().put(XMLResource.OPTION_RECORD_UNKNOWN_FEATURE, true);
+ rset.getLoadOptions().put(XMLResource.OPTION_LAX_FEATURE_PROCESSING, true);
+ }
+ result = Lists.newArrayList();
+ try {
+ for (URI next : initialResourceURIs) {
+ result.add(rset.getResource(next, true));
+ }
+ } finally {
+ if (bootstrapResourceSet) {
+ EMFHelper.unload(rset);
+ }
+ }
+ }
+
+ return result;
+ }
+
+ private Resource initModelResource(IPath resourcePath, ResourceKind kind) {
+ String targetResourceName = "model";
+ if (isDIModel(resourcePath)) {
+ // We will be initializing all three resources, and they have cross-references, so must not change
+ // resource name
+ targetResourceName = resourcePath.removeFileExtension().lastSegment();
+ }
+
+ return initModelResource(targetResourceName, kind, resourcePath.toString());
+ }
+
+ protected boolean isDIModel(IPath path) {
+ String fileExtension = path.getFileExtension();
+ return DiModel.DI_FILE_EXTENSION.equals(fileExtension);
+ }
+
+ protected Resource initModelResource(String targetPath, ResourceKind resourceKind, String resourcePath) {
+ Resource result = null;
+
+ ResourceSet resourceSet = getResourceSet();
+ final boolean bootstrapResourceSet = resourceSet == null;
+ if (bootstrapResourceSet) {
+ // Bootstrap the initialization of the test model with a plain resource set
+ resourceSet = new ResourceSetImpl();
+ resourceSet.getLoadOptions().put(XMLResource.OPTION_RECORD_UNKNOWN_FEATURE, true);
+ resourceSet.getLoadOptions().put(XMLResource.OPTION_LAX_FEATURE_PROCESSING, true);
+ }
+
+ Set<Resource> toUnload = Sets.newHashSet();
+ try {
+ // Ensure that the bundle ID prefix, if any, is taken as the "device"
+ IPath resourceIPath = Path.forWindows(resourcePath);
+ if (isDIModel(resourceIPath)) {
+ // Try to initialize the entire collection of files
+ resourceIPath = resourceIPath.removeFileExtension();
+
+ Map<IPath, Boolean> manifest = loadManifest(resourceKind, resourceIPath);
+ for (Map.Entry<IPath, Boolean> next : manifest.entrySet()) {
+ Resource resource = doInitModelResource(resourceSet, targetPath, resourceKind, next.getKey());
+
+ if ((result == null) && UmlModel.UML_FILE_EXTENSION.equals(next.getKey().getFileExtension())) {
+ // We should always have this one, at least, and it's the one we most care about
+ result = resource;
+ }
+
+ if (!next.getValue()) {
+ // Unload this resource
+ toUnload.add(resource);
+ }
+ }
+ } else {
+ result = doInitModelResource(resourceSet, targetPath, resourceKind, resourceIPath);
+ }
+
+ if (result == null) {
+ fail("No UML resource in test model");
+ }
+
+ // Look for any other dependencies (libraries, profiles, etc.) that also need to be copied
+ Queue<Resource> dependents = new LinkedList<>();
+ Set<Resource> scanned = new HashSet<>();
+ dependents.add(result);
+ boolean loadedProfiles = false;
+ for (Resource dependent = dependents.poll(); dependent != null; dependent = dependents.poll()) {
+ if (scanned.add(dependent)) {
+ URI baseURI = result.getURI().trimSegments(1);
+ if (!baseURI.isPrefix()) {
+ baseURI = baseURI.appendSegment("");
+ }
+
+ for (EObject proxy : EcoreUtil.UnresolvedProxyCrossReferencer.find(dependent).keySet()) {
+ URI dependencyURI = EcoreUtil.getURI(proxy).trimFragment();
+ if (dependencyURI.toString().startsWith(baseURI.toString())) {
+ Resource dependency = resourceSet.getResource(dependencyURI, false);
+ if ((dependency == null) || !dependency.isLoaded() || !dependency.getErrors().isEmpty()) {
+ // It should be available in the test bundle. Try to get it
+ URI relative = dependencyURI.deresolve(baseURI);
+ IPath depPath = resourceIPath.removeLastSegments(1).append(URI.decode(relative.toString()));
+ if (resourceKind.exists(testClass, depPath)) {
+ if (dependency == null) {
+ dependency = resourceSet.createResource(dependencyURI);
+ } else {
+ dependency.unload();
+ }
+
+ dependency = doInitModelResource(resourceSet, URI.decode(relative.toString()), resourceKind, depPath);
+ loadedProfiles = loadedProfiles || Iterables.any(dependency.getContents(), Predicates.instanceOf(Profile.class));
+
+ // Enqueue this for recursive dependency processing
+ dependents.add(dependency);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // If we depend on profiles, then we may have stereotype applications that need to resolve against that schema.
+ // In such case, re-load the model resource to resolve the stereotype schema
+ if (loadedProfiles && Iterables.any(result.getContents(), Predicates.instanceOf(AnyType.class))) {
+ try {
+ result.unload();
+ result.load(null);
+ } catch (Exception e) {
+ e.printStackTrace();
+ fail("Error re-loading resource to resolve stereotype schema: " + e.getLocalizedMessage());
+ }
+ }
+
+ // Now unload resources that the manifest indicates should not be loaded initially
+ for (Resource next : toUnload) {
+ next.unload();
+ next.getResourceSet().getResources().remove(next);
+ next.eAdapters().clear();
+ }
+ } finally {
+ if (bootstrapResourceSet) {
+ EMFHelper.unload(resourceSet);
+ }
+ }
+
+ return result;
+ }
+
+ private Map<IPath, Boolean> loadManifest(ResourceKind resourceKind, IPath resourceIPath) {
+ Map<IPath, Boolean> result = null;
+ IPath manifestPath = resourceIPath.addFileExtension("manifest");
+
+ URL manifestURL = resourceKind.getResourceURL(testClass, manifestPath);
+ if (manifestURL != null) {
+ try {
+ result = parseManifest(manifestPath.removeLastSegments(1), manifestURL);
+ } catch (IOException e) {
+ e.printStackTrace();
+ // Create a default manifest
+ }
+ }
+
+ if (result == null) {
+ // Default manifest
+ result = Maps.newHashMap();
+ IPath basePath = manifestPath.removeFileExtension();
+ result.put(basePath.addFileExtension(DiModel.DI_FILE_EXTENSION), true);
+ result.put(basePath.addFileExtension(UmlModel.UML_FILE_EXTENSION), true);
+ result.put(basePath.addFileExtension(NotationModel.NOTATION_FILE_EXTENSION), true);
+ }
+
+ return result;
+ }
+
+ private Map<IPath, Boolean> parseManifest(IPath baseResourcePath, URL manifestURL) throws IOException {
+ Map<IPath, Boolean> result = Maps.newLinkedHashMap();
+
+ List<String> lines = Resources.asByteSource(manifestURL).asCharSource(Charsets.UTF_8).readLines();
+ Pattern pattern = Pattern.compile("([^=]+)(?:=(true|false))?");
+ Matcher m = pattern.matcher("");
+ for (String line : lines) {
+ m.reset(line);
+ if (m.matches()) {
+ IPath path = baseResourcePath.append(m.group(1));
+
+ boolean load = true;
+ if (m.group(2) != null) {
+ load = Boolean.valueOf(m.group(2));
+ }
+
+ result.put(path, load);
+ }
+ }
+
+ return result;
+ }
+
+ private Resource doInitModelResource(ResourceSet resourceSet, String targetPath, ResourceKind resourceKind, IPath resourceIPath) {
+ IPath targetIPath = new Path(targetPath);
+ if (!resourceIPath.getFileExtension().equals(targetIPath.getFileExtension())) {
+ targetIPath = targetIPath.addFileExtension(resourceIPath.getFileExtension());
+ }
+
+ // If the file name is different from the core model name, then use it as is. It's an extra resource for some purpose
+ // (perhaps such as a library model)
+ if (!targetIPath.lastSegment().equals(resourceIPath.lastSegment())) {
+ targetIPath = targetIPath.removeLastSegments(1).append(resourceIPath.lastSegment());
+ }
+
+ final URI modelURI = project.getURI(targetIPath);
+ Resource result = resourceSet.getResource(modelURI, false);
+
+ if (result == null) {
+ String extension = modelURI.fileExtension();
+ if (DiModel.DI_FILE_EXTENSION.equals(extension) || UmlModel.UML_FILE_EXTENSION.equals(extension) || NotationModel.NOTATION_FILE_EXTENSION.equals(extension)) {
+ // Default load behaviour
+ result = resourceSet.createResource(modelURI);
+ } else {
+ // Assume it's a fragment of UML content (such as a profile-application resource)
+ result = resourceSet.createResource(modelURI, UMLPackage.eCONTENT_TYPE);
+ }
+ }
+
+ if (!result.isLoaded()) {
+ if (resourceSet instanceof ModelSet) {
+ ModelSet modelSet = (ModelSet) resourceSet;
+ if (modelSet.getURIWithoutExtension() == null) {
+ modelSet.getInternal().setPrimaryModelResourceURI(modelURI);
+ }
+ }
+
+ try {
+ InputStream input = resourceKind.getResourceURL(testClass, resourceIPath).openStream();
+ OutputStream output = resourceSet.getURIConverter().createOutputStream(result.getURI());
+
+ try {
+ ByteStreams.copy(input, output);
+ } finally {
+ input.close();
+ output.close();
+ }
+
+ result.load(null);
+ } catch (Exception e) {
+ e.printStackTrace();
+ fail("Failed to load test resource: " + resourceIPath.toString());
+ }
+ }
+
+ return result;
+ }
+
+ @Override
+ protected void finished(Description description) {
+ final ResourceSet resourceSet = getResourceSet();
+
+ initialResourceURIs = null;
+ model = null;
+ root = null;
+
+ if (domain instanceof TransactionalEditingDomain) {
+ ((TransactionalEditingDomain) domain).dispose();
+ }
+ domain = null;
+
+ if (resourceSet != null) {
+ EMFHelper.unload(resourceSet);
+ }
+ }
+
+ private Annotation getResourceAnnotation(Description description) {
+ Annotation result = JUnitUtils.getAnyAnnotation(description, JavaResource.class, PluginResource.class);
+
+ assertThat("No JavaResource or PluginResource annotation found on test.", result, notNullValue());
+
+ return result;
+ }
+
+ public static enum ResourceKind {
+ JAVA, BUNDLE;
+
+ static ResourceKind getResourceKind(Annotation resourceAnnotation) {
+ return (resourceAnnotation instanceof JavaResource) ? JAVA : (resourceAnnotation instanceof PluginResource) ? BUNDLE : null;
+ }
+
+ String[] getResourcePaths(Annotation resourceAnnotation) {
+ switch (this) {
+ case JAVA:
+ return ((JavaResource) resourceAnnotation).value();
+ case BUNDLE:
+ PluginResource plugin = (PluginResource) resourceAnnotation;
+ return plugin.bundle().isEmpty()
+ ? plugin.value()
+ : Stream.of(plugin.value()).map(path -> String.format("%s:%s", plugin.bundle(), path)).toArray(String[]::new);
+ }
+
+ fail("Not a resource annotation: " + resourceAnnotation);
+ return null; // Not reachable
+ }
+
+ boolean exists(Class<?> context, IPath path) {
+ return getResourceURL(context, path) != null;
+ }
+
+ URL getResourceURL(Class<?> context, IPath path) {
+ URL result = null;
+
+ switch (this) {
+ case JAVA:
+ result = context.getResource(path.toString());
+ break;
+ case BUNDLE:
+ result = getBundleURL(context, path);
+ break;
+ }
+
+ return result;
+ }
+
+ private URL getBundleURL(Class<?> testClass, IPath resourcePath) {
+ URL result = null;
+
+ String bundleID = resourcePath.getDevice();
+ if (bundleID != null) {
+ resourcePath = resourcePath.setDevice(null);
+
+ int colon = bundleID.lastIndexOf(':');
+ if (colon >= 0) {
+ bundleID = bundleID.substring(0, colon);
+ }
+ }
+
+ String pattern = resourcePath.lastSegment();
+ IPath search;
+ if (resourcePath.segmentCount() > 1) {
+ search = resourcePath.removeLastSegments(1);
+ } else {
+ search = Path.ROOT;
+ }
+
+ Bundle testBundle = (bundleID != null)
+ ? Platform.getBundle(bundleID)
+ : FrameworkUtil.getBundle(testClass);
+ Enumeration<URL> urls = testBundle.findEntries(search.toPortableString(), pattern, false);
+ if ((urls != null) && urls.hasMoreElements()) {
+ result = urls.nextElement();
+ }
+
+ if (result == null) {
+ // A test case can override a resource in a base test bundle with a corresponding resource of its
+ // own. But, it may also just use the resource provided by the base test bundle, so look for it
+ Bundle lastBundle = testBundle;
+ for (Class<?> baseClass = testClass.getSuperclass(); (baseClass != null); baseClass = baseClass.getSuperclass()) {
+ testBundle = FrameworkUtil.getBundle(baseClass);
+ if (testBundle == null) {
+ break;
+ } else if (testBundle != lastBundle) {
+ lastBundle = testBundle;
+ urls = testBundle.findEntries(search.toPortableString(), pattern, false);
+ if ((urls != null) && urls.hasMoreElements()) {
+ result = urls.nextElement();
+ }
+ }
+ }
+ }
+
+ return result;
+ }
+ }
+}
diff --git a/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/ActiveDiagram.java b/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/ActiveDiagram.java
new file mode 100644
index 00000000000..5ae3344d156
--- /dev/null
+++ b/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/ActiveDiagram.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2015 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ */
+package org.eclipse.papyrus.junit.utils.rules;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+
+/**
+ * Annotation on a test indicating the diagram to activate.
+ *
+ * @see PapyrusEditorFixture
+ */
+@Target({ ElementType.METHOD, ElementType.TYPE })
+@Retention(RetentionPolicy.RUNTIME)
+public @interface ActiveDiagram {
+ /**
+ * The name of the diagram to activate.
+ */
+ String value();
+}
diff --git a/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/ActiveTable.java b/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/ActiveTable.java
new file mode 100755
index 00000000000..44d26fb35fa
--- /dev/null
+++ b/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/ActiveTable.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2015 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ */
+package org.eclipse.papyrus.junit.utils.rules;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+
+/**
+ * Annotation on a test indicating the table to activate.
+ *
+ * @see PapyrusEditorFixture
+ */
+@Target({ ElementType.METHOD, ElementType.TYPE })
+@Retention(RetentionPolicy.RUNTIME)
+public @interface ActiveTable {
+ /**
+ * The name of the table to activate.
+ */
+ String value();
+}
diff --git a/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/AnnotationRule.java b/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/AnnotationRule.java
new file mode 100644
index 00000000000..ae3e6017797
--- /dev/null
+++ b/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/AnnotationRule.java
@@ -0,0 +1,152 @@
+/*****************************************************************************
+ * Copyright (c) 2015 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.junit.utils.rules;
+
+import static org.junit.Assert.fail;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+
+import org.eclipse.papyrus.junit.utils.JUnitUtils;
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+import com.google.common.base.Defaults;
+import com.google.common.base.Supplier;
+
+/**
+ * A rule that finds annotation metadata of a test. If the value of the annotation is a
+ * class, then the rule instantiates that class in order to provide a value.
+ */
+public class AnnotationRule<T> implements TestRule, Supplier<T> {
+ private final Class<? extends Annotation> annotationType;
+ private final Method valueAccessor;
+
+ private T value;
+
+ private AnnotationRule(Class<? extends Annotation> annotationType, Method accessor, T default_) {
+ super();
+
+ this.annotationType = annotationType;
+ this.valueAccessor = accessor;
+
+ this.value = default_;
+ }
+
+ /**
+ * Creates a new rule that extracts the value of the specified annotation type from
+ * a test case.
+ *
+ * @param annotationType
+ * the annotation type from which to extract the value
+ * @param default_
+ * the value to return in the case that the annotation is absent. If null
+ * and the annotation value is of a primitive type, the appropriate primitive default is substituted
+ *
+ * @return the rule
+ */
+ @SuppressWarnings("unchecked")
+ public static <T> AnnotationRule<T> create(Class<? extends Annotation> annotationType, T default_) {
+ try {
+ Method method = annotationType.getDeclaredMethod("value");
+
+ Class<?> resultType = method.getReturnType();
+
+ if ((default_ == null) && (resultType != Class.class)) {
+ default_ = (T) Defaults.defaultValue(resultType);
+ }
+
+ return new AnnotationRule<T>(annotationType, method, default_);
+ } catch (Exception e) {
+ fail("Cannot get annotation value: " + e.getMessage());
+ throw new Error();// unreachable
+ }
+ }
+
+ /**
+ * Creates a new rule that extracts the value of the specified annotation type from
+ * a test case. This rule does not have a default: if the annotation is absent, it
+ * returns {@code null}.
+ *
+ * @param annotationType
+ * the annotation type from which to extract the value
+ * @return the rule
+ */
+ public static <T> AnnotationRule<T> create(Class<? extends Annotation> annotationType) {
+ return create(annotationType, null);
+ }
+
+ /**
+ * Creates a new rule that just determines whether the specified annotation is applied to
+ * a test case.
+ *
+ * @param annotationType
+ * the annotation type to detect
+ *
+ * @return the rule
+ */
+ public static AnnotationRule<Boolean> createExists(Class<? extends Annotation> annotationType) {
+ return new AnnotationRule<Boolean>(annotationType, null, false);
+ }
+
+ @Override
+ public final T get() {
+ return value;
+ }
+
+ @Override
+ public Statement apply(final Statement base, Description description) {
+ Statement result = base;
+ final Annotation annotation = JUnitUtils.getAnnotation(description, annotationType);
+
+ if (annotation != null) {
+ result = new Statement() {
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public void evaluate() throws Throwable {
+ try {
+ // If we have no accessor method, we're just checking existence of the annotation,
+ // which is "extracted" as a boolean
+ if (valueAccessor == null) {
+ value = (T) Boolean.TRUE;
+ } else {
+ Object extracted = valueAccessor.invoke(annotation);
+ if (extracted instanceof Class<?>) {
+ // Instantiate the class
+ extracted = ((Class<?>) extracted).newInstance();
+ }
+ value = (T) extracted;
+ }
+ } catch (Exception e) {
+ fail("Cannot get annotation value: " + e.getMessage());
+ }
+
+ try {
+ base.evaluate();
+ } finally {
+ if (valueAccessor != null) {
+ // Clean up. Note that if the annotation value is a class, the
+ // default is null anyways, so the cast doesn't matter
+ value = (T) Defaults.defaultValue(valueAccessor.getReturnType());
+ }
+ }
+ }
+ };
+ }
+
+ return result;
+ }
+}
diff --git a/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/ExecutorRule.java b/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/ExecutorRule.java
new file mode 100644
index 00000000000..77347df01ce
--- /dev/null
+++ b/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/ExecutorRule.java
@@ -0,0 +1,56 @@
+/*****************************************************************************
+ * Copyright (c) 2015 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.junit.utils.rules;
+
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.Executor;
+
+import org.eclipse.papyrus.junit.utils.Activator;
+import org.junit.rules.TestRule;
+import org.junit.rules.TestWatcher;
+import org.junit.runner.Description;
+
+import com.google.common.collect.Queues;
+
+/**
+ * A JUnit {@linkplain TestRule rule} that is an {@link Executor} running tasks at clean-up of the
+ * test execution.
+ */
+public class ExecutorRule extends TestWatcher implements Executor {
+ private final BlockingQueue<Runnable> queue = Queues.newLinkedBlockingQueue();
+
+ public ExecutorRule() {
+ super();
+ }
+
+ @Override
+ public void execute(Runnable command) {
+ queue.add(command);
+ }
+
+ protected void runPending() {
+ for (Runnable next = queue.poll(); next != null; next = queue.poll()) {
+ try {
+ next.run();
+ } catch (Exception e) {
+ Activator.log.error("Uncaught exception in test shutdown runnable.", e); //$NON-NLS-1$
+ }
+ }
+ }
+
+ @Override
+ protected void finished(Description description) {
+ runPending();
+ }
+}
diff --git a/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/HideViewRule.java b/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/HideViewRule.java
new file mode 100644
index 00000000000..66830a5159b
--- /dev/null
+++ b/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/HideViewRule.java
@@ -0,0 +1,72 @@
+/*****************************************************************************
+ * Copyright (c) 2014 CEA LIST and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * CEA LIST - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.junit.utils.rules;
+
+import static org.junit.Assert.fail;
+
+import org.eclipse.ui.IViewPart;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.PlatformUI;
+import org.junit.rules.TestWatcher;
+import org.junit.runner.Description;
+
+
+/**
+ * A rule that hides a view for the duration of a test.
+ */
+public class HideViewRule extends TestWatcher {
+
+ private final String viewID;
+
+ private IWorkbenchPage page;
+
+ public HideViewRule(String viewID) {
+ super();
+
+ this.viewID = viewID;
+ }
+
+ @Override
+ protected void starting(Description description) {
+ IWorkbench bench = PlatformUI.getWorkbench();
+ IWorkbenchWindow window = bench.getActiveWorkbenchWindow();
+ if(window == null) {
+ window = bench.getWorkbenchWindows()[0];
+ }
+
+ IWorkbenchPage page = window.getActivePage();
+ IViewPart viewPart = page.findView(viewID);
+
+ if(viewPart != null) {
+ this.page = page;
+ page.hideView(viewPart);
+ }
+ }
+
+ @Override
+ protected void finished(Description description) {
+ if(page != null) {
+ try {
+ page.showView(viewID);
+ } catch (PartInitException e) {
+ fail(String.format("Failed to restore view %s: %s", viewID, e.getLocalizedMessage()));
+ }
+ }
+
+ page = null;
+ }
+}
diff --git a/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/HouseKeeper.java b/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/HouseKeeper.java
new file mode 100644
index 00000000000..c52cc8d17e5
--- /dev/null
+++ b/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/HouseKeeper.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2014, 2015 CEA, Christian W. Damus, and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus (CEA) - Initial API and implementation
+ * Christian W. Damus - bug 476683
+ *
+ */
+package org.eclipse.papyrus.junit.utils.rules;
+
+import java.util.Iterator;
+
+import org.eclipse.emf.ecore.EObject;
+import org.junit.ClassRule;
+import org.junit.rules.MethodRule;
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runners.model.FrameworkMethod;
+import org.junit.runners.model.Statement;
+
+
+/**
+ * <p>
+ * A JUnit rule that automatically cleans up resources when a test has finished. It provides a generic framework for cleaning stuff up, but it also
+ * has special cases for commonly used items.
+ * </p>
+ * <p>
+ * As a bonus, the {@code HouseKeeper} also automatically clears all non-{@code static} non-{@code final} fields of the test class that are of some
+ * type conforming to {@link EObject}, just to make sure that they can't cause memory leaks.
+ * </p>
+ * <p>
+ * To use the rule as a {@link ClassRule &#x40;ClassRule}, instantiate the {@linkplain Static} inner class.
+ * </p>
+ *
+ * @see Static
+ * @see Disposer
+ */
+public class HouseKeeper extends AbstractHouseKeeperRule implements MethodRule {
+
+ public HouseKeeper() {
+ super();
+ }
+
+ @Override
+ boolean isStatic() {
+ return false;
+ }
+
+ @Override
+ Class<?> getTestClass() {
+ return test.getClass();
+ }
+
+ //
+ // Rule protocol
+ //
+
+ @Override
+ public Statement apply(final Statement base, final FrameworkMethod method, final Object target) {
+ return new Statement() {
+
+ @Override
+ public void evaluate() throws Throwable {
+ test = target;
+ testName = method.getName();
+
+ try {
+ registerAutoCleanups();
+ base.evaluate();
+ } finally {
+ cleanUp();
+ }
+ }
+ };
+ }
+
+ //
+ // Nested types
+ //
+
+ /**
+ * A call-back interface for disposing of objects no longer needed by the test.
+ */
+ public static interface Disposer<T> {
+
+ void dispose(T object) throws Exception;
+ }
+
+ /**
+ * A variant of the {@link HouseKeeper} that is to be used for class rules. It cleans up static fields of the test class and runs disposers
+ * after the completion of the class's whole test suite.
+ */
+ public static class Static extends AbstractHouseKeeperRule implements TestRule {
+
+ @Override
+ boolean isStatic() {
+ return true;
+ }
+
+ @Override
+ Class<?> getTestClass() {
+ return (Class<?>) test;
+ }
+
+ @Override
+ public Statement apply(final Statement base, final Description description) {
+ return new Statement() {
+
+ @Override
+ public void evaluate() throws Throwable {
+ // description.getTestClass() is null for static rules
+ test = findTestClass(description);
+ testName = description.getMethodName();
+
+ try {
+ registerAutoCleanups();
+ base.evaluate();
+ } finally {
+ cleanUp();
+ }
+ }
+
+ Class<?> findTestClass(Description description) {
+ Class<?> result = description.getTestClass();
+
+ if (result == null) {
+ for (Iterator<Description> iter = description.getChildren().iterator(); (result == null) && iter.hasNext();) {
+ result = findTestClass(iter.next());
+ }
+ }
+
+ return result;
+ }
+ };
+ }
+
+ }
+}
diff --git a/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/JavaResource.java b/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/JavaResource.java
new file mode 100644
index 00000000000..23d870281ba
--- /dev/null
+++ b/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/JavaResource.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2014 CEA and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus (CEA) - Initial API and implementation
+ *
+ */
+package org.eclipse.papyrus.junit.utils.rules;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+
+/**
+ * Annotation indicating the classpath-relative path to one or more resources from which to load the test model of an {@link AbstractModelFixture}.
+ *
+ * @see AbstractModelFixture
+ * @see PluginResource
+ */
+@Target({ ElementType.METHOD, ElementType.TYPE })
+@Retention(RetentionPolicy.RUNTIME)
+public @interface JavaResource {
+
+ String[] value();
+}
diff --git a/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/ModelSetFixture.java b/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/ModelSetFixture.java
new file mode 100644
index 00000000000..65a8fbc9152
--- /dev/null
+++ b/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/ModelSetFixture.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2014, 2016 CEA, Christian W. Damus, and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus (CEA) - Initial API and implementation
+ * Christian W. Damus - bugs 399859, 485220
+ *
+ */
+package org.eclipse.papyrus.junit.utils.rules;
+
+import static org.junit.Assert.fail;
+
+import java.util.Collections;
+import java.util.regex.Pattern;
+
+import org.eclipse.emf.ecore.resource.ResourceSet;
+import org.eclipse.emf.transaction.TransactionalEditingDomain;
+import org.eclipse.papyrus.infra.core.resource.EditingDomainServiceFactory;
+import org.eclipse.papyrus.infra.core.resource.ModelMultiException;
+import org.eclipse.papyrus.infra.core.resource.ModelSet;
+import org.eclipse.papyrus.infra.core.services.ServiceDescriptor;
+import org.eclipse.papyrus.infra.core.services.ServiceDescriptor.ServiceTypeKind;
+import org.eclipse.papyrus.infra.core.services.ServiceException;
+import org.eclipse.papyrus.infra.core.services.ServiceStartKind;
+import org.eclipse.papyrus.infra.core.services.ServicesRegistry;
+import org.eclipse.papyrus.infra.emf.utils.ServiceUtilsForResourceSet;
+import org.junit.runner.Description;
+
+
+/**
+ * This is the ModelSetFixture type. Enjoy.
+ */
+public class ModelSetFixture extends AbstractModelFixture<TransactionalEditingDomain> {
+
+ public ModelSetFixture() {
+ super();
+ }
+
+ @Override
+ public ModelSet getResourceSet() {
+ return (ModelSet) super.getResourceSet();
+ }
+
+ @Override
+ protected TransactionalEditingDomain createEditingDomain() {
+ try {
+ ServicesRegistry services = createServiceRegistry();
+ return services.getService(ModelSet.class).getTransactionalEditingDomain();
+ } catch (Exception e) {
+ e.printStackTrace();
+ fail("Failed to initialize service registry and/or editing domain: " + e.getLocalizedMessage());
+ return null; // unreachable
+ }
+ }
+
+ @Override
+ protected void finished(Description description) {
+ ResourceSet rset = getEditingDomain().getResourceSet();
+
+ try {
+ ServicesRegistry services = ServiceUtilsForResourceSet.getInstance().getServiceRegistry(rset);
+ services.disposeRegistry();
+ } catch (Exception e) {
+ e.printStackTrace();
+ } finally {
+ super.finished(description);
+ }
+ }
+
+ protected ServicesRegistry createServiceRegistry() throws Exception {
+ ServicesRegistry result = new ServicesRegistry();
+
+ result.add(ModelSet.class, 10, new ModelSet());
+
+ ServiceDescriptor desc = new ServiceDescriptor(TransactionalEditingDomain.class, EditingDomainServiceFactory.class.getName(), ServiceStartKind.STARTUP, 10, Collections.singletonList(ModelSet.class.getName()));
+ desc.setServiceTypeKind(ServiceTypeKind.serviceFactory);
+ desc.setClassBundleID(org.eclipse.papyrus.infra.core.Activator.PLUGIN_ID);
+ result.add(desc);
+
+ result.startRegistry();
+
+ return result;
+ }
+
+ @Override
+ protected void didLoadResourceSet() {
+ try {
+ getResourceSet().loadModels(getModelResourceURI());
+ } catch (ModelMultiException e) {
+ // Is the problem only a missing model resource?
+ Pattern missingResource = Pattern.compile("ResourceException: Resource '.*' does not exist."); //$NON-NLS-1$
+ for (Throwable next : e.getExceptions()) {
+ if ((next.getMessage() == null) || !missingResource.matcher(next.getMessage()).find()) {
+ e.printStackTrace();
+
+ fail("Failed to initialize ModelSet fixture: " + e.getLocalizedMessage());
+ }
+ }
+ }
+ }
+
+ public final <S> S tryService(Class<S> serviceType) {
+ try {
+ ServicesRegistry services = ServiceUtilsForResourceSet.getInstance().getServiceRegistry(getResourceSet());
+ return services.getService(serviceType);
+ } catch (ServiceException e) {
+ // Okay, no such service
+ return null; // unreachable
+ }
+ }
+
+ public final <S> S requireService(Class<S> serviceType) {
+ try {
+ ServicesRegistry services = ServiceUtilsForResourceSet.getInstance().getServiceRegistry(getResourceSet());
+ return services.getService(serviceType);
+ } catch (ServiceException e) {
+ e.printStackTrace();
+ fail("Failed to initialize service registry and/or service: " + e.getLocalizedMessage());
+ return null; // unreachable
+ }
+ }
+}
diff --git a/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/NoTransactionFixture.java b/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/NoTransactionFixture.java
new file mode 100644
index 00000000000..dcada7fc60e
--- /dev/null
+++ b/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/NoTransactionFixture.java
@@ -0,0 +1,95 @@
+/*****************************************************************************
+ * Copyright (c) 2014 CEA LIST and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * CEA LIST - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.junit.utils.rules;
+
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.eclipse.emf.common.command.AbstractCommand;
+import org.eclipse.emf.ecore.resource.ResourceSet;
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+/**
+ * This rule provides a ResourceSet with a TransactionalEditingDomain
+ *
+ * All test methods are executed within a Transaction (Which means test method
+ * do not need to care about transactions)
+ *
+ * This fixture is meant to be used through {@link NoTransactionRule}
+ *
+ * @author Camille Letavernier
+ *
+ * @see {@link NoTransactionRule}
+ */
+public class NoTransactionFixture implements TestRule {
+
+
+ private final ModelSetFixture modelSet;
+
+ public NoTransactionFixture(ModelSetFixture modelSet) {
+ this.modelSet = modelSet;
+ }
+
+ /**
+ * @see org.junit.rules.TestRule#apply(org.junit.runners.model.Statement, org.junit.runner.Description)
+ *
+ * @param arg0
+ * @param arg1
+ * @return
+ */
+ public Statement apply(final Statement base, final Description description) {
+ return new Statement() {
+ @Override
+ public void evaluate() throws Throwable {
+
+ final AtomicReference<Throwable> throwable = new AtomicReference<Throwable>();
+ modelSet.getEditingDomain().getCommandStack().execute(new AbstractCommand() {
+
+ public void execute() {
+ try {
+ base.evaluate();
+ } catch (Throwable t) {
+ throwable.set(t);
+ }
+ }
+
+ public void redo() {
+ // Nothing
+ }
+
+ /**
+ * @see org.eclipse.emf.common.command.AbstractCommand#prepare()
+ *
+ * @return
+ */
+ @Override
+ protected boolean prepare() {
+ return true;
+ }
+
+ });
+
+ if (throwable.get() != null) {
+ throw throwable.get();
+ }
+ }
+ };
+ }
+
+ public ResourceSet getResourceSet() {
+ return modelSet.getResourceSet();
+ }
+
+}
diff --git a/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/NoTransactionRule.java b/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/NoTransactionRule.java
new file mode 100644
index 00000000000..b3dee015fda
--- /dev/null
+++ b/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/NoTransactionRule.java
@@ -0,0 +1,59 @@
+/*****************************************************************************
+ * Copyright (c) 2014 CEA LIST and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * CEA LIST - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.junit.utils.rules;
+
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.emf.ecore.resource.ResourceSet;
+import org.junit.rules.RuleChain;
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+/**
+ * This rule provides a ResourceSet with a TransactionalEditingDomain
+ *
+ * All test methods are executed within a Transaction (Which means test method
+ * do not need to care about transactions)
+ *
+ * Usage:
+ *
+ * <pre>
+ * &#064;Rule
+ * public NoTransactionRule noTransaction = new NoTransactionRule();
+ * </pre>
+ *
+ * @author Camille Letavernier
+ */
+public class NoTransactionRule implements TestRule {
+
+ private final ModelSetFixture modelSet = new ModelSetFixture();
+
+ private final NoTransactionFixture noTransaction = new NoTransactionFixture(modelSet);
+
+ public RuleChain getRuleChain() {
+ return RuleChain.outerRule(modelSet).around(noTransaction);
+ }
+
+ public Statement apply(Statement base, Description description) {
+ return getRuleChain().apply(base, description);
+ }
+
+ public ResourceSet getResourceSet() {
+ return modelSet.getResourceSet();
+ }
+
+ public Resource getModelResource() {
+ return modelSet.getModelResource();
+ }
+}
diff --git a/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/PapyrusEditorFixture.java b/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/PapyrusEditorFixture.java
new file mode 100644
index 00000000000..a061a4b3240
--- /dev/null
+++ b/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/PapyrusEditorFixture.java
@@ -0,0 +1,1415 @@
+/*****************************************************************************
+ * Copyright (c) 2014, 2017 CEA, Christian W. Damus, and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus (CEA) - Initial API and implementation
+ * Christian W. Damus - bugs 433206, 465416, 434983, 483721, 469188, 485220, 491542, 497865
+ * Thanh Liem PHAN (ALL4TEC) thanhliem.phan@all4tec.net - Bug 521550
+ *****************************************************************************/
+package org.eclipse.papyrus.junit.utils.rules;
+
+import static org.hamcrest.CoreMatchers.instanceOf;
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.notNullValue;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.fail;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.core.commands.operations.IOperationHistory;
+import org.eclipse.core.commands.operations.IOperationHistoryListener;
+import org.eclipse.core.commands.operations.IUndoContext;
+import org.eclipse.core.commands.operations.IUndoableOperation;
+import org.eclipse.core.commands.operations.OperationHistoryEvent;
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.draw2d.geometry.Dimension;
+import org.eclipse.draw2d.geometry.Point;
+import org.eclipse.e4.ui.model.application.ui.MUIElement;
+import org.eclipse.e4.ui.model.application.ui.advanced.MPlaceholder;
+import org.eclipse.e4.ui.model.application.ui.basic.MPart;
+import org.eclipse.e4.ui.model.application.ui.basic.MPartSashContainerElement;
+import org.eclipse.e4.ui.model.application.ui.basic.MPartStack;
+import org.eclipse.e4.ui.model.application.ui.basic.MStackElement;
+import org.eclipse.e4.ui.workbench.modeling.EModelService;
+import org.eclipse.emf.common.command.Command;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.emf.ecore.util.EcoreUtil;
+import org.eclipse.emf.edit.domain.AdapterFactoryEditingDomain;
+import org.eclipse.emf.edit.domain.EditingDomain;
+import org.eclipse.emf.edit.provider.IItemLabelProvider;
+import org.eclipse.emf.transaction.TransactionalEditingDomain;
+import org.eclipse.emf.workspace.IWorkspaceCommandStack;
+import org.eclipse.gef.EditPart;
+import org.eclipse.gef.GraphicalEditPart;
+import org.eclipse.gef.RootEditPart;
+import org.eclipse.gef.ui.palette.PaletteViewer;
+import org.eclipse.gmf.runtime.diagram.core.preferences.PreferencesHint;
+import org.eclipse.gmf.runtime.diagram.ui.commands.ICommandProxy;
+import org.eclipse.gmf.runtime.diagram.ui.commands.SetBoundsCommand;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.DiagramEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.IDiagramPreferenceSupport;
+import org.eclipse.gmf.runtime.diagram.ui.parts.DiagramEditor;
+import org.eclipse.gmf.runtime.diagram.ui.parts.DiagramEditorWithFlyOutPalette;
+import org.eclipse.gmf.runtime.diagram.ui.parts.IDiagramWorkbenchPart;
+import org.eclipse.gmf.runtime.notation.Diagram;
+import org.eclipse.gmf.runtime.notation.View;
+import org.eclipse.papyrus.editor.PapyrusMultiDiagramEditor;
+import org.eclipse.papyrus.infra.core.resource.ModelSet;
+import org.eclipse.papyrus.infra.core.resource.sasheditor.DiModel;
+import org.eclipse.papyrus.infra.core.sasheditor.editor.IComponentPage;
+import org.eclipse.papyrus.infra.core.sasheditor.editor.IEditorPage;
+import org.eclipse.papyrus.infra.core.sasheditor.editor.IPageVisitor;
+import org.eclipse.papyrus.infra.core.sasheditor.editor.ISashWindowsContainer;
+import org.eclipse.papyrus.infra.core.sashwindows.di.service.IPageManager;
+import org.eclipse.papyrus.infra.core.services.ServiceException;
+import org.eclipse.papyrus.infra.core.services.ServicesRegistry;
+import org.eclipse.papyrus.infra.core.utils.ServiceUtils;
+import org.eclipse.papyrus.infra.gmfdiag.common.model.NotationModel;
+import org.eclipse.papyrus.infra.nattable.common.editor.AbstractEMFNattableEditor;
+import org.eclipse.papyrus.infra.nattable.common.modelresource.PapyrusNattableModel;
+import org.eclipse.papyrus.infra.nattable.manager.table.INattableModelManager;
+import org.eclipse.papyrus.infra.nattable.model.nattable.Table;
+import org.eclipse.papyrus.infra.tools.util.PlatformHelper;
+import org.eclipse.papyrus.infra.tools.util.TypeUtils;
+import org.eclipse.papyrus.infra.ui.editor.IMultiDiagramEditor;
+import org.eclipse.papyrus.junit.utils.EditorUtils;
+import org.eclipse.papyrus.junit.utils.JUnitUtils;
+import org.eclipse.papyrus.junit.utils.tests.AbstractEditorTest;
+import org.eclipse.papyrus.uml.tools.model.UmlModel;
+import org.eclipse.papyrus.views.modelexplorer.ModelExplorerPage;
+import org.eclipse.papyrus.views.modelexplorer.ModelExplorerPageBookView;
+import org.eclipse.papyrus.views.modelexplorer.ModelExplorerView;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IEditorReference;
+import org.eclipse.ui.IPartListener;
+import org.eclipse.ui.IPerspectiveDescriptor;
+import org.eclipse.ui.ISaveablePart;
+import org.eclipse.ui.IViewPart;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.part.IPage;
+import org.eclipse.uml2.uml.NamedElement;
+import org.eclipse.uml2.uml.Package;
+import org.eclipse.uml2.uml.UMLPackage;
+import org.junit.runner.Description;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.FrameworkUtil;
+
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Iterators;
+import com.google.common.collect.ListMultimap;
+import com.google.common.collect.Lists;
+
+
+/**
+ * A fixture that presents editors on a model specified via an annotation as for {@link ProjectFixture}. The editor is closed automatically upon
+ * completion of the test.
+ */
+public class PapyrusEditorFixture extends AbstractModelFixture<TransactionalEditingDomain> {
+
+ private final Collection<IEditorPart> editorsToClose = Lists.newArrayList();
+
+ private final List<String> excludedTypeView = Arrays.asList(new String[] { "Note" });
+
+ private final boolean ensureOperationHistoryIntegrity;
+
+ @SuppressWarnings("restriction")
+ private org.eclipse.papyrus.infra.ui.internal.preferences.YesNo initialEditorLayoutStorageMigrationPreference;
+
+ private IMultiDiagramEditor editor;
+
+ private DiagramEditorWithFlyOutPalette activeDiagramEditor;
+
+ private AbstractEMFNattableEditor activeTableEditor;
+
+ private ModelExplorerView modelExplorer;
+
+ private Class<?> testClass;
+
+ private Description testDescription;
+
+ private Collection<IViewPart> viewsToClose;
+
+ private ListMultimap<Description, IFile> modelFiles;
+
+ private IOperationHistoryListener operationHistoryIntegrityListener;
+ private IOperationHistory operationHistory;
+
+ /**
+ * Initializes me with the assurance of undo/redo correspondence in the
+ * diagram and EMF views of the command history.
+ */
+ public PapyrusEditorFixture() {
+ this(true);
+ }
+
+ /**
+ * Initializes me with the option to ensure integrity of the operation history
+ * by listening for command execution in the diagram context and, if an operation
+ * executed in the diagram does not have the editing-domain context, adds that
+ * context. This ensures that the diagram editor and the model explorer, for
+ * example, see the same undo/redo history (which they would not if some
+ * diagram-only commands were only in the diagram's history). Some tests do
+ * need to suppress this convenience in order to accurately represent the
+ * normal Papyrus run-time environment.
+ *
+ * @param ensureOperationHistoryIntegrity
+ *
+ * @since 2.0
+ */
+ public PapyrusEditorFixture(boolean ensureOperationHistoryIntegrity) {
+ super();
+
+ this.ensureOperationHistoryIntegrity = ensureOperationHistoryIntegrity;
+ }
+
+ /**
+ * @since 2.0
+ */
+ public IMultiDiagramEditor getEditor() {
+ return editor;
+ }
+
+ /**
+ * @since 2.0
+ */
+ public IMultiDiagramEditor getEditor(String path) {
+ IMultiDiagramEditor result = null;
+
+ final String fileName = new Path(path).lastSegment();
+ for (IEditorReference next : getWorkbenchPage().getEditorReferences()) {
+ if (PapyrusMultiDiagramEditor.EDITOR_ID.equals(next.getId()) && fileName.equals(next.getName())) {
+ result = (IMultiDiagramEditor) next.getEditor(true);
+ }
+ }
+
+ return result;
+ }
+
+ @SuppressWarnings("restriction")
+ @Override
+ protected void starting(Description description) {
+ testClass = description.getTestClass();
+ testDescription = description;
+
+ // Ensure that we won't see a dialog prompting the user to migrate page layout
+ // storage from the DI file to the workspace-private sash file
+ initialEditorLayoutStorageMigrationPreference = org.eclipse.papyrus.infra.ui.internal.preferences.EditorPreferences.getInstance().getConvertSharedPageLayoutToPrivate();
+ org.eclipse.papyrus.infra.ui.internal.preferences.EditorPreferences.getInstance().setConvertSharedPageLayoutToPrivate(org.eclipse.papyrus.infra.ui.internal.preferences.YesNo.NO);
+
+ if (hasRequiredViews()) {
+ openRequiredViews();
+ }
+
+ modelFiles = ArrayListMultimap.create();
+ openAll(description);
+
+ ActiveDiagram activeDiagram = JUnitUtils.getAnnotation(description, ActiveDiagram.class);
+ if (activeDiagram != null) {
+ String name = activeDiagram.value();
+ activateDiagram(name);
+ if ((activeDiagramEditor == null) || !name.equals(getActiveDiagramEditor().getDiagram().getName())) {
+ // OK, we need to open it, then
+ openDiagram(name);
+ }
+ } else {
+ ActiveTable activeTable = JUnitUtils.getAnnotation(description, ActiveTable.class);
+ if (activeTable != null) {
+ String name = activeTable.value();
+ activateTable(name);
+ if ((activeTableEditor == null) || !name.equals(getActiveTableEditor().getTable().getName())) {
+ openTable(name);
+ }
+ }
+ }
+
+ super.starting(description);
+
+ if (ensureOperationHistoryIntegrity) {
+ // Ensure consistency of undo/redo with EMF operations
+ final IWorkspaceCommandStack stack = (IWorkspaceCommandStack) getEditingDomain().getCommandStack();
+ final IUndoContext emfContext = stack.getDefaultUndoContext();
+ operationHistory = stack.getOperationHistory();
+ operationHistoryIntegrityListener = new IOperationHistoryListener() {
+ @Override
+ public void historyNotification(OperationHistoryEvent event) {
+ if ((event.getEventType() == OperationHistoryEvent.DONE) && (activeDiagramEditor != null)) {
+ IUndoContext diagramContext = activeDiagramEditor.getDiagramEditDomain().getDiagramCommandStack().getUndoContext();
+ if (diagramContext != null) {
+ IUndoableOperation undo = event.getOperation();
+ if ((undo != null) && !undo.hasContext(emfContext)) {
+ undo.addContext(emfContext);
+ }
+ }
+ }
+ // nothing to do for table
+ }
+ };
+ operationHistory.addOperationHistoryListener(operationHistoryIntegrityListener);
+ }
+ }
+
+ @SuppressWarnings("restriction")
+ @Override
+ protected void finished(Description description) {
+ try {
+ modelFiles = null;
+
+ Exception exception = null;
+
+ for (IEditorPart editor : ImmutableList.copyOf(editorsToClose)) {
+ try {
+ close(editor);
+ } catch (Exception e) {
+ if (exception == null) {
+ exception = e;
+ }
+ }
+ }
+
+ if (exception != null) {
+ exception.printStackTrace();
+ fail("Failed to close an editor: " + exception.getLocalizedMessage());
+ }
+ } finally {
+ try {
+ if (operationHistoryIntegrityListener != null) {
+ operationHistory.removeOperationHistoryListener(operationHistoryIntegrityListener);
+ operationHistoryIntegrityListener = null;
+ operationHistory = null;
+ }
+
+ } finally {
+ editorsToClose.clear();
+ editor = null;
+ activeDiagramEditor = null;
+
+ org.eclipse.papyrus.infra.ui.internal.preferences.EditorPreferences.getInstance().setConvertSharedPageLayoutToPrivate(initialEditorLayoutStorageMigrationPreference);
+
+ try {
+ if (hasRequiredViews()) {
+ closeRequiredViews();
+ }
+ } finally {
+ super.finished(description);
+ }
+ }
+ }
+ }
+
+ @Override
+ public TransactionalEditingDomain getEditingDomain() {
+ TransactionalEditingDomain result = null;
+
+ if (editor != null) {
+ result = getEditingDomain(editor);
+ }
+
+ return result;
+ }
+
+ /**
+ * @since 2.0
+ */
+ public TransactionalEditingDomain getEditingDomain(IMultiDiagramEditor editor) {
+ TransactionalEditingDomain result = null;
+
+ try {
+ result = getServiceRegistry(editor).getService(TransactionalEditingDomain.class);
+ } catch (ServiceException e) {
+ e.printStackTrace();
+ fail("Failed to get editing domain from Papyrus editor: " + e.getLocalizedMessage());
+ }
+
+ return result;
+ }
+
+ @Override
+ protected TransactionalEditingDomain createEditingDomain() {
+ // We don't create the domain; the editor does
+ return null;
+ }
+
+ /**
+ * @since 2.0
+ */
+ protected IMultiDiagramEditor open(final IFile modelFile) {
+ final boolean firstEditor = editorsToClose.isEmpty();
+
+ Display.getDefault().syncExec(new Runnable() {
+
+ @Override
+ public void run() {
+ try {
+ editor = EditorUtils.openPapyrusEditor(modelFile);
+ editorsToClose.add(editor);
+ } catch (Exception e) {
+ e.printStackTrace();
+ fail("Failed to open Papyrus editor: " + e.getLocalizedMessage());
+ }
+ }
+ });
+
+ if (firstEditor && !editorsToClose.isEmpty()) {
+ final IWorkbenchPage page = editor.getSite().getPage();
+ page.addPartListener(new IPartListener() {
+
+ @Override
+ public void partClosed(IWorkbenchPart part) {
+ editorsToClose.remove(part);
+
+ if (part == editor) {
+ editor = null;
+ }
+
+ if (editorsToClose.isEmpty()) {
+ page.removePartListener(this);
+ }
+ }
+
+ @Override
+ public void partOpened(IWorkbenchPart part) {
+ // Pass
+ }
+
+ @Override
+ public void partDeactivated(IWorkbenchPart part) {
+ // Pass
+ }
+
+ @Override
+ public void partBroughtToTop(IWorkbenchPart part) {
+ // Pass
+ }
+
+ @Override
+ public void partActivated(IWorkbenchPart part) {
+ // Pass
+ }
+ });
+ }
+
+ flushDisplayEvents();
+
+ return editor;
+ }
+
+ /**
+ * @since 2.0
+ */
+ protected IMultiDiagramEditor openOne(Description description) {
+ IFile papyrusModel = getProject().getFile(Iterables.getOnlyElement(initModelResources(description)).getURI().trimFileExtension().appendFileExtension(DiModel.DI_FILE_EXTENSION));
+ modelFiles.put(description, papyrusModel);
+ return open(papyrusModel);
+ }
+
+ protected Iterable<IMultiDiagramEditor> openAll(Description description) {
+ List<IMultiDiagramEditor> result = Lists.newArrayList();
+
+ for (Resource resource : initModelResources(description)) {
+ if(resource.getURI().fileExtension().equals(UmlModel.UML_FILE_EXTENSION)){
+ IFile papyrusModel = getProject().getFile(resource.getURI().trimFileExtension().appendFileExtension(DiModel.DI_FILE_EXTENSION));
+ modelFiles.put(description, papyrusModel);
+ result.add(open(papyrusModel));
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * @since 2.0
+ */
+ protected IMultiDiagramEditor reopenOne(Description description) {
+ IFile papyrusModel = modelFiles.get(description).get(0);
+ return open(papyrusModel);
+ }
+
+ /**
+ * @since 2.0
+ */
+ public IMultiDiagramEditor open() {
+ return openOne(testDescription);
+ }
+
+ /**
+ * @since 2.0
+ */
+ public IMultiDiagramEditor open(String resourcePath) {
+ return open(new Path(resourcePath).removeFileExtension().lastSegment(), ResourceKind.BUNDLE, resourcePath);
+ }
+
+ /**
+ * @since 2.0
+ */
+ public IMultiDiagramEditor open(String targetPath, String resourcePath) {
+ return open(targetPath, ResourceKind.BUNDLE, resourcePath);
+ }
+
+ /**
+ * @since 2.0
+ */
+ public IMultiDiagramEditor open(String targetPath, ResourceKind resourceKind, String resourcePath) {
+ final IFile papyrusModel = getProject().getFile(initModelResource(targetPath, resourceKind, resourcePath).getURI().trimFileExtension().appendFileExtension(DiModel.DI_FILE_EXTENSION));
+ return open(papyrusModel);
+ }
+
+ /**
+ * Reopens the same test model that was previously {@link #open() opened} and the
+ * subsequently {@link #close() closed}. This is an important disction, as simply
+ * {@link #open() opening} the test model again would actually re-initialize it from
+ * the deployed test resources, potentially replacing any changes in the model files
+ * that may be significant to the test.
+ *
+ * @return the re-opened editor
+ * @since 2.0
+ */
+ public IMultiDiagramEditor reopen() {
+ return reopenOne(testDescription);
+ }
+
+ public void activate() {
+ if (editor != null) {
+ activate(editor);
+ }
+ }
+
+ public void activate(IWorkbenchPart part) {
+ IWorkbenchPage page = part.getSite().getPage();
+
+ if (page.getActivePart() != part) {
+ page.activate(part);
+ flushDisplayEvents();
+ }
+ }
+
+ public void close() {
+ if (editor != null) {
+ close(editor);
+ editor = null;
+ }
+ }
+
+ public void close(IEditorPart editor) {
+ editor.getSite().getPage().closeEditor(editor, false);
+ flushDisplayEvents();
+ }
+
+ public ModelExplorerView getModelExplorerView() {
+
+ Display.getDefault().syncExec(new Runnable() {
+
+ @Override
+ public void run() {
+ ModelExplorerPageBookView view;
+ try {
+ view = (ModelExplorerPageBookView) getWorkbenchPage().showView(AbstractEditorTest.MODELEXPLORER_VIEW_ID);
+ } catch (PartInitException e) {
+ e.printStackTrace();
+ return;
+ }
+
+ IPage currentPage = view.getCurrentPage();
+ ModelExplorerPage page = (ModelExplorerPage) currentPage;
+ IViewPart viewer = page.getViewer();
+ modelExplorer = (ModelExplorerView) viewer;
+ }
+ });
+
+ return modelExplorer;
+ }
+
+ protected final IWorkbenchPage getWorkbenchPage() {
+ IWorkbench bench = PlatformUI.getWorkbench();
+ IWorkbenchWindow window = bench.getActiveWorkbenchWindow();
+ if (window == null) {
+ window = bench.getWorkbenchWindows()[0];
+ }
+ return window.getActivePage();
+ }
+
+ public ServicesRegistry getServiceRegistry() {
+ return getServiceRegistry(editor);
+ }
+
+ /**
+ * @since 2.0
+ */
+ public ServicesRegistry getServiceRegistry(IMultiDiagramEditor editor) {
+ return editor.getServicesRegistry();
+ }
+
+ public ModelSet getModelSet() {
+ return getModelSet(editor);
+ }
+
+ /**
+ * @since 2.0
+ */
+ public ModelSet getModelSet(IMultiDiagramEditor editor) {
+ try {
+ return getServiceRegistry(editor).getService(ModelSet.class);
+ } catch (ServiceException e) {
+ e.printStackTrace();
+ fail("Failed to get model set from Papyrus editor: " + e.getLocalizedMessage());
+ return null; // Unreachable
+ }
+ }
+
+ @Override
+ public Package getModel() {
+ return getModel(editor);
+ }
+
+ /**
+ * @since 2.0
+ */
+ public Package getModel(IMultiDiagramEditor editor) {
+ Package result = null;
+
+ ModelSet modelSet = getModelSet(editor);
+ UmlModel uml = (UmlModel) modelSet.getModel(UmlModel.MODEL_ID);
+ assertThat("No UML model present in resource set", uml.getResource(), notNullValue());
+
+ result = (Package) EcoreUtil.getObjectByType(uml.getResource().getContents(), UMLPackage.Literals.PACKAGE);
+ assertThat("Model resource contains no UML Package", result, notNullValue());
+
+ return result;
+ }
+
+ /**
+ * @since 2.0
+ */
+ public IPageManager getPageManager() {
+ return getPageManager(editor);
+ }
+
+ /**
+ * @since 2.0
+ */
+ public IPageManager getPageManager(IMultiDiagramEditor editor) {
+ try {
+ return getServiceRegistry(editor).getService(IPageManager.class);
+ } catch (ServiceException e) {
+ e.printStackTrace();
+ fail("Failed to get page manager from Papyrus editor: " + e.getLocalizedMessage());
+ return null; // Unreachable
+ }
+ }
+
+ public PapyrusEditorFixture activateDiagram(String name) {
+ return activateDiagram(editor, name);
+ }
+
+ public PapyrusEditorFixture activateTable(String name) {
+ return activateTable(editor, name);
+ }
+
+ /**
+ * @since 2.0
+ */
+ public PapyrusEditorFixture activateDiagram(IMultiDiagramEditor editor, final String name) {
+ activate(editor);
+
+ final ISashWindowsContainer sashContainer = PlatformHelper.getAdapter(editor, ISashWindowsContainer.class);
+ final org.eclipse.papyrus.infra.core.sasheditor.editor.IPage[] select = { null };
+
+ sashContainer.visit(new IPageVisitor() {
+
+ @Override
+ public void accept(IEditorPage page) {
+ if (name.equals(page.getPageTitle()) && (page.getIEditorPart() instanceof DiagramEditorWithFlyOutPalette)) {
+ select[0] = page;
+ setActiveDiagramEditor((DiagramEditorWithFlyOutPalette) page.getIEditorPart());
+ }
+ }
+
+ @Override
+ public void accept(IComponentPage page) {
+ // Pass
+ }
+ });
+
+ if (select[0] != null) {
+ sashContainer.selectPage(select[0]);
+ flushDisplayEvents();
+ }
+
+ return this;
+ }
+
+ /**
+ * @since 2.0
+ */
+ public PapyrusEditorFixture activateTable(IMultiDiagramEditor editor, final String name) {
+ activate(editor);
+
+ final ISashWindowsContainer sashContainer = PlatformHelper.getAdapter(editor, ISashWindowsContainer.class);
+ final org.eclipse.papyrus.infra.core.sasheditor.editor.IPage[] select = { null };
+
+ sashContainer.visit(new IPageVisitor() {
+
+ @Override
+ public void accept(IEditorPage page) {
+ if (name.equals(page.getPageTitle()) && (page.getIEditorPart() instanceof AbstractEMFNattableEditor)) {
+ select[0] = page;
+ setActiveTableEditor((AbstractEMFNattableEditor) page.getIEditorPart());
+ }
+ }
+
+ @Override
+ public void accept(IComponentPage page) {
+ // Pass
+ }
+ });
+
+ if (select[0] != null) {
+ sashContainer.selectPage(select[0]);
+ flushDisplayEvents();
+ }
+
+ return this;
+ }
+
+ private void setActiveDiagramEditor(DiagramEditorWithFlyOutPalette editor) {
+ activeDiagramEditor = editor;
+ activeTableEditor = null;
+ }
+
+ private void setActiveTableEditor(AbstractEMFNattableEditor editor) {
+ activeTableEditor = editor;
+ activeDiagramEditor = null;
+ }
+
+ public PapyrusEditorFixture activateDiagram(DiagramEditPart diagram) {
+ return activateDiagram(editor, diagram);
+ }
+
+ /**
+ * @since 2.0
+ */
+ public PapyrusEditorFixture activateDiagram(IMultiDiagramEditor editor, final DiagramEditPart diagram) {
+ activate(editor);
+
+ final ISashWindowsContainer sashContainer = PlatformHelper.getAdapter(editor, ISashWindowsContainer.class);
+ final org.eclipse.papyrus.infra.core.sasheditor.editor.IPage[] select = { null };
+
+ sashContainer.visit(new IPageVisitor() {
+
+ @Override
+ public void accept(IEditorPage page) {
+ DiagramEditorWithFlyOutPalette nested = TypeUtils.as(page.getIEditorPart(), DiagramEditorWithFlyOutPalette.class);
+ if ((nested != null) && (nested.getDiagramEditPart() == diagram)) {
+ select[0] = page;
+ setActiveDiagramEditor(nested);
+ }
+ }
+
+ @Override
+ public void accept(IComponentPage page) {
+ // Pass
+ }
+ });
+
+ if (select[0] != null) {
+ sashContainer.selectPage(select[0]);
+ flushDisplayEvents();
+ }
+
+ return this;
+ }
+
+ public PapyrusEditorFixture openDiagram(String name) {
+ return openDiagram(editor, name);
+ }
+
+ public PapyrusEditorFixture openTable(String name) {
+ return openTable(editor, name);
+ }
+
+ /**
+ * @since 2.0
+ */
+ public PapyrusEditorFixture openDiagram(IMultiDiagramEditor editor, final String name) {
+ activate(editor);
+
+ try {
+ ModelSet modelSet = ServiceUtils.getInstance().getModelSet(editor.getServicesRegistry());
+ NotationModel notation = (NotationModel) modelSet.getModel(NotationModel.MODEL_ID);
+ Diagram diagram = notation.getDiagram(name);
+ ServiceUtils.getInstance().getService(IPageManager.class, editor.getServicesRegistry()).openPage(diagram);
+ flushDisplayEvents();
+
+ activateDiagram(editor, name);
+ } catch (Exception e) {
+ throw new IllegalStateException("Cannot initialize test", e);
+ }
+
+ return this;
+ }
+
+ /**
+ * @since 2.0
+ */
+ public PapyrusEditorFixture openTable(IMultiDiagramEditor editor, final String name) {
+ activate(editor);
+
+ try {
+ ModelSet modelSet = ServiceUtils.getInstance().getModelSet(editor.getServicesRegistry());
+ PapyrusNattableModel notation = (PapyrusNattableModel) modelSet.getModel(PapyrusNattableModel.MODEL_ID);
+ Table table = notation.getTable(name);
+ ServiceUtils.getInstance().getService(IPageManager.class, editor.getServicesRegistry()).openPage(table);
+ flushDisplayEvents();
+
+ activateTable(editor, name);
+ } catch (Exception e) {
+ throw new IllegalStateException("Cannot initialize test", e); // NON-NLS-1
+ }
+
+ return this;
+ }
+
+ public String closeDiagram() {
+ String result = getActiveDiagramEditor().getDiagram().getName();
+ closeDiagram(editor, result);
+ return result;
+ }
+
+ public PapyrusEditorFixture closeDiagram(String name) {
+ return closeDiagram(editor, name);
+ }
+
+ /**
+ * @since 2.0
+ */
+ public PapyrusEditorFixture closeDiagram(IMultiDiagramEditor editor, final String name) {
+ try {
+ ModelSet modelSet = ServiceUtils.getInstance().getModelSet(editor.getServicesRegistry());
+ NotationModel notation = (NotationModel) modelSet.getModel(NotationModel.MODEL_ID);
+ Diagram diagram = notation.getDiagram(name);
+
+ // If the diagram was deleted, then so too was its page
+ if (diagram != null) {
+ ServiceUtils.getInstance().getService(IPageManager.class, editor.getServicesRegistry()).closePage(diagram);
+ flushDisplayEvents();
+ }
+ } catch (Exception e) {
+ throw new IllegalStateException("Cannot close diagram", e);
+ }
+
+ return this;
+ }
+
+ public DiagramEditorWithFlyOutPalette getActiveDiagramEditor() {
+ DiagramEditorWithFlyOutPalette result = activeDiagramEditor;
+
+ if (result == null) {
+ IEditorPart activeEditor = getWorkbenchPage().getActiveEditor();
+ if (activeEditor instanceof IMultiDiagramEditor) {
+ activeEditor = ((IMultiDiagramEditor) activeEditor).getActiveEditor();
+ if (activeEditor instanceof DiagramEditorWithFlyOutPalette) {
+ result = (DiagramEditorWithFlyOutPalette) activeEditor;
+ setActiveDiagramEditor(result);
+ }
+ }
+ }
+
+ assertThat("No diagram active", result, notNullValue());
+
+ return result;
+ }
+
+ public AbstractEMFNattableEditor getActiveTableEditor() {
+ AbstractEMFNattableEditor result = activeTableEditor;
+
+ if (result == null) {
+ IEditorPart activeEditor = getWorkbenchPage().getActiveEditor();
+ if (activeEditor instanceof IMultiDiagramEditor) {
+ activeEditor = ((IMultiDiagramEditor) activeEditor).getActiveEditor();
+ if (activeEditor instanceof AbstractEMFNattableEditor) {
+ result = (AbstractEMFNattableEditor) activeEditor;
+ setActiveTableEditor(result);
+ }
+ }
+ }
+
+ assertThat("No table active", result, notNullValue());
+
+ return result;
+ }
+
+ public DiagramEditPart getActiveDiagram() {
+ return getActiveDiagramEditor().getDiagramEditPart();
+ }
+
+ public INattableModelManager getActiveTableManager() {
+ return (INattableModelManager) getActiveTableEditor().getAdapter(INattableModelManager.class);
+ }
+
+ public DiagramEditPart getDiagram(String name) {
+ return getDiagram(editor, name);
+ }
+
+ /**
+ * @since 2.0
+ */
+ public DiagramEditPart getDiagram(IMultiDiagramEditor editor, final String name) {
+ final ISashWindowsContainer sashContainer = PlatformHelper.getAdapter(editor, ISashWindowsContainer.class);
+ final org.eclipse.papyrus.infra.core.sasheditor.editor.IPage[] matchedPage = { null };
+
+ sashContainer.visit(new IPageVisitor() {
+
+ @Override
+ public void accept(IEditorPage page) {
+ if (name.equals(page.getPageTitle()) && (page.getIEditorPart() instanceof DiagramEditorWithFlyOutPalette)) {
+ matchedPage[0] = page;
+ }
+ }
+
+ @Override
+ public void accept(IComponentPage page) {
+ // Pass
+ }
+ });
+
+ IEditorPage editorPage = TypeUtils.as(matchedPage[0], IEditorPage.class);
+ IDiagramWorkbenchPart diagramPart = (editorPage == null) ? null : TypeUtils.as(editorPage.getIEditorPart(), IDiagramWorkbenchPart.class);
+
+ // The lazy initialization, used in the patch for bug 519107, does not initialize the diagram edit part of UmlGmfDiagramEditor
+ // So we call the setFocus method here to initialize it manually (see patch for bug 521353)
+ if (null != diagramPart) {
+ if (null == diagramPart.getDiagramEditPart()) {
+ diagramPart.setFocus();
+ }
+ return diagramPart.getDiagramEditPart();
+ }
+ return null;
+ }
+
+ public EditPart findEditPart(EObject modelElement) {
+ return findEditPart(getActiveDiagramEditor(), modelElement);
+ }
+
+ /**
+ * @since 2.0
+ */
+ public EditPart findEditPart(IMultiDiagramEditor editor, EObject modelElement) {
+ IEditorPart activeEditor = editor.getActiveEditor();
+ assertThat("No diagram active", activeEditor, instanceOf(DiagramEditor.class));
+ return findEditPart((DiagramEditor) activeEditor, modelElement);
+ }
+
+ public EditPart findEditPart(IDiagramWorkbenchPart editor, EObject modelElement) {
+ DiagramEditPart diagram = editor.getDiagramEditPart();
+ return findEditPart(diagram, modelElement);
+ }
+
+
+ /**
+ * Find orphan edit part with a type.
+ *
+ * @param type
+ * the type
+ * @return the edits the part
+ */
+ public EditPart findOrphanEditPart(String type) {
+ IDiagramWorkbenchPart activeEditor = (IDiagramWorkbenchPart) editor.getActiveEditor();
+ EditPart result = null;
+ for (Iterator<View> views = Iterators.filter(activeEditor.getDiagram().eAllContents(), View.class); views.hasNext();) {
+ View next = views.next();
+ EObject element = next.getElement();
+ if (element == null && type.equals(next.getType())) {
+ result = (EditPart) activeEditor.getDiagramGraphicalViewer().getEditPartRegistry().get(next);
+ break;
+ }
+ }
+
+ return result;
+
+ }
+
+ /**
+ * Find orphan edit part.
+ *
+ * @return the edits the part
+ */
+ public EditPart findOrphanEditPart() {
+ IDiagramWorkbenchPart activeEditor = (IDiagramWorkbenchPart) editor.getActiveEditor();
+ EditPart result = null;
+ for (Iterator<View> views = Iterators.filter(activeEditor.getDiagram().eAllContents(), View.class); views.hasNext();) {
+ View next = views.next();
+
+ String type = next.getType();
+ EObject element = next.getElement();
+
+ if (element == null && !excludedTypeView.contains(type)) {
+ result = (EditPart) activeEditor.getDiagramGraphicalViewer().getEditPartRegistry().get(next);
+ break;
+ }
+ }
+
+ return result;
+
+ }
+
+ /**
+ * Find an edit-part for a model element in a particular {@code scope}.
+ *
+ * @param scope
+ * an edit part in which to search (its children) for an edit-part
+ * @param modelElement
+ * the model element visualized by the edit-part to search for
+ *
+ * @return the matching edit-part, or {@code null} if none is found in the {@code scope}
+ */
+ public EditPart findEditPart(EditPart scope, EObject modelElement) {
+ EditPart result = null;
+
+ View view = PlatformHelper.getAdapter(scope, View.class);
+ if ((view != null) && (view.getElement() == modelElement)) {
+ result = scope;
+ }
+
+ if (result == null) {
+ // Search children
+ for (Iterator<?> iter = scope.getChildren().iterator(); (result == null) && iter.hasNext();) {
+ result = findEditPart((EditPart) iter.next(), modelElement);
+ }
+ }
+
+ if ((result == null) && (scope instanceof GraphicalEditPart)) {
+ // Search edges
+ for (Iterator<?> iter = ((GraphicalEditPart) scope).getSourceConnections().iterator(); (result == null) && iter.hasNext();) {
+ result = findEditPart((EditPart) iter.next(), modelElement);
+ }
+ if (result == null) {
+ for (Iterator<?> iter = ((GraphicalEditPart) scope).getTargetConnections().iterator(); (result == null) && iter.hasNext();) {
+ result = findEditPart((EditPart) iter.next(), modelElement);
+ }
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * Require an edit-part for a model element in a particular {@code scope}.
+ *
+ * @param scope
+ * an edit part in which to search (its children) for an edit-part
+ * @param modelElement
+ * the model element visualized by the edit-part to search for
+ *
+ * @return the matching edit-part
+ *
+ * @throws AssertionError
+ * if the required edit-part is found in the {@code scope}
+ */
+ public EditPart requireEditPart(EditPart scope, EObject modelElement) {
+ EditPart result = findEditPart(scope, modelElement);
+ if (result == null) {
+ String label = getLabel(modelElement);
+ fail(String.format("No edit-part found for \"%s\" in %s", label, scope));
+ }
+ return result;
+ }
+
+ public String getLabel(EObject object) {
+ String result = null;
+
+ try {
+ EditingDomain domain = ServiceUtils.getInstance().getTransactionalEditingDomain(editor.getServicesRegistry());
+ if (domain instanceof AdapterFactoryEditingDomain) {
+ IItemLabelProvider labels = (IItemLabelProvider) ((AdapterFactoryEditingDomain) domain).getAdapterFactory().adapt(object, IItemLabelProvider.class);
+ if (labels != null) {
+ result = labels.getText(object);
+ }
+ }
+ } catch (ServiceException e) {
+ // Doesn't matter
+ }
+
+ if (result == null) {
+ result = String.valueOf(object);
+ }
+
+ return result;
+ }
+
+ public EditPart findEditPart(String name, Class<? extends NamedElement> type) {
+ return findEditPart(getActiveDiagramEditor(), name, type);
+ }
+
+ /**
+ * @since 2.0
+ */
+ public EditPart findEditPart(IMultiDiagramEditor editor, String name, Class<? extends NamedElement> type) {
+ IEditorPart activeEditor = editor.getActiveEditor();
+ assertThat("No diagram active", activeEditor, instanceOf(DiagramEditor.class));
+ return findEditPart((DiagramEditor) activeEditor, name, type);
+ }
+
+ public EditPart findEditPart(IDiagramWorkbenchPart editor, String name, Class<? extends NamedElement> type) {
+ EditPart result = null;
+
+ for (Iterator<View> views = Iterators.filter(editor.getDiagram().eAllContents(), View.class); views.hasNext();) {
+ View next = views.next();
+ EObject element = next.getElement();
+ if (type.isInstance(element) && name.equals(type.cast(element).getName())) {
+ result = (EditPart) editor.getDiagramGraphicalViewer().getEditPartRegistry().get(next);
+ break;
+ }
+ }
+
+ return result;
+ }
+
+ public void select(EditPart editPart) {
+ editPart.getViewer().getSelectionManager().appendSelection(editPart);
+ }
+
+ public void deselect(EditPart editPart) {
+ editPart.getViewer().getSelectionManager().deselect(editPart);
+ }
+
+ public void move(EditPart editPart, Point newLocation) {
+ execute(new ICommandProxy(new SetBoundsCommand(getEditingDomain(), "Move Node", editPart, newLocation)));
+ }
+
+ public void resize(EditPart editPart, Dimension newSize) {
+ execute(new ICommandProxy(new SetBoundsCommand(getEditingDomain(), "Resize Node", editPart, newSize)));
+ }
+
+ public void execute(org.eclipse.gef.commands.Command command) {
+ assertThat("Command not executable", command.canExecute(), is(true));
+ getActiveDiagramEditor().getDiagramEditDomain().getDiagramCommandStack().execute(command);
+ flushDisplayEvents();
+ }
+
+ @Override
+ public void execute(Command command) {
+ super.execute(command);
+ flushDisplayEvents();
+ }
+
+ @Override
+ public IStatus execute(IUndoableOperation operation, IProgressMonitor monitor, IAdaptable info) {
+ IStatus result = super.execute(operation, monitor, info);
+ flushDisplayEvents();
+ return result;
+ }
+
+ @Override
+ public void undo() {
+ super.undo();
+ flushDisplayEvents();
+ }
+
+ @Override
+ public void redo() {
+ super.redo();
+ flushDisplayEvents();
+ }
+
+ public PaletteViewer getPalette() {
+ return getPalette(getActiveDiagramEditor());
+ }
+
+ /**
+ * @since 2.0
+ */
+ public PaletteViewer getPalette(IMultiDiagramEditor editor) {
+ IEditorPart activeEditor = editor.getActiveEditor();
+ assertThat("No diagram active", activeEditor, instanceOf(DiagramEditor.class));
+ return getPalette((DiagramEditor) activeEditor);
+ }
+
+ public PaletteViewer getPalette(IDiagramWorkbenchPart editor) {
+ return editor.getDiagramEditPart().getViewer().getEditDomain().getPaletteViewer();
+ }
+
+ public void flushDisplayEvents() {
+ for (;;) {
+ try {
+ if (Display.getCurrent()!=null && !Display.getCurrent().readAndDispatch()) {
+ break;
+ }
+ } catch (Exception e) {
+ Bundle testBundle = FrameworkUtil.getBundle((testClass == null) ? PapyrusEditorFixture.class : testClass);
+ Platform.getLog(testBundle).log(new Status(IStatus.ERROR, testBundle.getSymbolicName(), "Uncaught exception in display runnable.", e));
+ }
+ }
+ }
+
+ public IViewPart getView(String id, boolean open) {
+ IViewPart result = null;
+
+ IWorkbenchPage wbPage = getWorkbenchPage();
+
+ try {
+ result = wbPage.findView(id);
+ if ((result == null) && open) {
+ result = wbPage.showView(id);
+ }
+
+ if (result != null) {
+ result.getSite().getPage().activate(result);
+ flushDisplayEvents();
+ }
+ } catch (PartInitException e) {
+ e.printStackTrace();
+ fail("Failed to show a view: " + id);
+ } finally {
+ flushDisplayEvents();
+ }
+
+ return result;
+ }
+
+ public void save() {
+ save(getEditor());
+ }
+
+ public void save(ISaveablePart part) {
+ if (part.isDirty()) {
+ try {
+ part.doSave(new NullProgressMonitor());
+ } catch (Exception e) {
+ e.printStackTrace();
+ fail("Failed to save editor/view: " + e.getLocalizedMessage());
+ } finally {
+ // Must flush display events because some steps (e.g. dependent editor reload)
+ // are done asynchronously in a UI job
+ flushDisplayEvents();
+ }
+ }
+ }
+
+ public void saveAll() {
+ try {
+ IWorkbenchPage page = editor.getSite().getPage();
+ page.saveAllEditors(false);
+ } finally {
+ // Must flush display events because some steps (e.g. dependent editor reload)
+ // are done asynchronously in a UI job
+ flushDisplayEvents();
+ }
+ }
+
+ public void splitEditorArea(IEditorPart editorToMove, boolean splitHorizontally) {
+ MPart editorPart = editorToMove.getSite().getService(MPart.class);
+ EModelService modelService = editorPart.getContext().get(EModelService.class);
+ MPartStack oldStack = (MPartStack) modelService.getContainer(editorPart);
+ MPartStack newStack = modelService.createModelElement(MPartStack.class);
+ modelService.insert(newStack, oldStack, splitHorizontally ? EModelService.RIGHT_OF : EModelService.BELOW, 0.5f);
+ newStack.getChildren().add(editorPart);
+
+ activate(editorToMove);
+ }
+
+ public List<IWorkbenchPart> getPartStack(IWorkbenchPart part) {
+ List<IWorkbenchPart> result;
+
+ MPart mpart = part.getSite().getService(MPart.class);
+ EModelService modelService = mpart.getContext().get(EModelService.class);
+ MPartStack stack = (MPartStack) modelService.getContainer(mpart);
+
+ result = Lists.newArrayListWithCapacity(stack.getChildren().size());
+ for (MPart next : Iterables.filter(stack.getChildren(), MPart.class)) {
+ IWorkbenchPart wbPart = next.getContext().get(IWorkbenchPart.class);
+ if (wbPart != null) {
+ result.add(wbPart);
+ }
+ }
+
+ return result;
+ }
+
+ protected final boolean hasRequiredViews() {
+ return getRequiredViews() != null;
+ }
+
+ protected final ShowView getRequiredViews() {
+ ShowView result = testDescription.getAnnotation(ShowView.class);
+
+ if (result == null) {
+ for (Class<?> clazz = testClass; (result == null) && (clazz != null) && (clazz != Object.class); clazz = clazz.getSuperclass()) {
+ result = clazz.getAnnotation(ShowView.class);
+ }
+ }
+
+ return result;
+ }
+
+ protected void openRequiredViews() {
+ IWorkbenchPage page = getWorkbenchPage();
+
+ for (ShowViewDescriptor next : ShowViewDescriptor.getDescriptors(getRequiredViews())) {
+ IViewPart part = page.findView(next.viewID());
+ if (part == null) {
+ // Must open it
+ try {
+ part = page.showView(next.viewID());
+ movePartRelativeTo(part, next.relativeTo(), next.location());
+
+ if (viewsToClose == null) {
+ viewsToClose = Lists.newArrayListWithExpectedSize(1);
+ }
+ viewsToClose.add(part);
+ } catch (PartInitException e) {
+ e.printStackTrace();
+ fail("Failed to open required view: " + e.getLocalizedMessage());
+ }
+ }
+ }
+
+ flushDisplayEvents();
+ }
+
+ private void movePartRelativeTo(IWorkbenchPart part, String relativeTo, int where) {
+ MPart mPart = part.getSite().getService(MPart.class);
+ EModelService modelService = mPart.getContext().get(EModelService.class);
+ MUIElement relativePart = modelService.find(relativeTo, modelService.getTopLevelWindowFor(mPart));
+ if (relativePart instanceof MPartSashContainerElement) {
+ MStackElement toMove = mPart;
+ MPlaceholder placeHolder = mPart.getCurSharedRef();
+ if (placeHolder != null) {
+ toMove = placeHolder;
+ }
+
+ if (where < 0) {
+ // Add it to the relative part's containing stack
+ if (relativePart instanceof MPart) {
+ MPart relativeMPart = (MPart) relativePart;
+ if (relativeMPart.getCurSharedRef() != null) {
+ // This is where the part is stacked
+ relativePart = relativeMPart.getCurSharedRef();
+ }
+ }
+ relativePart.getParent().getChildren().add(toMove);
+ } else {
+ // Insert it next to the relative part
+ MPartStack newStack = modelService.createModelElement(MPartStack.class);
+ newStack.getChildren().add(toMove);
+ modelService.insert(newStack, (MPartSashContainerElement) relativePart, where, 0.3f);
+ }
+ }
+ }
+
+ protected void closeRequiredViews() {
+ // Only close the Palette view if we opened it
+ if (viewsToClose != null) {
+ for (IViewPart closeMe : viewsToClose) {
+ closeMe.getSite().getPage().hideView(closeMe);
+ }
+ viewsToClose = null;
+ flushDisplayEvents();
+ }
+ }
+
+ private static final class ShowViewDescriptor {
+
+ private static final String DEFAULT_RELATIVE_TO = "org.eclipse.ui.editorss"; //$NON-NLS-1$
+
+ private static final ShowView.Location DEFAULT_LOCATION_EDITORS = ShowView.Location.RIGHT;
+
+ private static final ShowView.Location DEFAULT_LOCATION_VIEW = ShowView.Location.STACKED;
+
+ private final String viewID;
+
+ private final String relativeTo;
+
+ private final ShowView.Location location;
+
+ private ShowViewDescriptor(ShowView annotation, int index) {
+ this.viewID = annotation.value()[index];
+
+ String[] relativeTo = annotation.relativeTo();
+ this.relativeTo = (relativeTo.length == 0) ? null : (relativeTo.length == 1) ? relativeTo[0] : relativeTo[index];
+
+ ShowView.Location[] location = annotation.location();
+ this.location = (location.length == 0) ? null : (location.length == 1) ? location[0] : location[index];
+ }
+
+ static Iterable<ShowViewDescriptor> getDescriptors(final ShowView annotation) {
+ ImmutableList.Builder<ShowViewDescriptor> result = ImmutableList.builder();
+
+ String[] ids = annotation.value();
+ for (int i = 0; i < ids.length; i++) {
+ result.add(new ShowViewDescriptor(annotation, i));
+ }
+
+ return result.build();
+ }
+
+ String viewID() {
+ return viewID;
+ }
+
+ String relativeTo() {
+ return (relativeTo != null) ? relativeTo : DEFAULT_RELATIVE_TO;
+ }
+
+ int location() {
+ return ((location != null) ? location : (relativeTo == null) ? DEFAULT_LOCATION_EDITORS : DEFAULT_LOCATION_VIEW).toModelServiceLocation();
+ }
+ }
+
+ public PreferencesHint getPreferencesHint() {
+ PreferencesHint result = PreferencesHint.USE_DEFAULTS;
+
+ if (activeDiagramEditor != null) {
+ RootEditPart rootEditPart = activeDiagramEditor.getDiagramGraphicalViewer().getRootEditPart();
+ if (rootEditPart instanceof IDiagramPreferenceSupport) {
+ result = ((IDiagramPreferenceSupport) rootEditPart).getPreferencesHint();
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * @since 2.0
+ */
+ public void ensurePapyrusPerspective() {
+ Display.getDefault().syncExec(new Runnable() {
+
+ @Override
+ public void run() {
+ final String papyrus = "org.eclipse.papyrus.infra.core.perspective"; //$NON-NLS-1$
+ final IWorkbenchPage activePage = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
+ IPerspectiveDescriptor perspective = activePage.getPerspective();
+ if (!papyrus.equals(perspective.getId())) {
+ perspective = PlatformUI.getWorkbench().getPerspectiveRegistry().findPerspectiveWithId(papyrus);
+ if (perspective != null) {
+ activePage.setPerspective(perspective);
+ flushDisplayEvents();
+ }
+ }
+ }
+ });
+ }
+}
diff --git a/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/PluginResource.java b/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/PluginResource.java
new file mode 100644
index 00000000000..cd13354c59e
--- /dev/null
+++ b/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/PluginResource.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2014, 2015 CEA, Christian W. Damus, and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus (CEA) - Initial API and implementation
+ * Christian W. Damus - bug 469188
+ *
+ */
+package org.eclipse.papyrus.junit.utils.rules;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+
+/**
+ * Annotation indicating the bundle-relative path to one or more resources from which to load the test model of an {@link AbstractModelFixture}.
+ *
+ * @see AbstractModelFixture
+ * @see JavaResource
+ */
+@Target({ ElementType.METHOD, ElementType.TYPE })
+@Retention(RetentionPolicy.RUNTIME)
+public @interface PluginResource {
+
+ String[] value();
+
+ /** The bundle containing the referenced paths, if not the bundle containing the test. */
+ String bundle() default "";
+}
diff --git a/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/ProjectFixture.java b/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/ProjectFixture.java
new file mode 100644
index 00000000000..dd726710dbc
--- /dev/null
+++ b/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/ProjectFixture.java
@@ -0,0 +1,256 @@
+/*
+ * Copyright (c) 2014, 2015 CEA, Christian W. Damus, and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus (CEA) - Initial API and implementation
+ * Christian W. Damus - bug 451230
+ * Christian W. Damus - bug 468030
+ *
+ */
+package org.eclipse.papyrus.junit.utils.rules;
+
+import static org.hamcrest.CoreMatchers.notNullValue;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.fail;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IFolder;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.IResourceVisitor;
+import org.eclipse.core.resources.ResourceAttributes;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.emf.workspace.util.WorkspaceSynchronizer;
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.FrameworkUtil;
+
+
+/**
+ * A self-creating and self-destroying workspace project named according to the current test case.
+ */
+public class ProjectFixture implements TestRule {
+
+ private IProject project;
+
+ public ProjectFixture() {
+ super();
+ }
+
+ public final IProject getProject() {
+ return project;
+ }
+
+ public URI getURI(IPath path) {
+ return URI.createPlatformResourceURI(project.getFile(path).getFullPath().toString(), true);
+ }
+
+ public URI getURI(String path) {
+ return URI.createPlatformResourceURI(project.getFile(new Path(path)).getFullPath().toString(), true);
+ }
+
+ public IFile getFile(URI uri) {
+ return !uri.isPlatformResource() ? null : project.getWorkspace().getRoot().getFile(new Path(uri.toPlatformString(true)));
+ }
+
+ /**
+ * Creates a new file at the specified project-relative path with the contents of a bundle resource.
+ *
+ * @param relativeFilePath
+ * the project-relative path of the file to create
+ * @param classFromBundle
+ * the bundle in which its content is to be found
+ * @param resourcePath
+ * the path in the context bundle of the resource to copy
+ *
+ * @return the new file
+ *
+ * @throws IOException
+ * on any problem in creating the file
+ */
+ public IFile createFile(String relativeFilePath, Class<?> classFromBundle, String resourcePath) throws IOException {
+ IFile result;
+
+ Bundle bundle = FrameworkUtil.getBundle(classFromBundle);
+ URL resource = (bundle == null) ? null : bundle.getResource(resourcePath);
+ if (resource == null) {
+ throw new IOException("No such bundle resource: " + resourcePath);
+ }
+
+ IPath path = new Path(relativeFilePath);
+
+ try (InputStream input = resource.openStream()) {
+ createFolders(path.removeLastSegments(1));
+ result = project.getFile(path);
+ result.create(input, false, null);
+ } catch (CoreException e) {
+ if (e.getStatus().getException() instanceof IOException) {
+ throw (IOException) e.getStatus().getException();
+ } else if (e.getCause() instanceof IOException) {
+ throw (IOException) e.getCause();
+ }
+ throw new IOException("Failed to create file", e);
+ }
+
+ return result;
+ }
+
+ private void createFolders(IPath folderPath) throws CoreException {
+ if ((folderPath.segmentCount() > 0) && !folderPath.lastSegment().isEmpty()) {
+ createFolders(folderPath.removeLastSegments(1));
+ IFolder folder = project.getFolder(folderPath);
+ if (!folder.isAccessible()) {
+ folder.create(false, true, null);
+ }
+ }
+ }
+
+ /**
+ * Creates a new file in my project with the contents of a bundle resource.
+ *
+ * @param classFromBundle
+ * the bundle in which its content is to be found
+ * @param resourcePath
+ * the path in the context bundle of the resource to copy
+ *
+ * @return the new file, which will have the same name as the bundle resource and will be at the top level of the project
+ *
+ * @throws IOException
+ * on any problem in creating the file
+ *
+ * @see #createFile(String, Class, String)
+ */
+ public IFile createFile(Class<?> classFromBundle, String resourcePath) throws IOException {
+ return createFile(new Path(resourcePath).lastSegment(), classFromBundle, resourcePath);
+ }
+
+ @Override
+ public Statement apply(final Statement base, Description description) {
+ String name = description.getMethodName();
+ if (name == null) {
+ // We are used as a class rule, then
+ name = description.getClassName();
+ if (name != null) {
+ name = name.substring(name.lastIndexOf('.') + 1);
+ }
+ }
+
+ final String projectName = name;
+ return new Statement() {
+
+ @Override
+ public void evaluate() throws Throwable {
+ createProject(projectName);
+
+ try {
+ base.evaluate();
+ } finally {
+ deleteProject();
+ }
+ }
+ };
+ }
+
+ protected void createProject(String name) throws CoreException {
+ project = ResourcesPlugin.getWorkspace().getRoot().getProject(name);
+
+ if (project.exists()) {
+ // Start clean, if we can
+ deleteProject();
+ }
+
+ if (!project.exists()) {
+ project.create(null);
+ }
+
+ if (!project.isOpen()) {
+ project.open(null);
+ }
+
+ project.refreshLocal(IResource.DEPTH_INFINITE, null);
+ }
+
+ protected void deleteProject() {
+ try {
+ project.refreshLocal(IResource.DEPTH_INFINITE, null);
+
+ // Make sure that we can delete everything
+ project.accept(new IResourceVisitor() {
+
+ @Override
+ public boolean visit(IResource resource) throws CoreException {
+ switch (resource.getType()) {
+ case IResource.FILE:
+ case IResource.FOLDER:
+ ensureWritable(resource);
+ break;
+ }
+
+ return true;
+ }
+ });
+
+ project.delete(true, null);
+ } catch (CoreException e) {
+ e.printStackTrace();
+ // leave the project. We may end up re-using it, who knows?
+ }
+ }
+
+ protected void ensureWritable(IResource resource) throws CoreException {
+ ResourceAttributes attr = resource.getResourceAttributes();
+ if (attr.isReadOnly()) {
+ attr.setReadOnly(false);
+ resource.setResourceAttributes(attr);
+ }
+ }
+
+ public void setReadOnly(String projectRelativePath) {
+ setReadOnly(new Path(projectRelativePath));
+ }
+
+ public void setReadOnly(IPath projectRelativePath) {
+ setReadOnly(project.findMember(projectRelativePath));
+ }
+
+ public void setReadOnly(Resource resource) {
+ IFile file = WorkspaceSynchronizer.getFile(resource);
+ assertThat("Cannot set non-workspace resource read-only", file, notNullValue());
+ setReadOnly(file);
+ }
+
+ public void setReadOnly(IResource resource) {
+ setReadOnly(resource, true);
+ }
+
+ public void setReadOnly(IResource resource, boolean readOnly) {
+ ResourceAttributes attr = resource.getResourceAttributes();
+
+ if (attr.isReadOnly() != readOnly) {
+ attr.setReadOnly(readOnly);
+
+ try {
+ resource.setResourceAttributes(attr);
+ } catch (CoreException e) {
+ e.getLocalizedMessage();
+ fail(String.format("Failed to make workspace resource %s: %s", readOnly ? "read-only" : "writable", e.getLocalizedMessage()));
+ }
+ }
+ }
+}
diff --git a/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/ResourceSetFixture.java b/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/ResourceSetFixture.java
new file mode 100644
index 00000000000..23b14c2a334
--- /dev/null
+++ b/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/ResourceSetFixture.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2014 CEA and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus (CEA) - Initial API and implementation
+ *
+ */
+package org.eclipse.papyrus.junit.utils.rules;
+
+import org.eclipse.emf.common.command.BasicCommandStack;
+import org.eclipse.emf.ecore.resource.ResourceSet;
+import org.eclipse.emf.edit.domain.AdapterFactoryEditingDomain;
+import org.eclipse.emf.edit.domain.EditingDomain;
+import org.eclipse.emf.edit.provider.ComposedAdapterFactory;
+
+
+/**
+ * A simple non-transactional {@link ResourceSet} fixture.
+ */
+public class ResourceSetFixture extends AbstractModelFixture<EditingDomain> {
+
+ public ResourceSetFixture() {
+ super();
+ }
+
+ protected EditingDomain createEditingDomain() {
+ return new AdapterFactoryEditingDomain(new ComposedAdapterFactory(ComposedAdapterFactory.Descriptor.Registry.INSTANCE), new BasicCommandStack());
+ }
+}
diff --git a/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/RuleUtil.java b/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/RuleUtil.java
new file mode 100644
index 00000000000..8ff16363b7c
--- /dev/null
+++ b/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/RuleUtil.java
@@ -0,0 +1,132 @@
+/*****************************************************************************
+ * Copyright (c) 2014 CEA LIST and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * CEA LIST - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.junit.utils.rules;
+
+import static org.junit.Assert.fail;
+
+import java.util.concurrent.Callable;
+
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+
+/**
+ * Utilities for working with JUnit {@linkplain TestRule rules}.
+ */
+public class RuleUtil {
+
+ private RuleUtil() {
+ super();
+ }
+
+ /**
+ * Ad hoc invocation of an operation wrapped in the start/finish behaviour of a JUnit rule.
+ *
+ * @param run
+ * the operation to run
+ * @param rule
+ * the rule to wrap it in
+ *
+ * @throws Exception
+ * on any exception thrown by the runnable or the rule
+ */
+ public static void runWith(Runnable run, TestRule rule) throws Exception {
+ callWith(call(run), rule);
+ }
+
+ /**
+ * Safe ad hoc invocation of an operation wrapped in the start/finish behaviour of a JUnit rule.
+ * Fails JUnitishly on any exception in the callable or the rule.
+ *
+ * @param run
+ * the operation to run
+ * @param rule
+ * the rule to wrap it in
+ */
+ public static void safeRunWith(Runnable run, TestRule rule) throws Exception {
+ safeCallWith(call(run), rule);
+ }
+
+ static Callable<?> call(final Runnable run) {
+ return new Callable<Void>() {
+
+ public Void call() throws Exception {
+ run.run();
+ return null;
+ }
+ };
+ }
+
+ /**
+ * Ad hoc invocation of a callable wrapped in the start/finish behaviour of a JUnit rule.
+ *
+ * @param callable
+ * the callable to execute
+ * @param rule
+ * the rule to wrap it in
+ *
+ * @throws Exception
+ * on any exception thrown by the callable or the rule
+ */
+ public static <V> V callWith(Callable<V> callable, TestRule rule) throws Exception {
+ class CallableStatement extends Statement {
+
+ final Callable<V> callable;
+
+ V result;
+
+ CallableStatement(Callable<V> callable) {
+ this.callable = callable;
+ }
+
+ @Override
+ public void evaluate() throws Throwable {
+ result = callable.call();
+ }
+ }
+
+ try {
+ CallableStatement statement = new CallableStatement(callable);
+ rule.apply(statement, Description.EMPTY).evaluate();
+ return statement.result;
+ } catch (Throwable t) {
+ if(t instanceof Exception) {
+ throw (Exception)t;
+ } else {
+ throw (Error)t;
+ }
+ }
+ }
+
+ /**
+ * Safe ad hoc invocation of a callable wrapped in the start/finish behaviour of a JUnit rule.
+ * Fails JUnitishly on any exception in the callable or the rule.
+ *
+ * @param callable
+ * the callable to execute
+ * @param rule
+ * the rule to wrap it in
+ */
+ public static <V> V safeCallWith(Callable<V> callable, TestRule rule) {
+ try {
+ return callWith(callable, rule);
+ } catch (Exception e) {
+ e.printStackTrace();
+ fail("Failed to invoke callable with rule: " + e.getLocalizedMessage());
+ return null; // Unreachable
+ }
+ }
+
+}
diff --git a/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/ServiceRegistryModelSetFixture.java b/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/ServiceRegistryModelSetFixture.java
new file mode 100644
index 00000000000..cf90e0274b2
--- /dev/null
+++ b/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/ServiceRegistryModelSetFixture.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2014 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ */
+package org.eclipse.papyrus.junit.utils.rules;
+
+import org.eclipse.papyrus.infra.core.services.ExtensionServicesRegistry;
+import org.eclipse.papyrus.infra.core.services.ServiceException;
+import org.eclipse.papyrus.infra.core.services.ServicesRegistry;
+
+
+/**
+ * A model-set fixture that uses a fully configured service registry to provide the model set.
+ */
+public class ServiceRegistryModelSetFixture extends ModelSetFixture {
+
+ public ServiceRegistryModelSetFixture() {
+ super();
+ }
+
+ @Override
+ protected ServicesRegistry createServiceRegistry() throws Exception {
+ ServicesRegistry result = new ExtensionServicesRegistry(org.eclipse.papyrus.infra.core.Activator.PLUGIN_ID);
+
+ try {
+ result.startRegistry();
+ } catch (ServiceException e) {
+ // Try to continue with the test, anyways. This is expected in the test environment
+ }
+
+ return result;
+ }
+}
diff --git a/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/ShowView.java b/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/ShowView.java
new file mode 100644
index 00000000000..103db0b1d37
--- /dev/null
+++ b/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/ShowView.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2014 CEA and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus (CEA) - Initial API and implementation
+ *
+ */
+package org.eclipse.papyrus.junit.utils.rules;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import org.eclipse.e4.ui.workbench.modeling.EModelService;
+
+
+/**
+ * An annotation on tests using the {@link PapyrusEditorFixture} that need the palette view to be open before initializing the
+ * test (which generally entails opening one or more editors).
+ */
+@Target({ ElementType.METHOD, ElementType.TYPE })
+@Retention(RetentionPolicy.RUNTIME)
+public @interface ShowView {
+
+ /** The IDs of the views to show before the editor is opened. */
+ String[] value();
+
+ /**
+ * The IDs of workbench parts relative to which the views specified by the annotation are to be shown. If unspecified,
+ * the default is the workbench's editor area. If exactly part ID is specified, it is used for all views. Otherwise, a
+ * corresponding value is required for each view ID to be shown.
+ */
+ String[] relativeTo() default {};
+
+ /**
+ * The relative locations of the views to show. If unspecified, the default is {@link Location#STACKED} when the {@linkplain #relativeTo()
+ * relative part} is a view, otherwise {@link Location#RIGHT} when the relative part is the editor area.
+ * If exactly one value is specified, it is used for all views. Otherwise, a corresponding value is
+ * required for each view ID.
+ */
+ Location[] location() default {};
+
+ /**
+ * Enumeration of locations in which to open a view relative to some other workbench part.
+ */
+ enum Location {
+ /** Stacked with the relative part. */
+ STACKED(-1),
+ /** To the left of the relative part. */
+ LEFT(EModelService.LEFT_OF),
+ /** To the right of the relative part. */
+ RIGHT(EModelService.RIGHT_OF),
+ /** Above the relative part. */
+ ABOVE(EModelService.ABOVE),
+ /** Below the relative part. */
+ BELOW(EModelService.BELOW);
+
+ private final int modelServiceLocation;
+
+ private Location(int modelServiceLocation) {
+ this.modelServiceLocation = modelServiceLocation;
+ }
+
+ public int toModelServiceLocation() {
+ return modelServiceLocation;
+ }
+ }
+}
diff --git a/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/ShowViewRule.java b/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/ShowViewRule.java
new file mode 100644
index 00000000000..0459c73a971
--- /dev/null
+++ b/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/ShowViewRule.java
@@ -0,0 +1,72 @@
+/*****************************************************************************
+ * Copyright (c) 2014 CEA LIST and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * CEA LIST - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.junit.utils.rules;
+
+import static org.junit.Assert.fail;
+
+import org.eclipse.ui.IViewPart;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.PlatformUI;
+import org.junit.rules.TestWatcher;
+import org.junit.runner.Description;
+
+
+/**
+ * A rule that ensures a view is showing for the duration of a test.
+ */
+public class ShowViewRule extends TestWatcher {
+
+ private final String viewID;
+
+ private IViewPart view;
+
+ public ShowViewRule(String viewID) {
+ super();
+
+ this.viewID = viewID;
+ }
+
+ @Override
+ protected void starting(Description description) {
+ IWorkbench bench = PlatformUI.getWorkbench();
+ IWorkbenchWindow window = bench.getActiveWorkbenchWindow();
+ if(window == null) {
+ window = bench.getWorkbenchWindows()[0];
+ }
+
+ IWorkbenchPage page = window.getActivePage();
+ view = page.findView(viewID);
+
+ if(view == null) {
+ try {
+ view = page.showView(viewID);
+ } catch (PartInitException e) {
+ fail(String.format("Failed to show view %s: %s", viewID, e.getLocalizedMessage()));
+ }
+ }
+ }
+
+ @Override
+ protected void finished(Description description) {
+ if(view != null) {
+ // Hide it again, because we showed it in the first place
+ view.getSite().getPage().hideView(view);
+ }
+
+ view = null;
+ }
+}
diff --git a/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/StandaloneResourceSetFixture.java b/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/StandaloneResourceSetFixture.java
new file mode 100644
index 00000000000..2bc1745a2df
--- /dev/null
+++ b/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/StandaloneResourceSetFixture.java
@@ -0,0 +1,179 @@
+/*****************************************************************************
+ * Copyright (c) 2015 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.junit.utils.rules;
+
+import static org.hamcrest.CoreMatchers.notNullValue;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+import java.net.URL;
+import java.util.Iterator;
+
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.plugin.EcorePlugin;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.emf.ecore.resource.ResourceSet;
+import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
+import org.eclipse.papyrus.junit.utils.JUnitUtils;
+import org.junit.rules.TestWatcher;
+import org.junit.runner.Description;
+
+import com.google.common.collect.Iterables;
+
+/**
+ * A {@link ResourceSet} fixture rule that is compatible with stand-alone JUnit
+ * execution (not in an Eclipse instance). It uses the {@link JavaResource}
+ * annotation (only, not also {@link PluginResource}) to identify test resources
+ * to load into the resource set on set-up.
+ *
+ * @param <T>
+ * the kind of model fixture element to load
+ */
+public class StandaloneResourceSetFixture<T extends EObject> extends TestWatcher {
+
+ private final Class<? extends T> modelType;
+
+ private ResourceSet resourceSet;
+ private Resource resource;
+ private T model;
+
+ /**
+ * Initializes me with the kind of model fixture element to load.
+ *
+ * @param modelType
+ * the model fixture element's type
+ */
+ public StandaloneResourceSetFixture(Class<? extends T> modelType) {
+ super();
+
+ this.modelType = modelType;
+ }
+
+ /**
+ * Obtains the resource set in which the {@linkplain #getModel() model fixture} is loaded.
+ *
+ * @see #getModel()
+ */
+ public ResourceSet getResourceSet() {
+ return resourceSet;
+ }
+
+ /**
+ * Obtains the resource containing the {@linkplain #getModel() model fixture}.
+ *
+ * @see #getModel()
+ */
+ public Resource getResource() {
+ return resource;
+ }
+
+ public Resource getResource(URI uri, boolean loadOnDemand) {
+ return getResourceSet().getResource(uri, loadOnDemand);
+ }
+
+ /**
+ * Obtains the model fixture.
+ */
+ public T getModel() {
+ return model;
+ }
+
+ /**
+ * Obtains the root model element of the specified type from my resource set.
+ *
+ * @param modelType
+ * the type of model to retrieve, or {@code null} if none is found
+ */
+ public <E extends EObject> E getModel(Class<E> modelType) {
+ E result = null;
+
+ Resource resource;
+ for (Iterator<Resource> iter = resourceSet.getResources().iterator(); (result == null) && iter.hasNext();) {
+ resource = iter.next();
+ result = Iterables.getFirst(Iterables.filter(resource.getContents(), modelType), null);
+ }
+
+ return result;
+ }
+
+ public static <T extends EObject> StandaloneResourceSetFixture<T> create(Class<T> modelType) {
+ return new StandaloneResourceSetFixture<>(modelType);
+ }
+
+ @Override
+ protected void starting(Description description) {
+ JavaResource annotation = JUnitUtils.getAnnotation(description, JavaResource.class);
+ assertThat("No @JavaResource annotation found in test case.", annotation, notNullValue());
+
+ resourceSet = new ResourceSetImpl();
+
+ if (!EcorePlugin.IS_ECLIPSE_RUNNING) {
+ // EMF ensures that additional invocations have no effect
+ EcorePlugin.ExtensionProcessor.process(null);
+ }
+
+ final Class<?> testClass = JUnitUtils.getTestClass(description);
+ for (String next : annotation.value()) {
+ resourceSet.getResource(getTestResourceURI(next, testClass), true);
+ }
+
+ model = getModel(modelType);
+
+ assertThat("No model of type " + modelType.getSimpleName() + " loaded.", model, notNullValue());
+ resource = model.eResource();
+ }
+
+ @Override
+ protected void finished(Description description) {
+ for (Iterator<Resource> iter = resourceSet.getResources().iterator(); iter.hasNext();) {
+ Resource next = iter.next();
+
+ next.unload();
+ iter.remove();
+
+ next.eAdapters().clear();
+ }
+
+ resourceSet.eAdapters().clear();
+ resourceSet = null;
+ resource = null;
+ model = null;
+ }
+
+ /**
+ * Obtains the URI of a test resource.
+ *
+ * @param path
+ * the path of the test resource. Absolute paths are searched on the classpath
+ * and relative paths are searched relative to the given {@code context} class
+ * @param context
+ * the context class for resolution of relative resource paths
+ *
+ * @return the URI of the referenced test resource
+ */
+ protected URI getTestResourceURI(String path, Class<?> context) {
+ URL resultURL;
+
+ IPath resourcePath = new Path(path);
+ if (resourcePath.isAbsolute()) {
+ resultURL = context.getClassLoader().getResource(path);
+ } else {
+ resultURL = context.getResource(path);
+ }
+
+ return URI.createURI(resultURL.toString(), true);
+ }
+}
diff --git a/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/UIThread.java b/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/UIThread.java
new file mode 100644
index 00000000000..4f7a1bd9d25
--- /dev/null
+++ b/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/UIThread.java
@@ -0,0 +1,31 @@
+/*****************************************************************************
+ * Copyright (c) 2016 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.junit.utils.rules;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Used with the {@link UIThreadRule} to annotated a test that requires the UI
+ * thread, where perhaps others in the same scope do not.
+ */
+@Target({ ElementType.METHOD, ElementType.TYPE })
+@Retention(RetentionPolicy.RUNTIME)
+@Inherited
+public @interface UIThread {
+ // Empty annotation
+}
diff --git a/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/UIThreadRule.java b/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/UIThreadRule.java
new file mode 100644
index 00000000000..a22f6652263
--- /dev/null
+++ b/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/rules/UIThreadRule.java
@@ -0,0 +1,94 @@
+/*****************************************************************************
+ * Copyright (c) 2016 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.junit.utils.rules;
+
+import org.eclipse.papyrus.junit.utils.JUnitUtils;
+import org.eclipse.swt.widgets.Display;
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+/**
+ * A JUnit rule that runs its test synchronously on the UI thread.
+ * This should be used only when the test manipulates API that
+ * require the current thread to be the UI thread.
+ */
+public class UIThreadRule implements TestRule {
+
+ private final boolean requireAnnotation;
+
+ /**
+ * Initializes me without the requirement for any annotation: all tests
+ * in my scope will run on the UI thread.
+ */
+ public UIThreadRule() {
+ this(false);
+ }
+
+ /**
+ * Initializes me with the requirement that individual tests needin the UI
+ * thread be annotated with {@link UIThread @UIThread}.
+ *
+ * @param requireAnnotation
+ */
+ public UIThreadRule(boolean requireAnnotation) {
+ super();
+
+ this.requireAnnotation = requireAnnotation;
+ }
+
+ @Override
+ public Statement apply(final Statement base, Description description) {
+ if (!requiresUIThread(description)) {
+ return base; // Nothing to do for this test
+ } else {
+ return new Statement() {
+
+ @Override
+ public void evaluate() throws Throwable {
+ final Throwable[] caught = { null };
+
+ final Runnable runTest = new Runnable() {
+
+ @Override
+ public void run() {
+ try {
+ base.evaluate();
+ } catch (Throwable t) {
+ caught[0] = t;
+ }
+ }
+ };
+
+ if (Display.getCurrent() != null) {
+ // Just run it
+ runTest.run();
+ } else {
+ // Run it on the UI thread
+ Display.getDefault().syncExec(runTest);
+ }
+
+ if (caught[0] != null) {
+ throw caught[0];
+ }
+ }
+ };
+ }
+ }
+
+ private boolean requiresUIThread(Description description) {
+ return !requireAnnotation
+ || JUnitUtils.getAnnotation(description, UIThread.class) != null;
+ }
+}
diff --git a/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/tests/AbstractEMFResourceTest.java b/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/tests/AbstractEMFResourceTest.java
new file mode 100644
index 00000000000..69066e9706d
--- /dev/null
+++ b/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/tests/AbstractEMFResourceTest.java
@@ -0,0 +1,57 @@
+/*****************************************************************************
+ * Copyright (c) 2015 CEA LIST and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * CEA LIST - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.junit.utils.tests;
+
+import java.util.List;
+
+import org.eclipse.emf.common.util.Diagnostic;
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
+import org.eclipse.emf.ecore.util.Diagnostician;
+import org.eclipse.papyrus.junit.framework.classification.tests.AbstractPapyrusTest;
+import org.junit.Assert;
+
+/**
+ * Abstract test class for all EMF-based configuration models (property view, palettes, etc.)
+ */
+public abstract class AbstractEMFResourceTest extends AbstractPapyrusTest {
+
+ /**
+ * URI of the EMF resource to test
+ *
+ * @return
+ */
+ public abstract String getFileUri();
+
+ /**
+ * do the validation checks on the EMF resource
+ */
+ protected void doValidateResource() {
+ URI createPlatformPluginURI = URI.createPlatformPluginURI(getFileUri(), true);
+ Resource resource = new ResourceSetImpl().getResource(createPlatformPluginURI, true);
+ Diagnostic diagnostic = Diagnostician.INSTANCE.validate(resource.getContents().get(0));
+ Assert.assertEquals("The constraint model is not valid: " + printDiagnostic(diagnostic), Diagnostic.OK, diagnostic.getSeverity());
+ }
+
+ // FIXME : Something should exist in API to do that
+ protected String printDiagnostic(Diagnostic diagnostic) {
+ String message = diagnostic.getMessage();
+ List<Diagnostic> children = diagnostic.getChildren();
+ for (Diagnostic diagnostic2 : children) {
+ message += "\n" + diagnostic2.getMessage();
+ }
+ return message;
+ }
+}
diff --git a/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/tests/AbstractEditorTest.java b/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/tests/AbstractEditorTest.java
new file mode 100644
index 00000000000..e143eaf99b7
--- /dev/null
+++ b/tests/junit/framework/org.eclipse.papyrus.junit.utils/src/org/eclipse/papyrus/junit/utils/tests/AbstractEditorTest.java
@@ -0,0 +1,244 @@
+/*****************************************************************************
+ * Copyright (c) 2013 CEA LIST.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Initial API and implementation
+ *****************************************************************************/
+package org.eclipse.papyrus.junit.utils.tests;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.emf.transaction.TransactionalEditingDomain;
+import org.eclipse.papyrus.infra.core.resource.AbstractBaseModel;
+import org.eclipse.papyrus.infra.core.resource.IModel;
+import org.eclipse.papyrus.infra.core.resource.ModelSet;
+import org.eclipse.papyrus.infra.core.sashwindows.di.service.IPageManager;
+import org.eclipse.papyrus.infra.core.services.ServiceException;
+import org.eclipse.papyrus.infra.core.services.ServicesRegistry;
+import org.eclipse.papyrus.infra.ui.editor.IMultiDiagramEditor;
+import org.eclipse.papyrus.junit.framework.classification.tests.AbstractPapyrusTest;
+import org.eclipse.papyrus.junit.utils.Activator;
+import org.eclipse.papyrus.junit.utils.EditorUtils;
+import org.eclipse.papyrus.junit.utils.PapyrusProjectUtils;
+import org.eclipse.papyrus.junit.utils.ProjectUtils;
+import org.eclipse.papyrus.views.modelexplorer.ModelExplorerPage;
+import org.eclipse.papyrus.views.modelexplorer.ModelExplorerPageBookView;
+import org.eclipse.papyrus.views.modelexplorer.ModelExplorerView;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IViewPart;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.part.IPage;
+import org.junit.After;
+import org.junit.Assert;
+import org.osgi.framework.Bundle;
+
+
+public abstract class AbstractEditorTest extends AbstractPapyrusTest {
+
+ /** the id of the model explorer */
+ public static final String MODELEXPLORER_VIEW_ID = "org.eclipse.papyrus.views.modelexplorer.modelexplorer"; //$NON-NLS-1$
+
+
+ protected IMultiDiagramEditor editor;
+
+ protected IProject project;
+
+
+ protected ModelExplorerView modelExplorerView;
+
+ protected IFile diModelFile;
+ /**
+ *
+ * @return
+ * the current bundle
+ */
+ protected Bundle getBundle() {
+ return Activator.getDefault().getBundle();
+ }
+
+ /**
+ * Create a new test project
+ * @param projectName
+ */
+ protected IProject createProject(String projectName) throws Exception {
+ project = ProjectUtils.createProject(projectName);
+ return project;
+ }
+
+ /**
+ * Initializes this editor
+ * Fails or throws an exception if an error occurs
+ *
+ * @param projectName
+ * the project that will be created at runtime to execute the test
+ * @param modelName
+ * the model that will be copied and test executed on.
+ * @param bundle
+ * the source bundle where the model is stored
+ */
+ protected void initModel(String projectName, String modelName, Bundle bundle) throws Exception {
+ createProject(projectName);
+ initModel(modelName, bundle);
+ }
+
+ /**
+ * Initializes this editor. Should be called, after a previous invocation of createProject()
+ *
+ * @param modelName
+ * @param bundle
+ * @throws Exception
+ */
+ protected void initModel(String modelName, Bundle bundle) throws Exception {
+ this.diModelFile = PapyrusProjectUtils.copyPapyrusModel(project, bundle, getSourcePath(), modelName);
+ Display.getDefault().syncExec(new Runnable() {
+
+ public void run() {
+ try {
+ editor = EditorUtils.openPapyrusEditor(diModelFile);
+ } catch (Exception ex) {
+ Activator.log.error(ex);
+ Assert.fail(ex.getMessage());
+ }
+ }
+ });
+
+ Assert.assertNotNull(editor);
+ }
+
+
+ /**
+ * copy a model into the workspace, e.g. a profile that is required by the test model
+ *
+ * @param projectName
+ * the project that will be created at runtime to execute the test
+ * @param modelName
+ * the model that will be copied and test executed on.
+ * @param bundle
+ * the source bundle where the model is stored
+ */
+ protected void copyModel(String modelName, Bundle bundle) throws Exception {
+ PapyrusProjectUtils.copyPapyrusModel(project, bundle, getSourcePath(), modelName);
+ }
+
+ @After
+ public void dispose() throws Exception {
+ if(editor != null) {
+ Display.getDefault().syncExec(new Runnable() {
+
+ public void run() {
+ ((IEditorPart)editor).getSite().getPage().closeEditor(editor, false);
+ }
+ });
+
+ editor = null;
+ }
+
+ if(project != null) {
+ project.delete(true, new NullProgressMonitor());
+ project = null;
+ }
+ }
+
+
+ public ModelExplorerView getModelExplorerView() {
+
+ Display.getDefault().syncExec(new Runnable() {
+
+ public void run() {
+ IWorkbenchWindow activeWorkbenchWindow = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
+
+ // we look for the modelexplorer
+ IViewPart modelexplorer;
+ try {
+ modelexplorer = activeWorkbenchWindow.getActivePage().showView(MODELEXPLORER_VIEW_ID);
+ } catch (PartInitException ex) {
+ ex.printStackTrace(System.out);
+ return;
+ }
+ ModelExplorerPageBookView view = (ModelExplorerPageBookView)modelexplorer;
+ IPage currentPage = view.getCurrentPage();
+ ModelExplorerPage page = (ModelExplorerPage)currentPage;
+ IViewPart viewer = page.getViewer();
+ modelExplorerView = (ModelExplorerView)viewer;
+
+ }
+ });
+ return modelExplorerView;
+ }
+
+ /**
+ *
+ * @return the current UML model
+ */
+ protected org.eclipse.uml2.uml.Package getRootUMLModel() {
+
+ IModel umlIModel;
+ try {
+ umlIModel = getModelSet().getModel("org.eclipse.papyrus.infra.core.resource.uml.UmlModel"); //$NON-NLS-1$
+
+ AbstractBaseModel umlModel = null;
+ if(umlIModel instanceof AbstractBaseModel) {
+ umlModel = (AbstractBaseModel)umlIModel;
+ }
+
+ Assert.assertFalse("umlRessource contains nothing", umlModel.getResource().getContents().isEmpty());
+ Object root = umlModel.getResource().getContents().get(0);
+ Assert.assertFalse("the root of UML model is not a package", root instanceof Package);
+
+ return (org.eclipse.uml2.uml.Package)root;
+ } catch (ServiceException e) {
+ Assert.fail(e.getMessage());
+ }
+ // not reachable due to asserts above (no check by caller)
+ return null;
+
+ }
+
+ protected IPageManager getPageManager() throws ServiceException {
+ return getServicesRegistry().getService(IPageManager.class);
+ }
+
+ protected ServicesRegistry getServicesRegistry() throws ServiceException {
+ return editor.getServicesRegistry();
+ }
+
+ protected TransactionalEditingDomain getTransactionalEditingDomain() throws ServiceException {
+ return getServicesRegistry().getService(TransactionalEditingDomain.class);
+ }
+
+ protected ModelSet getModelSet() throws ServiceException {
+ return getServicesRegistry().getService(ModelSet.class);
+ }
+
+ /**
+ * The path to the source model folder
+ *
+ * @return
+ */
+ protected abstract String getSourcePath();
+
+ protected void flushDisplayEvents() {
+ for(;;) {
+ try {
+ if(!Display.getCurrent().readAndDispatch()) {
+ break;
+ }
+ } catch (Exception e) {
+ Bundle testBundle = getBundle();
+ Platform.getLog(testBundle).log(new Status(IStatus.ERROR, testBundle.getSymbolicName(), "Uncaught exception in display runnable.", e));
+ }
+ }
+ }
+}
diff --git a/tests/junit/framework/pom.xml b/tests/junit/framework/pom.xml
new file mode 100755
index 00000000000..f4bd75c8042
--- /dev/null
+++ b/tests/junit/framework/pom.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<project>
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.eclipse.papyrus</groupId>
+ <artifactId>org.eclipse.papyrus.dev.releng</artifactId>
+ <version>3.0.0-SNAPSHOT</version>
+ <relativePath>../../../releng/dev/pom.xml</relativePath>
+ </parent>
+ <groupId>org.eclipse.papyrus.tests</groupId>
+ <artifactId>org.eclipse.papyrus.tests.junit-framework</artifactId>
+ <version>0.0.1-SNAPSHOT</version>
+ <packaging>pom</packaging>
+ <description>The top container of the junit test framework.</description>
+
+ <modules>
+ <module>org.eclipse.papyrus.junit.framework</module>
+ <module>org.eclipse.papyrus.junit.utils</module>
+ </modules>
+
+</project> \ No newline at end of file

Back to the top