Test different import locations

Import location should be relative to the importing document's URI.
Correct some test resources to reflect this, breaking the
corresponding tests. Add test cases with different kinds of import
locations (mostly relative, but also one case with an absolute
location).

Most tests have two versions, one with absolute URIs and one with
relative URIs for the BPMNResource, as the current implementation
handles only the absolute case correctly.

In total, 16 tests are failing. Subsequent commits will fix this.

Bug: 330017
diff --git a/org.eclipse.bpmn2.tests/res/qname_prefixNs_defaultNotResolvable.bpmn2 b/org.eclipse.bpmn2.tests/res/qname_prefixNs_defaultNotResolvable.bpmn2
index a4e0c81..46f7f35 100644
--- a/org.eclipse.bpmn2.tests/res/qname_prefixNs_defaultNotResolvable.bpmn2
+++ b/org.eclipse.bpmn2.tests/res/qname_prefixNs_defaultNotResolvable.bpmn2
@@ -4,7 +4,7 @@
     targetNamespace="urn:modelA"

     xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:b="urn:modelB">

   <import importType="http://www.omg.org/spec/BPMN/20100524/MODEL" 

-    location="res/qname_prefixNs_referenced.bpmn2" namespace="urn:modelB"/>

+    location="qname_prefixNs_referenced.bpmn2" namespace="urn:modelB"/>

   <collaboration id="colId"/>

   <process id="proc1Id" definitionalCollaborationRef="colId">

     <supports>b:proc2Id</supports>

diff --git a/org.eclipse.bpmn2.tests/res/qname_prefixNs_inverse.bpmn2 b/org.eclipse.bpmn2.tests/res/qname_prefixNs_inverse.bpmn2
index e3f54c2..22defab 100644
--- a/org.eclipse.bpmn2.tests/res/qname_prefixNs_inverse.bpmn2
+++ b/org.eclipse.bpmn2.tests/res/qname_prefixNs_inverse.bpmn2
@@ -4,7 +4,7 @@
     targetNamespace="urn:modelA"

     xmlns:a="urn:modelA" xmlns="urn:modelB">

   <bpmn2:import importType="http://www.omg.org/spec/BPMN/20100524/MODEL" 

-    location="res/qname_prefixNs_referenced.bpmn2" namespace="urn:modelB"/>

+    location="qname_prefixNs_referenced.bpmn2" namespace="urn:modelB"/>

   <bpmn2:collaboration id="colId"/>

   <bpmn2:process id="proc1Id" definitionalCollaborationRef="a:colId">

     <bpmn2:supports>proc2Id</bpmn2:supports>

diff --git a/org.eclipse.bpmn2.tests/res/qname_prefixNs_normal.bpmn2 b/org.eclipse.bpmn2.tests/res/qname_prefixNs_normal.bpmn2
index 94eb196..415dbf9 100644
--- a/org.eclipse.bpmn2.tests/res/qname_prefixNs_normal.bpmn2
+++ b/org.eclipse.bpmn2.tests/res/qname_prefixNs_normal.bpmn2
@@ -4,7 +4,7 @@
     targetNamespace="urn:modelA"

     xmlns="urn:modelA" xmlns:b="urn:modelB">

   <bpmn2:import importType="http://www.omg.org/spec/BPMN/20100524/MODEL" 

-    location="res/qname_prefixNs_referenced.bpmn2" namespace="urn:modelB"/>

+    location="qname_prefixNs_referenced.bpmn2" namespace="urn:modelB"/>

   <bpmn2:collaboration id="colId"/>

   <bpmn2:process id="proc1Id" definitionalCollaborationRef="colId">

     <bpmn2:supports>b:proc2Id</bpmn2:supports>

diff --git a/org.eclipse.bpmn2.tests/src/org/eclipse/bpmn2/tests/QNameReferenceTest.java b/org.eclipse.bpmn2.tests/src/org/eclipse/bpmn2/tests/QNameReferenceTest.java
index f7bbc22..2670dc9 100644
--- a/org.eclipse.bpmn2.tests/src/org/eclipse/bpmn2/tests/QNameReferenceTest.java
+++ b/org.eclipse.bpmn2.tests/src/org/eclipse/bpmn2/tests/QNameReferenceTest.java
@@ -87,8 +87,7 @@
      * Equivalent to {@link #saveAndLoadModels(String, String, boolean, String) saveAndLoadModels(name"_A", name"_B", absolute, ...)}
      */
     protected void saveAndLoadModels(String name, boolean absolute) throws IOException {
-        saveAndLoadModels(name + "_A", name + "_B", absolute,
-                getCompletePathURI(name + "_B", absolute).toString()); // TODO: Should just be <name>+"_B.bpmn2". 
+        saveAndLoadModels(name + "_A", name + "_B", absolute, name + "_B." + getFileExtension());
     }
 
     /**
@@ -171,7 +170,7 @@
         A_model.getRootElements().add(A_process2);
         A_process.getSupports().add(A_process2);
 
-        Resource res = saveAndLoadModel("intra", A_model, absolute);
+        Resource res = saveAndLoadModel("intra" + (absolute ? "Abs" : "Rel"), A_model, absolute);
 
         Process A_processNew = (Process) res.getEObject(A_process.getId());
         LinkEventDefinition A_led1New = (LinkEventDefinition) res.getEObject(A_led1.getId());
@@ -217,12 +216,22 @@
         }
     }
 
+    @Test
+    public void testInterModelReferencesRelative() throws IOException {
+        testInterModelReferences(false);
+    }
+
+    @Test
+    public void testInterModelReferencesAbsolute() throws IOException {
+        testInterModelReferences(true);
+    }
+
     /**
      * Test cross-file references.
+     * @param absolute Determines if the models are saved and loaded with absolute or relative URIs.
      * @throws IOException
      */
-    @Test
-    public void testInterModelReferences() throws IOException {
+    public void testInterModelReferences(boolean absolute) throws IOException {
         // single @ XML attribute
         A_process.setDefinitionalCollaborationRef(B_collab);
 
@@ -239,7 +248,7 @@
         // many @ XML element
         A_process.getSupports().add(B_process);
 
-        saveAndLoadModels("inter");
+        saveAndLoadModels("inter" + (absolute ? "Abs" : "Rel"), absolute);
 
         Process A_processNew = (Process) A_resource.getEObject(A_process.getId());
         LinkEventDefinition A_ledNew = (LinkEventDefinition) A_resource.getEObject(A_led.getId());
@@ -363,7 +372,7 @@
 
         Import importCintoA = Bpmn2Factory.eINSTANCE.createImport();
         importCintoA.setImportType("http://www.omg.org/spec/BPMN/20100524/MODEL");
-        importCintoA.setLocation(C_resource.getURI().toString());
+        importCintoA.setLocation("prefixClash_C.bpmn2");
         importCintoA.setNamespace(C_model.getTargetNamespace());
         A_model.getImports().add(importCintoA);
 
@@ -378,4 +387,113 @@
         assertResolvesTo("Reference to element of model C could not be resolved", A_processNew
                 .getSupports().get(1), C_process);
     }
+
+    /*
+     * Tests with different scenarios for the location attribute of import elements
+     */
+
+    @Test
+    public void testImportLocationSubfolderRelative() throws Exception {
+        testImportLocationSubfolder(false);
+    }
+
+    @Test
+    public void testImportLocationSubfolderAbsolute() throws Exception {
+        testImportLocationSubfolder(true);
+    }
+
+    /**
+     * A --> folder/B
+     */
+    public void testImportLocationSubfolder(boolean absolute) throws Exception {
+        String suffix = absolute ? "_Abs" : "_Rel";
+        testImportLocation("importSub_A" + suffix, "sub/importSub_B" + suffix, absolute,
+                "sub/importSub_B" + suffix + ".bpmn2");
+    }
+
+    /**
+     * Redundant path segments in import location ("./")
+     */
+    @Test
+    public void testImportRedundant() throws Exception {
+        testImportLocation("importRedundant_A", "importRedundant_B", false,
+                "./importRedundant_B.bpmn2");
+    }
+
+    /**
+     * Redundant path segments in resource uri ("./")
+     */
+    @Test
+    public void testImportRedundantResource() throws Exception {
+        testImportLocation("importRedundant_A", "./importRedundant_B", false,
+                "importRedundant_B.bpmn2");
+    }
+
+    @Test
+    public void testImportLocationParentFolderRelative() throws Exception {
+        testImportLocationParentFolder(false);
+    }
+
+    @Test
+    public void testImportLocationParentFolderAbsolute() throws Exception {
+        testImportLocationParentFolder(true);
+    }
+
+    /**
+     * A --> ../B
+     */
+    public void testImportLocationParentFolder(boolean absolute) throws Exception {
+        String suffix = absolute ? "_Abs" : "_Rel";
+        testImportLocation("sub/importParent_A" + suffix, "importParent_B" + suffix, absolute,
+                "../importParent_B" + suffix + ".bpmn2");
+    }
+
+    @Test
+    public void testImportLocationNestedFolderRelative() throws Exception {
+        testImportLocationNestedFolder(false);
+    }
+
+    @Test
+    public void testImportLocationNestedFolderAbsolute() throws Exception {
+        testImportLocationNestedFolder(true);
+    }
+
+    /**
+     * A --> ../folder/B
+     */
+    public void testImportLocationNestedFolder(boolean absolute) throws Exception {
+        String suffix = absolute ? "_Abs" : "_Rel";
+        testImportLocation("subA/importNested_A" + suffix, "subB/importNested_B" + suffix,
+                absolute, "../subB/importNested_B" + suffix + ".bpmn2");
+    }
+
+    @Test
+    public void testImportLocationCompletePathRelative() throws Exception {
+        testImportLocationCompletePath(false);
+    }
+
+    @Test
+    public void testImportLocationCompletePathAbsolute() throws Exception {
+        testImportLocationCompletePath(true);
+    }
+
+    /**
+     * A --> /absolute/Path/To/B
+     */
+    public void testImportLocationCompletePath(boolean absolute) throws Exception {
+        String suffix = absolute ? "_Abs" : "_Rel";
+        testImportLocation("importComplete_A" + suffix, "importComplete_B" + suffix, absolute,
+                getCompletePathURI("importComplete_B" + suffix, true).toString()); // TODO: toString (file:/E:/path/to/B.bpmn2) or toFileString (E:\path\to\B.bpmn2) ??
+    }
+
+    public void testImportLocation(String nameA, String nameB, boolean absolute,
+            String importLocation) throws Exception {
+        A_process.setDefinitionalCollaborationRef(B_collab);
+
+        saveAndLoadModels(nameA, nameB, absolute, importLocation);
+
+        Process A_processNew = (Process) A_resource.getEObject(A_process.getId());
+        assertResolvesTo("Proxy could not be resolved, import location: " + importLocation,
+                A_processNew.getDefinitionalCollaborationRef(), B_collab);
+    }
 }
diff --git a/org.eclipse.bpmn2.tests/src/org/eclipse/bpmn2/tests/XMLSerializationTest.java b/org.eclipse.bpmn2.tests/src/org/eclipse/bpmn2/tests/XMLSerializationTest.java
index 81c2d6c..47a99a8 100644
--- a/org.eclipse.bpmn2.tests/src/org/eclipse/bpmn2/tests/XMLSerializationTest.java
+++ b/org.eclipse.bpmn2.tests/src/org/eclipse/bpmn2/tests/XMLSerializationTest.java
@@ -278,7 +278,7 @@
             throws Exception {
         Import xsdImport = Bpmn2Factory.eINSTANCE.createImport();
         xsdImport.setNamespace(namespace);
-        xsdImport.setLocation(location);
+        xsdImport.setLocation("../../" + location); // Relative to resource during test run.
         model.getImports().add(xsdImport);
 
         ItemDefinition xsdItem = Bpmn2Factory.eINSTANCE.createItemDefinition();
@@ -305,10 +305,14 @@
         final InternalEObject xsdStructure = (InternalEObject) itemDef.getStructureRef();
         assertNotNull(xsdStructure);
         if (xsdStructure.eIsProxy())
-            assertEquals(uriExpected, xsdStructure.eProxyURI());
+            assertTrue(String.format("Proxy and expected URI differ (expected: %s, actual: %s)",
+                    uriExpected, xsdStructure.eProxyURI()), xsdStructure.eProxyURI().toString()
+                    .endsWith(uriExpected.toString()));
         else {
             final Resource res = xsdStructure.eResource();
-            assertEquals(uriExpected, res.getURI().appendFragment(res.getURIFragment(xsdStructure)));
+            URI actual = res.getURI().appendFragment(res.getURIFragment(xsdStructure));
+            assertTrue(String.format("Actual and expected URI differ (expected: %s, actual: %s)",
+                    uriExpected, actual), actual.toString().endsWith(uriExpected.toString()));
         }
     }
 
diff --git a/org.eclipse.bpmn2/src/org/eclipse/bpmn2/util/Bpmn2ResourceImpl.java b/org.eclipse.bpmn2/src/org/eclipse/bpmn2/util/Bpmn2ResourceImpl.java
index be51f19..f6ba5f8 100644
--- a/org.eclipse.bpmn2/src/org/eclipse/bpmn2/util/Bpmn2ResourceImpl.java
+++ b/org.eclipse.bpmn2/src/org/eclipse/bpmn2/util/Bpmn2ResourceImpl.java
@@ -344,7 +344,7 @@
                 ns = getDefinitions().getTargetNamespace();

             else {

                 for (Import imp : getDefinitions().getImports()) {

-                    if (filePath.equals(imp.getLocation())) {

+                    if (filePath.equals(imp.getLocation())) { // TODO: this needs to operate on "canonical paths" as well

                         // TODO: Also check that imp.getType() is BPMN

                         ns = imp.getNamespace();

                         break;