Move compliance commands into subdirectories

Move each compliance command into its own directory to avoid Go tooling
considering all the files to be a single package and complaining about
conflicting global names.

Test: go test ./...
Change-Id: I3db6310e7368bcc7fe6a3704b40a84078ed44209
diff --git a/tools/compliance/cmd/dumpresolutions/dumpresolutions.go b/tools/compliance/cmd/dumpresolutions/dumpresolutions.go
new file mode 100644
index 0000000..463dfad
--- /dev/null
+++ b/tools/compliance/cmd/dumpresolutions/dumpresolutions.go
@@ -0,0 +1,238 @@
+// Copyright 2021 Google LLC
+//
+// Licensed 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 main
+
+import (
+	"flag"
+	"fmt"
+	"io"
+	"os"
+	"path/filepath"
+	"sort"
+	"strings"
+
+	"android/soong/tools/compliance"
+)
+
+var (
+	conditions      = newMultiString("c", "License condition to resolve. (may be given multiple times)")
+	graphViz        = flag.Bool("dot", false, "Whether to output graphviz (i.e. dot) format.")
+	labelConditions = flag.Bool("label_conditions", false, "Whether to label target nodes with conditions.")
+	stripPrefix     = flag.String("strip_prefix", "", "Prefix to remove from paths. i.e. path to root")
+
+	failNoneRequested = fmt.Errorf("\nNo license metadata files requested")
+	failNoLicenses    = fmt.Errorf("No licenses found")
+)
+
+type context struct {
+	conditions      []compliance.LicenseCondition
+	graphViz        bool
+	labelConditions bool
+	stripPrefix     string
+}
+
+func init() {
+	flag.Usage = func() {
+		fmt.Fprintf(os.Stderr, `Usage: %s {options} file.meta_lic {file.meta_lic...}
+
+Outputs a space-separated Target ActsOn Origin Condition tuple for each
+resolution in the graph. When -dot flag given, outputs nodes and edges
+in graphviz directed graph format.
+
+If one or more '-c condition' conditions are given, outputs the
+resolution for the union of the conditions. Otherwise, outputs the
+resolution for all conditions.
+
+In plain text mode, when '-label_conditions' is requested, the Target
+and Origin have colon-separated license conditions appended:
+i.e. target:condition1:condition2 etc.
+
+Options:
+`, filepath.Base(os.Args[0]))
+		flag.PrintDefaults()
+	}
+}
+
+// newMultiString creates a flag that allows multiple values in an array.
+func newMultiString(name, usage string) *multiString {
+	var f multiString
+	flag.Var(&f, name, usage)
+	return &f
+}
+
+// multiString implements the flag `Value` interface for multiple strings.
+type multiString []string
+
+func (ms *multiString) String() string     { return strings.Join(*ms, ", ") }
+func (ms *multiString) Set(s string) error { *ms = append(*ms, s); return nil }
+
+func main() {
+	flag.Parse()
+
+	// Must specify at least one root target.
+	if flag.NArg() == 0 {
+		flag.Usage()
+		os.Exit(2)
+	}
+
+	lcs := make([]compliance.LicenseCondition, 0, len(*conditions))
+	for _, name := range *conditions {
+		lcs = append(lcs, compliance.RecognizedConditionNames[name])
+	}
+	ctx := &context{
+		conditions:      lcs,
+		graphViz:        *graphViz,
+		labelConditions: *labelConditions,
+		stripPrefix:     *stripPrefix,
+	}
+	_, err := dumpResolutions(ctx, os.Stdout, os.Stderr, flag.Args()...)
+	if err != nil {
+		if err == failNoneRequested {
+			flag.Usage()
+		}
+		fmt.Fprintf(os.Stderr, "%s\n", err.Error())
+		os.Exit(1)
+	}
+	os.Exit(0)
+}
+
+// dumpResolutions implements the dumpresolutions utility.
+func dumpResolutions(ctx *context, stdout, stderr io.Writer, files ...string) (*compliance.LicenseGraph, error) {
+	if len(files) < 1 {
+		return nil, failNoneRequested
+	}
+
+	// Read the license graph from the license metadata files (*.meta_lic).
+	licenseGraph, err := compliance.ReadLicenseGraph(os.DirFS("."), stderr, files)
+	if err != nil {
+		return nil, fmt.Errorf("Unable to read license metadata file(s) %q: %v\n", files, err)
+	}
+	if licenseGraph == nil {
+		return nil, failNoLicenses
+	}
+
+	compliance.ResolveTopDownConditions(licenseGraph)
+	cs := compliance.AllLicenseConditions
+	if len(ctx.conditions) > 0 {
+		cs = compliance.NewLicenseConditionSet()
+		for _, c := range ctx.conditions {
+			cs = cs.Plus(c)
+		}
+	}
+
+	resolutions := compliance.WalkResolutionsForCondition(licenseGraph, cs)
+
+	// nodes maps license metadata file names to graphViz node names when graphViz requested.
+	nodes := make(map[string]string)
+	n := 0
+
+	// targetOut calculates the string to output for `target` adding `sep`-separated conditions as needed.
+	targetOut := func(target *compliance.TargetNode, sep string) string {
+		tOut := strings.TrimPrefix(target.Name(), ctx.stripPrefix)
+		if ctx.labelConditions {
+			conditions := target.LicenseConditions().Names()
+			if len(conditions) > 0 {
+				tOut += sep + strings.Join(conditions, sep)
+			}
+		}
+		return tOut
+	}
+
+	// makeNode maps `target` to a graphViz node name.
+	makeNode := func(target *compliance.TargetNode) {
+		tName := target.Name()
+		if _, ok := nodes[tName]; !ok {
+			nodeName := fmt.Sprintf("n%d", n)
+			nodes[tName] = nodeName
+			fmt.Fprintf(stdout, "\t%s [label=\"%s\"];\n", nodeName, targetOut(target, "\\n"))
+			n++
+		}
+	}
+
+	// outputResolution prints a resolution in the requested format to `stdout`, where one can read
+	// a resolution as `tname` resolves `oname`'s conditions named in `cnames`.
+	// `tname` is the name of the target the resolution applies to.
+	// `cnames` is the list of conditions to resolve.
+	outputResolution := func(tname, aname string, cnames []string) {
+		if ctx.graphViz {
+			// ... one edge per line labelled with \\n-separated annotations.
+			tNode := nodes[tname]
+			aNode := nodes[aname]
+			fmt.Fprintf(stdout, "\t%s -> %s [label=\"%s\"];\n", tNode, aNode, strings.Join(cnames, "\\n"))
+		} else {
+			// ... one edge per line with names in a colon-separated tuple.
+			fmt.Fprintf(stdout, "%s %s %s\n", tname, aname, strings.Join(cnames, ":"))
+		}
+	}
+
+	// Sort the resolutions by targetname for repeatability/stability.
+	targets := resolutions.AttachesTo()
+	sort.Sort(targets)
+
+	// If graphviz output, start the directed graph.
+	if ctx.graphViz {
+		fmt.Fprintf(stdout, "strict digraph {\n\trankdir=LR;\n")
+		for _, target := range targets {
+			makeNode(target)
+			rl := resolutions.Resolutions(target)
+			sort.Sort(rl)
+			for _, r := range rl {
+				makeNode(r.ActsOn())
+			}
+		}
+	}
+
+	// Output the sorted targets.
+	for _, target := range targets {
+		var tname string
+		if ctx.graphViz {
+			tname = target.Name()
+		} else {
+			tname = targetOut(target, ":")
+		}
+
+		rl := resolutions.Resolutions(target)
+		sort.Sort(rl)
+		for _, r := range rl {
+			var aname string
+			if ctx.graphViz {
+				aname = r.ActsOn().Name()
+			} else {
+				aname = targetOut(r.ActsOn(), ":")
+			}
+
+			// cnames accumulates the list of condition names originating at a single origin that apply to `target`.
+			cnames := r.Resolves().Names()
+
+			// Output 1 line for each attachesTo+actsOn combination.
+			outputResolution(tname, aname, cnames)
+		}
+	}
+	// If graphViz output, rank the root nodes together, and complete the directed graph.
+	if ctx.graphViz {
+		fmt.Fprintf(stdout, "\t{rank=same;")
+		for _, f := range files {
+			fName := f
+			if !strings.HasSuffix(fName, ".meta_lic") {
+				fName += ".meta_lic"
+			}
+			if fNode, ok := nodes[fName]; ok {
+				fmt.Fprintf(stdout, " %s", fNode)
+			}
+		}
+		fmt.Fprintf(stdout, "}\n}\n")
+	}
+	return licenseGraph, nil
+}
diff --git a/tools/compliance/cmd/dumpresolutions/dumpresolutions_test.go b/tools/compliance/cmd/dumpresolutions/dumpresolutions_test.go
new file mode 100644
index 0000000..b698bf2
--- /dev/null
+++ b/tools/compliance/cmd/dumpresolutions/dumpresolutions_test.go
@@ -0,0 +1,3358 @@
+// Copyright 2021 Google LLC
+//
+// Licensed 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 main
+
+import (
+	"bytes"
+	"fmt"
+	"os"
+	"strings"
+	"testing"
+
+	"android/soong/tools/compliance"
+)
+
+func TestMain(m *testing.M) {
+	// Change into the parent directory before running the tests
+	// so they can find the testdata directory.
+	if err := os.Chdir(".."); err != nil {
+		fmt.Printf("failed to change to testdata directory: %s\n", err)
+		os.Exit(1)
+	}
+	os.Exit(m.Run())
+}
+
+func Test_plaintext(t *testing.T) {
+	tests := []struct {
+		condition   string
+		name        string
+		roots       []string
+		ctx         context
+		expectedOut []string
+	}{
+		{
+			condition: "firstparty",
+			name:      "apex",
+			roots:     []string{"highest.apex.meta_lic"},
+			expectedOut: []string{
+				"testdata/firstparty/bin/bin1.meta_lic testdata/firstparty/bin/bin1.meta_lic notice",
+				"testdata/firstparty/bin/bin1.meta_lic testdata/firstparty/lib/liba.so.meta_lic notice",
+				"testdata/firstparty/bin/bin1.meta_lic testdata/firstparty/lib/libc.a.meta_lic notice",
+				"testdata/firstparty/bin/bin2.meta_lic testdata/firstparty/bin/bin2.meta_lic notice",
+				"testdata/firstparty/highest.apex.meta_lic testdata/firstparty/bin/bin1.meta_lic notice",
+				"testdata/firstparty/highest.apex.meta_lic testdata/firstparty/bin/bin2.meta_lic notice",
+				"testdata/firstparty/highest.apex.meta_lic testdata/firstparty/highest.apex.meta_lic notice",
+				"testdata/firstparty/highest.apex.meta_lic testdata/firstparty/lib/liba.so.meta_lic notice",
+				"testdata/firstparty/highest.apex.meta_lic testdata/firstparty/lib/libb.so.meta_lic notice",
+				"testdata/firstparty/highest.apex.meta_lic testdata/firstparty/lib/libc.a.meta_lic notice",
+				"testdata/firstparty/lib/liba.so.meta_lic testdata/firstparty/lib/liba.so.meta_lic notice",
+				"testdata/firstparty/lib/libb.so.meta_lic testdata/firstparty/lib/libb.so.meta_lic notice",
+			},
+		},
+		{
+			condition: "firstparty",
+			name:      "apex_trimmed",
+			roots:     []string{"highest.apex.meta_lic"},
+			ctx:       context{stripPrefix: "testdata/firstparty/"},
+			expectedOut: []string{
+				"bin/bin1.meta_lic bin/bin1.meta_lic notice",
+				"bin/bin1.meta_lic lib/liba.so.meta_lic notice",
+				"bin/bin1.meta_lic lib/libc.a.meta_lic notice",
+				"bin/bin2.meta_lic bin/bin2.meta_lic notice",
+				"highest.apex.meta_lic bin/bin1.meta_lic notice",
+				"highest.apex.meta_lic bin/bin2.meta_lic notice",
+				"highest.apex.meta_lic highest.apex.meta_lic notice",
+				"highest.apex.meta_lic lib/liba.so.meta_lic notice",
+				"highest.apex.meta_lic lib/libb.so.meta_lic notice",
+				"highest.apex.meta_lic lib/libc.a.meta_lic notice",
+				"lib/liba.so.meta_lic lib/liba.so.meta_lic notice",
+				"lib/libb.so.meta_lic lib/libb.so.meta_lic notice",
+			},
+		},
+		{
+			condition: "firstparty",
+			name:      "apex_trimmed_notice",
+			roots:     []string{"highest.apex.meta_lic"},
+			ctx: context{
+				conditions:  []compliance.LicenseCondition{compliance.NoticeCondition},
+				stripPrefix: "testdata/firstparty/",
+			},
+			expectedOut: []string{
+				"bin/bin1.meta_lic bin/bin1.meta_lic notice",
+				"bin/bin1.meta_lic lib/liba.so.meta_lic notice",
+				"bin/bin1.meta_lic lib/libc.a.meta_lic notice",
+				"bin/bin2.meta_lic bin/bin2.meta_lic notice",
+				"highest.apex.meta_lic bin/bin1.meta_lic notice",
+				"highest.apex.meta_lic bin/bin2.meta_lic notice",
+				"highest.apex.meta_lic highest.apex.meta_lic notice",
+				"highest.apex.meta_lic lib/liba.so.meta_lic notice",
+				"highest.apex.meta_lic lib/libb.so.meta_lic notice",
+				"highest.apex.meta_lic lib/libc.a.meta_lic notice",
+				"lib/liba.so.meta_lic lib/liba.so.meta_lic notice",
+				"lib/libb.so.meta_lic lib/libb.so.meta_lic notice",
+			},
+		},
+		{
+			condition: "firstparty",
+			name:      "apex_trimmed_share",
+			roots:     []string{"highest.apex.meta_lic"},
+			ctx: context{
+				conditions:  compliance.ImpliesShared.AsList(),
+				stripPrefix: "testdata/firstparty/",
+			},
+			expectedOut: []string{},
+		},
+		{
+			condition: "firstparty",
+			name:      "apex_trimmed_private",
+			roots:     []string{"highest.apex.meta_lic"},
+			ctx: context{
+				conditions:  compliance.ImpliesPrivate.AsList(),
+				stripPrefix: "testdata/firstparty/",
+			},
+			expectedOut: []string{},
+		},
+		{
+			condition: "firstparty",
+			name:      "apex_trimmed_share_private",
+			roots:     []string{"highest.apex.meta_lic"},
+			ctx: context{
+				conditions:  append(compliance.ImpliesPrivate.AsList(), compliance.ImpliesShared.AsList()...),
+				stripPrefix: "testdata/firstparty/",
+			},
+			expectedOut: []string{},
+		},
+		{
+			condition: "firstparty",
+			name:      "apex_trimmed_labelled",
+			roots:     []string{"highest.apex.meta_lic"},
+			ctx:       context{stripPrefix: "testdata/firstparty/", labelConditions: true},
+			expectedOut: []string{
+				"bin/bin1.meta_lic:notice bin/bin1.meta_lic:notice notice",
+				"bin/bin1.meta_lic:notice lib/liba.so.meta_lic:notice notice",
+				"bin/bin1.meta_lic:notice lib/libc.a.meta_lic:notice notice",
+				"bin/bin2.meta_lic:notice bin/bin2.meta_lic:notice notice",
+				"highest.apex.meta_lic:notice bin/bin1.meta_lic:notice notice",
+				"highest.apex.meta_lic:notice bin/bin2.meta_lic:notice notice",
+				"highest.apex.meta_lic:notice highest.apex.meta_lic:notice notice",
+				"highest.apex.meta_lic:notice lib/liba.so.meta_lic:notice notice",
+				"highest.apex.meta_lic:notice lib/libb.so.meta_lic:notice notice",
+				"highest.apex.meta_lic:notice lib/libc.a.meta_lic:notice notice",
+				"lib/liba.so.meta_lic:notice lib/liba.so.meta_lic:notice notice",
+				"lib/libb.so.meta_lic:notice lib/libb.so.meta_lic:notice notice",
+			},
+		},
+		{
+			condition: "firstparty",
+			name:      "container",
+			roots:     []string{"container.zip.meta_lic"},
+			expectedOut: []string{
+				"testdata/firstparty/bin/bin1.meta_lic testdata/firstparty/bin/bin1.meta_lic notice",
+				"testdata/firstparty/bin/bin1.meta_lic testdata/firstparty/lib/liba.so.meta_lic notice",
+				"testdata/firstparty/bin/bin1.meta_lic testdata/firstparty/lib/libc.a.meta_lic notice",
+				"testdata/firstparty/bin/bin2.meta_lic testdata/firstparty/bin/bin2.meta_lic notice",
+				"testdata/firstparty/container.zip.meta_lic testdata/firstparty/bin/bin1.meta_lic notice",
+				"testdata/firstparty/container.zip.meta_lic testdata/firstparty/bin/bin2.meta_lic notice",
+				"testdata/firstparty/container.zip.meta_lic testdata/firstparty/container.zip.meta_lic notice",
+				"testdata/firstparty/container.zip.meta_lic testdata/firstparty/lib/liba.so.meta_lic notice",
+				"testdata/firstparty/container.zip.meta_lic testdata/firstparty/lib/libb.so.meta_lic notice",
+				"testdata/firstparty/container.zip.meta_lic testdata/firstparty/lib/libc.a.meta_lic notice",
+				"testdata/firstparty/lib/liba.so.meta_lic testdata/firstparty/lib/liba.so.meta_lic notice",
+				"testdata/firstparty/lib/libb.so.meta_lic testdata/firstparty/lib/libb.so.meta_lic notice",
+			},
+		},
+		{
+			condition: "firstparty",
+			name:      "application",
+			roots:     []string{"application.meta_lic"},
+			expectedOut: []string{
+				"testdata/firstparty/application.meta_lic testdata/firstparty/application.meta_lic notice",
+				"testdata/firstparty/application.meta_lic testdata/firstparty/lib/liba.so.meta_lic notice",
+			},
+		},
+		{
+			condition: "firstparty",
+			name:      "binary",
+			roots:     []string{"bin/bin1.meta_lic"},
+			expectedOut: []string{
+				"testdata/firstparty/bin/bin1.meta_lic testdata/firstparty/bin/bin1.meta_lic notice",
+				"testdata/firstparty/bin/bin1.meta_lic testdata/firstparty/lib/liba.so.meta_lic notice",
+				"testdata/firstparty/bin/bin1.meta_lic testdata/firstparty/lib/libc.a.meta_lic notice",
+			},
+		},
+		{
+			condition: "firstparty",
+			name:      "library",
+			roots:     []string{"lib/libd.so.meta_lic"},
+			expectedOut: []string{
+				"testdata/firstparty/lib/libd.so.meta_lic testdata/firstparty/lib/libd.so.meta_lic notice",
+			},
+		},
+		{
+			condition: "notice",
+			name:      "apex",
+			roots:     []string{"highest.apex.meta_lic"},
+			expectedOut: []string{
+				"testdata/notice/bin/bin1.meta_lic testdata/notice/bin/bin1.meta_lic notice",
+				"testdata/notice/bin/bin1.meta_lic testdata/notice/lib/liba.so.meta_lic notice",
+				"testdata/notice/bin/bin1.meta_lic testdata/notice/lib/libc.a.meta_lic notice",
+				"testdata/notice/bin/bin2.meta_lic testdata/notice/bin/bin2.meta_lic notice",
+				"testdata/notice/highest.apex.meta_lic testdata/notice/bin/bin1.meta_lic notice",
+				"testdata/notice/highest.apex.meta_lic testdata/notice/bin/bin2.meta_lic notice",
+				"testdata/notice/highest.apex.meta_lic testdata/notice/highest.apex.meta_lic notice",
+				"testdata/notice/highest.apex.meta_lic testdata/notice/lib/liba.so.meta_lic notice",
+				"testdata/notice/highest.apex.meta_lic testdata/notice/lib/libb.so.meta_lic notice",
+				"testdata/notice/highest.apex.meta_lic testdata/notice/lib/libc.a.meta_lic notice",
+				"testdata/notice/lib/liba.so.meta_lic testdata/notice/lib/liba.so.meta_lic notice",
+				"testdata/notice/lib/libb.so.meta_lic testdata/notice/lib/libb.so.meta_lic notice",
+			},
+		},
+		{
+			condition: "notice",
+			name:      "apex_trimmed",
+			roots:     []string{"highest.apex.meta_lic"},
+			ctx:       context{stripPrefix: "testdata/notice/"},
+			expectedOut: []string{
+				"bin/bin1.meta_lic bin/bin1.meta_lic notice",
+				"bin/bin1.meta_lic lib/liba.so.meta_lic notice",
+				"bin/bin1.meta_lic lib/libc.a.meta_lic notice",
+				"bin/bin2.meta_lic bin/bin2.meta_lic notice",
+				"highest.apex.meta_lic bin/bin1.meta_lic notice",
+				"highest.apex.meta_lic bin/bin2.meta_lic notice",
+				"highest.apex.meta_lic highest.apex.meta_lic notice",
+				"highest.apex.meta_lic lib/liba.so.meta_lic notice",
+				"highest.apex.meta_lic lib/libb.so.meta_lic notice",
+				"highest.apex.meta_lic lib/libc.a.meta_lic notice",
+				"lib/liba.so.meta_lic lib/liba.so.meta_lic notice",
+				"lib/libb.so.meta_lic lib/libb.so.meta_lic notice",
+			},
+		},
+		{
+			condition: "notice",
+			name:      "apex_trimmed_notice",
+			roots:     []string{"highest.apex.meta_lic"},
+			ctx: context{
+				conditions:  []compliance.LicenseCondition{compliance.NoticeCondition},
+				stripPrefix: "testdata/notice/",
+			},
+			expectedOut: []string{
+				"bin/bin1.meta_lic bin/bin1.meta_lic notice",
+				"bin/bin1.meta_lic lib/liba.so.meta_lic notice",
+				"bin/bin1.meta_lic lib/libc.a.meta_lic notice",
+				"bin/bin2.meta_lic bin/bin2.meta_lic notice",
+				"highest.apex.meta_lic bin/bin1.meta_lic notice",
+				"highest.apex.meta_lic bin/bin2.meta_lic notice",
+				"highest.apex.meta_lic highest.apex.meta_lic notice",
+				"highest.apex.meta_lic lib/liba.so.meta_lic notice",
+				"highest.apex.meta_lic lib/libb.so.meta_lic notice",
+				"highest.apex.meta_lic lib/libc.a.meta_lic notice",
+				"lib/liba.so.meta_lic lib/liba.so.meta_lic notice",
+				"lib/libb.so.meta_lic lib/libb.so.meta_lic notice",
+			},
+		},
+		{
+			condition: "notice",
+			name:      "apex_trimmed_share",
+			roots:     []string{"highest.apex.meta_lic"},
+			ctx: context{
+				conditions:  compliance.ImpliesShared.AsList(),
+				stripPrefix: "testdata/notice/",
+			},
+			expectedOut: []string{},
+		},
+		{
+			condition: "notice",
+			name:      "apex_trimmed_private",
+			roots:     []string{"highest.apex.meta_lic"},
+			ctx: context{
+				conditions:  compliance.ImpliesPrivate.AsList(),
+				stripPrefix: "testdata/notice/",
+			},
+			expectedOut: []string{},
+		},
+		{
+			condition: "notice",
+			name:      "apex_trimmed_share_private",
+			roots:     []string{"highest.apex.meta_lic"},
+			ctx: context{
+				conditions:  append(compliance.ImpliesShared.AsList(), compliance.ImpliesPrivate.AsList()...),
+				stripPrefix: "testdata/notice/",
+			},
+			expectedOut: []string{},
+		},
+		{
+			condition: "notice",
+			name:      "apex_trimmed_labelled",
+			roots:     []string{"highest.apex.meta_lic"},
+			ctx:       context{stripPrefix: "testdata/notice/", labelConditions: true},
+			expectedOut: []string{
+				"bin/bin1.meta_lic:notice bin/bin1.meta_lic:notice notice",
+				"bin/bin1.meta_lic:notice lib/liba.so.meta_lic:notice notice",
+				"bin/bin1.meta_lic:notice lib/libc.a.meta_lic:notice notice",
+				"bin/bin2.meta_lic:notice bin/bin2.meta_lic:notice notice",
+				"highest.apex.meta_lic:notice bin/bin1.meta_lic:notice notice",
+				"highest.apex.meta_lic:notice bin/bin2.meta_lic:notice notice",
+				"highest.apex.meta_lic:notice highest.apex.meta_lic:notice notice",
+				"highest.apex.meta_lic:notice lib/liba.so.meta_lic:notice notice",
+				"highest.apex.meta_lic:notice lib/libb.so.meta_lic:notice notice",
+				"highest.apex.meta_lic:notice lib/libc.a.meta_lic:notice notice",
+				"lib/liba.so.meta_lic:notice lib/liba.so.meta_lic:notice notice",
+				"lib/libb.so.meta_lic:notice lib/libb.so.meta_lic:notice notice",
+			},
+		},
+		{
+			condition: "notice",
+			name:      "container",
+			roots:     []string{"container.zip.meta_lic"},
+			expectedOut: []string{
+				"testdata/notice/bin/bin1.meta_lic testdata/notice/bin/bin1.meta_lic notice",
+				"testdata/notice/bin/bin1.meta_lic testdata/notice/lib/liba.so.meta_lic notice",
+				"testdata/notice/bin/bin1.meta_lic testdata/notice/lib/libc.a.meta_lic notice",
+				"testdata/notice/bin/bin2.meta_lic testdata/notice/bin/bin2.meta_lic notice",
+				"testdata/notice/container.zip.meta_lic testdata/notice/bin/bin1.meta_lic notice",
+				"testdata/notice/container.zip.meta_lic testdata/notice/bin/bin2.meta_lic notice",
+				"testdata/notice/container.zip.meta_lic testdata/notice/container.zip.meta_lic notice",
+				"testdata/notice/container.zip.meta_lic testdata/notice/lib/liba.so.meta_lic notice",
+				"testdata/notice/container.zip.meta_lic testdata/notice/lib/libb.so.meta_lic notice",
+				"testdata/notice/container.zip.meta_lic testdata/notice/lib/libc.a.meta_lic notice",
+				"testdata/notice/lib/liba.so.meta_lic testdata/notice/lib/liba.so.meta_lic notice",
+				"testdata/notice/lib/libb.so.meta_lic testdata/notice/lib/libb.so.meta_lic notice",
+			},
+		},
+		{
+			condition: "notice",
+			name:      "application",
+			roots:     []string{"application.meta_lic"},
+			expectedOut: []string{
+				"testdata/notice/application.meta_lic testdata/notice/application.meta_lic notice",
+				"testdata/notice/application.meta_lic testdata/notice/lib/liba.so.meta_lic notice",
+			},
+		},
+		{
+			condition: "notice",
+			name:      "binary",
+			roots:     []string{"bin/bin1.meta_lic"},
+			expectedOut: []string{
+				"testdata/notice/bin/bin1.meta_lic testdata/notice/bin/bin1.meta_lic notice",
+				"testdata/notice/bin/bin1.meta_lic testdata/notice/lib/liba.so.meta_lic notice",
+				"testdata/notice/bin/bin1.meta_lic testdata/notice/lib/libc.a.meta_lic notice",
+			},
+		},
+		{
+			condition: "notice",
+			name:      "library",
+			roots:     []string{"lib/libd.so.meta_lic"},
+			expectedOut: []string{
+				"testdata/notice/lib/libd.so.meta_lic testdata/notice/lib/libd.so.meta_lic notice",
+			},
+		},
+		{
+			condition: "reciprocal",
+			name:      "apex",
+			roots:     []string{"highest.apex.meta_lic"},
+			expectedOut: []string{
+				"testdata/reciprocal/bin/bin1.meta_lic testdata/reciprocal/bin/bin1.meta_lic notice",
+				"testdata/reciprocal/bin/bin1.meta_lic testdata/reciprocal/lib/liba.so.meta_lic reciprocal",
+				"testdata/reciprocal/bin/bin1.meta_lic testdata/reciprocal/lib/libc.a.meta_lic reciprocal",
+				"testdata/reciprocal/bin/bin2.meta_lic testdata/reciprocal/bin/bin2.meta_lic notice",
+				"testdata/reciprocal/highest.apex.meta_lic testdata/reciprocal/bin/bin1.meta_lic notice",
+				"testdata/reciprocal/highest.apex.meta_lic testdata/reciprocal/bin/bin2.meta_lic notice",
+				"testdata/reciprocal/highest.apex.meta_lic testdata/reciprocal/highest.apex.meta_lic notice",
+				"testdata/reciprocal/highest.apex.meta_lic testdata/reciprocal/lib/liba.so.meta_lic reciprocal",
+				"testdata/reciprocal/highest.apex.meta_lic testdata/reciprocal/lib/libb.so.meta_lic notice",
+				"testdata/reciprocal/highest.apex.meta_lic testdata/reciprocal/lib/libc.a.meta_lic reciprocal",
+				"testdata/reciprocal/lib/liba.so.meta_lic testdata/reciprocal/lib/liba.so.meta_lic reciprocal",
+				"testdata/reciprocal/lib/libb.so.meta_lic testdata/reciprocal/lib/libb.so.meta_lic notice",
+			},
+		},
+		{
+			condition: "reciprocal",
+			name:      "apex_trimmed",
+			roots:     []string{"highest.apex.meta_lic"},
+			ctx:       context{stripPrefix: "testdata/reciprocal/"},
+			expectedOut: []string{
+				"bin/bin1.meta_lic bin/bin1.meta_lic notice",
+				"bin/bin1.meta_lic lib/liba.so.meta_lic reciprocal",
+				"bin/bin1.meta_lic lib/libc.a.meta_lic reciprocal",
+				"bin/bin2.meta_lic bin/bin2.meta_lic notice",
+				"highest.apex.meta_lic bin/bin1.meta_lic notice",
+				"highest.apex.meta_lic bin/bin2.meta_lic notice",
+				"highest.apex.meta_lic highest.apex.meta_lic notice",
+				"highest.apex.meta_lic lib/liba.so.meta_lic reciprocal",
+				"highest.apex.meta_lic lib/libb.so.meta_lic notice",
+				"highest.apex.meta_lic lib/libc.a.meta_lic reciprocal",
+				"lib/liba.so.meta_lic lib/liba.so.meta_lic reciprocal",
+				"lib/libb.so.meta_lic lib/libb.so.meta_lic notice",
+			},
+		},
+		{
+			condition: "reciprocal",
+			name:      "apex_trimmed_notice",
+			roots:     []string{"highest.apex.meta_lic"},
+			ctx: context{
+				conditions:  []compliance.LicenseCondition{compliance.NoticeCondition},
+				stripPrefix: "testdata/reciprocal/",
+			},
+			expectedOut: []string{
+				"bin/bin1.meta_lic bin/bin1.meta_lic notice",
+				"bin/bin2.meta_lic bin/bin2.meta_lic notice",
+				"highest.apex.meta_lic bin/bin1.meta_lic notice",
+				"highest.apex.meta_lic bin/bin2.meta_lic notice",
+				"highest.apex.meta_lic highest.apex.meta_lic notice",
+				"highest.apex.meta_lic lib/libb.so.meta_lic notice",
+				"lib/libb.so.meta_lic lib/libb.so.meta_lic notice",
+			},
+		},
+		{
+			condition: "reciprocal",
+			name:      "apex_trimmed_share",
+			roots:     []string{"highest.apex.meta_lic"},
+			ctx: context{
+				conditions:  compliance.ImpliesShared.AsList(),
+				stripPrefix: "testdata/reciprocal/",
+			},
+			expectedOut: []string{
+				"bin/bin1.meta_lic lib/liba.so.meta_lic reciprocal",
+				"bin/bin1.meta_lic lib/libc.a.meta_lic reciprocal",
+				"highest.apex.meta_lic lib/liba.so.meta_lic reciprocal",
+				"highest.apex.meta_lic lib/libc.a.meta_lic reciprocal",
+				"lib/liba.so.meta_lic lib/liba.so.meta_lic reciprocal",
+			},
+		},
+		{
+			condition: "reciprocal",
+			name:      "apex_trimmed_private",
+			roots:     []string{"highest.apex.meta_lic"},
+			ctx: context{
+				conditions:  compliance.ImpliesPrivate.AsList(),
+				stripPrefix: "testdata/reciprocal/",
+			},
+			expectedOut: []string{},
+		},
+		{
+			condition: "reciprocal",
+			name:      "apex_trimmed_share_private",
+			roots:     []string{"highest.apex.meta_lic"},
+			ctx: context{
+				conditions:  append(compliance.ImpliesShared.AsList(), compliance.ImpliesPrivate.AsList()...),
+				stripPrefix: "testdata/reciprocal/",
+			},
+			expectedOut: []string{
+				"bin/bin1.meta_lic lib/liba.so.meta_lic reciprocal",
+				"bin/bin1.meta_lic lib/libc.a.meta_lic reciprocal",
+				"highest.apex.meta_lic lib/liba.so.meta_lic reciprocal",
+				"highest.apex.meta_lic lib/libc.a.meta_lic reciprocal",
+				"lib/liba.so.meta_lic lib/liba.so.meta_lic reciprocal",
+			},
+		},
+		{
+			condition: "reciprocal",
+			name:      "apex_trimmed_labelled",
+			roots:     []string{"highest.apex.meta_lic"},
+			ctx:       context{stripPrefix: "testdata/reciprocal/", labelConditions: true},
+			expectedOut: []string{
+				"bin/bin1.meta_lic:notice bin/bin1.meta_lic:notice notice",
+				"bin/bin1.meta_lic:notice lib/liba.so.meta_lic:reciprocal reciprocal",
+				"bin/bin1.meta_lic:notice lib/libc.a.meta_lic:reciprocal reciprocal",
+				"bin/bin2.meta_lic:notice bin/bin2.meta_lic:notice notice",
+				"highest.apex.meta_lic:notice bin/bin1.meta_lic:notice notice",
+				"highest.apex.meta_lic:notice bin/bin2.meta_lic:notice notice",
+				"highest.apex.meta_lic:notice highest.apex.meta_lic:notice notice",
+				"highest.apex.meta_lic:notice lib/liba.so.meta_lic:reciprocal reciprocal",
+				"highest.apex.meta_lic:notice lib/libb.so.meta_lic:notice notice",
+				"highest.apex.meta_lic:notice lib/libc.a.meta_lic:reciprocal reciprocal",
+				"lib/liba.so.meta_lic:reciprocal lib/liba.so.meta_lic:reciprocal reciprocal",
+				"lib/libb.so.meta_lic:notice lib/libb.so.meta_lic:notice notice",
+			},
+		},
+		{
+			condition: "reciprocal",
+			name:      "container",
+			roots:     []string{"container.zip.meta_lic"},
+			expectedOut: []string{
+				"testdata/reciprocal/bin/bin1.meta_lic testdata/reciprocal/bin/bin1.meta_lic notice",
+				"testdata/reciprocal/bin/bin1.meta_lic testdata/reciprocal/lib/liba.so.meta_lic reciprocal",
+				"testdata/reciprocal/bin/bin1.meta_lic testdata/reciprocal/lib/libc.a.meta_lic reciprocal",
+				"testdata/reciprocal/bin/bin2.meta_lic testdata/reciprocal/bin/bin2.meta_lic notice",
+				"testdata/reciprocal/container.zip.meta_lic testdata/reciprocal/bin/bin1.meta_lic notice",
+				"testdata/reciprocal/container.zip.meta_lic testdata/reciprocal/bin/bin2.meta_lic notice",
+				"testdata/reciprocal/container.zip.meta_lic testdata/reciprocal/container.zip.meta_lic notice",
+				"testdata/reciprocal/container.zip.meta_lic testdata/reciprocal/lib/liba.so.meta_lic reciprocal",
+				"testdata/reciprocal/container.zip.meta_lic testdata/reciprocal/lib/libb.so.meta_lic notice",
+				"testdata/reciprocal/container.zip.meta_lic testdata/reciprocal/lib/libc.a.meta_lic reciprocal",
+				"testdata/reciprocal/lib/liba.so.meta_lic testdata/reciprocal/lib/liba.so.meta_lic reciprocal",
+				"testdata/reciprocal/lib/libb.so.meta_lic testdata/reciprocal/lib/libb.so.meta_lic notice",
+			},
+		},
+		{
+			condition: "reciprocal",
+			name:      "application",
+			roots:     []string{"application.meta_lic"},
+			expectedOut: []string{
+				"testdata/reciprocal/application.meta_lic testdata/reciprocal/application.meta_lic notice",
+				"testdata/reciprocal/application.meta_lic testdata/reciprocal/lib/liba.so.meta_lic reciprocal",
+			},
+		},
+		{
+			condition: "reciprocal",
+			name:      "binary",
+			roots:     []string{"bin/bin1.meta_lic"},
+			expectedOut: []string{
+				"testdata/reciprocal/bin/bin1.meta_lic testdata/reciprocal/bin/bin1.meta_lic notice",
+				"testdata/reciprocal/bin/bin1.meta_lic testdata/reciprocal/lib/liba.so.meta_lic reciprocal",
+				"testdata/reciprocal/bin/bin1.meta_lic testdata/reciprocal/lib/libc.a.meta_lic reciprocal",
+			},
+		},
+		{
+			condition: "reciprocal",
+			name:      "library",
+			roots:     []string{"lib/libd.so.meta_lic"},
+			expectedOut: []string{
+				"testdata/reciprocal/lib/libd.so.meta_lic testdata/reciprocal/lib/libd.so.meta_lic notice",
+			},
+		},
+		{
+			condition: "restricted",
+			name:      "apex",
+			roots:     []string{"highest.apex.meta_lic"},
+			expectedOut: []string{
+				"testdata/restricted/bin/bin1.meta_lic testdata/restricted/bin/bin1.meta_lic notice:restricted_allows_dynamic_linking",
+				"testdata/restricted/bin/bin1.meta_lic testdata/restricted/lib/liba.so.meta_lic restricted_allows_dynamic_linking",
+				"testdata/restricted/bin/bin1.meta_lic testdata/restricted/lib/libc.a.meta_lic reciprocal:restricted_allows_dynamic_linking",
+				"testdata/restricted/bin/bin2.meta_lic testdata/restricted/bin/bin2.meta_lic notice:restricted",
+				"testdata/restricted/bin/bin2.meta_lic testdata/restricted/lib/libb.so.meta_lic restricted",
+				"testdata/restricted/highest.apex.meta_lic testdata/restricted/bin/bin1.meta_lic notice:restricted_allows_dynamic_linking",
+				"testdata/restricted/highest.apex.meta_lic testdata/restricted/bin/bin2.meta_lic notice:restricted",
+				"testdata/restricted/highest.apex.meta_lic testdata/restricted/highest.apex.meta_lic notice:restricted:restricted_allows_dynamic_linking",
+				"testdata/restricted/highest.apex.meta_lic testdata/restricted/lib/liba.so.meta_lic restricted_allows_dynamic_linking",
+				"testdata/restricted/highest.apex.meta_lic testdata/restricted/lib/libb.so.meta_lic restricted",
+				"testdata/restricted/highest.apex.meta_lic testdata/restricted/lib/libc.a.meta_lic reciprocal:restricted_allows_dynamic_linking",
+				"testdata/restricted/lib/liba.so.meta_lic testdata/restricted/lib/liba.so.meta_lic restricted_allows_dynamic_linking",
+				"testdata/restricted/lib/libb.so.meta_lic testdata/restricted/lib/libb.so.meta_lic restricted",
+			},
+		},
+		{
+			condition: "restricted",
+			name:      "apex_trimmed",
+			roots:     []string{"highest.apex.meta_lic"},
+			ctx:       context{stripPrefix: "testdata/restricted/"},
+			expectedOut: []string{
+				"bin/bin1.meta_lic bin/bin1.meta_lic notice:restricted_allows_dynamic_linking",
+				"bin/bin1.meta_lic lib/liba.so.meta_lic restricted_allows_dynamic_linking",
+				"bin/bin1.meta_lic lib/libc.a.meta_lic reciprocal:restricted_allows_dynamic_linking",
+				"bin/bin2.meta_lic bin/bin2.meta_lic notice:restricted",
+				"bin/bin2.meta_lic lib/libb.so.meta_lic restricted",
+				"highest.apex.meta_lic bin/bin1.meta_lic notice:restricted_allows_dynamic_linking",
+				"highest.apex.meta_lic bin/bin2.meta_lic notice:restricted",
+				"highest.apex.meta_lic highest.apex.meta_lic notice:restricted:restricted_allows_dynamic_linking",
+				"highest.apex.meta_lic lib/liba.so.meta_lic restricted_allows_dynamic_linking",
+				"highest.apex.meta_lic lib/libb.so.meta_lic restricted",
+				"highest.apex.meta_lic lib/libc.a.meta_lic reciprocal:restricted_allows_dynamic_linking",
+				"lib/liba.so.meta_lic lib/liba.so.meta_lic restricted_allows_dynamic_linking",
+				"lib/libb.so.meta_lic lib/libb.so.meta_lic restricted",
+			},
+		},
+		{
+			condition: "restricted",
+			name:      "apex_trimmed_notice",
+			roots:     []string{"highest.apex.meta_lic"},
+			ctx: context{
+				conditions:  []compliance.LicenseCondition{compliance.NoticeCondition},
+				stripPrefix: "testdata/restricted/",
+			},
+			expectedOut: []string{
+				"bin/bin1.meta_lic bin/bin1.meta_lic notice",
+				"bin/bin2.meta_lic bin/bin2.meta_lic notice",
+				"highest.apex.meta_lic bin/bin1.meta_lic notice",
+				"highest.apex.meta_lic bin/bin2.meta_lic notice",
+				"highest.apex.meta_lic highest.apex.meta_lic notice",
+			},
+		},
+		{
+			condition: "restricted",
+			name:      "apex_trimmed_share",
+			roots:     []string{"highest.apex.meta_lic"},
+			ctx: context{
+				conditions:  compliance.ImpliesShared.AsList(),
+				stripPrefix: "testdata/restricted/",
+			},
+			expectedOut: []string{
+				"bin/bin1.meta_lic bin/bin1.meta_lic restricted_allows_dynamic_linking",
+				"bin/bin1.meta_lic lib/liba.so.meta_lic restricted_allows_dynamic_linking",
+				"bin/bin1.meta_lic lib/libc.a.meta_lic reciprocal:restricted_allows_dynamic_linking",
+				"bin/bin2.meta_lic bin/bin2.meta_lic restricted",
+				"bin/bin2.meta_lic lib/libb.so.meta_lic restricted",
+				"highest.apex.meta_lic bin/bin1.meta_lic restricted_allows_dynamic_linking",
+				"highest.apex.meta_lic bin/bin2.meta_lic restricted",
+				"highest.apex.meta_lic highest.apex.meta_lic restricted:restricted_allows_dynamic_linking",
+				"highest.apex.meta_lic lib/liba.so.meta_lic restricted_allows_dynamic_linking",
+				"highest.apex.meta_lic lib/libb.so.meta_lic restricted",
+				"highest.apex.meta_lic lib/libc.a.meta_lic reciprocal:restricted_allows_dynamic_linking",
+				"lib/liba.so.meta_lic lib/liba.so.meta_lic restricted_allows_dynamic_linking",
+				"lib/libb.so.meta_lic lib/libb.so.meta_lic restricted",
+			},
+		},
+		{
+			condition: "restricted",
+			name:      "apex_trimmed_private",
+			roots:     []string{"highest.apex.meta_lic"},
+			ctx: context{
+				conditions:  compliance.ImpliesPrivate.AsList(),
+				stripPrefix: "testdata/restricted/",
+			},
+			expectedOut: []string{},
+		},
+		{
+			condition: "restricted",
+			name:      "apex_trimmed_share_private",
+			roots:     []string{"highest.apex.meta_lic"},
+			ctx: context{
+				conditions:  append(compliance.ImpliesShared.AsList(), compliance.ImpliesPrivate.AsList()...),
+				stripPrefix: "testdata/restricted/",
+			},
+			expectedOut: []string{
+				"bin/bin1.meta_lic bin/bin1.meta_lic restricted_allows_dynamic_linking",
+				"bin/bin1.meta_lic lib/liba.so.meta_lic restricted_allows_dynamic_linking",
+				"bin/bin1.meta_lic lib/libc.a.meta_lic reciprocal:restricted_allows_dynamic_linking",
+				"bin/bin2.meta_lic bin/bin2.meta_lic restricted",
+				"bin/bin2.meta_lic lib/libb.so.meta_lic restricted",
+				"highest.apex.meta_lic bin/bin1.meta_lic restricted_allows_dynamic_linking",
+				"highest.apex.meta_lic bin/bin2.meta_lic restricted",
+				"highest.apex.meta_lic highest.apex.meta_lic restricted:restricted_allows_dynamic_linking",
+				"highest.apex.meta_lic lib/liba.so.meta_lic restricted_allows_dynamic_linking",
+				"highest.apex.meta_lic lib/libb.so.meta_lic restricted",
+				"highest.apex.meta_lic lib/libc.a.meta_lic reciprocal:restricted_allows_dynamic_linking",
+				"lib/liba.so.meta_lic lib/liba.so.meta_lic restricted_allows_dynamic_linking",
+				"lib/libb.so.meta_lic lib/libb.so.meta_lic restricted",
+			},
+		},
+		{
+			condition: "restricted",
+			name:      "apex_trimmed_labelled",
+			roots:     []string{"highest.apex.meta_lic"},
+			ctx:       context{stripPrefix: "testdata/restricted/", labelConditions: true},
+			expectedOut: []string{
+				"bin/bin1.meta_lic:notice bin/bin1.meta_lic:notice notice:restricted_allows_dynamic_linking",
+				"bin/bin1.meta_lic:notice lib/liba.so.meta_lic:restricted_allows_dynamic_linking restricted_allows_dynamic_linking",
+				"bin/bin1.meta_lic:notice lib/libc.a.meta_lic:reciprocal reciprocal:restricted_allows_dynamic_linking",
+				"bin/bin2.meta_lic:notice bin/bin2.meta_lic:notice notice:restricted",
+				"bin/bin2.meta_lic:notice lib/libb.so.meta_lic:restricted restricted",
+				"highest.apex.meta_lic:notice bin/bin1.meta_lic:notice notice:restricted_allows_dynamic_linking",
+				"highest.apex.meta_lic:notice bin/bin2.meta_lic:notice notice:restricted",
+				"highest.apex.meta_lic:notice highest.apex.meta_lic:notice notice:restricted:restricted_allows_dynamic_linking",
+				"highest.apex.meta_lic:notice lib/liba.so.meta_lic:restricted_allows_dynamic_linking restricted_allows_dynamic_linking",
+				"highest.apex.meta_lic:notice lib/libb.so.meta_lic:restricted restricted",
+				"highest.apex.meta_lic:notice lib/libc.a.meta_lic:reciprocal reciprocal:restricted_allows_dynamic_linking",
+				"lib/liba.so.meta_lic:restricted_allows_dynamic_linking lib/liba.so.meta_lic:restricted_allows_dynamic_linking restricted_allows_dynamic_linking",
+				"lib/libb.so.meta_lic:restricted lib/libb.so.meta_lic:restricted restricted",
+			},
+		},
+		{
+			condition: "restricted",
+			name:      "container",
+			roots:     []string{"container.zip.meta_lic"},
+			expectedOut: []string{
+				"testdata/restricted/bin/bin1.meta_lic testdata/restricted/bin/bin1.meta_lic notice:restricted_allows_dynamic_linking",
+				"testdata/restricted/bin/bin1.meta_lic testdata/restricted/lib/liba.so.meta_lic restricted_allows_dynamic_linking",
+				"testdata/restricted/bin/bin1.meta_lic testdata/restricted/lib/libc.a.meta_lic reciprocal:restricted_allows_dynamic_linking",
+				"testdata/restricted/bin/bin2.meta_lic testdata/restricted/bin/bin2.meta_lic notice:restricted",
+				"testdata/restricted/bin/bin2.meta_lic testdata/restricted/lib/libb.so.meta_lic restricted",
+				"testdata/restricted/container.zip.meta_lic testdata/restricted/bin/bin1.meta_lic notice:restricted_allows_dynamic_linking",
+				"testdata/restricted/container.zip.meta_lic testdata/restricted/bin/bin2.meta_lic notice:restricted",
+				"testdata/restricted/container.zip.meta_lic testdata/restricted/container.zip.meta_lic notice:restricted:restricted_allows_dynamic_linking",
+				"testdata/restricted/container.zip.meta_lic testdata/restricted/lib/liba.so.meta_lic restricted_allows_dynamic_linking",
+				"testdata/restricted/container.zip.meta_lic testdata/restricted/lib/libb.so.meta_lic restricted",
+				"testdata/restricted/container.zip.meta_lic testdata/restricted/lib/libc.a.meta_lic reciprocal:restricted_allows_dynamic_linking",
+				"testdata/restricted/lib/liba.so.meta_lic testdata/restricted/lib/liba.so.meta_lic restricted_allows_dynamic_linking",
+				"testdata/restricted/lib/libb.so.meta_lic testdata/restricted/lib/libb.so.meta_lic restricted",
+			},
+		},
+		{
+			condition: "restricted",
+			name:      "application",
+			roots:     []string{"application.meta_lic"},
+			expectedOut: []string{
+				"testdata/restricted/application.meta_lic testdata/restricted/application.meta_lic notice:restricted:restricted_allows_dynamic_linking",
+				"testdata/restricted/application.meta_lic testdata/restricted/lib/liba.so.meta_lic restricted:restricted_allows_dynamic_linking",
+			},
+		},
+		{
+			condition: "restricted",
+			name:      "binary",
+			roots:     []string{"bin/bin1.meta_lic"},
+			expectedOut: []string{
+				"testdata/restricted/bin/bin1.meta_lic testdata/restricted/bin/bin1.meta_lic notice:restricted_allows_dynamic_linking",
+				"testdata/restricted/bin/bin1.meta_lic testdata/restricted/lib/liba.so.meta_lic restricted_allows_dynamic_linking",
+				"testdata/restricted/bin/bin1.meta_lic testdata/restricted/lib/libc.a.meta_lic reciprocal:restricted_allows_dynamic_linking",
+			},
+		},
+		{
+			condition: "restricted",
+			name:      "library",
+			roots:     []string{"lib/libd.so.meta_lic"},
+			expectedOut: []string{
+				"testdata/restricted/lib/libd.so.meta_lic testdata/restricted/lib/libd.so.meta_lic notice",
+			},
+		},
+		{
+			condition: "proprietary",
+			name:      "apex",
+			roots:     []string{"highest.apex.meta_lic"},
+			expectedOut: []string{
+				"testdata/proprietary/bin/bin1.meta_lic testdata/proprietary/bin/bin1.meta_lic notice",
+				"testdata/proprietary/bin/bin1.meta_lic testdata/proprietary/lib/liba.so.meta_lic proprietary:by_exception_only",
+				"testdata/proprietary/bin/bin1.meta_lic testdata/proprietary/lib/libc.a.meta_lic proprietary:by_exception_only",
+				"testdata/proprietary/bin/bin2.meta_lic testdata/proprietary/bin/bin2.meta_lic restricted:proprietary:by_exception_only",
+				"testdata/proprietary/bin/bin2.meta_lic testdata/proprietary/lib/libb.so.meta_lic restricted",
+				"testdata/proprietary/highest.apex.meta_lic testdata/proprietary/bin/bin1.meta_lic notice",
+				"testdata/proprietary/highest.apex.meta_lic testdata/proprietary/bin/bin2.meta_lic restricted:proprietary:by_exception_only",
+				"testdata/proprietary/highest.apex.meta_lic testdata/proprietary/highest.apex.meta_lic notice:restricted",
+				"testdata/proprietary/highest.apex.meta_lic testdata/proprietary/lib/liba.so.meta_lic proprietary:by_exception_only",
+				"testdata/proprietary/highest.apex.meta_lic testdata/proprietary/lib/libb.so.meta_lic restricted",
+				"testdata/proprietary/highest.apex.meta_lic testdata/proprietary/lib/libc.a.meta_lic proprietary:by_exception_only",
+				"testdata/proprietary/lib/liba.so.meta_lic testdata/proprietary/lib/liba.so.meta_lic proprietary:by_exception_only",
+				"testdata/proprietary/lib/libb.so.meta_lic testdata/proprietary/lib/libb.so.meta_lic restricted",
+			},
+		},
+		{
+			condition: "proprietary",
+			name:      "apex_trimmed",
+			roots:     []string{"highest.apex.meta_lic"},
+			ctx:       context{stripPrefix: "testdata/proprietary/"},
+			expectedOut: []string{
+				"bin/bin1.meta_lic bin/bin1.meta_lic notice",
+				"bin/bin1.meta_lic lib/liba.so.meta_lic proprietary:by_exception_only",
+				"bin/bin1.meta_lic lib/libc.a.meta_lic proprietary:by_exception_only",
+				"bin/bin2.meta_lic bin/bin2.meta_lic restricted:proprietary:by_exception_only",
+				"bin/bin2.meta_lic lib/libb.so.meta_lic restricted",
+				"highest.apex.meta_lic bin/bin1.meta_lic notice",
+				"highest.apex.meta_lic bin/bin2.meta_lic restricted:proprietary:by_exception_only",
+				"highest.apex.meta_lic highest.apex.meta_lic notice:restricted",
+				"highest.apex.meta_lic lib/liba.so.meta_lic proprietary:by_exception_only",
+				"highest.apex.meta_lic lib/libb.so.meta_lic restricted",
+				"highest.apex.meta_lic lib/libc.a.meta_lic proprietary:by_exception_only",
+				"lib/liba.so.meta_lic lib/liba.so.meta_lic proprietary:by_exception_only",
+				"lib/libb.so.meta_lic lib/libb.so.meta_lic restricted",
+			},
+		},
+		{
+			condition: "proprietary",
+			name:      "apex_trimmed_notice",
+			roots:     []string{"highest.apex.meta_lic"},
+			ctx: context{
+				conditions:  []compliance.LicenseCondition{compliance.NoticeCondition},
+				stripPrefix: "testdata/proprietary/",
+			},
+			expectedOut: []string{
+				"bin/bin1.meta_lic bin/bin1.meta_lic notice",
+				"highest.apex.meta_lic bin/bin1.meta_lic notice",
+				"highest.apex.meta_lic highest.apex.meta_lic notice",
+			},
+		},
+		{
+			condition: "proprietary",
+			name:      "apex_trimmed_share",
+			roots:     []string{"highest.apex.meta_lic"},
+			ctx: context{
+				conditions:  compliance.ImpliesShared.AsList(),
+				stripPrefix: "testdata/proprietary/",
+			},
+			expectedOut: []string{
+				"bin/bin2.meta_lic bin/bin2.meta_lic restricted",
+				"bin/bin2.meta_lic lib/libb.so.meta_lic restricted",
+				"highest.apex.meta_lic bin/bin2.meta_lic restricted",
+				"highest.apex.meta_lic highest.apex.meta_lic restricted",
+				"highest.apex.meta_lic lib/libb.so.meta_lic restricted",
+				"lib/libb.so.meta_lic lib/libb.so.meta_lic restricted",
+			},
+		},
+		{
+			condition: "proprietary",
+			name:      "apex_trimmed_private",
+			roots:     []string{"highest.apex.meta_lic"},
+			ctx: context{
+				conditions:  compliance.ImpliesPrivate.AsList(),
+				stripPrefix: "testdata/proprietary/",
+			},
+			expectedOut: []string{
+				"bin/bin1.meta_lic lib/liba.so.meta_lic proprietary",
+				"bin/bin1.meta_lic lib/libc.a.meta_lic proprietary",
+				"bin/bin2.meta_lic bin/bin2.meta_lic proprietary",
+				"highest.apex.meta_lic bin/bin2.meta_lic proprietary",
+				"highest.apex.meta_lic lib/liba.so.meta_lic proprietary",
+				"highest.apex.meta_lic lib/libc.a.meta_lic proprietary",
+				"lib/liba.so.meta_lic lib/liba.so.meta_lic proprietary",
+			},
+		},
+		{
+			condition: "proprietary",
+			name:      "apex_trimmed_share_private",
+			roots:     []string{"highest.apex.meta_lic"},
+			ctx: context{
+				conditions:  append(compliance.ImpliesShared.AsList(), compliance.ImpliesPrivate.AsList()...),
+				stripPrefix: "testdata/proprietary/",
+			},
+			expectedOut: []string{
+				"bin/bin1.meta_lic lib/liba.so.meta_lic proprietary",
+				"bin/bin1.meta_lic lib/libc.a.meta_lic proprietary",
+				"bin/bin2.meta_lic bin/bin2.meta_lic restricted:proprietary",
+				"bin/bin2.meta_lic lib/libb.so.meta_lic restricted",
+				"highest.apex.meta_lic bin/bin2.meta_lic restricted:proprietary",
+				"highest.apex.meta_lic highest.apex.meta_lic restricted",
+				"highest.apex.meta_lic lib/liba.so.meta_lic proprietary",
+				"highest.apex.meta_lic lib/libb.so.meta_lic restricted",
+				"highest.apex.meta_lic lib/libc.a.meta_lic proprietary",
+				"lib/liba.so.meta_lic lib/liba.so.meta_lic proprietary",
+				"lib/libb.so.meta_lic lib/libb.so.meta_lic restricted",
+			},
+		},
+		{
+			condition: "proprietary",
+			name:      "apex_trimmed_labelled",
+			roots:     []string{"highest.apex.meta_lic"},
+			ctx:       context{stripPrefix: "testdata/proprietary/", labelConditions: true},
+			expectedOut: []string{
+				"bin/bin1.meta_lic:notice bin/bin1.meta_lic:notice notice",
+				"bin/bin1.meta_lic:notice lib/liba.so.meta_lic:proprietary:by_exception_only proprietary:by_exception_only",
+				"bin/bin1.meta_lic:notice lib/libc.a.meta_lic:proprietary:by_exception_only proprietary:by_exception_only",
+				"bin/bin2.meta_lic:proprietary:by_exception_only bin/bin2.meta_lic:proprietary:by_exception_only restricted:proprietary:by_exception_only",
+				"bin/bin2.meta_lic:proprietary:by_exception_only lib/libb.so.meta_lic:restricted restricted",
+				"highest.apex.meta_lic:notice bin/bin1.meta_lic:notice notice",
+				"highest.apex.meta_lic:notice bin/bin2.meta_lic:proprietary:by_exception_only restricted:proprietary:by_exception_only",
+				"highest.apex.meta_lic:notice highest.apex.meta_lic:notice notice:restricted",
+				"highest.apex.meta_lic:notice lib/liba.so.meta_lic:proprietary:by_exception_only proprietary:by_exception_only",
+				"highest.apex.meta_lic:notice lib/libb.so.meta_lic:restricted restricted",
+				"highest.apex.meta_lic:notice lib/libc.a.meta_lic:proprietary:by_exception_only proprietary:by_exception_only",
+				"lib/liba.so.meta_lic:proprietary:by_exception_only lib/liba.so.meta_lic:proprietary:by_exception_only proprietary:by_exception_only",
+				"lib/libb.so.meta_lic:restricted lib/libb.so.meta_lic:restricted restricted",
+			},
+		},
+		{
+			condition: "proprietary",
+			name:      "container",
+			roots:     []string{"container.zip.meta_lic"},
+			expectedOut: []string{
+				"testdata/proprietary/bin/bin1.meta_lic testdata/proprietary/bin/bin1.meta_lic notice",
+				"testdata/proprietary/bin/bin1.meta_lic testdata/proprietary/lib/liba.so.meta_lic proprietary:by_exception_only",
+				"testdata/proprietary/bin/bin1.meta_lic testdata/proprietary/lib/libc.a.meta_lic proprietary:by_exception_only",
+				"testdata/proprietary/bin/bin2.meta_lic testdata/proprietary/bin/bin2.meta_lic restricted:proprietary:by_exception_only",
+				"testdata/proprietary/bin/bin2.meta_lic testdata/proprietary/lib/libb.so.meta_lic restricted",
+				"testdata/proprietary/container.zip.meta_lic testdata/proprietary/bin/bin1.meta_lic notice",
+				"testdata/proprietary/container.zip.meta_lic testdata/proprietary/bin/bin2.meta_lic restricted:proprietary:by_exception_only",
+				"testdata/proprietary/container.zip.meta_lic testdata/proprietary/container.zip.meta_lic notice:restricted",
+				"testdata/proprietary/container.zip.meta_lic testdata/proprietary/lib/liba.so.meta_lic proprietary:by_exception_only",
+				"testdata/proprietary/container.zip.meta_lic testdata/proprietary/lib/libb.so.meta_lic restricted",
+				"testdata/proprietary/container.zip.meta_lic testdata/proprietary/lib/libc.a.meta_lic proprietary:by_exception_only",
+				"testdata/proprietary/lib/liba.so.meta_lic testdata/proprietary/lib/liba.so.meta_lic proprietary:by_exception_only",
+				"testdata/proprietary/lib/libb.so.meta_lic testdata/proprietary/lib/libb.so.meta_lic restricted",
+			},
+		},
+		{
+			condition: "proprietary",
+			name:      "application",
+			roots:     []string{"application.meta_lic"},
+			expectedOut: []string{
+				"testdata/proprietary/application.meta_lic testdata/proprietary/application.meta_lic notice:restricted",
+				"testdata/proprietary/application.meta_lic testdata/proprietary/lib/liba.so.meta_lic restricted:proprietary:by_exception_only",
+			},
+		},
+		{
+			condition: "proprietary",
+			name:      "binary",
+			roots:     []string{"bin/bin1.meta_lic"},
+			expectedOut: []string{
+				"testdata/proprietary/bin/bin1.meta_lic testdata/proprietary/bin/bin1.meta_lic notice",
+				"testdata/proprietary/bin/bin1.meta_lic testdata/proprietary/lib/liba.so.meta_lic proprietary:by_exception_only",
+				"testdata/proprietary/bin/bin1.meta_lic testdata/proprietary/lib/libc.a.meta_lic proprietary:by_exception_only",
+			},
+		},
+		{
+			condition: "proprietary",
+			name:      "library",
+			roots:     []string{"lib/libd.so.meta_lic"},
+			expectedOut: []string{
+				"testdata/proprietary/lib/libd.so.meta_lic testdata/proprietary/lib/libd.so.meta_lic notice",
+			},
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.condition+" "+tt.name, func(t *testing.T) {
+			expectedOut := &bytes.Buffer{}
+			for _, eo := range tt.expectedOut {
+				expectedOut.WriteString(eo)
+				expectedOut.WriteString("\n")
+			}
+
+			stdout := &bytes.Buffer{}
+			stderr := &bytes.Buffer{}
+
+			rootFiles := make([]string, 0, len(tt.roots))
+			for _, r := range tt.roots {
+				rootFiles = append(rootFiles, "testdata/"+tt.condition+"/"+r)
+			}
+			_, err := dumpResolutions(&tt.ctx, stdout, stderr, rootFiles...)
+			if err != nil {
+				t.Fatalf("dumpresolutions: error = %v, stderr = %v", err, stderr)
+				return
+			}
+			if stderr.Len() > 0 {
+				t.Errorf("dumpresolutions: gotStderr = %v, want none", stderr)
+			}
+			out := stdout.String()
+			expected := expectedOut.String()
+			if out != expected {
+				outList := strings.Split(out, "\n")
+				expectedList := strings.Split(expected, "\n")
+				startLine := 0
+				for len(outList) > startLine && len(expectedList) > startLine && outList[startLine] == expectedList[startLine] {
+					startLine++
+				}
+				t.Errorf("listshare: gotStdout = %v, want %v, somewhere near line %d Stdout = %v, want %v",
+					out, expected, startLine+1, outList[startLine], expectedList[startLine])
+			}
+		})
+	}
+}
+
+type testContext struct {
+	nextNode int
+	nodes    map[string]string
+}
+
+type matcher interface {
+	matchString(*testContext, *compliance.LicenseGraph) string
+	typeString() string
+}
+
+type targetMatcher struct {
+	target     string
+	conditions []string
+}
+
+// newTestCondition constructs a test license condition in the license graph.
+func newTestCondition(lg *compliance.LicenseGraph, conditionName ...string) compliance.LicenseConditionSet {
+	cs := compliance.NewLicenseConditionSet()
+	for _, name := range conditionName {
+		cs = cs.Plus(compliance.RecognizedConditionNames[name])
+	}
+	if cs.IsEmpty() && len(conditionName) != 0 {
+		panic(fmt.Errorf("attempt to create unrecognized condition: %q", conditionName))
+	}
+	return cs
+}
+
+func (tm *targetMatcher) matchString(ctx *testContext, lg *compliance.LicenseGraph) string {
+	cs := newTestCondition(lg, tm.conditions...)
+	m := tm.target
+	if !cs.IsEmpty() {
+		m += "\\n" + strings.Join(cs.Names(), "\\n")
+	}
+	m = ctx.nodes[tm.target] + " [label=\"" + m + "\"];"
+	return m
+}
+
+func (tm *targetMatcher) typeString() string {
+	return "target"
+}
+
+type resolutionMatcher struct {
+	appliesTo  string
+	actsOn     string
+	conditions []string
+}
+
+func (rm *resolutionMatcher) matchString(ctx *testContext, lg *compliance.LicenseGraph) string {
+	cs := newTestCondition(lg, rm.conditions...)
+	return ctx.nodes[rm.appliesTo] + " -> " + ctx.nodes[rm.actsOn] +
+		" [label=\"" + strings.Join(cs.Names(), "\\n") + "\"];"
+}
+
+func (rm *resolutionMatcher) typeString() string {
+	return "resolution"
+}
+
+type getMatcher func(*testContext) matcher
+
+func matchTarget(target string, conditions ...string) getMatcher {
+	return func(ctx *testContext) matcher {
+		ctx.nodes[target] = fmt.Sprintf("n%d", ctx.nextNode)
+		ctx.nextNode++
+		return &targetMatcher{target, append([]string{}, conditions...)}
+	}
+}
+
+func matchResolution(appliesTo, actsOn string, conditions ...string) getMatcher {
+	return func(ctx *testContext) matcher {
+		if _, ok := ctx.nodes[appliesTo]; !ok {
+			ctx.nodes[appliesTo] = fmt.Sprintf("unknown%d", ctx.nextNode)
+			ctx.nextNode++
+		}
+		if _, ok := ctx.nodes[actsOn]; !ok {
+			ctx.nodes[actsOn] = fmt.Sprintf("unknown%d", ctx.nextNode)
+			ctx.nextNode++
+		}
+		return &resolutionMatcher{appliesTo, actsOn, append([]string{}, conditions...)}
+	}
+}
+
+func Test_graphviz(t *testing.T) {
+	tests := []struct {
+		condition   string
+		name        string
+		roots       []string
+		ctx         context
+		expectedOut []getMatcher
+	}{
+		{
+			condition: "firstparty",
+			name:      "apex",
+			roots:     []string{"highest.apex.meta_lic"},
+			expectedOut: []getMatcher{
+				matchTarget("testdata/firstparty/bin/bin1.meta_lic"),
+				matchTarget("testdata/firstparty/lib/liba.so.meta_lic"),
+				matchTarget("testdata/firstparty/lib/libc.a.meta_lic"),
+				matchTarget("testdata/firstparty/bin/bin2.meta_lic"),
+				matchTarget("testdata/firstparty/highest.apex.meta_lic"),
+				matchTarget("testdata/firstparty/lib/libb.so.meta_lic"),
+				matchResolution(
+					"testdata/firstparty/bin/bin1.meta_lic",
+					"testdata/firstparty/bin/bin1.meta_lic",
+					"notice"),
+				matchResolution(
+					"testdata/firstparty/bin/bin1.meta_lic",
+					"testdata/firstparty/lib/liba.so.meta_lic",
+					"notice"),
+				matchResolution(
+					"testdata/firstparty/bin/bin1.meta_lic",
+					"testdata/firstparty/lib/libc.a.meta_lic",
+					"notice"),
+				matchResolution(
+					"testdata/firstparty/bin/bin2.meta_lic",
+					"testdata/firstparty/bin/bin2.meta_lic",
+					"notice"),
+				matchResolution(
+					"testdata/firstparty/highest.apex.meta_lic",
+					"testdata/firstparty/bin/bin1.meta_lic",
+					"notice"),
+				matchResolution(
+					"testdata/firstparty/highest.apex.meta_lic",
+					"testdata/firstparty/bin/bin2.meta_lic",
+					"notice"),
+				matchResolution(
+					"testdata/firstparty/highest.apex.meta_lic",
+					"testdata/firstparty/highest.apex.meta_lic",
+					"notice"),
+				matchResolution(
+					"testdata/firstparty/highest.apex.meta_lic",
+					"testdata/firstparty/lib/liba.so.meta_lic",
+					"notice"),
+				matchResolution(
+					"testdata/firstparty/highest.apex.meta_lic",
+					"testdata/firstparty/lib/libb.so.meta_lic",
+					"notice"),
+				matchResolution(
+					"testdata/firstparty/highest.apex.meta_lic",
+					"testdata/firstparty/lib/libc.a.meta_lic",
+					"notice"),
+				matchResolution(
+					"testdata/firstparty/lib/liba.so.meta_lic",
+					"testdata/firstparty/lib/liba.so.meta_lic",
+					"notice"),
+				matchResolution(
+					"testdata/firstparty/lib/libb.so.meta_lic",
+					"testdata/firstparty/lib/libb.so.meta_lic",
+					"notice"),
+			},
+		},
+		{
+			condition: "firstparty",
+			name:      "apex_trimmed",
+			roots:     []string{"highest.apex.meta_lic"},
+			ctx:       context{stripPrefix: "testdata/firstparty/"},
+			expectedOut: []getMatcher{
+				matchTarget("bin/bin1.meta_lic"),
+				matchTarget("lib/liba.so.meta_lic"),
+				matchTarget("lib/libc.a.meta_lic"),
+				matchTarget("bin/bin2.meta_lic"),
+				matchTarget("highest.apex.meta_lic"),
+				matchTarget("lib/libb.so.meta_lic"),
+				matchResolution(
+					"bin/bin1.meta_lic",
+					"bin/bin1.meta_lic",
+					"notice"),
+				matchResolution(
+					"bin/bin1.meta_lic",
+					"lib/liba.so.meta_lic",
+					"notice"),
+				matchResolution(
+					"bin/bin1.meta_lic",
+					"lib/libc.a.meta_lic",
+					"notice"),
+				matchResolution(
+					"bin/bin2.meta_lic",
+					"bin/bin2.meta_lic",
+					"notice"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"bin/bin1.meta_lic",
+					"notice"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"bin/bin2.meta_lic",
+					"notice"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"highest.apex.meta_lic",
+					"notice"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"lib/liba.so.meta_lic",
+					"notice"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"lib/libb.so.meta_lic",
+					"notice"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"lib/libc.a.meta_lic",
+					"notice"),
+				matchResolution(
+					"lib/liba.so.meta_lic",
+					"lib/liba.so.meta_lic",
+					"notice"),
+				matchResolution(
+					"lib/libb.so.meta_lic",
+					"lib/libb.so.meta_lic",
+					"notice"),
+			},
+		},
+		{
+			condition: "firstparty",
+			name:      "apex_trimmed_notice",
+			roots:     []string{"highest.apex.meta_lic"},
+			ctx: context{
+				conditions:  []compliance.LicenseCondition{compliance.NoticeCondition},
+				stripPrefix: "testdata/firstparty/",
+			},
+			expectedOut: []getMatcher{
+				matchTarget("bin/bin1.meta_lic"),
+				matchTarget("lib/liba.so.meta_lic"),
+				matchTarget("lib/libc.a.meta_lic"),
+				matchTarget("bin/bin2.meta_lic"),
+				matchTarget("highest.apex.meta_lic"),
+				matchTarget("lib/libb.so.meta_lic"),
+				matchResolution(
+					"bin/bin1.meta_lic",
+					"bin/bin1.meta_lic",
+					"notice"),
+				matchResolution(
+					"bin/bin1.meta_lic",
+					"lib/liba.so.meta_lic",
+					"notice"),
+				matchResolution(
+					"bin/bin1.meta_lic",
+					"lib/libc.a.meta_lic",
+					"notice"),
+				matchResolution(
+					"bin/bin2.meta_lic",
+					"bin/bin2.meta_lic",
+					"notice"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"bin/bin1.meta_lic",
+					"notice"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"bin/bin2.meta_lic",
+					"notice"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"highest.apex.meta_lic",
+					"notice"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"lib/liba.so.meta_lic",
+					"notice"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"lib/libb.so.meta_lic",
+					"notice"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"lib/libc.a.meta_lic",
+					"notice"),
+				matchResolution(
+					"lib/liba.so.meta_lic",
+					"lib/liba.so.meta_lic",
+					"notice"),
+				matchResolution(
+					"lib/libb.so.meta_lic",
+					"lib/libb.so.meta_lic",
+					"notice"),
+			},
+		},
+		{
+			condition: "firstparty",
+			name:      "apex_trimmed_share",
+			roots:     []string{"highest.apex.meta_lic"},
+			ctx: context{
+				conditions:  compliance.ImpliesShared.AsList(),
+				stripPrefix: "testdata/firstparty/",
+			},
+			expectedOut: []getMatcher{},
+		},
+		{
+			condition: "firstparty",
+			name:      "apex_trimmed_private",
+			roots:     []string{"highest.apex.meta_lic"},
+			ctx: context{
+				conditions:  compliance.ImpliesPrivate.AsList(),
+				stripPrefix: "testdata/firstparty/",
+			},
+			expectedOut: []getMatcher{},
+		},
+		{
+			condition: "firstparty",
+			name:      "apex_trimmed_share_private",
+			roots:     []string{"highest.apex.meta_lic"},
+			ctx: context{
+				conditions:  compliance.ImpliesShared.Union(compliance.ImpliesPrivate).AsList(),
+				stripPrefix: "testdata/firstparty/",
+			},
+			expectedOut: []getMatcher{},
+		},
+		{
+			condition: "firstparty",
+			name:      "apex_trimmed_labelled",
+			roots:     []string{"highest.apex.meta_lic"},
+			ctx:       context{stripPrefix: "testdata/firstparty/", labelConditions: true},
+			expectedOut: []getMatcher{
+				matchTarget("bin/bin1.meta_lic", "notice"),
+				matchTarget("lib/liba.so.meta_lic", "notice"),
+				matchTarget("lib/libc.a.meta_lic", "notice"),
+				matchTarget("bin/bin2.meta_lic", "notice"),
+				matchTarget("highest.apex.meta_lic", "notice"),
+				matchTarget("lib/libb.so.meta_lic", "notice"),
+				matchResolution(
+					"bin/bin1.meta_lic",
+					"bin/bin1.meta_lic",
+					"notice"),
+				matchResolution(
+					"bin/bin1.meta_lic",
+					"lib/liba.so.meta_lic",
+					"notice"),
+				matchResolution(
+					"bin/bin1.meta_lic",
+					"lib/libc.a.meta_lic",
+					"notice"),
+				matchResolution(
+					"bin/bin2.meta_lic",
+					"bin/bin2.meta_lic",
+					"notice"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"bin/bin1.meta_lic",
+					"notice"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"bin/bin2.meta_lic",
+					"notice"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"highest.apex.meta_lic",
+					"notice"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"lib/liba.so.meta_lic",
+					"notice"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"lib/libb.so.meta_lic",
+					"notice"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"lib/libc.a.meta_lic",
+					"notice"),
+				matchResolution(
+					"lib/liba.so.meta_lic",
+					"lib/liba.so.meta_lic",
+					"notice"),
+				matchResolution(
+					"lib/libb.so.meta_lic",
+					"lib/libb.so.meta_lic",
+					"notice"),
+			},
+		},
+		{
+			condition: "firstparty",
+			name:      "container",
+			roots:     []string{"container.zip.meta_lic"},
+			expectedOut: []getMatcher{
+				matchTarget("testdata/firstparty/bin/bin1.meta_lic"),
+				matchTarget("testdata/firstparty/lib/liba.so.meta_lic"),
+				matchTarget("testdata/firstparty/lib/libc.a.meta_lic"),
+				matchTarget("testdata/firstparty/bin/bin2.meta_lic"),
+				matchTarget("testdata/firstparty/container.zip.meta_lic"),
+				matchTarget("testdata/firstparty/lib/libb.so.meta_lic"),
+				matchResolution(
+					"testdata/firstparty/bin/bin1.meta_lic",
+					"testdata/firstparty/bin/bin1.meta_lic",
+					"notice"),
+				matchResolution(
+					"testdata/firstparty/bin/bin1.meta_lic",
+					"testdata/firstparty/lib/liba.so.meta_lic",
+					"notice"),
+				matchResolution(
+					"testdata/firstparty/bin/bin1.meta_lic",
+					"testdata/firstparty/lib/libc.a.meta_lic",
+					"notice"),
+				matchResolution(
+					"testdata/firstparty/bin/bin2.meta_lic",
+					"testdata/firstparty/bin/bin2.meta_lic",
+					"notice"),
+				matchResolution(
+					"testdata/firstparty/container.zip.meta_lic",
+					"testdata/firstparty/bin/bin1.meta_lic",
+					"notice"),
+				matchResolution(
+					"testdata/firstparty/container.zip.meta_lic",
+					"testdata/firstparty/bin/bin2.meta_lic",
+					"notice"),
+				matchResolution(
+					"testdata/firstparty/container.zip.meta_lic",
+					"testdata/firstparty/container.zip.meta_lic",
+					"notice"),
+				matchResolution(
+					"testdata/firstparty/container.zip.meta_lic",
+					"testdata/firstparty/lib/liba.so.meta_lic",
+					"notice"),
+				matchResolution(
+					"testdata/firstparty/container.zip.meta_lic",
+					"testdata/firstparty/lib/libb.so.meta_lic",
+					"notice"),
+				matchResolution(
+					"testdata/firstparty/container.zip.meta_lic",
+					"testdata/firstparty/lib/libc.a.meta_lic",
+					"notice"),
+				matchResolution(
+					"testdata/firstparty/lib/liba.so.meta_lic",
+					"testdata/firstparty/lib/liba.so.meta_lic",
+					"notice"),
+				matchResolution(
+					"testdata/firstparty/lib/libb.so.meta_lic",
+					"testdata/firstparty/lib/libb.so.meta_lic",
+					"notice"),
+			},
+		},
+		{
+			condition: "firstparty",
+			name:      "application",
+			roots:     []string{"application.meta_lic"},
+			expectedOut: []getMatcher{
+				matchTarget("testdata/firstparty/application.meta_lic"),
+				matchTarget("testdata/firstparty/lib/liba.so.meta_lic"),
+				matchResolution(
+					"testdata/firstparty/application.meta_lic",
+					"testdata/firstparty/application.meta_lic",
+					"notice"),
+				matchResolution(
+					"testdata/firstparty/application.meta_lic",
+					"testdata/firstparty/lib/liba.so.meta_lic",
+					"notice"),
+			},
+		},
+		{
+			condition: "firstparty",
+			name:      "binary",
+			roots:     []string{"bin/bin1.meta_lic"},
+			expectedOut: []getMatcher{
+				matchTarget("testdata/firstparty/bin/bin1.meta_lic"),
+				matchTarget("testdata/firstparty/lib/liba.so.meta_lic"),
+				matchTarget("testdata/firstparty/lib/libc.a.meta_lic"),
+				matchResolution(
+					"testdata/firstparty/bin/bin1.meta_lic",
+					"testdata/firstparty/bin/bin1.meta_lic",
+					"notice"),
+				matchResolution(
+					"testdata/firstparty/bin/bin1.meta_lic",
+					"testdata/firstparty/lib/liba.so.meta_lic",
+					"notice"),
+				matchResolution(
+					"testdata/firstparty/bin/bin1.meta_lic",
+					"testdata/firstparty/lib/libc.a.meta_lic",
+					"notice"),
+			},
+		},
+		{
+			condition: "firstparty",
+			name:      "library",
+			roots:     []string{"lib/libd.so.meta_lic"},
+			expectedOut: []getMatcher{
+				matchTarget("testdata/firstparty/lib/libd.so.meta_lic"),
+				matchResolution(
+					"testdata/firstparty/lib/libd.so.meta_lic",
+					"testdata/firstparty/lib/libd.so.meta_lic",
+					"notice"),
+			},
+		},
+		{
+			condition: "notice",
+			name:      "apex",
+			roots:     []string{"highest.apex.meta_lic"},
+			expectedOut: []getMatcher{
+				matchTarget("testdata/notice/bin/bin1.meta_lic"),
+				matchTarget("testdata/notice/lib/liba.so.meta_lic"),
+				matchTarget("testdata/notice/lib/libc.a.meta_lic"),
+				matchTarget("testdata/notice/bin/bin2.meta_lic"),
+				matchTarget("testdata/notice/highest.apex.meta_lic"),
+				matchTarget("testdata/notice/lib/libb.so.meta_lic"),
+				matchResolution(
+					"testdata/notice/bin/bin1.meta_lic",
+					"testdata/notice/bin/bin1.meta_lic",
+					"notice"),
+				matchResolution(
+					"testdata/notice/bin/bin1.meta_lic",
+					"testdata/notice/lib/liba.so.meta_lic",
+					"notice"),
+				matchResolution(
+					"testdata/notice/bin/bin1.meta_lic",
+					"testdata/notice/lib/libc.a.meta_lic",
+					"notice"),
+				matchResolution(
+					"testdata/notice/bin/bin2.meta_lic",
+					"testdata/notice/bin/bin2.meta_lic",
+					"notice"),
+				matchResolution(
+					"testdata/notice/highest.apex.meta_lic",
+					"testdata/notice/bin/bin1.meta_lic",
+					"notice"),
+				matchResolution(
+					"testdata/notice/highest.apex.meta_lic",
+					"testdata/notice/bin/bin2.meta_lic",
+					"notice"),
+				matchResolution(
+					"testdata/notice/highest.apex.meta_lic",
+					"testdata/notice/highest.apex.meta_lic",
+					"notice"),
+				matchResolution(
+					"testdata/notice/highest.apex.meta_lic",
+					"testdata/notice/lib/liba.so.meta_lic",
+					"notice"),
+				matchResolution(
+					"testdata/notice/highest.apex.meta_lic",
+					"testdata/notice/lib/libb.so.meta_lic",
+					"notice"),
+				matchResolution(
+					"testdata/notice/highest.apex.meta_lic",
+					"testdata/notice/lib/libc.a.meta_lic",
+					"notice"),
+				matchResolution(
+					"testdata/notice/lib/liba.so.meta_lic",
+					"testdata/notice/lib/liba.so.meta_lic",
+					"notice"),
+				matchResolution(
+					"testdata/notice/lib/libb.so.meta_lic",
+					"testdata/notice/lib/libb.so.meta_lic",
+					"notice"),
+			},
+		},
+		{
+			condition: "notice",
+			name:      "apex_trimmed",
+			roots:     []string{"highest.apex.meta_lic"},
+			ctx:       context{stripPrefix: "testdata/notice/"},
+			expectedOut: []getMatcher{
+				matchTarget("bin/bin1.meta_lic"),
+				matchTarget("lib/liba.so.meta_lic"),
+				matchTarget("lib/libc.a.meta_lic"),
+				matchTarget("bin/bin2.meta_lic"),
+				matchTarget("highest.apex.meta_lic"),
+				matchTarget("lib/libb.so.meta_lic"),
+				matchResolution(
+					"bin/bin1.meta_lic",
+					"bin/bin1.meta_lic",
+					"notice"),
+				matchResolution(
+					"bin/bin1.meta_lic",
+					"lib/liba.so.meta_lic",
+					"notice"),
+				matchResolution(
+					"bin/bin1.meta_lic",
+					"lib/libc.a.meta_lic",
+					"notice"),
+				matchResolution(
+					"bin/bin2.meta_lic",
+					"bin/bin2.meta_lic",
+					"notice"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"bin/bin1.meta_lic",
+					"notice"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"bin/bin2.meta_lic",
+					"notice"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"highest.apex.meta_lic",
+					"notice"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"lib/liba.so.meta_lic",
+					"notice"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"lib/libb.so.meta_lic",
+					"notice"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"lib/libc.a.meta_lic",
+					"notice"),
+				matchResolution(
+					"lib/liba.so.meta_lic",
+					"lib/liba.so.meta_lic",
+					"notice"),
+				matchResolution(
+					"lib/libb.so.meta_lic",
+					"lib/libb.so.meta_lic",
+					"notice"),
+			},
+		},
+		{
+			condition: "notice",
+			name:      "apex_trimmed_notice",
+			roots:     []string{"highest.apex.meta_lic"},
+			ctx: context{
+				conditions:  []compliance.LicenseCondition{compliance.NoticeCondition},
+				stripPrefix: "testdata/notice/",
+			},
+			expectedOut: []getMatcher{
+				matchTarget("bin/bin1.meta_lic"),
+				matchTarget("lib/liba.so.meta_lic"),
+				matchTarget("lib/libc.a.meta_lic"),
+				matchTarget("bin/bin2.meta_lic"),
+				matchTarget("highest.apex.meta_lic"),
+				matchTarget("lib/libb.so.meta_lic"),
+				matchResolution(
+					"bin/bin1.meta_lic",
+					"bin/bin1.meta_lic",
+					"notice"),
+				matchResolution(
+					"bin/bin1.meta_lic",
+					"lib/liba.so.meta_lic",
+					"notice"),
+				matchResolution(
+					"bin/bin1.meta_lic",
+					"lib/libc.a.meta_lic",
+					"notice"),
+				matchResolution(
+					"bin/bin2.meta_lic",
+					"bin/bin2.meta_lic",
+					"notice"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"bin/bin1.meta_lic",
+					"notice"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"bin/bin2.meta_lic",
+					"notice"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"highest.apex.meta_lic",
+					"notice"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"lib/liba.so.meta_lic",
+					"notice"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"lib/libb.so.meta_lic",
+					"notice"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"lib/libc.a.meta_lic",
+					"notice"),
+				matchResolution(
+					"lib/liba.so.meta_lic",
+					"lib/liba.so.meta_lic",
+					"notice"),
+				matchResolution(
+					"lib/libb.so.meta_lic",
+					"lib/libb.so.meta_lic",
+					"notice"),
+			},
+		},
+		{
+			condition: "notice",
+			name:      "apex_trimmed_share",
+			roots:     []string{"highest.apex.meta_lic"},
+			ctx: context{
+				conditions:  compliance.ImpliesShared.AsList(),
+				stripPrefix: "testdata/notice/",
+			},
+			expectedOut: []getMatcher{},
+		},
+		{
+			condition: "notice",
+			name:      "apex_trimmed_private",
+			roots:     []string{"highest.apex.meta_lic"},
+			ctx: context{
+				conditions:  compliance.ImpliesPrivate.AsList(),
+				stripPrefix: "testdata/notice/",
+			},
+			expectedOut: []getMatcher{},
+		},
+		{
+			condition: "notice",
+			name:      "apex_trimmed_share_private",
+			roots:     []string{"highest.apex.meta_lic"},
+			ctx: context{
+				conditions:  compliance.ImpliesShared.Union(compliance.ImpliesPrivate).AsList(),
+				stripPrefix: "testdata/notice/",
+			},
+			expectedOut: []getMatcher{},
+		},
+		{
+			condition: "notice",
+			name:      "apex_trimmed_labelled",
+			roots:     []string{"highest.apex.meta_lic"},
+			ctx:       context{stripPrefix: "testdata/notice/", labelConditions: true},
+			expectedOut: []getMatcher{
+				matchTarget("bin/bin1.meta_lic", "notice"),
+				matchTarget("lib/liba.so.meta_lic", "notice"),
+				matchTarget("lib/libc.a.meta_lic", "notice"),
+				matchTarget("bin/bin2.meta_lic", "notice"),
+				matchTarget("highest.apex.meta_lic", "notice"),
+				matchTarget("lib/libb.so.meta_lic", "notice"),
+				matchResolution(
+					"bin/bin1.meta_lic",
+					"bin/bin1.meta_lic",
+					"notice"),
+				matchResolution(
+					"bin/bin1.meta_lic",
+					"lib/liba.so.meta_lic",
+					"notice"),
+				matchResolution(
+					"bin/bin1.meta_lic",
+					"lib/libc.a.meta_lic",
+					"notice"),
+				matchResolution(
+					"bin/bin2.meta_lic",
+					"bin/bin2.meta_lic",
+					"notice"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"bin/bin1.meta_lic",
+					"notice"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"bin/bin2.meta_lic",
+					"notice"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"highest.apex.meta_lic",
+					"notice"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"lib/liba.so.meta_lic",
+					"notice"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"lib/libb.so.meta_lic",
+					"notice"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"lib/libc.a.meta_lic",
+					"notice"),
+				matchResolution(
+					"lib/liba.so.meta_lic",
+					"lib/liba.so.meta_lic",
+					"notice"),
+				matchResolution(
+					"lib/libb.so.meta_lic",
+					"lib/libb.so.meta_lic",
+					"notice"),
+			},
+		},
+		{
+			condition: "notice",
+			name:      "container",
+			roots:     []string{"container.zip.meta_lic"},
+			expectedOut: []getMatcher{
+				matchTarget("testdata/notice/bin/bin1.meta_lic"),
+				matchTarget("testdata/notice/lib/liba.so.meta_lic"),
+				matchTarget("testdata/notice/lib/libc.a.meta_lic"),
+				matchTarget("testdata/notice/bin/bin2.meta_lic"),
+				matchTarget("testdata/notice/container.zip.meta_lic"),
+				matchTarget("testdata/notice/lib/libb.so.meta_lic"),
+				matchResolution(
+					"testdata/notice/bin/bin1.meta_lic",
+					"testdata/notice/bin/bin1.meta_lic",
+					"notice"),
+				matchResolution(
+					"testdata/notice/bin/bin1.meta_lic",
+					"testdata/notice/lib/liba.so.meta_lic",
+					"notice"),
+				matchResolution(
+					"testdata/notice/bin/bin1.meta_lic",
+					"testdata/notice/lib/libc.a.meta_lic",
+					"notice"),
+				matchResolution(
+					"testdata/notice/bin/bin2.meta_lic",
+					"testdata/notice/bin/bin2.meta_lic",
+					"notice"),
+				matchResolution(
+					"testdata/notice/container.zip.meta_lic",
+					"testdata/notice/bin/bin1.meta_lic",
+					"notice"),
+				matchResolution(
+					"testdata/notice/container.zip.meta_lic",
+					"testdata/notice/bin/bin2.meta_lic",
+					"notice"),
+				matchResolution(
+					"testdata/notice/container.zip.meta_lic",
+					"testdata/notice/container.zip.meta_lic",
+					"notice"),
+				matchResolution(
+					"testdata/notice/container.zip.meta_lic",
+					"testdata/notice/lib/liba.so.meta_lic",
+					"notice"),
+				matchResolution(
+					"testdata/notice/container.zip.meta_lic",
+					"testdata/notice/lib/libb.so.meta_lic",
+					"notice"),
+				matchResolution(
+					"testdata/notice/container.zip.meta_lic",
+					"testdata/notice/lib/libc.a.meta_lic",
+					"notice"),
+				matchResolution(
+					"testdata/notice/lib/liba.so.meta_lic",
+					"testdata/notice/lib/liba.so.meta_lic",
+					"notice"),
+				matchResolution(
+					"testdata/notice/lib/libb.so.meta_lic",
+					"testdata/notice/lib/libb.so.meta_lic",
+					"notice"),
+			},
+		},
+		{
+			condition: "notice",
+			name:      "application",
+			roots:     []string{"application.meta_lic"},
+			expectedOut: []getMatcher{
+				matchTarget("testdata/notice/application.meta_lic"),
+				matchTarget("testdata/notice/lib/liba.so.meta_lic"),
+				matchResolution(
+					"testdata/notice/application.meta_lic",
+					"testdata/notice/application.meta_lic",
+					"notice"),
+				matchResolution(
+					"testdata/notice/application.meta_lic",
+					"testdata/notice/lib/liba.so.meta_lic",
+					"notice"),
+			},
+		},
+		{
+			condition: "notice",
+			name:      "binary",
+			roots:     []string{"bin/bin1.meta_lic"},
+			expectedOut: []getMatcher{
+				matchTarget("testdata/notice/bin/bin1.meta_lic"),
+				matchTarget("testdata/notice/lib/liba.so.meta_lic"),
+				matchTarget("testdata/notice/lib/libc.a.meta_lic"),
+				matchResolution(
+					"testdata/notice/bin/bin1.meta_lic",
+					"testdata/notice/bin/bin1.meta_lic",
+					"notice"),
+				matchResolution(
+					"testdata/notice/bin/bin1.meta_lic",
+					"testdata/notice/lib/liba.so.meta_lic",
+					"notice"),
+				matchResolution(
+					"testdata/notice/bin/bin1.meta_lic",
+					"testdata/notice/lib/libc.a.meta_lic",
+					"notice"),
+			},
+		},
+		{
+			condition: "notice",
+			name:      "library",
+			roots:     []string{"lib/libd.so.meta_lic"},
+			expectedOut: []getMatcher{
+				matchTarget("testdata/notice/lib/libd.so.meta_lic"),
+				matchResolution(
+					"testdata/notice/lib/libd.so.meta_lic",
+					"testdata/notice/lib/libd.so.meta_lic",
+					"notice"),
+			},
+		},
+		{
+			condition: "reciprocal",
+			name:      "apex",
+			roots:     []string{"highest.apex.meta_lic"},
+			expectedOut: []getMatcher{
+				matchTarget("testdata/reciprocal/bin/bin1.meta_lic"),
+				matchTarget("testdata/reciprocal/lib/liba.so.meta_lic"),
+				matchTarget("testdata/reciprocal/lib/libc.a.meta_lic"),
+				matchTarget("testdata/reciprocal/bin/bin2.meta_lic"),
+				matchTarget("testdata/reciprocal/highest.apex.meta_lic"),
+				matchTarget("testdata/reciprocal/lib/libb.so.meta_lic"),
+				matchResolution(
+					"testdata/reciprocal/bin/bin1.meta_lic",
+					"testdata/reciprocal/bin/bin1.meta_lic",
+					"notice"),
+				matchResolution(
+					"testdata/reciprocal/bin/bin1.meta_lic",
+					"testdata/reciprocal/lib/liba.so.meta_lic",
+					"reciprocal"),
+				matchResolution(
+					"testdata/reciprocal/bin/bin1.meta_lic",
+					"testdata/reciprocal/lib/libc.a.meta_lic",
+					"reciprocal"),
+				matchResolution(
+					"testdata/reciprocal/bin/bin2.meta_lic",
+					"testdata/reciprocal/bin/bin2.meta_lic",
+					"notice"),
+				matchResolution(
+					"testdata/reciprocal/highest.apex.meta_lic",
+					"testdata/reciprocal/bin/bin1.meta_lic",
+					"notice"),
+				matchResolution(
+					"testdata/reciprocal/highest.apex.meta_lic",
+					"testdata/reciprocal/bin/bin2.meta_lic",
+					"notice"),
+				matchResolution(
+					"testdata/reciprocal/highest.apex.meta_lic",
+					"testdata/reciprocal/highest.apex.meta_lic",
+					"notice"),
+				matchResolution(
+					"testdata/reciprocal/highest.apex.meta_lic",
+					"testdata/reciprocal/lib/liba.so.meta_lic",
+					"reciprocal"),
+				matchResolution(
+					"testdata/reciprocal/highest.apex.meta_lic",
+					"testdata/reciprocal/lib/libb.so.meta_lic",
+					"notice"),
+				matchResolution(
+					"testdata/reciprocal/highest.apex.meta_lic",
+					"testdata/reciprocal/lib/libc.a.meta_lic",
+					"reciprocal"),
+				matchResolution(
+					"testdata/reciprocal/lib/liba.so.meta_lic",
+					"testdata/reciprocal/lib/liba.so.meta_lic",
+					"reciprocal"),
+				matchResolution(
+					"testdata/reciprocal/lib/libb.so.meta_lic",
+					"testdata/reciprocal/lib/libb.so.meta_lic",
+					"notice"),
+			},
+		},
+		{
+			condition: "reciprocal",
+			name:      "apex_trimmed",
+			roots:     []string{"highest.apex.meta_lic"},
+			ctx:       context{stripPrefix: "testdata/reciprocal/"},
+			expectedOut: []getMatcher{
+				matchTarget("bin/bin1.meta_lic"),
+				matchTarget("lib/liba.so.meta_lic"),
+				matchTarget("lib/libc.a.meta_lic"),
+				matchTarget("bin/bin2.meta_lic"),
+				matchTarget("highest.apex.meta_lic"),
+				matchTarget("lib/libb.so.meta_lic"),
+				matchResolution(
+					"bin/bin1.meta_lic",
+					"bin/bin1.meta_lic",
+					"notice"),
+				matchResolution(
+					"bin/bin1.meta_lic",
+					"lib/liba.so.meta_lic",
+					"reciprocal"),
+				matchResolution(
+					"bin/bin1.meta_lic",
+					"lib/libc.a.meta_lic",
+					"reciprocal"),
+				matchResolution(
+					"bin/bin2.meta_lic",
+					"bin/bin2.meta_lic",
+					"notice"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"bin/bin1.meta_lic",
+					"notice"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"bin/bin2.meta_lic",
+					"notice"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"highest.apex.meta_lic",
+					"notice"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"lib/liba.so.meta_lic",
+					"reciprocal"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"lib/libb.so.meta_lic",
+					"notice"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"lib/libc.a.meta_lic",
+					"reciprocal"),
+				matchResolution(
+					"lib/liba.so.meta_lic",
+					"lib/liba.so.meta_lic",
+					"reciprocal"),
+				matchResolution(
+					"lib/libb.so.meta_lic",
+					"lib/libb.so.meta_lic",
+					"notice"),
+			},
+		},
+		{
+			condition: "reciprocal",
+			name:      "apex_trimmed_notice",
+			roots:     []string{"highest.apex.meta_lic"},
+			ctx: context{
+				conditions:  []compliance.LicenseCondition{compliance.NoticeCondition},
+				stripPrefix: "testdata/reciprocal/",
+			},
+			expectedOut: []getMatcher{
+				matchTarget("bin/bin1.meta_lic"),
+				matchTarget("bin/bin2.meta_lic"),
+				matchTarget("highest.apex.meta_lic"),
+				matchTarget("lib/libb.so.meta_lic"),
+				matchResolution(
+					"bin/bin1.meta_lic",
+					"bin/bin1.meta_lic",
+					"notice"),
+				matchResolution(
+					"bin/bin2.meta_lic",
+					"bin/bin2.meta_lic",
+					"notice"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"bin/bin1.meta_lic",
+					"notice"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"bin/bin2.meta_lic",
+					"notice"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"highest.apex.meta_lic",
+					"notice"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"lib/libb.so.meta_lic",
+					"notice"),
+				matchResolution(
+					"lib/libb.so.meta_lic",
+					"lib/libb.so.meta_lic",
+					"notice"),
+			},
+		},
+		{
+			condition: "reciprocal",
+			name:      "apex_trimmed_share",
+			roots:     []string{"highest.apex.meta_lic"},
+			ctx: context{
+				conditions:  compliance.ImpliesShared.AsList(),
+				stripPrefix: "testdata/reciprocal/",
+			},
+			expectedOut: []getMatcher{
+				matchTarget("bin/bin1.meta_lic"),
+				matchTarget("lib/liba.so.meta_lic"),
+				matchTarget("lib/libc.a.meta_lic"),
+				matchTarget("highest.apex.meta_lic"),
+				matchResolution(
+					"bin/bin1.meta_lic",
+					"lib/liba.so.meta_lic",
+					"reciprocal"),
+				matchResolution(
+					"bin/bin1.meta_lic",
+					"lib/libc.a.meta_lic",
+					"reciprocal"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"lib/liba.so.meta_lic",
+					"reciprocal"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"lib/libc.a.meta_lic",
+					"reciprocal"),
+				matchResolution(
+					"lib/liba.so.meta_lic",
+					"lib/liba.so.meta_lic",
+					"reciprocal"),
+			},
+		},
+		{
+			condition: "reciprocal",
+			name:      "apex_trimmed_private",
+			roots:     []string{"highest.apex.meta_lic"},
+			ctx: context{
+				conditions:  compliance.ImpliesPrivate.AsList(),
+				stripPrefix: "testdata/reciprocal/",
+			},
+			expectedOut: []getMatcher{},
+		},
+		{
+			condition: "reciprocal",
+			name:      "apex_trimmed_share_private",
+			roots:     []string{"highest.apex.meta_lic"},
+			ctx: context{
+				conditions:  compliance.ImpliesShared.Union(compliance.ImpliesPrivate).AsList(),
+				stripPrefix: "testdata/reciprocal/",
+			},
+			expectedOut: []getMatcher{
+				matchTarget("bin/bin1.meta_lic"),
+				matchTarget("lib/liba.so.meta_lic"),
+				matchTarget("lib/libc.a.meta_lic"),
+				matchTarget("highest.apex.meta_lic"),
+				matchResolution(
+					"bin/bin1.meta_lic",
+					"lib/liba.so.meta_lic",
+					"reciprocal"),
+				matchResolution(
+					"bin/bin1.meta_lic",
+					"lib/libc.a.meta_lic",
+					"reciprocal"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"lib/liba.so.meta_lic",
+					"reciprocal"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"lib/libc.a.meta_lic",
+					"reciprocal"),
+				matchResolution(
+					"lib/liba.so.meta_lic",
+					"lib/liba.so.meta_lic",
+					"reciprocal"),
+			},
+		},
+		{
+			condition: "reciprocal",
+			name:      "apex_trimmed_labelled",
+			roots:     []string{"highest.apex.meta_lic"},
+			ctx:       context{stripPrefix: "testdata/reciprocal/", labelConditions: true},
+			expectedOut: []getMatcher{
+				matchTarget("bin/bin1.meta_lic", "notice"),
+				matchTarget("lib/liba.so.meta_lic", "reciprocal"),
+				matchTarget("lib/libc.a.meta_lic", "reciprocal"),
+				matchTarget("bin/bin2.meta_lic", "notice"),
+				matchTarget("highest.apex.meta_lic", "notice"),
+				matchTarget("lib/libb.so.meta_lic", "notice"),
+				matchResolution(
+					"bin/bin1.meta_lic",
+					"bin/bin1.meta_lic",
+					"notice"),
+				matchResolution(
+					"bin/bin1.meta_lic",
+					"lib/liba.so.meta_lic",
+					"reciprocal"),
+				matchResolution(
+					"bin/bin1.meta_lic",
+					"lib/libc.a.meta_lic",
+					"reciprocal"),
+				matchResolution(
+					"bin/bin2.meta_lic",
+					"bin/bin2.meta_lic",
+					"notice"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"bin/bin1.meta_lic",
+					"notice"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"bin/bin2.meta_lic",
+					"notice"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"highest.apex.meta_lic",
+					"notice"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"lib/liba.so.meta_lic",
+					"reciprocal"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"lib/libb.so.meta_lic",
+					"notice"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"lib/libc.a.meta_lic",
+					"reciprocal"),
+				matchResolution(
+					"lib/liba.so.meta_lic",
+					"lib/liba.so.meta_lic",
+					"reciprocal"),
+				matchResolution(
+					"lib/libb.so.meta_lic",
+					"lib/libb.so.meta_lic",
+					"notice"),
+			},
+		},
+		{
+			condition: "reciprocal",
+			name:      "container",
+			roots:     []string{"container.zip.meta_lic"},
+			expectedOut: []getMatcher{
+				matchTarget("testdata/reciprocal/bin/bin1.meta_lic"),
+				matchTarget("testdata/reciprocal/lib/liba.so.meta_lic"),
+				matchTarget("testdata/reciprocal/lib/libc.a.meta_lic"),
+				matchTarget("testdata/reciprocal/bin/bin2.meta_lic"),
+				matchTarget("testdata/reciprocal/container.zip.meta_lic"),
+				matchTarget("testdata/reciprocal/lib/libb.so.meta_lic"),
+				matchResolution(
+					"testdata/reciprocal/bin/bin1.meta_lic",
+					"testdata/reciprocal/bin/bin1.meta_lic",
+					"notice"),
+				matchResolution(
+					"testdata/reciprocal/bin/bin1.meta_lic",
+					"testdata/reciprocal/lib/liba.so.meta_lic",
+					"reciprocal"),
+				matchResolution(
+					"testdata/reciprocal/bin/bin1.meta_lic",
+					"testdata/reciprocal/lib/libc.a.meta_lic",
+					"reciprocal"),
+				matchResolution(
+					"testdata/reciprocal/bin/bin2.meta_lic",
+					"testdata/reciprocal/bin/bin2.meta_lic",
+					"notice"),
+				matchResolution(
+					"testdata/reciprocal/container.zip.meta_lic",
+					"testdata/reciprocal/bin/bin1.meta_lic",
+					"notice"),
+				matchResolution(
+					"testdata/reciprocal/container.zip.meta_lic",
+					"testdata/reciprocal/bin/bin2.meta_lic",
+					"notice"),
+				matchResolution(
+					"testdata/reciprocal/container.zip.meta_lic",
+					"testdata/reciprocal/container.zip.meta_lic",
+					"notice"),
+				matchResolution(
+					"testdata/reciprocal/container.zip.meta_lic",
+					"testdata/reciprocal/lib/liba.so.meta_lic",
+					"reciprocal"),
+				matchResolution(
+					"testdata/reciprocal/container.zip.meta_lic",
+					"testdata/reciprocal/lib/libb.so.meta_lic",
+					"notice"),
+				matchResolution(
+					"testdata/reciprocal/container.zip.meta_lic",
+					"testdata/reciprocal/lib/libc.a.meta_lic",
+					"reciprocal"),
+				matchResolution(
+					"testdata/reciprocal/lib/liba.so.meta_lic",
+					"testdata/reciprocal/lib/liba.so.meta_lic",
+					"reciprocal"),
+				matchResolution(
+					"testdata/reciprocal/lib/libb.so.meta_lic",
+					"testdata/reciprocal/lib/libb.so.meta_lic",
+					"notice"),
+			},
+		},
+		{
+			condition: "reciprocal",
+			name:      "application",
+			roots:     []string{"application.meta_lic"},
+			expectedOut: []getMatcher{
+				matchTarget("testdata/reciprocal/application.meta_lic"),
+				matchTarget("testdata/reciprocal/lib/liba.so.meta_lic"),
+				matchResolution(
+					"testdata/reciprocal/application.meta_lic",
+					"testdata/reciprocal/application.meta_lic",
+					"notice"),
+				matchResolution(
+					"testdata/reciprocal/application.meta_lic",
+					"testdata/reciprocal/lib/liba.so.meta_lic",
+					"reciprocal"),
+			},
+		},
+		{
+			condition: "reciprocal",
+			name:      "binary",
+			roots:     []string{"bin/bin1.meta_lic"},
+			expectedOut: []getMatcher{
+				matchTarget("testdata/reciprocal/bin/bin1.meta_lic"),
+				matchTarget("testdata/reciprocal/lib/liba.so.meta_lic"),
+				matchTarget("testdata/reciprocal/lib/libc.a.meta_lic"),
+				matchResolution(
+					"testdata/reciprocal/bin/bin1.meta_lic",
+					"testdata/reciprocal/bin/bin1.meta_lic",
+					"notice"),
+				matchResolution(
+					"testdata/reciprocal/bin/bin1.meta_lic",
+					"testdata/reciprocal/lib/liba.so.meta_lic",
+					"reciprocal"),
+				matchResolution(
+					"testdata/reciprocal/bin/bin1.meta_lic",
+					"testdata/reciprocal/lib/libc.a.meta_lic",
+					"reciprocal"),
+			},
+		},
+		{
+			condition: "reciprocal",
+			name:      "library",
+			roots:     []string{"lib/libd.so.meta_lic"},
+			expectedOut: []getMatcher{
+				matchTarget("testdata/reciprocal/lib/libd.so.meta_lic"),
+				matchResolution(
+					"testdata/reciprocal/lib/libd.so.meta_lic",
+					"testdata/reciprocal/lib/libd.so.meta_lic",
+					"notice"),
+			},
+		},
+		{
+			condition: "restricted",
+			name:      "apex",
+			roots:     []string{"highest.apex.meta_lic"},
+			expectedOut: []getMatcher{
+				matchTarget("testdata/restricted/bin/bin1.meta_lic"),
+				matchTarget("testdata/restricted/lib/liba.so.meta_lic"),
+				matchTarget("testdata/restricted/lib/libc.a.meta_lic"),
+				matchTarget("testdata/restricted/bin/bin2.meta_lic"),
+				matchTarget("testdata/restricted/lib/libb.so.meta_lic"),
+				matchTarget("testdata/restricted/highest.apex.meta_lic"),
+				matchResolution(
+					"testdata/restricted/bin/bin1.meta_lic",
+					"testdata/restricted/bin/bin1.meta_lic",
+					"restricted_allows_dynamic_linking",
+					"notice"),
+				matchResolution(
+					"testdata/restricted/bin/bin1.meta_lic",
+					"testdata/restricted/lib/liba.so.meta_lic",
+					"restricted_allows_dynamic_linking"),
+				matchResolution(
+					"testdata/restricted/bin/bin1.meta_lic",
+					"testdata/restricted/lib/libc.a.meta_lic",
+					"reciprocal",
+					"restricted_allows_dynamic_linking"),
+				matchResolution(
+					"testdata/restricted/bin/bin2.meta_lic",
+					"testdata/restricted/bin/bin2.meta_lic",
+					"restricted",
+					"notice"),
+				matchResolution(
+					"testdata/restricted/bin/bin2.meta_lic",
+					"testdata/restricted/lib/libb.so.meta_lic",
+					"restricted"),
+				matchResolution(
+					"testdata/restricted/highest.apex.meta_lic",
+					"testdata/restricted/bin/bin1.meta_lic",
+					"restricted_allows_dynamic_linking",
+					"notice"),
+				matchResolution(
+					"testdata/restricted/highest.apex.meta_lic",
+					"testdata/restricted/bin/bin2.meta_lic",
+					"restricted",
+					"notice"),
+				matchResolution(
+					"testdata/restricted/highest.apex.meta_lic",
+					"testdata/restricted/highest.apex.meta_lic",
+					"restricted",
+					"restricted_allows_dynamic_linking",
+					"notice"),
+				matchResolution(
+					"testdata/restricted/highest.apex.meta_lic",
+					"testdata/restricted/lib/liba.so.meta_lic",
+					"restricted_allows_dynamic_linking"),
+				matchResolution(
+					"testdata/restricted/highest.apex.meta_lic",
+					"testdata/restricted/lib/libb.so.meta_lic",
+					"restricted"),
+				matchResolution(
+					"testdata/restricted/highest.apex.meta_lic",
+					"testdata/restricted/lib/libc.a.meta_lic",
+					"reciprocal",
+					"restricted_allows_dynamic_linking"),
+				matchResolution(
+					"testdata/restricted/lib/liba.so.meta_lic",
+					"testdata/restricted/lib/liba.so.meta_lic",
+					"restricted_allows_dynamic_linking"),
+				matchResolution(
+					"testdata/restricted/lib/libb.so.meta_lic",
+					"testdata/restricted/lib/libb.so.meta_lic",
+					"restricted"),
+			},
+		},
+		{
+			condition: "restricted",
+			name:      "apex_trimmed",
+			roots:     []string{"highest.apex.meta_lic"},
+			ctx:       context{stripPrefix: "testdata/restricted/"},
+			expectedOut: []getMatcher{
+				matchTarget("bin/bin1.meta_lic"),
+				matchTarget("lib/liba.so.meta_lic"),
+				matchTarget("lib/libc.a.meta_lic"),
+				matchTarget("bin/bin2.meta_lic"),
+				matchTarget("lib/libb.so.meta_lic"),
+				matchTarget("highest.apex.meta_lic"),
+				matchResolution(
+					"bin/bin1.meta_lic",
+					"bin/bin1.meta_lic",
+					"restricted_allows_dynamic_linking",
+					"notice"),
+				matchResolution(
+					"bin/bin1.meta_lic",
+					"lib/liba.so.meta_lic",
+					"restricted_allows_dynamic_linking"),
+				matchResolution(
+					"bin/bin1.meta_lic",
+					"lib/libc.a.meta_lic",
+					"reciprocal",
+					"restricted_allows_dynamic_linking"),
+				matchResolution(
+					"bin/bin2.meta_lic",
+					"bin/bin2.meta_lic",
+					"restricted",
+					"notice"),
+				matchResolution(
+					"bin/bin2.meta_lic",
+					"lib/libb.so.meta_lic",
+					"restricted"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"bin/bin1.meta_lic",
+					"restricted_allows_dynamic_linking",
+					"notice"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"bin/bin2.meta_lic",
+					"restricted",
+					"notice"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"highest.apex.meta_lic",
+					"restricted",
+					"restricted_allows_dynamic_linking",
+					"notice"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"lib/liba.so.meta_lic",
+					"restricted_allows_dynamic_linking"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"lib/libb.so.meta_lic",
+					"restricted"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"lib/libc.a.meta_lic",
+					"reciprocal",
+					"restricted_allows_dynamic_linking"),
+				matchResolution(
+					"lib/liba.so.meta_lic",
+					"lib/liba.so.meta_lic",
+					"restricted_allows_dynamic_linking"),
+				matchResolution(
+					"lib/libb.so.meta_lic",
+					"lib/libb.so.meta_lic",
+					"restricted"),
+			},
+		},
+		{
+			condition: "restricted",
+			name:      "apex_trimmed_notice",
+			roots:     []string{"highest.apex.meta_lic"},
+			ctx: context{
+				conditions:  []compliance.LicenseCondition{compliance.NoticeCondition},
+				stripPrefix: "testdata/restricted/",
+			},
+			expectedOut: []getMatcher{
+				matchTarget("bin/bin1.meta_lic"),
+				matchTarget("bin/bin2.meta_lic"),
+				matchTarget("highest.apex.meta_lic"),
+				matchResolution(
+					"bin/bin1.meta_lic",
+					"bin/bin1.meta_lic",
+					"notice"),
+				matchResolution(
+					"bin/bin2.meta_lic",
+					"bin/bin2.meta_lic",
+					"notice"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"bin/bin1.meta_lic",
+					"notice"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"bin/bin2.meta_lic",
+					"notice"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"highest.apex.meta_lic",
+					"notice"),
+			},
+		},
+		{
+			condition: "restricted",
+			name:      "apex_trimmed_share",
+			roots:     []string{"highest.apex.meta_lic"},
+			ctx: context{
+				conditions:  compliance.ImpliesShared.AsList(),
+				stripPrefix: "testdata/restricted/",
+			},
+			expectedOut: []getMatcher{
+				matchTarget("bin/bin1.meta_lic"),
+				matchTarget("lib/liba.so.meta_lic"),
+				matchTarget("lib/libc.a.meta_lic"),
+				matchTarget("bin/bin2.meta_lic"),
+				matchTarget("lib/libb.so.meta_lic"),
+				matchTarget("highest.apex.meta_lic"),
+				matchResolution(
+					"bin/bin1.meta_lic",
+					"bin/bin1.meta_lic",
+					"restricted_allows_dynamic_linking"),
+				matchResolution(
+					"bin/bin1.meta_lic",
+					"lib/liba.so.meta_lic",
+					"restricted_allows_dynamic_linking"),
+				matchResolution(
+					"bin/bin1.meta_lic",
+					"lib/libc.a.meta_lic",
+					"reciprocal",
+					"restricted_allows_dynamic_linking"),
+				matchResolution(
+					"bin/bin2.meta_lic",
+					"bin/bin2.meta_lic",
+					"restricted"),
+				matchResolution(
+					"bin/bin2.meta_lic",
+					"lib/libb.so.meta_lic",
+					"restricted"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"bin/bin1.meta_lic",
+					"restricted_allows_dynamic_linking"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"bin/bin2.meta_lic",
+					"restricted"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"highest.apex.meta_lic",
+					"restricted",
+					"restricted_allows_dynamic_linking"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"lib/liba.so.meta_lic",
+					"restricted_allows_dynamic_linking"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"lib/libb.so.meta_lic",
+					"restricted"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"lib/libc.a.meta_lic",
+					"reciprocal",
+					"restricted_allows_dynamic_linking"),
+				matchResolution(
+					"lib/liba.so.meta_lic",
+					"lib/liba.so.meta_lic",
+					"restricted_allows_dynamic_linking"),
+				matchResolution(
+					"lib/libb.so.meta_lic",
+					"lib/libb.so.meta_lic",
+					"restricted"),
+			},
+		},
+		{
+			condition: "restricted",
+			name:      "apex_trimmed_private",
+			roots:     []string{"highest.apex.meta_lic"},
+			ctx: context{
+				conditions:  compliance.ImpliesPrivate.AsList(),
+				stripPrefix: "testdata/restricted/",
+			},
+			expectedOut: []getMatcher{},
+		},
+		{
+			condition: "restricted",
+			name:      "apex_trimmed_share_private",
+			roots:     []string{"highest.apex.meta_lic"},
+			ctx: context{
+				conditions:  compliance.ImpliesShared.Union(compliance.ImpliesPrivate).AsList(),
+				stripPrefix: "testdata/restricted/",
+			},
+			expectedOut: []getMatcher{
+				matchTarget("bin/bin1.meta_lic"),
+				matchTarget("lib/liba.so.meta_lic"),
+				matchTarget("lib/libc.a.meta_lic"),
+				matchTarget("bin/bin2.meta_lic"),
+				matchTarget("lib/libb.so.meta_lic"),
+				matchTarget("highest.apex.meta_lic"),
+				matchResolution(
+					"bin/bin1.meta_lic",
+					"bin/bin1.meta_lic",
+					"restricted_allows_dynamic_linking"),
+				matchResolution(
+					"bin/bin1.meta_lic",
+					"lib/liba.so.meta_lic",
+					"restricted_allows_dynamic_linking"),
+				matchResolution(
+					"bin/bin1.meta_lic",
+					"lib/libc.a.meta_lic",
+					"reciprocal",
+					"restricted_allows_dynamic_linking"),
+				matchResolution(
+					"bin/bin2.meta_lic",
+					"bin/bin2.meta_lic",
+					"restricted"),
+				matchResolution(
+					"bin/bin2.meta_lic",
+					"lib/libb.so.meta_lic",
+					"restricted"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"bin/bin1.meta_lic",
+					"restricted_allows_dynamic_linking"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"bin/bin2.meta_lic",
+					"restricted"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"highest.apex.meta_lic",
+					"restricted",
+					"restricted_allows_dynamic_linking"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"lib/liba.so.meta_lic",
+					"restricted_allows_dynamic_linking"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"lib/libb.so.meta_lic",
+					"restricted"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"lib/libc.a.meta_lic",
+					"reciprocal",
+					"restricted_allows_dynamic_linking"),
+				matchResolution(
+					"lib/liba.so.meta_lic",
+					"lib/liba.so.meta_lic",
+					"restricted_allows_dynamic_linking"),
+				matchResolution(
+					"lib/libb.so.meta_lic",
+					"lib/libb.so.meta_lic",
+					"restricted"),
+			},
+		},
+		{
+			condition: "restricted",
+			name:      "apex_trimmed_labelled",
+			roots:     []string{"highest.apex.meta_lic"},
+			ctx:       context{stripPrefix: "testdata/restricted/", labelConditions: true},
+			expectedOut: []getMatcher{
+				matchTarget("bin/bin1.meta_lic", "notice"),
+				matchTarget("lib/liba.so.meta_lic", "restricted_allows_dynamic_linking"),
+				matchTarget("lib/libc.a.meta_lic", "reciprocal"),
+				matchTarget("bin/bin2.meta_lic", "notice"),
+				matchTarget("lib/libb.so.meta_lic", "restricted"),
+				matchTarget("highest.apex.meta_lic", "notice"),
+				matchResolution(
+					"bin/bin1.meta_lic",
+					"bin/bin1.meta_lic",
+					"restricted_allows_dynamic_linking",
+					"notice"),
+				matchResolution(
+					"bin/bin1.meta_lic",
+					"lib/liba.so.meta_lic",
+					"restricted_allows_dynamic_linking"),
+				matchResolution(
+					"bin/bin1.meta_lic",
+					"lib/libc.a.meta_lic",
+					"reciprocal",
+					"restricted_allows_dynamic_linking"),
+				matchResolution(
+					"bin/bin2.meta_lic",
+					"bin/bin2.meta_lic",
+					"restricted",
+					"notice"),
+				matchResolution(
+					"bin/bin2.meta_lic",
+					"lib/libb.so.meta_lic",
+					"restricted"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"bin/bin1.meta_lic",
+					"restricted_allows_dynamic_linking",
+					"notice"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"bin/bin2.meta_lic",
+					"restricted",
+					"notice"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"highest.apex.meta_lic",
+					"restricted",
+					"restricted_allows_dynamic_linking",
+					"notice"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"lib/liba.so.meta_lic",
+					"restricted_allows_dynamic_linking"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"lib/libb.so.meta_lic",
+					"restricted"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"lib/libc.a.meta_lic",
+					"reciprocal",
+					"restricted_allows_dynamic_linking"),
+				matchResolution(
+					"lib/liba.so.meta_lic",
+					"lib/liba.so.meta_lic",
+					"restricted_allows_dynamic_linking"),
+				matchResolution(
+					"lib/libb.so.meta_lic",
+					"lib/libb.so.meta_lic",
+					"restricted"),
+			},
+		},
+		{
+			condition: "restricted",
+			name:      "container",
+			roots:     []string{"container.zip.meta_lic"},
+			expectedOut: []getMatcher{
+				matchTarget("testdata/restricted/bin/bin1.meta_lic"),
+				matchTarget("testdata/restricted/lib/liba.so.meta_lic"),
+				matchTarget("testdata/restricted/lib/libc.a.meta_lic"),
+				matchTarget("testdata/restricted/bin/bin2.meta_lic"),
+				matchTarget("testdata/restricted/lib/libb.so.meta_lic"),
+				matchTarget("testdata/restricted/container.zip.meta_lic"),
+				matchResolution(
+					"testdata/restricted/bin/bin1.meta_lic",
+					"testdata/restricted/bin/bin1.meta_lic",
+					"restricted_allows_dynamic_linking",
+					"notice"),
+				matchResolution(
+					"testdata/restricted/bin/bin1.meta_lic",
+					"testdata/restricted/lib/liba.so.meta_lic",
+					"restricted_allows_dynamic_linking"),
+				matchResolution(
+					"testdata/restricted/bin/bin1.meta_lic",
+					"testdata/restricted/lib/libc.a.meta_lic",
+					"reciprocal",
+					"restricted_allows_dynamic_linking"),
+				matchResolution(
+					"testdata/restricted/bin/bin2.meta_lic",
+					"testdata/restricted/bin/bin2.meta_lic",
+					"restricted",
+					"notice"),
+				matchResolution(
+					"testdata/restricted/bin/bin2.meta_lic",
+					"testdata/restricted/lib/libb.so.meta_lic",
+					"restricted"),
+				matchResolution(
+					"testdata/restricted/container.zip.meta_lic",
+					"testdata/restricted/bin/bin1.meta_lic",
+					"restricted_allows_dynamic_linking",
+					"notice"),
+				matchResolution(
+					"testdata/restricted/container.zip.meta_lic",
+					"testdata/restricted/bin/bin2.meta_lic",
+					"restricted",
+					"notice"),
+				matchResolution(
+					"testdata/restricted/container.zip.meta_lic",
+					"testdata/restricted/container.zip.meta_lic",
+					"restricted",
+					"restricted_allows_dynamic_linking",
+					"notice"),
+				matchResolution(
+					"testdata/restricted/container.zip.meta_lic",
+					"testdata/restricted/lib/liba.so.meta_lic",
+					"restricted_allows_dynamic_linking"),
+				matchResolution(
+					"testdata/restricted/container.zip.meta_lic",
+					"testdata/restricted/lib/libb.so.meta_lic",
+					"restricted"),
+				matchResolution(
+					"testdata/restricted/container.zip.meta_lic",
+					"testdata/restricted/lib/libc.a.meta_lic",
+					"reciprocal",
+					"restricted_allows_dynamic_linking"),
+				matchResolution(
+					"testdata/restricted/lib/liba.so.meta_lic",
+					"testdata/restricted/lib/liba.so.meta_lic",
+					"restricted_allows_dynamic_linking"),
+				matchResolution(
+					"testdata/restricted/lib/libb.so.meta_lic",
+					"testdata/restricted/lib/libb.so.meta_lic",
+					"restricted"),
+			},
+		},
+		{
+			condition: "restricted",
+			name:      "application",
+			roots:     []string{"application.meta_lic"},
+			expectedOut: []getMatcher{
+				matchTarget("testdata/restricted/application.meta_lic"),
+				matchTarget("testdata/restricted/lib/liba.so.meta_lic"),
+				matchResolution(
+					"testdata/restricted/application.meta_lic",
+					"testdata/restricted/application.meta_lic",
+					"restricted",
+					"restricted_allows_dynamic_linking",
+					"notice"),
+				matchResolution(
+					"testdata/restricted/application.meta_lic",
+					"testdata/restricted/lib/liba.so.meta_lic",
+					"restricted_allows_dynamic_linking",
+					"restricted"),
+			},
+		},
+		{
+			condition: "restricted",
+			name:      "binary",
+			roots:     []string{"bin/bin1.meta_lic"},
+			expectedOut: []getMatcher{
+				matchTarget("testdata/restricted/bin/bin1.meta_lic"),
+				matchTarget("testdata/restricted/lib/liba.so.meta_lic"),
+				matchTarget("testdata/restricted/lib/libc.a.meta_lic"),
+				matchResolution(
+					"testdata/restricted/bin/bin1.meta_lic",
+					"testdata/restricted/bin/bin1.meta_lic",
+					"restricted_allows_dynamic_linking",
+					"notice"),
+				matchResolution(
+					"testdata/restricted/bin/bin1.meta_lic",
+					"testdata/restricted/lib/liba.so.meta_lic",
+					"restricted_allows_dynamic_linking"),
+				matchResolution(
+					"testdata/restricted/bin/bin1.meta_lic",
+					"testdata/restricted/lib/libc.a.meta_lic",
+					"restricted_allows_dynamic_linking",
+					"reciprocal"),
+			},
+		},
+		{
+			condition: "restricted",
+			name:      "library",
+			roots:     []string{"lib/libd.so.meta_lic"},
+			expectedOut: []getMatcher{
+				matchTarget("testdata/restricted/lib/libd.so.meta_lic"),
+				matchResolution(
+					"testdata/restricted/lib/libd.so.meta_lic",
+					"testdata/restricted/lib/libd.so.meta_lic",
+					"notice"),
+			},
+		},
+		{
+			condition: "proprietary",
+			name:      "apex",
+			roots:     []string{"highest.apex.meta_lic"},
+			expectedOut: []getMatcher{
+				matchTarget("testdata/proprietary/bin/bin1.meta_lic"),
+				matchTarget("testdata/proprietary/lib/liba.so.meta_lic"),
+				matchTarget("testdata/proprietary/lib/libc.a.meta_lic"),
+				matchTarget("testdata/proprietary/bin/bin2.meta_lic"),
+				matchTarget("testdata/proprietary/lib/libb.so.meta_lic"),
+				matchTarget("testdata/proprietary/highest.apex.meta_lic"),
+				matchResolution(
+					"testdata/proprietary/bin/bin1.meta_lic",
+					"testdata/proprietary/bin/bin1.meta_lic",
+					"notice"),
+				matchResolution(
+					"testdata/proprietary/bin/bin1.meta_lic",
+					"testdata/proprietary/lib/liba.so.meta_lic",
+					"by_exception_only",
+					"proprietary"),
+				matchResolution(
+					"testdata/proprietary/bin/bin1.meta_lic",
+					"testdata/proprietary/lib/libc.a.meta_lic",
+					"by_exception_only",
+					"proprietary"),
+				matchResolution(
+					"testdata/proprietary/bin/bin2.meta_lic",
+					"testdata/proprietary/bin/bin2.meta_lic",
+					"restricted",
+					"by_exception_only",
+					"proprietary"),
+				matchResolution(
+					"testdata/proprietary/bin/bin2.meta_lic",
+					"testdata/proprietary/lib/libb.so.meta_lic",
+					"restricted"),
+				matchResolution(
+					"testdata/proprietary/highest.apex.meta_lic",
+					"testdata/proprietary/bin/bin1.meta_lic",
+					"notice"),
+				matchResolution(
+					"testdata/proprietary/highest.apex.meta_lic",
+					"testdata/proprietary/bin/bin2.meta_lic",
+					"restricted",
+					"by_exception_only",
+					"proprietary"),
+				matchResolution(
+					"testdata/proprietary/highest.apex.meta_lic",
+					"testdata/proprietary/highest.apex.meta_lic",
+					"restricted",
+					"notice"),
+				matchResolution(
+					"testdata/proprietary/highest.apex.meta_lic",
+					"testdata/proprietary/lib/liba.so.meta_lic",
+					"by_exception_only",
+					"proprietary"),
+				matchResolution(
+					"testdata/proprietary/highest.apex.meta_lic",
+					"testdata/proprietary/lib/libb.so.meta_lic",
+					"restricted"),
+				matchResolution(
+					"testdata/proprietary/highest.apex.meta_lic",
+					"testdata/proprietary/lib/libc.a.meta_lic",
+					"by_exception_only",
+					"proprietary"),
+				matchResolution(
+					"testdata/proprietary/lib/liba.so.meta_lic",
+					"testdata/proprietary/lib/liba.so.meta_lic",
+					"by_exception_only",
+					"proprietary"),
+				matchResolution(
+					"testdata/proprietary/lib/libb.so.meta_lic",
+					"testdata/proprietary/lib/libb.so.meta_lic",
+					"restricted"),
+			},
+		},
+		{
+			condition: "proprietary",
+			name:      "apex_trimmed",
+			roots:     []string{"highest.apex.meta_lic"},
+			ctx:       context{stripPrefix: "testdata/proprietary/"},
+			expectedOut: []getMatcher{
+				matchTarget("bin/bin1.meta_lic"),
+				matchTarget("lib/liba.so.meta_lic"),
+				matchTarget("lib/libc.a.meta_lic"),
+				matchTarget("bin/bin2.meta_lic"),
+				matchTarget("lib/libb.so.meta_lic"),
+				matchTarget("highest.apex.meta_lic"),
+				matchResolution(
+					"bin/bin1.meta_lic",
+					"bin/bin1.meta_lic",
+					"notice"),
+				matchResolution(
+					"bin/bin1.meta_lic",
+					"lib/liba.so.meta_lic",
+					"by_exception_only",
+					"proprietary"),
+				matchResolution(
+					"bin/bin1.meta_lic",
+					"lib/libc.a.meta_lic",
+					"by_exception_only",
+					"proprietary"),
+				matchResolution(
+					"bin/bin2.meta_lic",
+					"bin/bin2.meta_lic",
+					"by_exception_only",
+					"restricted",
+					"proprietary"),
+				matchResolution(
+					"bin/bin2.meta_lic",
+					"lib/libb.so.meta_lic",
+					"restricted"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"bin/bin1.meta_lic",
+					"notice"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"bin/bin2.meta_lic",
+					"restricted",
+					"by_exception_only",
+					"proprietary"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"highest.apex.meta_lic",
+					"restricted",
+					"notice"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"lib/liba.so.meta_lic",
+					"by_exception_only",
+					"proprietary"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"lib/libb.so.meta_lic",
+					"restricted"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"lib/libc.a.meta_lic",
+					"by_exception_only",
+					"proprietary"),
+				matchResolution(
+					"lib/liba.so.meta_lic",
+					"lib/liba.so.meta_lic",
+					"by_exception_only",
+					"proprietary"),
+				matchResolution(
+					"lib/libb.so.meta_lic",
+					"lib/libb.so.meta_lic",
+					"restricted"),
+			},
+		},
+		{
+			condition: "proprietary",
+			name:      "apex_trimmed_notice",
+			roots:     []string{"highest.apex.meta_lic"},
+			ctx: context{
+				conditions:  []compliance.LicenseCondition{compliance.NoticeCondition},
+				stripPrefix: "testdata/proprietary/",
+			},
+			expectedOut: []getMatcher{
+				matchTarget("bin/bin1.meta_lic"),
+				matchTarget("highest.apex.meta_lic"),
+				matchResolution(
+					"bin/bin1.meta_lic",
+					"bin/bin1.meta_lic",
+					"notice"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"bin/bin1.meta_lic",
+					"notice"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"highest.apex.meta_lic",
+					"notice"),
+			},
+		},
+		{
+			condition: "proprietary",
+			name:      "apex_trimmed_share",
+			roots:     []string{"highest.apex.meta_lic"},
+			ctx: context{
+				conditions:  compliance.ImpliesShared.AsList(),
+				stripPrefix: "testdata/proprietary/",
+			},
+			expectedOut: []getMatcher{
+				matchTarget("bin/bin2.meta_lic"),
+				matchTarget("lib/libb.so.meta_lic"),
+				matchTarget("highest.apex.meta_lic"),
+				matchResolution(
+					"bin/bin2.meta_lic",
+					"bin/bin2.meta_lic",
+					"restricted"),
+				matchResolution(
+					"bin/bin2.meta_lic",
+					"lib/libb.so.meta_lic",
+					"restricted"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"bin/bin2.meta_lic",
+					"restricted"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"highest.apex.meta_lic",
+					"restricted"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"lib/libb.so.meta_lic",
+					"restricted"),
+				matchResolution(
+					"lib/libb.so.meta_lic",
+					"lib/libb.so.meta_lic",
+					"restricted"),
+			},
+		},
+		{
+			condition: "proprietary",
+			name:      "apex_trimmed_private",
+			roots:     []string{"highest.apex.meta_lic"},
+			ctx: context{
+				conditions:  compliance.ImpliesPrivate.AsList(),
+				stripPrefix: "testdata/proprietary/",
+			},
+			expectedOut: []getMatcher{
+				matchTarget("bin/bin1.meta_lic"),
+				matchTarget("lib/liba.so.meta_lic"),
+				matchTarget("lib/libc.a.meta_lic"),
+				matchTarget("bin/bin2.meta_lic"),
+				matchTarget("highest.apex.meta_lic"),
+				matchResolution(
+					"bin/bin1.meta_lic",
+					"lib/liba.so.meta_lic",
+					"proprietary"),
+				matchResolution(
+					"bin/bin1.meta_lic",
+					"lib/libc.a.meta_lic",
+					"proprietary"),
+				matchResolution(
+					"bin/bin2.meta_lic",
+					"bin/bin2.meta_lic",
+					"proprietary"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"bin/bin2.meta_lic",
+					"proprietary"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"lib/liba.so.meta_lic",
+					"proprietary"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"lib/libc.a.meta_lic",
+					"proprietary"),
+				matchResolution(
+					"lib/liba.so.meta_lic",
+					"lib/liba.so.meta_lic",
+					"proprietary"),
+			},
+		},
+		{
+			condition: "proprietary",
+			name:      "apex_trimmed_share_private",
+			roots:     []string{"highest.apex.meta_lic"},
+			ctx: context{
+				conditions:  compliance.ImpliesShared.Union(compliance.ImpliesPrivate).AsList(),
+				stripPrefix: "testdata/proprietary/",
+			},
+			expectedOut: []getMatcher{
+				matchTarget("bin/bin1.meta_lic"),
+				matchTarget("lib/liba.so.meta_lic"),
+				matchTarget("lib/libc.a.meta_lic"),
+				matchTarget("bin/bin2.meta_lic"),
+				matchTarget("lib/libb.so.meta_lic"),
+				matchTarget("highest.apex.meta_lic"),
+				matchResolution(
+					"bin/bin1.meta_lic",
+					"lib/liba.so.meta_lic",
+					"proprietary"),
+				matchResolution(
+					"bin/bin1.meta_lic",
+					"lib/libc.a.meta_lic",
+					"proprietary"),
+				matchResolution(
+					"bin/bin2.meta_lic",
+					"bin/bin2.meta_lic",
+					"restricted",
+					"proprietary"),
+				matchResolution(
+					"bin/bin2.meta_lic",
+					"lib/libb.so.meta_lic",
+					"restricted"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"bin/bin2.meta_lic",
+					"restricted",
+					"proprietary"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"highest.apex.meta_lic",
+					"restricted"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"lib/liba.so.meta_lic",
+					"proprietary"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"lib/libb.so.meta_lic",
+					"restricted"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"lib/libc.a.meta_lic",
+					"proprietary"),
+				matchResolution(
+					"lib/liba.so.meta_lic",
+					"lib/liba.so.meta_lic",
+					"proprietary"),
+				matchResolution(
+					"lib/libb.so.meta_lic",
+					"lib/libb.so.meta_lic",
+					"restricted"),
+			},
+		},
+		{
+			condition: "proprietary",
+			name:      "apex_trimmed_labelled",
+			roots:     []string{"highest.apex.meta_lic"},
+			ctx:       context{stripPrefix: "testdata/proprietary/", labelConditions: true},
+			expectedOut: []getMatcher{
+				matchTarget("bin/bin1.meta_lic", "notice"),
+				matchTarget("lib/liba.so.meta_lic", "by_exception_only", "proprietary"),
+				matchTarget("lib/libc.a.meta_lic", "by_exception_only", "proprietary"),
+				matchTarget("bin/bin2.meta_lic", "by_exception_only", "proprietary"),
+				matchTarget("lib/libb.so.meta_lic", "restricted"),
+				matchTarget("highest.apex.meta_lic", "notice"),
+				matchResolution(
+					"bin/bin1.meta_lic",
+					"bin/bin1.meta_lic",
+					"notice"),
+				matchResolution(
+					"bin/bin1.meta_lic",
+					"lib/liba.so.meta_lic",
+					"by_exception_only",
+					"proprietary"),
+				matchResolution(
+					"bin/bin1.meta_lic",
+					"lib/libc.a.meta_lic",
+					"by_exception_only",
+					"proprietary"),
+				matchResolution(
+					"bin/bin2.meta_lic",
+					"bin/bin2.meta_lic",
+					"restricted",
+					"by_exception_only",
+					"proprietary"),
+				matchResolution(
+					"bin/bin2.meta_lic",
+					"lib/libb.so.meta_lic",
+					"restricted"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"bin/bin1.meta_lic",
+					"notice"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"bin/bin2.meta_lic",
+					"restricted",
+					"by_exception_only",
+					"proprietary"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"highest.apex.meta_lic",
+					"restricted",
+					"notice"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"lib/liba.so.meta_lic",
+					"by_exception_only",
+					"proprietary"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"lib/libb.so.meta_lic",
+					"restricted"),
+				matchResolution(
+					"highest.apex.meta_lic",
+					"lib/libc.a.meta_lic",
+					"by_exception_only",
+					"proprietary"),
+				matchResolution(
+					"lib/liba.so.meta_lic",
+					"lib/liba.so.meta_lic",
+					"by_exception_only",
+					"proprietary"),
+				matchResolution(
+					"lib/libb.so.meta_lic",
+					"lib/libb.so.meta_lic",
+					"restricted"),
+			},
+		},
+		{
+			condition: "proprietary",
+			name:      "container",
+			roots:     []string{"container.zip.meta_lic"},
+			expectedOut: []getMatcher{
+				matchTarget("testdata/proprietary/bin/bin1.meta_lic"),
+				matchTarget("testdata/proprietary/lib/liba.so.meta_lic"),
+				matchTarget("testdata/proprietary/lib/libc.a.meta_lic"),
+				matchTarget("testdata/proprietary/bin/bin2.meta_lic"),
+				matchTarget("testdata/proprietary/lib/libb.so.meta_lic"),
+				matchTarget("testdata/proprietary/container.zip.meta_lic"),
+				matchResolution(
+					"testdata/proprietary/bin/bin1.meta_lic",
+					"testdata/proprietary/bin/bin1.meta_lic",
+					"notice"),
+				matchResolution(
+					"testdata/proprietary/bin/bin1.meta_lic",
+					"testdata/proprietary/lib/liba.so.meta_lic",
+					"by_exception_only",
+					"proprietary"),
+				matchResolution(
+					"testdata/proprietary/bin/bin1.meta_lic",
+					"testdata/proprietary/lib/libc.a.meta_lic",
+					"by_exception_only",
+					"proprietary"),
+				matchResolution(
+					"testdata/proprietary/bin/bin2.meta_lic",
+					"testdata/proprietary/bin/bin2.meta_lic",
+					"restricted",
+					"by_exception_only",
+					"proprietary"),
+				matchResolution(
+					"testdata/proprietary/bin/bin2.meta_lic",
+					"testdata/proprietary/lib/libb.so.meta_lic",
+					"restricted"),
+				matchResolution(
+					"testdata/proprietary/container.zip.meta_lic",
+					"testdata/proprietary/bin/bin1.meta_lic",
+					"notice"),
+				matchResolution(
+					"testdata/proprietary/container.zip.meta_lic",
+					"testdata/proprietary/bin/bin2.meta_lic",
+					"restricted",
+					"by_exception_only",
+					"proprietary"),
+				matchResolution(
+					"testdata/proprietary/container.zip.meta_lic",
+					"testdata/proprietary/container.zip.meta_lic",
+					"restricted",
+					"notice"),
+				matchResolution(
+					"testdata/proprietary/container.zip.meta_lic",
+					"testdata/proprietary/lib/liba.so.meta_lic",
+					"by_exception_only",
+					"proprietary"),
+				matchResolution(
+					"testdata/proprietary/container.zip.meta_lic",
+					"testdata/proprietary/lib/libb.so.meta_lic",
+					"restricted"),
+				matchResolution(
+					"testdata/proprietary/container.zip.meta_lic",
+					"testdata/proprietary/lib/libc.a.meta_lic",
+					"by_exception_only",
+					"proprietary"),
+				matchResolution(
+					"testdata/proprietary/lib/liba.so.meta_lic",
+					"testdata/proprietary/lib/liba.so.meta_lic",
+					"by_exception_only",
+					"proprietary"),
+				matchResolution(
+					"testdata/proprietary/lib/libb.so.meta_lic",
+					"testdata/proprietary/lib/libb.so.meta_lic",
+					"restricted"),
+			},
+		},
+		{
+			condition: "proprietary",
+			name:      "application",
+			roots:     []string{"application.meta_lic"},
+			expectedOut: []getMatcher{
+				matchTarget("testdata/proprietary/application.meta_lic"),
+				matchTarget("testdata/proprietary/lib/liba.so.meta_lic"),
+				matchResolution(
+					"testdata/proprietary/application.meta_lic",
+					"testdata/proprietary/application.meta_lic",
+					"notice",
+					"restricted"),
+				matchResolution(
+					"testdata/proprietary/application.meta_lic",
+					"testdata/proprietary/lib/liba.so.meta_lic",
+					"restricted",
+					"by_exception_only",
+					"proprietary"),
+			},
+		},
+		{
+			condition: "proprietary",
+			name:      "binary",
+			roots:     []string{"bin/bin1.meta_lic"},
+			expectedOut: []getMatcher{
+				matchTarget("testdata/proprietary/bin/bin1.meta_lic"),
+				matchTarget("testdata/proprietary/lib/liba.so.meta_lic"),
+				matchTarget("testdata/proprietary/lib/libc.a.meta_lic"),
+				matchResolution(
+					"testdata/proprietary/bin/bin1.meta_lic",
+					"testdata/proprietary/bin/bin1.meta_lic",
+					"notice"),
+				matchResolution(
+					"testdata/proprietary/bin/bin1.meta_lic",
+					"testdata/proprietary/lib/liba.so.meta_lic",
+					"by_exception_only",
+					"proprietary"),
+				matchResolution(
+					"testdata/proprietary/bin/bin1.meta_lic",
+					"testdata/proprietary/lib/libc.a.meta_lic",
+					"by_exception_only",
+					"proprietary"),
+			},
+		},
+		{
+			condition: "proprietary",
+			name:      "library",
+			roots:     []string{"lib/libd.so.meta_lic"},
+			expectedOut: []getMatcher{
+				matchTarget("testdata/proprietary/lib/libd.so.meta_lic"),
+				matchResolution(
+					"testdata/proprietary/lib/libd.so.meta_lic",
+					"testdata/proprietary/lib/libd.so.meta_lic",
+					"notice"),
+			},
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.condition+" "+tt.name, func(t *testing.T) {
+			ctx := &testContext{0, make(map[string]string)}
+
+			stdout := &bytes.Buffer{}
+			stderr := &bytes.Buffer{}
+
+			rootFiles := make([]string, 0, len(tt.roots))
+			for _, r := range tt.roots {
+				rootFiles = append(rootFiles, "testdata/"+tt.condition+"/"+r)
+			}
+			tt.ctx.graphViz = true
+			lg, err := dumpResolutions(&tt.ctx, stdout, stderr, rootFiles...)
+			if err != nil {
+				t.Fatalf("dumpresolutions: error = %v, stderr = %v", err, stderr)
+				return
+			}
+			if stderr.Len() > 0 {
+				t.Errorf("dumpresolutions: gotStderr = %v, want none", stderr)
+			}
+
+			expectedOut := &bytes.Buffer{}
+			for _, eo := range tt.expectedOut {
+				m := eo(ctx)
+				expectedOut.WriteString(m.matchString(ctx, lg))
+				expectedOut.WriteString("\n")
+			}
+
+			outList := strings.Split(stdout.String(), "\n")
+			outLine := 0
+			if outList[outLine] != "strict digraph {" {
+				t.Errorf("dumpresolutions: got 1st line %v, want strict digraph {", outList[outLine])
+			}
+			outLine++
+			if strings.HasPrefix(strings.TrimLeft(outList[outLine], " \t"), "rankdir") {
+				outLine++
+			}
+			endOut := len(outList)
+			for endOut > 0 && strings.TrimLeft(outList[endOut-1], " \t") == "" {
+				endOut--
+			}
+			if outList[endOut-1] != "}" {
+				t.Errorf("dumpresolutions: got last line %v, want }", outList[endOut-1])
+			}
+			endOut--
+			if strings.HasPrefix(strings.TrimLeft(outList[endOut-1], " \t"), "{rank=same") {
+				endOut--
+			}
+			expectedList := strings.Split(expectedOut.String(), "\n")
+			for len(expectedList) > 0 && expectedList[len(expectedList)-1] == "" {
+				expectedList = expectedList[0 : len(expectedList)-1]
+			}
+			matchLine := 0
+
+			for outLine < endOut && matchLine < len(expectedList) && strings.TrimLeft(outList[outLine], " \t") == expectedList[matchLine] {
+				outLine++
+				matchLine++
+			}
+			if outLine < endOut || matchLine < len(expectedList) {
+				if outLine >= endOut {
+					t.Errorf("dumpresolutions: missing lines at end of graph, want %d lines %v", len(expectedList)-matchLine, strings.Join(expectedList[matchLine:], "\n"))
+				} else if matchLine >= len(expectedList) {
+					t.Errorf("dumpresolutions: unexpected lines at end of graph starting line %d, got %v, want nothing", outLine+1, strings.Join(outList[outLine:], "\n"))
+				} else {
+					t.Errorf("dumpresolutions: at line %d, got %v, want %v", outLine+1, strings.Join(outList[outLine:], "\n"), strings.Join(expectedList[matchLine:], "\n"))
+				}
+			}
+		})
+	}
+}