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

slachiewicz pushed a commit to branch master
in repository 
https://gitbox.apache.org/repos/asf/maven-remote-resources-plugin.git

commit c2ab5ad812052eaeab6c420f18c2ba797dec8ca8
Author: Sylwester Lachiewicz <[email protected]>
AuthorDate: Wed Oct 28 09:45:57 2026 +0000

    Group dependencies by the license an ASF distribution would choose
    
    A dependency with several licenses may be used under any one of them, and an
    ASF distribution names only the one it chose, preferring Category A to B to 
X.
    Choices that resolve to nothing no longer leave the dependency unresolved.
---
 .../project/src/main/resources/DEPENDENCIES.vm     |   2 +
 .../plugin/resources/remote/SpdxLicenses.java      | 214 ++++++++++++++++++---
 .../plugin/resources/remote/license-categories.txt |  65 +++++++
 src/site/markdown/usage.md.vm                      |   4 +-
 .../plugin/resources/remote/SpdxLicensesTest.java  |  55 +++++-
 .../resources/remote/it/ITSpdxLicenseId.java       |  25 ++-
 6 files changed, 320 insertions(+), 45 deletions(-)

diff --git 
a/src/it/resources/spdx-license-id/project/src/main/resources/DEPENDENCIES.vm 
b/src/it/resources/spdx-license-id/project/src/main/resources/DEPENDENCIES.vm
index 6ebd36b..428baa9 100644
--- 
a/src/it/resources/spdx-license-id/project/src/main/resources/DEPENDENCIES.vm
+++ 
b/src/it/resources/spdx-license-id/project/src/main/resources/DEPENDENCIES.vm
@@ -17,6 +17,8 @@
 Override: #if ($projectName)$projectName#else${project.name}#end
 #foreach( $dependency in $projects )
 $dependency.artifactId expression: $!spdx.expression($dependency)
+#set( $preferred = $spdx.preferred($dependency) )
+$dependency.artifactId preferred:#if( $preferred ) $preferred 
$!spdx.category($preferred)#end
 #foreach( $license in $dependency.licenses )
 #set( $id = $spdx.id($license) )
 $dependency.artifactId: #if( $id )$id#else$license.name#end
diff --git 
a/src/main/java/org/apache/maven/plugin/resources/remote/SpdxLicenses.java 
b/src/main/java/org/apache/maven/plugin/resources/remote/SpdxLicenses.java
index 9dfbc2b..ec6699e 100644
--- a/src/main/java/org/apache/maven/plugin/resources/remote/SpdxLicenses.java
+++ b/src/main/java/org/apache/maven/plugin/resources/remote/SpdxLicenses.java
@@ -53,7 +53,11 @@ import org.apache.maven.project.MavenProject;
  * A project that declares several licenses may be used under any one of them, 
so
  * <code>$!spdx.expression($project)</code> joins their IDs with 
<code>OR</code>.
  * <p>
- * To list each license once, <code>$spdx.group($projects)</code> groups 
dependencies by SPDX expression,
+ * An ASF distribution names one chosen license for such a project: 
<code>$!spdx.preferred($project)</code>
+ * picks it by <a href="https://www.apache.org/legal/resolved.html";>ASF 
license category</a>, which
+ * <code>$!spdx.category($id)</code> returns.
+ * <p>
+ * To list each license once, <code>$spdx.group($projects)</code> groups 
dependencies by preferred license,
  * <code>$spdx.ids($projects)</code> returns every ID they use, and 
<code>$spdx.unresolved($projects)</code>
  * returns the dependencies that match nothing.
  *
@@ -63,6 +67,8 @@ public class SpdxLicenses {
 
     private static final String RESOURCE = "license-aliases.txt";
 
+    private static final String CATEGORIES = "license-categories.txt";
+
     private static final Pattern EXPRESSION_TOKEN = 
Pattern.compile("\\(|\\)|[^\\s()]+");
 
     private static final Pattern LICENSE_REF = 
Pattern.compile("LicenseRef-[A-Za-z0-9.-]+");
@@ -81,6 +87,9 @@ public class SpdxLicenses {
     /** Normalised URL to ID or expression. */
     private final Map<String, String> urls = new HashMap<>();
 
+    /** Lower-case ID or expression to ASF category. */
+    private final Map<String, String> categories = new HashMap<>();
+
     private final List<LicenseMapping> mappings;
 
     SpdxLicenses() {
@@ -89,33 +98,42 @@ public class SpdxLicenses {
 
     SpdxLicenses(List<LicenseMapping> mappings) {
         this.mappings = new ArrayList<>(mappings);
-        InputStream in = SpdxLicenses.class.getResourceAsStream(RESOURCE);
+        for (String[] fields : read(RESOURCE)) {
+            String id = fields[0].trim();
+            if (id.indexOf(' ') < 0) {
+                ids.put(id.toLowerCase(Locale.ROOT), id);
+            }
+            if (fields.length > 1) {
+                String alias = fields[1].trim();
+                if (alias.startsWith("http://";) || 
alias.startsWith("https://";)) {
+                    put(urls, normaliseUrl(alias), id);
+                } else {
+                    put(names, normaliseName(alias), id);
+                }
+            }
+        }
+        for (String[] fields : read(CATEGORIES)) {
+            categories.put(fields[0].trim().toLowerCase(Locale.ROOT), 
fields[1].trim());
+        }
+    }
+
+    private static List<String[]> read(String resource) {
+        InputStream in = SpdxLicenses.class.getResourceAsStream(resource);
         if (in == null) {
-            throw new IllegalStateException("Missing resource " + RESOURCE);
+            throw new IllegalStateException("Missing resource " + resource);
         }
+        List<String[]> lines = new ArrayList<>();
         try (BufferedReader reader = new BufferedReader(new 
InputStreamReader(in, StandardCharsets.UTF_8))) {
             String line;
             while ((line = reader.readLine()) != null) {
-                if (line.trim().isEmpty() || line.startsWith("#")) {
-                    continue;
-                }
-                String[] fields = line.split("\t", 2);
-                String id = fields[0].trim();
-                if (id.indexOf(' ') < 0) {
-                    ids.put(id.toLowerCase(Locale.ROOT), id);
-                }
-                if (fields.length > 1) {
-                    String alias = fields[1].trim();
-                    if (alias.startsWith("http://";) || 
alias.startsWith("https://";)) {
-                        put(urls, normaliseUrl(alias), id);
-                    } else {
-                        put(names, normaliseName(alias), id);
-                    }
+                if (!line.trim().isEmpty() && !line.startsWith("#")) {
+                    lines.add(line.split("\t", 2));
                 }
             }
         } catch (IOException e) {
             throw new UncheckedIOException(e);
         }
+        return lines;
     }
 
     private static void put(Map<String, String> map, String key, String id) {
@@ -172,18 +190,154 @@ public class SpdxLicenses {
     }
 
     /**
-     * Groups projects by their SPDX license expression, leaving out the 
projects whose expression is unknown.
+     * Returns the license to use a project under: of the choices its licenses 
resolve to, the first one in
+     * ASF Category A, else in Category B, else without a known category, else 
in Category X. Choices that
+     * resolve to nothing are skipped, as are the alternatives of an 
<code>OR</code> expression that lose.
+     *
+     * @param project a project, typically a dependency
+     * @return the SPDX ID or expression of the chosen license, or {@code 
null} when none of its licenses resolve
+     */
+    public String preferred(MavenProject project) {
+        List<License> licenses = project == null ? null : 
project.getLicenses();
+        if (licenses == null) {
+            return null;
+        }
+        String best = null;
+        int bestRank = Integer.MAX_VALUE;
+        for (License license : licenses) {
+            String id = id(license);
+            if (id == null) {
+                continue;
+            }
+            for (String choice : alternatives(id)) {
+                int rank = rank(category(choice));
+                if (rank < bestRank) {
+                    best = choice;
+                    bestRank = rank;
+                }
+            }
+        }
+        return best;
+    }
+
+    /**
+     * Returns the <a href="https://www.apache.org/legal/resolved.html";>ASF 
license category</a> of an SPDX ID or
+     * expression: <code>A</code>, <code>B</code> or <code>X</code>. An 
<code>OR</code> expression takes the best
+     * category of its alternatives, an <code>AND</code> expression the worst 
of its parts.
+     *
+     * @param expression an SPDX ID or expression, for example from 
<code>$spdx.preferred($dependency)</code>
+     * @return the category, or {@code null} when it is not known
+     */
+    public String category(String expression) {
+        if (isBlank(expression)) {
+            return null;
+        }
+        String e = stripParentheses(expression.trim());
+        String category = categories.get(e.toLowerCase(Locale.ROOT));
+        if (category != null) {
+            return category;
+        }
+        List<String> alternatives = split(e, " OR ");
+        if (alternatives.size() > 1) {
+            String best = null;
+            for (String alternative : alternatives) {
+                String c = category(alternative);
+                best = rank(c) < rank(best) ? c : best;
+            }
+            return best;
+        }
+        List<String> parts = split(e, " AND ");
+        if (parts.size() > 1) {
+            String worst = "A";
+            for (String part : parts) {
+                String c = category(part);
+                worst = rank(c) > rank(worst) ? c : worst;
+            }
+            return worst;
+        }
+        int with = e.toUpperCase(Locale.ROOT).indexOf(" WITH ");
+        return with > 0 ? categories.get(e.substring(0, 
with).toLowerCase(Locale.ROOT)) : null;
+    }
+
+    /** A, B, unknown, X. */
+    private static int rank(String category) {
+        if ("A".equals(category)) {
+            return 0;
+        }
+        if ("B".equals(category)) {
+            return 1;
+        }
+        return "X".equals(category) ? 3 : 2;
+    }
+
+    /** Returns the alternatives of an <code>OR</code> expression, each 
without enclosing parentheses. */
+    private static List<String> alternatives(String expression) {
+        List<String> result = new ArrayList<>();
+        for (String alternative : split(stripParentheses(expression), " OR ")) 
{
+            String a = stripParentheses(alternative);
+            if (split(a, " OR ").size() > 1) {
+                result.addAll(alternatives(a));
+            } else {
+                result.add(a);
+            }
+        }
+        return result;
+    }
+
+    /** Splits at the operator where it is outside parentheses. */
+    private static List<String> split(String expression, String operator) {
+        List<String> parts = new ArrayList<>();
+        int depth = 0;
+        int start = 0;
+        for (int i = 0; i < expression.length(); i++) {
+            char c = expression.charAt(i);
+            if (c == '(') {
+                depth++;
+            } else if (c == ')') {
+                depth--;
+            } else if (depth == 0 && expression.regionMatches(true, i, 
operator, 0, operator.length())) {
+                parts.add(expression.substring(start, i).trim());
+                start = i + operator.length();
+                i = start - 1;
+            }
+        }
+        parts.add(expression.substring(start).trim());
+        return parts;
+    }
+
+    private static String stripParentheses(String expression) {
+        String e = expression.trim();
+        while (e.startsWith("(") && e.endsWith(")") && encloses(e)) {
+            e = e.substring(1, e.length() - 1).trim();
+        }
+        return e;
+    }
+
+    /** Whether the opening parenthesis at the start closes at the end. */
+    private static boolean encloses(String e) {
+        int depth = 0;
+        for (int i = 0; i < e.length(); i++) {
+            depth += e.charAt(i) == '(' ? 1 : e.charAt(i) == ')' ? -1 : 0;
+            if (depth == 0) {
+                return i == e.length() - 1;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Groups projects by their preferred license, leaving out the projects 
whose licenses resolve to nothing.
      *
      * @param projects projects, typically <code>$projects</code>
-     * @return the projects for each expression, sorted by expression
+     * @return the projects for each preferred license, sorted by SPDX ID
      */
     public Map<String, List<MavenProject>> group(List<MavenProject> projects) {
         Map<String, List<MavenProject>> groups = new 
TreeMap<>(String.CASE_INSENSITIVE_ORDER);
         if (projects != null) {
             for (MavenProject project : projects) {
-                String expression = expression(project);
-                if (expression != null) {
-                    groups.computeIfAbsent(expression, k -> new 
ArrayList<>()).add(project);
+                String preferred = preferred(project);
+                if (preferred != null) {
+                    groups.computeIfAbsent(preferred, k -> new 
ArrayList<>()).add(project);
                 }
             }
         }
@@ -191,8 +345,8 @@ public class SpdxLicenses {
     }
 
     /**
-     * Returns every SPDX license and exception ID that the projects' 
expressions use, each one once, so that a
-     * template can add each license text once.
+     * Returns every SPDX license and exception ID that the projects' 
preferred licenses use, each one once, so
+     * that a template can add each license text once.
      *
      * @param projects projects, typically <code>$projects</code>
      * @return the IDs, sorted
@@ -203,9 +357,7 @@ public class SpdxLicenses {
             Matcher m = EXPRESSION_TOKEN.matcher(expression);
             while (m.find()) {
                 String token = m.group();
-                if (!token.equalsIgnoreCase("AND")
-                        && !token.equalsIgnoreCase("OR")
-                        && !token.equalsIgnoreCase("WITH")) {
+                if (!isOperator(token) && !token.equals("(") && 
!token.equals(")")) {
                     result.add(token);
                 }
             }
@@ -214,16 +366,16 @@ public class SpdxLicenses {
     }
 
     /**
-     * Returns the projects whose SPDX license expression is unknown.
+     * Returns the projects that have no preferred license.
      *
      * @param projects projects, typically <code>$projects</code>
-     * @return the projects that declare no license or a license that matches 
nothing
+     * @return the projects that declare no license, or only licenses that 
match nothing
      */
     public List<MavenProject> unresolved(List<MavenProject> projects) {
         List<MavenProject> result = new ArrayList<>();
         if (projects != null) {
             for (MavenProject project : projects) {
-                if (expression(project) == null) {
+                if (preferred(project) == null) {
                     result.add(project);
                 }
             }
diff --git 
a/src/main/resources/org/apache/maven/plugin/resources/remote/license-categories.txt
 
b/src/main/resources/org/apache/maven/plugin/resources/remote/license-categories.txt
new file mode 100644
index 0000000..2d05426
--- /dev/null
+++ 
b/src/main/resources/org/apache/maven/plugin/resources/remote/license-categories.txt
@@ -0,0 +1,65 @@
+# 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.
+
+# ASF license categories of the IDs in license-aliases.txt, from
+# https://www.apache.org/legal/resolved.html. Category A may be included in ASF
+# products, Category B in binary form only and labelled, Category X not at all.
+#
+# Each line holds an SPDX ID or expression, a tab, and A, B or X. An ID that is
+# missing here has no known category.
+
+0BSD   A
+Apache-1.1     A
+Apache-2.0     A
+BSD-2-Clause   A
+BSD-3-Clause   A
+BSL-1.0        A
+CC0-1.0        A
+ISC    A
+MIT    A
+MIT-0  A
+UPL-1.0        A
+Unlicense      A
+
+CDDL-1.0       B
+CDDL-1.1       B
+CPL-1.0        B
+EPL-1.0        B
+EPL-2.0        B
+MPL-1.0        B
+MPL-1.1        B
+MPL-2.0        B
+GPL-2.0-only WITH Classpath-exception-2.0      B
+
+AGPL-3.0-only  X
+AGPL-3.0-or-later      X
+GPL-2.0        X
+GPL-2.0+       X
+GPL-2.0-only   X
+GPL-2.0-or-later       X
+GPL-3.0        X
+GPL-3.0+       X
+GPL-3.0-only   X
+GPL-3.0-or-later       X
+LGPL-2.1       X
+LGPL-2.1+      X
+LGPL-2.1-only  X
+LGPL-2.1-or-later      X
+LGPL-3.0       X
+LGPL-3.0+      X
+LGPL-3.0-only  X
+LGPL-3.0-or-later      X
diff --git a/src/site/markdown/usage.md.vm b/src/site/markdown/usage.md.vm
index c2d81ba..6b082fe 100644
--- a/src/site/markdown/usage.md.vm
+++ b/src/site/markdown/usage.md.vm
@@ -131,7 +131,9 @@ A mapping matches a spelling wherever it appears, like 
`licenseMerges` in the [L
 
 A dependency that declares several licenses may be used under any one of them. 
`${esc.d}spdx.expression(${esc.d}dependency)` returns one SPDX license 
expression for the whole dependency, joining the IDs with `OR`, for example 
`CDDL-1.1 OR (GPL-2.0-only WITH Classpath-exception-2.0)`. It returns null when 
the dependency declares no license or when one of its licenses matches nothing, 
because a partial expression would leave out a choice.
 
-To list each license once rather than once per dependency, group the 
dependencies by SPDX expression. `${esc.d}spdx.ids(${esc.d}projects)` returns 
every license and exception ID in use, each one once, so a template can add 
each license text once. `${esc.d}spdx.unresolved(${esc.d}projects)` returns the 
dependencies that `${esc.d}spdx` could not resolve, which still need their 
declared licenses listed:
+An ASF distribution states the one license it uses a dependency under: 
"include only the license that you have chosen. Prefer Category A to Category B 
to Category X" ([ASF 3rd Party License 
Policy](https://www.apache.org/legal/resolved.html)). 
`${esc.d}spdx.preferred(${esc.d}dependency)` makes that choice. Of the licenses 
that resolve, it returns the first one in Category A, else in Category B, else 
one without a known category, else in Category X; licenses that resolve to 
nothing are sk [...]
+
+To list each license once rather than once per dependency, 
`${esc.d}spdx.group(${esc.d}projects)` groups the dependencies by preferred 
license. `${esc.d}spdx.ids(${esc.d}projects)` returns every license and 
exception ID in use, each one once, so a template can add each license text 
once. `${esc.d}spdx.unresolved(${esc.d}projects)` returns the dependencies 
without a preferred license, which still need their declared licenses listed:
 
 ```
 #[[#foreach( $group in $spdx.group($projects).entrySet() )
diff --git 
a/src/test/java/org/apache/maven/plugin/resources/remote/SpdxLicensesTest.java 
b/src/test/java/org/apache/maven/plugin/resources/remote/SpdxLicensesTest.java
index 47fcb51..39ef612 100644
--- 
a/src/test/java/org/apache/maven/plugin/resources/remote/SpdxLicensesTest.java
+++ 
b/src/test/java/org/apache/maven/plugin/resources/remote/SpdxLicensesTest.java
@@ -139,16 +139,63 @@ class SpdxLicensesTest {
 
         Map<String, List<MavenProject>> groups = spdx.group(projects);
         assertEquals(
-                Arrays.asList(
-                        "Apache-2.0", "Apache-2.0 OR MIT", "CDDL-1.1 OR 
(GPL-2.0-only WITH Classpath-exception-2.0)"),
+                Arrays.asList("Apache-2.0", "CDDL-1.1"),
                 Arrays.asList(groups.keySet().toArray()));
-        assertEquals(Arrays.asList(a, b), groups.get("Apache-2.0"));
+        assertEquals(Arrays.asList(a, b, e), groups.get("Apache-2.0"));
+        assertEquals(Arrays.asList(c), groups.get("CDDL-1.1"));
         assertEquals(
-                Arrays.asList("Apache-2.0", "CDDL-1.1", 
"Classpath-exception-2.0", "GPL-2.0-only", "MIT"),
+                Arrays.asList("Apache-2.0", "CDDL-1.1"),
                 Arrays.asList(spdx.ids(projects).toArray()));
         assertEquals(Arrays.asList(d), spdx.unresolved(projects));
     }
 
+    @Test
+    void preferredSkipsUnresolvedChoices() {
+        // javassist 3.30.2-GA and rocksdbjni 9.7.3 as their POMs declare them
+        assertEquals(
+                "Apache-2.0",
+                spdx.preferred(project(
+                        license("MPL 1.1", 
"https://www.mozilla.org/en-US/MPL/1.1/";),
+                        license("LGPL 2.1", 
"https://www.gnu.org/licenses/lgpl-2.1.html";),
+                        license("Apache License 2.0", 
"https://www.apache.org/licenses/LICENSE-2.0";))));
+        assertEquals(
+                "Apache-2.0",
+                spdx.preferred(project(
+                        license("Apache License 2.0", 
"http://www.apache.org/licenses/LICENSE-2.0.html";),
+                        license("GNU General Public License, version 2", 
"http://www.gnu.org/licenses/gpl-2.0.html";))));
+        assertNull(spdx.preferred(project(license("Public Domain", null))));
+        assertNull(spdx.preferred(project()));
+        assertNull(spdx.preferred(null));
+    }
+
+    @Test
+    void preferredFollowsCategory() {
+        assertEquals("MPL-1.1", 
spdx.preferred(project(license("LGPL-2.1-only", null), license("MPL 1.1", 
null))));
+        assertEquals("Apache-2.0", spdx.preferred(project(license("EPL-2.0 OR 
Apache-2.0", null))));
+        assertEquals("MIT", spdx.preferred(project(license("(MIT OR 
Apache-2.0)", null))));
+        assertEquals("GPL-2.0-only", 
spdx.preferred(project(license("GPL-2.0-only", null))));
+        assertEquals(
+                "LicenseRef-Widget",
+                spdx.preferred(project(license("GPL-3.0-only", null), 
license("LicenseRef-Widget", null))));
+        assertEquals(
+                "GPL-2.0-only WITH Classpath-exception-2.0",
+                spdx.preferred(project(license("GPL-3.0-only", null), 
license("GPL2 w/ CPE", null))));
+    }
+
+    @Test
+    void category() {
+        assertEquals("A", spdx.category("Apache-2.0"));
+        assertEquals("B", spdx.category("EPL-2.0"));
+        assertEquals("X", spdx.category("LGPL-2.1-or-later"));
+        assertEquals("B", spdx.category("GPL-2.0-only WITH 
Classpath-exception-2.0"));
+        assertEquals("X", spdx.category("GPL-3.0-only WITH 
Classpath-exception-2.0"));
+        assertEquals("A", spdx.category("(MIT OR GPL-2.0-only)"));
+        assertEquals("B", spdx.category("MIT AND EPL-2.0"));
+        assertNull(spdx.category("MIT AND Zlib"));
+        assertNull(spdx.category("Zlib"));
+        assertNull(spdx.category(null));
+    }
+
     private static License license(String name, String url) {
         License license = new License();
         license.setName(name);
diff --git 
a/src/test/java/org/apache/maven/plugin/resources/remote/it/ITSpdxLicenseId.java
 
b/src/test/java/org/apache/maven/plugin/resources/remote/it/ITSpdxLicenseId.java
index c65ea2c..423d44a 100644
--- 
a/src/test/java/org/apache/maven/plugin/resources/remote/it/ITSpdxLicenseId.java
+++ 
b/src/test/java/org/apache/maven/plugin/resources/remote/it/ITSpdxLicenseId.java
@@ -62,18 +62,25 @@ public class ITSpdxLicenseId extends AbstractIT {
                 content);
         assertTrue(content.contains("f-mapped: BSD-3-Clause\n"), content);
 
-        assertTrue(content.contains("Group Apache-2.0: a-name b-url\n"), 
content);
-        assertTrue(content.contains("Group (Apache-2.0 OR EPL-2.0): 
c-expression\n"), content);
+        assertTrue(content.contains("c-expression preferred: Apache-2.0 A\n"), 
content);
+        assertTrue(content.contains("e-dual preferred: CDDL-1.1 B\n"), 
content);
+        assertTrue(content.contains("d-unknown preferred:\n"), content);
+
+        assertTrue(content.contains("Group Apache-2.0: a-name b-url 
c-expression\n"), content);
+        assertTrue(content.contains("Group CDDL-1.1: e-dual\n"), content);
         assertTrue(content.contains("Unresolved: d-unknown\n"), content);
-        assertEquals(1, content.split("License text: Apache-2.0\n", -1).length 
- 1, content);
-        assertTrue(content.contains("License text: 
Classpath-exception-2.0\n"), content);
+        assertEquals(
+                "License text: Apache-2.0\nLicense text: BSD-3-Clause\nLicense 
text: CDDL-1.1\n",
+                content.replaceAll("(?m)^(?!License text: ).*\n", ""),
+                content);
 
+        assertTrue(content.contains("Org Example Org:\n  License Apache-2.0: 
a-name c-expression\n"), content);
         assertTrue(
-                content.contains("Org Example Org:\n"
-                        + "  License (Apache-2.0 OR EPL-2.0): c-expression\n"
-                        + "  License Apache-2.0: a-name\n"),
+                content.contains("Org an unknown organization:\n"
+                        + "  License Apache-2.0: b-url\n"
+                        + "  License BSD-3-Clause: f-mapped\n"
+                        + "  License CDDL-1.1: e-dual\n"
+                        + "  Unresolved d-unknown\n"),
                 content);
-        assertTrue(content.contains("Org an unknown organization:\n  License 
Apache-2.0: b-url\n"), content);
-        assertTrue(content.contains("  Unresolved d-unknown\n"), content);
     }
 }

Reply via email to