This is an automated email from the ASF dual-hosted git repository.

davidb pushed a commit to branch master
in repository 
https://gitbox.apache.org/repos/asf/sling-org-apache-sling-feature-analyser.git


The following commit(s) were added to refs/heads/master by this push:
     new 604b53c  SLING-9489 Make it possible to compare parts of feature models
604b53c is described below

commit 604b53c3ed25fc1ea5ecc23ab036ae2ea2eae4c6
Author: David Bosschaert <[email protected]>
AuthorDate: Thu Jun 18 09:54:05 2020 +0100

    SLING-9489 Make it possible to compare parts of feature models
---
 pom.xml                                            |   2 +-
 readme.md                                          |  18 +-
 .../apache/sling/feature/analyser/Analyser.java    |  11 +
 .../sling/feature/analyser/package-info.java       |   2 +-
 .../feature/analyser/task/AnalyserTaskContext.java |   3 +
 .../analyser/task/impl/CheckCompareFeatures.java   | 145 +++++++++++
 .../sling/feature/analyser/task/package-info.java  |   2 +-
 ...apache.sling.feature.analyser.task.AnalyserTask |   3 +-
 .../task/impl/CheckApisJarsPropertiesTest.java     |   6 +
 .../task/impl/CheckCompareFeaturesTest.java        | 277 +++++++++++++++++++++
 .../analyser/task/impl/CheckRepoinitTest.java      |   6 +
 11 files changed, 470 insertions(+), 5 deletions(-)

diff --git a/pom.xml b/pom.xml
index ceef91d..dc7dc85 100644
--- a/pom.xml
+++ b/pom.xml
@@ -22,7 +22,7 @@
     </parent>
 
     <artifactId>org.apache.sling.feature.analyser</artifactId>
-    <version>1.2.7-SNAPSHOT</version>
+    <version>1.3.0-SNAPSHOT</version>
 
     <name>Apache Sling Feature Model Analyser</name>
     <description>
diff --git a/readme.md b/readme.md
index 1be6ebc..015355f 100644
--- a/readme.md
+++ b/readme.md
@@ -25,11 +25,27 @@ information as part of the check, to ensure that bundles 
don't import packages o
 
 * `bundle-resources`: Gives a warning if a bundle contains resources specified 
with `Sling-Bundle-Resources`.
 
-* `requirements-capabilities`: Checks bundle requirements/capabilities for 
consistency and completeness.
+* `compare-features`: Compares the artifacts in the bundles sections or in an 
extension between two feature models. For more information see 
[below](#compare-features).
 
+* `requirements-capabilities`: Checks bundle requirements/capabilities for 
consistency and completeness.
 
 * `apis-jar`: validates that the `sourceId` property of a bundle, if defined, 
is a comma-separated value list of artifact ids.
 
 Additional analysers in relation to Feature Model API Regions can be found 
here: 
https://github.com/apache/sling-org-apache-sling-feature-extension-apiregions
 
 For further documentation see: 
https://github.com/apache/sling-org-apache-sling-feature/blob/master/readme.md
+
+## `compare-features`
+
+This analyser compares certain sections of two feature models.
+
+This analyser requires additional configuration:
+
+ Configuration key | Allowed values | Description 
+ ----- | ----- | -----
+`compare-type` | `ARTIFACTS` | The types of entities being compared. Currently 
only artifacts can be compared.
+`compare-with` | Maven ID, e.g. `mygroup:myart:1.2.3` | The _golden_ feature 
to compare the features selected for the analyser with.
+`compare-extension` | extension name | If this configuration is absent, the 
feature's bundles are compared. Otherwise the extensions with the specified 
name are compared. These extensions must be of type `ARTIFACTS`.
+`compare-mode` | `SAME` or `DIFFERENT` | Whether the sections must be the same 
or must be different. Defaults to `SAME`.
+`compare-metadata` | `true` or `false` | Whether to include the artifact 
metadata in the comparison. Defaults to `false`.
+
diff --git a/src/main/java/org/apache/sling/feature/analyser/Analyser.java 
b/src/main/java/org/apache/sling/feature/analyser/Analyser.java
index 2186ede..d14c33e 100644
--- a/src/main/java/org/apache/sling/feature/analyser/Analyser.java
+++ b/src/main/java/org/apache/sling/feature/analyser/Analyser.java
@@ -34,6 +34,7 @@ import org.apache.sling.feature.ExecutionEnvironmentExtension;
 import org.apache.sling.feature.Feature;
 import org.apache.sling.feature.analyser.task.AnalyserTask;
 import org.apache.sling.feature.analyser.task.AnalyserTaskContext;
+import org.apache.sling.feature.builder.FeatureProvider;
 import org.apache.sling.feature.scanner.BundleDescriptor;
 import org.apache.sling.feature.scanner.FeatureDescriptor;
 import org.apache.sling.feature.scanner.Scanner;
@@ -105,6 +106,11 @@ public class Analyser {
     }
 
     public AnalyserResult analyse(final Feature feature, final ArtifactId fwk) 
throws Exception {
+        return analyse(feature, fwk, null);
+    }
+
+    public AnalyserResult analyse(final Feature feature, final ArtifactId fwk,
+            final FeatureProvider featureProvider) throws Exception {
         logger.info("Starting analyzing feature '{}'...", feature.getId());
 
         final FeatureDescriptor featureDesc = scanner.scan(feature);
@@ -143,6 +149,11 @@ public class Analyser {
                 }
 
                 @Override
+                public FeatureProvider getFeatureProvider() {
+                    return featureProvider;
+                }
+
+                @Override
                 public BundleDescriptor getFrameworkDescriptor() {
                     return fwkDesc;
                 }
diff --git a/src/main/java/org/apache/sling/feature/analyser/package-info.java 
b/src/main/java/org/apache/sling/feature/analyser/package-info.java
index 3042a56..2edfaae 100644
--- a/src/main/java/org/apache/sling/feature/analyser/package-info.java
+++ b/src/main/java/org/apache/sling/feature/analyser/package-info.java
@@ -17,7 +17,7 @@
  * under the License.
  */
 
[email protected]("1.0.0")
[email protected]("1.1.0")
 package org.apache.sling.feature.analyser;
 
 
diff --git 
a/src/main/java/org/apache/sling/feature/analyser/task/AnalyserTaskContext.java 
b/src/main/java/org/apache/sling/feature/analyser/task/AnalyserTaskContext.java
index 414c69f..af5ec38 100644
--- 
a/src/main/java/org/apache/sling/feature/analyser/task/AnalyserTaskContext.java
+++ 
b/src/main/java/org/apache/sling/feature/analyser/task/AnalyserTaskContext.java
@@ -17,6 +17,7 @@
 package org.apache.sling.feature.analyser.task;
 
 import org.apache.sling.feature.Feature;
+import org.apache.sling.feature.builder.FeatureProvider;
 import org.apache.sling.feature.scanner.BundleDescriptor;
 import org.apache.sling.feature.scanner.FeatureDescriptor;
 import org.osgi.annotation.versioning.ProviderType;
@@ -38,6 +39,8 @@ public interface AnalyserTaskContext {
      */
     FeatureDescriptor getFeatureDescriptor();
 
+    FeatureProvider getFeatureProvider();
+
     /**
      * The framework descriptor
      * @return the descriptor
diff --git 
a/src/main/java/org/apache/sling/feature/analyser/task/impl/CheckCompareFeatures.java
 
b/src/main/java/org/apache/sling/feature/analyser/task/impl/CheckCompareFeatures.java
new file mode 100644
index 0000000..af5b450
--- /dev/null
+++ 
b/src/main/java/org/apache/sling/feature/analyser/task/impl/CheckCompareFeatures.java
@@ -0,0 +1,145 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sling.feature.analyser.task.impl;
+
+import org.apache.sling.feature.Artifact;
+import org.apache.sling.feature.ArtifactId;
+import org.apache.sling.feature.Artifacts;
+import org.apache.sling.feature.Extension;
+import org.apache.sling.feature.ExtensionType;
+import org.apache.sling.feature.Feature;
+import org.apache.sling.feature.analyser.task.AnalyserTask;
+import org.apache.sling.feature.analyser.task.AnalyserTaskContext;
+
+import java.util.Map;
+
+public class CheckCompareFeatures implements AnalyserTask {
+
+    @Override
+    public String getId() {
+        return "compare-features";
+    }
+
+    @Override
+    public String getName() {
+        return "Comparing Features";
+    }
+
+    @Override
+    public void execute(AnalyserTaskContext ctx) throws Exception {
+        Map<String, String> cfg = ctx.getConfiguration();
+        String aid = cfg.get("compare-with");
+        if (aid == null) {
+            throw new Exception("Missing 'compare-with' configuration for 
compare-features analyser.");
+        }
+
+        String ext = cfg.get("compare-extension");
+        String mode = cfg.getOrDefault("compare-mode", "SAME");
+        String type = cfg.getOrDefault("compare-type", "ARTIFACTS");
+        if (!"ARTIFACTS".equals(type)) {
+            throw new Exception("The only supported value for 'compare-type' 
right now is ARTIFACTS");
+        }
+
+        boolean strictMetadata = !cfg.getOrDefault("compare-metadata", 
"false").equalsIgnoreCase("false");
+
+        Feature feat = 
ctx.getFeatureProvider().provide(ArtifactId.fromMvnId(aid));
+        if (feat == null)
+            throw new Exception("Feature not found: " + aid);
+
+        Artifacts mainArts = getArtifactsToCompare(feat, ext);
+        Artifacts compArts = getArtifactsToCompare(ctx.getFeature(), ext);
+
+        String violationMessage = null;
+        switch (mode) {
+        case "SAME":
+            violationMessage = assertArtifactsSame(mainArts, compArts, 
strictMetadata);
+            break;
+        case "DIFFERENT":
+            violationMessage = assertArtifactsSame(mainArts, compArts, 
strictMetadata);
+            if (violationMessage == null) {
+                violationMessage = "Artifacts are not different";
+            } else {
+                violationMessage = null;
+            }
+            break;
+        default:
+            throw new Exception("Unknown comparison mode: " + mode);
+        }
+
+        if (violationMessage != null) {
+            String origin;
+            if (ext == null) {
+                origin = "bundles";
+            } else {
+                origin = "extension " + ext;
+            }
+
+            ctx.reportError("Compare " + origin + " in feature " + 
feat.getId() + " and "
+                    + ctx.getFeature().getId() + " failed: " + 
violationMessage);
+        }
+    }
+
+    static String assertArtifactsSame(Artifacts mainArts, Artifacts compArts, 
boolean strictMetadata) {
+        if (mainArts.size() != compArts.size()) {
+            return "Compared artifacts are of different sizes";
+        }
+
+        for (Artifact a : mainArts) {
+            Artifact a2 = findArtifact(compArts, a.getId());
+            if (a2 == null) {
+                return "Artifact " + a.getId() + " not found.";
+            }
+
+            if (strictMetadata) {
+                Map<String, String> md1 = a.getMetadata();
+                Map<String, String> md2 = a2.getMetadata();
+                if (!md1.equals(md2)) {
+                    return "Metadata of " + a.getId() + " is different: " + 
md1 + " vs " + md2;
+                }
+            }
+        }
+        return null;
+    }
+
+    private static Artifact findArtifact(Artifacts list, ArtifactId 
artifactId) {
+        for (Artifact a : list) {
+            if (a.getId().equals(artifactId))
+                return a;
+        }
+        return null;
+    }
+
+    static Artifacts getArtifactsToCompare(Feature feat, String ext) throws 
Exception {
+        Artifacts artifacts;
+        if (ext == null) {
+            // compare bundles
+            artifacts = feat.getBundles();
+        } else {
+            // compare extensions
+            Extension extension = feat.getExtensions().getByName(ext);
+            if (extension == null) {
+                throw new Exception("Extension " + ext + " not found in 
feature " + feat.getId());
+            }
+            if (ExtensionType.ARTIFACTS != extension.getType()) {
+                throw new Exception("Extension " + extension + " is not of 
type ARTIFACTS.");
+            }
+
+            artifacts = extension.getArtifacts();
+        }
+        return artifacts;
+    }
+}
diff --git 
a/src/main/java/org/apache/sling/feature/analyser/task/package-info.java 
b/src/main/java/org/apache/sling/feature/analyser/task/package-info.java
index d265303..614898f 100644
--- a/src/main/java/org/apache/sling/feature/analyser/task/package-info.java
+++ b/src/main/java/org/apache/sling/feature/analyser/task/package-info.java
@@ -17,7 +17,7 @@
  * under the License.
  */
 
[email protected]("1.0.0")
[email protected]("1.1.0")
 package org.apache.sling.feature.analyser.task;
 
 
diff --git 
a/src/main/resources/META-INF/services/org.apache.sling.feature.analyser.task.AnalyserTask
 
b/src/main/resources/META-INF/services/org.apache.sling.feature.analyser.task.AnalyserTask
index bfbe662..773f53e 100644
--- 
a/src/main/resources/META-INF/services/org.apache.sling.feature.analyser.task.AnalyserTask
+++ 
b/src/main/resources/META-INF/services/org.apache.sling.feature.analyser.task.AnalyserTask
@@ -6,4 +6,5 @@ 
org.apache.sling.feature.analyser.task.impl.CheckRequirementsCapabilities
 org.apache.sling.feature.analyser.task.impl.CheckContentPackageForInstallables
 org.apache.sling.feature.analyser.task.impl.CheckContentPackagesDependencies
 org.apache.sling.feature.analyser.task.impl.CheckApisJarsProperties
-org.apache.sling.feature.analyser.task.impl.CheckRepoinit
\ No newline at end of file
+org.apache.sling.feature.analyser.task.impl.CheckCompareFeatures
+org.apache.sling.feature.analyser.task.impl.CheckRepoinit
diff --git 
a/src/test/java/org/apache/sling/feature/analyser/task/impl/CheckApisJarsPropertiesTest.java
 
b/src/test/java/org/apache/sling/feature/analyser/task/impl/CheckApisJarsPropertiesTest.java
index 34ea6f6..983b43f 100644
--- 
a/src/test/java/org/apache/sling/feature/analyser/task/impl/CheckApisJarsPropertiesTest.java
+++ 
b/src/test/java/org/apache/sling/feature/analyser/task/impl/CheckApisJarsPropertiesTest.java
@@ -30,6 +30,7 @@ import org.apache.sling.feature.Artifact;
 import org.apache.sling.feature.ArtifactId;
 import org.apache.sling.feature.Feature;
 import org.apache.sling.feature.analyser.task.AnalyserTaskContext;
+import org.apache.sling.feature.builder.FeatureProvider;
 import org.apache.sling.feature.scanner.BundleDescriptor;
 import org.apache.sling.feature.scanner.FeatureDescriptor;
 import org.junit.Test;
@@ -77,6 +78,11 @@ public class CheckApisJarsPropertiesTest {
             return Collections.emptyMap();
         }
         
+        @Override
+        public FeatureProvider getFeatureProvider() {
+            return null;
+        }
+
         public List<String> getErrors() {
             return errors;
         }
diff --git 
a/src/test/java/org/apache/sling/feature/analyser/task/impl/CheckCompareFeaturesTest.java
 
b/src/test/java/org/apache/sling/feature/analyser/task/impl/CheckCompareFeaturesTest.java
new file mode 100644
index 0000000..825fd30
--- /dev/null
+++ 
b/src/test/java/org/apache/sling/feature/analyser/task/impl/CheckCompareFeaturesTest.java
@@ -0,0 +1,277 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sling.feature.analyser.task.impl;
+
+import org.apache.sling.feature.Artifact;
+import org.apache.sling.feature.ArtifactId;
+import org.apache.sling.feature.Artifacts;
+import org.apache.sling.feature.Extension;
+import org.apache.sling.feature.ExtensionState;
+import org.apache.sling.feature.ExtensionType;
+import org.apache.sling.feature.Feature;
+import org.apache.sling.feature.analyser.task.AnalyserTaskContext;
+import org.apache.sling.feature.builder.FeatureProvider;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import java.util.AbstractMap;
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.fail;
+
+public class CheckCompareFeaturesTest {
+    @Test
+    public void testAssertEmptyArtifactsSame() {
+        Artifacts a1 = new Artifacts();
+        Artifacts a2 = new Artifacts();
+
+        assertNull(CheckCompareFeatures.assertArtifactsSame(a1, a2, true));
+        assertNull(CheckCompareFeatures.assertArtifactsSame(a1, a2, false));
+    }
+
+    @Test
+    public void testAssertDiffSizeArtifactsNotSame() {
+        Artifacts a1 = new Artifacts();
+        Artifacts a2 = new Artifacts();
+        a2.add(new Artifact(ArtifactId.fromMvnId("a:b:1")));
+
+        assertNotNull(CheckCompareFeatures.assertArtifactsSame(a1, a2, true));
+        assertNotNull(CheckCompareFeatures.assertArtifactsSame(a1, a2, false));
+    }
+
+    @Test
+    public void testAssertDiffSizeArtifactsNotSame2() {
+        Artifacts a1 = new Artifacts();
+        a1.add(new Artifact(ArtifactId.fromMvnId("a:b:1")));
+        Artifacts a2 = new Artifacts();
+        a2.add(new Artifact(ArtifactId.fromMvnId("a:b:2")));
+
+        assertNotNull(CheckCompareFeatures.assertArtifactsSame(a1, a2, true));
+        assertNotNull(CheckCompareFeatures.assertArtifactsSame(a1, a2, false));
+    }
+
+    @Test
+    public void testAssertArtifactsSame() {
+        Artifacts a1 = new Artifacts();
+        a1.add(new Artifact(ArtifactId.fromMvnId("a:b:1")));
+        a1.add(new Artifact(ArtifactId.fromMvnId("a:b:2")));
+        Artifacts a2 = new Artifacts();
+        a2.add(new Artifact(ArtifactId.fromMvnId("a:b:2")));
+        a2.add(new Artifact(ArtifactId.fromMvnId("a:b:1")));
+
+        assertNull(CheckCompareFeatures.assertArtifactsSame(a1, a2, true));
+        assertNull(CheckCompareFeatures.assertArtifactsSame(a1, a2, false));
+    }
+
+    @Test
+    public void testAssertArtifactsSameDifferentMetadata() {
+        Artifact art1 = new Artifact(ArtifactId.fromMvnId("a:b:1"));
+        art1.getMetadata().put("foo", "bar");
+        Artifacts a1 = new Artifacts();
+        a1.add(art1);
+
+        Artifact art2 = new Artifact(ArtifactId.fromMvnId("a:b:1"));
+        Artifacts a2 = new Artifacts();
+        a2.add(art2);
+
+        assertNotNull(CheckCompareFeatures.assertArtifactsSame(a1, a2, true));
+        assertNull(CheckCompareFeatures.assertArtifactsSame(a1, a2, false));
+    }
+
+    @Test
+    public void testFindArtifactsToCompare() throws Exception {
+        Feature f = new Feature(ArtifactId.fromMvnId("x:y:123"));
+        f.getBundles().add(new 
Artifact(ArtifactId.fromMvnId("grp:bundle1:1")));
+        Extension ext = new Extension(ExtensionType.TEXT, "textext", 
ExtensionState.REQUIRED);
+        ext.setText("hello");
+        f.getExtensions().add(ext);
+        Extension ext2 = new Extension(ExtensionType.ARTIFACTS, "artext", 
ExtensionState.REQUIRED);
+        ext2.getArtifacts().add(new 
Artifact(ArtifactId.fromMvnId("grp:extart1:2")));
+        ext2.getArtifacts().add(new 
Artifact(ArtifactId.fromMvnId("grp:extart2:5")));
+        f.getExtensions().add(ext2);
+
+        Artifacts arts1 = CheckCompareFeatures.getArtifactsToCompare(f, null);
+        assertEquals(arts1, f.getBundles());
+
+        Artifacts arts2 = CheckCompareFeatures.getArtifactsToCompare(f, 
"artext");
+        assertEquals(ext2.getArtifacts(), arts2);
+
+        try {
+            CheckCompareFeatures.getArtifactsToCompare(f, "textext");
+            fail("Expected an exception, because textext is not of type 
Artifacts");
+        } catch (Exception ex) {
+            // good
+        }
+
+        try {
+            CheckCompareFeatures.getArtifactsToCompare(f, "nonexisting");
+            fail("Expected an exception, because a non-existing extension was 
requested");
+        } catch (Exception ex) {
+            // good
+        }
+    }
+
+    @Test
+    public void testExecute1() throws Exception {
+        Feature f = new Feature(ArtifactId.fromMvnId("g:a:123"));
+        f.getBundles().add(new Artifact(ArtifactId.fromMvnId("g:b:1")));
+        Feature fc = new Feature(ArtifactId.fromMvnId("g:b:456"));
+        fc.getBundles().add(new Artifact(ArtifactId.fromMvnId("g:b:1")));
+
+        AnalyserTaskContext ctx = testExecute(f, fc);
+
+        Mockito.verify(ctx, Mockito.never()).reportError(Mockito.anyString());
+    }
+
+    @Test
+    public void testExecute2() throws Exception {
+        Feature f = new Feature(ArtifactId.fromMvnId("g:a:123"));
+        f.getBundles().add(new Artifact(ArtifactId.fromMvnId("g:b:1")));
+        Feature fc = new Feature(ArtifactId.fromMvnId("g:b:456"));
+
+        AnalyserTaskContext ctx = testExecute(f, fc);
+
+        Mockito.verify(ctx).reportError(Mockito.anyString());
+    }
+
+    @Test
+    public void testExecute3() throws Exception {
+        Feature f1 = new Feature(ArtifactId.fromMvnId("g:a:123"));
+        Extension e1 = new Extension(ExtensionType.ARTIFACTS, "myarts", 
ExtensionState.REQUIRED);
+        e1.getArtifacts().add(new Artifact(ArtifactId.fromMvnId("g:c:1")));
+        e1.getArtifacts().add(new Artifact(ArtifactId.fromMvnId("g:c:2")));
+        f1.getExtensions().add(e1);
+
+        Feature f2 = new Feature(ArtifactId.fromMvnId("g:b:456"));
+        Extension e2 = new Extension(ExtensionType.ARTIFACTS, "myarts", 
ExtensionState.REQUIRED);
+        e2.getArtifacts().add(new Artifact(ArtifactId.fromMvnId("g:c:2")));
+        e2.getArtifacts().add(new Artifact(ArtifactId.fromMvnId("g:c:1")));
+        f2.getExtensions().add(e2);
+
+        AnalyserTaskContext ctx = testExecute(f1, f2, "myarts");
+
+        Mockito.verify(ctx, Mockito.never()).reportError(Mockito.anyString());
+    }
+
+    @Test
+    public void testExecute4() throws Exception {
+        Feature f1 = new Feature(ArtifactId.fromMvnId("g:a:123"));
+        Extension e1 = new Extension(ExtensionType.ARTIFACTS, "myarts", 
ExtensionState.REQUIRED);
+        f1.getExtensions().add(e1);
+
+        Feature f2 = new Feature(ArtifactId.fromMvnId("g:b:456"));
+        Extension e2 = new Extension(ExtensionType.ARTIFACTS, "myarts", 
ExtensionState.REQUIRED);
+        e2.getArtifacts().add(new Artifact(ArtifactId.fromMvnId("g:c:2")));
+        f2.getExtensions().add(e2);
+
+        AnalyserTaskContext ctx = testExecute("SAME", f1, f2, "myarts");
+
+        Mockito.verify(ctx).reportError(Mockito.anyString());
+    }
+
+    @Test
+    public void testAssertEmptyArtifactsNotDifferent() throws Exception {
+        Feature f = new Feature(ArtifactId.fromMvnId("g:a:123"));
+        Feature fc = new Feature(ArtifactId.fromMvnId("g:b:456"));
+
+        AnalyserTaskContext ctx = testExecute("DIFFERENT", f, fc);
+
+        Mockito.verify(ctx).reportError(Mockito.anyString());
+    }
+
+    @Test
+    public void testAssertDiffSizeArtifactsDifferent() throws Exception {
+        Artifact art1 = new Artifact(ArtifactId.fromMvnId("a:b:1"));
+        art1.getMetadata().put("foo", "bar");
+
+        Artifact art2 = new Artifact(ArtifactId.fromMvnId("a:b:1"));
+
+        Feature f = new Feature(ArtifactId.fromMvnId("g:a:123"));
+        f.getBundles().add(art1);
+        Feature fc = new Feature(ArtifactId.fromMvnId("g:b:456"));
+        fc.getBundles().add(art2);
+
+        @SuppressWarnings("unchecked")
+        AnalyserTaskContext ctx = testExecute("DIFFERENT", f, fc, null,
+                new AbstractMap.SimpleEntry<>("compare-metadata", "false"));
+        Mockito.verify(ctx).reportError(Mockito.anyString());
+
+        @SuppressWarnings("unchecked")
+        AnalyserTaskContext ctx2 = testExecute("DIFFERENT", f, fc, null,
+                new AbstractMap.SimpleEntry<>("compare-metadata", "true"));
+        Mockito.verify(ctx2, Mockito.never()).reportError(Mockito.anyString());
+    }
+
+    private AnalyserTaskContext testExecute(String mode, Feature f, Feature 
fc) throws Exception {
+        return testExecute(mode, f, fc, null);
+    }
+
+    private AnalyserTaskContext testExecute(Feature f, Feature fc) throws 
Exception {
+        return testExecute(null, f, fc, null);
+    }
+
+    private AnalyserTaskContext testExecute(Feature f, Feature fc, String 
extension) throws Exception {
+        return testExecute(null, f, fc, extension);
+    }
+
+    @SuppressWarnings("unchecked")
+    private AnalyserTaskContext testExecute(String mode, Feature f, Feature 
fc, String extension) throws Exception {
+        return testExecute(mode, f, fc, extension, new Map.Entry[0]);
+    }
+
+    private AnalyserTaskContext testExecute(String mode, Feature f, Feature 
fc, String extension,
+            @SuppressWarnings("unchecked") Map.Entry<String, String> ... 
cfgEntries) throws Exception {
+        Map<String, String> cfg = new HashMap<>();
+        cfg.put("compare-with", f.getId().toMvnId());
+
+        if (mode != null) {
+            cfg.put("compare-mode", mode);
+        }
+
+        if (extension != null) {
+            cfg.put("compare-extension", extension);
+        }
+
+        for (Map.Entry<String, String> entry : cfgEntries) {
+            cfg.put(entry.getKey(), entry.getValue());
+        }
+
+        CheckCompareFeatures cfe = new CheckCompareFeatures();
+
+        FeatureProvider fp = new FeatureProvider() {
+            @Override
+            public Feature provide(ArtifactId id) {
+                if ("g:a:123".equals(id.toMvnId())) {
+                    return f;
+                }
+                return null;
+            }
+        };
+
+        AnalyserTaskContext ctx = Mockito.mock(AnalyserTaskContext.class);
+        Mockito.when(ctx.getConfiguration()).thenReturn(cfg);
+        Mockito.when(ctx.getFeatureProvider()).thenReturn(fp);
+        Mockito.when(ctx.getFeature()).thenReturn(fc);
+
+        cfe.execute(ctx);
+        return ctx;
+    }
+}
diff --git 
a/src/test/java/org/apache/sling/feature/analyser/task/impl/CheckRepoinitTest.java
 
b/src/test/java/org/apache/sling/feature/analyser/task/impl/CheckRepoinitTest.java
index 517e1fa..1355e52 100644
--- 
a/src/test/java/org/apache/sling/feature/analyser/task/impl/CheckRepoinitTest.java
+++ 
b/src/test/java/org/apache/sling/feature/analyser/task/impl/CheckRepoinitTest.java
@@ -32,6 +32,7 @@ import org.apache.sling.feature.ExtensionType;
 import org.apache.sling.feature.Feature;
 import org.apache.sling.feature.analyser.task.AnalyserTask;
 import org.apache.sling.feature.analyser.task.AnalyserTaskContext;
+import org.apache.sling.feature.builder.FeatureProvider;
 import org.apache.sling.feature.scanner.BundleDescriptor;
 import org.apache.sling.feature.scanner.FeatureDescriptor;
 import org.junit.Test;
@@ -131,6 +132,11 @@ public class CheckRepoinitTest {
         }
 
         @Override
+        public FeatureProvider getFeatureProvider() {
+            return null;
+        }
+
+        @Override
         public void reportWarning(String message) {
         }
 

Reply via email to