diff --git a/tools/compliance/Android.bp b/tools/compliance/Android.bp index afb3080d3d..bbeb76fcee 100644 --- a/tools/compliance/Android.bp +++ b/tools/compliance/Android.bp @@ -48,7 +48,6 @@ blueprint_go_binary { bootstrap_go_package { name: "compliance-module", srcs: [ - "actionset.go", "condition.go", "conditionset.go", "doc.go", diff --git a/tools/compliance/actionset.go b/tools/compliance/actionset.go deleted file mode 100644 index 656c5deea8..0000000000 --- a/tools/compliance/actionset.go +++ /dev/null @@ -1,119 +0,0 @@ -// 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 compliance - -import ( - "fmt" - "sort" - "strings" -) - -// actionSet maps `actOn` target nodes to the license conditions the actions resolve. -type actionSet map[*TargetNode]*LicenseConditionSet - -// String returns a string representation of the set. -func (as actionSet) String() string { - var sb strings.Builder - fmt.Fprintf(&sb, "{") - osep := "" - for actsOn, cs := range as { - cl := cs.AsList() - sort.Sort(cl) - fmt.Fprintf(&sb, "%s%s -> %s", osep, actsOn.name, cl.String()) - osep = ", " - } - fmt.Fprintf(&sb, "}") - return sb.String() -} - -// byName returns the subset of `as` actions where the condition name is in `names`. -func (as actionSet) byName(names ConditionNames) actionSet { - result := make(actionSet) - for actsOn, cs := range as { - bn := cs.ByName(names) - if bn.IsEmpty() { - continue - } - result[actsOn] = bn - } - return result -} - -// byActsOn returns the subset of `as` where `actsOn` is in the `reachable` target node set. -func (as actionSet) byActsOn(reachable *TargetNodeSet) actionSet { - result := make(actionSet) - for actsOn, cs := range as { - if !reachable.Contains(actsOn) || cs.IsEmpty() { - continue - } - result[actsOn] = cs.Copy() - } - return result -} - -// copy returns another actionSet with the same value as `as` -func (as actionSet) copy() actionSet { - result := make(actionSet) - for actsOn, cs := range as { - if cs.IsEmpty() { - continue - } - result[actsOn] = cs.Copy() - } - return result -} - -// addSet adds all of the actions of `other` if not already present. -func (as actionSet) addSet(other actionSet) { - for actsOn, cs := range other { - as.add(actsOn, cs) - } -} - -// add makes the action on `actsOn` to resolve the conditions in `cs` a member of the set. -func (as actionSet) add(actsOn *TargetNode, cs *LicenseConditionSet) { - if acs, ok := as[actsOn]; ok { - acs.AddSet(cs) - } else { - as[actsOn] = cs.Copy() - } -} - -// addCondition makes the action on `actsOn` to resolve `lc` a member of the set. -func (as actionSet) addCondition(actsOn *TargetNode, lc LicenseCondition) { - if _, ok := as[actsOn]; !ok { - as[actsOn] = newLicenseConditionSet() - } - as[actsOn].Add(lc) -} - -// isEmpty returns true if no action to resolve a condition exists. -func (as actionSet) isEmpty() bool { - for _, cs := range as { - if !cs.IsEmpty() { - return false - } - } - return true -} - -// conditions returns the set of conditions resolved by the action set. -func (as actionSet) conditions() *LicenseConditionSet { - result := newLicenseConditionSet() - for _, cs := range as { - result.AddSet(cs) - } - return result -} diff --git a/tools/compliance/cmd/checkshare.go b/tools/compliance/cmd/checkshare.go index efac8dc661..5114a28d6b 100644 --- a/tools/compliance/cmd/checkshare.go +++ b/tools/compliance/cmd/checkshare.go @@ -30,8 +30,8 @@ func init() { Reports on stderr any targets where policy says that the source both must and must not be shared. The error report indicates the target, the -license condition with origin that has a source privacy policy, and the -license condition with origin that has a source sharing policy. +license condition that has a source privacy policy, and the license +condition that has a source sharing policy. Any given target may appear multiple times with different combinations of conflicting license conditions. diff --git a/tools/compliance/cmd/checkshare_test.go b/tools/compliance/cmd/checkshare_test.go index 8ea7748b90..5036aa5f15 100644 --- a/tools/compliance/cmd/checkshare_test.go +++ b/tools/compliance/cmd/checkshare_test.go @@ -23,15 +23,12 @@ import ( type outcome struct { target string - privacyOrigin string privacyCondition string - shareOrigin string shareCondition string } func (o *outcome) String() string { - return fmt.Sprintf("%s %s from %s and must share from %s %s", - o.target, o.privacyCondition, o.privacyOrigin, o.shareCondition, o.shareOrigin) + return fmt.Sprintf("%s %s and must share from %s", o.target, o.privacyCondition, o.shareCondition) } type outcomeList []*outcome @@ -180,9 +177,7 @@ func Test(t *testing.T) { expectedOutcomes: outcomeList{ &outcome{ target: "testdata/proprietary/bin/bin2.meta_lic", - privacyOrigin: "testdata/proprietary/bin/bin2.meta_lic", privacyCondition: "proprietary", - shareOrigin: "testdata/proprietary/lib/libb.so.meta_lic", shareCondition: "restricted", }, }, @@ -195,9 +190,7 @@ func Test(t *testing.T) { expectedOutcomes: outcomeList{ &outcome{ target: "testdata/proprietary/bin/bin2.meta_lic", - privacyOrigin: "testdata/proprietary/bin/bin2.meta_lic", privacyCondition: "proprietary", - shareOrigin: "testdata/proprietary/lib/libb.so.meta_lic", shareCondition: "restricted", }, }, @@ -210,9 +203,7 @@ func Test(t *testing.T) { expectedOutcomes: outcomeList{ &outcome{ target: "testdata/proprietary/lib/liba.so.meta_lic", - privacyOrigin: "testdata/proprietary/lib/liba.so.meta_lic", privacyCondition: "proprietary", - shareOrigin: "testdata/proprietary/lib/libb.so.meta_lic", shareCondition: "restricted", }, }, @@ -225,9 +216,7 @@ func Test(t *testing.T) { expectedOutcomes: outcomeList{ &outcome{ target: "testdata/proprietary/bin/bin2.meta_lic", - privacyOrigin: "testdata/proprietary/bin/bin2.meta_lic", privacyCondition: "proprietary", - shareOrigin: "testdata/proprietary/lib/libb.so.meta_lic", shareCondition: "restricted", }, }, @@ -277,10 +266,8 @@ func Test(t *testing.T) { cFields := strings.Split(ts, " ") actualOutcomes = append(actualOutcomes, &outcome{ target: cFields[0], - privacyOrigin: cFields[3], privacyCondition: cFields[1], - shareOrigin: cFields[9], - shareCondition: cFields[8], + shareCondition: cFields[6], }) } if len(actualOutcomes) != len(tt.expectedOutcomes) { diff --git a/tools/compliance/cmd/dumpgraph_test.go b/tools/compliance/cmd/dumpgraph_test.go index b7d66f7940..305502239c 100644 --- a/tools/compliance/cmd/dumpgraph_test.go +++ b/tools/compliance/cmd/dumpgraph_test.go @@ -327,13 +327,13 @@ func Test_plaintext(t *testing.T) { roots: []string{"highest.apex.meta_lic"}, ctx: context{stripPrefix: "testdata/restricted/", labelConditions: true}, expectedOut: []string{ - "bin/bin1.meta_lic:notice lib/liba.so.meta_lic:restricted static", + "bin/bin1.meta_lic:notice lib/liba.so.meta_lic:restricted_allows_dynamic_linking static", "bin/bin1.meta_lic:notice lib/libc.a.meta_lic:reciprocal static", "bin/bin2.meta_lic:notice lib/libb.so.meta_lic:restricted dynamic", "bin/bin2.meta_lic:notice lib/libd.so.meta_lic:notice dynamic", "highest.apex.meta_lic:notice bin/bin1.meta_lic:notice static", "highest.apex.meta_lic:notice bin/bin2.meta_lic:notice static", - "highest.apex.meta_lic:notice lib/liba.so.meta_lic:restricted static", + "highest.apex.meta_lic:notice lib/liba.so.meta_lic:restricted_allows_dynamic_linking static", "highest.apex.meta_lic:notice lib/libb.so.meta_lic:restricted static", }, }, @@ -996,7 +996,7 @@ func Test_graphviz(t *testing.T) { matchTarget("bin/bin1.meta_lic", "notice"), matchTarget("bin/bin2.meta_lic", "notice"), matchTarget("highest.apex.meta_lic", "notice"), - matchTarget("lib/liba.so.meta_lic", "restricted"), + matchTarget("lib/liba.so.meta_lic", "restricted_allows_dynamic_linking"), matchTarget("lib/libb.so.meta_lic", "restricted"), matchTarget("lib/libc.a.meta_lic", "reciprocal"), matchTarget("lib/libd.so.meta_lic", "notice"), diff --git a/tools/compliance/cmd/dumpresolutions.go b/tools/compliance/cmd/dumpresolutions.go index 36fbb7d8b9..318cd918e6 100644 --- a/tools/compliance/cmd/dumpresolutions.go +++ b/tools/compliance/cmd/dumpresolutions.go @@ -36,7 +36,7 @@ var ( ) type context struct { - conditions []string + conditions []compliance.LicenseCondition graphViz bool labelConditions bool stripPrefix string @@ -50,9 +50,9 @@ 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 joined -set of resolutions for all of the conditions. Otherwise, outputs the -result of the bottom-up and top-down resolve only. +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: @@ -86,13 +86,17 @@ func main() { os.Exit(2) } + lcs := make([]compliance.LicenseCondition, 0, len(*conditions)) + for _, name := range *conditions { + lcs = append(lcs, compliance.RecognizedConditionNames[name]) + } ctx := &context{ - conditions: append([]string{}, *conditions...), + conditions: lcs, graphViz: *graphViz, labelConditions: *labelConditions, stripPrefix: *stripPrefix, } - err := dumpResolutions(ctx, os.Stdout, os.Stderr, flag.Args()...) + _, err := dumpResolutions(ctx, os.Stdout, os.Stderr, flag.Args()...) if err != nil { if err == failNoneRequested { flag.Usage() @@ -104,36 +108,31 @@ func main() { } // dumpResolutions implements the dumpresolutions utility. -func dumpResolutions(ctx *context, stdout, stderr io.Writer, files ...string) error { +func dumpResolutions(ctx *context, stdout, stderr io.Writer, files ...string) (*compliance.LicenseGraph, error) { if len(files) < 1 { - return failNoneRequested + 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 fmt.Errorf("Unable to read license metadata file(s) %q: %v\n", files, err) + return nil, fmt.Errorf("Unable to read license metadata file(s) %q: %v\n", files, err) } if licenseGraph == nil { - return failNoLicenses + return nil, failNoLicenses } - // resolutions will contain the requested set of resolutions. - var resolutions *compliance.ResolutionSet - - resolutions = compliance.ResolveTopDownConditions(licenseGraph) + compliance.ResolveTopDownConditions(licenseGraph) + cs := compliance.AllLicenseConditions if len(ctx.conditions) > 0 { - rlist := make([]*compliance.ResolutionSet, 0, len(ctx.conditions)) + cs = compliance.NewLicenseConditionSet() for _, c := range ctx.conditions { - rlist = append(rlist, compliance.WalkResolutionsForCondition(licenseGraph, resolutions, compliance.ConditionNames{c})) - } - if len(rlist) == 1 { - resolutions = rlist[0] - } else { - resolutions = compliance.JoinResolutionSets(rlist...) + 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 @@ -142,11 +141,7 @@ func dumpResolutions(ctx *context, stdout, stderr io.Writer, files ...string) er targetOut := func(target *compliance.TargetNode, sep string) string { tOut := strings.TrimPrefix(target.Name(), ctx.stripPrefix) if ctx.labelConditions { - conditions := make([]string, 0, target.LicenseConditions().Count()) - for _, lc := range target.LicenseConditions().AsList() { - conditions = append(conditions, lc.Name()) - } - sort.Strings(conditions) + conditions := target.LicenseConditions().Names() if len(conditions) > 0 { tOut += sep + strings.Join(conditions, sep) } @@ -168,26 +163,16 @@ func dumpResolutions(ctx *context, stdout, stderr io.Writer, files ...string) er // 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. - // `oname` is the name of the target where the conditions originate. // `cnames` is the list of conditions to resolve. - outputResolution := func(tname, aname, oname string, cnames []string) { + 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] - oNode := nodes[oname] - fmt.Fprintf(stdout, "\t%s -> %s; %s -> %s [label=\"%s\"];\n", tNode, aNode, aNode, oNode, strings.Join(cnames, "\\n")) + 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 %s\n", tname, aname, oname, strings.Join(cnames, ":")) - } - } - - // outputSingleton prints `tname` to plain text in the unexpected event that `tname` is the name of - // a target in `resolutions.AppliesTo()` but has no conditions to resolve. - outputSingleton := func(tname, aname string) { - if !ctx.graphViz { - fmt.Fprintf(stdout, "%s %s\n", tname, aname) + fmt.Fprintf(stdout, "%s %s %s\n", tname, aname, strings.Join(cnames, ":")) } } @@ -200,16 +185,11 @@ func dumpResolutions(ctx *context, stdout, stderr io.Writer, files ...string) er fmt.Fprintf(stdout, "strict digraph {\n\trankdir=LR;\n") for _, target := range targets { makeNode(target) - rl := compliance.ResolutionList(resolutions.Resolutions(target)) + rl := resolutions.Resolutions(target) sort.Sort(rl) for _, r := range rl { makeNode(r.ActsOn()) } - conditions := rl.AllConditions().AsList() - sort.Sort(conditions) - for _, lc := range conditions { - makeNode(lc.Origin()) - } } } @@ -222,7 +202,7 @@ func dumpResolutions(ctx *context, stdout, stderr io.Writer, files ...string) er tname = targetOut(target, ":") } - rl := compliance.ResolutionList(resolutions.Resolutions(target)) + rl := resolutions.Resolutions(target) sort.Sort(rl) for _, r := range rl { var aname string @@ -232,38 +212,11 @@ func dumpResolutions(ctx *context, stdout, stderr io.Writer, files ...string) er aname = targetOut(r.ActsOn(), ":") } - conditions := r.Resolves().AsList() - sort.Sort(conditions) - - // poname is the previous origin name or "" if no previous - poname := "" - // cnames accumulates the list of condition names originating at a single origin that apply to `target`. - cnames := make([]string, 0, len(conditions)) + cnames := r.Resolves().Names() - // Output 1 line for each attachesTo+actsOn+origin combination. - for _, condition := range conditions { - var oname string - if ctx.graphViz { - oname = condition.Origin().Name() - } else { - oname = targetOut(condition.Origin(), ":") - } - - // Detect when origin changes and output prior origin's conditions. - if poname != oname && poname != "" { - outputResolution(tname, aname, poname, cnames) - cnames = cnames[:0] - } - poname = oname - cnames = append(cnames, condition.Name()) - } - // Output last origin's conditions or a singleton if no origins. - if poname == "" { - outputSingleton(tname, aname) - } else { - outputResolution(tname, aname, poname, cnames) - } + // 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. @@ -280,5 +233,5 @@ func dumpResolutions(ctx *context, stdout, stderr io.Writer, files ...string) er } fmt.Fprintf(stdout, "}\n}\n") } - return nil + return licenseGraph, nil } diff --git a/tools/compliance/cmd/dumpresolutions_test.go b/tools/compliance/cmd/dumpresolutions_test.go index cab1cc8f05..d9046717b2 100644 --- a/tools/compliance/cmd/dumpresolutions_test.go +++ b/tools/compliance/cmd/dumpresolutions_test.go @@ -16,6 +16,7 @@ package main import ( "bytes" + "compliance" "fmt" "strings" "testing" @@ -34,20 +35,18 @@ func Test_plaintext(t *testing.T) { name: "apex", roots: []string{"highest.apex.meta_lic"}, expectedOut: []string{ - "testdata/firstparty/bin/bin1.meta_lic 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 testdata/firstparty/lib/liba.so.meta_lic notice", - "testdata/firstparty/bin/bin1.meta_lic testdata/firstparty/lib/libc.a.meta_lic testdata/firstparty/lib/libc.a.meta_lic notice", - "testdata/firstparty/bin/bin2.meta_lic 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 testdata/firstparty/bin/bin1.meta_lic notice", - "testdata/firstparty/highest.apex.meta_lic testdata/firstparty/bin/bin2.meta_lic testdata/firstparty/bin/bin2.meta_lic notice", - "testdata/firstparty/highest.apex.meta_lic 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 testdata/firstparty/lib/liba.so.meta_lic notice", - "testdata/firstparty/highest.apex.meta_lic testdata/firstparty/lib/libb.so.meta_lic testdata/firstparty/lib/libb.so.meta_lic notice", - "testdata/firstparty/highest.apex.meta_lic testdata/firstparty/lib/libc.a.meta_lic testdata/firstparty/lib/libc.a.meta_lic notice", - "testdata/firstparty/lib/liba.so.meta_lic 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 testdata/firstparty/lib/libb.so.meta_lic notice", - "testdata/firstparty/lib/libc.a.meta_lic testdata/firstparty/lib/libc.a.meta_lic testdata/firstparty/lib/libc.a.meta_lic notice", - "testdata/firstparty/lib/libd.so.meta_lic testdata/firstparty/lib/libd.so.meta_lic testdata/firstparty/lib/libd.so.meta_lic notice", + "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", }, }, { @@ -56,20 +55,18 @@ func Test_plaintext(t *testing.T) { roots: []string{"highest.apex.meta_lic"}, ctx: context{stripPrefix: "testdata/firstparty/"}, expectedOut: []string{ - "bin/bin1.meta_lic bin/bin1.meta_lic bin/bin1.meta_lic notice", - "bin/bin1.meta_lic lib/liba.so.meta_lic lib/liba.so.meta_lic notice", - "bin/bin1.meta_lic lib/libc.a.meta_lic lib/libc.a.meta_lic notice", - "bin/bin2.meta_lic bin/bin2.meta_lic bin/bin2.meta_lic notice", - "highest.apex.meta_lic bin/bin1.meta_lic bin/bin1.meta_lic notice", - "highest.apex.meta_lic bin/bin2.meta_lic bin/bin2.meta_lic notice", - "highest.apex.meta_lic highest.apex.meta_lic highest.apex.meta_lic notice", - "highest.apex.meta_lic lib/liba.so.meta_lic lib/liba.so.meta_lic notice", - "highest.apex.meta_lic lib/libb.so.meta_lic lib/libb.so.meta_lic notice", - "highest.apex.meta_lic lib/libc.a.meta_lic lib/libc.a.meta_lic notice", - "lib/liba.so.meta_lic lib/liba.so.meta_lic lib/liba.so.meta_lic notice", - "lib/libb.so.meta_lic lib/libb.so.meta_lic lib/libb.so.meta_lic notice", - "lib/libc.a.meta_lic lib/libc.a.meta_lic lib/libc.a.meta_lic notice", - "lib/libd.so.meta_lic lib/libd.so.meta_lic lib/libd.so.meta_lic notice", + "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", }, }, { @@ -77,22 +74,22 @@ func Test_plaintext(t *testing.T) { name: "apex_trimmed_notice", roots: []string{"highest.apex.meta_lic"}, ctx: context{ - conditions: []string{"notice"}, + conditions: []compliance.LicenseCondition{compliance.NoticeCondition}, stripPrefix: "testdata/firstparty/", }, expectedOut: []string{ - "bin/bin1.meta_lic bin/bin1.meta_lic bin/bin1.meta_lic notice", - "bin/bin1.meta_lic lib/liba.so.meta_lic lib/liba.so.meta_lic notice", - "bin/bin1.meta_lic lib/libc.a.meta_lic lib/libc.a.meta_lic notice", - "bin/bin2.meta_lic bin/bin2.meta_lic bin/bin2.meta_lic notice", - "highest.apex.meta_lic bin/bin1.meta_lic bin/bin1.meta_lic notice", - "highest.apex.meta_lic bin/bin2.meta_lic bin/bin2.meta_lic notice", - "highest.apex.meta_lic highest.apex.meta_lic highest.apex.meta_lic notice", - "highest.apex.meta_lic lib/liba.so.meta_lic lib/liba.so.meta_lic notice", - "highest.apex.meta_lic lib/libb.so.meta_lic lib/libb.so.meta_lic notice", - "highest.apex.meta_lic lib/libc.a.meta_lic lib/libc.a.meta_lic notice", - "lib/liba.so.meta_lic lib/liba.so.meta_lic lib/liba.so.meta_lic notice", - "lib/libb.so.meta_lic lib/libb.so.meta_lic lib/libb.so.meta_lic notice", + "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", }, }, { @@ -100,7 +97,7 @@ func Test_plaintext(t *testing.T) { name: "apex_trimmed_share", roots: []string{"highest.apex.meta_lic"}, ctx: context{ - conditions: []string{"reciprocal", "restricted"}, + conditions: compliance.ImpliesShared.AsList(), stripPrefix: "testdata/firstparty/", }, expectedOut: []string{}, @@ -110,7 +107,7 @@ func Test_plaintext(t *testing.T) { name: "apex_trimmed_private", roots: []string{"highest.apex.meta_lic"}, ctx: context{ - conditions: []string{"proprietary"}, + conditions: compliance.ImpliesPrivate.AsList(), stripPrefix: "testdata/firstparty/", }, expectedOut: []string{}, @@ -120,7 +117,7 @@ func Test_plaintext(t *testing.T) { name: "apex_trimmed_share_private", roots: []string{"highest.apex.meta_lic"}, ctx: context{ - conditions: []string{"reciprocal", "restricted", "proprietary"}, + conditions: append(compliance.ImpliesPrivate.AsList(),compliance.ImpliesShared.AsList()...), stripPrefix: "testdata/firstparty/", }, expectedOut: []string{}, @@ -131,20 +128,18 @@ func Test_plaintext(t *testing.T) { 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 bin/bin1.meta_lic:notice notice", - "bin/bin1.meta_lic:notice lib/liba.so.meta_lic:notice lib/liba.so.meta_lic:notice notice", - "bin/bin1.meta_lic:notice lib/libc.a.meta_lic:notice lib/libc.a.meta_lic:notice notice", - "bin/bin2.meta_lic:notice bin/bin2.meta_lic:notice bin/bin2.meta_lic:notice notice", - "highest.apex.meta_lic:notice bin/bin1.meta_lic:notice bin/bin1.meta_lic:notice notice", - "highest.apex.meta_lic:notice bin/bin2.meta_lic:notice bin/bin2.meta_lic:notice notice", - "highest.apex.meta_lic:notice highest.apex.meta_lic:notice highest.apex.meta_lic:notice notice", - "highest.apex.meta_lic:notice lib/liba.so.meta_lic:notice lib/liba.so.meta_lic:notice notice", - "highest.apex.meta_lic:notice lib/libb.so.meta_lic:notice lib/libb.so.meta_lic:notice notice", - "highest.apex.meta_lic:notice lib/libc.a.meta_lic:notice lib/libc.a.meta_lic:notice notice", - "lib/liba.so.meta_lic: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 lib/libb.so.meta_lic:notice notice", - "lib/libc.a.meta_lic:notice lib/libc.a.meta_lic:notice lib/libc.a.meta_lic:notice notice", - "lib/libd.so.meta_lic:notice lib/libd.so.meta_lic:notice lib/libd.so.meta_lic:notice notice", + "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", }, }, { @@ -152,20 +147,18 @@ func Test_plaintext(t *testing.T) { name: "container", roots: []string{"container.zip.meta_lic"}, expectedOut: []string{ - "testdata/firstparty/bin/bin1.meta_lic 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 testdata/firstparty/lib/liba.so.meta_lic notice", - "testdata/firstparty/bin/bin1.meta_lic testdata/firstparty/lib/libc.a.meta_lic testdata/firstparty/lib/libc.a.meta_lic notice", - "testdata/firstparty/bin/bin2.meta_lic 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 testdata/firstparty/bin/bin1.meta_lic notice", - "testdata/firstparty/container.zip.meta_lic testdata/firstparty/bin/bin2.meta_lic testdata/firstparty/bin/bin2.meta_lic notice", - "testdata/firstparty/container.zip.meta_lic 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 testdata/firstparty/lib/liba.so.meta_lic notice", - "testdata/firstparty/container.zip.meta_lic testdata/firstparty/lib/libb.so.meta_lic testdata/firstparty/lib/libb.so.meta_lic notice", - "testdata/firstparty/container.zip.meta_lic testdata/firstparty/lib/libc.a.meta_lic testdata/firstparty/lib/libc.a.meta_lic notice", - "testdata/firstparty/lib/liba.so.meta_lic 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 testdata/firstparty/lib/libb.so.meta_lic notice", - "testdata/firstparty/lib/libc.a.meta_lic testdata/firstparty/lib/libc.a.meta_lic testdata/firstparty/lib/libc.a.meta_lic notice", - "testdata/firstparty/lib/libd.so.meta_lic testdata/firstparty/lib/libd.so.meta_lic testdata/firstparty/lib/libd.so.meta_lic notice", + "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", }, }, { @@ -173,11 +166,8 @@ func Test_plaintext(t *testing.T) { name: "application", roots: []string{"application.meta_lic"}, expectedOut: []string{ - "testdata/firstparty/application.meta_lic testdata/firstparty/application.meta_lic testdata/firstparty/application.meta_lic notice", - "testdata/firstparty/application.meta_lic testdata/firstparty/lib/liba.so.meta_lic testdata/firstparty/lib/liba.so.meta_lic notice", - "testdata/firstparty/bin/bin3.meta_lic testdata/firstparty/bin/bin3.meta_lic testdata/firstparty/bin/bin3.meta_lic notice", - "testdata/firstparty/lib/liba.so.meta_lic 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 testdata/firstparty/lib/libb.so.meta_lic notice", + "testdata/firstparty/application.meta_lic testdata/firstparty/application.meta_lic notice", + "testdata/firstparty/application.meta_lic testdata/firstparty/lib/liba.so.meta_lic notice", }, }, { @@ -185,11 +175,9 @@ func Test_plaintext(t *testing.T) { name: "binary", roots: []string{"bin/bin1.meta_lic"}, expectedOut: []string{ - "testdata/firstparty/bin/bin1.meta_lic 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 testdata/firstparty/lib/liba.so.meta_lic notice", - "testdata/firstparty/bin/bin1.meta_lic testdata/firstparty/lib/libc.a.meta_lic testdata/firstparty/lib/libc.a.meta_lic notice", - "testdata/firstparty/lib/liba.so.meta_lic testdata/firstparty/lib/liba.so.meta_lic testdata/firstparty/lib/liba.so.meta_lic notice", - "testdata/firstparty/lib/libc.a.meta_lic testdata/firstparty/lib/libc.a.meta_lic testdata/firstparty/lib/libc.a.meta_lic notice", + "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", }, }, { @@ -197,7 +185,7 @@ func Test_plaintext(t *testing.T) { 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 testdata/firstparty/lib/libd.so.meta_lic notice", + "testdata/firstparty/lib/libd.so.meta_lic testdata/firstparty/lib/libd.so.meta_lic notice", }, }, { @@ -205,20 +193,18 @@ func Test_plaintext(t *testing.T) { name: "apex", roots: []string{"highest.apex.meta_lic"}, expectedOut: []string{ - "testdata/notice/bin/bin1.meta_lic 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 testdata/notice/lib/liba.so.meta_lic notice", - "testdata/notice/bin/bin1.meta_lic testdata/notice/lib/libc.a.meta_lic testdata/notice/lib/libc.a.meta_lic notice", - "testdata/notice/bin/bin2.meta_lic 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 testdata/notice/bin/bin1.meta_lic notice", - "testdata/notice/highest.apex.meta_lic testdata/notice/bin/bin2.meta_lic testdata/notice/bin/bin2.meta_lic notice", - "testdata/notice/highest.apex.meta_lic 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 testdata/notice/lib/liba.so.meta_lic notice", - "testdata/notice/highest.apex.meta_lic testdata/notice/lib/libb.so.meta_lic testdata/notice/lib/libb.so.meta_lic notice", - "testdata/notice/highest.apex.meta_lic testdata/notice/lib/libc.a.meta_lic testdata/notice/lib/libc.a.meta_lic notice", - "testdata/notice/lib/liba.so.meta_lic 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 testdata/notice/lib/libb.so.meta_lic notice", - "testdata/notice/lib/libc.a.meta_lic testdata/notice/lib/libc.a.meta_lic testdata/notice/lib/libc.a.meta_lic notice", - "testdata/notice/lib/libd.so.meta_lic testdata/notice/lib/libd.so.meta_lic testdata/notice/lib/libd.so.meta_lic notice", + "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", }, }, { @@ -227,20 +213,18 @@ func Test_plaintext(t *testing.T) { roots: []string{"highest.apex.meta_lic"}, ctx: context{stripPrefix: "testdata/notice/"}, expectedOut: []string{ - "bin/bin1.meta_lic bin/bin1.meta_lic bin/bin1.meta_lic notice", - "bin/bin1.meta_lic lib/liba.so.meta_lic lib/liba.so.meta_lic notice", - "bin/bin1.meta_lic lib/libc.a.meta_lic lib/libc.a.meta_lic notice", - "bin/bin2.meta_lic bin/bin2.meta_lic bin/bin2.meta_lic notice", - "highest.apex.meta_lic bin/bin1.meta_lic bin/bin1.meta_lic notice", - "highest.apex.meta_lic bin/bin2.meta_lic bin/bin2.meta_lic notice", - "highest.apex.meta_lic highest.apex.meta_lic highest.apex.meta_lic notice", - "highest.apex.meta_lic lib/liba.so.meta_lic lib/liba.so.meta_lic notice", - "highest.apex.meta_lic lib/libb.so.meta_lic lib/libb.so.meta_lic notice", - "highest.apex.meta_lic lib/libc.a.meta_lic lib/libc.a.meta_lic notice", - "lib/liba.so.meta_lic lib/liba.so.meta_lic lib/liba.so.meta_lic notice", - "lib/libb.so.meta_lic lib/libb.so.meta_lic lib/libb.so.meta_lic notice", - "lib/libc.a.meta_lic lib/libc.a.meta_lic lib/libc.a.meta_lic notice", - "lib/libd.so.meta_lic lib/libd.so.meta_lic lib/libd.so.meta_lic notice", + "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", }, }, { @@ -248,22 +232,22 @@ func Test_plaintext(t *testing.T) { name: "apex_trimmed_notice", roots: []string{"highest.apex.meta_lic"}, ctx: context{ - conditions: []string{"notice"}, + conditions: []compliance.LicenseCondition{compliance.NoticeCondition}, stripPrefix: "testdata/notice/", }, expectedOut: []string{ - "bin/bin1.meta_lic bin/bin1.meta_lic bin/bin1.meta_lic notice", - "bin/bin1.meta_lic lib/liba.so.meta_lic lib/liba.so.meta_lic notice", - "bin/bin1.meta_lic lib/libc.a.meta_lic lib/libc.a.meta_lic notice", - "bin/bin2.meta_lic bin/bin2.meta_lic bin/bin2.meta_lic notice", - "highest.apex.meta_lic bin/bin1.meta_lic bin/bin1.meta_lic notice", - "highest.apex.meta_lic bin/bin2.meta_lic bin/bin2.meta_lic notice", - "highest.apex.meta_lic highest.apex.meta_lic highest.apex.meta_lic notice", - "highest.apex.meta_lic lib/liba.so.meta_lic lib/liba.so.meta_lic notice", - "highest.apex.meta_lic lib/libb.so.meta_lic lib/libb.so.meta_lic notice", - "highest.apex.meta_lic lib/libc.a.meta_lic lib/libc.a.meta_lic notice", - "lib/liba.so.meta_lic lib/liba.so.meta_lic lib/liba.so.meta_lic notice", - "lib/libb.so.meta_lic lib/libb.so.meta_lic lib/libb.so.meta_lic notice", + "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", }, }, { @@ -271,7 +255,7 @@ func Test_plaintext(t *testing.T) { name: "apex_trimmed_share", roots: []string{"highest.apex.meta_lic"}, ctx: context{ - conditions: []string{"reciprocal", "restricted"}, + conditions: compliance.ImpliesShared.AsList(), stripPrefix: "testdata/notice/", }, expectedOut: []string{}, @@ -281,7 +265,7 @@ func Test_plaintext(t *testing.T) { name: "apex_trimmed_private", roots: []string{"highest.apex.meta_lic"}, ctx: context{ - conditions: []string{"proprietary"}, + conditions: compliance.ImpliesPrivate.AsList(), stripPrefix: "testdata/notice/", }, expectedOut: []string{}, @@ -291,7 +275,7 @@ func Test_plaintext(t *testing.T) { name: "apex_trimmed_share_private", roots: []string{"highest.apex.meta_lic"}, ctx: context{ - conditions: []string{"reciprocal", "restricted", "proprietary"}, + conditions: append(compliance.ImpliesShared.AsList(),compliance.ImpliesPrivate.AsList()...), stripPrefix: "testdata/notice/", }, expectedOut: []string{}, @@ -302,20 +286,18 @@ func Test_plaintext(t *testing.T) { 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 bin/bin1.meta_lic:notice notice", - "bin/bin1.meta_lic:notice lib/liba.so.meta_lic:notice lib/liba.so.meta_lic:notice notice", - "bin/bin1.meta_lic:notice lib/libc.a.meta_lic:notice lib/libc.a.meta_lic:notice notice", - "bin/bin2.meta_lic:notice bin/bin2.meta_lic:notice bin/bin2.meta_lic:notice notice", - "highest.apex.meta_lic:notice bin/bin1.meta_lic:notice bin/bin1.meta_lic:notice notice", - "highest.apex.meta_lic:notice bin/bin2.meta_lic:notice bin/bin2.meta_lic:notice notice", - "highest.apex.meta_lic:notice highest.apex.meta_lic:notice highest.apex.meta_lic:notice notice", - "highest.apex.meta_lic:notice lib/liba.so.meta_lic:notice lib/liba.so.meta_lic:notice notice", - "highest.apex.meta_lic:notice lib/libb.so.meta_lic:notice lib/libb.so.meta_lic:notice notice", - "highest.apex.meta_lic:notice lib/libc.a.meta_lic:notice lib/libc.a.meta_lic:notice notice", - "lib/liba.so.meta_lic: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 lib/libb.so.meta_lic:notice notice", - "lib/libc.a.meta_lic:notice lib/libc.a.meta_lic:notice lib/libc.a.meta_lic:notice notice", - "lib/libd.so.meta_lic:notice lib/libd.so.meta_lic:notice lib/libd.so.meta_lic:notice notice", + "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", }, }, { @@ -323,20 +305,18 @@ func Test_plaintext(t *testing.T) { name: "container", roots: []string{"container.zip.meta_lic"}, expectedOut: []string{ - "testdata/notice/bin/bin1.meta_lic 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 testdata/notice/lib/liba.so.meta_lic notice", - "testdata/notice/bin/bin1.meta_lic testdata/notice/lib/libc.a.meta_lic testdata/notice/lib/libc.a.meta_lic notice", - "testdata/notice/bin/bin2.meta_lic 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 testdata/notice/bin/bin1.meta_lic notice", - "testdata/notice/container.zip.meta_lic testdata/notice/bin/bin2.meta_lic testdata/notice/bin/bin2.meta_lic notice", - "testdata/notice/container.zip.meta_lic 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 testdata/notice/lib/liba.so.meta_lic notice", - "testdata/notice/container.zip.meta_lic testdata/notice/lib/libb.so.meta_lic testdata/notice/lib/libb.so.meta_lic notice", - "testdata/notice/container.zip.meta_lic testdata/notice/lib/libc.a.meta_lic testdata/notice/lib/libc.a.meta_lic notice", - "testdata/notice/lib/liba.so.meta_lic 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 testdata/notice/lib/libb.so.meta_lic notice", - "testdata/notice/lib/libc.a.meta_lic testdata/notice/lib/libc.a.meta_lic testdata/notice/lib/libc.a.meta_lic notice", - "testdata/notice/lib/libd.so.meta_lic testdata/notice/lib/libd.so.meta_lic testdata/notice/lib/libd.so.meta_lic notice", + "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", }, }, { @@ -344,11 +324,8 @@ func Test_plaintext(t *testing.T) { name: "application", roots: []string{"application.meta_lic"}, expectedOut: []string{ - "testdata/notice/application.meta_lic testdata/notice/application.meta_lic testdata/notice/application.meta_lic notice", - "testdata/notice/application.meta_lic testdata/notice/lib/liba.so.meta_lic testdata/notice/lib/liba.so.meta_lic notice", - "testdata/notice/bin/bin3.meta_lic testdata/notice/bin/bin3.meta_lic testdata/notice/bin/bin3.meta_lic notice", - "testdata/notice/lib/liba.so.meta_lic 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 testdata/notice/lib/libb.so.meta_lic notice", + "testdata/notice/application.meta_lic testdata/notice/application.meta_lic notice", + "testdata/notice/application.meta_lic testdata/notice/lib/liba.so.meta_lic notice", }, }, { @@ -356,11 +333,9 @@ func Test_plaintext(t *testing.T) { name: "binary", roots: []string{"bin/bin1.meta_lic"}, expectedOut: []string{ - "testdata/notice/bin/bin1.meta_lic 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 testdata/notice/lib/liba.so.meta_lic notice", - "testdata/notice/bin/bin1.meta_lic testdata/notice/lib/libc.a.meta_lic testdata/notice/lib/libc.a.meta_lic notice", - "testdata/notice/lib/liba.so.meta_lic testdata/notice/lib/liba.so.meta_lic testdata/notice/lib/liba.so.meta_lic notice", - "testdata/notice/lib/libc.a.meta_lic testdata/notice/lib/libc.a.meta_lic testdata/notice/lib/libc.a.meta_lic notice", + "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", }, }, { @@ -368,7 +343,7 @@ func Test_plaintext(t *testing.T) { 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 testdata/notice/lib/libd.so.meta_lic notice", + "testdata/notice/lib/libd.so.meta_lic testdata/notice/lib/libd.so.meta_lic notice", }, }, { @@ -376,20 +351,18 @@ func Test_plaintext(t *testing.T) { name: "apex", roots: []string{"highest.apex.meta_lic"}, expectedOut: []string{ - "testdata/reciprocal/bin/bin1.meta_lic 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 testdata/reciprocal/lib/liba.so.meta_lic reciprocal", - "testdata/reciprocal/bin/bin1.meta_lic testdata/reciprocal/lib/libc.a.meta_lic testdata/reciprocal/lib/libc.a.meta_lic reciprocal", - "testdata/reciprocal/bin/bin2.meta_lic 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 testdata/reciprocal/bin/bin1.meta_lic notice", - "testdata/reciprocal/highest.apex.meta_lic testdata/reciprocal/bin/bin2.meta_lic testdata/reciprocal/bin/bin2.meta_lic notice", - "testdata/reciprocal/highest.apex.meta_lic 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 testdata/reciprocal/lib/liba.so.meta_lic reciprocal", - "testdata/reciprocal/highest.apex.meta_lic testdata/reciprocal/lib/libb.so.meta_lic testdata/reciprocal/lib/libb.so.meta_lic notice", - "testdata/reciprocal/highest.apex.meta_lic testdata/reciprocal/lib/libc.a.meta_lic testdata/reciprocal/lib/libc.a.meta_lic reciprocal", - "testdata/reciprocal/lib/liba.so.meta_lic 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 testdata/reciprocal/lib/libb.so.meta_lic notice", - "testdata/reciprocal/lib/libc.a.meta_lic testdata/reciprocal/lib/libc.a.meta_lic testdata/reciprocal/lib/libc.a.meta_lic reciprocal", - "testdata/reciprocal/lib/libd.so.meta_lic testdata/reciprocal/lib/libd.so.meta_lic testdata/reciprocal/lib/libd.so.meta_lic notice", + "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", }, }, { @@ -398,20 +371,18 @@ func Test_plaintext(t *testing.T) { roots: []string{"highest.apex.meta_lic"}, ctx: context{stripPrefix: "testdata/reciprocal/"}, expectedOut: []string{ - "bin/bin1.meta_lic bin/bin1.meta_lic bin/bin1.meta_lic notice", - "bin/bin1.meta_lic lib/liba.so.meta_lic lib/liba.so.meta_lic reciprocal", - "bin/bin1.meta_lic lib/libc.a.meta_lic lib/libc.a.meta_lic reciprocal", - "bin/bin2.meta_lic bin/bin2.meta_lic bin/bin2.meta_lic notice", - "highest.apex.meta_lic bin/bin1.meta_lic bin/bin1.meta_lic notice", - "highest.apex.meta_lic bin/bin2.meta_lic bin/bin2.meta_lic notice", - "highest.apex.meta_lic highest.apex.meta_lic highest.apex.meta_lic notice", - "highest.apex.meta_lic lib/liba.so.meta_lic lib/liba.so.meta_lic reciprocal", - "highest.apex.meta_lic lib/libb.so.meta_lic lib/libb.so.meta_lic notice", - "highest.apex.meta_lic lib/libc.a.meta_lic lib/libc.a.meta_lic reciprocal", - "lib/liba.so.meta_lic lib/liba.so.meta_lic lib/liba.so.meta_lic reciprocal", - "lib/libb.so.meta_lic lib/libb.so.meta_lic lib/libb.so.meta_lic notice", - "lib/libc.a.meta_lic lib/libc.a.meta_lic lib/libc.a.meta_lic reciprocal", - "lib/libd.so.meta_lic lib/libd.so.meta_lic lib/libd.so.meta_lic notice", + "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", }, }, { @@ -419,17 +390,17 @@ func Test_plaintext(t *testing.T) { name: "apex_trimmed_notice", roots: []string{"highest.apex.meta_lic"}, ctx: context{ - conditions: []string{"notice"}, + conditions: []compliance.LicenseCondition{compliance.NoticeCondition}, stripPrefix: "testdata/reciprocal/", }, expectedOut: []string{ - "bin/bin1.meta_lic bin/bin1.meta_lic bin/bin1.meta_lic notice", - "bin/bin2.meta_lic bin/bin2.meta_lic bin/bin2.meta_lic notice", - "highest.apex.meta_lic bin/bin1.meta_lic bin/bin1.meta_lic notice", - "highest.apex.meta_lic bin/bin2.meta_lic bin/bin2.meta_lic notice", - "highest.apex.meta_lic highest.apex.meta_lic highest.apex.meta_lic notice", - "highest.apex.meta_lic lib/libb.so.meta_lic lib/libb.so.meta_lic notice", - "lib/libb.so.meta_lic lib/libb.so.meta_lic lib/libb.so.meta_lic notice", + "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", }, }, { @@ -437,15 +408,15 @@ func Test_plaintext(t *testing.T) { name: "apex_trimmed_share", roots: []string{"highest.apex.meta_lic"}, ctx: context{ - conditions: []string{"reciprocal", "restricted"}, + conditions: compliance.ImpliesShared.AsList(), stripPrefix: "testdata/reciprocal/", }, expectedOut: []string{ - "bin/bin1.meta_lic lib/liba.so.meta_lic lib/liba.so.meta_lic reciprocal", - "bin/bin1.meta_lic lib/libc.a.meta_lic lib/libc.a.meta_lic reciprocal", - "highest.apex.meta_lic lib/liba.so.meta_lic lib/liba.so.meta_lic reciprocal", - "highest.apex.meta_lic lib/libc.a.meta_lic lib/libc.a.meta_lic reciprocal", - "lib/liba.so.meta_lic lib/liba.so.meta_lic lib/liba.so.meta_lic reciprocal", + "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", }, }, { @@ -453,7 +424,7 @@ func Test_plaintext(t *testing.T) { name: "apex_trimmed_private", roots: []string{"highest.apex.meta_lic"}, ctx: context{ - conditions: []string{"proprietary"}, + conditions: compliance.ImpliesPrivate.AsList(), stripPrefix: "testdata/reciprocal/", }, expectedOut: []string{}, @@ -463,15 +434,15 @@ func Test_plaintext(t *testing.T) { name: "apex_trimmed_share_private", roots: []string{"highest.apex.meta_lic"}, ctx: context{ - conditions: []string{"reciprocal", "restricted", "proprietary"}, + conditions: append(compliance.ImpliesShared.AsList(),compliance.ImpliesPrivate.AsList()...), stripPrefix: "testdata/reciprocal/", }, expectedOut: []string{ - "bin/bin1.meta_lic lib/liba.so.meta_lic lib/liba.so.meta_lic reciprocal", - "bin/bin1.meta_lic lib/libc.a.meta_lic lib/libc.a.meta_lic reciprocal", - "highest.apex.meta_lic lib/liba.so.meta_lic lib/liba.so.meta_lic reciprocal", - "highest.apex.meta_lic lib/libc.a.meta_lic lib/libc.a.meta_lic reciprocal", - "lib/liba.so.meta_lic lib/liba.so.meta_lic lib/liba.so.meta_lic reciprocal", + "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", }, }, { @@ -480,20 +451,18 @@ func Test_plaintext(t *testing.T) { 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 bin/bin1.meta_lic:notice notice", - "bin/bin1.meta_lic:notice lib/liba.so.meta_lic:reciprocal lib/liba.so.meta_lic:reciprocal reciprocal", - "bin/bin1.meta_lic:notice lib/libc.a.meta_lic:reciprocal lib/libc.a.meta_lic:reciprocal reciprocal", - "bin/bin2.meta_lic:notice bin/bin2.meta_lic:notice bin/bin2.meta_lic:notice notice", - "highest.apex.meta_lic:notice bin/bin1.meta_lic:notice bin/bin1.meta_lic:notice notice", - "highest.apex.meta_lic:notice bin/bin2.meta_lic:notice bin/bin2.meta_lic:notice notice", - "highest.apex.meta_lic:notice highest.apex.meta_lic:notice highest.apex.meta_lic:notice notice", - "highest.apex.meta_lic:notice lib/liba.so.meta_lic:reciprocal lib/liba.so.meta_lic:reciprocal reciprocal", - "highest.apex.meta_lic:notice lib/libb.so.meta_lic:notice lib/libb.so.meta_lic:notice notice", - "highest.apex.meta_lic:notice lib/libc.a.meta_lic:reciprocal lib/libc.a.meta_lic:reciprocal reciprocal", - "lib/liba.so.meta_lic: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 lib/libb.so.meta_lic:notice notice", - "lib/libc.a.meta_lic:reciprocal lib/libc.a.meta_lic:reciprocal lib/libc.a.meta_lic:reciprocal reciprocal", - "lib/libd.so.meta_lic:notice lib/libd.so.meta_lic:notice lib/libd.so.meta_lic:notice notice", + "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", }, }, { @@ -501,20 +470,18 @@ func Test_plaintext(t *testing.T) { name: "container", roots: []string{"container.zip.meta_lic"}, expectedOut: []string{ - "testdata/reciprocal/bin/bin1.meta_lic 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 testdata/reciprocal/lib/liba.so.meta_lic reciprocal", - "testdata/reciprocal/bin/bin1.meta_lic testdata/reciprocal/lib/libc.a.meta_lic testdata/reciprocal/lib/libc.a.meta_lic reciprocal", - "testdata/reciprocal/bin/bin2.meta_lic 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 testdata/reciprocal/bin/bin1.meta_lic notice", - "testdata/reciprocal/container.zip.meta_lic testdata/reciprocal/bin/bin2.meta_lic testdata/reciprocal/bin/bin2.meta_lic notice", - "testdata/reciprocal/container.zip.meta_lic 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 testdata/reciprocal/lib/liba.so.meta_lic reciprocal", - "testdata/reciprocal/container.zip.meta_lic testdata/reciprocal/lib/libb.so.meta_lic testdata/reciprocal/lib/libb.so.meta_lic notice", - "testdata/reciprocal/container.zip.meta_lic testdata/reciprocal/lib/libc.a.meta_lic testdata/reciprocal/lib/libc.a.meta_lic reciprocal", - "testdata/reciprocal/lib/liba.so.meta_lic 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 testdata/reciprocal/lib/libb.so.meta_lic notice", - "testdata/reciprocal/lib/libc.a.meta_lic testdata/reciprocal/lib/libc.a.meta_lic testdata/reciprocal/lib/libc.a.meta_lic reciprocal", - "testdata/reciprocal/lib/libd.so.meta_lic testdata/reciprocal/lib/libd.so.meta_lic testdata/reciprocal/lib/libd.so.meta_lic notice", + "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", }, }, { @@ -522,11 +489,8 @@ func Test_plaintext(t *testing.T) { name: "application", roots: []string{"application.meta_lic"}, expectedOut: []string{ - "testdata/reciprocal/application.meta_lic testdata/reciprocal/application.meta_lic testdata/reciprocal/application.meta_lic notice", - "testdata/reciprocal/application.meta_lic testdata/reciprocal/lib/liba.so.meta_lic testdata/reciprocal/lib/liba.so.meta_lic reciprocal", - "testdata/reciprocal/bin/bin3.meta_lic testdata/reciprocal/bin/bin3.meta_lic testdata/reciprocal/bin/bin3.meta_lic notice", - "testdata/reciprocal/lib/liba.so.meta_lic 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 testdata/reciprocal/lib/libb.so.meta_lic notice", + "testdata/reciprocal/application.meta_lic testdata/reciprocal/application.meta_lic notice", + "testdata/reciprocal/application.meta_lic testdata/reciprocal/lib/liba.so.meta_lic reciprocal", }, }, { @@ -534,11 +498,9 @@ func Test_plaintext(t *testing.T) { name: "binary", roots: []string{"bin/bin1.meta_lic"}, expectedOut: []string{ - "testdata/reciprocal/bin/bin1.meta_lic 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 testdata/reciprocal/lib/liba.so.meta_lic reciprocal", - "testdata/reciprocal/bin/bin1.meta_lic testdata/reciprocal/lib/libc.a.meta_lic testdata/reciprocal/lib/libc.a.meta_lic reciprocal", - "testdata/reciprocal/lib/liba.so.meta_lic testdata/reciprocal/lib/liba.so.meta_lic testdata/reciprocal/lib/liba.so.meta_lic reciprocal", - "testdata/reciprocal/lib/libc.a.meta_lic testdata/reciprocal/lib/libc.a.meta_lic testdata/reciprocal/lib/libc.a.meta_lic reciprocal", + "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", }, }, { @@ -546,7 +508,7 @@ func Test_plaintext(t *testing.T) { 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 testdata/reciprocal/lib/libd.so.meta_lic notice", + "testdata/reciprocal/lib/libd.so.meta_lic testdata/reciprocal/lib/libd.so.meta_lic notice", }, }, { @@ -554,33 +516,19 @@ func Test_plaintext(t *testing.T) { name: "apex", roots: []string{"highest.apex.meta_lic"}, expectedOut: []string{ - "testdata/restricted/bin/bin1.meta_lic testdata/restricted/bin/bin1.meta_lic testdata/restricted/bin/bin1.meta_lic notice", - "testdata/restricted/bin/bin1.meta_lic testdata/restricted/bin/bin1.meta_lic testdata/restricted/lib/liba.so.meta_lic restricted", - "testdata/restricted/bin/bin1.meta_lic testdata/restricted/lib/liba.so.meta_lic testdata/restricted/lib/liba.so.meta_lic restricted", - "testdata/restricted/bin/bin1.meta_lic testdata/restricted/lib/libc.a.meta_lic testdata/restricted/lib/liba.so.meta_lic restricted", - "testdata/restricted/bin/bin1.meta_lic testdata/restricted/lib/libc.a.meta_lic testdata/restricted/lib/libc.a.meta_lic reciprocal", - "testdata/restricted/bin/bin2.meta_lic testdata/restricted/bin/bin2.meta_lic testdata/restricted/bin/bin2.meta_lic notice", - "testdata/restricted/bin/bin2.meta_lic testdata/restricted/bin/bin2.meta_lic testdata/restricted/lib/libb.so.meta_lic restricted", - "testdata/restricted/bin/bin2.meta_lic testdata/restricted/lib/libb.so.meta_lic testdata/restricted/lib/libb.so.meta_lic restricted", - "testdata/restricted/bin/bin2.meta_lic testdata/restricted/lib/libd.so.meta_lic testdata/restricted/lib/libb.so.meta_lic restricted", - "testdata/restricted/highest.apex.meta_lic testdata/restricted/bin/bin1.meta_lic testdata/restricted/bin/bin1.meta_lic notice", - "testdata/restricted/highest.apex.meta_lic testdata/restricted/bin/bin1.meta_lic testdata/restricted/lib/liba.so.meta_lic restricted", - "testdata/restricted/highest.apex.meta_lic testdata/restricted/bin/bin2.meta_lic testdata/restricted/bin/bin2.meta_lic notice", - "testdata/restricted/highest.apex.meta_lic testdata/restricted/bin/bin2.meta_lic testdata/restricted/lib/libb.so.meta_lic restricted", - "testdata/restricted/highest.apex.meta_lic testdata/restricted/highest.apex.meta_lic testdata/restricted/highest.apex.meta_lic notice", - "testdata/restricted/highest.apex.meta_lic testdata/restricted/highest.apex.meta_lic testdata/restricted/lib/liba.so.meta_lic restricted", - "testdata/restricted/highest.apex.meta_lic testdata/restricted/highest.apex.meta_lic testdata/restricted/lib/libb.so.meta_lic restricted", - "testdata/restricted/highest.apex.meta_lic testdata/restricted/lib/liba.so.meta_lic testdata/restricted/lib/liba.so.meta_lic restricted", - "testdata/restricted/highest.apex.meta_lic testdata/restricted/lib/libb.so.meta_lic testdata/restricted/lib/libb.so.meta_lic restricted", - "testdata/restricted/highest.apex.meta_lic testdata/restricted/lib/libc.a.meta_lic testdata/restricted/lib/liba.so.meta_lic restricted", - "testdata/restricted/highest.apex.meta_lic testdata/restricted/lib/libc.a.meta_lic testdata/restricted/lib/libc.a.meta_lic reciprocal", - "testdata/restricted/highest.apex.meta_lic testdata/restricted/lib/libd.so.meta_lic testdata/restricted/lib/libb.so.meta_lic restricted", - "testdata/restricted/lib/liba.so.meta_lic testdata/restricted/lib/liba.so.meta_lic testdata/restricted/lib/liba.so.meta_lic restricted", - "testdata/restricted/lib/libb.so.meta_lic testdata/restricted/lib/libb.so.meta_lic testdata/restricted/lib/libb.so.meta_lic restricted", - "testdata/restricted/lib/libc.a.meta_lic testdata/restricted/lib/libc.a.meta_lic testdata/restricted/lib/liba.so.meta_lic restricted", - "testdata/restricted/lib/libc.a.meta_lic testdata/restricted/lib/libc.a.meta_lic testdata/restricted/lib/libc.a.meta_lic reciprocal", - "testdata/restricted/lib/libd.so.meta_lic testdata/restricted/lib/libd.so.meta_lic testdata/restricted/lib/libb.so.meta_lic restricted", - "testdata/restricted/lib/libd.so.meta_lic testdata/restricted/lib/libd.so.meta_lic testdata/restricted/lib/libd.so.meta_lic notice", + "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", }, }, { @@ -589,33 +537,19 @@ func Test_plaintext(t *testing.T) { roots: []string{"highest.apex.meta_lic"}, ctx: context{stripPrefix: "testdata/restricted/"}, expectedOut: []string{ - "bin/bin1.meta_lic bin/bin1.meta_lic bin/bin1.meta_lic notice", - "bin/bin1.meta_lic bin/bin1.meta_lic lib/liba.so.meta_lic restricted", - "bin/bin1.meta_lic lib/liba.so.meta_lic lib/liba.so.meta_lic restricted", - "bin/bin1.meta_lic lib/libc.a.meta_lic lib/liba.so.meta_lic restricted", - "bin/bin1.meta_lic lib/libc.a.meta_lic lib/libc.a.meta_lic reciprocal", - "bin/bin2.meta_lic bin/bin2.meta_lic bin/bin2.meta_lic notice", - "bin/bin2.meta_lic bin/bin2.meta_lic lib/libb.so.meta_lic restricted", - "bin/bin2.meta_lic lib/libb.so.meta_lic lib/libb.so.meta_lic restricted", - "bin/bin2.meta_lic lib/libd.so.meta_lic lib/libb.so.meta_lic restricted", - "highest.apex.meta_lic bin/bin1.meta_lic bin/bin1.meta_lic notice", - "highest.apex.meta_lic bin/bin1.meta_lic lib/liba.so.meta_lic restricted", - "highest.apex.meta_lic bin/bin2.meta_lic bin/bin2.meta_lic notice", - "highest.apex.meta_lic bin/bin2.meta_lic lib/libb.so.meta_lic restricted", - "highest.apex.meta_lic highest.apex.meta_lic highest.apex.meta_lic notice", - "highest.apex.meta_lic highest.apex.meta_lic lib/liba.so.meta_lic restricted", - "highest.apex.meta_lic highest.apex.meta_lic lib/libb.so.meta_lic restricted", - "highest.apex.meta_lic lib/liba.so.meta_lic lib/liba.so.meta_lic restricted", - "highest.apex.meta_lic lib/libb.so.meta_lic lib/libb.so.meta_lic restricted", - "highest.apex.meta_lic lib/libc.a.meta_lic lib/liba.so.meta_lic restricted", - "highest.apex.meta_lic lib/libc.a.meta_lic lib/libc.a.meta_lic reciprocal", - "highest.apex.meta_lic lib/libd.so.meta_lic lib/libb.so.meta_lic restricted", - "lib/liba.so.meta_lic lib/liba.so.meta_lic lib/liba.so.meta_lic restricted", - "lib/libb.so.meta_lic lib/libb.so.meta_lic lib/libb.so.meta_lic restricted", - "lib/libc.a.meta_lic lib/libc.a.meta_lic lib/liba.so.meta_lic restricted", - "lib/libc.a.meta_lic lib/libc.a.meta_lic lib/libc.a.meta_lic reciprocal", - "lib/libd.so.meta_lic lib/libd.so.meta_lic lib/libb.so.meta_lic restricted", - "lib/libd.so.meta_lic lib/libd.so.meta_lic lib/libd.so.meta_lic notice", + "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", }, }, { @@ -623,15 +557,15 @@ func Test_plaintext(t *testing.T) { name: "apex_trimmed_notice", roots: []string{"highest.apex.meta_lic"}, ctx: context{ - conditions: []string{"notice"}, + conditions: []compliance.LicenseCondition{compliance.NoticeCondition}, stripPrefix: "testdata/restricted/", }, expectedOut: []string{ - "bin/bin1.meta_lic bin/bin1.meta_lic bin/bin1.meta_lic notice", - "bin/bin2.meta_lic bin/bin2.meta_lic bin/bin2.meta_lic notice", - "highest.apex.meta_lic bin/bin1.meta_lic bin/bin1.meta_lic notice", - "highest.apex.meta_lic bin/bin2.meta_lic bin/bin2.meta_lic notice", - "highest.apex.meta_lic highest.apex.meta_lic highest.apex.meta_lic notice", + "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", }, }, { @@ -639,26 +573,23 @@ func Test_plaintext(t *testing.T) { name: "apex_trimmed_share", roots: []string{"highest.apex.meta_lic"}, ctx: context{ - conditions: []string{"reciprocal", "restricted"}, + conditions: compliance.ImpliesShared.AsList(), stripPrefix: "testdata/restricted/", }, expectedOut: []string{ - "bin/bin1.meta_lic bin/bin1.meta_lic lib/liba.so.meta_lic restricted", - "bin/bin1.meta_lic lib/liba.so.meta_lic lib/liba.so.meta_lic restricted", - "bin/bin1.meta_lic lib/libc.a.meta_lic lib/liba.so.meta_lic restricted", - "bin/bin1.meta_lic lib/libc.a.meta_lic lib/libc.a.meta_lic reciprocal", - "bin/bin2.meta_lic bin/bin2.meta_lic lib/libb.so.meta_lic restricted", - "bin/bin2.meta_lic lib/libb.so.meta_lic lib/libb.so.meta_lic restricted", - "highest.apex.meta_lic bin/bin1.meta_lic lib/liba.so.meta_lic restricted", - "highest.apex.meta_lic bin/bin2.meta_lic lib/libb.so.meta_lic restricted", - "highest.apex.meta_lic highest.apex.meta_lic lib/liba.so.meta_lic restricted", - "highest.apex.meta_lic highest.apex.meta_lic lib/libb.so.meta_lic restricted", - "highest.apex.meta_lic lib/liba.so.meta_lic lib/liba.so.meta_lic restricted", - "highest.apex.meta_lic lib/libb.so.meta_lic lib/libb.so.meta_lic restricted", - "highest.apex.meta_lic lib/libc.a.meta_lic lib/liba.so.meta_lic restricted", - "highest.apex.meta_lic lib/libc.a.meta_lic lib/libc.a.meta_lic reciprocal", - "lib/liba.so.meta_lic lib/liba.so.meta_lic lib/liba.so.meta_lic restricted", - "lib/libb.so.meta_lic lib/libb.so.meta_lic lib/libb.so.meta_lic restricted", + "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", }, }, { @@ -666,7 +597,7 @@ func Test_plaintext(t *testing.T) { name: "apex_trimmed_private", roots: []string{"highest.apex.meta_lic"}, ctx: context{ - conditions: []string{"proprietary"}, + conditions: compliance.ImpliesPrivate.AsList(), stripPrefix: "testdata/restricted/", }, expectedOut: []string{}, @@ -676,26 +607,23 @@ func Test_plaintext(t *testing.T) { name: "apex_trimmed_share_private", roots: []string{"highest.apex.meta_lic"}, ctx: context{ - conditions: []string{"reciprocal", "restricted", "proprietary"}, + conditions: append(compliance.ImpliesShared.AsList(),compliance.ImpliesPrivate.AsList()...), stripPrefix: "testdata/restricted/", }, expectedOut: []string{ - "bin/bin1.meta_lic bin/bin1.meta_lic lib/liba.so.meta_lic restricted", - "bin/bin1.meta_lic lib/liba.so.meta_lic lib/liba.so.meta_lic restricted", - "bin/bin1.meta_lic lib/libc.a.meta_lic lib/liba.so.meta_lic restricted", - "bin/bin1.meta_lic lib/libc.a.meta_lic lib/libc.a.meta_lic reciprocal", - "bin/bin2.meta_lic bin/bin2.meta_lic lib/libb.so.meta_lic restricted", - "bin/bin2.meta_lic lib/libb.so.meta_lic lib/libb.so.meta_lic restricted", - "highest.apex.meta_lic bin/bin1.meta_lic lib/liba.so.meta_lic restricted", - "highest.apex.meta_lic bin/bin2.meta_lic lib/libb.so.meta_lic restricted", - "highest.apex.meta_lic highest.apex.meta_lic lib/liba.so.meta_lic restricted", - "highest.apex.meta_lic highest.apex.meta_lic lib/libb.so.meta_lic restricted", - "highest.apex.meta_lic lib/liba.so.meta_lic lib/liba.so.meta_lic restricted", - "highest.apex.meta_lic lib/libb.so.meta_lic lib/libb.so.meta_lic restricted", - "highest.apex.meta_lic lib/libc.a.meta_lic lib/liba.so.meta_lic restricted", - "highest.apex.meta_lic lib/libc.a.meta_lic lib/libc.a.meta_lic reciprocal", - "lib/liba.so.meta_lic lib/liba.so.meta_lic lib/liba.so.meta_lic restricted", - "lib/libb.so.meta_lic lib/libb.so.meta_lic lib/libb.so.meta_lic restricted", + "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", }, }, { @@ -704,33 +632,19 @@ func Test_plaintext(t *testing.T) { 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 bin/bin1.meta_lic:notice notice", - "bin/bin1.meta_lic:notice bin/bin1.meta_lic:notice lib/liba.so.meta_lic:restricted restricted", - "bin/bin1.meta_lic:notice lib/liba.so.meta_lic:restricted lib/liba.so.meta_lic:restricted restricted", - "bin/bin1.meta_lic:notice lib/libc.a.meta_lic:reciprocal lib/liba.so.meta_lic:restricted restricted", - "bin/bin1.meta_lic:notice lib/libc.a.meta_lic:reciprocal lib/libc.a.meta_lic:reciprocal reciprocal", - "bin/bin2.meta_lic:notice bin/bin2.meta_lic:notice bin/bin2.meta_lic:notice notice", - "bin/bin2.meta_lic:notice bin/bin2.meta_lic:notice lib/libb.so.meta_lic:restricted restricted", - "bin/bin2.meta_lic:notice lib/libb.so.meta_lic:restricted lib/libb.so.meta_lic:restricted restricted", - "bin/bin2.meta_lic:notice lib/libd.so.meta_lic:notice lib/libb.so.meta_lic:restricted restricted", - "highest.apex.meta_lic:notice bin/bin1.meta_lic:notice bin/bin1.meta_lic:notice notice", - "highest.apex.meta_lic:notice bin/bin1.meta_lic:notice lib/liba.so.meta_lic:restricted restricted", - "highest.apex.meta_lic:notice bin/bin2.meta_lic:notice bin/bin2.meta_lic:notice notice", - "highest.apex.meta_lic:notice bin/bin2.meta_lic:notice lib/libb.so.meta_lic:restricted restricted", - "highest.apex.meta_lic:notice highest.apex.meta_lic:notice highest.apex.meta_lic:notice notice", - "highest.apex.meta_lic:notice highest.apex.meta_lic:notice lib/liba.so.meta_lic:restricted restricted", - "highest.apex.meta_lic:notice highest.apex.meta_lic:notice lib/libb.so.meta_lic:restricted restricted", - "highest.apex.meta_lic:notice lib/liba.so.meta_lic:restricted lib/liba.so.meta_lic:restricted restricted", - "highest.apex.meta_lic:notice lib/libb.so.meta_lic:restricted lib/libb.so.meta_lic:restricted restricted", - "highest.apex.meta_lic:notice lib/libc.a.meta_lic:reciprocal lib/liba.so.meta_lic:restricted restricted", - "highest.apex.meta_lic:notice lib/libc.a.meta_lic:reciprocal lib/libc.a.meta_lic:reciprocal reciprocal", - "highest.apex.meta_lic:notice lib/libd.so.meta_lic:notice lib/libb.so.meta_lic:restricted restricted", - "lib/liba.so.meta_lic:restricted lib/liba.so.meta_lic:restricted lib/liba.so.meta_lic:restricted restricted", - "lib/libb.so.meta_lic:restricted lib/libb.so.meta_lic:restricted lib/libb.so.meta_lic:restricted restricted", - "lib/libc.a.meta_lic:reciprocal lib/libc.a.meta_lic:reciprocal lib/liba.so.meta_lic:restricted restricted", - "lib/libc.a.meta_lic:reciprocal lib/libc.a.meta_lic:reciprocal lib/libc.a.meta_lic:reciprocal reciprocal", - "lib/libd.so.meta_lic:notice lib/libd.so.meta_lic:notice lib/libb.so.meta_lic:restricted restricted", - "lib/libd.so.meta_lic:notice lib/libd.so.meta_lic:notice lib/libd.so.meta_lic:notice notice", + "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", }, }, { @@ -738,33 +652,19 @@ func Test_plaintext(t *testing.T) { name: "container", roots: []string{"container.zip.meta_lic"}, expectedOut: []string{ - "testdata/restricted/bin/bin1.meta_lic testdata/restricted/bin/bin1.meta_lic testdata/restricted/bin/bin1.meta_lic notice", - "testdata/restricted/bin/bin1.meta_lic testdata/restricted/bin/bin1.meta_lic testdata/restricted/lib/liba.so.meta_lic restricted", - "testdata/restricted/bin/bin1.meta_lic testdata/restricted/lib/liba.so.meta_lic testdata/restricted/lib/liba.so.meta_lic restricted", - "testdata/restricted/bin/bin1.meta_lic testdata/restricted/lib/libc.a.meta_lic testdata/restricted/lib/liba.so.meta_lic restricted", - "testdata/restricted/bin/bin1.meta_lic testdata/restricted/lib/libc.a.meta_lic testdata/restricted/lib/libc.a.meta_lic reciprocal", - "testdata/restricted/bin/bin2.meta_lic testdata/restricted/bin/bin2.meta_lic testdata/restricted/bin/bin2.meta_lic notice", - "testdata/restricted/bin/bin2.meta_lic testdata/restricted/bin/bin2.meta_lic testdata/restricted/lib/libb.so.meta_lic restricted", - "testdata/restricted/bin/bin2.meta_lic testdata/restricted/lib/libb.so.meta_lic testdata/restricted/lib/libb.so.meta_lic restricted", - "testdata/restricted/bin/bin2.meta_lic testdata/restricted/lib/libd.so.meta_lic testdata/restricted/lib/libb.so.meta_lic restricted", - "testdata/restricted/container.zip.meta_lic testdata/restricted/bin/bin1.meta_lic testdata/restricted/bin/bin1.meta_lic notice", - "testdata/restricted/container.zip.meta_lic testdata/restricted/bin/bin1.meta_lic testdata/restricted/lib/liba.so.meta_lic restricted", - "testdata/restricted/container.zip.meta_lic testdata/restricted/bin/bin2.meta_lic testdata/restricted/bin/bin2.meta_lic notice", - "testdata/restricted/container.zip.meta_lic testdata/restricted/bin/bin2.meta_lic testdata/restricted/lib/libb.so.meta_lic restricted", - "testdata/restricted/container.zip.meta_lic testdata/restricted/container.zip.meta_lic testdata/restricted/container.zip.meta_lic notice", - "testdata/restricted/container.zip.meta_lic testdata/restricted/container.zip.meta_lic testdata/restricted/lib/liba.so.meta_lic restricted", - "testdata/restricted/container.zip.meta_lic testdata/restricted/container.zip.meta_lic testdata/restricted/lib/libb.so.meta_lic restricted", - "testdata/restricted/container.zip.meta_lic testdata/restricted/lib/liba.so.meta_lic testdata/restricted/lib/liba.so.meta_lic restricted", - "testdata/restricted/container.zip.meta_lic testdata/restricted/lib/libb.so.meta_lic testdata/restricted/lib/libb.so.meta_lic restricted", - "testdata/restricted/container.zip.meta_lic testdata/restricted/lib/libc.a.meta_lic testdata/restricted/lib/liba.so.meta_lic restricted", - "testdata/restricted/container.zip.meta_lic testdata/restricted/lib/libc.a.meta_lic testdata/restricted/lib/libc.a.meta_lic reciprocal", - "testdata/restricted/container.zip.meta_lic testdata/restricted/lib/libd.so.meta_lic testdata/restricted/lib/libb.so.meta_lic restricted", - "testdata/restricted/lib/liba.so.meta_lic testdata/restricted/lib/liba.so.meta_lic testdata/restricted/lib/liba.so.meta_lic restricted", - "testdata/restricted/lib/libb.so.meta_lic testdata/restricted/lib/libb.so.meta_lic testdata/restricted/lib/libb.so.meta_lic restricted", - "testdata/restricted/lib/libc.a.meta_lic testdata/restricted/lib/libc.a.meta_lic testdata/restricted/lib/liba.so.meta_lic restricted", - "testdata/restricted/lib/libc.a.meta_lic testdata/restricted/lib/libc.a.meta_lic testdata/restricted/lib/libc.a.meta_lic reciprocal", - "testdata/restricted/lib/libd.so.meta_lic testdata/restricted/lib/libd.so.meta_lic testdata/restricted/lib/libb.so.meta_lic restricted", - "testdata/restricted/lib/libd.so.meta_lic testdata/restricted/lib/libd.so.meta_lic testdata/restricted/lib/libd.so.meta_lic notice", + "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", }, }, { @@ -772,16 +672,8 @@ func Test_plaintext(t *testing.T) { name: "application", roots: []string{"application.meta_lic"}, expectedOut: []string{ - "testdata/restricted/application.meta_lic testdata/restricted/application.meta_lic testdata/restricted/application.meta_lic notice", - "testdata/restricted/application.meta_lic testdata/restricted/application.meta_lic testdata/restricted/lib/liba.so.meta_lic restricted", - "testdata/restricted/application.meta_lic testdata/restricted/application.meta_lic testdata/restricted/lib/libb.so.meta_lic restricted", - "testdata/restricted/application.meta_lic testdata/restricted/lib/liba.so.meta_lic testdata/restricted/lib/liba.so.meta_lic restricted", - "testdata/restricted/application.meta_lic testdata/restricted/lib/liba.so.meta_lic testdata/restricted/lib/libb.so.meta_lic restricted", - "testdata/restricted/application.meta_lic testdata/restricted/lib/libb.so.meta_lic testdata/restricted/lib/libb.so.meta_lic restricted", - "testdata/restricted/bin/bin3.meta_lic testdata/restricted/bin/bin3.meta_lic testdata/restricted/bin/bin3.meta_lic restricted", - "testdata/restricted/lib/liba.so.meta_lic testdata/restricted/lib/liba.so.meta_lic testdata/restricted/lib/liba.so.meta_lic restricted", - "testdata/restricted/lib/liba.so.meta_lic testdata/restricted/lib/liba.so.meta_lic testdata/restricted/lib/libb.so.meta_lic restricted", - "testdata/restricted/lib/libb.so.meta_lic testdata/restricted/lib/libb.so.meta_lic testdata/restricted/lib/libb.so.meta_lic restricted", + "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", }, }, { @@ -789,14 +681,9 @@ func Test_plaintext(t *testing.T) { name: "binary", roots: []string{"bin/bin1.meta_lic"}, expectedOut: []string{ - "testdata/restricted/bin/bin1.meta_lic testdata/restricted/bin/bin1.meta_lic testdata/restricted/bin/bin1.meta_lic notice", - "testdata/restricted/bin/bin1.meta_lic testdata/restricted/bin/bin1.meta_lic testdata/restricted/lib/liba.so.meta_lic restricted", - "testdata/restricted/bin/bin1.meta_lic testdata/restricted/lib/liba.so.meta_lic testdata/restricted/lib/liba.so.meta_lic restricted", - "testdata/restricted/bin/bin1.meta_lic testdata/restricted/lib/libc.a.meta_lic testdata/restricted/lib/liba.so.meta_lic restricted", - "testdata/restricted/bin/bin1.meta_lic testdata/restricted/lib/libc.a.meta_lic testdata/restricted/lib/libc.a.meta_lic reciprocal", - "testdata/restricted/lib/liba.so.meta_lic testdata/restricted/lib/liba.so.meta_lic testdata/restricted/lib/liba.so.meta_lic restricted", - "testdata/restricted/lib/libc.a.meta_lic testdata/restricted/lib/libc.a.meta_lic testdata/restricted/lib/liba.so.meta_lic restricted", - "testdata/restricted/lib/libc.a.meta_lic testdata/restricted/lib/libc.a.meta_lic testdata/restricted/lib/libc.a.meta_lic reciprocal", + "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", }, }, { @@ -804,7 +691,7 @@ func Test_plaintext(t *testing.T) { 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 testdata/restricted/lib/libd.so.meta_lic notice", + "testdata/restricted/lib/libd.so.meta_lic testdata/restricted/lib/libd.so.meta_lic notice", }, }, { @@ -812,27 +699,19 @@ func Test_plaintext(t *testing.T) { name: "apex", roots: []string{"highest.apex.meta_lic"}, expectedOut: []string{ - "testdata/proprietary/bin/bin1.meta_lic 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 testdata/proprietary/lib/liba.so.meta_lic by_exception_only:proprietary", - "testdata/proprietary/bin/bin1.meta_lic testdata/proprietary/lib/libc.a.meta_lic testdata/proprietary/lib/libc.a.meta_lic by_exception_only:proprietary", - "testdata/proprietary/bin/bin2.meta_lic testdata/proprietary/bin/bin2.meta_lic testdata/proprietary/bin/bin2.meta_lic by_exception_only:proprietary", - "testdata/proprietary/bin/bin2.meta_lic testdata/proprietary/bin/bin2.meta_lic testdata/proprietary/lib/libb.so.meta_lic restricted", - "testdata/proprietary/bin/bin2.meta_lic testdata/proprietary/lib/libb.so.meta_lic testdata/proprietary/lib/libb.so.meta_lic restricted", - "testdata/proprietary/bin/bin2.meta_lic testdata/proprietary/lib/libd.so.meta_lic testdata/proprietary/lib/libb.so.meta_lic restricted", - "testdata/proprietary/highest.apex.meta_lic testdata/proprietary/bin/bin1.meta_lic testdata/proprietary/bin/bin1.meta_lic notice", - "testdata/proprietary/highest.apex.meta_lic testdata/proprietary/bin/bin2.meta_lic testdata/proprietary/bin/bin2.meta_lic by_exception_only:proprietary", - "testdata/proprietary/highest.apex.meta_lic testdata/proprietary/bin/bin2.meta_lic testdata/proprietary/lib/libb.so.meta_lic restricted", - "testdata/proprietary/highest.apex.meta_lic testdata/proprietary/highest.apex.meta_lic testdata/proprietary/highest.apex.meta_lic notice", - "testdata/proprietary/highest.apex.meta_lic testdata/proprietary/highest.apex.meta_lic testdata/proprietary/lib/libb.so.meta_lic restricted", - "testdata/proprietary/highest.apex.meta_lic testdata/proprietary/lib/liba.so.meta_lic testdata/proprietary/lib/liba.so.meta_lic by_exception_only:proprietary", - "testdata/proprietary/highest.apex.meta_lic testdata/proprietary/lib/libb.so.meta_lic testdata/proprietary/lib/libb.so.meta_lic restricted", - "testdata/proprietary/highest.apex.meta_lic testdata/proprietary/lib/libc.a.meta_lic testdata/proprietary/lib/libc.a.meta_lic by_exception_only:proprietary", - "testdata/proprietary/highest.apex.meta_lic testdata/proprietary/lib/libd.so.meta_lic testdata/proprietary/lib/libb.so.meta_lic restricted", - "testdata/proprietary/lib/liba.so.meta_lic testdata/proprietary/lib/liba.so.meta_lic testdata/proprietary/lib/liba.so.meta_lic by_exception_only:proprietary", - "testdata/proprietary/lib/libb.so.meta_lic testdata/proprietary/lib/libb.so.meta_lic testdata/proprietary/lib/libb.so.meta_lic restricted", - "testdata/proprietary/lib/libc.a.meta_lic testdata/proprietary/lib/libc.a.meta_lic testdata/proprietary/lib/libc.a.meta_lic by_exception_only:proprietary", - "testdata/proprietary/lib/libd.so.meta_lic testdata/proprietary/lib/libd.so.meta_lic testdata/proprietary/lib/libb.so.meta_lic restricted", - "testdata/proprietary/lib/libd.so.meta_lic testdata/proprietary/lib/libd.so.meta_lic testdata/proprietary/lib/libd.so.meta_lic notice", + "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", }, }, { @@ -841,27 +720,19 @@ func Test_plaintext(t *testing.T) { roots: []string{"highest.apex.meta_lic"}, ctx: context{stripPrefix: "testdata/proprietary/"}, expectedOut: []string{ - "bin/bin1.meta_lic bin/bin1.meta_lic bin/bin1.meta_lic notice", - "bin/bin1.meta_lic lib/liba.so.meta_lic lib/liba.so.meta_lic by_exception_only:proprietary", - "bin/bin1.meta_lic lib/libc.a.meta_lic lib/libc.a.meta_lic by_exception_only:proprietary", - "bin/bin2.meta_lic bin/bin2.meta_lic bin/bin2.meta_lic by_exception_only:proprietary", - "bin/bin2.meta_lic bin/bin2.meta_lic lib/libb.so.meta_lic restricted", - "bin/bin2.meta_lic lib/libb.so.meta_lic lib/libb.so.meta_lic restricted", - "bin/bin2.meta_lic lib/libd.so.meta_lic lib/libb.so.meta_lic restricted", - "highest.apex.meta_lic bin/bin1.meta_lic bin/bin1.meta_lic notice", - "highest.apex.meta_lic bin/bin2.meta_lic bin/bin2.meta_lic by_exception_only:proprietary", - "highest.apex.meta_lic bin/bin2.meta_lic lib/libb.so.meta_lic restricted", - "highest.apex.meta_lic highest.apex.meta_lic highest.apex.meta_lic notice", - "highest.apex.meta_lic highest.apex.meta_lic lib/libb.so.meta_lic restricted", - "highest.apex.meta_lic lib/liba.so.meta_lic lib/liba.so.meta_lic by_exception_only:proprietary", - "highest.apex.meta_lic lib/libb.so.meta_lic lib/libb.so.meta_lic restricted", - "highest.apex.meta_lic lib/libc.a.meta_lic lib/libc.a.meta_lic by_exception_only:proprietary", - "highest.apex.meta_lic lib/libd.so.meta_lic lib/libb.so.meta_lic restricted", - "lib/liba.so.meta_lic lib/liba.so.meta_lic lib/liba.so.meta_lic by_exception_only:proprietary", - "lib/libb.so.meta_lic lib/libb.so.meta_lic lib/libb.so.meta_lic restricted", - "lib/libc.a.meta_lic lib/libc.a.meta_lic lib/libc.a.meta_lic by_exception_only:proprietary", - "lib/libd.so.meta_lic lib/libd.so.meta_lic lib/libb.so.meta_lic restricted", - "lib/libd.so.meta_lic lib/libd.so.meta_lic lib/libd.so.meta_lic notice", + "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", }, }, { @@ -869,13 +740,13 @@ func Test_plaintext(t *testing.T) { name: "apex_trimmed_notice", roots: []string{"highest.apex.meta_lic"}, ctx: context{ - conditions: []string{"notice"}, + conditions: []compliance.LicenseCondition{compliance.NoticeCondition}, stripPrefix: "testdata/proprietary/", }, expectedOut: []string{ - "bin/bin1.meta_lic bin/bin1.meta_lic bin/bin1.meta_lic notice", - "highest.apex.meta_lic bin/bin1.meta_lic bin/bin1.meta_lic notice", - "highest.apex.meta_lic highest.apex.meta_lic highest.apex.meta_lic notice", + "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", }, }, { @@ -883,16 +754,16 @@ func Test_plaintext(t *testing.T) { name: "apex_trimmed_share", roots: []string{"highest.apex.meta_lic"}, ctx: context{ - conditions: []string{"reciprocal", "restricted"}, + conditions: compliance.ImpliesShared.AsList(), stripPrefix: "testdata/proprietary/", }, expectedOut: []string{ - "bin/bin2.meta_lic bin/bin2.meta_lic lib/libb.so.meta_lic restricted", - "bin/bin2.meta_lic lib/libb.so.meta_lic lib/libb.so.meta_lic restricted", - "highest.apex.meta_lic bin/bin2.meta_lic lib/libb.so.meta_lic restricted", - "highest.apex.meta_lic highest.apex.meta_lic lib/libb.so.meta_lic restricted", - "highest.apex.meta_lic lib/libb.so.meta_lic lib/libb.so.meta_lic restricted", - "lib/libb.so.meta_lic lib/libb.so.meta_lic lib/libb.so.meta_lic restricted", + "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", }, }, { @@ -900,17 +771,17 @@ func Test_plaintext(t *testing.T) { name: "apex_trimmed_private", roots: []string{"highest.apex.meta_lic"}, ctx: context{ - conditions: []string{"proprietary"}, + conditions: compliance.ImpliesPrivate.AsList(), stripPrefix: "testdata/proprietary/", }, expectedOut: []string{ - "bin/bin1.meta_lic lib/liba.so.meta_lic lib/liba.so.meta_lic proprietary", - "bin/bin1.meta_lic lib/libc.a.meta_lic lib/libc.a.meta_lic proprietary", - "bin/bin2.meta_lic bin/bin2.meta_lic bin/bin2.meta_lic proprietary", - "highest.apex.meta_lic bin/bin2.meta_lic bin/bin2.meta_lic proprietary", - "highest.apex.meta_lic lib/liba.so.meta_lic lib/liba.so.meta_lic proprietary", - "highest.apex.meta_lic lib/libc.a.meta_lic lib/libc.a.meta_lic proprietary", - "lib/liba.so.meta_lic lib/liba.so.meta_lic lib/liba.so.meta_lic proprietary", + "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", }, }, { @@ -918,23 +789,21 @@ func Test_plaintext(t *testing.T) { name: "apex_trimmed_share_private", roots: []string{"highest.apex.meta_lic"}, ctx: context{ - conditions: []string{"reciprocal", "restricted", "proprietary"}, + conditions: append(compliance.ImpliesShared.AsList(),compliance.ImpliesPrivate.AsList()...), stripPrefix: "testdata/proprietary/", }, expectedOut: []string{ - "bin/bin1.meta_lic lib/liba.so.meta_lic lib/liba.so.meta_lic proprietary", - "bin/bin1.meta_lic lib/libc.a.meta_lic lib/libc.a.meta_lic proprietary", - "bin/bin2.meta_lic bin/bin2.meta_lic bin/bin2.meta_lic proprietary", - "bin/bin2.meta_lic bin/bin2.meta_lic lib/libb.so.meta_lic restricted", - "bin/bin2.meta_lic lib/libb.so.meta_lic lib/libb.so.meta_lic restricted", - "highest.apex.meta_lic bin/bin2.meta_lic bin/bin2.meta_lic proprietary", - "highest.apex.meta_lic bin/bin2.meta_lic lib/libb.so.meta_lic restricted", - "highest.apex.meta_lic highest.apex.meta_lic lib/libb.so.meta_lic restricted", - "highest.apex.meta_lic lib/liba.so.meta_lic lib/liba.so.meta_lic proprietary", - "highest.apex.meta_lic lib/libb.so.meta_lic lib/libb.so.meta_lic restricted", - "highest.apex.meta_lic lib/libc.a.meta_lic lib/libc.a.meta_lic proprietary", - "lib/liba.so.meta_lic lib/liba.so.meta_lic lib/liba.so.meta_lic proprietary", - "lib/libb.so.meta_lic lib/libb.so.meta_lic lib/libb.so.meta_lic restricted", + "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", }, }, { @@ -943,27 +812,19 @@ func Test_plaintext(t *testing.T) { 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 bin/bin1.meta_lic:notice notice", - "bin/bin1.meta_lic:notice lib/liba.so.meta_lic:by_exception_only:proprietary lib/liba.so.meta_lic:by_exception_only:proprietary by_exception_only:proprietary", - "bin/bin1.meta_lic:notice lib/libc.a.meta_lic:by_exception_only:proprietary lib/libc.a.meta_lic:by_exception_only:proprietary by_exception_only:proprietary", - "bin/bin2.meta_lic:by_exception_only:proprietary bin/bin2.meta_lic:by_exception_only:proprietary bin/bin2.meta_lic:by_exception_only:proprietary by_exception_only:proprietary", - "bin/bin2.meta_lic:by_exception_only:proprietary bin/bin2.meta_lic:by_exception_only:proprietary lib/libb.so.meta_lic:restricted restricted", - "bin/bin2.meta_lic:by_exception_only:proprietary lib/libb.so.meta_lic:restricted lib/libb.so.meta_lic:restricted restricted", - "bin/bin2.meta_lic:by_exception_only:proprietary lib/libd.so.meta_lic:notice lib/libb.so.meta_lic:restricted restricted", - "highest.apex.meta_lic:notice bin/bin1.meta_lic:notice bin/bin1.meta_lic:notice notice", - "highest.apex.meta_lic:notice bin/bin2.meta_lic:by_exception_only:proprietary bin/bin2.meta_lic:by_exception_only:proprietary by_exception_only:proprietary", - "highest.apex.meta_lic:notice bin/bin2.meta_lic:by_exception_only:proprietary lib/libb.so.meta_lic:restricted restricted", - "highest.apex.meta_lic:notice highest.apex.meta_lic:notice highest.apex.meta_lic:notice notice", - "highest.apex.meta_lic:notice highest.apex.meta_lic:notice lib/libb.so.meta_lic:restricted restricted", - "highest.apex.meta_lic:notice lib/liba.so.meta_lic:by_exception_only:proprietary lib/liba.so.meta_lic:by_exception_only:proprietary by_exception_only:proprietary", - "highest.apex.meta_lic:notice lib/libb.so.meta_lic:restricted lib/libb.so.meta_lic:restricted restricted", - "highest.apex.meta_lic:notice lib/libc.a.meta_lic:by_exception_only:proprietary lib/libc.a.meta_lic:by_exception_only:proprietary by_exception_only:proprietary", - "highest.apex.meta_lic:notice lib/libd.so.meta_lic:notice lib/libb.so.meta_lic:restricted restricted", - "lib/liba.so.meta_lic:by_exception_only:proprietary lib/liba.so.meta_lic:by_exception_only:proprietary lib/liba.so.meta_lic:by_exception_only:proprietary by_exception_only:proprietary", - "lib/libb.so.meta_lic:restricted lib/libb.so.meta_lic:restricted lib/libb.so.meta_lic:restricted restricted", - "lib/libc.a.meta_lic:by_exception_only:proprietary lib/libc.a.meta_lic:by_exception_only:proprietary lib/libc.a.meta_lic:by_exception_only:proprietary by_exception_only:proprietary", - "lib/libd.so.meta_lic:notice lib/libd.so.meta_lic:notice lib/libb.so.meta_lic:restricted restricted", - "lib/libd.so.meta_lic:notice lib/libd.so.meta_lic:notice lib/libd.so.meta_lic:notice notice", + "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", }, }, { @@ -971,27 +832,19 @@ func Test_plaintext(t *testing.T) { name: "container", roots: []string{"container.zip.meta_lic"}, expectedOut: []string{ - "testdata/proprietary/bin/bin1.meta_lic 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 testdata/proprietary/lib/liba.so.meta_lic by_exception_only:proprietary", - "testdata/proprietary/bin/bin1.meta_lic testdata/proprietary/lib/libc.a.meta_lic testdata/proprietary/lib/libc.a.meta_lic by_exception_only:proprietary", - "testdata/proprietary/bin/bin2.meta_lic testdata/proprietary/bin/bin2.meta_lic testdata/proprietary/bin/bin2.meta_lic by_exception_only:proprietary", - "testdata/proprietary/bin/bin2.meta_lic testdata/proprietary/bin/bin2.meta_lic testdata/proprietary/lib/libb.so.meta_lic restricted", - "testdata/proprietary/bin/bin2.meta_lic testdata/proprietary/lib/libb.so.meta_lic testdata/proprietary/lib/libb.so.meta_lic restricted", - "testdata/proprietary/bin/bin2.meta_lic testdata/proprietary/lib/libd.so.meta_lic testdata/proprietary/lib/libb.so.meta_lic restricted", - "testdata/proprietary/container.zip.meta_lic testdata/proprietary/bin/bin1.meta_lic testdata/proprietary/bin/bin1.meta_lic notice", - "testdata/proprietary/container.zip.meta_lic testdata/proprietary/bin/bin2.meta_lic testdata/proprietary/bin/bin2.meta_lic by_exception_only:proprietary", - "testdata/proprietary/container.zip.meta_lic testdata/proprietary/bin/bin2.meta_lic testdata/proprietary/lib/libb.so.meta_lic restricted", - "testdata/proprietary/container.zip.meta_lic testdata/proprietary/container.zip.meta_lic testdata/proprietary/container.zip.meta_lic notice", - "testdata/proprietary/container.zip.meta_lic testdata/proprietary/container.zip.meta_lic testdata/proprietary/lib/libb.so.meta_lic restricted", - "testdata/proprietary/container.zip.meta_lic testdata/proprietary/lib/liba.so.meta_lic testdata/proprietary/lib/liba.so.meta_lic by_exception_only:proprietary", - "testdata/proprietary/container.zip.meta_lic testdata/proprietary/lib/libb.so.meta_lic testdata/proprietary/lib/libb.so.meta_lic restricted", - "testdata/proprietary/container.zip.meta_lic testdata/proprietary/lib/libc.a.meta_lic testdata/proprietary/lib/libc.a.meta_lic by_exception_only:proprietary", - "testdata/proprietary/container.zip.meta_lic testdata/proprietary/lib/libd.so.meta_lic testdata/proprietary/lib/libb.so.meta_lic restricted", - "testdata/proprietary/lib/liba.so.meta_lic testdata/proprietary/lib/liba.so.meta_lic testdata/proprietary/lib/liba.so.meta_lic by_exception_only:proprietary", - "testdata/proprietary/lib/libb.so.meta_lic testdata/proprietary/lib/libb.so.meta_lic testdata/proprietary/lib/libb.so.meta_lic restricted", - "testdata/proprietary/lib/libc.a.meta_lic testdata/proprietary/lib/libc.a.meta_lic testdata/proprietary/lib/libc.a.meta_lic by_exception_only:proprietary", - "testdata/proprietary/lib/libd.so.meta_lic testdata/proprietary/lib/libd.so.meta_lic testdata/proprietary/lib/libb.so.meta_lic restricted", - "testdata/proprietary/lib/libd.so.meta_lic testdata/proprietary/lib/libd.so.meta_lic testdata/proprietary/lib/libd.so.meta_lic notice", + "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", }, }, { @@ -999,15 +852,8 @@ func Test_plaintext(t *testing.T) { name: "application", roots: []string{"application.meta_lic"}, expectedOut: []string{ - "testdata/proprietary/application.meta_lic testdata/proprietary/application.meta_lic testdata/proprietary/application.meta_lic notice", - "testdata/proprietary/application.meta_lic testdata/proprietary/application.meta_lic testdata/proprietary/lib/libb.so.meta_lic restricted", - "testdata/proprietary/application.meta_lic testdata/proprietary/lib/liba.so.meta_lic testdata/proprietary/lib/liba.so.meta_lic by_exception_only:proprietary", - "testdata/proprietary/application.meta_lic testdata/proprietary/lib/liba.so.meta_lic testdata/proprietary/lib/libb.so.meta_lic restricted", - "testdata/proprietary/application.meta_lic testdata/proprietary/lib/libb.so.meta_lic testdata/proprietary/lib/libb.so.meta_lic restricted", - "testdata/proprietary/bin/bin3.meta_lic testdata/proprietary/bin/bin3.meta_lic testdata/proprietary/bin/bin3.meta_lic restricted", - "testdata/proprietary/lib/liba.so.meta_lic testdata/proprietary/lib/liba.so.meta_lic testdata/proprietary/lib/liba.so.meta_lic by_exception_only:proprietary", - "testdata/proprietary/lib/liba.so.meta_lic testdata/proprietary/lib/liba.so.meta_lic testdata/proprietary/lib/libb.so.meta_lic restricted", - "testdata/proprietary/lib/libb.so.meta_lic testdata/proprietary/lib/libb.so.meta_lic testdata/proprietary/lib/libb.so.meta_lic restricted", + "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", }, }, { @@ -1015,11 +861,9 @@ func Test_plaintext(t *testing.T) { name: "binary", roots: []string{"bin/bin1.meta_lic"}, expectedOut: []string{ - "testdata/proprietary/bin/bin1.meta_lic 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 testdata/proprietary/lib/liba.so.meta_lic by_exception_only:proprietary", - "testdata/proprietary/bin/bin1.meta_lic testdata/proprietary/lib/libc.a.meta_lic testdata/proprietary/lib/libc.a.meta_lic by_exception_only:proprietary", - "testdata/proprietary/lib/liba.so.meta_lic testdata/proprietary/lib/liba.so.meta_lic testdata/proprietary/lib/liba.so.meta_lic by_exception_only:proprietary", - "testdata/proprietary/lib/libc.a.meta_lic testdata/proprietary/lib/libc.a.meta_lic testdata/proprietary/lib/libc.a.meta_lic by_exception_only:proprietary", + "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", }, }, { @@ -1027,7 +871,7 @@ func Test_plaintext(t *testing.T) { 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 testdata/proprietary/lib/libd.so.meta_lic notice", + "testdata/proprietary/lib/libd.so.meta_lic testdata/proprietary/lib/libd.so.meta_lic notice", }, }, } @@ -1046,7 +890,7 @@ func Test_plaintext(t *testing.T) { for _, r := range tt.roots { rootFiles = append(rootFiles, "testdata/"+tt.condition+"/"+r) } - err := dumpResolutions(&tt.ctx, stdout, stderr, rootFiles...) + _, err := dumpResolutions(&tt.ctx, stdout, stderr, rootFiles...) if err != nil { t.Fatalf("dumpresolutions: error = %v, stderr = %v", err, stderr) return @@ -1076,7 +920,7 @@ type testContext struct { } type matcher interface { - matchString(*testContext) string + matchString(*testContext, *compliance.LicenseGraph) string typeString() string } @@ -1085,10 +929,23 @@ type targetMatcher struct { conditions []string } -func (tm *targetMatcher) matchString(ctx *testContext) 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 len(tm.conditions) > 0 { - m += "\\n" + strings.Join(tm.conditions, "\\n") + if !cs.IsEmpty() { + m += "\\n" + strings.Join(cs.Names(), "\\n") } m = ctx.nodes[tm.target] + " [label=\"" + m + "\"];" return m @@ -1101,14 +958,13 @@ func (tm *targetMatcher) typeString() string { type resolutionMatcher struct { appliesTo string actsOn string - origin string conditions []string } -func (rm *resolutionMatcher) matchString(ctx *testContext) string { - return ctx.nodes[rm.appliesTo] + " -> " + ctx.nodes[rm.actsOn] + "; " + - ctx.nodes[rm.actsOn] + " -> " + ctx.nodes[rm.origin] + - " [label=\"" + strings.Join(rm.conditions, "\\n") + "\"];" +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 { @@ -1125,7 +981,7 @@ func matchTarget(target string, conditions ...string) getMatcher { } } -func matchResolution(appliesTo, actsOn, origin string, conditions ...string) getMatcher { +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) @@ -1135,11 +991,7 @@ func matchResolution(appliesTo, actsOn, origin string, conditions ...string) get ctx.nodes[actsOn] = fmt.Sprintf("unknown%d", ctx.nextNode) ctx.nextNode++ } - if _, ok := ctx.nodes[origin]; !ok { - ctx.nodes[origin] = fmt.Sprintf("unknown%d", ctx.nextNode) - ctx.nextNode++ - } - return &resolutionMatcher{appliesTo, actsOn, origin, append([]string{}, conditions...)} + return &resolutionMatcher{appliesTo, actsOn, append([]string{}, conditions...)} } } @@ -1162,76 +1014,53 @@ func Test_graphviz(t *testing.T) { matchTarget("testdata/firstparty/bin/bin2.meta_lic"), matchTarget("testdata/firstparty/highest.apex.meta_lic"), matchTarget("testdata/firstparty/lib/libb.so.meta_lic"), - matchTarget("testdata/firstparty/lib/libd.so.meta_lic"), matchResolution( - "testdata/firstparty/bin/bin1.meta_lic", "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", - "testdata/firstparty/lib/liba.so.meta_lic", "notice"), matchResolution( "testdata/firstparty/bin/bin1.meta_lic", "testdata/firstparty/lib/libc.a.meta_lic", - "testdata/firstparty/lib/libc.a.meta_lic", "notice"), matchResolution( - "testdata/firstparty/bin/bin2.meta_lic", "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", - "testdata/firstparty/bin/bin1.meta_lic", "notice"), matchResolution( "testdata/firstparty/highest.apex.meta_lic", "testdata/firstparty/bin/bin2.meta_lic", - "testdata/firstparty/bin/bin2.meta_lic", "notice"), matchResolution( - "testdata/firstparty/highest.apex.meta_lic", "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", - "testdata/firstparty/lib/liba.so.meta_lic", "notice"), matchResolution( "testdata/firstparty/highest.apex.meta_lic", "testdata/firstparty/lib/libb.so.meta_lic", - "testdata/firstparty/lib/libb.so.meta_lic", "notice"), matchResolution( "testdata/firstparty/highest.apex.meta_lic", "testdata/firstparty/lib/libc.a.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", "testdata/firstparty/lib/liba.so.meta_lic", "notice"), matchResolution( "testdata/firstparty/lib/libb.so.meta_lic", "testdata/firstparty/lib/libb.so.meta_lic", - "testdata/firstparty/lib/libb.so.meta_lic", - "notice"), - matchResolution( - "testdata/firstparty/lib/libc.a.meta_lic", - "testdata/firstparty/lib/libc.a.meta_lic", - "testdata/firstparty/lib/libc.a.meta_lic", - "notice"), - matchResolution( - "testdata/firstparty/lib/libd.so.meta_lic", - "testdata/firstparty/lib/libd.so.meta_lic", - "testdata/firstparty/lib/libd.so.meta_lic", "notice"), }, }, @@ -1247,76 +1076,53 @@ func Test_graphviz(t *testing.T) { matchTarget("bin/bin2.meta_lic"), matchTarget("highest.apex.meta_lic"), matchTarget("lib/libb.so.meta_lic"), - matchTarget("lib/libd.so.meta_lic"), matchResolution( - "bin/bin1.meta_lic", "bin/bin1.meta_lic", "bin/bin1.meta_lic", "notice"), matchResolution( "bin/bin1.meta_lic", "lib/liba.so.meta_lic", - "lib/liba.so.meta_lic", "notice"), matchResolution( "bin/bin1.meta_lic", "lib/libc.a.meta_lic", - "lib/libc.a.meta_lic", "notice"), matchResolution( - "bin/bin2.meta_lic", "bin/bin2.meta_lic", "bin/bin2.meta_lic", "notice"), matchResolution( "highest.apex.meta_lic", "bin/bin1.meta_lic", - "bin/bin1.meta_lic", "notice"), matchResolution( "highest.apex.meta_lic", "bin/bin2.meta_lic", - "bin/bin2.meta_lic", "notice"), matchResolution( - "highest.apex.meta_lic", "highest.apex.meta_lic", "highest.apex.meta_lic", "notice"), matchResolution( "highest.apex.meta_lic", "lib/liba.so.meta_lic", - "lib/liba.so.meta_lic", "notice"), matchResolution( "highest.apex.meta_lic", "lib/libb.so.meta_lic", - "lib/libb.so.meta_lic", "notice"), matchResolution( "highest.apex.meta_lic", "lib/libc.a.meta_lic", - "lib/libc.a.meta_lic", "notice"), matchResolution( - "lib/liba.so.meta_lic", "lib/liba.so.meta_lic", "lib/liba.so.meta_lic", "notice"), matchResolution( "lib/libb.so.meta_lic", "lib/libb.so.meta_lic", - "lib/libb.so.meta_lic", - "notice"), - matchResolution( - "lib/libc.a.meta_lic", - "lib/libc.a.meta_lic", - "lib/libc.a.meta_lic", - "notice"), - matchResolution( - "lib/libd.so.meta_lic", - "lib/libd.so.meta_lic", - "lib/libd.so.meta_lic", "notice"), }, }, @@ -1325,7 +1131,7 @@ func Test_graphviz(t *testing.T) { name: "apex_trimmed_notice", roots: []string{"highest.apex.meta_lic"}, ctx: context{ - conditions: []string{"notice"}, + conditions: []compliance.LicenseCondition{compliance.NoticeCondition}, stripPrefix: "testdata/firstparty/", }, expectedOut: []getMatcher{ @@ -1336,62 +1142,50 @@ func Test_graphviz(t *testing.T) { matchTarget("highest.apex.meta_lic"), matchTarget("lib/libb.so.meta_lic"), matchResolution( - "bin/bin1.meta_lic", "bin/bin1.meta_lic", "bin/bin1.meta_lic", "notice"), matchResolution( "bin/bin1.meta_lic", "lib/liba.so.meta_lic", - "lib/liba.so.meta_lic", "notice"), matchResolution( "bin/bin1.meta_lic", "lib/libc.a.meta_lic", - "lib/libc.a.meta_lic", "notice"), matchResolution( - "bin/bin2.meta_lic", "bin/bin2.meta_lic", "bin/bin2.meta_lic", "notice"), matchResolution( "highest.apex.meta_lic", "bin/bin1.meta_lic", - "bin/bin1.meta_lic", "notice"), matchResolution( "highest.apex.meta_lic", "bin/bin2.meta_lic", - "bin/bin2.meta_lic", "notice"), matchResolution( - "highest.apex.meta_lic", "highest.apex.meta_lic", "highest.apex.meta_lic", "notice"), matchResolution( "highest.apex.meta_lic", "lib/liba.so.meta_lic", - "lib/liba.so.meta_lic", "notice"), matchResolution( "highest.apex.meta_lic", "lib/libb.so.meta_lic", - "lib/libb.so.meta_lic", "notice"), matchResolution( "highest.apex.meta_lic", "lib/libc.a.meta_lic", - "lib/libc.a.meta_lic", "notice"), matchResolution( - "lib/liba.so.meta_lic", "lib/liba.so.meta_lic", "lib/liba.so.meta_lic", "notice"), matchResolution( - "lib/libb.so.meta_lic", "lib/libb.so.meta_lic", "lib/libb.so.meta_lic", "notice"), @@ -1402,7 +1196,7 @@ func Test_graphviz(t *testing.T) { name: "apex_trimmed_share", roots: []string{"highest.apex.meta_lic"}, ctx: context{ - conditions: []string{"reciprocal", "restricted"}, + conditions: compliance.ImpliesShared.AsList(), stripPrefix: "testdata/firstparty/", }, expectedOut: []getMatcher{}, @@ -1412,7 +1206,7 @@ func Test_graphviz(t *testing.T) { name: "apex_trimmed_private", roots: []string{"highest.apex.meta_lic"}, ctx: context{ - conditions: []string{"proprietary"}, + conditions: compliance.ImpliesPrivate.AsList(), stripPrefix: "testdata/firstparty/", }, expectedOut: []getMatcher{}, @@ -1422,7 +1216,7 @@ func Test_graphviz(t *testing.T) { name: "apex_trimmed_share_private", roots: []string{"highest.apex.meta_lic"}, ctx: context{ - conditions: []string{"reciprocal", "restricted", "proprietary"}, + conditions: compliance.ImpliesShared.Union(compliance.ImpliesPrivate).AsList(), stripPrefix: "testdata/firstparty/", }, expectedOut: []getMatcher{}, @@ -1439,76 +1233,53 @@ func Test_graphviz(t *testing.T) { matchTarget("bin/bin2.meta_lic", "notice"), matchTarget("highest.apex.meta_lic", "notice"), matchTarget("lib/libb.so.meta_lic", "notice"), - matchTarget("lib/libd.so.meta_lic", "notice"), matchResolution( - "bin/bin1.meta_lic", "bin/bin1.meta_lic", "bin/bin1.meta_lic", "notice"), matchResolution( "bin/bin1.meta_lic", "lib/liba.so.meta_lic", - "lib/liba.so.meta_lic", "notice"), matchResolution( "bin/bin1.meta_lic", "lib/libc.a.meta_lic", - "lib/libc.a.meta_lic", "notice"), matchResolution( - "bin/bin2.meta_lic", "bin/bin2.meta_lic", "bin/bin2.meta_lic", "notice"), matchResolution( "highest.apex.meta_lic", "bin/bin1.meta_lic", - "bin/bin1.meta_lic", "notice"), matchResolution( "highest.apex.meta_lic", "bin/bin2.meta_lic", - "bin/bin2.meta_lic", "notice"), matchResolution( - "highest.apex.meta_lic", "highest.apex.meta_lic", "highest.apex.meta_lic", "notice"), matchResolution( "highest.apex.meta_lic", "lib/liba.so.meta_lic", - "lib/liba.so.meta_lic", "notice"), matchResolution( "highest.apex.meta_lic", "lib/libb.so.meta_lic", - "lib/libb.so.meta_lic", "notice"), matchResolution( "highest.apex.meta_lic", "lib/libc.a.meta_lic", - "lib/libc.a.meta_lic", "notice"), matchResolution( - "lib/liba.so.meta_lic", "lib/liba.so.meta_lic", "lib/liba.so.meta_lic", "notice"), matchResolution( "lib/libb.so.meta_lic", "lib/libb.so.meta_lic", - "lib/libb.so.meta_lic", - "notice"), - matchResolution( - "lib/libc.a.meta_lic", - "lib/libc.a.meta_lic", - "lib/libc.a.meta_lic", - "notice"), - matchResolution( - "lib/libd.so.meta_lic", - "lib/libd.so.meta_lic", - "lib/libd.so.meta_lic", "notice"), }, }, @@ -1523,76 +1294,53 @@ func Test_graphviz(t *testing.T) { matchTarget("testdata/firstparty/bin/bin2.meta_lic"), matchTarget("testdata/firstparty/container.zip.meta_lic"), matchTarget("testdata/firstparty/lib/libb.so.meta_lic"), - matchTarget("testdata/firstparty/lib/libd.so.meta_lic"), matchResolution( - "testdata/firstparty/bin/bin1.meta_lic", "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", - "testdata/firstparty/lib/liba.so.meta_lic", "notice"), matchResolution( "testdata/firstparty/bin/bin1.meta_lic", "testdata/firstparty/lib/libc.a.meta_lic", - "testdata/firstparty/lib/libc.a.meta_lic", "notice"), matchResolution( - "testdata/firstparty/bin/bin2.meta_lic", "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", - "testdata/firstparty/bin/bin1.meta_lic", "notice"), matchResolution( "testdata/firstparty/container.zip.meta_lic", "testdata/firstparty/bin/bin2.meta_lic", - "testdata/firstparty/bin/bin2.meta_lic", "notice"), matchResolution( - "testdata/firstparty/container.zip.meta_lic", "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", - "testdata/firstparty/lib/liba.so.meta_lic", "notice"), matchResolution( "testdata/firstparty/container.zip.meta_lic", "testdata/firstparty/lib/libb.so.meta_lic", - "testdata/firstparty/lib/libb.so.meta_lic", "notice"), matchResolution( "testdata/firstparty/container.zip.meta_lic", "testdata/firstparty/lib/libc.a.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", "testdata/firstparty/lib/liba.so.meta_lic", "notice"), matchResolution( "testdata/firstparty/lib/libb.so.meta_lic", "testdata/firstparty/lib/libb.so.meta_lic", - "testdata/firstparty/lib/libb.so.meta_lic", - "notice"), - matchResolution( - "testdata/firstparty/lib/libc.a.meta_lic", - "testdata/firstparty/lib/libc.a.meta_lic", - "testdata/firstparty/lib/libc.a.meta_lic", - "notice"), - matchResolution( - "testdata/firstparty/lib/libd.so.meta_lic", - "testdata/firstparty/lib/libd.so.meta_lic", - "testdata/firstparty/lib/libd.so.meta_lic", "notice"), }, }, @@ -1603,32 +1351,13 @@ func Test_graphviz(t *testing.T) { expectedOut: []getMatcher{ matchTarget("testdata/firstparty/application.meta_lic"), matchTarget("testdata/firstparty/lib/liba.so.meta_lic"), - matchTarget("testdata/firstparty/bin/bin3.meta_lic"), - matchTarget("testdata/firstparty/lib/libb.so.meta_lic"), matchResolution( - "testdata/firstparty/application.meta_lic", "testdata/firstparty/application.meta_lic", "testdata/firstparty/application.meta_lic", "notice"), matchResolution( "testdata/firstparty/application.meta_lic", "testdata/firstparty/lib/liba.so.meta_lic", - "testdata/firstparty/lib/liba.so.meta_lic", - "notice"), - matchResolution( - "testdata/firstparty/bin/bin3.meta_lic", - "testdata/firstparty/bin/bin3.meta_lic", - "testdata/firstparty/bin/bin3.meta_lic", - "notice"), - matchResolution( - "testdata/firstparty/lib/liba.so.meta_lic", - "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", - "testdata/firstparty/lib/libb.so.meta_lic", "notice"), }, }, @@ -1641,29 +1370,16 @@ func Test_graphviz(t *testing.T) { 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", "testdata/firstparty/bin/bin1.meta_lic", "notice"), matchResolution( "testdata/firstparty/bin/bin1.meta_lic", "testdata/firstparty/lib/liba.so.meta_lic", - "testdata/firstparty/lib/liba.so.meta_lic", "notice"), matchResolution( "testdata/firstparty/bin/bin1.meta_lic", "testdata/firstparty/lib/libc.a.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", - "testdata/firstparty/lib/liba.so.meta_lic", - "notice"), - matchResolution( - "testdata/firstparty/lib/libc.a.meta_lic", - "testdata/firstparty/lib/libc.a.meta_lic", - "testdata/firstparty/lib/libc.a.meta_lic", "notice"), }, }, @@ -1674,7 +1390,6 @@ func Test_graphviz(t *testing.T) { 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", "testdata/firstparty/lib/libd.so.meta_lic", "notice"), @@ -1691,76 +1406,53 @@ func Test_graphviz(t *testing.T) { matchTarget("testdata/notice/bin/bin2.meta_lic"), matchTarget("testdata/notice/highest.apex.meta_lic"), matchTarget("testdata/notice/lib/libb.so.meta_lic"), - matchTarget("testdata/notice/lib/libd.so.meta_lic"), matchResolution( - "testdata/notice/bin/bin1.meta_lic", "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", - "testdata/notice/lib/liba.so.meta_lic", "notice"), matchResolution( "testdata/notice/bin/bin1.meta_lic", "testdata/notice/lib/libc.a.meta_lic", - "testdata/notice/lib/libc.a.meta_lic", "notice"), matchResolution( - "testdata/notice/bin/bin2.meta_lic", "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", - "testdata/notice/bin/bin1.meta_lic", "notice"), matchResolution( "testdata/notice/highest.apex.meta_lic", "testdata/notice/bin/bin2.meta_lic", - "testdata/notice/bin/bin2.meta_lic", "notice"), matchResolution( - "testdata/notice/highest.apex.meta_lic", "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", - "testdata/notice/lib/liba.so.meta_lic", "notice"), matchResolution( "testdata/notice/highest.apex.meta_lic", "testdata/notice/lib/libb.so.meta_lic", - "testdata/notice/lib/libb.so.meta_lic", "notice"), matchResolution( "testdata/notice/highest.apex.meta_lic", "testdata/notice/lib/libc.a.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", "testdata/notice/lib/liba.so.meta_lic", "notice"), matchResolution( "testdata/notice/lib/libb.so.meta_lic", "testdata/notice/lib/libb.so.meta_lic", - "testdata/notice/lib/libb.so.meta_lic", - "notice"), - matchResolution( - "testdata/notice/lib/libc.a.meta_lic", - "testdata/notice/lib/libc.a.meta_lic", - "testdata/notice/lib/libc.a.meta_lic", - "notice"), - matchResolution( - "testdata/notice/lib/libd.so.meta_lic", - "testdata/notice/lib/libd.so.meta_lic", - "testdata/notice/lib/libd.so.meta_lic", "notice"), }, }, @@ -1776,76 +1468,53 @@ func Test_graphviz(t *testing.T) { matchTarget("bin/bin2.meta_lic"), matchTarget("highest.apex.meta_lic"), matchTarget("lib/libb.so.meta_lic"), - matchTarget("lib/libd.so.meta_lic"), matchResolution( - "bin/bin1.meta_lic", "bin/bin1.meta_lic", "bin/bin1.meta_lic", "notice"), matchResolution( "bin/bin1.meta_lic", "lib/liba.so.meta_lic", - "lib/liba.so.meta_lic", "notice"), matchResolution( "bin/bin1.meta_lic", "lib/libc.a.meta_lic", - "lib/libc.a.meta_lic", "notice"), matchResolution( - "bin/bin2.meta_lic", "bin/bin2.meta_lic", "bin/bin2.meta_lic", "notice"), matchResolution( "highest.apex.meta_lic", "bin/bin1.meta_lic", - "bin/bin1.meta_lic", "notice"), matchResolution( "highest.apex.meta_lic", "bin/bin2.meta_lic", - "bin/bin2.meta_lic", "notice"), matchResolution( - "highest.apex.meta_lic", "highest.apex.meta_lic", "highest.apex.meta_lic", "notice"), matchResolution( "highest.apex.meta_lic", "lib/liba.so.meta_lic", - "lib/liba.so.meta_lic", "notice"), matchResolution( "highest.apex.meta_lic", "lib/libb.so.meta_lic", - "lib/libb.so.meta_lic", "notice"), matchResolution( "highest.apex.meta_lic", "lib/libc.a.meta_lic", - "lib/libc.a.meta_lic", "notice"), matchResolution( - "lib/liba.so.meta_lic", "lib/liba.so.meta_lic", "lib/liba.so.meta_lic", "notice"), matchResolution( "lib/libb.so.meta_lic", "lib/libb.so.meta_lic", - "lib/libb.so.meta_lic", - "notice"), - matchResolution( - "lib/libc.a.meta_lic", - "lib/libc.a.meta_lic", - "lib/libc.a.meta_lic", - "notice"), - matchResolution( - "lib/libd.so.meta_lic", - "lib/libd.so.meta_lic", - "lib/libd.so.meta_lic", "notice"), }, }, @@ -1854,7 +1523,7 @@ func Test_graphviz(t *testing.T) { name: "apex_trimmed_notice", roots: []string{"highest.apex.meta_lic"}, ctx: context{ - conditions: []string{"notice"}, + conditions: []compliance.LicenseCondition{compliance.NoticeCondition}, stripPrefix: "testdata/notice/", }, expectedOut: []getMatcher{ @@ -1865,62 +1534,50 @@ func Test_graphviz(t *testing.T) { matchTarget("highest.apex.meta_lic"), matchTarget("lib/libb.so.meta_lic"), matchResolution( - "bin/bin1.meta_lic", "bin/bin1.meta_lic", "bin/bin1.meta_lic", "notice"), matchResolution( "bin/bin1.meta_lic", "lib/liba.so.meta_lic", - "lib/liba.so.meta_lic", "notice"), matchResolution( "bin/bin1.meta_lic", "lib/libc.a.meta_lic", - "lib/libc.a.meta_lic", "notice"), matchResolution( - "bin/bin2.meta_lic", "bin/bin2.meta_lic", "bin/bin2.meta_lic", "notice"), matchResolution( "highest.apex.meta_lic", "bin/bin1.meta_lic", - "bin/bin1.meta_lic", "notice"), matchResolution( "highest.apex.meta_lic", "bin/bin2.meta_lic", - "bin/bin2.meta_lic", "notice"), matchResolution( - "highest.apex.meta_lic", "highest.apex.meta_lic", "highest.apex.meta_lic", "notice"), matchResolution( "highest.apex.meta_lic", "lib/liba.so.meta_lic", - "lib/liba.so.meta_lic", "notice"), matchResolution( "highest.apex.meta_lic", "lib/libb.so.meta_lic", - "lib/libb.so.meta_lic", "notice"), matchResolution( "highest.apex.meta_lic", "lib/libc.a.meta_lic", - "lib/libc.a.meta_lic", "notice"), matchResolution( - "lib/liba.so.meta_lic", "lib/liba.so.meta_lic", "lib/liba.so.meta_lic", "notice"), matchResolution( - "lib/libb.so.meta_lic", "lib/libb.so.meta_lic", "lib/libb.so.meta_lic", "notice"), @@ -1931,7 +1588,7 @@ func Test_graphviz(t *testing.T) { name: "apex_trimmed_share", roots: []string{"highest.apex.meta_lic"}, ctx: context{ - conditions: []string{"reciprocal", "restricted"}, + conditions: compliance.ImpliesShared.AsList(), stripPrefix: "testdata/notice/", }, expectedOut: []getMatcher{}, @@ -1941,7 +1598,7 @@ func Test_graphviz(t *testing.T) { name: "apex_trimmed_private", roots: []string{"highest.apex.meta_lic"}, ctx: context{ - conditions: []string{"proprietary"}, + conditions: compliance.ImpliesPrivate.AsList(), stripPrefix: "testdata/notice/", }, expectedOut: []getMatcher{}, @@ -1951,7 +1608,7 @@ func Test_graphviz(t *testing.T) { name: "apex_trimmed_share_private", roots: []string{"highest.apex.meta_lic"}, ctx: context{ - conditions: []string{"reciprocal", "restricted", "proprietary"}, + conditions: compliance.ImpliesShared.Union(compliance.ImpliesPrivate).AsList(), stripPrefix: "testdata/notice/", }, expectedOut: []getMatcher{}, @@ -1968,76 +1625,53 @@ func Test_graphviz(t *testing.T) { matchTarget("bin/bin2.meta_lic", "notice"), matchTarget("highest.apex.meta_lic", "notice"), matchTarget("lib/libb.so.meta_lic", "notice"), - matchTarget("lib/libd.so.meta_lic", "notice"), matchResolution( - "bin/bin1.meta_lic", "bin/bin1.meta_lic", "bin/bin1.meta_lic", "notice"), matchResolution( "bin/bin1.meta_lic", "lib/liba.so.meta_lic", - "lib/liba.so.meta_lic", "notice"), matchResolution( "bin/bin1.meta_lic", "lib/libc.a.meta_lic", - "lib/libc.a.meta_lic", "notice"), matchResolution( - "bin/bin2.meta_lic", "bin/bin2.meta_lic", "bin/bin2.meta_lic", "notice"), matchResolution( "highest.apex.meta_lic", "bin/bin1.meta_lic", - "bin/bin1.meta_lic", "notice"), matchResolution( "highest.apex.meta_lic", "bin/bin2.meta_lic", - "bin/bin2.meta_lic", "notice"), matchResolution( - "highest.apex.meta_lic", "highest.apex.meta_lic", "highest.apex.meta_lic", "notice"), matchResolution( "highest.apex.meta_lic", "lib/liba.so.meta_lic", - "lib/liba.so.meta_lic", "notice"), matchResolution( "highest.apex.meta_lic", "lib/libb.so.meta_lic", - "lib/libb.so.meta_lic", "notice"), matchResolution( "highest.apex.meta_lic", "lib/libc.a.meta_lic", - "lib/libc.a.meta_lic", "notice"), matchResolution( - "lib/liba.so.meta_lic", "lib/liba.so.meta_lic", "lib/liba.so.meta_lic", "notice"), matchResolution( "lib/libb.so.meta_lic", "lib/libb.so.meta_lic", - "lib/libb.so.meta_lic", - "notice"), - matchResolution( - "lib/libc.a.meta_lic", - "lib/libc.a.meta_lic", - "lib/libc.a.meta_lic", - "notice"), - matchResolution( - "lib/libd.so.meta_lic", - "lib/libd.so.meta_lic", - "lib/libd.so.meta_lic", "notice"), }, }, @@ -2052,76 +1686,53 @@ func Test_graphviz(t *testing.T) { matchTarget("testdata/notice/bin/bin2.meta_lic"), matchTarget("testdata/notice/container.zip.meta_lic"), matchTarget("testdata/notice/lib/libb.so.meta_lic"), - matchTarget("testdata/notice/lib/libd.so.meta_lic"), matchResolution( - "testdata/notice/bin/bin1.meta_lic", "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", - "testdata/notice/lib/liba.so.meta_lic", "notice"), matchResolution( "testdata/notice/bin/bin1.meta_lic", "testdata/notice/lib/libc.a.meta_lic", - "testdata/notice/lib/libc.a.meta_lic", "notice"), matchResolution( - "testdata/notice/bin/bin2.meta_lic", "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", - "testdata/notice/bin/bin1.meta_lic", "notice"), matchResolution( "testdata/notice/container.zip.meta_lic", "testdata/notice/bin/bin2.meta_lic", - "testdata/notice/bin/bin2.meta_lic", "notice"), matchResolution( - "testdata/notice/container.zip.meta_lic", "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", - "testdata/notice/lib/liba.so.meta_lic", "notice"), matchResolution( "testdata/notice/container.zip.meta_lic", "testdata/notice/lib/libb.so.meta_lic", - "testdata/notice/lib/libb.so.meta_lic", "notice"), matchResolution( "testdata/notice/container.zip.meta_lic", "testdata/notice/lib/libc.a.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", "testdata/notice/lib/liba.so.meta_lic", "notice"), matchResolution( "testdata/notice/lib/libb.so.meta_lic", "testdata/notice/lib/libb.so.meta_lic", - "testdata/notice/lib/libb.so.meta_lic", - "notice"), - matchResolution( - "testdata/notice/lib/libc.a.meta_lic", - "testdata/notice/lib/libc.a.meta_lic", - "testdata/notice/lib/libc.a.meta_lic", - "notice"), - matchResolution( - "testdata/notice/lib/libd.so.meta_lic", - "testdata/notice/lib/libd.so.meta_lic", - "testdata/notice/lib/libd.so.meta_lic", "notice"), }, }, @@ -2132,32 +1743,13 @@ func Test_graphviz(t *testing.T) { expectedOut: []getMatcher{ matchTarget("testdata/notice/application.meta_lic"), matchTarget("testdata/notice/lib/liba.so.meta_lic"), - matchTarget("testdata/notice/bin/bin3.meta_lic"), - matchTarget("testdata/notice/lib/libb.so.meta_lic"), matchResolution( - "testdata/notice/application.meta_lic", "testdata/notice/application.meta_lic", "testdata/notice/application.meta_lic", "notice"), matchResolution( "testdata/notice/application.meta_lic", "testdata/notice/lib/liba.so.meta_lic", - "testdata/notice/lib/liba.so.meta_lic", - "notice"), - matchResolution( - "testdata/notice/bin/bin3.meta_lic", - "testdata/notice/bin/bin3.meta_lic", - "testdata/notice/bin/bin3.meta_lic", - "notice"), - matchResolution( - "testdata/notice/lib/liba.so.meta_lic", - "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", - "testdata/notice/lib/libb.so.meta_lic", "notice"), }, }, @@ -2170,29 +1762,16 @@ func Test_graphviz(t *testing.T) { 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", "testdata/notice/bin/bin1.meta_lic", "notice"), matchResolution( "testdata/notice/bin/bin1.meta_lic", "testdata/notice/lib/liba.so.meta_lic", - "testdata/notice/lib/liba.so.meta_lic", "notice"), matchResolution( "testdata/notice/bin/bin1.meta_lic", "testdata/notice/lib/libc.a.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", - "testdata/notice/lib/liba.so.meta_lic", - "notice"), - matchResolution( - "testdata/notice/lib/libc.a.meta_lic", - "testdata/notice/lib/libc.a.meta_lic", - "testdata/notice/lib/libc.a.meta_lic", "notice"), }, }, @@ -2203,7 +1782,6 @@ func Test_graphviz(t *testing.T) { 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", "testdata/notice/lib/libd.so.meta_lic", "notice"), @@ -2220,76 +1798,53 @@ func Test_graphviz(t *testing.T) { matchTarget("testdata/reciprocal/bin/bin2.meta_lic"), matchTarget("testdata/reciprocal/highest.apex.meta_lic"), matchTarget("testdata/reciprocal/lib/libb.so.meta_lic"), - matchTarget("testdata/reciprocal/lib/libd.so.meta_lic"), matchResolution( - "testdata/reciprocal/bin/bin1.meta_lic", "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", - "testdata/reciprocal/lib/liba.so.meta_lic", "reciprocal"), matchResolution( "testdata/reciprocal/bin/bin1.meta_lic", "testdata/reciprocal/lib/libc.a.meta_lic", - "testdata/reciprocal/lib/libc.a.meta_lic", "reciprocal"), matchResolution( - "testdata/reciprocal/bin/bin2.meta_lic", "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", - "testdata/reciprocal/bin/bin1.meta_lic", "notice"), matchResolution( "testdata/reciprocal/highest.apex.meta_lic", "testdata/reciprocal/bin/bin2.meta_lic", - "testdata/reciprocal/bin/bin2.meta_lic", "notice"), matchResolution( - "testdata/reciprocal/highest.apex.meta_lic", "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", - "testdata/reciprocal/lib/liba.so.meta_lic", "reciprocal"), matchResolution( "testdata/reciprocal/highest.apex.meta_lic", "testdata/reciprocal/lib/libb.so.meta_lic", - "testdata/reciprocal/lib/libb.so.meta_lic", "notice"), matchResolution( "testdata/reciprocal/highest.apex.meta_lic", "testdata/reciprocal/lib/libc.a.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", "testdata/reciprocal/lib/liba.so.meta_lic", "reciprocal"), matchResolution( "testdata/reciprocal/lib/libb.so.meta_lic", "testdata/reciprocal/lib/libb.so.meta_lic", - "testdata/reciprocal/lib/libb.so.meta_lic", - "notice"), - matchResolution( - "testdata/reciprocal/lib/libc.a.meta_lic", - "testdata/reciprocal/lib/libc.a.meta_lic", - "testdata/reciprocal/lib/libc.a.meta_lic", - "reciprocal"), - matchResolution( - "testdata/reciprocal/lib/libd.so.meta_lic", - "testdata/reciprocal/lib/libd.so.meta_lic", - "testdata/reciprocal/lib/libd.so.meta_lic", "notice"), }, }, @@ -2305,76 +1860,53 @@ func Test_graphviz(t *testing.T) { matchTarget("bin/bin2.meta_lic"), matchTarget("highest.apex.meta_lic"), matchTarget("lib/libb.so.meta_lic"), - matchTarget("lib/libd.so.meta_lic"), matchResolution( - "bin/bin1.meta_lic", "bin/bin1.meta_lic", "bin/bin1.meta_lic", "notice"), matchResolution( "bin/bin1.meta_lic", "lib/liba.so.meta_lic", - "lib/liba.so.meta_lic", "reciprocal"), matchResolution( "bin/bin1.meta_lic", "lib/libc.a.meta_lic", - "lib/libc.a.meta_lic", "reciprocal"), matchResolution( - "bin/bin2.meta_lic", "bin/bin2.meta_lic", "bin/bin2.meta_lic", "notice"), matchResolution( "highest.apex.meta_lic", "bin/bin1.meta_lic", - "bin/bin1.meta_lic", "notice"), matchResolution( "highest.apex.meta_lic", "bin/bin2.meta_lic", - "bin/bin2.meta_lic", "notice"), matchResolution( - "highest.apex.meta_lic", "highest.apex.meta_lic", "highest.apex.meta_lic", "notice"), matchResolution( "highest.apex.meta_lic", "lib/liba.so.meta_lic", - "lib/liba.so.meta_lic", "reciprocal"), matchResolution( "highest.apex.meta_lic", "lib/libb.so.meta_lic", - "lib/libb.so.meta_lic", "notice"), matchResolution( "highest.apex.meta_lic", "lib/libc.a.meta_lic", - "lib/libc.a.meta_lic", "reciprocal"), matchResolution( - "lib/liba.so.meta_lic", "lib/liba.so.meta_lic", "lib/liba.so.meta_lic", "reciprocal"), matchResolution( "lib/libb.so.meta_lic", "lib/libb.so.meta_lic", - "lib/libb.so.meta_lic", - "notice"), - matchResolution( - "lib/libc.a.meta_lic", - "lib/libc.a.meta_lic", - "lib/libc.a.meta_lic", - "reciprocal"), - matchResolution( - "lib/libd.so.meta_lic", - "lib/libd.so.meta_lic", - "lib/libd.so.meta_lic", "notice"), }, }, @@ -2383,7 +1915,7 @@ func Test_graphviz(t *testing.T) { name: "apex_trimmed_notice", roots: []string{"highest.apex.meta_lic"}, ctx: context{ - conditions: []string{"notice"}, + conditions: []compliance.LicenseCondition{compliance.NoticeCondition}, stripPrefix: "testdata/reciprocal/", }, expectedOut: []getMatcher{ @@ -2392,37 +1924,30 @@ func Test_graphviz(t *testing.T) { matchTarget("highest.apex.meta_lic"), matchTarget("lib/libb.so.meta_lic"), matchResolution( - "bin/bin1.meta_lic", "bin/bin1.meta_lic", "bin/bin1.meta_lic", "notice"), matchResolution( - "bin/bin2.meta_lic", "bin/bin2.meta_lic", "bin/bin2.meta_lic", "notice"), matchResolution( "highest.apex.meta_lic", "bin/bin1.meta_lic", - "bin/bin1.meta_lic", "notice"), matchResolution( "highest.apex.meta_lic", "bin/bin2.meta_lic", - "bin/bin2.meta_lic", "notice"), matchResolution( - "highest.apex.meta_lic", "highest.apex.meta_lic", "highest.apex.meta_lic", "notice"), matchResolution( "highest.apex.meta_lic", "lib/libb.so.meta_lic", - "lib/libb.so.meta_lic", "notice"), matchResolution( - "lib/libb.so.meta_lic", "lib/libb.so.meta_lic", "lib/libb.so.meta_lic", "notice"), @@ -2433,7 +1958,7 @@ func Test_graphviz(t *testing.T) { name: "apex_trimmed_share", roots: []string{"highest.apex.meta_lic"}, ctx: context{ - conditions: []string{"reciprocal", "restricted"}, + conditions: compliance.ImpliesShared.AsList(), stripPrefix: "testdata/reciprocal/", }, expectedOut: []getMatcher{ @@ -2444,25 +1969,20 @@ func Test_graphviz(t *testing.T) { matchResolution( "bin/bin1.meta_lic", "lib/liba.so.meta_lic", - "lib/liba.so.meta_lic", "reciprocal"), matchResolution( "bin/bin1.meta_lic", "lib/libc.a.meta_lic", - "lib/libc.a.meta_lic", "reciprocal"), matchResolution( "highest.apex.meta_lic", "lib/liba.so.meta_lic", - "lib/liba.so.meta_lic", "reciprocal"), matchResolution( "highest.apex.meta_lic", "lib/libc.a.meta_lic", - "lib/libc.a.meta_lic", "reciprocal"), matchResolution( - "lib/liba.so.meta_lic", "lib/liba.so.meta_lic", "lib/liba.so.meta_lic", "reciprocal"), @@ -2473,7 +1993,7 @@ func Test_graphviz(t *testing.T) { name: "apex_trimmed_private", roots: []string{"highest.apex.meta_lic"}, ctx: context{ - conditions: []string{"proprietary"}, + conditions: compliance.ImpliesPrivate.AsList(), stripPrefix: "testdata/reciprocal/", }, expectedOut: []getMatcher{}, @@ -2483,7 +2003,7 @@ func Test_graphviz(t *testing.T) { name: "apex_trimmed_share_private", roots: []string{"highest.apex.meta_lic"}, ctx: context{ - conditions: []string{"reciprocal", "restricted", "proprietary"}, + conditions: compliance.ImpliesShared.Union(compliance.ImpliesPrivate).AsList(), stripPrefix: "testdata/reciprocal/", }, expectedOut: []getMatcher{ @@ -2494,25 +2014,20 @@ func Test_graphviz(t *testing.T) { matchResolution( "bin/bin1.meta_lic", "lib/liba.so.meta_lic", - "lib/liba.so.meta_lic", "reciprocal"), matchResolution( "bin/bin1.meta_lic", "lib/libc.a.meta_lic", - "lib/libc.a.meta_lic", "reciprocal"), matchResolution( "highest.apex.meta_lic", "lib/liba.so.meta_lic", - "lib/liba.so.meta_lic", "reciprocal"), matchResolution( "highest.apex.meta_lic", "lib/libc.a.meta_lic", - "lib/libc.a.meta_lic", "reciprocal"), matchResolution( - "lib/liba.so.meta_lic", "lib/liba.so.meta_lic", "lib/liba.so.meta_lic", "reciprocal"), @@ -2530,76 +2045,53 @@ func Test_graphviz(t *testing.T) { matchTarget("bin/bin2.meta_lic", "notice"), matchTarget("highest.apex.meta_lic", "notice"), matchTarget("lib/libb.so.meta_lic", "notice"), - matchTarget("lib/libd.so.meta_lic", "notice"), matchResolution( - "bin/bin1.meta_lic", "bin/bin1.meta_lic", "bin/bin1.meta_lic", "notice"), matchResolution( "bin/bin1.meta_lic", "lib/liba.so.meta_lic", - "lib/liba.so.meta_lic", "reciprocal"), matchResolution( "bin/bin1.meta_lic", "lib/libc.a.meta_lic", - "lib/libc.a.meta_lic", "reciprocal"), matchResolution( - "bin/bin2.meta_lic", "bin/bin2.meta_lic", "bin/bin2.meta_lic", "notice"), matchResolution( "highest.apex.meta_lic", "bin/bin1.meta_lic", - "bin/bin1.meta_lic", "notice"), matchResolution( "highest.apex.meta_lic", "bin/bin2.meta_lic", - "bin/bin2.meta_lic", "notice"), matchResolution( - "highest.apex.meta_lic", "highest.apex.meta_lic", "highest.apex.meta_lic", "notice"), matchResolution( "highest.apex.meta_lic", "lib/liba.so.meta_lic", - "lib/liba.so.meta_lic", "reciprocal"), matchResolution( "highest.apex.meta_lic", "lib/libb.so.meta_lic", - "lib/libb.so.meta_lic", "notice"), matchResolution( "highest.apex.meta_lic", "lib/libc.a.meta_lic", - "lib/libc.a.meta_lic", "reciprocal"), matchResolution( - "lib/liba.so.meta_lic", "lib/liba.so.meta_lic", "lib/liba.so.meta_lic", "reciprocal"), matchResolution( "lib/libb.so.meta_lic", "lib/libb.so.meta_lic", - "lib/libb.so.meta_lic", - "notice"), - matchResolution( - "lib/libc.a.meta_lic", - "lib/libc.a.meta_lic", - "lib/libc.a.meta_lic", - "reciprocal"), - matchResolution( - "lib/libd.so.meta_lic", - "lib/libd.so.meta_lic", - "lib/libd.so.meta_lic", "notice"), }, }, @@ -2614,76 +2106,53 @@ func Test_graphviz(t *testing.T) { matchTarget("testdata/reciprocal/bin/bin2.meta_lic"), matchTarget("testdata/reciprocal/container.zip.meta_lic"), matchTarget("testdata/reciprocal/lib/libb.so.meta_lic"), - matchTarget("testdata/reciprocal/lib/libd.so.meta_lic"), matchResolution( - "testdata/reciprocal/bin/bin1.meta_lic", "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", - "testdata/reciprocal/lib/liba.so.meta_lic", "reciprocal"), matchResolution( "testdata/reciprocal/bin/bin1.meta_lic", "testdata/reciprocal/lib/libc.a.meta_lic", - "testdata/reciprocal/lib/libc.a.meta_lic", "reciprocal"), matchResolution( - "testdata/reciprocal/bin/bin2.meta_lic", "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", - "testdata/reciprocal/bin/bin1.meta_lic", "notice"), matchResolution( "testdata/reciprocal/container.zip.meta_lic", "testdata/reciprocal/bin/bin2.meta_lic", - "testdata/reciprocal/bin/bin2.meta_lic", "notice"), matchResolution( - "testdata/reciprocal/container.zip.meta_lic", "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", - "testdata/reciprocal/lib/liba.so.meta_lic", "reciprocal"), matchResolution( "testdata/reciprocal/container.zip.meta_lic", "testdata/reciprocal/lib/libb.so.meta_lic", - "testdata/reciprocal/lib/libb.so.meta_lic", "notice"), matchResolution( "testdata/reciprocal/container.zip.meta_lic", "testdata/reciprocal/lib/libc.a.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", "testdata/reciprocal/lib/liba.so.meta_lic", "reciprocal"), matchResolution( "testdata/reciprocal/lib/libb.so.meta_lic", "testdata/reciprocal/lib/libb.so.meta_lic", - "testdata/reciprocal/lib/libb.so.meta_lic", - "notice"), - matchResolution( - "testdata/reciprocal/lib/libc.a.meta_lic", - "testdata/reciprocal/lib/libc.a.meta_lic", - "testdata/reciprocal/lib/libc.a.meta_lic", - "reciprocal"), - matchResolution( - "testdata/reciprocal/lib/libd.so.meta_lic", - "testdata/reciprocal/lib/libd.so.meta_lic", - "testdata/reciprocal/lib/libd.so.meta_lic", "notice"), }, }, @@ -2694,33 +2163,14 @@ func Test_graphviz(t *testing.T) { expectedOut: []getMatcher{ matchTarget("testdata/reciprocal/application.meta_lic"), matchTarget("testdata/reciprocal/lib/liba.so.meta_lic"), - matchTarget("testdata/reciprocal/bin/bin3.meta_lic"), - matchTarget("testdata/reciprocal/lib/libb.so.meta_lic"), matchResolution( - "testdata/reciprocal/application.meta_lic", "testdata/reciprocal/application.meta_lic", "testdata/reciprocal/application.meta_lic", "notice"), matchResolution( "testdata/reciprocal/application.meta_lic", "testdata/reciprocal/lib/liba.so.meta_lic", - "testdata/reciprocal/lib/liba.so.meta_lic", "reciprocal"), - matchResolution( - "testdata/reciprocal/bin/bin3.meta_lic", - "testdata/reciprocal/bin/bin3.meta_lic", - "testdata/reciprocal/bin/bin3.meta_lic", - "notice"), - matchResolution( - "testdata/reciprocal/lib/liba.so.meta_lic", - "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", - "testdata/reciprocal/lib/libb.so.meta_lic", - "notice"), }, }, { @@ -2732,29 +2182,16 @@ func Test_graphviz(t *testing.T) { 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", "testdata/reciprocal/bin/bin1.meta_lic", "notice"), matchResolution( "testdata/reciprocal/bin/bin1.meta_lic", "testdata/reciprocal/lib/liba.so.meta_lic", - "testdata/reciprocal/lib/liba.so.meta_lic", "reciprocal"), matchResolution( "testdata/reciprocal/bin/bin1.meta_lic", "testdata/reciprocal/lib/libc.a.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", - "testdata/reciprocal/lib/liba.so.meta_lic", - "reciprocal"), - matchResolution( - "testdata/reciprocal/lib/libc.a.meta_lic", - "testdata/reciprocal/lib/libc.a.meta_lic", - "testdata/reciprocal/lib/libc.a.meta_lic", "reciprocal"), }, }, @@ -2765,7 +2202,6 @@ func Test_graphviz(t *testing.T) { 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", "testdata/reciprocal/lib/libd.so.meta_lic", "notice"), @@ -2781,143 +2217,67 @@ func Test_graphviz(t *testing.T) { 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/lib/libd.so.meta_lic"), matchTarget("testdata/restricted/highest.apex.meta_lic"), matchResolution( "testdata/restricted/bin/bin1.meta_lic", "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/bin/bin1.meta_lic", "testdata/restricted/lib/liba.so.meta_lic", - "restricted"), - matchResolution( - "testdata/restricted/bin/bin1.meta_lic", - "testdata/restricted/lib/liba.so.meta_lic", - "testdata/restricted/lib/liba.so.meta_lic", - "restricted"), + "restricted_allows_dynamic_linking"), matchResolution( "testdata/restricted/bin/bin1.meta_lic", "testdata/restricted/lib/libc.a.meta_lic", - "testdata/restricted/lib/liba.so.meta_lic", - "restricted"), - matchResolution( - "testdata/restricted/bin/bin1.meta_lic", - "testdata/restricted/lib/libc.a.meta_lic", - "testdata/restricted/lib/libc.a.meta_lic", - "reciprocal"), + "reciprocal", + "restricted_allows_dynamic_linking"), matchResolution( "testdata/restricted/bin/bin2.meta_lic", "testdata/restricted/bin/bin2.meta_lic", - "testdata/restricted/bin/bin2.meta_lic", + "restricted", "notice"), matchResolution( "testdata/restricted/bin/bin2.meta_lic", - "testdata/restricted/bin/bin2.meta_lic", - "testdata/restricted/lib/libb.so.meta_lic", - "restricted"), - matchResolution( - "testdata/restricted/bin/bin2.meta_lic", - "testdata/restricted/lib/libb.so.meta_lic", - "testdata/restricted/lib/libb.so.meta_lic", - "restricted"), - matchResolution( - "testdata/restricted/bin/bin2.meta_lic", - "testdata/restricted/lib/libd.so.meta_lic", "testdata/restricted/lib/libb.so.meta_lic", "restricted"), matchResolution( "testdata/restricted/highest.apex.meta_lic", "testdata/restricted/bin/bin1.meta_lic", - "testdata/restricted/bin/bin1.meta_lic", - "notice"), - matchResolution( - "testdata/restricted/highest.apex.meta_lic", - "testdata/restricted/bin/bin1.meta_lic", - "testdata/restricted/lib/liba.so.meta_lic", - "restricted"), - matchResolution( - "testdata/restricted/highest.apex.meta_lic", - "testdata/restricted/bin/bin2.meta_lic", - "testdata/restricted/bin/bin2.meta_lic", + "restricted_allows_dynamic_linking", "notice"), matchResolution( "testdata/restricted/highest.apex.meta_lic", "testdata/restricted/bin/bin2.meta_lic", - "testdata/restricted/lib/libb.so.meta_lic", - "restricted"), - matchResolution( - "testdata/restricted/highest.apex.meta_lic", - "testdata/restricted/highest.apex.meta_lic", - "testdata/restricted/highest.apex.meta_lic", + "restricted", "notice"), matchResolution( "testdata/restricted/highest.apex.meta_lic", "testdata/restricted/highest.apex.meta_lic", - "testdata/restricted/lib/liba.so.meta_lic", - "restricted"), - matchResolution( - "testdata/restricted/highest.apex.meta_lic", - "testdata/restricted/highest.apex.meta_lic", - "testdata/restricted/lib/libb.so.meta_lic", - "restricted"), - matchResolution( - "testdata/restricted/highest.apex.meta_lic", - "testdata/restricted/lib/liba.so.meta_lic", - "testdata/restricted/lib/liba.so.meta_lic", - "restricted"), - matchResolution( - "testdata/restricted/highest.apex.meta_lic", - "testdata/restricted/lib/libb.so.meta_lic", - "testdata/restricted/lib/libb.so.meta_lic", - "restricted"), - matchResolution( - "testdata/restricted/highest.apex.meta_lic", - "testdata/restricted/lib/libc.a.meta_lic", - "testdata/restricted/lib/liba.so.meta_lic", - "restricted"), - matchResolution( - "testdata/restricted/highest.apex.meta_lic", - "testdata/restricted/lib/libc.a.meta_lic", - "testdata/restricted/lib/libc.a.meta_lic", - "reciprocal"), - matchResolution( - "testdata/restricted/highest.apex.meta_lic", - "testdata/restricted/lib/libd.so.meta_lic", - "testdata/restricted/lib/libb.so.meta_lic", - "restricted"), - matchResolution( - "testdata/restricted/lib/liba.so.meta_lic", - "testdata/restricted/lib/liba.so.meta_lic", - "testdata/restricted/lib/liba.so.meta_lic", - "restricted"), - matchResolution( - "testdata/restricted/lib/libb.so.meta_lic", - "testdata/restricted/lib/libb.so.meta_lic", - "testdata/restricted/lib/libb.so.meta_lic", - "restricted"), - matchResolution( - "testdata/restricted/lib/libc.a.meta_lic", - "testdata/restricted/lib/libc.a.meta_lic", - "testdata/restricted/lib/liba.so.meta_lic", - "restricted"), - matchResolution( - "testdata/restricted/lib/libc.a.meta_lic", - "testdata/restricted/lib/libc.a.meta_lic", - "testdata/restricted/lib/libc.a.meta_lic", - "reciprocal"), - matchResolution( - "testdata/restricted/lib/libd.so.meta_lic", - "testdata/restricted/lib/libd.so.meta_lic", - "testdata/restricted/lib/libb.so.meta_lic", - "restricted"), - matchResolution( - "testdata/restricted/lib/libd.so.meta_lic", - "testdata/restricted/lib/libd.so.meta_lic", - "testdata/restricted/lib/libd.so.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"), }, }, { @@ -2931,143 +2291,67 @@ func Test_graphviz(t *testing.T) { matchTarget("lib/libc.a.meta_lic"), matchTarget("bin/bin2.meta_lic"), matchTarget("lib/libb.so.meta_lic"), - matchTarget("lib/libd.so.meta_lic"), matchTarget("highest.apex.meta_lic"), matchResolution( "bin/bin1.meta_lic", "bin/bin1.meta_lic", - "bin/bin1.meta_lic", + "restricted_allows_dynamic_linking", "notice"), matchResolution( - "bin/bin1.meta_lic", "bin/bin1.meta_lic", "lib/liba.so.meta_lic", - "restricted"), - matchResolution( - "bin/bin1.meta_lic", - "lib/liba.so.meta_lic", - "lib/liba.so.meta_lic", - "restricted"), + "restricted_allows_dynamic_linking"), matchResolution( "bin/bin1.meta_lic", "lib/libc.a.meta_lic", - "lib/liba.so.meta_lic", - "restricted"), - matchResolution( - "bin/bin1.meta_lic", - "lib/libc.a.meta_lic", - "lib/libc.a.meta_lic", - "reciprocal"), + "reciprocal", + "restricted_allows_dynamic_linking"), matchResolution( "bin/bin2.meta_lic", "bin/bin2.meta_lic", - "bin/bin2.meta_lic", + "restricted", "notice"), matchResolution( "bin/bin2.meta_lic", - "bin/bin2.meta_lic", - "lib/libb.so.meta_lic", - "restricted"), - matchResolution( - "bin/bin2.meta_lic", - "lib/libb.so.meta_lic", - "lib/libb.so.meta_lic", - "restricted"), - matchResolution( - "bin/bin2.meta_lic", - "lib/libd.so.meta_lic", "lib/libb.so.meta_lic", "restricted"), matchResolution( "highest.apex.meta_lic", "bin/bin1.meta_lic", - "bin/bin1.meta_lic", - "notice"), - matchResolution( - "highest.apex.meta_lic", - "bin/bin1.meta_lic", - "lib/liba.so.meta_lic", - "restricted"), - matchResolution( - "highest.apex.meta_lic", - "bin/bin2.meta_lic", - "bin/bin2.meta_lic", + "restricted_allows_dynamic_linking", "notice"), matchResolution( "highest.apex.meta_lic", "bin/bin2.meta_lic", - "lib/libb.so.meta_lic", - "restricted"), - matchResolution( - "highest.apex.meta_lic", - "highest.apex.meta_lic", - "highest.apex.meta_lic", + "restricted", "notice"), matchResolution( "highest.apex.meta_lic", "highest.apex.meta_lic", - "lib/liba.so.meta_lic", - "restricted"), - matchResolution( - "highest.apex.meta_lic", - "highest.apex.meta_lic", - "lib/libb.so.meta_lic", - "restricted"), - matchResolution( - "highest.apex.meta_lic", - "lib/liba.so.meta_lic", - "lib/liba.so.meta_lic", - "restricted"), - matchResolution( - "highest.apex.meta_lic", - "lib/libb.so.meta_lic", - "lib/libb.so.meta_lic", - "restricted"), - matchResolution( - "highest.apex.meta_lic", - "lib/libc.a.meta_lic", - "lib/liba.so.meta_lic", - "restricted"), - matchResolution( - "highest.apex.meta_lic", - "lib/libc.a.meta_lic", - "lib/libc.a.meta_lic", - "reciprocal"), - matchResolution( - "highest.apex.meta_lic", - "lib/libd.so.meta_lic", - "lib/libb.so.meta_lic", - "restricted"), - matchResolution( - "lib/liba.so.meta_lic", - "lib/liba.so.meta_lic", - "lib/liba.so.meta_lic", - "restricted"), - matchResolution( - "lib/libb.so.meta_lic", - "lib/libb.so.meta_lic", - "lib/libb.so.meta_lic", - "restricted"), - matchResolution( - "lib/libc.a.meta_lic", - "lib/libc.a.meta_lic", - "lib/liba.so.meta_lic", - "restricted"), - matchResolution( - "lib/libc.a.meta_lic", - "lib/libc.a.meta_lic", - "lib/libc.a.meta_lic", - "reciprocal"), - matchResolution( - "lib/libd.so.meta_lic", - "lib/libd.so.meta_lic", - "lib/libb.so.meta_lic", - "restricted"), - matchResolution( - "lib/libd.so.meta_lic", - "lib/libd.so.meta_lic", - "lib/libd.so.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"), }, }, { @@ -3075,7 +2359,7 @@ func Test_graphviz(t *testing.T) { name: "apex_trimmed_notice", roots: []string{"highest.apex.meta_lic"}, ctx: context{ - conditions: []string{"notice"}, + conditions: []compliance.LicenseCondition{compliance.NoticeCondition}, stripPrefix: "testdata/restricted/", }, expectedOut: []getMatcher{ @@ -3083,27 +2367,22 @@ func Test_graphviz(t *testing.T) { matchTarget("bin/bin2.meta_lic"), matchTarget("highest.apex.meta_lic"), matchResolution( - "bin/bin1.meta_lic", "bin/bin1.meta_lic", "bin/bin1.meta_lic", "notice"), matchResolution( - "bin/bin2.meta_lic", "bin/bin2.meta_lic", "bin/bin2.meta_lic", "notice"), matchResolution( "highest.apex.meta_lic", "bin/bin1.meta_lic", - "bin/bin1.meta_lic", "notice"), matchResolution( "highest.apex.meta_lic", "bin/bin2.meta_lic", - "bin/bin2.meta_lic", "notice"), matchResolution( - "highest.apex.meta_lic", "highest.apex.meta_lic", "highest.apex.meta_lic", "notice"), @@ -3114,7 +2393,7 @@ func Test_graphviz(t *testing.T) { name: "apex_trimmed_share", roots: []string{"highest.apex.meta_lic"}, ctx: context{ - conditions: []string{"reciprocal", "restricted"}, + conditions: compliance.ImpliesShared.AsList(), stripPrefix: "testdata/restricted/", }, expectedOut: []getMatcher{ @@ -3127,80 +2406,55 @@ func Test_graphviz(t *testing.T) { matchResolution( "bin/bin1.meta_lic", "bin/bin1.meta_lic", - "lib/liba.so.meta_lic", - "restricted"), + "restricted_allows_dynamic_linking"), matchResolution( "bin/bin1.meta_lic", "lib/liba.so.meta_lic", - "lib/liba.so.meta_lic", - "restricted"), + "restricted_allows_dynamic_linking"), matchResolution( "bin/bin1.meta_lic", "lib/libc.a.meta_lic", - "lib/liba.so.meta_lic", - "restricted"), - matchResolution( - "bin/bin1.meta_lic", - "lib/libc.a.meta_lic", - "lib/libc.a.meta_lic", - "reciprocal"), + "reciprocal", + "restricted_allows_dynamic_linking"), matchResolution( "bin/bin2.meta_lic", "bin/bin2.meta_lic", - "lib/libb.so.meta_lic", "restricted"), matchResolution( - "bin/bin2.meta_lic", - "lib/libb.so.meta_lic", - "lib/libb.so.meta_lic", - "restricted"), - matchResolution( - "highest.apex.meta_lic", - "bin/bin1.meta_lic", - "lib/liba.so.meta_lic", - "restricted"), - matchResolution( - "highest.apex.meta_lic", "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", - "lib/liba.so.meta_lic", + "bin/bin2.meta_lic", "restricted"), matchResolution( "highest.apex.meta_lic", "highest.apex.meta_lic", - "lib/libb.so.meta_lic", - "restricted"), + "restricted", + "restricted_allows_dynamic_linking"), matchResolution( "highest.apex.meta_lic", "lib/liba.so.meta_lic", - "lib/liba.so.meta_lic", - "restricted"), + "restricted_allows_dynamic_linking"), matchResolution( "highest.apex.meta_lic", "lib/libb.so.meta_lic", - "lib/libb.so.meta_lic", "restricted"), matchResolution( "highest.apex.meta_lic", "lib/libc.a.meta_lic", - "lib/liba.so.meta_lic", - "restricted"), - matchResolution( - "highest.apex.meta_lic", - "lib/libc.a.meta_lic", - "lib/libc.a.meta_lic", - "reciprocal"), + "reciprocal", + "restricted_allows_dynamic_linking"), matchResolution( "lib/liba.so.meta_lic", "lib/liba.so.meta_lic", - "lib/liba.so.meta_lic", - "restricted"), + "restricted_allows_dynamic_linking"), matchResolution( - "lib/libb.so.meta_lic", "lib/libb.so.meta_lic", "lib/libb.so.meta_lic", "restricted"), @@ -3211,7 +2465,7 @@ func Test_graphviz(t *testing.T) { name: "apex_trimmed_private", roots: []string{"highest.apex.meta_lic"}, ctx: context{ - conditions: []string{"proprietary"}, + conditions: compliance.ImpliesPrivate.AsList(), stripPrefix: "testdata/restricted/", }, expectedOut: []getMatcher{}, @@ -3221,7 +2475,7 @@ func Test_graphviz(t *testing.T) { name: "apex_trimmed_share_private", roots: []string{"highest.apex.meta_lic"}, ctx: context{ - conditions: []string{"reciprocal", "restricted", "proprietary"}, + conditions: compliance.ImpliesShared.Union(compliance.ImpliesPrivate).AsList(), stripPrefix: "testdata/restricted/", }, expectedOut: []getMatcher{ @@ -3234,80 +2488,55 @@ func Test_graphviz(t *testing.T) { matchResolution( "bin/bin1.meta_lic", "bin/bin1.meta_lic", - "lib/liba.so.meta_lic", - "restricted"), + "restricted_allows_dynamic_linking"), matchResolution( "bin/bin1.meta_lic", "lib/liba.so.meta_lic", - "lib/liba.so.meta_lic", - "restricted"), + "restricted_allows_dynamic_linking"), matchResolution( "bin/bin1.meta_lic", "lib/libc.a.meta_lic", - "lib/liba.so.meta_lic", - "restricted"), - matchResolution( - "bin/bin1.meta_lic", - "lib/libc.a.meta_lic", - "lib/libc.a.meta_lic", - "reciprocal"), + "reciprocal", + "restricted_allows_dynamic_linking"), matchResolution( "bin/bin2.meta_lic", "bin/bin2.meta_lic", - "lib/libb.so.meta_lic", "restricted"), matchResolution( - "bin/bin2.meta_lic", - "lib/libb.so.meta_lic", - "lib/libb.so.meta_lic", - "restricted"), - matchResolution( - "highest.apex.meta_lic", - "bin/bin1.meta_lic", - "lib/liba.so.meta_lic", - "restricted"), - matchResolution( - "highest.apex.meta_lic", "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", - "lib/liba.so.meta_lic", + "bin/bin2.meta_lic", "restricted"), matchResolution( "highest.apex.meta_lic", "highest.apex.meta_lic", - "lib/libb.so.meta_lic", - "restricted"), + "restricted", + "restricted_allows_dynamic_linking"), matchResolution( "highest.apex.meta_lic", "lib/liba.so.meta_lic", - "lib/liba.so.meta_lic", - "restricted"), + "restricted_allows_dynamic_linking"), matchResolution( "highest.apex.meta_lic", "lib/libb.so.meta_lic", - "lib/libb.so.meta_lic", "restricted"), matchResolution( "highest.apex.meta_lic", "lib/libc.a.meta_lic", - "lib/liba.so.meta_lic", - "restricted"), - matchResolution( - "highest.apex.meta_lic", - "lib/libc.a.meta_lic", - "lib/libc.a.meta_lic", - "reciprocal"), + "reciprocal", + "restricted_allows_dynamic_linking"), matchResolution( "lib/liba.so.meta_lic", "lib/liba.so.meta_lic", - "lib/liba.so.meta_lic", - "restricted"), + "restricted_allows_dynamic_linking"), matchResolution( - "lib/libb.so.meta_lic", "lib/libb.so.meta_lic", "lib/libb.so.meta_lic", "restricted"), @@ -3320,147 +2549,71 @@ func Test_graphviz(t *testing.T) { ctx: context{stripPrefix: "testdata/restricted/", labelConditions: true}, expectedOut: []getMatcher{ matchTarget("bin/bin1.meta_lic", "notice"), - matchTarget("lib/liba.so.meta_lic", "restricted"), + 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("lib/libd.so.meta_lic", "notice"), matchTarget("highest.apex.meta_lic", "notice"), matchResolution( "bin/bin1.meta_lic", "bin/bin1.meta_lic", - "bin/bin1.meta_lic", + "restricted_allows_dynamic_linking", "notice"), matchResolution( - "bin/bin1.meta_lic", "bin/bin1.meta_lic", "lib/liba.so.meta_lic", - "restricted"), - matchResolution( - "bin/bin1.meta_lic", - "lib/liba.so.meta_lic", - "lib/liba.so.meta_lic", - "restricted"), + "restricted_allows_dynamic_linking"), matchResolution( "bin/bin1.meta_lic", "lib/libc.a.meta_lic", - "lib/liba.so.meta_lic", - "restricted"), - matchResolution( - "bin/bin1.meta_lic", - "lib/libc.a.meta_lic", - "lib/libc.a.meta_lic", - "reciprocal"), + "reciprocal", + "restricted_allows_dynamic_linking"), matchResolution( "bin/bin2.meta_lic", "bin/bin2.meta_lic", - "bin/bin2.meta_lic", + "restricted", "notice"), matchResolution( "bin/bin2.meta_lic", - "bin/bin2.meta_lic", - "lib/libb.so.meta_lic", - "restricted"), - matchResolution( - "bin/bin2.meta_lic", - "lib/libb.so.meta_lic", - "lib/libb.so.meta_lic", - "restricted"), - matchResolution( - "bin/bin2.meta_lic", - "lib/libd.so.meta_lic", "lib/libb.so.meta_lic", "restricted"), matchResolution( "highest.apex.meta_lic", "bin/bin1.meta_lic", - "bin/bin1.meta_lic", - "notice"), - matchResolution( - "highest.apex.meta_lic", - "bin/bin1.meta_lic", - "lib/liba.so.meta_lic", - "restricted"), - matchResolution( - "highest.apex.meta_lic", - "bin/bin2.meta_lic", - "bin/bin2.meta_lic", + "restricted_allows_dynamic_linking", "notice"), matchResolution( "highest.apex.meta_lic", "bin/bin2.meta_lic", - "lib/libb.so.meta_lic", - "restricted"), - matchResolution( - "highest.apex.meta_lic", - "highest.apex.meta_lic", - "highest.apex.meta_lic", + "restricted", "notice"), matchResolution( "highest.apex.meta_lic", "highest.apex.meta_lic", - "lib/liba.so.meta_lic", - "restricted"), - matchResolution( - "highest.apex.meta_lic", - "highest.apex.meta_lic", - "lib/libb.so.meta_lic", - "restricted"), - matchResolution( - "highest.apex.meta_lic", - "lib/liba.so.meta_lic", - "lib/liba.so.meta_lic", - "restricted"), - matchResolution( - "highest.apex.meta_lic", - "lib/libb.so.meta_lic", - "lib/libb.so.meta_lic", - "restricted"), - matchResolution( - "highest.apex.meta_lic", - "lib/libc.a.meta_lic", - "lib/liba.so.meta_lic", - "restricted"), - matchResolution( - "highest.apex.meta_lic", - "lib/libc.a.meta_lic", - "lib/libc.a.meta_lic", - "reciprocal"), - matchResolution( - "highest.apex.meta_lic", - "lib/libd.so.meta_lic", - "lib/libb.so.meta_lic", - "restricted"), - matchResolution( - "lib/liba.so.meta_lic", - "lib/liba.so.meta_lic", - "lib/liba.so.meta_lic", - "restricted"), - matchResolution( - "lib/libb.so.meta_lic", - "lib/libb.so.meta_lic", - "lib/libb.so.meta_lic", - "restricted"), - matchResolution( - "lib/libc.a.meta_lic", - "lib/libc.a.meta_lic", - "lib/liba.so.meta_lic", - "restricted"), - matchResolution( - "lib/libc.a.meta_lic", - "lib/libc.a.meta_lic", - "lib/libc.a.meta_lic", - "reciprocal"), - matchResolution( - "lib/libd.so.meta_lic", - "lib/libd.so.meta_lic", - "lib/libb.so.meta_lic", - "restricted"), - matchResolution( - "lib/libd.so.meta_lic", - "lib/libd.so.meta_lic", - "lib/libd.so.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"), }, }, { @@ -3473,143 +2626,67 @@ func Test_graphviz(t *testing.T) { 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/lib/libd.so.meta_lic"), matchTarget("testdata/restricted/container.zip.meta_lic"), matchResolution( "testdata/restricted/bin/bin1.meta_lic", "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/bin/bin1.meta_lic", "testdata/restricted/lib/liba.so.meta_lic", - "restricted"), - matchResolution( - "testdata/restricted/bin/bin1.meta_lic", - "testdata/restricted/lib/liba.so.meta_lic", - "testdata/restricted/lib/liba.so.meta_lic", - "restricted"), + "restricted_allows_dynamic_linking"), matchResolution( "testdata/restricted/bin/bin1.meta_lic", "testdata/restricted/lib/libc.a.meta_lic", - "testdata/restricted/lib/liba.so.meta_lic", - "restricted"), - matchResolution( - "testdata/restricted/bin/bin1.meta_lic", - "testdata/restricted/lib/libc.a.meta_lic", - "testdata/restricted/lib/libc.a.meta_lic", - "reciprocal"), + "reciprocal", + "restricted_allows_dynamic_linking"), matchResolution( "testdata/restricted/bin/bin2.meta_lic", "testdata/restricted/bin/bin2.meta_lic", - "testdata/restricted/bin/bin2.meta_lic", + "restricted", "notice"), matchResolution( "testdata/restricted/bin/bin2.meta_lic", - "testdata/restricted/bin/bin2.meta_lic", - "testdata/restricted/lib/libb.so.meta_lic", - "restricted"), - matchResolution( - "testdata/restricted/bin/bin2.meta_lic", - "testdata/restricted/lib/libb.so.meta_lic", - "testdata/restricted/lib/libb.so.meta_lic", - "restricted"), - matchResolution( - "testdata/restricted/bin/bin2.meta_lic", - "testdata/restricted/lib/libd.so.meta_lic", "testdata/restricted/lib/libb.so.meta_lic", "restricted"), matchResolution( "testdata/restricted/container.zip.meta_lic", "testdata/restricted/bin/bin1.meta_lic", - "testdata/restricted/bin/bin1.meta_lic", - "notice"), - matchResolution( - "testdata/restricted/container.zip.meta_lic", - "testdata/restricted/bin/bin1.meta_lic", - "testdata/restricted/lib/liba.so.meta_lic", - "restricted"), - matchResolution( - "testdata/restricted/container.zip.meta_lic", - "testdata/restricted/bin/bin2.meta_lic", - "testdata/restricted/bin/bin2.meta_lic", + "restricted_allows_dynamic_linking", "notice"), matchResolution( "testdata/restricted/container.zip.meta_lic", "testdata/restricted/bin/bin2.meta_lic", - "testdata/restricted/lib/libb.so.meta_lic", - "restricted"), - matchResolution( - "testdata/restricted/container.zip.meta_lic", - "testdata/restricted/container.zip.meta_lic", - "testdata/restricted/container.zip.meta_lic", + "restricted", "notice"), matchResolution( "testdata/restricted/container.zip.meta_lic", "testdata/restricted/container.zip.meta_lic", - "testdata/restricted/lib/liba.so.meta_lic", - "restricted"), - matchResolution( - "testdata/restricted/container.zip.meta_lic", - "testdata/restricted/container.zip.meta_lic", - "testdata/restricted/lib/libb.so.meta_lic", - "restricted"), - matchResolution( - "testdata/restricted/container.zip.meta_lic", - "testdata/restricted/lib/liba.so.meta_lic", - "testdata/restricted/lib/liba.so.meta_lic", - "restricted"), - matchResolution( - "testdata/restricted/container.zip.meta_lic", - "testdata/restricted/lib/libb.so.meta_lic", - "testdata/restricted/lib/libb.so.meta_lic", - "restricted"), - matchResolution( - "testdata/restricted/container.zip.meta_lic", - "testdata/restricted/lib/libc.a.meta_lic", - "testdata/restricted/lib/liba.so.meta_lic", - "restricted"), - matchResolution( - "testdata/restricted/container.zip.meta_lic", - "testdata/restricted/lib/libc.a.meta_lic", - "testdata/restricted/lib/libc.a.meta_lic", - "reciprocal"), - matchResolution( - "testdata/restricted/container.zip.meta_lic", - "testdata/restricted/lib/libd.so.meta_lic", - "testdata/restricted/lib/libb.so.meta_lic", - "restricted"), - matchResolution( - "testdata/restricted/lib/liba.so.meta_lic", - "testdata/restricted/lib/liba.so.meta_lic", - "testdata/restricted/lib/liba.so.meta_lic", - "restricted"), - matchResolution( - "testdata/restricted/lib/libb.so.meta_lic", - "testdata/restricted/lib/libb.so.meta_lic", - "testdata/restricted/lib/libb.so.meta_lic", - "restricted"), - matchResolution( - "testdata/restricted/lib/libc.a.meta_lic", - "testdata/restricted/lib/libc.a.meta_lic", - "testdata/restricted/lib/liba.so.meta_lic", - "restricted"), - matchResolution( - "testdata/restricted/lib/libc.a.meta_lic", - "testdata/restricted/lib/libc.a.meta_lic", - "testdata/restricted/lib/libc.a.meta_lic", - "reciprocal"), - matchResolution( - "testdata/restricted/lib/libd.so.meta_lic", - "testdata/restricted/lib/libd.so.meta_lic", - "testdata/restricted/lib/libb.so.meta_lic", - "restricted"), - matchResolution( - "testdata/restricted/lib/libd.so.meta_lic", - "testdata/restricted/lib/libd.so.meta_lic", - "testdata/restricted/lib/libd.so.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"), }, }, { @@ -3619,57 +2696,16 @@ func Test_graphviz(t *testing.T) { expectedOut: []getMatcher{ matchTarget("testdata/restricted/application.meta_lic"), matchTarget("testdata/restricted/lib/liba.so.meta_lic"), - matchTarget("testdata/restricted/lib/libb.so.meta_lic"), - matchTarget("testdata/restricted/bin/bin3.meta_lic"), matchResolution( "testdata/restricted/application.meta_lic", "testdata/restricted/application.meta_lic", - "testdata/restricted/application.meta_lic", + "restricted", + "restricted_allows_dynamic_linking", "notice"), matchResolution( - "testdata/restricted/application.meta_lic", "testdata/restricted/application.meta_lic", "testdata/restricted/lib/liba.so.meta_lic", - "restricted"), - matchResolution( - "testdata/restricted/application.meta_lic", - "testdata/restricted/application.meta_lic", - "testdata/restricted/lib/libb.so.meta_lic", - "restricted"), - matchResolution( - "testdata/restricted/application.meta_lic", - "testdata/restricted/lib/liba.so.meta_lic", - "testdata/restricted/lib/liba.so.meta_lic", - "restricted"), - matchResolution( - "testdata/restricted/application.meta_lic", - "testdata/restricted/lib/liba.so.meta_lic", - "testdata/restricted/lib/libb.so.meta_lic", - "restricted"), - matchResolution( - "testdata/restricted/application.meta_lic", - "testdata/restricted/lib/libb.so.meta_lic", - "testdata/restricted/lib/libb.so.meta_lic", - "restricted"), - matchResolution( - "testdata/restricted/bin/bin3.meta_lic", - "testdata/restricted/bin/bin3.meta_lic", - "testdata/restricted/bin/bin3.meta_lic", - "restricted"), - matchResolution( - "testdata/restricted/lib/liba.so.meta_lic", - "testdata/restricted/lib/liba.so.meta_lic", - "testdata/restricted/lib/liba.so.meta_lic", - "restricted"), - matchResolution( - "testdata/restricted/lib/liba.so.meta_lic", - "testdata/restricted/lib/liba.so.meta_lic", - "testdata/restricted/lib/libb.so.meta_lic", - "restricted"), - matchResolution( - "testdata/restricted/lib/libb.so.meta_lic", - "testdata/restricted/lib/libb.so.meta_lic", - "testdata/restricted/lib/libb.so.meta_lic", + "restricted_allows_dynamic_linking", "restricted"), }, }, @@ -3684,42 +2720,16 @@ func Test_graphviz(t *testing.T) { matchResolution( "testdata/restricted/bin/bin1.meta_lic", "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/bin/bin1.meta_lic", "testdata/restricted/lib/liba.so.meta_lic", - "restricted"), - matchResolution( - "testdata/restricted/bin/bin1.meta_lic", - "testdata/restricted/lib/liba.so.meta_lic", - "testdata/restricted/lib/liba.so.meta_lic", - "restricted"), + "restricted_allows_dynamic_linking"), matchResolution( "testdata/restricted/bin/bin1.meta_lic", "testdata/restricted/lib/libc.a.meta_lic", - "testdata/restricted/lib/liba.so.meta_lic", - "restricted"), - matchResolution( - "testdata/restricted/bin/bin1.meta_lic", - "testdata/restricted/lib/libc.a.meta_lic", - "testdata/restricted/lib/libc.a.meta_lic", - "reciprocal"), - matchResolution( - "testdata/restricted/lib/liba.so.meta_lic", - "testdata/restricted/lib/liba.so.meta_lic", - "testdata/restricted/lib/liba.so.meta_lic", - "restricted"), - matchResolution( - "testdata/restricted/lib/libc.a.meta_lic", - "testdata/restricted/lib/libc.a.meta_lic", - "testdata/restricted/lib/liba.so.meta_lic", - "restricted"), - matchResolution( - "testdata/restricted/lib/libc.a.meta_lic", - "testdata/restricted/lib/libc.a.meta_lic", - "testdata/restricted/lib/libc.a.meta_lic", + "restricted_allows_dynamic_linking", "reciprocal"), }, }, @@ -3730,7 +2740,6 @@ func Test_graphviz(t *testing.T) { 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", "testdata/restricted/lib/libd.so.meta_lic", "notice"), @@ -3746,121 +2755,69 @@ func Test_graphviz(t *testing.T) { 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/lib/libd.so.meta_lic"), matchTarget("testdata/proprietary/highest.apex.meta_lic"), matchResolution( - "testdata/proprietary/bin/bin1.meta_lic", "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", - "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", - "testdata/proprietary/lib/libc.a.meta_lic", "by_exception_only", "proprietary"), matchResolution( "testdata/proprietary/bin/bin2.meta_lic", "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/bin/bin2.meta_lic", - "testdata/proprietary/lib/libb.so.meta_lic", - "restricted"), - matchResolution( - "testdata/proprietary/bin/bin2.meta_lic", - "testdata/proprietary/lib/libb.so.meta_lic", - "testdata/proprietary/lib/libb.so.meta_lic", - "restricted"), - matchResolution( - "testdata/proprietary/bin/bin2.meta_lic", - "testdata/proprietary/lib/libd.so.meta_lic", "testdata/proprietary/lib/libb.so.meta_lic", "restricted"), matchResolution( "testdata/proprietary/highest.apex.meta_lic", "testdata/proprietary/bin/bin1.meta_lic", - "testdata/proprietary/bin/bin1.meta_lic", "notice"), matchResolution( "testdata/proprietary/highest.apex.meta_lic", "testdata/proprietary/bin/bin2.meta_lic", - "testdata/proprietary/bin/bin2.meta_lic", + "restricted", "by_exception_only", "proprietary"), matchResolution( - "testdata/proprietary/highest.apex.meta_lic", - "testdata/proprietary/bin/bin2.meta_lic", - "testdata/proprietary/lib/libb.so.meta_lic", - "restricted"), - matchResolution( - "testdata/proprietary/highest.apex.meta_lic", "testdata/proprietary/highest.apex.meta_lic", "testdata/proprietary/highest.apex.meta_lic", + "restricted", "notice"), matchResolution( "testdata/proprietary/highest.apex.meta_lic", - "testdata/proprietary/highest.apex.meta_lic", - "testdata/proprietary/lib/libb.so.meta_lic", - "restricted"), - matchResolution( - "testdata/proprietary/highest.apex.meta_lic", - "testdata/proprietary/lib/liba.so.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", - "testdata/proprietary/lib/libb.so.meta_lic", "restricted"), matchResolution( "testdata/proprietary/highest.apex.meta_lic", "testdata/proprietary/lib/libc.a.meta_lic", - "testdata/proprietary/lib/libc.a.meta_lic", "by_exception_only", "proprietary"), matchResolution( - "testdata/proprietary/highest.apex.meta_lic", - "testdata/proprietary/lib/libd.so.meta_lic", - "testdata/proprietary/lib/libb.so.meta_lic", - "restricted"), - matchResolution( - "testdata/proprietary/lib/liba.so.meta_lic", "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", "testdata/proprietary/lib/libb.so.meta_lic", "restricted"), - matchResolution( - "testdata/proprietary/lib/libc.a.meta_lic", - "testdata/proprietary/lib/libc.a.meta_lic", - "testdata/proprietary/lib/libc.a.meta_lic", - "by_exception_only", - "proprietary"), - matchResolution( - "testdata/proprietary/lib/libd.so.meta_lic", - "testdata/proprietary/lib/libd.so.meta_lic", - "testdata/proprietary/lib/libb.so.meta_lic", - "restricted"), - matchResolution( - "testdata/proprietary/lib/libd.so.meta_lic", - "testdata/proprietary/lib/libd.so.meta_lic", - "testdata/proprietary/lib/libd.so.meta_lic", - "notice"), }, }, { @@ -3874,121 +2831,69 @@ func Test_graphviz(t *testing.T) { matchTarget("lib/libc.a.meta_lic"), matchTarget("bin/bin2.meta_lic"), matchTarget("lib/libb.so.meta_lic"), - matchTarget("lib/libd.so.meta_lic"), matchTarget("highest.apex.meta_lic"), matchResolution( - "bin/bin1.meta_lic", "bin/bin1.meta_lic", "bin/bin1.meta_lic", "notice"), matchResolution( "bin/bin1.meta_lic", "lib/liba.so.meta_lic", - "lib/liba.so.meta_lic", "by_exception_only", "proprietary"), matchResolution( "bin/bin1.meta_lic", "lib/libc.a.meta_lic", - "lib/libc.a.meta_lic", "by_exception_only", "proprietary"), matchResolution( - "bin/bin2.meta_lic", "bin/bin2.meta_lic", "bin/bin2.meta_lic", "by_exception_only", + "restricted", "proprietary"), matchResolution( "bin/bin2.meta_lic", - "bin/bin2.meta_lic", - "lib/libb.so.meta_lic", - "restricted"), - matchResolution( - "bin/bin2.meta_lic", - "lib/libb.so.meta_lic", - "lib/libb.so.meta_lic", - "restricted"), - matchResolution( - "bin/bin2.meta_lic", - "lib/libd.so.meta_lic", "lib/libb.so.meta_lic", "restricted"), matchResolution( "highest.apex.meta_lic", "bin/bin1.meta_lic", - "bin/bin1.meta_lic", "notice"), matchResolution( "highest.apex.meta_lic", "bin/bin2.meta_lic", - "bin/bin2.meta_lic", + "restricted", "by_exception_only", "proprietary"), matchResolution( - "highest.apex.meta_lic", - "bin/bin2.meta_lic", - "lib/libb.so.meta_lic", - "restricted"), - matchResolution( - "highest.apex.meta_lic", "highest.apex.meta_lic", "highest.apex.meta_lic", + "restricted", "notice"), matchResolution( "highest.apex.meta_lic", - "highest.apex.meta_lic", - "lib/libb.so.meta_lic", - "restricted"), - matchResolution( - "highest.apex.meta_lic", - "lib/liba.so.meta_lic", "lib/liba.so.meta_lic", "by_exception_only", "proprietary"), matchResolution( "highest.apex.meta_lic", "lib/libb.so.meta_lic", - "lib/libb.so.meta_lic", "restricted"), matchResolution( "highest.apex.meta_lic", "lib/libc.a.meta_lic", - "lib/libc.a.meta_lic", "by_exception_only", "proprietary"), matchResolution( - "highest.apex.meta_lic", - "lib/libd.so.meta_lic", - "lib/libb.so.meta_lic", - "restricted"), - matchResolution( - "lib/liba.so.meta_lic", "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", "lib/libb.so.meta_lic", "restricted"), - matchResolution( - "lib/libc.a.meta_lic", - "lib/libc.a.meta_lic", - "lib/libc.a.meta_lic", - "by_exception_only", - "proprietary"), - matchResolution( - "lib/libd.so.meta_lic", - "lib/libd.so.meta_lic", - "lib/libb.so.meta_lic", - "restricted"), - matchResolution( - "lib/libd.so.meta_lic", - "lib/libd.so.meta_lic", - "lib/libd.so.meta_lic", - "notice"), }, }, { @@ -3996,24 +2901,21 @@ func Test_graphviz(t *testing.T) { name: "apex_trimmed_notice", roots: []string{"highest.apex.meta_lic"}, ctx: context{ - conditions: []string{"notice"}, + 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", "bin/bin1.meta_lic", "notice"), matchResolution( "highest.apex.meta_lic", "bin/bin1.meta_lic", - "bin/bin1.meta_lic", "notice"), matchResolution( - "highest.apex.meta_lic", "highest.apex.meta_lic", "highest.apex.meta_lic", "notice"), @@ -4024,7 +2926,7 @@ func Test_graphviz(t *testing.T) { name: "apex_trimmed_share", roots: []string{"highest.apex.meta_lic"}, ctx: context{ - conditions: []string{"reciprocal", "restricted"}, + conditions: compliance.ImpliesShared.AsList(), stripPrefix: "testdata/proprietary/", }, expectedOut: []getMatcher{ @@ -4034,30 +2936,24 @@ func Test_graphviz(t *testing.T) { matchResolution( "bin/bin2.meta_lic", "bin/bin2.meta_lic", - "lib/libb.so.meta_lic", "restricted"), matchResolution( "bin/bin2.meta_lic", "lib/libb.so.meta_lic", - "lib/libb.so.meta_lic", "restricted"), matchResolution( "highest.apex.meta_lic", "bin/bin2.meta_lic", - "lib/libb.so.meta_lic", "restricted"), matchResolution( "highest.apex.meta_lic", "highest.apex.meta_lic", - "lib/libb.so.meta_lic", "restricted"), matchResolution( "highest.apex.meta_lic", "lib/libb.so.meta_lic", - "lib/libb.so.meta_lic", "restricted"), matchResolution( - "lib/libb.so.meta_lic", "lib/libb.so.meta_lic", "lib/libb.so.meta_lic", "restricted"), @@ -4068,7 +2964,7 @@ func Test_graphviz(t *testing.T) { name: "apex_trimmed_private", roots: []string{"highest.apex.meta_lic"}, ctx: context{ - conditions: []string{"proprietary"}, + conditions: compliance.ImpliesPrivate.AsList(), stripPrefix: "testdata/proprietary/", }, expectedOut: []getMatcher{ @@ -4080,35 +2976,28 @@ func Test_graphviz(t *testing.T) { matchResolution( "bin/bin1.meta_lic", "lib/liba.so.meta_lic", - "lib/liba.so.meta_lic", "proprietary"), matchResolution( "bin/bin1.meta_lic", "lib/libc.a.meta_lic", - "lib/libc.a.meta_lic", "proprietary"), matchResolution( - "bin/bin2.meta_lic", "bin/bin2.meta_lic", "bin/bin2.meta_lic", "proprietary"), matchResolution( "highest.apex.meta_lic", "bin/bin2.meta_lic", - "bin/bin2.meta_lic", "proprietary"), matchResolution( "highest.apex.meta_lic", "lib/liba.so.meta_lic", - "lib/liba.so.meta_lic", "proprietary"), matchResolution( "highest.apex.meta_lic", "lib/libc.a.meta_lic", - "lib/libc.a.meta_lic", "proprietary"), matchResolution( - "lib/liba.so.meta_lic", "lib/liba.so.meta_lic", "lib/liba.so.meta_lic", "proprietary"), @@ -4119,7 +3008,7 @@ func Test_graphviz(t *testing.T) { name: "apex_trimmed_share_private", roots: []string{"highest.apex.meta_lic"}, ctx: context{ - conditions: []string{"reciprocal", "restricted", "proprietary"}, + conditions: compliance.ImpliesShared.Union(compliance.ImpliesPrivate).AsList(), stripPrefix: "testdata/proprietary/", }, expectedOut: []getMatcher{ @@ -4132,65 +3021,46 @@ func Test_graphviz(t *testing.T) { matchResolution( "bin/bin1.meta_lic", "lib/liba.so.meta_lic", - "lib/liba.so.meta_lic", "proprietary"), matchResolution( "bin/bin1.meta_lic", "lib/libc.a.meta_lic", - "lib/libc.a.meta_lic", "proprietary"), matchResolution( "bin/bin2.meta_lic", "bin/bin2.meta_lic", - "bin/bin2.meta_lic", + "restricted", "proprietary"), matchResolution( "bin/bin2.meta_lic", - "bin/bin2.meta_lic", - "lib/libb.so.meta_lic", - "restricted"), - matchResolution( - "bin/bin2.meta_lic", - "lib/libb.so.meta_lic", "lib/libb.so.meta_lic", "restricted"), matchResolution( "highest.apex.meta_lic", "bin/bin2.meta_lic", - "bin/bin2.meta_lic", + "restricted", "proprietary"), matchResolution( "highest.apex.meta_lic", - "bin/bin2.meta_lic", - "lib/libb.so.meta_lic", - "restricted"), - matchResolution( "highest.apex.meta_lic", - "highest.apex.meta_lic", - "lib/libb.so.meta_lic", "restricted"), matchResolution( "highest.apex.meta_lic", "lib/liba.so.meta_lic", - "lib/liba.so.meta_lic", "proprietary"), matchResolution( "highest.apex.meta_lic", "lib/libb.so.meta_lic", - "lib/libb.so.meta_lic", "restricted"), matchResolution( "highest.apex.meta_lic", "lib/libc.a.meta_lic", - "lib/libc.a.meta_lic", "proprietary"), matchResolution( - "lib/liba.so.meta_lic", "lib/liba.so.meta_lic", "lib/liba.so.meta_lic", "proprietary"), matchResolution( - "lib/libb.so.meta_lic", "lib/libb.so.meta_lic", "lib/libb.so.meta_lic", "restricted"), @@ -4207,121 +3077,69 @@ func Test_graphviz(t *testing.T) { 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("lib/libd.so.meta_lic", "notice"), matchTarget("highest.apex.meta_lic", "notice"), matchResolution( - "bin/bin1.meta_lic", "bin/bin1.meta_lic", "bin/bin1.meta_lic", "notice"), matchResolution( "bin/bin1.meta_lic", "lib/liba.so.meta_lic", - "lib/liba.so.meta_lic", "by_exception_only", "proprietary"), matchResolution( "bin/bin1.meta_lic", "lib/libc.a.meta_lic", - "lib/libc.a.meta_lic", "by_exception_only", "proprietary"), matchResolution( "bin/bin2.meta_lic", "bin/bin2.meta_lic", - "bin/bin2.meta_lic", + "restricted", "by_exception_only", "proprietary"), matchResolution( "bin/bin2.meta_lic", - "bin/bin2.meta_lic", - "lib/libb.so.meta_lic", - "restricted"), - matchResolution( - "bin/bin2.meta_lic", - "lib/libb.so.meta_lic", - "lib/libb.so.meta_lic", - "restricted"), - matchResolution( - "bin/bin2.meta_lic", - "lib/libd.so.meta_lic", "lib/libb.so.meta_lic", "restricted"), matchResolution( "highest.apex.meta_lic", "bin/bin1.meta_lic", - "bin/bin1.meta_lic", "notice"), matchResolution( "highest.apex.meta_lic", "bin/bin2.meta_lic", - "bin/bin2.meta_lic", + "restricted", "by_exception_only", "proprietary"), matchResolution( - "highest.apex.meta_lic", - "bin/bin2.meta_lic", - "lib/libb.so.meta_lic", - "restricted"), - matchResolution( - "highest.apex.meta_lic", "highest.apex.meta_lic", "highest.apex.meta_lic", + "restricted", "notice"), matchResolution( "highest.apex.meta_lic", - "highest.apex.meta_lic", - "lib/libb.so.meta_lic", - "restricted"), - matchResolution( - "highest.apex.meta_lic", - "lib/liba.so.meta_lic", "lib/liba.so.meta_lic", "by_exception_only", "proprietary"), matchResolution( "highest.apex.meta_lic", "lib/libb.so.meta_lic", - "lib/libb.so.meta_lic", "restricted"), matchResolution( "highest.apex.meta_lic", "lib/libc.a.meta_lic", - "lib/libc.a.meta_lic", "by_exception_only", "proprietary"), matchResolution( - "highest.apex.meta_lic", - "lib/libd.so.meta_lic", - "lib/libb.so.meta_lic", - "restricted"), - matchResolution( - "lib/liba.so.meta_lic", "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", "lib/libb.so.meta_lic", "restricted"), - matchResolution( - "lib/libc.a.meta_lic", - "lib/libc.a.meta_lic", - "lib/libc.a.meta_lic", - "by_exception_only", - "proprietary"), - matchResolution( - "lib/libd.so.meta_lic", - "lib/libd.so.meta_lic", - "lib/libb.so.meta_lic", - "restricted"), - matchResolution( - "lib/libd.so.meta_lic", - "lib/libd.so.meta_lic", - "lib/libd.so.meta_lic", - "notice"), }, }, { @@ -4334,121 +3152,69 @@ func Test_graphviz(t *testing.T) { 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/lib/libd.so.meta_lic"), matchTarget("testdata/proprietary/container.zip.meta_lic"), matchResolution( - "testdata/proprietary/bin/bin1.meta_lic", "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", - "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", - "testdata/proprietary/lib/libc.a.meta_lic", "by_exception_only", "proprietary"), matchResolution( "testdata/proprietary/bin/bin2.meta_lic", "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/bin/bin2.meta_lic", - "testdata/proprietary/lib/libb.so.meta_lic", - "restricted"), - matchResolution( - "testdata/proprietary/bin/bin2.meta_lic", - "testdata/proprietary/lib/libb.so.meta_lic", - "testdata/proprietary/lib/libb.so.meta_lic", - "restricted"), - matchResolution( - "testdata/proprietary/bin/bin2.meta_lic", - "testdata/proprietary/lib/libd.so.meta_lic", "testdata/proprietary/lib/libb.so.meta_lic", "restricted"), matchResolution( "testdata/proprietary/container.zip.meta_lic", "testdata/proprietary/bin/bin1.meta_lic", - "testdata/proprietary/bin/bin1.meta_lic", "notice"), matchResolution( "testdata/proprietary/container.zip.meta_lic", "testdata/proprietary/bin/bin2.meta_lic", - "testdata/proprietary/bin/bin2.meta_lic", + "restricted", "by_exception_only", "proprietary"), matchResolution( - "testdata/proprietary/container.zip.meta_lic", - "testdata/proprietary/bin/bin2.meta_lic", - "testdata/proprietary/lib/libb.so.meta_lic", - "restricted"), - matchResolution( - "testdata/proprietary/container.zip.meta_lic", "testdata/proprietary/container.zip.meta_lic", "testdata/proprietary/container.zip.meta_lic", + "restricted", "notice"), matchResolution( "testdata/proprietary/container.zip.meta_lic", - "testdata/proprietary/container.zip.meta_lic", - "testdata/proprietary/lib/libb.so.meta_lic", - "restricted"), - matchResolution( - "testdata/proprietary/container.zip.meta_lic", - "testdata/proprietary/lib/liba.so.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", - "testdata/proprietary/lib/libb.so.meta_lic", "restricted"), matchResolution( "testdata/proprietary/container.zip.meta_lic", "testdata/proprietary/lib/libc.a.meta_lic", - "testdata/proprietary/lib/libc.a.meta_lic", "by_exception_only", "proprietary"), matchResolution( - "testdata/proprietary/container.zip.meta_lic", - "testdata/proprietary/lib/libd.so.meta_lic", - "testdata/proprietary/lib/libb.so.meta_lic", - "restricted"), - matchResolution( - "testdata/proprietary/lib/liba.so.meta_lic", "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", "testdata/proprietary/lib/libb.so.meta_lic", "restricted"), - matchResolution( - "testdata/proprietary/lib/libc.a.meta_lic", - "testdata/proprietary/lib/libc.a.meta_lic", - "testdata/proprietary/lib/libc.a.meta_lic", - "by_exception_only", - "proprietary"), - matchResolution( - "testdata/proprietary/lib/libd.so.meta_lic", - "testdata/proprietary/lib/libd.so.meta_lic", - "testdata/proprietary/lib/libb.so.meta_lic", - "restricted"), - matchResolution( - "testdata/proprietary/lib/libd.so.meta_lic", - "testdata/proprietary/lib/libd.so.meta_lic", - "testdata/proprietary/lib/libd.so.meta_lic", - "notice"), }, }, { @@ -4458,55 +3224,17 @@ func Test_graphviz(t *testing.T) { expectedOut: []getMatcher{ matchTarget("testdata/proprietary/application.meta_lic"), matchTarget("testdata/proprietary/lib/liba.so.meta_lic"), - matchTarget("testdata/proprietary/lib/libb.so.meta_lic"), - matchTarget("testdata/proprietary/bin/bin3.meta_lic"), matchResolution( "testdata/proprietary/application.meta_lic", "testdata/proprietary/application.meta_lic", - "testdata/proprietary/application.meta_lic", - "notice"), - matchResolution( - "testdata/proprietary/application.meta_lic", - "testdata/proprietary/application.meta_lic", - "testdata/proprietary/lib/libb.so.meta_lic", + "notice", "restricted"), matchResolution( "testdata/proprietary/application.meta_lic", "testdata/proprietary/lib/liba.so.meta_lic", - "testdata/proprietary/lib/liba.so.meta_lic", + "restricted", "by_exception_only", "proprietary"), - matchResolution( - "testdata/proprietary/application.meta_lic", - "testdata/proprietary/lib/liba.so.meta_lic", - "testdata/proprietary/lib/libb.so.meta_lic", - "restricted"), - matchResolution( - "testdata/proprietary/application.meta_lic", - "testdata/proprietary/lib/libb.so.meta_lic", - "testdata/proprietary/lib/libb.so.meta_lic", - "restricted"), - matchResolution( - "testdata/proprietary/bin/bin3.meta_lic", - "testdata/proprietary/bin/bin3.meta_lic", - "testdata/proprietary/bin/bin3.meta_lic", - "restricted"), - matchResolution( - "testdata/proprietary/lib/liba.so.meta_lic", - "testdata/proprietary/lib/liba.so.meta_lic", - "testdata/proprietary/lib/liba.so.meta_lic", - "by_exception_only", - "proprietary"), - matchResolution( - "testdata/proprietary/lib/liba.so.meta_lic", - "testdata/proprietary/lib/liba.so.meta_lic", - "testdata/proprietary/lib/libb.so.meta_lic", - "restricted"), - matchResolution( - "testdata/proprietary/lib/libb.so.meta_lic", - "testdata/proprietary/lib/libb.so.meta_lic", - "testdata/proprietary/lib/libb.so.meta_lic", - "restricted"), }, }, { @@ -4518,32 +3246,17 @@ func Test_graphviz(t *testing.T) { 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", "testdata/proprietary/bin/bin1.meta_lic", "notice"), matchResolution( "testdata/proprietary/bin/bin1.meta_lic", "testdata/proprietary/lib/liba.so.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", - "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", - "testdata/proprietary/lib/liba.so.meta_lic", - "by_exception_only", - "proprietary"), - matchResolution( - "testdata/proprietary/lib/libc.a.meta_lic", - "testdata/proprietary/lib/libc.a.meta_lic", - "testdata/proprietary/lib/libc.a.meta_lic", "by_exception_only", "proprietary"), }, @@ -4555,7 +3268,6 @@ func Test_graphviz(t *testing.T) { 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", "testdata/proprietary/lib/libd.so.meta_lic", "notice"), @@ -4566,13 +3278,6 @@ func Test_graphviz(t *testing.T) { t.Run(tt.condition+" "+tt.name, func(t *testing.T) { ctx := &testContext{0, make(map[string]string)} - expectedOut := &bytes.Buffer{} - for _, eo := range tt.expectedOut { - m := eo(ctx) - expectedOut.WriteString(m.matchString(ctx)) - expectedOut.WriteString("\n") - } - stdout := &bytes.Buffer{} stderr := &bytes.Buffer{} @@ -4581,8 +3286,7 @@ func Test_graphviz(t *testing.T) { rootFiles = append(rootFiles, "testdata/"+tt.condition+"/"+r) } tt.ctx.graphViz = true - err := dumpResolutions(&tt.ctx, stdout, stderr, rootFiles...) - + lg, err := dumpResolutions(&tt.ctx, stdout, stderr, rootFiles...) if err != nil { t.Fatalf("dumpresolutions: error = %v, stderr = %v", err, stderr) return @@ -4590,6 +3294,14 @@ func Test_graphviz(t *testing.T) { 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 {" { diff --git a/tools/compliance/cmd/listshare.go b/tools/compliance/cmd/listshare.go index bba2308300..5c58dc4052 100644 --- a/tools/compliance/cmd/listshare.go +++ b/tools/compliance/cmd/listshare.go @@ -22,6 +22,7 @@ import ( "os" "path/filepath" "sort" + "strings" ) func init() { @@ -83,17 +84,17 @@ func listShare(stdout, stderr io.Writer, files ...string) error { shareSource := compliance.ResolveSourceSharing(licenseGraph) // Group the resolutions by project. - presolution := make(map[string]*compliance.LicenseConditionSet) + presolution := make(map[string]compliance.LicenseConditionSet) for _, target := range shareSource.AttachesTo() { rl := shareSource.Resolutions(target) sort.Sort(rl) for _, r := range rl { for _, p := range r.ActsOn().Projects() { if _, ok := presolution[p]; !ok { - presolution[p] = r.Resolves().Copy() + presolution[p] = r.Resolves() continue } - presolution[p].AddSet(r.Resolves()) + presolution[p] = presolution[p].Union(r.Resolves()) } } } @@ -107,17 +108,11 @@ func listShare(stdout, stderr io.Writer, files ...string) error { // Output the sorted projects and the source-sharing license conditions that each project resolves. for _, p := range projects { - fmt.Fprintf(stdout, "%s", p) - - // Sort the conditions for repeatability/stability. - conditions := presolution[p].AsList() - sort.Sort(conditions) - - // Output the sorted origin:condition pairs. - for _, lc := range conditions { - fmt.Fprintf(stdout, ",%s:%s", lc.Origin().Name(), lc.Name()) + if presolution[p].IsEmpty() { + fmt.Fprintf(stdout, "%s\n", p) + } else { + fmt.Fprintf(stdout, "%s,%s\n", p, strings.Join(presolution[p].Names(), ",")) } - fmt.Fprintf(stdout, "\n") } return nil diff --git a/tools/compliance/cmd/listshare_test.go b/tools/compliance/cmd/listshare_test.go index b4847e39c7..2ee249dd7a 100644 --- a/tools/compliance/cmd/listshare_test.go +++ b/tools/compliance/cmd/listshare_test.go @@ -98,12 +98,12 @@ func Test(t *testing.T) { expectedOut: []projectShare{ { project: "device/library", - conditions: []string{"lib/liba.so.meta_lic:reciprocal"}, + conditions: []string{"reciprocal"}, }, { project: "static/library", conditions: []string{ - "lib/libc.a.meta_lic:reciprocal", + "reciprocal", }, }, }, @@ -115,12 +115,12 @@ func Test(t *testing.T) { expectedOut: []projectShare{ { project: "device/library", - conditions: []string{"lib/liba.so.meta_lic:reciprocal"}, + conditions: []string{"reciprocal"}, }, { project: "static/library", conditions: []string{ - "lib/libc.a.meta_lic:reciprocal", + "reciprocal", }, }, }, @@ -132,7 +132,7 @@ func Test(t *testing.T) { expectedOut: []projectShare{ { project: "device/library", - conditions: []string{"lib/liba.so.meta_lic:reciprocal"}, + conditions: []string{"reciprocal"}, }, }, }, @@ -144,13 +144,13 @@ func Test(t *testing.T) { { project: "device/library", conditions: []string{ - "lib/liba.so.meta_lic:reciprocal", + "reciprocal", }, }, { project: "static/library", conditions: []string{ - "lib/libc.a.meta_lic:reciprocal", + "reciprocal", }, }, }, @@ -168,34 +168,34 @@ func Test(t *testing.T) { expectedOut: []projectShare{ { project: "base/library", - conditions: []string{"lib/libb.so.meta_lic:restricted"}, + conditions: []string{"restricted"}, }, { project: "device/library", - conditions: []string{"lib/liba.so.meta_lic:restricted"}, + conditions: []string{"restricted_allows_dynamic_linking"}, }, { project: "dynamic/binary", - conditions: []string{"lib/libb.so.meta_lic:restricted"}, + conditions: []string{"restricted"}, }, { project: "highest/apex", conditions: []string{ - "lib/liba.so.meta_lic:restricted", - "lib/libb.so.meta_lic:restricted", + "restricted", + "restricted_allows_dynamic_linking", }, }, { project: "static/binary", conditions: []string{ - "lib/liba.so.meta_lic:restricted", + "restricted_allows_dynamic_linking", }, }, { project: "static/library", conditions: []string{ - "lib/liba.so.meta_lic:restricted", - "lib/libc.a.meta_lic:reciprocal", + "reciprocal", + "restricted_allows_dynamic_linking", }, }, }, @@ -207,34 +207,34 @@ func Test(t *testing.T) { expectedOut: []projectShare{ { project: "base/library", - conditions: []string{"lib/libb.so.meta_lic:restricted"}, + conditions: []string{"restricted"}, }, { project: "container/zip", conditions: []string{ - "lib/liba.so.meta_lic:restricted", - "lib/libb.so.meta_lic:restricted", + "restricted", + "restricted_allows_dynamic_linking", }, }, { project: "device/library", - conditions: []string{"lib/liba.so.meta_lic:restricted"}, + conditions: []string{"restricted_allows_dynamic_linking"}, }, { project: "dynamic/binary", - conditions: []string{"lib/libb.so.meta_lic:restricted"}, + conditions: []string{"restricted"}, }, { project: "static/binary", conditions: []string{ - "lib/liba.so.meta_lic:restricted", + "restricted_allows_dynamic_linking", }, }, { project: "static/library", conditions: []string{ - "lib/liba.so.meta_lic:restricted", - "lib/libc.a.meta_lic:reciprocal", + "reciprocal", + "restricted_allows_dynamic_linking", }, }, }, @@ -247,15 +247,15 @@ func Test(t *testing.T) { { project: "device/library", conditions: []string{ - "lib/liba.so.meta_lic:restricted", - "lib/libb.so.meta_lic:restricted", + "restricted", + "restricted_allows_dynamic_linking", }, }, { project: "distributable/application", conditions: []string{ - "lib/liba.so.meta_lic:restricted", - "lib/libb.so.meta_lic:restricted", + "restricted", + "restricted_allows_dynamic_linking", }, }, }, @@ -268,20 +268,20 @@ func Test(t *testing.T) { { project: "device/library", conditions: []string{ - "lib/liba.so.meta_lic:restricted", + "restricted_allows_dynamic_linking", }, }, { project: "static/binary", conditions: []string{ - "lib/liba.so.meta_lic:restricted", + "restricted_allows_dynamic_linking", }, }, { project: "static/library", conditions: []string{ - "lib/liba.so.meta_lic:restricted", - "lib/libc.a.meta_lic:reciprocal", + "reciprocal", + "restricted_allows_dynamic_linking", }, }, }, @@ -299,15 +299,15 @@ func Test(t *testing.T) { expectedOut: []projectShare{ { project: "base/library", - conditions: []string{"lib/libb.so.meta_lic:restricted"}, + conditions: []string{"restricted"}, }, { project: "dynamic/binary", - conditions: []string{"lib/libb.so.meta_lic:restricted"}, + conditions: []string{"restricted"}, }, { project: "highest/apex", - conditions: []string{"lib/libb.so.meta_lic:restricted"}, + conditions: []string{"restricted"}, }, }, }, @@ -318,15 +318,15 @@ func Test(t *testing.T) { expectedOut: []projectShare{ { project: "base/library", - conditions: []string{"lib/libb.so.meta_lic:restricted"}, + conditions: []string{"restricted"}, }, { project: "container/zip", - conditions: []string{"lib/libb.so.meta_lic:restricted"}, + conditions: []string{"restricted"}, }, { project: "dynamic/binary", - conditions: []string{"lib/libb.so.meta_lic:restricted"}, + conditions: []string{"restricted"}, }, }, }, @@ -337,11 +337,11 @@ func Test(t *testing.T) { expectedOut: []projectShare{ { project: "device/library", - conditions: []string{"lib/libb.so.meta_lic:restricted"}, + conditions: []string{"restricted"}, }, { project: "distributable/application", - conditions: []string{"lib/libb.so.meta_lic:restricted"}, + conditions: []string{"restricted"}, }, }, }, @@ -365,9 +365,6 @@ func Test(t *testing.T) { expectedOut.WriteString(p.project) for _, lc := range p.conditions { expectedOut.WriteString(",") - expectedOut.WriteString("testdata/") - expectedOut.WriteString(tt.condition) - expectedOut.WriteString("/") expectedOut.WriteString(lc) } expectedOut.WriteString("\n") diff --git a/tools/compliance/condition.go b/tools/compliance/condition.go index b5c8cec04d..26b91cab2e 100644 --- a/tools/compliance/condition.go +++ b/tools/compliance/condition.go @@ -16,150 +16,87 @@ package compliance import ( "fmt" - "strings" ) -// LicenseCondition describes an individual license condition or requirement -// originating at a specific target node. (immutable) -// -// e.g. A module licensed under GPL terms would originate a `restricted` condition. -type LicenseCondition struct { - name string - origin *TargetNode -} +// LicenseCondition identifies a recognized license condition by setting the +// corresponding bit. +type LicenseCondition uint16 -// Name returns the name of the condition. e.g. "restricted" or "notice" +// LicenseConditionMask is a bitmask for the recognized license conditions. +const LicenseConditionMask = LicenseCondition(0x3ff) + +const ( + // UnencumberedCondition identifies public domain or public domain- + // like license that disclaims copyright. + UnencumberedCondition = LicenseCondition(0x0001) + // PermissiveCondition identifies a license without notice or other + // significant requirements. + PermissiveCondition = LicenseCondition(0x0002) + // NoticeCondition identifies a typical open-source license with only + // notice or attribution requirements. + NoticeCondition = LicenseCondition(0x0004) + // ReciprocalCondition identifies a license with requirement to share + // the module's source only. + ReciprocalCondition = LicenseCondition(0x0008) + // RestrictedCondition identifies a license with requirement to share + // all source code linked to the module's source. + RestrictedCondition = LicenseCondition(0x0010) + // RestrictedClasspathExceptionCondition identifies RestrictedCondition + // waived for dynamic linking from independent modules. + RestrictedClasspathExceptionCondition = LicenseCondition(0x0020) + // WeaklyRestrictedCondition identifies a RestrictedCondition waived + // for dynamic linking. + WeaklyRestrictedCondition = LicenseCondition(0x0040) + // ProprietaryCondition identifies a license with source privacy + // requirements. + ProprietaryCondition = LicenseCondition(0x0080) + // ByExceptionOnly identifies a license where policy requires product + // counsel review prior to use. + ByExceptionOnlyCondition = LicenseCondition(0x0100) + // NotAllowedCondition identifies a license with onerous conditions + // where policy prohibits use. + NotAllowedCondition = LicenseCondition(0x0200) +) + +var ( + // RecognizedConditionNames maps condition strings to LicenseCondition. + RecognizedConditionNames = map[string]LicenseCondition{ + "unencumbered": UnencumberedCondition, + "permissive": PermissiveCondition, + "notice": NoticeCondition, + "reciprocal": ReciprocalCondition, + "restricted": RestrictedCondition, + "restricted_with_classpath_exception": RestrictedClasspathExceptionCondition, + "restricted_allows_dynamic_linking": WeaklyRestrictedCondition, + "proprietary": ProprietaryCondition, + "by_exception_only": ByExceptionOnlyCondition, + "not_allowed": NotAllowedCondition, + } +) + +// Name returns the condition string corresponding to the LicenseCondition. func (lc LicenseCondition) Name() string { - return lc.name -} - -// Origin identifies the TargetNode where the condition originates. -func (lc LicenseCondition) Origin() *TargetNode { - return lc.origin -} - -// asString returns a string representation of a license condition: -// origin+separator+condition. -func (lc LicenseCondition) asString(separator string) string { - return lc.origin.name + separator + lc.name -} - -// ConditionList implements introspection methods to arrays of LicenseCondition. -type ConditionList []LicenseCondition - - -// ConditionList orders arrays of LicenseCondition by Origin and Name. - -// Len returns the length of the list. -func (l ConditionList) Len() int { return len(l) } - -// Swap rearranges 2 elements in the list so each occupies the other's former position. -func (l ConditionList) Swap(i, j int) { l[i], l[j] = l[j], l[i] } - -// Less returns true when the `i`th element is lexicographically less than tht `j`th element. -func (l ConditionList) Less(i, j int) bool { - if l[i].origin.name == l[j].origin.name { - return l[i].name < l[j].name + switch lc { + case UnencumberedCondition: + return "unencumbered" + case PermissiveCondition: + return "permissive" + case NoticeCondition: + return "notice" + case ReciprocalCondition: + return "reciprocal" + case RestrictedCondition: + return "restricted" + case RestrictedClasspathExceptionCondition: + return "restricted_with_classpath_exception" + case WeaklyRestrictedCondition: + return "restricted_allows_dynamic_linking" + case ProprietaryCondition: + return "proprietary" + case ByExceptionOnlyCondition: + return "by_exception_only" + case NotAllowedCondition: + return "not_allowed" } - return l[i].origin.name < l[j].origin.name -} - -// String returns a string representation of the set. -func (cl ConditionList) String() string { - var sb strings.Builder - fmt.Fprintf(&sb, "[") - sep := "" - for _, lc := range cl { - fmt.Fprintf(&sb, "%s%s:%s", sep, lc.origin.name, lc.name) - sep = ", " - } - fmt.Fprintf(&sb, "]") - return sb.String() -} - -// Names returns the list of the conditions' names. -func (cl ConditionList) Names() []string { - result := make([]string, 0, len(cl)) - for _, lc := range cl { - result = append(result, lc.name) - } - return result -} - -// HasByName returns true if the list contains any condition matching `name`. -func (cl ConditionList) HasByName(name ConditionNames) bool { - for _, lc := range cl { - if name.Contains(lc.name) { - return true - } - } - return false -} - -// ByName returns the sublist of conditions that match `name`. -func (cl ConditionList) ByName(name ConditionNames) ConditionList { - result := make(ConditionList, 0, cl.CountByName(name)) - for _, lc := range cl { - if name.Contains(lc.name) { - result = append(result, lc) - } - } - return result -} - -// CountByName returns the size of the sublist of conditions that match `name`. -func (cl ConditionList) CountByName(name ConditionNames) int { - size := 0 - for _, lc := range cl { - if name.Contains(lc.name) { - size++ - } - } - return size -} - -// HasByOrigin returns true if the list contains any condition originating at `origin`. -func (cl ConditionList) HasByOrigin(origin *TargetNode) bool { - for _, lc := range cl { - if lc.origin.name == origin.name { - return true - } - } - return false -} - -// ByOrigin returns the sublist of conditions that originate at `origin`. -func (cl ConditionList) ByOrigin(origin *TargetNode) ConditionList { - result := make(ConditionList, 0, cl.CountByOrigin(origin)) - for _, lc := range cl { - if lc.origin.name == origin.name { - result = append(result, lc) - } - } - return result -} - -// CountByOrigin returns the size of the sublist of conditions that originate at `origin`. -func (cl ConditionList) CountByOrigin(origin *TargetNode) int { - size := 0 - for _, lc := range cl { - if lc.origin.name == origin.name { - size++ - } - } - return size -} - -// ConditionNames implements the Contains predicate for slices of condition -// name strings. -type ConditionNames []string - -// Contains returns true if the name matches one of the ConditionNames. -func (cn ConditionNames) Contains(name string) bool { - for _, cname := range cn { - if cname == name { - return true - } - } - return false + panic(fmt.Errorf("unrecognized license condition: %04x", lc)) } diff --git a/tools/compliance/condition_test.go b/tools/compliance/condition_test.go index 0507469225..778ce4a8dd 100644 --- a/tools/compliance/condition_test.go +++ b/tools/compliance/condition_test.go @@ -15,204 +15,53 @@ package compliance import ( - "sort" - "strings" "testing" ) -func TestConditionNames(t *testing.T) { - impliesShare := ConditionNames([]string{"restricted", "reciprocal"}) +func TestConditionSetHas(t *testing.T) { + impliesShare := ImpliesShared - if impliesShare.Contains("notice") { - t.Errorf("impliesShare.Contains(\"notice\") got true, want false") + t.Logf("testing with imliesShare=%04x", impliesShare) + + if impliesShare.HasAny(NoticeCondition) { + t.Errorf("impliesShare.HasAny(\"notice\"=%04x) got true, want false", NoticeCondition) } - if !impliesShare.Contains("restricted") { - t.Errorf("impliesShare.Contains(\"restricted\") got false, want true") + if !impliesShare.HasAny(RestrictedCondition) { + t.Errorf("impliesShare.HasAny(\"restricted\"=%04x) got false, want true", RestrictedCondition) } - if !impliesShare.Contains("reciprocal") { - t.Errorf("impliesShare.Contains(\"reciprocal\") got false, want true") + if !impliesShare.HasAny(ReciprocalCondition) { + t.Errorf("impliesShare.HasAny(\"reciprocal\"=%04x) got false, want true", ReciprocalCondition) } - if impliesShare.Contains("") { - t.Errorf("impliesShare.Contains(\"\") got true, want false") + if impliesShare.HasAny(LicenseCondition(0x0000)) { + t.Errorf("impliesShare.HasAny(nil=%04x) got true, want false", LicenseCondition(0x0000)) } } -func TestConditionList(t *testing.T) { - tests := []struct { - name string - conditions map[string][]string - byName map[string][]string - byOrigin map[string][]string - }{ - { - name: "noticeonly", - conditions: map[string][]string{ - "notice": []string{"bin1", "lib1"}, - }, - byName: map[string][]string{ - "notice": []string{"bin1", "lib1"}, - "restricted": []string{}, - }, - byOrigin: map[string][]string{ - "bin1": []string{"notice"}, - "lib1": []string{"notice"}, - "bin2": []string{}, - "lib2": []string{}, - }, - }, - { - name: "empty", - conditions: map[string][]string{}, - byName: map[string][]string{ - "notice": []string{}, - "restricted": []string{}, - }, - byOrigin: map[string][]string{ - "bin1": []string{}, - "lib1": []string{}, - "bin2": []string{}, - "lib2": []string{}, - }, - }, - { - name: "everything", - conditions: map[string][]string{ - "notice": []string{"bin1", "bin2", "lib1", "lib2"}, - "reciprocal": []string{"bin1", "bin2", "lib1", "lib2"}, - "restricted": []string{"bin1", "bin2", "lib1", "lib2"}, - "by_exception_only": []string{"bin1", "bin2", "lib1", "lib2"}, - }, - byName: map[string][]string{ - "permissive": []string{}, - "notice": []string{"bin1", "bin2", "lib1", "lib2"}, - "reciprocal": []string{"bin1", "bin2", "lib1", "lib2"}, - "restricted": []string{"bin1", "bin2", "lib1", "lib2"}, - "by_exception_only": []string{"bin1", "bin2", "lib1", "lib2"}, - }, - byOrigin: map[string][]string{ - "bin1": []string{"notice", "reciprocal", "restricted", "by_exception_only"}, - "bin2": []string{"notice", "reciprocal", "restricted", "by_exception_only"}, - "lib1": []string{"notice", "reciprocal", "restricted", "by_exception_only"}, - "lib2": []string{"notice", "reciprocal", "restricted", "by_exception_only"}, - "other": []string{}, - }, - }, - { - name: "allbutoneeach", - conditions: map[string][]string{ - "notice": []string{"bin2", "lib1", "lib2"}, - "reciprocal": []string{"bin1", "lib1", "lib2"}, - "restricted": []string{"bin1", "bin2", "lib2"}, - "by_exception_only": []string{"bin1", "bin2", "lib1"}, - }, - byName: map[string][]string{ - "permissive": []string{}, - "notice": []string{"bin2", "lib1", "lib2"}, - "reciprocal": []string{"bin1", "lib1", "lib2"}, - "restricted": []string{"bin1", "bin2", "lib2"}, - "by_exception_only": []string{"bin1", "bin2", "lib1"}, - }, - byOrigin: map[string][]string{ - "bin1": []string{"reciprocal", "restricted", "by_exception_only"}, - "bin2": []string{"notice", "restricted", "by_exception_only"}, - "lib1": []string{"notice", "reciprocal", "by_exception_only"}, - "lib2": []string{"notice", "reciprocal", "restricted"}, - "other": []string{}, - }, - }, - { - name: "oneeach", - conditions: map[string][]string{ - "notice": []string{"bin1"}, - "reciprocal": []string{"bin2"}, - "restricted": []string{"lib1"}, - "by_exception_only": []string{"lib2"}, - }, - byName: map[string][]string{ - "permissive": []string{}, - "notice": []string{"bin1"}, - "reciprocal": []string{"bin2"}, - "restricted": []string{"lib1"}, - "by_exception_only": []string{"lib2"}, - }, - byOrigin: map[string][]string{ - "bin1": []string{"notice"}, - "bin2": []string{"reciprocal"}, - "lib1": []string{"restricted"}, - "lib2": []string{"by_exception_only"}, - "other": []string{}, - }, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - lg := newLicenseGraph() - cl := toConditionList(lg, tt.conditions) - for names, expected := range tt.byName { - name := ConditionNames(strings.Split(names, ":")) - if cl.HasByName(name) { - if len(expected) == 0 { - t.Errorf("unexpected ConditionList.HasByName(%q): got true, want false", name) - } - } else { - if len(expected) != 0 { - t.Errorf("unexpected ConditionList.HasByName(%q): got false, want true", name) - } - } - if len(expected) != cl.CountByName(name) { - t.Errorf("unexpected ConditionList.CountByName(%q): got %d, want %d", name, cl.CountByName(name), len(expected)) - } - byName := cl.ByName(name) - if len(expected) != len(byName) { - t.Errorf("unexpected ConditionList.ByName(%q): got %v, want %v", name, byName, expected) - } else { - sort.Strings(expected) - actual := make([]string, 0, len(byName)) - for _, lc := range byName { - actual = append(actual, lc.Origin().Name()) - } - sort.Strings(actual) - for i := 0; i < len(expected); i++ { - if expected[i] != actual[i] { - t.Errorf("unexpected ConditionList.ByName(%q) index %d in %v: got %s, want %s", name, i, actual, actual[i], expected[i]) - } - } - } - } - for origin, expected := range tt.byOrigin { - onode := newTestNode(lg, origin) - if cl.HasByOrigin(onode) { - if len(expected) == 0 { - t.Errorf("unexpected ConditionList.HasByOrigin(%q): got true, want false", origin) - } - } else { - if len(expected) != 0 { - t.Errorf("unexpected ConditionList.HasByOrigin(%q): got false, want true", origin) - } - } - if len(expected) != cl.CountByOrigin(onode) { - t.Errorf("unexpected ConditionList.CountByOrigin(%q): got %d, want %d", origin, cl.CountByOrigin(onode), len(expected)) - } - byOrigin := cl.ByOrigin(onode) - if len(expected) != len(byOrigin) { - t.Errorf("unexpected ConditionList.ByOrigin(%q): got %v, want %v", origin, byOrigin, expected) - } else { - sort.Strings(expected) - actual := make([]string, 0, len(byOrigin)) - for _, lc := range byOrigin { - actual = append(actual, lc.Name()) - } - sort.Strings(actual) - for i := 0; i < len(expected); i++ { - if expected[i] != actual[i] { - t.Errorf("unexpected ConditionList.ByOrigin(%q) index %d in %v: got %s, want %s", origin, i, actual, actual[i], expected[i]) - } - } - } - } - }) +func TestConditionName(t *testing.T) { + for expected, condition := range RecognizedConditionNames { + actual := condition.Name() + if expected != actual { + t.Errorf("unexpected name for condition %04x: got %s, want %s", condition, actual, expected) + } + } +} + +func TestConditionName_InvalidCondition(t *testing.T) { + panicked := false + var lc LicenseCondition + func() { + defer func() { + if err := recover(); err != nil { + panicked = true + } + }() + name := lc.Name() + t.Errorf("invalid condition unexpected name: got %s, wanted panic", name) + }() + if !panicked { + t.Errorf("no expected panic for %04x.Name(): got no panic, wanted panic", lc) } } diff --git a/tools/compliance/conditionset.go b/tools/compliance/conditionset.go index 102e35ad91..7a12ddc298 100644 --- a/tools/compliance/conditionset.go +++ b/tools/compliance/conditionset.go @@ -16,263 +16,174 @@ package compliance import ( "fmt" + "strings" ) -// NewLicenseConditionSet creates a new instance or variable of *LicenseConditionSet. -func NewLicenseConditionSet(conditions ...LicenseCondition) *LicenseConditionSet { - cs := newLicenseConditionSet() - cs.Add(conditions...) +// LicenseConditionSet identifies sets of license conditions. +type LicenseConditionSet LicenseCondition + +// AllLicenseConditions is the set of all recognized license conditions. +const AllLicenseConditions = LicenseConditionSet(LicenseConditionMask) + +// NewLicenseConditionSet returns a set containing exactly the elements of +// `conditions`. +func NewLicenseConditionSet(conditions ...LicenseCondition) LicenseConditionSet { + cs := LicenseConditionSet(0x00) + for _, lc := range conditions { + cs |= LicenseConditionSet(lc) + } return cs } -// LicenseConditionSet describes a mutable set of immutable license conditions. -type LicenseConditionSet struct { - // conditions describes the set of license conditions i.e. (condition name, origin target) pairs - // by mapping condition name -> origin target -> struct{}{}. - conditions map[string]map[*TargetNode]struct{} -} - -// Add makes all `conditions` members of the set if they were not previously. -func (cs *LicenseConditionSet) Add(conditions ...LicenseCondition) { - if len(conditions) == 0 { - return - } +// Plus returns a new set containing all of the elements of `cs` and all of the +// `conditions`. +func (cs LicenseConditionSet) Plus(conditions ...LicenseCondition) LicenseConditionSet { + result := cs for _, lc := range conditions { - if _, ok := cs.conditions[lc.name]; !ok { - cs.conditions[lc.name] = make(map[*TargetNode]struct{}) - } - cs.conditions[lc.name][lc.origin] = struct{}{} + result |= LicenseConditionSet(lc) } + return result } -// AddSet makes all elements of `conditions` members of the set if they were not previously. -func (cs *LicenseConditionSet) AddSet(other *LicenseConditionSet) { - if len(other.conditions) == 0 { - return - } - for name, origins := range other.conditions { - if len(origins) == 0 { - continue - } - if _, ok := cs.conditions[name]; !ok { - cs.conditions[name] = make(map[*TargetNode]struct{}) - } - for origin := range origins { - cs.conditions[name][origin] = other.conditions[name][origin] - } +// Union returns a new set containing all of the elements of `cs` and all of the +// elements of the `other` sets. +func (cs LicenseConditionSet) Union(other ...LicenseConditionSet) LicenseConditionSet { + result := cs + for _, ls := range other { + result |= ls } + return result } -// ByName returns a list of the conditions in the set matching `names`. -func (cs *LicenseConditionSet) ByName(names ...ConditionNames) *LicenseConditionSet { - other := newLicenseConditionSet() - for _, cn := range names { - for _, name := range cn { - if origins, ok := cs.conditions[name]; ok { - other.conditions[name] = make(map[*TargetNode]struct{}) - for origin := range origins { - other.conditions[name][origin] = struct{}{} - } - } - } +// MatchingAny returns the subset of `cs` equal to any of the `conditions`. +func (cs LicenseConditionSet) MatchingAny(conditions ...LicenseCondition) LicenseConditionSet { + result := LicenseConditionSet(0x00) + for _, lc := range conditions { + result |= cs & LicenseConditionSet(lc) } - return other + return result } -// HasAnyByName returns true if the set contains any conditions matching `names` originating at any target. -func (cs *LicenseConditionSet) HasAnyByName(names ...ConditionNames) bool { - for _, cn := range names { - for _, name := range cn { - if origins, ok := cs.conditions[name]; ok { - if len(origins) > 0 { - return true - } - } - } +// MatchingAnySet returns the subset of `cs` that are members of any of the +// `other` sets. +func (cs LicenseConditionSet) MatchingAnySet(other ...LicenseConditionSet) LicenseConditionSet { + result := LicenseConditionSet(0x00) + for _, ls := range other { + result |= cs & ls } - return false + return result } -// CountByName returns the number of conditions matching `names` originating at any target. -func (cs *LicenseConditionSet) CountByName(names ...ConditionNames) int { - size := 0 - for _, cn := range names { - for _, name := range cn { - if origins, ok := cs.conditions[name]; ok { - size += len(origins) - } - } - } - return size -} - -// ByOrigin returns all of the conditions that originate at `origin` regardless of name. -func (cs *LicenseConditionSet) ByOrigin(origin *TargetNode) *LicenseConditionSet { - other := newLicenseConditionSet() - for name, origins := range cs.conditions { - if _, ok := origins[origin]; ok { - other.conditions[name] = make(map[*TargetNode]struct{}) - other.conditions[name][origin] = struct{}{} - } - } - return other -} - -// HasAnyByOrigin returns true if the set contains any conditions originating at `origin` regardless of condition name. -func (cs *LicenseConditionSet) HasAnyByOrigin(origin *TargetNode) bool { - for _, origins := range cs.conditions { - if _, ok := origins[origin]; ok { +// HasAny returns true when `cs` contains at least one of the `conditions`. +func (cs LicenseConditionSet) HasAny(conditions ...LicenseCondition) bool { + for _, lc := range conditions { + if 0x0000 != (cs & LicenseConditionSet(lc)) { return true } } return false } -// CountByOrigin returns the number of conditions originating at `origin` regardless of condition name. -func (cs *LicenseConditionSet) CountByOrigin(origin *TargetNode) int { - size := 0 - for _, origins := range cs.conditions { - if _, ok := origins[origin]; ok { - size++ - } - } - return size -} - -// AsList returns a list of all the conditions in the set. -func (cs *LicenseConditionSet) AsList() ConditionList { - result := make(ConditionList, 0, cs.Count()) - for name, origins := range cs.conditions { - for origin := range origins { - result = append(result, LicenseCondition{name, origin}) - } - } - return result -} - -// Names returns a list of the names of the conditions in the set. -func (cs *LicenseConditionSet) Names() []string { - result := make([]string, 0, len(cs.conditions)) - for name := range cs.conditions { - result = append(result, name) - } - return result -} - -// Count returns the number of conditions in the set. -func (cs *LicenseConditionSet) Count() int { - size := 0 - for _, origins := range cs.conditions { - size += len(origins) - } - return size -} - -// Copy creates a new LicenseCondition variable with the same value. -func (cs *LicenseConditionSet) Copy() *LicenseConditionSet { - other := newLicenseConditionSet() - for name := range cs.conditions { - other.conditions[name] = make(map[*TargetNode]struct{}) - for origin := range cs.conditions[name] { - other.conditions[name][origin] = cs.conditions[name][origin] - } - } - return other -} - -// HasCondition returns true if the set contains any condition matching both `names` and `origin`. -func (cs *LicenseConditionSet) HasCondition(names ConditionNames, origin *TargetNode) bool { - for _, name := range names { - if origins, ok := cs.conditions[name]; ok { - _, isPresent := origins[origin] - if isPresent { - return true - } +// MatchesAnySet returns true when `cs` has a non-empty intersection with at +// least one of the `other` condition sets. +func (cs LicenseConditionSet) MatchesAnySet(other ...LicenseConditionSet) bool { + for _, ls := range other { + if 0x0000 != (cs & ls) { + return true } } return false } -// IsEmpty returns true when the set of conditions contains zero elements. -func (cs *LicenseConditionSet) IsEmpty() bool { - for _, origins := range cs.conditions { - if 0 < len(origins) { +// HasAll returns true when `cs` contains every one of the `conditions`. +func (cs LicenseConditionSet) HasAll(conditions ...LicenseCondition) bool { + for _, lc := range conditions { + if 0x0000 == (cs & LicenseConditionSet(lc)) { return false } } return true } -// RemoveAllByName changes the set to delete all conditions matching `names`. -func (cs *LicenseConditionSet) RemoveAllByName(names ...ConditionNames) { - for _, cn := range names { - for _, name := range cn { - delete(cs.conditions, name) +// MatchesEverySet returns true when `cs` has a non-empty intersection with +// each of the `other` condition sets. +func (cs LicenseConditionSet) MatchesEverySet(other ...LicenseConditionSet) bool { + for _, ls := range other { + if 0x0000 == (cs & ls) { + return false } } + return true } -// Remove changes the set to delete `conditions`. -func (cs *LicenseConditionSet) Remove(conditions ...LicenseCondition) { +// Intersection returns the subset of `cs` that are members of every `other` +// set. +func (cs LicenseConditionSet) Intersection(other ...LicenseConditionSet) LicenseConditionSet { + result := cs + for _, ls := range other { + result &= ls + } + return result +} + +// Minus returns the subset of `cs` that are not equaal to any `conditions`. +func (cs LicenseConditionSet) Minus(conditions ...LicenseCondition) LicenseConditionSet { + result := cs for _, lc := range conditions { - if _, isPresent := cs.conditions[lc.name]; !isPresent { - panic(fmt.Errorf("attempt to remove non-existent condition: %q", lc.asString(":"))) - } - if _, isPresent := cs.conditions[lc.name][lc.origin]; !isPresent { - panic(fmt.Errorf("attempt to remove non-existent origin: %q", lc.asString(":"))) - } - delete(cs.conditions[lc.name], lc.origin) + result &^= LicenseConditionSet(lc) } + return result } -// removeSet changes the set to delete all conditions also present in `other`. -func (cs *LicenseConditionSet) RemoveSet(other *LicenseConditionSet) { - for name, origins := range other.conditions { - if _, isPresent := cs.conditions[name]; !isPresent { - continue - } - for origin := range origins { - delete(cs.conditions[name], origin) +// Difference returns the subset of `cs` that are not members of any `other` +// set. +func (cs LicenseConditionSet) Difference(other ...LicenseConditionSet) LicenseConditionSet { + result := cs + for _, ls := range other { + result &^= ls + } + return result +} + +// Len returns the number of license conditions in the set. +func (cs LicenseConditionSet) Len() int { + size := 0 + for lc := LicenseConditionSet(0x01); 0x00 != (AllLicenseConditions & lc); lc <<= 1 { + if 0x00 != (cs & lc) { + size++ } } + return size } -// compliance-only LicenseConditionSet methods - -// newLicenseConditionSet constructs a set of `conditions`. -func newLicenseConditionSet() *LicenseConditionSet { - return &LicenseConditionSet{make(map[string]map[*TargetNode]struct{})} -} - -// add changes the set to include each element of `conditions` originating at `origin`. -func (cs *LicenseConditionSet) add(origin *TargetNode, conditions ...string) { - for _, name := range conditions { - if _, ok := cs.conditions[name]; !ok { - cs.conditions[name] = make(map[*TargetNode]struct{}) - } - cs.conditions[name][origin] = struct{}{} - } -} - -// asStringList returns the conditions in the set as `separator`-separated (origin, condition-name) pair strings. -func (cs *LicenseConditionSet) asStringList(separator string) []string { - result := make([]string, 0, cs.Count()) - for name, origins := range cs.conditions { - for origin := range origins { - result = append(result, origin.name+separator+name) +// AsList returns an array of the license conditions in the set. +func (cs LicenseConditionSet) AsList() []LicenseCondition { + result := make([]LicenseCondition, 0, cs.Len()) + for lc := LicenseConditionSet(0x01); 0x00 != (AllLicenseConditions & lc); lc <<= 1 { + if 0x00 != (cs & lc) { + result = append(result, LicenseCondition(lc)) } } return result } -// conditionNamesArray implements a `contains` predicate for arrays of ConditionNames -type conditionNamesArray []ConditionNames - -func (cn conditionNamesArray) contains(name string) bool { - for _, names := range cn { - if names.Contains(name) { - return true +// Names returns an array of the names of the license conditions in the set. +func (cs LicenseConditionSet) Names() []string { + result := make([]string, 0, cs.Len()) + for lc := LicenseConditionSet(0x01); 0x00 != (AllLicenseConditions & lc); lc <<= 1 { + if 0x00 != (cs & lc) { + result = append(result, LicenseCondition(lc).Name()) } } - return false + return result +} + +// IsEmpty returns true when the set contains no license conditions. +func (cs LicenseConditionSet) IsEmpty() bool { + return 0x00 == (cs & AllLicenseConditions) +} + +// String returns a human-readable string representation of the set. +func (cs LicenseConditionSet) String() string { + return fmt.Sprintf("{%s}", strings.Join(cs.Names(), "|")) } diff --git a/tools/compliance/conditionset_test.go b/tools/compliance/conditionset_test.go index eac0680486..c7306e7c14 100644 --- a/tools/compliance/conditionset_test.go +++ b/tools/compliance/conditionset_test.go @@ -15,576 +15,643 @@ package compliance import ( - "sort" "strings" "testing" ) -type byName map[string][]string - -func (bn byName) checkPublic(ls *LicenseConditionSet, t *testing.T) { - for names, expected := range bn { - name := ConditionNames(strings.Split(names, ":")) - if ls.HasAnyByName(name) { - if len(expected) == 0 { - t.Errorf("unexpected LicenseConditionSet.HasAnyByName(%q): got true, want false", name) - } - } else { - if len(expected) != 0 { - t.Errorf("unexpected LicenseConditionSet.HasAnyByName(%q): got false, want true", name) - } - } - if len(expected) != ls.CountByName(name) { - t.Errorf("unexpected LicenseConditionSet.CountByName(%q): got %d, want %d", name, ls.CountByName(name), len(expected)) - } - byName := ls.ByName(name).AsList() - if len(expected) != len(byName) { - t.Errorf("unexpected LicenseConditionSet.ByName(%q): got %v, want %v", name, byName, expected) - } else { - sort.Strings(expected) - actual := make([]string, 0, len(byName)) - for _, lc := range byName { - actual = append(actual, lc.Origin().Name()) - } - sort.Strings(actual) - for i := 0; i < len(expected); i++ { - if expected[i] != actual[i] { - t.Errorf("unexpected LicenseConditionSet.ByName(%q) index %d in %v: got %s, want %s", name, i, actual, actual[i], expected[i]) - } - } - } - } -} - -type byOrigin map[string][]string - -func (bo byOrigin) checkPublic(lg *LicenseGraph, ls *LicenseConditionSet, t *testing.T) { - expectedCount := 0 - for origin, expected := range bo { - expectedCount += len(expected) - onode := newTestNode(lg, origin) - if ls.HasAnyByOrigin(onode) { - if len(expected) == 0 { - t.Errorf("unexpected LicenseConditionSet.HasAnyByOrigin(%q): got true, want false", origin) - } - } else { - if len(expected) != 0 { - t.Errorf("unexpected LicenseConditionSet.HasAnyByOrigin(%q): got false, want true", origin) - } - } - if len(expected) != ls.CountByOrigin(onode) { - t.Errorf("unexpected LicenseConditionSet.CountByOrigin(%q): got %d, want %d", origin, ls.CountByOrigin(onode), len(expected)) - } - byOrigin := ls.ByOrigin(onode).AsList() - if len(expected) != len(byOrigin) { - t.Errorf("unexpected LicenseConditionSet.ByOrigin(%q): got %v, want %v", origin, byOrigin, expected) - } else { - sort.Strings(expected) - actual := make([]string, 0, len(byOrigin)) - for _, lc := range byOrigin { - actual = append(actual, lc.Name()) - } - sort.Strings(actual) - for i := 0; i < len(expected); i++ { - if expected[i] != actual[i] { - t.Errorf("unexpected LicenseConditionSet.ByOrigin(%q) index %d in %v: got %s, want %s", origin, i, actual, actual[i], expected[i]) - } - } - } - } - if expectedCount != ls.Count() { - t.Errorf("unexpected LicenseConditionSet.Count(): got %d, want %d", ls.Count(), expectedCount) - } - if ls.IsEmpty() { - if expectedCount != 0 { - t.Errorf("unexpected LicenseConditionSet.IsEmpty(): got true, want false") - } - } else { - if expectedCount == 0 { - t.Errorf("unexpected LicenseConditionSet.IsEmpty(): got false, want true") - } - } -} - func TestConditionSet(t *testing.T) { tests := []struct { - name string - conditions map[string][]string - add map[string][]string - byName map[string][]string - byOrigin map[string][]string + name string + conditions []string + plus *[]string + minus *[]string + matchingAny map[string][]string + expected []string }{ { name: "empty", - conditions: map[string][]string{}, - add: map[string][]string{}, - byName: map[string][]string{ + conditions: []string{}, + plus: &[]string{}, + matchingAny: map[string][]string{ "notice": []string{}, "restricted": []string{}, + "restricted|reciprocal": []string{}, }, - byOrigin: map[string][]string{ - "bin1": []string{}, - "lib1": []string{}, - "bin2": []string{}, - "lib2": []string{}, + expected: []string{}, + }, + { + name: "emptyminusnothing", + conditions: []string{}, + minus: &[]string{}, + matchingAny: map[string][]string{ + "notice": []string{}, + "restricted": []string{}, + "restricted|reciprocal": []string{}, }, + expected: []string{}, + }, + { + name: "emptyminusnotice", + conditions: []string{}, + minus: &[]string{"notice"}, + matchingAny: map[string][]string{ + "notice": []string{}, + "restricted": []string{}, + "restricted|reciprocal": []string{}, + }, + expected: []string{}, }, { name: "noticeonly", - conditions: map[string][]string{ - "notice": []string{"bin1", "lib1"}, - }, - byName: map[string][]string{ - "notice": []string{"bin1", "lib1"}, + conditions: []string{"notice"}, + matchingAny: map[string][]string{ + "notice": []string{"notice"}, + "notice|proprietary": []string{"notice"}, "restricted": []string{}, }, - byOrigin: map[string][]string{ - "bin1": []string{"notice"}, - "lib1": []string{"notice"}, - "bin2": []string{}, - "lib2": []string{}, - }, + expected: []string{"notice"}, }, { - name: "noticeonlyadded", - conditions: map[string][]string{ - "notice": []string{"bin1", "lib1"}, - }, - add: map[string][]string{ - "notice": []string{"bin1", "bin2"}, - }, - byName: map[string][]string{ - "notice": []string{"bin1", "bin2", "lib1"}, + name: "allnoticeonly", + conditions: []string{"notice"}, + plus: &[]string{"notice"}, + matchingAny: map[string][]string{ + "notice": []string{"notice"}, + "notice|proprietary": []string{"notice"}, "restricted": []string{}, }, - byOrigin: map[string][]string{ - "bin1": []string{"notice"}, - "lib1": []string{"notice"}, - "bin2": []string{"notice"}, - "lib2": []string{}, + expected: []string{"notice"}, + }, + { + name: "emptyplusnotice", + conditions: []string{}, + plus: &[]string{"notice"}, + matchingAny: map[string][]string{ + "notice": []string{"notice"}, + "notice|proprietary": []string{"notice"}, + "restricted": []string{}, }, + expected: []string{"notice"}, }, { name: "everything", - conditions: map[string][]string{ - "notice": []string{"bin1", "bin2", "lib1", "lib2"}, - "reciprocal": []string{"bin1", "bin2", "lib1", "lib2"}, - "restricted": []string{"bin1", "bin2", "lib1", "lib2"}, - "by_exception_only": []string{"bin1", "bin2", "lib1", "lib2"}, + conditions: []string{"unencumbered", "permissive", "notice", "reciprocal", "restricted", "proprietary"}, + plus: &[]string{"restricted_with_classpath_exception", "restricted_allows_dynamic_linking", "by_exception_only", "not_allowed"}, + matchingAny: map[string][]string{ + "unencumbered": []string{"unencumbered"}, + "permissive": []string{"permissive"}, + "notice": []string{"notice"}, + "reciprocal": []string{"reciprocal"}, + "restricted": []string{"restricted"}, + "restricted_with_classpath_exception": []string{"restricted_with_classpath_exception"}, + "restricted_allows_dynamic_linking": []string{"restricted_allows_dynamic_linking"}, + "proprietary": []string{"proprietary"}, + "by_exception_only": []string{"by_exception_only"}, + "not_allowed": []string{"not_allowed"}, + "notice|proprietary": []string{"notice", "proprietary"}, }, - add: map[string][]string{ - "notice": []string{"bin1", "bin2", "lib1", "lib2"}, - "reciprocal": []string{"bin1", "bin2", "lib1", "lib2"}, - "restricted": []string{"bin1", "bin2", "lib1", "lib2"}, - "by_exception_only": []string{"bin1", "bin2", "lib1", "lib2"}, - }, - byName: map[string][]string{ - "permissive": []string{}, - "notice": []string{"bin1", "bin2", "lib1", "lib2"}, - "reciprocal": []string{"bin1", "bin2", "lib1", "lib2"}, - "restricted": []string{"bin1", "bin2", "lib1", "lib2"}, - "by_exception_only": []string{"bin1", "bin2", "lib1", "lib2"}, - }, - byOrigin: map[string][]string{ - "bin1": []string{"notice", "reciprocal", "restricted", "by_exception_only"}, - "bin2": []string{"notice", "reciprocal", "restricted", "by_exception_only"}, - "lib1": []string{"notice", "reciprocal", "restricted", "by_exception_only"}, - "lib2": []string{"notice", "reciprocal", "restricted", "by_exception_only"}, - "other": []string{}, + expected: []string{ + "unencumbered", + "permissive", + "notice", + "reciprocal", + "restricted", + "restricted_with_classpath_exception", + "restricted_allows_dynamic_linking", + "proprietary", + "by_exception_only", + "not_allowed", }, }, { - name: "allbutoneeach", - conditions: map[string][]string{ - "notice": []string{"bin2", "lib1", "lib2"}, - "reciprocal": []string{"bin1", "lib1", "lib2"}, - "restricted": []string{"bin1", "bin2", "lib2"}, - "by_exception_only": []string{"bin1", "bin2", "lib1"}, + name: "everythingplusminusnothing", + conditions: []string{ + "unencumbered", + "permissive", + "notice", + "reciprocal", + "restricted", + "restricted_with_classpath_exception", + "restricted_allows_dynamic_linking", + "proprietary", + "by_exception_only", + "not_allowed", }, - byName: map[string][]string{ - "permissive": []string{}, - "notice": []string{"bin2", "lib1", "lib2"}, - "reciprocal": []string{"bin1", "lib1", "lib2"}, - "restricted": []string{"bin1", "bin2", "lib2"}, - "by_exception_only": []string{"bin1", "bin2", "lib1"}, + plus: &[]string{}, + minus: &[]string{}, + matchingAny: map[string][]string{ + "unencumbered|permissive|notice": []string{"unencumbered", "permissive", "notice"}, + "restricted|reciprocal": []string{"reciprocal", "restricted"}, + "proprietary|by_exception_only": []string{"proprietary", "by_exception_only"}, + "not_allowed": []string{"not_allowed"}, }, - byOrigin: map[string][]string{ - "bin1": []string{"reciprocal", "restricted", "by_exception_only"}, - "bin2": []string{"notice", "restricted", "by_exception_only"}, - "lib1": []string{"notice", "reciprocal", "by_exception_only"}, - "lib2": []string{"notice", "reciprocal", "restricted"}, - "other": []string{}, + expected: []string{ + "unencumbered", + "permissive", + "notice", + "reciprocal", + "restricted", + "restricted_with_classpath_exception", + "restricted_allows_dynamic_linking", + "proprietary", + "by_exception_only", + "not_allowed", }, }, { - name: "allbutoneeachadded", - conditions: map[string][]string{ - "notice": []string{"bin2", "lib1", "lib2"}, - "reciprocal": []string{"bin1", "lib1", "lib2"}, - "restricted": []string{"bin1", "bin2", "lib2"}, - "by_exception_only": []string{"bin1", "bin2", "lib1"}, + name: "allbutone", + conditions: []string{"unencumbered", "permissive", "notice", "reciprocal", "restricted", "proprietary"}, + plus: &[]string{"restricted_allows_dynamic_linking", "by_exception_only", "not_allowed"}, + matchingAny: map[string][]string{ + "unencumbered": []string{"unencumbered"}, + "permissive": []string{"permissive"}, + "notice": []string{"notice"}, + "reciprocal": []string{"reciprocal"}, + "restricted": []string{"restricted"}, + "restricted_with_classpath_exception": []string{}, + "restricted_allows_dynamic_linking": []string{"restricted_allows_dynamic_linking"}, + "proprietary": []string{"proprietary"}, + "by_exception_only": []string{"by_exception_only"}, + "not_allowed": []string{"not_allowed"}, + "notice|proprietary": []string{"notice", "proprietary"}, }, - add: map[string][]string{ - "notice": []string{"bin2", "lib1", "lib2"}, - "reciprocal": []string{"bin1", "lib1", "lib2"}, - "restricted": []string{"bin1", "bin2", "lib2"}, - "by_exception_only": []string{"bin1", "bin2", "lib1"}, - }, - byName: map[string][]string{ - "permissive": []string{}, - "notice": []string{"bin2", "lib1", "lib2"}, - "reciprocal": []string{"bin1", "lib1", "lib2"}, - "restricted": []string{"bin1", "bin2", "lib2"}, - "by_exception_only": []string{"bin1", "bin2", "lib1"}, - }, - byOrigin: map[string][]string{ - "bin1": []string{"reciprocal", "restricted", "by_exception_only"}, - "bin2": []string{"notice", "restricted", "by_exception_only"}, - "lib1": []string{"notice", "reciprocal", "by_exception_only"}, - "lib2": []string{"notice", "reciprocal", "restricted"}, - "other": []string{}, + expected: []string{ + "unencumbered", + "permissive", + "notice", + "reciprocal", + "restricted", + "restricted_allows_dynamic_linking", + "proprietary", + "by_exception_only", + "not_allowed", }, }, { - name: "allbutoneeachfilled", - conditions: map[string][]string{ - "notice": []string{"bin2", "lib1", "lib2"}, - "reciprocal": []string{"bin1", "lib1", "lib2"}, - "restricted": []string{"bin1", "bin2", "lib2"}, - "by_exception_only": []string{"bin1", "bin2", "lib1"}, + name: "everythingminusone", + conditions: []string{ + "unencumbered", + "permissive", + "notice", + "reciprocal", + "restricted", + "restricted_with_classpath_exception", + "restricted_allows_dynamic_linking", + "proprietary", + "by_exception_only", + "not_allowed", }, - add: map[string][]string{ - "notice": []string{"bin1", "bin2", "lib1"}, - "reciprocal": []string{"bin1", "bin2", "lib2"}, - "restricted": []string{"bin1", "lib1", "lib2"}, - "by_exception_only": []string{"bin2", "lib1", "lib2"}, + minus: &[]string{"restricted_allows_dynamic_linking"}, + matchingAny: map[string][]string{ + "unencumbered": []string{"unencumbered"}, + "permissive": []string{"permissive"}, + "notice": []string{"notice"}, + "reciprocal": []string{"reciprocal"}, + "restricted": []string{"restricted"}, + "restricted_with_classpath_exception": []string{"restricted_with_classpath_exception"}, + "restricted_allows_dynamic_linking": []string{}, + "proprietary": []string{"proprietary"}, + "by_exception_only": []string{"by_exception_only"}, + "not_allowed": []string{"not_allowed"}, + "restricted|proprietary": []string{"restricted", "proprietary"}, }, - byName: map[string][]string{ - "permissive": []string{}, - "notice": []string{"bin1", "bin2", "lib1", "lib2"}, - "reciprocal": []string{"bin1", "bin2", "lib1", "lib2"}, - "restricted": []string{"bin1", "bin2", "lib1", "lib2"}, - "by_exception_only": []string{"bin1", "bin2", "lib1", "lib2"}, - }, - byOrigin: map[string][]string{ - "bin1": []string{"notice", "reciprocal", "restricted", "by_exception_only"}, - "bin2": []string{"notice", "reciprocal", "restricted", "by_exception_only"}, - "lib1": []string{"notice", "reciprocal", "restricted", "by_exception_only"}, - "lib2": []string{"notice", "reciprocal", "restricted", "by_exception_only"}, - "other": []string{}, + expected: []string{ + "unencumbered", + "permissive", + "notice", + "reciprocal", + "restricted", + "restricted_with_classpath_exception", + "proprietary", + "by_exception_only", + "not_allowed", }, }, { - name: "oneeach", - conditions: map[string][]string{ - "notice": []string{"bin1"}, - "reciprocal": []string{"bin2"}, - "restricted": []string{"lib1"}, - "by_exception_only": []string{"lib2"}, + name: "everythingminuseverything", + conditions: []string{ + "unencumbered", + "permissive", + "notice", + "reciprocal", + "restricted", + "restricted_with_classpath_exception", + "restricted_allows_dynamic_linking", + "proprietary", + "by_exception_only", + "not_allowed", }, - byName: map[string][]string{ - "permissive": []string{}, - "notice": []string{"bin1"}, - "reciprocal": []string{"bin2"}, - "restricted": []string{"lib1"}, - "by_exception_only": []string{"lib2"}, + minus: &[]string{ + "unencumbered", + "permissive", + "notice", + "reciprocal", + "restricted", + "restricted_with_classpath_exception", + "restricted_allows_dynamic_linking", + "proprietary", + "by_exception_only", + "not_allowed", }, - byOrigin: map[string][]string{ - "bin1": []string{"notice"}, - "bin2": []string{"reciprocal"}, - "lib1": []string{"restricted"}, - "lib2": []string{"by_exception_only"}, - "other": []string{}, + matchingAny: map[string][]string{ + "unencumbered": []string{}, + "permissive": []string{}, + "notice": []string{}, + "reciprocal": []string{}, + "restricted": []string{}, + "restricted_with_classpath_exception": []string{}, + "restricted_allows_dynamic_linking": []string{}, + "proprietary": []string{}, + "by_exception_only": []string{}, + "not_allowed": []string{}, + "restricted|proprietary": []string{}, }, + expected: []string{}, }, { - name: "oneeachoverlap", - conditions: map[string][]string{ - "notice": []string{"bin1"}, - "reciprocal": []string{"bin2"}, - "restricted": []string{"lib1"}, - "by_exception_only": []string{"lib2"}, - }, - add: map[string][]string{ - "notice": []string{"lib2"}, - "reciprocal": []string{"lib1"}, - "restricted": []string{"bin2"}, - "by_exception_only": []string{"bin1"}, - }, - byName: map[string][]string{ - "permissive": []string{}, - "notice": []string{"bin1", "lib2"}, - "reciprocal": []string{"bin2", "lib1"}, - "restricted": []string{"bin2", "lib1"}, - "by_exception_only": []string{"bin1", "lib2"}, - }, - byOrigin: map[string][]string{ - "bin1": []string{"by_exception_only", "notice"}, - "bin2": []string{"reciprocal", "restricted"}, - "lib1": []string{"reciprocal", "restricted"}, - "lib2": []string{"by_exception_only", "notice"}, - "other": []string{}, - }, - }, - { - name: "oneeachadded", - conditions: map[string][]string{ - "notice": []string{"bin1"}, - "reciprocal": []string{"bin2"}, - "restricted": []string{"lib1"}, - "by_exception_only": []string{"lib2"}, - }, - add: map[string][]string{ - "notice": []string{"bin1"}, - "reciprocal": []string{"bin2"}, - "restricted": []string{"lib1"}, - "by_exception_only": []string{"lib2"}, - }, - byName: map[string][]string{ - "permissive": []string{}, - "notice": []string{"bin1"}, - "reciprocal": []string{"bin2"}, - "restricted": []string{"lib1"}, - "by_exception_only": []string{"lib2"}, - }, - byOrigin: map[string][]string{ - "bin1": []string{"notice"}, - "bin2": []string{"reciprocal"}, - "lib1": []string{"restricted"}, - "lib2": []string{"by_exception_only"}, - "other": []string{}, + name: "restrictedplus", + conditions: []string{"restricted", "restricted_with_classpath_exception", "restricted_allows_dynamic_linking"}, + plus: &[]string{"permissive", "notice", "restricted", "proprietary"}, + matchingAny: map[string][]string{ + "unencumbered": []string{}, + "permissive": []string{"permissive"}, + "notice": []string{"notice"}, + "restricted": []string{"restricted"}, + "restricted_with_classpath_exception": []string{"restricted_with_classpath_exception"}, + "restricted_allows_dynamic_linking": []string{"restricted_allows_dynamic_linking"}, + "proprietary": []string{"proprietary"}, + "restricted|proprietary": []string{"restricted", "proprietary"}, + "by_exception_only": []string{}, + "proprietary|by_exception_only": []string{"proprietary"}, }, + expected: []string{"permissive", "notice", "restricted", "restricted_with_classpath_exception", "restricted_allows_dynamic_linking", "proprietary"}, }, } for _, tt := range tests { - testPublicInterface := func(lg *LicenseGraph, cs *LicenseConditionSet, t *testing.T) { - byName(tt.byName).checkPublic(cs, t) - byOrigin(tt.byOrigin).checkPublic(lg, cs, t) + toConditions := func(names []string) []LicenseCondition { + result := make([]LicenseCondition, 0, len(names)) + for _, name := range names { + result = append(result, RecognizedConditionNames[name]) + } + return result } - t.Run(tt.name+"_public_interface", func(t *testing.T) { - lg := newLicenseGraph() - cs := NewLicenseConditionSet(toConditionList(lg, tt.conditions)...) - if tt.add != nil { - cs.Add(toConditionList(lg, tt.add)...) + populate := func() LicenseConditionSet { + testSet := NewLicenseConditionSet(toConditions(tt.conditions)...) + if tt.plus != nil { + testSet = testSet.Plus(toConditions(*tt.plus)...) } - testPublicInterface(lg, cs, t) - }) - - t.Run("Copy() of "+tt.name+"_public_interface", func(t *testing.T) { - lg := newLicenseGraph() - cs := NewLicenseConditionSet(toConditionList(lg, tt.conditions)...) - if tt.add != nil { - cs.Add(toConditionList(lg, tt.add)...) + if tt.minus != nil { + testSet = testSet.Minus(toConditions(*tt.minus)...) } - testPublicInterface(lg, cs.Copy(), t) - }) + return testSet + } + populateSet := func() LicenseConditionSet { + testSet := NewLicenseConditionSet(toConditions(tt.conditions)...) + if tt.plus != nil { + testSet = testSet.Union(NewLicenseConditionSet(toConditions(*tt.plus)...)) + } + if tt.minus != nil { + testSet = testSet.Difference(NewLicenseConditionSet(toConditions(*tt.minus)...)) + } + return testSet + } + populatePlusSet := func() LicenseConditionSet { + testSet := NewLicenseConditionSet(toConditions(tt.conditions)...) + if tt.plus != nil { + testSet = testSet.Union(NewLicenseConditionSet(toConditions(*tt.plus)...)) + } + if tt.minus != nil { + testSet = testSet.Minus(toConditions(*tt.minus)...) + } + return testSet + } + populateMinusSet := func() LicenseConditionSet { + testSet := NewLicenseConditionSet(toConditions(tt.conditions)...) + if tt.plus != nil { + testSet = testSet.Plus(toConditions(*tt.plus)...) + } + if tt.minus != nil { + testSet = testSet.Difference(NewLicenseConditionSet(toConditions(*tt.minus)...)) + } + return testSet + } + checkMatching := func(cs LicenseConditionSet, t *testing.T) { + for data, expectedNames := range tt.matchingAny { + expectedConditions := toConditions(expectedNames) + expected := NewLicenseConditionSet(expectedConditions...) + actual := cs.MatchingAny(toConditions(strings.Split(data, "|"))...) + actualNames := actual.Names() - testPrivateInterface := func(lg *LicenseGraph, cs *LicenseConditionSet, t *testing.T) { - slist := make([]string, 0, cs.Count()) - for origin, expected := range tt.byOrigin { - for _, name := range expected { - slist = append(slist, origin+";"+name) + t.Logf("MatchingAny(%s): actual set %04x %s", data, actual, actual.String()) + t.Logf("MatchingAny(%s): expected set %04x %s", data, expected, expected.String()) + + if actual != expected { + t.Errorf("MatchingAny(%s): got %04x, want %04x", data, actual, expected) + continue + } + if len(actualNames) != len(expectedNames) { + t.Errorf("len(MatchinAny(%s).Names()): got %d, want %d", + data, len(actualNames), len(expectedNames)) + } else { + for i := 0; i < len(actualNames); i++ { + if actualNames[i] != expectedNames[i] { + t.Errorf("MatchingAny(%s).Names()[%d]: got %s, want %s", + data, i, actualNames[i], expectedNames[i]) + break + } + } + } + actualConditions := actual.AsList() + if len(actualConditions) != len(expectedConditions) { + t.Errorf("len(MatchingAny(%d).AsList()): got %d, want %d", + data, len(actualNames), len(expectedNames)) + } else { + for i := 0; i < len(actualNames); i++ { + if actualNames[i] != expectedNames[i] { + t.Errorf("MatchingAny(%s).AsList()[%d]: got %s, want %s", + data, i, actualNames[i], expectedNames[i]) + break + } + } } } - actualSlist := cs.asStringList(";") - if len(slist) != len(actualSlist) { - t.Errorf("unexpected LicenseConditionSet.asStringList(\";\"): got %v, want %v", actualSlist, slist) + } + checkMatchingSet := func(cs LicenseConditionSet, t *testing.T) { + for data, expectedNames := range tt.matchingAny { + expected := NewLicenseConditionSet(toConditions(expectedNames)...) + actual := cs.MatchingAnySet(NewLicenseConditionSet(toConditions(strings.Split(data, "|"))...)) + actualNames := actual.Names() + + t.Logf("MatchingAnySet(%s): actual set %04x %s", data, actual, actual.String()) + t.Logf("MatchingAnySet(%s): expected set %04x %s", data, expected, expected.String()) + + if actual != expected { + t.Errorf("MatchingAnySet(%s): got %04x, want %04x", data, actual, expected) + continue + } + if len(actualNames) != len(expectedNames) { + t.Errorf("len(MatchingAnySet(%s).Names()): got %d, want %d", + data, len(actualNames), len(expectedNames)) + } else { + for i := 0; i < len(actualNames); i++ { + if actualNames[i] != expectedNames[i] { + t.Errorf("MatchingAnySet(%s).Names()[%d]: got %s, want %s", + data, i, actualNames[i], expectedNames[i]) + break + } + } + } + expectedConditions := toConditions(expectedNames) + actualConditions := actual.AsList() + if len(actualConditions) != len(expectedConditions) { + t.Errorf("len(MatchingAnySet(%s).AsList()): got %d, want %d", + data, len(actualNames), len(expectedNames)) + } else { + for i := 0; i < len(actualNames); i++ { + if actualNames[i] != expectedNames[i] { + t.Errorf("MatchingAnySet(%s).AsList()[%d]: got %s, want %s", + data, i, actualNames[i], expectedNames[i]) + break + } + } + } + } + } + + checkExpected := func(actual LicenseConditionSet, t *testing.T) bool { + t.Logf("checkExpected{%s}", strings.Join(tt.expected, ", ")) + + expectedConditions := toConditions(tt.expected) + expected := NewLicenseConditionSet(expectedConditions...) + + actualNames := actual.Names() + + t.Logf("actual license condition set: %04x %s", actual, actual.String()) + t.Logf("expected license condition set: %04x %s", expected, expected.String()) + + if actual != expected { + t.Errorf("checkExpected: got %04x, want %04x", actual, expected) + return false + } + + if len(actualNames) != len(tt.expected) { + t.Errorf("len(actual.Names()): got %d, want %d", len(actualNames), len(tt.expected)) } else { - sort.Strings(slist) - sort.Strings(actualSlist) - for i := 0; i < len(slist); i++ { - if slist[i] != actualSlist[i] { - t.Errorf("unexpected LicenseConditionSet.asStringList(\";\") index %d in %v: got %s, want %s", i, actualSlist, actualSlist[i], slist[i]) + for i := 0; i < len(actualNames); i++ { + if actualNames[i] != tt.expected[i] { + t.Errorf("actual.Names()[%d]: got %s, want %s", i, actualNames[i], tt.expected[i]) + break } } } + + actualConditions := actual.AsList() + if len(actualConditions) != len(expectedConditions) { + t.Errorf("len(actual.AsList()): got %d, want %d", len(actualConditions), len(expectedConditions)) + } else { + for i := 0; i < len(actualConditions); i++ { + if actualConditions[i] != expectedConditions[i] { + t.Errorf("actual.AsList()[%d]: got %s, want %s", + i, actualConditions[i], expectedConditions[i]) + break + } + } + } + + if len(tt.expected) == 0 { + if !actual.IsEmpty() { + t.Errorf("actual.IsEmpty(): got false, want true") + } + if actual.HasAny(expectedConditions...) { + t.Errorf("actual.HasAny(): got true, want false") + } + } else { + if actual.IsEmpty() { + t.Errorf("actual.IsEmpty(): got true, want false") + } + if !actual.HasAny(expectedConditions...) { + t.Errorf("actual.HasAny(all expected): got false, want true") + } + } + if !actual.HasAll(expectedConditions...) { + t.Errorf("actual.Hasll(all expected): want true, got false") + } + for _, expectedCondition := range expectedConditions { + if !actual.HasAny(expectedCondition) { + t.Errorf("actual.HasAny(%q): got false, want true", expectedCondition.Name()) + } + if !actual.HasAll(expectedCondition) { + t.Errorf("actual.HasAll(%q): got false, want true", expectedCondition.Name()) + } + } + + notExpected := (AllLicenseConditions &^ expected) + notExpectedList := notExpected.AsList() + t.Logf("not expected license condition set: %04x %s", notExpected, notExpected.String()) + + if len(tt.expected) == 0 { + if actual.HasAny(append(expectedConditions, notExpectedList...)...) { + t.Errorf("actual.HasAny(all conditions): want false, got true") + } + } else { + if !actual.HasAny(append(expectedConditions, notExpectedList...)...) { + t.Errorf("actual.HasAny(all conditions): want true, got false") + } + } + if len(notExpectedList) == 0 { + if !actual.HasAll(append(expectedConditions, notExpectedList...)...) { + t.Errorf("actual.HasAll(all conditions): want true, got false") + } + } else { + if actual.HasAll(append(expectedConditions, notExpectedList...)...) { + t.Errorf("actual.HasAll(all conditions): want false, got true") + } + } + for _, unexpectedCondition := range notExpectedList { + if actual.HasAny(unexpectedCondition) { + t.Errorf("actual.HasAny(%q): got true, want false", unexpectedCondition.Name()) + } + if actual.HasAll(unexpectedCondition) { + t.Errorf("actual.HasAll(%q): got true, want false", unexpectedCondition.Name()) + } + } + return true } - t.Run(tt.name+"_private_list_interface", func(t *testing.T) { - lg := newLicenseGraph() - cs := newLicenseConditionSet() - for name, origins := range tt.conditions { - for _, origin := range origins { - cs.add(newTestNode(lg, origin), name) - } - } - if tt.add != nil { - cs.Add(toConditionList(lg, tt.add)...) - } - testPrivateInterface(lg, cs, t) - }) + checkExpectedSet := func(actual LicenseConditionSet, t *testing.T) bool { + t.Logf("checkExpectedSet{%s}", strings.Join(tt.expected, ", ")) - t.Run(tt.name+"_private_set_interface", func(t *testing.T) { - lg := newLicenseGraph() - cs := newLicenseConditionSet() - for name, origins := range tt.conditions { - for _, origin := range origins { - cs.add(newTestNode(lg, origin), name) - } + expectedConditions := toConditions(tt.expected) + expected := NewLicenseConditionSet(expectedConditions...) + + actualNames := actual.Names() + + t.Logf("actual license condition set: %04x %s", actual, actual.String()) + t.Logf("expected license condition set: %04x %s", expected, expected.String()) + + if actual != expected { + t.Errorf("checkExpectedSet: got %04x, want %04x", actual, expected) + return false } - if tt.add != nil { - other := newLicenseConditionSet() - for name, origins := range tt.add { - for _, origin := range origins { - other.add(newTestNode(lg, origin), name) + + if len(actualNames) != len(tt.expected) { + t.Errorf("len(actual.Names()): got %d, want %d", len(actualNames), len(tt.expected)) + } else { + for i := 0; i < len(actualNames); i++ { + if actualNames[i] != tt.expected[i] { + t.Errorf("actual.Names()[%d]: got %s, want %s", i, actualNames[i], tt.expected[i]) + break } } - cs.AddSet(other) } - testPrivateInterface(lg, cs, t) - }) - } -} -func TestConditionSet_Removals(t *testing.T) { - tests := []struct { - name string - conditions map[string][]string - removeByName []ConditionNames - removeSet map[string][]string - byName map[string][]string - byOrigin map[string][]string - }{ - { - name: "emptybyname", - conditions: map[string][]string{}, - removeByName: []ConditionNames{{"reciprocal", "restricted"}}, - byName: map[string][]string{ - "notice": []string{}, - "restricted": []string{}, - }, - byOrigin: map[string][]string{ - "bin1": []string{}, - "lib1": []string{}, - "bin2": []string{}, - "lib2": []string{}, - }, - }, - { - name: "emptybyset", - conditions: map[string][]string{}, - removeSet: map[string][]string{ - "notice": []string{"bin1", "bin2"}, - "restricted": []string{"lib1", "lib2"}, - }, - byName: map[string][]string{ - "notice": []string{}, - "restricted": []string{}, - }, - byOrigin: map[string][]string{ - "bin1": []string{}, - "lib1": []string{}, - "bin2": []string{}, - "lib2": []string{}, - }, - }, - { - name: "everythingremovenone", - conditions: map[string][]string{ - "notice": []string{"bin1", "bin2", "lib1", "lib2"}, - "reciprocal": []string{"bin1", "bin2", "lib1", "lib2"}, - "restricted": []string{"bin1", "bin2", "lib1", "lib2"}, - "by_exception_only": []string{"bin1", "bin2", "lib1", "lib2"}, - }, - removeByName: []ConditionNames{{"permissive", "unencumbered"}}, - removeSet: map[string][]string{ - "notice": []string{"apk1"}, - }, - byName: map[string][]string{ - "permissive": []string{}, - "notice": []string{"bin1", "bin2", "lib1", "lib2"}, - "reciprocal": []string{"bin1", "bin2", "lib1", "lib2"}, - "restricted": []string{"bin1", "bin2", "lib1", "lib2"}, - "by_exception_only": []string{"bin1", "bin2", "lib1", "lib2"}, - }, - byOrigin: map[string][]string{ - "bin1": []string{"notice", "reciprocal", "restricted", "by_exception_only"}, - "bin2": []string{"notice", "reciprocal", "restricted", "by_exception_only"}, - "lib1": []string{"notice", "reciprocal", "restricted", "by_exception_only"}, - "lib2": []string{"notice", "reciprocal", "restricted", "by_exception_only"}, - "other": []string{}, - }, - }, - { - name: "everythingremovesome", - conditions: map[string][]string{ - "notice": []string{"bin1", "bin2", "lib1", "lib2"}, - "reciprocal": []string{"bin1", "bin2", "lib1", "lib2"}, - "restricted": []string{"bin1", "bin2", "lib1", "lib2"}, - "by_exception_only": []string{"bin1", "bin2", "lib1", "lib2"}, - }, - removeByName: []ConditionNames{{"restricted", "by_exception_only"}}, - removeSet: map[string][]string{ - "notice": []string{"lib1"}, - }, - byName: map[string][]string{ - "permissive": []string{}, - "notice": []string{"bin1", "bin2", "lib2"}, - "reciprocal": []string{"bin1", "bin2", "lib1", "lib2"}, - "restricted": []string{}, - "by_exception_only": []string{}, - }, - byOrigin: map[string][]string{ - "bin1": []string{"notice", "reciprocal"}, - "bin2": []string{"notice", "reciprocal"}, - "lib1": []string{"reciprocal"}, - "lib2": []string{"notice", "reciprocal"}, - "other": []string{}, - }, - }, - { - name: "everythingremoveall", - conditions: map[string][]string{ - "notice": []string{"bin1", "bin2", "lib1", "lib2"}, - "reciprocal": []string{"bin1", "bin2", "lib1", "lib2"}, - "restricted": []string{"bin1", "bin2", "lib1", "lib2"}, - "by_exception_only": []string{"bin1", "bin2", "lib1", "lib2"}, - }, - removeByName: []ConditionNames{{"restricted", "by_exception_only"}}, - removeSet: map[string][]string{ - "notice": []string{"bin1", "bin2", "lib1", "lib2"}, - "reciprocal": []string{"bin1", "bin2", "lib1", "lib2"}, - "restricted": []string{"bin1"}, - }, - byName: map[string][]string{ - "permissive": []string{}, - "notice": []string{}, - "reciprocal": []string{}, - "restricted": []string{}, - "by_exception_only": []string{}, - }, - byOrigin: map[string][]string{ - "bin1": []string{}, - "bin2": []string{}, - "lib1": []string{}, - "lib2": []string{}, - "other": []string{}, - }, - }, - } - for _, tt := range tests { + actualConditions := actual.AsList() + if len(actualConditions) != len(expectedConditions) { + t.Errorf("len(actual.AsList()): got %d, want %d", len(actualConditions), len(expectedConditions)) + } else { + for i := 0; i < len(actualConditions); i++ { + if actualConditions[i] != expectedConditions[i] { + t.Errorf("actual.AsList()[%d}: got %s, want %s", + i, actualConditions[i], expectedConditions[i]) + break + } + } + } + + if len(tt.expected) == 0 { + if !actual.IsEmpty() { + t.Errorf("actual.IsEmpty(): got false, want true") + } + if actual.MatchesAnySet(expected) { + t.Errorf("actual.MatchesAnySet({}): got true, want false") + } + if actual.MatchesEverySet(expected, expected) { + t.Errorf("actual.MatchesEverySet({}, {}): want false, got true") + } + } else { + if actual.IsEmpty() { + t.Errorf("actual.IsEmpty(): got true, want false") + } + if !actual.MatchesAnySet(expected) { + t.Errorf("actual.MatchesAnySet({all expected}): want true, got false") + } + if !actual.MatchesEverySet(expected, expected) { + t.Errorf("actual.MatchesEverySet({all expected}, {all expected}): want true, got false") + } + } + + notExpected := (AllLicenseConditions &^ expected) + t.Logf("not expected license condition set: %04x %s", notExpected, notExpected.String()) + + if len(tt.expected) == 0 { + if actual.MatchesAnySet(expected, notExpected) { + t.Errorf("empty actual.MatchesAnySet({expected}, {not expected}): want false, got true") + } + } else { + if !actual.MatchesAnySet(expected, notExpected) { + t.Errorf("actual.MatchesAnySet({expected}, {not expected}): want true, got false") + } + } + if actual.MatchesAnySet(notExpected) { + t.Errorf("actual.MatchesAnySet({not expected}): want false, got true") + } + if actual.MatchesEverySet(notExpected) { + t.Errorf("actual.MatchesEverySet({not expected}): want false, got true") + } + if actual.MatchesEverySet(expected, notExpected) { + t.Errorf("actual.MatchesEverySet({expected}, {not expected}): want false, got true") + } + + if !actual.Difference(expected).IsEmpty() { + t.Errorf("actual.Difference({expected}).IsEmpty(): want true, got false") + } + if expected != actual.Intersection(expected) { + t.Errorf("expected == actual.Intersection({expected}): want true, got false (%04x != %04x)", expected, actual.Intersection(expected)) + } + if actual != actual.Intersection(expected) { + t.Errorf("actual == actual.Intersection({expected}): want true, got false (%04x != %04x)", actual, actual.Intersection(expected)) + } + return true + } + t.Run(tt.name, func(t *testing.T) { - lg := newLicenseGraph() - cs := newLicenseConditionSet() - for name, origins := range tt.conditions { - for _, origin := range origins { - cs.add(newTestNode(lg, origin), name) - } + cs := populate() + if checkExpected(cs, t) { + checkMatching(cs, t) } - if tt.removeByName != nil { - cs.RemoveAllByName(tt.removeByName...) + if checkExpectedSet(cs, t) { + checkMatchingSet(cs, t) } - if tt.removeSet != nil { - other := newLicenseConditionSet() - for name, origins := range tt.removeSet { - for _, origin := range origins { - other.add(newTestNode(lg, origin), name) - } - } - cs.RemoveSet(other) + }) + + t.Run(tt.name+"_sets", func(t *testing.T) { + cs := populateSet() + if checkExpected(cs, t) { + checkMatching(cs, t) + } + if checkExpectedSet(cs, t){ + checkMatchingSet(cs, t) + } + }) + + t.Run(tt.name+"_plusset", func(t *testing.T) { + cs := populatePlusSet() + if checkExpected(cs, t) { + checkMatching(cs, t) + } + if checkExpectedSet(cs, t){ + checkMatchingSet(cs, t) + } + }) + + t.Run(tt.name+"_minusset", func(t *testing.T) { + cs := populateMinusSet() + if checkExpected(cs, t) { + checkMatching(cs, t) + } + if checkExpectedSet(cs, t){ + checkMatchingSet(cs, t) } - byName(tt.byName).checkPublic(cs, t) - byOrigin(tt.byOrigin).checkPublic(lg, cs, t) }) } } diff --git a/tools/compliance/graph.go b/tools/compliance/graph.go index f26e7e83a7..97fa657fd7 100644 --- a/tools/compliance/graph.go +++ b/tools/compliance/graph.go @@ -52,30 +52,19 @@ type LicenseGraph struct { // edges lists the directed edges in the graph from target to dependency. (guarded by mu) // // Alternatively, the graph is the set of `edges`. - edges []*dependencyEdge + edges TargetEdgeList - // targets identifies, indexes by name, and describes the entire set of target node files. + // targets identifies, indexes, and describes the entire set of target node files. /// (guarded by mu) targets map[string]*TargetNode - // index facilitates looking up edges from targets. (creation guarded by my) - // - // This is a forward index from target to dependencies. i.e. "top-down" - index map[string][]*dependencyEdge + // wgBU becomes non-nil when the bottom-up resolve begins and reaches 0 + // (i.e. Wait() proceeds) when the bottom-up resolve completes. (guarded by mu) + wgBU *sync.WaitGroup - // rsBU caches the results of a full bottom-up resolve. (creation guarded by mu) - // - // A bottom-up resolve is a prerequisite for all of the top-down resolves so caching - // the result is a performance win. - rsBU *ResolutionSet - - // rsTD caches the results of a full top-down resolve. (creation guarded by mu) - // - // A top-down resolve is a prerequisite for final resolutions. - // e.g. a shipped node inheriting a `restricted` condition from a parent through a - // dynamic dependency implies a notice dependency on the parent; even though, the - // distribution does not happen as a result of the dynamic dependency itself. - rsTD *ResolutionSet + // wgTD becomes non-nil when the top-down resolve begins and reaches 0 (i.e. Wait() + // proceeds) when the top-down resolve completes. (guarded by mu) + wgTD *sync.WaitGroup // shippedNodes caches the results of a full walk of nodes identifying targets // distributed either directly or as derivative works. (creation guarded by mu) @@ -85,35 +74,18 @@ type LicenseGraph struct { mu sync.Mutex } -// TargetNode returns the target node identified by `name`. -func (lg *LicenseGraph) TargetNode(name string) *TargetNode { - if _, ok := lg.targets[name]; !ok { - panic(fmt.Errorf("target node %q missing from graph", name)) - } - return lg.targets[name] -} - -// HasTargetNode returns true if a target node identified by `name` appears in -// the graph. -func (lg *LicenseGraph) HasTargetNode(name string) bool { - _, isPresent := lg.targets[name] - return isPresent -} - // Edges returns the list of edges in the graph. (unordered) func (lg *LicenseGraph) Edges() TargetEdgeList { edges := make(TargetEdgeList, 0, len(lg.edges)) - for _, e := range lg.edges { - edges = append(edges, TargetEdge{lg, e}) - } + edges = append(edges, lg.edges...) return edges } // Targets returns the list of target nodes in the graph. (unordered) func (lg *LicenseGraph) Targets() TargetNodeList { targets := make(TargetNodeList, 0, len(lg.targets)) - for target := range lg.targets { - targets = append(targets, lg.targets[target]) + for _, target := range lg.targets { + targets = append(targets, target) } return targets } @@ -124,33 +96,10 @@ func (lg *LicenseGraph) Targets() TargetNodeList { func newLicenseGraph() *LicenseGraph { return &LicenseGraph{ rootFiles: []string{}, - edges: make([]*dependencyEdge, 0, 1000), targets: make(map[string]*TargetNode), } } -// indexForward guarantees the `index` map is populated to look up edges by -// `target`. -func (lg *LicenseGraph) indexForward() { - lg.mu.Lock() - defer func() { - lg.mu.Unlock() - }() - - if lg.index != nil { - return - } - - lg.index = make(map[string][]*dependencyEdge) - for _, e := range lg.edges { - if _, ok := lg.index[e.target]; ok { - lg.index[e.target] = append(lg.index[e.target], e) - } else { - lg.index[e.target] = []*dependencyEdge{e} - } - } -} - // TargetEdge describes a directed, annotated edge from a target to a // dependency. (immutable) // @@ -159,25 +108,25 @@ func (lg *LicenseGraph) indexForward() { // i.e. `Target` depends on `Dependency` in the manner described by // `Annotations`. type TargetEdge struct { - // lg identifies the scope, i.e. license graph, in which the edge appears. - lg *LicenseGraph + // target and dependency identify the nodes connected by the edge. + target, dependency *TargetNode - // e identifies describes the target, dependency, and annotations of the edge. - e *dependencyEdge + // annotations identifies the set of compliance-relevant annotations describing the edge. + annotations TargetEdgeAnnotations } // Target identifies the target that depends on the dependency. // // Target needs Dependency to build. -func (e TargetEdge) Target() *TargetNode { - return e.lg.targets[e.e.target] +func (e *TargetEdge) Target() *TargetNode { + return e.target } // Dependency identifies the target depended on by the target. // // Dependency builds without Target, but Target needs Dependency to build. -func (e TargetEdge) Dependency() *TargetNode { - return e.lg.targets[e.e.dependency] +func (e *TargetEdge) Dependency() *TargetNode { + return e.dependency } // Annotations describes the type of edge by the set of annotations attached to @@ -186,12 +135,17 @@ func (e TargetEdge) Dependency() *TargetNode { // Only annotations prescribed by policy have any meaning for licensing, and // the meaning for licensing is likewise prescribed by policy. Other annotations // are preserved and ignored by policy. -func (e TargetEdge) Annotations() TargetEdgeAnnotations { - return e.e.annotations +func (e *TargetEdge) Annotations() TargetEdgeAnnotations { + return e.annotations +} + +// String returns a human-readable string representation of the edge. +func (e *TargetEdge) String() string { + return fmt.Sprintf("%s -[%s]> %s", e.target.name, strings.Join(e.annotations.AsList(), ", "), e.dependency.name) } // TargetEdgeList orders lists of edges by target then dependency then annotations. -type TargetEdgeList []TargetEdge +type TargetEdgeList []*TargetEdge // Len returns the count of the elmements in the list. func (l TargetEdgeList) Len() int { return len(l) } @@ -201,18 +155,63 @@ func (l TargetEdgeList) Swap(i, j int) { l[i], l[j] = l[j], l[i] } // Less returns true when the `i`th element is lexicographically less than the `j`th. func (l TargetEdgeList) Less(i, j int) bool { - if l[i].e.target == l[j].e.target { - if l[i].e.dependency == l[j].e.dependency { - return l[i].e.annotations.Compare(l[j].e.annotations) < 0 - } - return l[i].e.dependency < l[j].e.dependency + namei := l[i].target.name + namej := l[j].target.name + if namei == namej { + namei = l[i].dependency.name + namej = l[j].dependency.name } - return l[i].e.target < l[j].e.target + if namei == namej { + return l[i].annotations.Compare(l[j].annotations) < 0 + } + return namei < namej +} + +// TargetEdgePathSegment describes a single arc in a TargetPath associating the +// edge with a context `ctx` defined by whatever process is creating the path. +type TargetEdgePathSegment struct { + edge *TargetEdge + ctx interface{} +} + +// Target identifies the target that depends on the dependency. +// +// Target needs Dependency to build. +func (s TargetEdgePathSegment) Target() *TargetNode { + return s.edge.target +} + +// Dependency identifies the target depended on by the target. +// +// Dependency builds without Target, but Target needs Dependency to build. +func (s TargetEdgePathSegment) Dependency() *TargetNode { + return s.edge.dependency +} + +// Annotations describes the type of edge by the set of annotations attached to +// it. +// +// Only annotations prescribed by policy have any meaning for licensing, and +// the meaning for licensing is likewise prescribed by policy. Other annotations +// are preserved and ignored by policy. +func (s TargetEdgePathSegment) Annotations() TargetEdgeAnnotations { + return s.edge.annotations +} + +// Context returns the context associated with the path segment. The type and +// value of the context defined by the process creating the path. +func (s TargetEdgePathSegment) Context() interface{} { + return s.ctx +} + +// String returns a human-readable string representation of the edge. +func (s TargetEdgePathSegment) String() string { + return fmt.Sprintf("%s -[%s]> %s", s.edge.target.name, strings.Join(s.edge.annotations.AsList(), ", "), s.edge.dependency.name) } // TargetEdgePath describes a sequence of edges starting at a root and ending // at some final dependency. -type TargetEdgePath []TargetEdge +type TargetEdgePath []TargetEdgePathSegment // NewTargetEdgePath creates a new, empty path with capacity `cap`. func NewTargetEdgePath(cap int) *TargetEdgePath { @@ -222,15 +221,15 @@ func NewTargetEdgePath(cap int) *TargetEdgePath { // Push appends a new edge to the list verifying that the target of the new // edge is the dependency of the prior. -func (p *TargetEdgePath) Push(edge TargetEdge) { +func (p *TargetEdgePath) Push(edge *TargetEdge, ctx interface{}) { if len(*p) == 0 { - *p = append(*p, edge) + *p = append(*p, TargetEdgePathSegment{edge, ctx}) return } - if (*p)[len(*p)-1].e.dependency != edge.e.target { - panic(fmt.Errorf("disjoint path %s does not end at %s", p.String(), edge.e.target)) + if (*p)[len(*p)-1].edge.dependency != edge.target { + panic(fmt.Errorf("disjoint path %s does not end at %s", p.String(), edge.target.name)) } - *p = append(*p, edge) + *p = append(*p, TargetEdgePathSegment{edge, ctx}) } // Pop shortens the path by 1 edge. @@ -256,10 +255,11 @@ func (p *TargetEdgePath) String() string { } var sb strings.Builder fmt.Fprintf(&sb, "[") - for _, e := range *p { - fmt.Fprintf(&sb, "%s -> ", e.e.target) + for _, s := range *p { + fmt.Fprintf(&sb, "%s -> ", s.edge.target.name) } - fmt.Fprintf(&sb, "%s]", (*p)[len(*p)-1].e.dependency) + lastSegment := (*p)[len(*p)-1] + fmt.Fprintf(&sb, "%s]", lastSegment.edge.dependency.name) return sb.String() } @@ -279,6 +279,13 @@ func (tn *TargetNode) Name() string { return tn.name } +// Dependencies returns the list of edges to dependencies of `tn`. +func (tn *TargetNode) Dependencies() TargetEdgeList { + edges := make(TargetEdgeList, 0, len(tn.edges)) + edges = append(edges, tn.edges...) + return edges +} + // PackageName returns the string that identifes the package for the target. func (tn *TargetNode) PackageName() string { return tn.proto.GetPackageName() @@ -323,10 +330,8 @@ func (tn *TargetNode) LicenseKinds() []string { // is a matter of policy. (unordered) // // e.g. notice or proprietary -func (tn *TargetNode) LicenseConditions() *LicenseConditionSet { - result := newLicenseConditionSet() - result.add(tn, tn.proto.LicenseConditions...) - return result +func (tn *TargetNode) LicenseConditions() LicenseConditionSet { + return tn.licenseConditions } // LicenseTexts returns the paths to the files containing the license texts for @@ -466,6 +471,11 @@ func (ts *TargetNodeSet) Names() []string { return result } +// String returns a human-readable string representation of the set. +func (ts *TargetNodeSet) String() string { + return fmt.Sprintf("{%s}", strings.Join(ts.Names(), ", ")) +} + // TargetNodeList orders a list of targets by name. type TargetNodeList []*TargetNode diff --git a/tools/compliance/policy/policy.go b/tools/compliance/policy/policy.go index d3e412b84e..581912a7ee 100644 --- a/tools/compliance/policy/policy.go +++ b/tools/compliance/policy/policy.go @@ -30,31 +30,33 @@ var ( } // ImpliesUnencumbered lists the condition names representing an author attempt to disclaim copyright. - ImpliesUnencumbered = ConditionNames{"unencumbered"} + ImpliesUnencumbered = LicenseConditionSet(UnencumberedCondition) // ImpliesPermissive lists the condition names representing copyrighted but "licensed without policy requirements". - ImpliesPermissive = ConditionNames{"permissive"} + ImpliesPermissive = LicenseConditionSet(PermissiveCondition) // ImpliesNotice lists the condition names implying a notice or attribution policy. - ImpliesNotice = ConditionNames{"unencumbered", "permissive", "notice", "reciprocal", "restricted", "proprietary", "by_exception_only"} + ImpliesNotice = LicenseConditionSet(UnencumberedCondition | PermissiveCondition | NoticeCondition | ReciprocalCondition | + RestrictedCondition | RestrictedClasspathExceptionCondition | WeaklyRestrictedCondition | + ProprietaryCondition | ByExceptionOnlyCondition) // ImpliesReciprocal lists the condition names implying a local source-sharing policy. - ImpliesReciprocal = ConditionNames{"reciprocal"} + ImpliesReciprocal = LicenseConditionSet(ReciprocalCondition) // Restricted lists the condition names implying an infectious source-sharing policy. - ImpliesRestricted = ConditionNames{"restricted"} + ImpliesRestricted = LicenseConditionSet(RestrictedCondition | RestrictedClasspathExceptionCondition | WeaklyRestrictedCondition) // ImpliesProprietary lists the condition names implying a confidentiality policy. - ImpliesProprietary = ConditionNames{"proprietary"} + ImpliesProprietary = LicenseConditionSet(ProprietaryCondition) // ImpliesByExceptionOnly lists the condition names implying a policy for "license review and approval before use". - ImpliesByExceptionOnly = ConditionNames{"proprietary", "by_exception_only"} + ImpliesByExceptionOnly = LicenseConditionSet(ProprietaryCondition | ByExceptionOnlyCondition) // ImpliesPrivate lists the condition names implying a source-code privacy policy. - ImpliesPrivate = ConditionNames{"proprietary"} + ImpliesPrivate = LicenseConditionSet(ProprietaryCondition) // ImpliesShared lists the condition names implying a source-code sharing policy. - ImpliesShared = ConditionNames{"reciprocal", "restricted"} + ImpliesShared = LicenseConditionSet(ReciprocalCondition | RestrictedCondition | RestrictedClasspathExceptionCondition | WeaklyRestrictedCondition) ) var ( @@ -64,100 +66,117 @@ var ( ccBySa = regexp.MustCompile(`^SPDX-license-identifier-CC-BY.*-SA.*`) ) -// Resolution happens in two passes: + +// LicenseConditionSetFromNames returns a set containing the recognized `names` and +// silently ignoring or discarding the unrecognized `names`. +func LicenseConditionSetFromNames(tn *TargetNode, names ...string) LicenseConditionSet { + cs := NewLicenseConditionSet() + for _, name := range names { + if name == "restricted" { + if 0 == len(tn.LicenseKinds()) { + cs = cs.Plus(RestrictedCondition) + continue + } + hasLgpl := false + hasClasspath := false + hasGeneric := false + for _, kind := range tn.LicenseKinds() { + if strings.HasSuffix(kind, "-with-classpath-exception") { + cs = cs.Plus(RestrictedClasspathExceptionCondition) + hasClasspath = true + } else if anyLgpl.MatchString(kind) { + cs = cs.Plus(WeaklyRestrictedCondition) + hasLgpl = true + } else if versionedGpl.MatchString(kind) { + cs = cs.Plus(RestrictedCondition) + } else if genericGpl.MatchString(kind) { + hasGeneric = true + } else if kind == "legacy_restricted" || ccBySa.MatchString(kind) { + cs = cs.Plus(RestrictedCondition) + } else { + cs = cs.Plus(RestrictedCondition) + } + } + if hasGeneric && !hasLgpl && !hasClasspath { + cs = cs.Plus(RestrictedCondition) + } + continue + } + if lc, ok := RecognizedConditionNames[name]; ok { + cs |= LicenseConditionSet(lc) + } + } + return cs +} + + +// Resolution happens in three phases: // -// 1. A bottom-up traversal propagates license conditions up to targets from -// dendencies as needed. +// 1. A bottom-up traversal propagates (restricted) license conditions up to +// targets from dendencies as needed. // -// 2. For each condition of interest, a top-down traversal adjusts the attached -// conditions pushing restricted down from targets into linked dependencies. +// 2. For each condition of interest, a top-down traversal propagates +// (restricted) conditions down from targets into linked dependencies. // -// The behavior of the 2 passes gets controlled by the 2 functions below. +// 3. Finally, a walk of the shipped target nodes attaches resolutions to the +// ancestor nodes from the root down to and including the first non-container. // -// The first function controls what happens during the bottom-up traversal. In -// general conditions flow up through static links but not other dependencies; -// except, restricted sometimes flows up through dynamic links. +// e.g. If a disk image contains a binary bin1 that links a library liba, the +// notice requirement for liba gets attached to the disk image and to bin1. +// Because liba doesn't actually get shipped as a separate artifact, but only +// as bits in bin1, it has no actions 'attached' to it. The actions attached +// to the image and to bin1 'act on' liba by providing notice. // -// In general, too, the originating target gets acted on to resolve the -// condition (e.g. providing notice), but again restricted is special in that -// it requires acting on (i.e. sharing source of) both the originating module -// and the target using the module. +// The behavior of the 3 phases gets controlled by the 3 functions below. // -// The latter function controls what happens during the top-down traversal. In -// general, only restricted conditions flow down at all, and only through -// static links. +// The first function controls what happens during the bottom-up propagation. +// Restricted conditions propagate up all non-toolchain dependencies; except, +// some do not propagate up dynamic links, which may depend on whether the +// modules are independent. +// +// The second function controls what happens during the top-down propagation. +// Restricted conditions propagate down as above with the added caveat that +// inherited restricted conditions do not propagate from pure aggregates to +// their dependencies. +// +// The final function controls which conditions apply/get attached to ancestors +// depending on the types of dependencies involved. All conditions apply across +// normal derivation dependencies. No conditions apply across toolchain +// dependencies. Some restricted conditions apply across dynamic link +// dependencies. // // Not all restricted licenses are create equal. Some have special rules or // exceptions. e.g. LGPL or "with classpath excption". -// depActionsApplicableToTarget returns the actions which propagate up an + +// depConditionsPropagatingToTarget returns the conditions which propagate up an // edge from dependency to target. // -// This function sets the policy for the bottom-up traversal and how conditions +// This function sets the policy for the bottom-up propagation and how conditions // flow up the graph from dependencies to targets. // // If a pure aggregation is built into a derivative work that is not a pure // aggregation, per policy it ceases to be a pure aggregation in the context of // that derivative work. The `treatAsAggregate` parameter will be false for // non-aggregates and for aggregates in non-aggregate contexts. -func depActionsApplicableToTarget(e TargetEdge, depActions actionSet, treatAsAggregate bool) actionSet { - result := make(actionSet) +func depConditionsPropagatingToTarget(lg *LicenseGraph, e *TargetEdge, depConditions LicenseConditionSet, treatAsAggregate bool) LicenseConditionSet { + result := LicenseConditionSet(0x0000) if edgeIsDerivation(e) { - result.addSet(depActions) - for _, cs := range depActions.byName(ImpliesRestricted) { - result.add(e.Target(), cs) - } + result |= depConditions & ImpliesRestricted return result } if !edgeIsDynamicLink(e) { return result } - restricted := depActions.byName(ImpliesRestricted) - for actsOn, cs := range restricted { - for _, lc := range cs.AsList() { - hasGpl := false - hasLgpl := false - hasClasspath := false - hasGeneric := false - hasOther := false - for _, kind := range lc.origin.LicenseKinds() { - if strings.HasSuffix(kind, "-with-classpath-exception") { - hasClasspath = true - } else if anyLgpl.MatchString(kind) { - hasLgpl = true - } else if versionedGpl.MatchString(kind) { - hasGpl = true - } else if genericGpl.MatchString(kind) { - hasGeneric = true - } else if kind == "legacy_restricted" || ccBySa.MatchString(kind) { - hasOther = true - } - } - if hasOther || hasGpl { - result.addCondition(actsOn, lc) - result.addCondition(e.Target(), lc) - continue - } - if hasClasspath && !edgeNodesAreIndependentModules(e) { - result.addCondition(actsOn, lc) - result.addCondition(e.Target(), lc) - continue - } - if hasLgpl || hasClasspath { - continue - } - if !hasGeneric { - continue - } - result.addCondition(actsOn, lc) - result.addCondition(e.Target(), lc) - } + result |= depConditions & LicenseConditionSet(RestrictedCondition) + if 0 != (depConditions & LicenseConditionSet(RestrictedClasspathExceptionCondition)) && !edgeNodesAreIndependentModules(e) { + result |= LicenseConditionSet(RestrictedClasspathExceptionCondition) } return result } -// targetConditionsApplicableToDep returns the conditions which propagate down +// targetConditionsPropagatingToDep returns the conditions which propagate down // an edge from target to dependency. // // This function sets the policy for the top-down traversal and how conditions @@ -167,81 +186,73 @@ func depActionsApplicableToTarget(e TargetEdge, depActions actionSet, treatAsAgg // aggregation, per policy it ceases to be a pure aggregation in the context of // that derivative work. The `treatAsAggregate` parameter will be false for // non-aggregates and for aggregates in non-aggregate contexts. -func targetConditionsApplicableToDep(e TargetEdge, targetConditions *LicenseConditionSet, treatAsAggregate bool) *LicenseConditionSet { - result := targetConditions.Copy() +func targetConditionsPropagatingToDep(lg *LicenseGraph, e *TargetEdge, targetConditions LicenseConditionSet, treatAsAggregate bool) LicenseConditionSet { + result := targetConditions // reverse direction -- none of these apply to things depended-on, only to targets depending-on. - result.RemoveAllByName(ConditionNames{"unencumbered", "permissive", "notice", "reciprocal", "proprietary", "by_exception_only"}) + result = result.Minus(UnencumberedCondition, PermissiveCondition, NoticeCondition, ReciprocalCondition, ProprietaryCondition, ByExceptionOnlyCondition) if !edgeIsDerivation(e) && !edgeIsDynamicLink(e) { // target is not a derivative work of dependency and is not linked to dependency - result.RemoveAllByName(ImpliesRestricted) + result = result.Difference(ImpliesRestricted) return result } if treatAsAggregate { // If the author of a pure aggregate licenses it restricted, apply restricted to immediate dependencies. // Otherwise, restricted does not propagate back down to dependencies. - restricted := result.ByName(ImpliesRestricted).AsList() - for _, lc := range restricted { - if lc.origin.name != e.e.target { - result.Remove(lc) - } + if !LicenseConditionSetFromNames(e.target, e.target.proto.LicenseConditions...).MatchesAnySet(ImpliesRestricted) { + result = result.Difference(ImpliesRestricted) } return result } if edgeIsDerivation(e) { return result } - restricted := result.ByName(ImpliesRestricted).AsList() - for _, lc := range restricted { - hasGpl := false - hasLgpl := false - hasClasspath := false - hasGeneric := false - hasOther := false - for _, kind := range lc.origin.LicenseKinds() { - if strings.HasSuffix(kind, "-with-classpath-exception") { - hasClasspath = true - } else if anyLgpl.MatchString(kind) { - hasLgpl = true - } else if versionedGpl.MatchString(kind) { - hasGpl = true - } else if genericGpl.MatchString(kind) { - hasGeneric = true - } else if kind == "legacy_restricted" || ccBySa.MatchString(kind) { - hasOther = true - } - } - if hasOther || hasGpl { - continue - } - if hasClasspath && !edgeNodesAreIndependentModules(e) { - continue - } - if hasGeneric && !hasLgpl && !hasClasspath { - continue - } - result.Remove(lc) + result = result.Minus(WeaklyRestrictedCondition) + if edgeNodesAreIndependentModules(e) { + result = result.Minus(RestrictedClasspathExceptionCondition) } return result } +// conditionsAttachingAcrossEdge returns the subset of conditions in `universe` +// that apply across edge `e`. +// +// This function sets the policy for attaching actions to ancestor nodes in the +// final resolution walk. +func conditionsAttachingAcrossEdge(lg *LicenseGraph, e *TargetEdge, universe LicenseConditionSet) LicenseConditionSet { + result := universe + if edgeIsDerivation(e) { + return result + } + if !edgeIsDynamicLink(e) { + return NewLicenseConditionSet() + } + + result &= LicenseConditionSet(RestrictedCondition | RestrictedClasspathExceptionCondition) + if 0 != (result & LicenseConditionSet(RestrictedClasspathExceptionCondition)) && edgeNodesAreIndependentModules(e) { + result &= LicenseConditionSet(RestrictedCondition) + } + return result +} + + // edgeIsDynamicLink returns true for edges representing shared libraries // linked dynamically at runtime. -func edgeIsDynamicLink(e TargetEdge) bool { - return e.e.annotations.HasAnnotation("dynamic") +func edgeIsDynamicLink(e *TargetEdge) bool { + return e.annotations.HasAnnotation("dynamic") } // edgeIsDerivation returns true for edges where the target is a derivative // work of dependency. -func edgeIsDerivation(e TargetEdge) bool { - isDynamic := e.e.annotations.HasAnnotation("dynamic") - isToolchain := e.e.annotations.HasAnnotation("toolchain") +func edgeIsDerivation(e *TargetEdge) bool { + isDynamic := e.annotations.HasAnnotation("dynamic") + isToolchain := e.annotations.HasAnnotation("toolchain") return !isDynamic && !isToolchain } // edgeNodesAreIndependentModules returns true for edges where the target and // dependency are independent modules. -func edgeNodesAreIndependentModules(e TargetEdge) bool { - return e.Target().PackageName() != e.Dependency().PackageName() +func edgeNodesAreIndependentModules(e *TargetEdge) bool { + return e.target.PackageName() != e.dependency.PackageName() } diff --git a/tools/compliance/policy/policy_test.go b/tools/compliance/policy/policy_test.go index aea307f87e..09e831cc23 100644 --- a/tools/compliance/policy/policy_test.go +++ b/tools/compliance/policy/policy_test.go @@ -34,21 +34,21 @@ func TestPolicy_edgeConditions(t *testing.T) { { name: "firstparty", edge: annotated{"apacheBin.meta_lic", "apacheLib.meta_lic", []string{"static"}}, - expectedDepActions: []string{"apacheLib.meta_lic:apacheLib.meta_lic:notice"}, + expectedDepActions: []string{}, expectedTargetConditions: []string{}, }, { name: "notice", edge: annotated{"mitBin.meta_lic", "mitLib.meta_lic", []string{"static"}}, - expectedDepActions: []string{"mitLib.meta_lic:mitLib.meta_lic:notice"}, + expectedDepActions: []string{}, expectedTargetConditions: []string{}, }, { name: "fponlgpl", edge: annotated{"apacheBin.meta_lic", "lgplLib.meta_lic", []string{"static"}}, expectedDepActions: []string{ - "apacheBin.meta_lic:lgplLib.meta_lic:restricted", - "lgplLib.meta_lic:lgplLib.meta_lic:restricted", + "apacheBin.meta_lic:lgplLib.meta_lic:restricted_allows_dynamic_linking", + "lgplLib.meta_lic:lgplLib.meta_lic:restricted_allows_dynamic_linking", }, expectedTargetConditions: []string{}, }, @@ -86,8 +86,8 @@ func TestPolicy_edgeConditions(t *testing.T) { name: "independentmodulestatic", edge: annotated{"apacheBin.meta_lic", "gplWithClasspathException.meta_lic", []string{"static"}}, expectedDepActions: []string{ - "apacheBin.meta_lic:gplWithClasspathException.meta_lic:restricted", - "gplWithClasspathException.meta_lic:gplWithClasspathException.meta_lic:restricted", + "apacheBin.meta_lic:gplWithClasspathException.meta_lic:restricted_with_classpath_exception", + "gplWithClasspathException.meta_lic:gplWithClasspathException.meta_lic:restricted_with_classpath_exception", }, expectedTargetConditions: []string{}, }, @@ -95,8 +95,8 @@ func TestPolicy_edgeConditions(t *testing.T) { name: "dependentmodule", edge: annotated{"dependentModule.meta_lic", "gplWithClasspathException.meta_lic", []string{"dynamic"}}, expectedDepActions: []string{ - "dependentModule.meta_lic:gplWithClasspathException.meta_lic:restricted", - "gplWithClasspathException.meta_lic:gplWithClasspathException.meta_lic:restricted", + "dependentModule.meta_lic:gplWithClasspathException.meta_lic:restricted_with_classpath_exception", + "gplWithClasspathException.meta_lic:gplWithClasspathException.meta_lic:restricted_with_classpath_exception", }, expectedTargetConditions: []string{}, }, @@ -104,8 +104,8 @@ func TestPolicy_edgeConditions(t *testing.T) { { name: "lgplonfp", edge: annotated{"lgplBin.meta_lic", "apacheLib.meta_lic", []string{"static"}}, - expectedDepActions: []string{"apacheLib.meta_lic:apacheLib.meta_lic:notice"}, - expectedTargetConditions: []string{"lgplBin.meta_lic:restricted"}, + expectedDepActions: []string{}, + expectedTargetConditions: []string{"lgplBin.meta_lic:restricted_allows_dynamic_linking"}, }, { name: "lgplonfpdynamic", @@ -116,14 +116,14 @@ func TestPolicy_edgeConditions(t *testing.T) { { name: "gplonfp", edge: annotated{"gplBin.meta_lic", "apacheLib.meta_lic", []string{"static"}}, - expectedDepActions: []string{"apacheLib.meta_lic:apacheLib.meta_lic:notice"}, + expectedDepActions: []string{}, expectedTargetConditions: []string{"gplBin.meta_lic:restricted"}, }, { name: "gplcontainer", edge: annotated{"gplContainer.meta_lic", "apacheLib.meta_lic", []string{"static"}}, treatAsAggregate: true, - expectedDepActions: []string{"apacheLib.meta_lic:apacheLib.meta_lic:notice"}, + expectedDepActions: []string{}, expectedTargetConditions: []string{"gplContainer.meta_lic:restricted"}, }, { @@ -133,7 +133,6 @@ func TestPolicy_edgeConditions(t *testing.T) { otherCondition: "gplLib.meta_lic:restricted", expectedDepActions: []string{ "apacheContainer.meta_lic:gplLib.meta_lic:restricted", - "apacheLib.meta_lic:apacheLib.meta_lic:notice", "apacheLib.meta_lic:gplLib.meta_lic:restricted", "gplLib.meta_lic:gplLib.meta_lic:restricted", }, @@ -146,7 +145,6 @@ func TestPolicy_edgeConditions(t *testing.T) { otherCondition: "gplLib.meta_lic:restricted", expectedDepActions: []string{ "apacheBin.meta_lic:gplLib.meta_lic:restricted", - "apacheLib.meta_lic:apacheLib.meta_lic:notice", "apacheLib.meta_lic:gplLib.meta_lic:restricted", "gplLib.meta_lic:gplLib.meta_lic:restricted", }, @@ -167,14 +165,14 @@ func TestPolicy_edgeConditions(t *testing.T) { { name: "independentmodulereversestatic", edge: annotated{"gplWithClasspathException.meta_lic", "apacheBin.meta_lic", []string{"static"}}, - expectedDepActions: []string{"apacheBin.meta_lic:apacheBin.meta_lic:notice"}, - expectedTargetConditions: []string{"gplWithClasspathException.meta_lic:restricted"}, + expectedDepActions: []string{}, + expectedTargetConditions: []string{"gplWithClasspathException.meta_lic:restricted_with_classpath_exception"}, }, { name: "dependentmodulereverse", edge: annotated{"gplWithClasspathException.meta_lic", "dependentModule.meta_lic", []string{"dynamic"}}, expectedDepActions: []string{}, - expectedTargetConditions: []string{"gplWithClasspathException.meta_lic:restricted"}, + expectedTargetConditions: []string{"gplWithClasspathException.meta_lic:restricted_with_classpath_exception"}, }, { name: "ponr", @@ -188,31 +186,31 @@ func TestPolicy_edgeConditions(t *testing.T) { { name: "ronp", edge: annotated{"gplBin.meta_lic", "proprietary.meta_lic", []string{"static"}}, - expectedDepActions: []string{"proprietary.meta_lic:proprietary.meta_lic:proprietary"}, + expectedDepActions: []string{}, expectedTargetConditions: []string{"gplBin.meta_lic:restricted"}, }, { name: "noticeonb_e_o", edge: annotated{"mitBin.meta_lic", "by_exception.meta_lic", []string{"static"}}, - expectedDepActions: []string{"by_exception.meta_lic:by_exception.meta_lic:by_exception_only"}, + expectedDepActions: []string{}, expectedTargetConditions: []string{}, }, { name: "b_e_oonnotice", edge: annotated{"by_exception.meta_lic", "mitLib.meta_lic", []string{"static"}}, - expectedDepActions: []string{"mitLib.meta_lic:mitLib.meta_lic:notice"}, + expectedDepActions: []string{}, expectedTargetConditions: []string{}, }, { name: "noticeonrecip", edge: annotated{"mitBin.meta_lic", "mplLib.meta_lic", []string{"static"}}, - expectedDepActions: []string{"mplLib.meta_lic:mplLib.meta_lic:reciprocal"}, + expectedDepActions: []string{}, expectedTargetConditions: []string{}, }, { name: "reciponnotice", edge: annotated{"mplBin.meta_lic", "mitLib.meta_lic", []string{"static"}}, - expectedDepActions: []string{"mitLib.meta_lic:mitLib.meta_lic:notice"}, + expectedDepActions: []string{}, expectedTargetConditions: []string{}, }, } @@ -231,69 +229,80 @@ func TestPolicy_edgeConditions(t *testing.T) { t.Errorf("unexpected error reading graph: %w", err) return } + edge := lg.Edges()[0] // simulate a condition inherited from another edge/dependency. otherTarget := "" otherCondition := "" + var otn *TargetNode if len(tt.otherCondition) > 0 { fields := strings.Split(tt.otherCondition, ":") otherTarget = fields[0] otherCondition = fields[1] + otn = &TargetNode{name: otherTarget} // other target must exist in graph - lg.targets[otherTarget] = &TargetNode{name: otherTarget} - lg.targets[otherTarget].proto.LicenseConditions = append(lg.targets[otherTarget].proto.LicenseConditions, otherCondition) + lg.targets[otherTarget] = otn + otn.licenseConditions = LicenseConditionSet(RecognizedConditionNames[otherCondition]) + } + targets := make(map[string]*TargetNode) + targets[edge.target.name] = edge.target + targets[edge.dependency.name] = edge.dependency + if otn != nil { + targets[otn.name] = otn } if tt.expectedDepActions != nil { - depActions := make(actionSet) - depActions[lg.targets[tt.edge.dep]] = lg.targets[tt.edge.dep].LicenseConditions() - if otherTarget != "" { - // simulate a sub-dependency's condition having already propagated up to dep and about to go to target - otherCs := lg.targets[otherTarget].LicenseConditions() - depActions[lg.targets[tt.edge.dep]].AddSet(otherCs) - depActions[lg.targets[otherTarget]] = otherCs - } - asActual := depActionsApplicableToTarget(lg.Edges()[0], depActions, tt.treatAsAggregate) - asExpected := make(actionSet) - for _, triple := range tt.expectedDepActions { - fields := strings.Split(triple, ":") - actsOn := lg.targets[fields[0]] - origin := lg.targets[fields[1]] - expectedConditions := newLicenseConditionSet() - expectedConditions.add(origin, fields[2:]...) - if _, ok := asExpected[actsOn]; ok { - asExpected[actsOn].AddSet(expectedConditions) - } else { - asExpected[actsOn] = expectedConditions + t.Run("depConditionsPropagatingToTarget", func(t *testing.T) { + depConditions := edge.dependency.LicenseConditions() + if otherTarget != "" { + // simulate a sub-dependency's condition having already propagated up to dep and about to go to target + otherCs := otn.LicenseConditions() + depConditions |= otherCs } - } - - checkSameActions(lg, asActual, asExpected, t) + t.Logf("calculate target actions for edge=%s, dep conditions=%04x, treatAsAggregate=%v", edge.String(), depConditions, tt.treatAsAggregate) + csActual := depConditionsPropagatingToTarget(lg, edge, depConditions, tt.treatAsAggregate) + t.Logf("calculated target conditions as %04x{%s}", csActual, strings.Join(csActual.Names(), ", ")) + csExpected := NewLicenseConditionSet() + for _, triple := range tt.expectedDepActions { + fields := strings.Split(triple, ":") + expectedConditions := NewLicenseConditionSet() + for _, cname := range fields[2:] { + expectedConditions = expectedConditions.Plus(RecognizedConditionNames[cname]) + } + csExpected |= expectedConditions + } + t.Logf("expected target conditions as %04x{%s}", csExpected, strings.Join(csExpected.Names(), ", ")) + if csActual != csExpected { + t.Errorf("unexpected license conditions: got %04x, want %04x", csActual, csExpected) + } + }) } if tt.expectedTargetConditions != nil { - targetConditions := lg.TargetNode(tt.edge.target).LicenseConditions() - if otherTarget != "" { - targetConditions.add(lg.targets[otherTarget], otherCondition) - } - cs := targetConditionsApplicableToDep( - lg.Edges()[0], - targetConditions, - tt.treatAsAggregate) - actual := make([]string, 0, cs.Count()) - for _, lc := range cs.AsList() { - actual = append(actual, lc.asString(":")) - } - sort.Strings(actual) - sort.Strings(tt.expectedTargetConditions) - if len(actual) != len(tt.expectedTargetConditions) { - t.Errorf("unexpected number of target conditions: got %v with %d conditions, want %v with %d conditions", - actual, len(actual), tt.expectedTargetConditions, len(tt.expectedTargetConditions)) - } else { - for i := 0; i < len(actual); i++ { - if actual[i] != tt.expectedTargetConditions[i] { - t.Errorf("unexpected target condition at element %d: got %q, want %q", - i, actual[i], tt.expectedTargetConditions[i]) + t.Run("targetConditionsPropagatingToDep", func(t *testing.T) { + targetConditions := edge.target.LicenseConditions() + if otherTarget != "" { + targetConditions = targetConditions.Union(otn.licenseConditions) + } + t.Logf("calculate dep conditions for edge=%s, target conditions=%v, treatAsAggregate=%v", edge.String(), targetConditions.Names(), tt.treatAsAggregate) + cs := targetConditionsPropagatingToDep(lg, edge, targetConditions, tt.treatAsAggregate) + t.Logf("calculated dep conditions as %v", cs.Names()) + actual := cs.Names() + sort.Strings(actual) + expected := make([]string, 0) + for _, expectedDepCondition := range tt.expectedTargetConditions { + expected = append(expected, strings.Split(expectedDepCondition, ":")[1]) + } + sort.Strings(expected) + if len(actual) != len(expected) { + t.Errorf("unexpected number of target conditions: got %v with %d conditions, want %v with %d conditions", + actual, len(actual), expected, len(expected)) + } else { + for i := 0; i < len(actual); i++ { + if actual[i] != expected[i] { + t.Errorf("unexpected target condition at element %d: got %q, want %q", + i, actual[i], expected[i]) + } } } - } + }) } }) } diff --git a/tools/compliance/policy/resolve.go b/tools/compliance/policy/resolve.go index c107520eea..336894af0a 100644 --- a/tools/compliance/policy/resolve.go +++ b/tools/compliance/policy/resolve.go @@ -14,228 +14,196 @@ package compliance +import ( + "sync" +) + // ResolveBottomUpConditions performs a bottom-up walk of the LicenseGraph // propagating conditions up the graph as necessary according to the properties // of each edge and according to each license condition in question. // -// Subsequent top-down walks of the graph will filter some resolutions and may -// introduce new resolutions. -// // e.g. if a "restricted" condition applies to a binary, it also applies to all // of the statically-linked libraries and the transitive closure of their static // dependencies; even if neither they nor the transitive closure of their // dependencies originate any "restricted" conditions. The bottom-up walk will // not resolve the library and its transitive closure, but the later top-down // walk will. -func ResolveBottomUpConditions(lg *LicenseGraph) *ResolutionSet { +func ResolveBottomUpConditions(lg *LicenseGraph) { // short-cut if already walked and cached lg.mu.Lock() - rs := lg.rsBU + wg := lg.wgBU + + if wg != nil { + lg.mu.Unlock() + wg.Wait() + return + } + wg = &sync.WaitGroup{} + wg.Add(1) + lg.wgBU = wg lg.mu.Unlock() - if rs != nil { - return rs + // amap identifes targets previously walked. (guarded by mu) + amap := make(map[*TargetNode]struct{}) + + // cmap identifies targets previously walked as pure aggregates. i.e. as containers + // (guarded by mu) + cmap := make(map[*TargetNode]struct{}) + var mu sync.Mutex + + var walk func(target *TargetNode, treatAsAggregate bool) LicenseConditionSet + + walk = func(target *TargetNode, treatAsAggregate bool) LicenseConditionSet { + priorWalkResults := func() (LicenseConditionSet, bool) { + mu.Lock() + defer mu.Unlock() + + if _, alreadyWalked := amap[target]; alreadyWalked { + if treatAsAggregate { + return target.resolution, true + } + if _, asAggregate := cmap[target]; !asAggregate { + return target.resolution, true + } + // previously walked in a pure aggregate context, + // needs to walk again in non-aggregate context + delete(cmap, target) + } else { + target.resolution |= target.licenseConditions + amap[target] = struct{}{} + } + if treatAsAggregate { + cmap[target] = struct{}{} + } + return target.resolution, false + } + cs, alreadyWalked := priorWalkResults() + if alreadyWalked { + return cs + } + + c := make(chan LicenseConditionSet, len(target.edges)) + // add all the conditions from all the dependencies + for _, edge := range target.edges { + go func(edge *TargetEdge) { + // walk dependency to get its conditions + cs := walk(edge.dependency, treatAsAggregate && edge.dependency.IsContainer()) + + // turn those into the conditions that apply to the target + cs = depConditionsPropagatingToTarget(lg, edge, cs, treatAsAggregate) + + c <- cs + }(edge) + } + for i := 0; i < len(target.edges); i++ { + cs |= <-c + } + mu.Lock() + target.resolution |= cs + mu.Unlock() + + // return conditions up the tree + return cs } - // must be indexed for fast lookup - lg.indexForward() - - rs = resolveBottomUp(lg, make(map[*TargetNode]actionSet) /* empty map; no prior resolves */) - - // if not yet cached, save the result - lg.mu.Lock() - if lg.rsBU == nil { - lg.rsBU = rs - } else { - // if we end up with 2, release the later for garbage collection - rs = lg.rsBU + // walk each of the roots + for _, rname := range lg.rootFiles { + rnode := lg.targets[rname] + _ = walk(rnode, rnode.IsContainer()) } - lg.mu.Unlock() - return rs + wg.Done() } // ResolveTopDownCondtions performs a top-down walk of the LicenseGraph -// resolving all reachable nodes for `condition`. Policy establishes the rules -// for transforming and propagating resolutions down the graph. +// propagating conditions from target to dependency. // // e.g. For current policy, none of the conditions propagate from target to // dependency except restricted. For restricted, the policy is to share the // source of any libraries linked to restricted code and to provide notice. -func ResolveTopDownConditions(lg *LicenseGraph) *ResolutionSet { +func ResolveTopDownConditions(lg *LicenseGraph) { // short-cut if already walked and cached lg.mu.Lock() - rs := lg.rsTD + wg := lg.wgTD + + if wg != nil { + lg.mu.Unlock() + wg.Wait() + return + } + wg = &sync.WaitGroup{} + wg.Add(1) + lg.wgTD = wg lg.mu.Unlock() - if rs != nil { - return rs - } - // start with the conditions propagated up the graph - rs = ResolveBottomUpConditions(lg) + ResolveBottomUpConditions(lg) - // rmap maps 'appliesTo' targets to their applicable conditions - // - // rmap is the resulting ResolutionSet - rmap := make(map[*TargetNode]actionSet) + // amap contains the set of targets already walked. (guarded by mu) + amap := make(map[*TargetNode]struct{}) // cmap contains the set of targets walked as pure aggregates. i.e. containers + // (guarded by mu) cmap := make(map[*TargetNode]struct{}) - var walk func(fnode *TargetNode, cs *LicenseConditionSet, treatAsAggregate bool) + // mu guards concurrent access to cmap + var mu sync.Mutex - walk = func(fnode *TargetNode, cs *LicenseConditionSet, treatAsAggregate bool) { - if _, ok := rmap[fnode]; !ok { - rmap[fnode] = make(actionSet) - } - rmap[fnode].add(fnode, cs) + var walk func(fnode *TargetNode, cs LicenseConditionSet, treatAsAggregate bool) + + walk = func(fnode *TargetNode, cs LicenseConditionSet, treatAsAggregate bool) { + defer wg.Done() + mu.Lock() + fnode.resolution |= fnode.licenseConditions + fnode.resolution |= cs + amap[fnode] = struct{}{} if treatAsAggregate { cmap[fnode] = struct{}{} } - // add conditions attached to `fnode` - cs = cs.Copy() - for _, fcs := range rs.resolutions[fnode] { - cs.AddSet(fcs) - } + cs = fnode.resolution + mu.Unlock() // for each dependency - for _, edge := range lg.index[fnode.name] { - e := TargetEdge{lg, edge} - // dcs holds the dpendency conditions inherited from the target - dcs := targetConditionsApplicableToDep(e, cs, treatAsAggregate) - if dcs.IsEmpty() && !treatAsAggregate { - continue - } - dnode := lg.targets[edge.dependency] - if as, alreadyWalked := rmap[dnode]; alreadyWalked { - diff := dcs.Copy() - diff.RemoveSet(as.conditions()) - if diff.IsEmpty() { - // no new conditions + for _, edge := range fnode.edges { + func(edge *TargetEdge) { + // dcs holds the dpendency conditions inherited from the target + dcs := targetConditionsPropagatingToDep(lg, edge, cs, treatAsAggregate) + dnode := edge.dependency + mu.Lock() + defer mu.Unlock() + depcs := dnode.resolution + _, alreadyWalked := amap[dnode] + if !dcs.IsEmpty() && alreadyWalked { + if dcs.Difference(depcs).IsEmpty() { + // no new conditions - // pure aggregates never need walking a 2nd time with same conditions - if treatAsAggregate { - continue + // pure aggregates never need walking a 2nd time with same conditions + if treatAsAggregate { + return + } + // non-aggregates don't need walking as non-aggregate a 2nd time + if _, asAggregate := cmap[dnode]; !asAggregate { + return + } + // previously walked as pure aggregate; need to re-walk as non-aggregate + delete(cmap, dnode) } - // non-aggregates don't need walking as non-aggregate a 2nd time - if _, asAggregate := cmap[dnode]; !asAggregate { - continue - } - // previously walked as pure aggregate; need to re-walk as non-aggregate - delete(cmap, dnode) } - } - // add the conditions to the dependency - walk(dnode, dcs, treatAsAggregate && lg.targets[edge.dependency].IsContainer()) + // add the conditions to the dependency + wg.Add(1) + go walk(dnode, dcs, treatAsAggregate && dnode.IsContainer()) + }(edge) } } // walk each of the roots - for _, r := range lg.rootFiles { - rnode := lg.targets[r] - as, ok := rs.resolutions[rnode] - if !ok { - // no conditions in root or transitive closure of dependencies - continue - } - if as.isEmpty() { - continue - } - + for _, rname := range lg.rootFiles { + rnode := lg.targets[rname] + wg.Add(1) // add the conditions to the root and its transitive closure - walk(rnode, newLicenseConditionSet(), lg.targets[r].IsContainer()) + go walk(rnode, NewLicenseConditionSet(), rnode.IsContainer()) } - - // back-fill any bottom-up conditions on targets missed by top-down walk - for attachesTo, as := range rs.resolutions { - if _, ok := rmap[attachesTo]; !ok { - rmap[attachesTo] = as.copy() - } else { - rmap[attachesTo].addSet(as) - } - } - - // propagate any new conditions back up the graph - rs = resolveBottomUp(lg, rmap) - - // if not yet cached, save the result - lg.mu.Lock() - if lg.rsTD == nil { - lg.rsTD = rs - } else { - // if we end up with 2, release the later for garbage collection - rs = lg.rsTD - } - lg.mu.Unlock() - - return rs -} - -// resolveBottomUp implements a bottom-up resolve propagating conditions both -// from the graph, and from a `priors` map of resolutions. -func resolveBottomUp(lg *LicenseGraph, priors map[*TargetNode]actionSet) *ResolutionSet { - rs := newResolutionSet() - - // cmap contains an entry for every target that was previously walked as a pure aggregate only. - cmap := make(map[string]struct{}) - - var walk func(f string, treatAsAggregate bool) actionSet - - walk = func(f string, treatAsAggregate bool) actionSet { - target := lg.targets[f] - result := make(actionSet) - result[target] = newLicenseConditionSet() - result[target].add(target, target.proto.LicenseConditions...) - if pas, ok := priors[target]; ok { - result.addSet(pas) - } - if preresolved, ok := rs.resolutions[target]; ok { - if treatAsAggregate { - result.addSet(preresolved) - return result - } - if _, asAggregate := cmap[f]; !asAggregate { - result.addSet(preresolved) - return result - } - // previously walked in a pure aggregate context, - // needs to walk again in non-aggregate context - delete(cmap, f) - } - if treatAsAggregate { - cmap[f] = struct{}{} - } - - // add all the conditions from all the dependencies - for _, edge := range lg.index[f] { - // walk dependency to get its conditions - as := walk(edge.dependency, treatAsAggregate && lg.targets[edge.dependency].IsContainer()) - - // turn those into the conditions that apply to the target - as = depActionsApplicableToTarget(TargetEdge{lg, edge}, as, treatAsAggregate) - - // add them to the result - result.addSet(as) - } - - // record these conditions as applicable to the target - rs.addConditions(target, result) - if len(priors) == 0 { - // on the first bottom-up resolve, parents have their own sharing and notice needs - // on the later resolve, if priors is empty, there will be nothing new to add - rs.addSelf(target, result.byName(ImpliesRestricted)) - } - - // return this up the tree - return result - } - - // walk each of the roots - for _, r := range lg.rootFiles { - _ = walk(r, lg.targets[r].IsContainer()) - } - - return rs + wg.Done() + wg.Wait() } diff --git a/tools/compliance/policy/resolve_test.go b/tools/compliance/policy/resolve_test.go index 4c99d3546f..09dd7dd3c8 100644 --- a/tools/compliance/policy/resolve_test.go +++ b/tools/compliance/policy/resolve_test.go @@ -16,15 +16,16 @@ package compliance import ( "bytes" + "sort" "testing" ) func TestResolveBottomUpConditions(t *testing.T) { tests := []struct { - name string - roots []string - edges []annotated - expectedResolutions []res + name string + roots []string + edges []annotated + expectedActions []tcond }{ { name: "firstparty", @@ -32,10 +33,9 @@ func TestResolveBottomUpConditions(t *testing.T) { edges: []annotated{ {"apacheBin.meta_lic", "apacheLib.meta_lic", []string{"static"}}, }, - expectedResolutions: []res{ - {"apacheBin.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"}, - {"apacheBin.meta_lic", "apacheLib.meta_lic", "apacheLib.meta_lic", "notice"}, - {"apacheLib.meta_lic", "apacheLib.meta_lic", "apacheLib.meta_lic", "notice"}, + expectedActions: []tcond{ + {"apacheBin.meta_lic", "notice"}, + {"apacheLib.meta_lic", "notice"}, }, }, { @@ -44,9 +44,9 @@ func TestResolveBottomUpConditions(t *testing.T) { edges: []annotated{ {"apacheBin.meta_lic", "apacheLib.meta_lic", []string{"toolchain"}}, }, - expectedResolutions: []res{ - {"apacheBin.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"}, - {"apacheLib.meta_lic", "apacheLib.meta_lic", "apacheLib.meta_lic", "notice"}, + expectedActions: []tcond{ + {"apacheBin.meta_lic", "notice"}, + {"apacheLib.meta_lic", "notice"}, }, }, { @@ -56,13 +56,10 @@ func TestResolveBottomUpConditions(t *testing.T) { {"apacheContainer.meta_lic", "apacheBin.meta_lic", []string{"static"}}, {"apacheBin.meta_lic", "apacheLib.meta_lic", []string{"static"}}, }, - expectedResolutions: []res{ - {"apacheContainer.meta_lic", "apacheContainer.meta_lic", "apacheContainer.meta_lic", "notice"}, - {"apacheContainer.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"}, - {"apacheContainer.meta_lic", "apacheLib.meta_lic", "apacheLib.meta_lic", "notice"}, - {"apacheBin.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"}, - {"apacheBin.meta_lic", "apacheLib.meta_lic", "apacheLib.meta_lic", "notice"}, - {"apacheLib.meta_lic", "apacheLib.meta_lic", "apacheLib.meta_lic", "notice"}, + expectedActions: []tcond{ + {"apacheContainer.meta_lic", "notice"}, + {"apacheBin.meta_lic", "notice"}, + {"apacheLib.meta_lic", "notice"}, }, }, { @@ -72,12 +69,10 @@ func TestResolveBottomUpConditions(t *testing.T) { {"apacheContainer.meta_lic", "apacheBin.meta_lic", []string{"static"}}, {"apacheContainer.meta_lic", "apacheLib.meta_lic", []string{"static"}}, }, - expectedResolutions: []res{ - {"apacheContainer.meta_lic", "apacheContainer.meta_lic", "apacheContainer.meta_lic", "notice"}, - {"apacheContainer.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"}, - {"apacheContainer.meta_lic", "apacheLib.meta_lic", "apacheLib.meta_lic", "notice"}, - {"apacheBin.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"}, - {"apacheLib.meta_lic", "apacheLib.meta_lic", "apacheLib.meta_lic", "notice"}, + expectedActions: []tcond{ + {"apacheContainer.meta_lic", "notice"}, + {"apacheBin.meta_lic", "notice"}, + {"apacheLib.meta_lic", "notice"}, }, }, { @@ -86,9 +81,9 @@ func TestResolveBottomUpConditions(t *testing.T) { edges: []annotated{ {"apacheBin.meta_lic", "apacheLib.meta_lic", []string{"dynamic"}}, }, - expectedResolutions: []res{ - {"apacheBin.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"}, - {"apacheLib.meta_lic", "apacheLib.meta_lic", "apacheLib.meta_lic", "notice"}, + expectedActions: []tcond{ + {"apacheBin.meta_lic", "notice"}, + {"apacheLib.meta_lic", "notice"}, }, }, { @@ -98,11 +93,10 @@ func TestResolveBottomUpConditions(t *testing.T) { {"apacheContainer.meta_lic", "apacheBin.meta_lic", []string{"static"}}, {"apacheBin.meta_lic", "apacheLib.meta_lic", []string{"dynamic"}}, }, - expectedResolutions: []res{ - {"apacheContainer.meta_lic", "apacheContainer.meta_lic", "apacheContainer.meta_lic", "notice"}, - {"apacheContainer.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"}, - {"apacheBin.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"}, - {"apacheLib.meta_lic", "apacheLib.meta_lic", "apacheLib.meta_lic", "notice"}, + expectedActions: []tcond{ + {"apacheContainer.meta_lic", "notice"}, + {"apacheBin.meta_lic", "notice"}, + {"apacheLib.meta_lic", "notice"}, }, }, { @@ -112,11 +106,10 @@ func TestResolveBottomUpConditions(t *testing.T) { {"apacheContainer.meta_lic", "apacheBin.meta_lic", []string{"static"}}, {"apacheContainer.meta_lic", "apacheLib.meta_lic", []string{"dynamic"}}, }, - expectedResolutions: []res{ - {"apacheContainer.meta_lic", "apacheContainer.meta_lic", "apacheContainer.meta_lic", "notice"}, - {"apacheContainer.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"}, - {"apacheBin.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"}, - {"apacheLib.meta_lic", "apacheLib.meta_lic", "apacheLib.meta_lic", "notice"}, + expectedActions: []tcond{ + {"apacheContainer.meta_lic", "notice"}, + {"apacheBin.meta_lic", "notice"}, + {"apacheLib.meta_lic", "notice"}, }, }, { @@ -125,11 +118,9 @@ func TestResolveBottomUpConditions(t *testing.T) { edges: []annotated{ {"apacheBin.meta_lic", "gplLib.meta_lic", []string{"static"}}, }, - expectedResolutions: []res{ - {"apacheBin.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"}, - {"apacheBin.meta_lic", "apacheBin.meta_lic", "gplLib.meta_lic", "restricted"}, - {"apacheBin.meta_lic", "gplLib.meta_lic", "gplLib.meta_lic", "restricted"}, - {"gplLib.meta_lic", "gplLib.meta_lic", "gplLib.meta_lic", "restricted"}, + expectedActions: []tcond{ + {"apacheBin.meta_lic", "notice|restricted"}, + {"gplLib.meta_lic", "restricted"}, }, }, { @@ -138,9 +129,9 @@ func TestResolveBottomUpConditions(t *testing.T) { edges: []annotated{ {"apacheBin.meta_lic", "gplLib.meta_lic", []string{"toolchain"}}, }, - expectedResolutions: []res{ - {"apacheBin.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"}, - {"gplLib.meta_lic", "gplLib.meta_lic", "gplLib.meta_lic", "restricted"}, + expectedActions: []tcond{ + {"apacheBin.meta_lic", "notice"}, + {"gplLib.meta_lic", "restricted"}, }, }, { @@ -150,16 +141,10 @@ func TestResolveBottomUpConditions(t *testing.T) { {"apacheContainer.meta_lic", "apacheBin.meta_lic", []string{"static"}}, {"apacheBin.meta_lic", "gplLib.meta_lic", []string{"static"}}, }, - expectedResolutions: []res{ - {"apacheContainer.meta_lic", "apacheContainer.meta_lic", "apacheContainer.meta_lic", "notice"}, - {"apacheContainer.meta_lic", "apacheContainer.meta_lic", "gplLib.meta_lic", "restricted"}, - {"apacheContainer.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"}, - {"apacheContainer.meta_lic", "apacheBin.meta_lic", "gplLib.meta_lic", "restricted"}, - {"apacheContainer.meta_lic", "gplLib.meta_lic", "gplLib.meta_lic", "restricted"}, - {"apacheBin.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"}, - {"apacheBin.meta_lic", "apacheBin.meta_lic", "gplLib.meta_lic", "restricted"}, - {"apacheBin.meta_lic", "gplLib.meta_lic", "gplLib.meta_lic", "restricted"}, - {"gplLib.meta_lic", "gplLib.meta_lic", "gplLib.meta_lic", "restricted"}, + expectedActions: []tcond{ + {"apacheContainer.meta_lic", "notice|restricted"}, + {"apacheBin.meta_lic", "notice|restricted"}, + {"gplLib.meta_lic", "restricted"}, }, }, { @@ -169,13 +154,10 @@ func TestResolveBottomUpConditions(t *testing.T) { {"apacheContainer.meta_lic", "apacheBin.meta_lic", []string{"static"}}, {"apacheContainer.meta_lic", "gplLib.meta_lic", []string{"static"}}, }, - expectedResolutions: []res{ - {"apacheContainer.meta_lic", "apacheContainer.meta_lic", "apacheContainer.meta_lic", "notice"}, - {"apacheContainer.meta_lic", "apacheContainer.meta_lic", "gplLib.meta_lic", "restricted"}, - {"apacheContainer.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"}, - {"apacheContainer.meta_lic", "gplLib.meta_lic", "gplLib.meta_lic", "restricted"}, - {"apacheBin.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"}, - {"gplLib.meta_lic", "gplLib.meta_lic", "gplLib.meta_lic", "restricted"}, + expectedActions: []tcond{ + {"apacheContainer.meta_lic", "notice|restricted"}, + {"apacheBin.meta_lic", "notice"}, + {"gplLib.meta_lic", "restricted"}, }, }, { @@ -184,11 +166,9 @@ func TestResolveBottomUpConditions(t *testing.T) { edges: []annotated{ {"apacheBin.meta_lic", "gplLib.meta_lic", []string{"dynamic"}}, }, - expectedResolutions: []res{ - {"apacheBin.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"}, - {"apacheBin.meta_lic", "apacheBin.meta_lic", "gplLib.meta_lic", "restricted"}, - {"apacheBin.meta_lic", "gplLib.meta_lic", "gplLib.meta_lic", "restricted"}, - {"gplLib.meta_lic", "gplLib.meta_lic", "gplLib.meta_lic", "restricted"}, + expectedActions: []tcond{ + {"apacheBin.meta_lic", "notice|restricted"}, + {"gplLib.meta_lic", "restricted"}, }, }, { @@ -198,16 +178,10 @@ func TestResolveBottomUpConditions(t *testing.T) { {"apacheContainer.meta_lic", "apacheBin.meta_lic", []string{"static"}}, {"apacheBin.meta_lic", "gplLib.meta_lic", []string{"dynamic"}}, }, - expectedResolutions: []res{ - {"apacheContainer.meta_lic", "apacheContainer.meta_lic", "apacheContainer.meta_lic", "notice"}, - {"apacheContainer.meta_lic", "apacheContainer.meta_lic", "gplLib.meta_lic", "restricted"}, - {"apacheContainer.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"}, - {"apacheContainer.meta_lic", "apacheBin.meta_lic", "gplLib.meta_lic", "restricted"}, - {"apacheContainer.meta_lic", "gplLib.meta_lic", "gplLib.meta_lic", "restricted"}, - {"apacheBin.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"}, - {"apacheBin.meta_lic", "apacheBin.meta_lic", "gplLib.meta_lic", "restricted"}, - {"apacheBin.meta_lic", "gplLib.meta_lic", "gplLib.meta_lic", "restricted"}, - {"gplLib.meta_lic", "gplLib.meta_lic", "gplLib.meta_lic", "restricted"}, + expectedActions: []tcond{ + {"apacheContainer.meta_lic", "notice|restricted"}, + {"apacheBin.meta_lic", "notice|restricted"}, + {"gplLib.meta_lic", "restricted"}, }, }, { @@ -217,13 +191,10 @@ func TestResolveBottomUpConditions(t *testing.T) { {"apacheContainer.meta_lic", "apacheBin.meta_lic", []string{"static"}}, {"apacheContainer.meta_lic", "gplLib.meta_lic", []string{"dynamic"}}, }, - expectedResolutions: []res{ - {"apacheContainer.meta_lic", "apacheContainer.meta_lic", "apacheContainer.meta_lic", "notice"}, - {"apacheContainer.meta_lic", "apacheContainer.meta_lic", "gplLib.meta_lic", "restricted"}, - {"apacheContainer.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"}, - {"apacheContainer.meta_lic", "gplLib.meta_lic", "gplLib.meta_lic", "restricted"}, - {"apacheBin.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"}, - {"gplLib.meta_lic", "gplLib.meta_lic", "gplLib.meta_lic", "restricted"}, + expectedActions: []tcond{ + {"apacheContainer.meta_lic", "notice|restricted"}, + {"apacheBin.meta_lic", "notice"}, + {"gplLib.meta_lic", "restricted"}, }, }, { @@ -232,11 +203,9 @@ func TestResolveBottomUpConditions(t *testing.T) { edges: []annotated{ {"apacheBin.meta_lic", "lgplLib.meta_lic", []string{"static"}}, }, - expectedResolutions: []res{ - {"apacheBin.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"}, - {"apacheBin.meta_lic", "apacheBin.meta_lic", "lgplLib.meta_lic", "restricted"}, - {"apacheBin.meta_lic", "lgplLib.meta_lic", "lgplLib.meta_lic", "restricted"}, - {"lgplLib.meta_lic", "lgplLib.meta_lic", "lgplLib.meta_lic", "restricted"}, + expectedActions: []tcond{ + {"apacheBin.meta_lic", "notice|restricted_allows_dynamic_linking"}, + {"lgplLib.meta_lic", "restricted_allows_dynamic_linking"}, }, }, { @@ -245,9 +214,9 @@ func TestResolveBottomUpConditions(t *testing.T) { edges: []annotated{ {"apacheBin.meta_lic", "lgplLib.meta_lic", []string{"toolchain"}}, }, - expectedResolutions: []res{ - {"apacheBin.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"}, - {"lgplLib.meta_lic", "lgplLib.meta_lic", "lgplLib.meta_lic", "restricted"}, + expectedActions: []tcond{ + {"apacheBin.meta_lic", "notice"}, + {"lgplLib.meta_lic", "restricted_allows_dynamic_linking"}, }, }, { @@ -257,16 +226,10 @@ func TestResolveBottomUpConditions(t *testing.T) { {"apacheContainer.meta_lic", "apacheBin.meta_lic", []string{"static"}}, {"apacheBin.meta_lic", "lgplLib.meta_lic", []string{"static"}}, }, - expectedResolutions: []res{ - {"apacheContainer.meta_lic", "apacheContainer.meta_lic", "apacheContainer.meta_lic", "notice"}, - {"apacheContainer.meta_lic", "apacheContainer.meta_lic", "lgplLib.meta_lic", "restricted"}, - {"apacheContainer.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"}, - {"apacheContainer.meta_lic", "apacheBin.meta_lic", "lgplLib.meta_lic", "restricted"}, - {"apacheContainer.meta_lic", "lgplLib.meta_lic", "lgplLib.meta_lic", "restricted"}, - {"apacheBin.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"}, - {"apacheBin.meta_lic", "apacheBin.meta_lic", "lgplLib.meta_lic", "restricted"}, - {"apacheBin.meta_lic", "lgplLib.meta_lic", "lgplLib.meta_lic", "restricted"}, - {"lgplLib.meta_lic", "lgplLib.meta_lic", "lgplLib.meta_lic", "restricted"}, + expectedActions: []tcond{ + {"apacheContainer.meta_lic", "notice|restricted_allows_dynamic_linking"}, + {"apacheBin.meta_lic", "notice|restricted_allows_dynamic_linking"}, + {"lgplLib.meta_lic", "restricted_allows_dynamic_linking"}, }, }, { @@ -276,13 +239,10 @@ func TestResolveBottomUpConditions(t *testing.T) { {"apacheContainer.meta_lic", "apacheBin.meta_lic", []string{"static"}}, {"apacheContainer.meta_lic", "lgplLib.meta_lic", []string{"static"}}, }, - expectedResolutions: []res{ - {"apacheContainer.meta_lic", "apacheContainer.meta_lic", "apacheContainer.meta_lic", "notice"}, - {"apacheContainer.meta_lic", "apacheContainer.meta_lic", "lgplLib.meta_lic", "restricted"}, - {"apacheContainer.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"}, - {"apacheContainer.meta_lic", "lgplLib.meta_lic", "lgplLib.meta_lic", "restricted"}, - {"apacheBin.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"}, - {"lgplLib.meta_lic", "lgplLib.meta_lic", "lgplLib.meta_lic", "restricted"}, + expectedActions: []tcond{ + {"apacheContainer.meta_lic", "notice|restricted_allows_dynamic_linking"}, + {"apacheBin.meta_lic", "notice"}, + {"lgplLib.meta_lic", "restricted_allows_dynamic_linking"}, }, }, { @@ -291,9 +251,9 @@ func TestResolveBottomUpConditions(t *testing.T) { edges: []annotated{ {"apacheBin.meta_lic", "lgplLib.meta_lic", []string{"dynamic"}}, }, - expectedResolutions: []res{ - {"apacheBin.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"}, - {"lgplLib.meta_lic", "lgplLib.meta_lic", "lgplLib.meta_lic", "restricted"}, + expectedActions: []tcond{ + {"apacheBin.meta_lic", "notice"}, + {"lgplLib.meta_lic", "restricted_allows_dynamic_linking"}, }, }, { @@ -303,11 +263,10 @@ func TestResolveBottomUpConditions(t *testing.T) { {"apacheContainer.meta_lic", "apacheBin.meta_lic", []string{"static"}}, {"apacheBin.meta_lic", "lgplLib.meta_lic", []string{"dynamic"}}, }, - expectedResolutions: []res{ - {"apacheContainer.meta_lic", "apacheContainer.meta_lic", "apacheContainer.meta_lic", "notice"}, - {"apacheContainer.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"}, - {"apacheBin.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"}, - {"lgplLib.meta_lic", "lgplLib.meta_lic", "lgplLib.meta_lic", "restricted"}, + expectedActions: []tcond{ + {"apacheContainer.meta_lic", "notice"}, + {"apacheBin.meta_lic", "notice"}, + {"lgplLib.meta_lic", "restricted_allows_dynamic_linking"}, }, }, { @@ -317,11 +276,10 @@ func TestResolveBottomUpConditions(t *testing.T) { {"apacheContainer.meta_lic", "apacheBin.meta_lic", []string{"static"}}, {"apacheContainer.meta_lic", "lgplLib.meta_lic", []string{"dynamic"}}, }, - expectedResolutions: []res{ - {"apacheContainer.meta_lic", "apacheContainer.meta_lic", "apacheContainer.meta_lic", "notice"}, - {"apacheContainer.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"}, - {"apacheBin.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"}, - {"lgplLib.meta_lic", "lgplLib.meta_lic", "lgplLib.meta_lic", "restricted"}, + expectedActions: []tcond{ + {"apacheContainer.meta_lic", "notice"}, + {"apacheBin.meta_lic", "notice"}, + {"lgplLib.meta_lic", "restricted_allows_dynamic_linking"}, }, }, { @@ -330,11 +288,9 @@ func TestResolveBottomUpConditions(t *testing.T) { edges: []annotated{ {"apacheBin.meta_lic", "gplWithClasspathException.meta_lic", []string{"static"}}, }, - expectedResolutions: []res{ - {"apacheBin.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"}, - {"apacheBin.meta_lic", "apacheBin.meta_lic", "gplWithClasspathException.meta_lic", "restricted"}, - {"apacheBin.meta_lic", "gplWithClasspathException.meta_lic", "gplWithClasspathException.meta_lic", "restricted"}, - {"gplWithClasspathException.meta_lic", "gplWithClasspathException.meta_lic", "gplWithClasspathException.meta_lic", "restricted"}, + expectedActions: []tcond{ + {"apacheBin.meta_lic", "notice|restricted_with_classpath_exception"}, + {"gplWithClasspathException.meta_lic", "restricted_with_classpath_exception"}, }, }, { @@ -343,11 +299,9 @@ func TestResolveBottomUpConditions(t *testing.T) { edges: []annotated{ {"dependentModule.meta_lic", "gplWithClasspathException.meta_lic", []string{"static"}}, }, - expectedResolutions: []res{ - {"dependentModule.meta_lic", "dependentModule.meta_lic", "dependentModule.meta_lic", "notice"}, - {"dependentModule.meta_lic", "dependentModule.meta_lic", "gplWithClasspathException.meta_lic", "restricted"}, - {"dependentModule.meta_lic", "gplWithClasspathException.meta_lic", "gplWithClasspathException.meta_lic", "restricted"}, - {"gplWithClasspathException.meta_lic", "gplWithClasspathException.meta_lic", "gplWithClasspathException.meta_lic", "restricted"}, + expectedActions: []tcond{ + {"dependentModule.meta_lic", "notice|restricted_with_classpath_exception"}, + {"gplWithClasspathException.meta_lic", "restricted_with_classpath_exception"}, }, }, { @@ -356,9 +310,9 @@ func TestResolveBottomUpConditions(t *testing.T) { edges: []annotated{ {"apacheBin.meta_lic", "gplWithClasspathException.meta_lic", []string{"dynamic"}}, }, - expectedResolutions: []res{ - {"apacheBin.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"}, - {"gplWithClasspathException.meta_lic", "gplWithClasspathException.meta_lic", "gplWithClasspathException.meta_lic", "restricted"}, + expectedActions: []tcond{ + {"apacheBin.meta_lic", "notice"}, + {"gplWithClasspathException.meta_lic", "restricted_with_classpath_exception"}, }, }, { @@ -367,11 +321,9 @@ func TestResolveBottomUpConditions(t *testing.T) { edges: []annotated{ {"dependentModule.meta_lic", "gplWithClasspathException.meta_lic", []string{"dynamic"}}, }, - expectedResolutions: []res{ - {"dependentModule.meta_lic", "dependentModule.meta_lic", "dependentModule.meta_lic", "notice"}, - {"dependentModule.meta_lic", "dependentModule.meta_lic", "gplWithClasspathException.meta_lic", "restricted"}, - {"dependentModule.meta_lic", "gplWithClasspathException.meta_lic", "gplWithClasspathException.meta_lic", "restricted"}, - {"gplWithClasspathException.meta_lic", "gplWithClasspathException.meta_lic", "gplWithClasspathException.meta_lic", "restricted"}, + expectedActions: []tcond{ + {"dependentModule.meta_lic", "notice|restricted_with_classpath_exception"}, + {"gplWithClasspathException.meta_lic", "restricted_with_classpath_exception"}, }, }, } @@ -383,19 +335,37 @@ func TestResolveBottomUpConditions(t *testing.T) { t.Errorf("unexpected test data error: got %w, want no error", err) return } - expectedRs := toResolutionSet(lg, tt.expectedResolutions) - actualRs := ResolveBottomUpConditions(lg) - checkSame(actualRs, expectedRs, t) + + logGraph(lg, t) + + ResolveBottomUpConditions(lg) + actual := asActionList(lg) + sort.Sort(actual) + t.Logf("actual: %s", actual.String()) + + expected := toActionList(lg, tt.expectedActions) + sort.Sort(expected) + t.Logf("expected: %s", expected.String()) + + if len(actual) != len(expected) { + t.Errorf("unexpected number of actions: got %d, want %d", len(actual), len(expected)) + return + } + for i := 0; i < len(actual); i++ { + if actual[i] != expected[i] { + t.Errorf("unexpected action at index %d: got %s, want %s", i, actual[i].String(), expected[i].String()) + } + } }) } } func TestResolveTopDownConditions(t *testing.T) { tests := []struct { - name string - roots []string - edges []annotated - expectedResolutions []res + name string + roots []string + edges []annotated + expectedActions []tcond }{ { name: "firstparty", @@ -403,10 +373,9 @@ func TestResolveTopDownConditions(t *testing.T) { edges: []annotated{ {"apacheBin.meta_lic", "apacheLib.meta_lic", []string{"static"}}, }, - expectedResolutions: []res{ - {"apacheBin.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"}, - {"apacheBin.meta_lic", "apacheLib.meta_lic", "apacheLib.meta_lic", "notice"}, - {"apacheLib.meta_lic", "apacheLib.meta_lic", "apacheLib.meta_lic", "notice"}, + expectedActions: []tcond{ + {"apacheBin.meta_lic", "notice"}, + {"apacheLib.meta_lic", "notice"}, }, }, { @@ -415,9 +384,9 @@ func TestResolveTopDownConditions(t *testing.T) { edges: []annotated{ {"apacheBin.meta_lic", "apacheLib.meta_lic", []string{"dynamic"}}, }, - expectedResolutions: []res{ - {"apacheBin.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"}, - {"apacheLib.meta_lic", "apacheLib.meta_lic", "apacheLib.meta_lic", "notice"}, + expectedActions: []tcond{ + {"apacheBin.meta_lic", "notice"}, + {"apacheLib.meta_lic", "notice"}, }, }, { @@ -427,15 +396,10 @@ func TestResolveTopDownConditions(t *testing.T) { {"apacheBin.meta_lic", "gplLib.meta_lic", []string{"static"}}, {"apacheBin.meta_lic", "mitLib.meta_lic", []string{"static"}}, }, - expectedResolutions: []res{ - {"apacheBin.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"}, - {"apacheBin.meta_lic", "apacheBin.meta_lic", "gplLib.meta_lic", "restricted"}, - {"apacheBin.meta_lic", "gplLib.meta_lic", "gplLib.meta_lic", "restricted"}, - {"apacheBin.meta_lic", "mitLib.meta_lic", "gplLib.meta_lic", "restricted"}, - {"apacheBin.meta_lic", "mitLib.meta_lic", "mitLib.meta_lic", "notice"}, - {"gplLib.meta_lic", "gplLib.meta_lic", "gplLib.meta_lic", "restricted"}, - {"mitLib.meta_lic", "mitLib.meta_lic", "gplLib.meta_lic", "restricted"}, - {"mitLib.meta_lic", "mitLib.meta_lic", "mitLib.meta_lic", "notice"}, + expectedActions: []tcond{ + {"apacheBin.meta_lic", "notice|restricted"}, + {"mitLib.meta_lic", "notice|restricted"}, + {"gplLib.meta_lic", "restricted"}, }, }, { @@ -445,11 +409,10 @@ func TestResolveTopDownConditions(t *testing.T) { {"apacheBin.meta_lic", "gplBin.meta_lic", []string{"toolchain"}}, {"apacheBin.meta_lic", "mitLib.meta_lic", []string{"static"}}, }, - expectedResolutions: []res{ - {"apacheBin.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"}, - {"apacheBin.meta_lic", "mitLib.meta_lic", "mitLib.meta_lic", "notice"}, - {"gplBin.meta_lic", "gplBin.meta_lic", "gplBin.meta_lic", "restricted"}, - {"mitLib.meta_lic", "mitLib.meta_lic", "mitLib.meta_lic", "notice"}, + expectedActions: []tcond{ + {"apacheBin.meta_lic", "notice"}, + {"mitLib.meta_lic", "notice"}, + {"gplBin.meta_lic", "restricted"}, }, }, { @@ -462,27 +425,13 @@ func TestResolveTopDownConditions(t *testing.T) { {"apacheBin.meta_lic", "mplLib.meta_lic", []string{"static"}}, {"mitBin.meta_lic", "mitLib.meta_lic", []string{"static"}}, }, - expectedResolutions: []res{ - {"apacheContainer.meta_lic", "apacheContainer.meta_lic", "apacheContainer.meta_lic", "notice"}, - {"apacheContainer.meta_lic", "apacheContainer.meta_lic", "gplLib.meta_lic", "restricted"}, - {"apacheContainer.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"}, - {"apacheContainer.meta_lic", "apacheBin.meta_lic", "gplLib.meta_lic", "restricted"}, - {"apacheContainer.meta_lic", "gplLib.meta_lic", "gplLib.meta_lic", "restricted"}, - {"apacheContainer.meta_lic", "mitBin.meta_lic", "mitBin.meta_lic", "notice"}, - {"apacheContainer.meta_lic", "mitLib.meta_lic", "mitLib.meta_lic", "notice"}, - {"apacheContainer.meta_lic", "mplLib.meta_lic", "gplLib.meta_lic", "restricted"}, - {"apacheContainer.meta_lic", "mplLib.meta_lic", "mplLib.meta_lic", "reciprocal"}, - {"apacheBin.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"}, - {"apacheBin.meta_lic", "apacheBin.meta_lic", "gplLib.meta_lic", "restricted"}, - {"apacheBin.meta_lic", "gplLib.meta_lic", "gplLib.meta_lic", "restricted"}, - {"apacheBin.meta_lic", "mplLib.meta_lic", "gplLib.meta_lic", "restricted"}, - {"apacheBin.meta_lic", "mplLib.meta_lic", "mplLib.meta_lic", "reciprocal"}, - {"gplLib.meta_lic", "gplLib.meta_lic", "gplLib.meta_lic", "restricted"}, - {"mitBin.meta_lic", "mitBin.meta_lic", "mitBin.meta_lic", "notice"}, - {"mitBin.meta_lic", "mitLib.meta_lic", "mitLib.meta_lic", "notice"}, - {"mitLib.meta_lic", "mitLib.meta_lic", "mitLib.meta_lic", "notice"}, - {"mplLib.meta_lic", "mplLib.meta_lic", "gplLib.meta_lic", "restricted"}, - {"mplLib.meta_lic", "mplLib.meta_lic", "mplLib.meta_lic", "reciprocal"}, + expectedActions: []tcond{ + {"apacheContainer.meta_lic", "notice|restricted"}, + {"apacheBin.meta_lic", "notice|restricted"}, + {"mitBin.meta_lic", "notice"}, + {"gplLib.meta_lic", "restricted"}, + {"mplLib.meta_lic", "reciprocal|restricted"}, + {"mitLib.meta_lic", "notice"}, }, }, { @@ -492,13 +441,10 @@ func TestResolveTopDownConditions(t *testing.T) { {"apacheContainer.meta_lic", "apacheBin.meta_lic", []string{"static"}}, {"apacheContainer.meta_lic", "gplLib.meta_lic", []string{"static"}}, }, - expectedResolutions: []res{ - {"apacheContainer.meta_lic", "apacheContainer.meta_lic", "apacheContainer.meta_lic", "notice"}, - {"apacheContainer.meta_lic", "apacheContainer.meta_lic", "gplLib.meta_lic", "restricted"}, - {"apacheContainer.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"}, - {"apacheContainer.meta_lic", "gplLib.meta_lic", "gplLib.meta_lic", "restricted"}, - {"apacheBin.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"}, - {"gplLib.meta_lic", "gplLib.meta_lic", "gplLib.meta_lic", "restricted"}, + expectedActions: []tcond{ + {"apacheContainer.meta_lic", "notice|restricted"}, + {"apacheBin.meta_lic", "notice"}, + {"gplLib.meta_lic", "restricted"}, }, }, { @@ -508,14 +454,10 @@ func TestResolveTopDownConditions(t *testing.T) { {"apacheBin.meta_lic", "gplLib.meta_lic", []string{"dynamic"}}, {"apacheBin.meta_lic", "mitLib.meta_lic", []string{"dynamic"}}, }, - expectedResolutions: []res{ - {"apacheBin.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"}, - {"apacheBin.meta_lic", "apacheBin.meta_lic", "gplLib.meta_lic", "restricted"}, - {"apacheBin.meta_lic", "gplLib.meta_lic", "gplLib.meta_lic", "restricted"}, - {"apacheBin.meta_lic", "mitLib.meta_lic", "gplLib.meta_lic", "restricted"}, - {"gplLib.meta_lic", "gplLib.meta_lic", "gplLib.meta_lic", "restricted"}, - {"mitLib.meta_lic", "mitLib.meta_lic", "gplLib.meta_lic", "restricted"}, - {"mitLib.meta_lic", "mitLib.meta_lic", "mitLib.meta_lic", "notice"}, + expectedActions: []tcond{ + {"apacheBin.meta_lic", "notice|restricted"}, + {"gplLib.meta_lic", "restricted"}, + {"mitLib.meta_lic", "notice|restricted"}, }, }, { @@ -528,23 +470,13 @@ func TestResolveTopDownConditions(t *testing.T) { {"apacheBin.meta_lic", "mplLib.meta_lic", []string{"dynamic"}}, {"mitBin.meta_lic", "mitLib.meta_lic", []string{"dynamic"}}, }, - expectedResolutions: []res{ - {"apacheContainer.meta_lic", "apacheContainer.meta_lic", "apacheContainer.meta_lic", "notice"}, - {"apacheContainer.meta_lic", "apacheContainer.meta_lic", "gplLib.meta_lic", "restricted"}, - {"apacheContainer.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"}, - {"apacheContainer.meta_lic", "apacheBin.meta_lic", "gplLib.meta_lic", "restricted"}, - {"apacheContainer.meta_lic", "gplLib.meta_lic", "gplLib.meta_lic", "restricted"}, - {"apacheContainer.meta_lic", "mitBin.meta_lic", "mitBin.meta_lic", "notice"}, - {"apacheContainer.meta_lic", "mplLib.meta_lic", "gplLib.meta_lic", "restricted"}, - {"apacheBin.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"}, - {"apacheBin.meta_lic", "apacheBin.meta_lic", "gplLib.meta_lic", "restricted"}, - {"apacheBin.meta_lic", "gplLib.meta_lic", "gplLib.meta_lic", "restricted"}, - {"apacheBin.meta_lic", "mplLib.meta_lic", "gplLib.meta_lic", "restricted"}, - {"gplLib.meta_lic", "gplLib.meta_lic", "gplLib.meta_lic", "restricted"}, - {"mitBin.meta_lic", "mitBin.meta_lic", "mitBin.meta_lic", "notice"}, - {"mitLib.meta_lic", "mitLib.meta_lic", "mitLib.meta_lic", "notice"}, - {"mplLib.meta_lic", "mplLib.meta_lic", "gplLib.meta_lic", "restricted"}, - {"mplLib.meta_lic", "mplLib.meta_lic", "mplLib.meta_lic", "reciprocal"}, + expectedActions: []tcond{ + {"apacheContainer.meta_lic", "notice|restricted"}, + {"apacheBin.meta_lic", "notice|restricted"}, + {"mitBin.meta_lic", "notice"}, + {"gplLib.meta_lic", "restricted"}, + {"mplLib.meta_lic", "reciprocal|restricted"}, + {"mitLib.meta_lic", "notice"}, }, }, { @@ -554,13 +486,10 @@ func TestResolveTopDownConditions(t *testing.T) { {"apacheContainer.meta_lic", "apacheBin.meta_lic", []string{"static"}}, {"apacheContainer.meta_lic", "gplLib.meta_lic", []string{"dynamic"}}, }, - expectedResolutions: []res{ - {"apacheContainer.meta_lic", "apacheContainer.meta_lic", "apacheContainer.meta_lic", "notice"}, - {"apacheContainer.meta_lic", "apacheContainer.meta_lic", "gplLib.meta_lic", "restricted"}, - {"apacheContainer.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"}, - {"apacheContainer.meta_lic", "gplLib.meta_lic", "gplLib.meta_lic", "restricted"}, - {"apacheBin.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"}, - {"gplLib.meta_lic", "gplLib.meta_lic", "gplLib.meta_lic", "restricted"}, + expectedActions: []tcond{ + {"apacheContainer.meta_lic", "notice|restricted"}, + {"apacheBin.meta_lic", "notice"}, + {"gplLib.meta_lic", "restricted"}, }, }, { @@ -570,15 +499,10 @@ func TestResolveTopDownConditions(t *testing.T) { {"apacheBin.meta_lic", "lgplLib.meta_lic", []string{"static"}}, {"apacheBin.meta_lic", "mitLib.meta_lic", []string{"static"}}, }, - expectedResolutions: []res{ - {"apacheBin.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"}, - {"apacheBin.meta_lic", "apacheBin.meta_lic", "lgplLib.meta_lic", "restricted"}, - {"apacheBin.meta_lic", "lgplLib.meta_lic", "lgplLib.meta_lic", "restricted"}, - {"apacheBin.meta_lic", "mitLib.meta_lic", "mitLib.meta_lic", "notice"}, - {"apacheBin.meta_lic", "mitLib.meta_lic", "lgplLib.meta_lic", "restricted"}, - {"lgplLib.meta_lic", "lgplLib.meta_lic", "lgplLib.meta_lic", "restricted"}, - {"mitLib.meta_lic", "mitLib.meta_lic", "lgplLib.meta_lic", "restricted"}, - {"mitLib.meta_lic", "mitLib.meta_lic", "mitLib.meta_lic", "notice"}, + expectedActions: []tcond{ + {"apacheBin.meta_lic", "notice|restricted_allows_dynamic_linking"}, + {"lgplLib.meta_lic", "restricted_allows_dynamic_linking"}, + {"mitLib.meta_lic", "notice|restricted_allows_dynamic_linking"}, }, }, { @@ -588,11 +512,10 @@ func TestResolveTopDownConditions(t *testing.T) { {"apacheBin.meta_lic", "lgplBin.meta_lic", []string{"toolchain"}}, {"apacheBin.meta_lic", "mitLib.meta_lic", []string{"static"}}, }, - expectedResolutions: []res{ - {"apacheBin.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"}, - {"apacheBin.meta_lic", "mitLib.meta_lic", "mitLib.meta_lic", "notice"}, - {"lgplBin.meta_lic", "lgplBin.meta_lic", "lgplBin.meta_lic", "restricted"}, - {"mitLib.meta_lic", "mitLib.meta_lic", "mitLib.meta_lic", "notice"}, + expectedActions: []tcond{ + {"apacheBin.meta_lic", "notice"}, + {"lgplBin.meta_lic", "restricted_allows_dynamic_linking"}, + {"mitLib.meta_lic", "notice"}, }, }, { @@ -603,22 +526,11 @@ func TestResolveTopDownConditions(t *testing.T) { {"apacheBin.meta_lic", "lgplLib.meta_lic", []string{"static"}}, {"apacheBin.meta_lic", "mitLib.meta_lic", []string{"static"}}, }, - expectedResolutions: []res{ - {"apacheContainer.meta_lic", "apacheContainer.meta_lic", "apacheContainer.meta_lic", "notice"}, - {"apacheContainer.meta_lic", "apacheContainer.meta_lic", "lgplLib.meta_lic", "restricted"}, - {"apacheContainer.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"}, - {"apacheContainer.meta_lic", "apacheBin.meta_lic", "lgplLib.meta_lic", "restricted"}, - {"apacheContainer.meta_lic", "lgplLib.meta_lic", "lgplLib.meta_lic", "restricted"}, - {"apacheContainer.meta_lic", "mitLib.meta_lic", "mitLib.meta_lic", "notice"}, - {"apacheContainer.meta_lic", "mitLib.meta_lic", "lgplLib.meta_lic", "restricted"}, - {"apacheBin.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"}, - {"apacheBin.meta_lic", "apacheBin.meta_lic", "lgplLib.meta_lic", "restricted"}, - {"apacheBin.meta_lic", "lgplLib.meta_lic", "lgplLib.meta_lic", "restricted"}, - {"apacheBin.meta_lic", "mitLib.meta_lic", "mitLib.meta_lic", "notice"}, - {"apacheBin.meta_lic", "mitLib.meta_lic", "lgplLib.meta_lic", "restricted"}, - {"lgplLib.meta_lic", "lgplLib.meta_lic", "lgplLib.meta_lic", "restricted"}, - {"mitLib.meta_lic", "mitLib.meta_lic", "lgplLib.meta_lic", "restricted"}, - {"mitLib.meta_lic", "mitLib.meta_lic", "mitLib.meta_lic", "notice"}, + expectedActions: []tcond{ + {"apacheContainer.meta_lic", "notice|restricted_allows_dynamic_linking"}, + {"apacheBin.meta_lic", "notice|restricted_allows_dynamic_linking"}, + {"lgplLib.meta_lic", "restricted_allows_dynamic_linking"}, + {"mitLib.meta_lic", "notice|restricted_allows_dynamic_linking"}, }, }, { @@ -628,13 +540,10 @@ func TestResolveTopDownConditions(t *testing.T) { {"apacheContainer.meta_lic", "apacheBin.meta_lic", []string{"static"}}, {"apacheContainer.meta_lic", "lgplLib.meta_lic", []string{"static"}}, }, - expectedResolutions: []res{ - {"apacheContainer.meta_lic", "apacheContainer.meta_lic", "apacheContainer.meta_lic", "notice"}, - {"apacheContainer.meta_lic", "apacheContainer.meta_lic", "lgplLib.meta_lic", "restricted"}, - {"apacheContainer.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"}, - {"apacheContainer.meta_lic", "lgplLib.meta_lic", "lgplLib.meta_lic", "restricted"}, - {"apacheBin.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"}, - {"lgplLib.meta_lic", "lgplLib.meta_lic", "lgplLib.meta_lic", "restricted"}, + expectedActions: []tcond{ + {"apacheContainer.meta_lic", "notice|restricted_allows_dynamic_linking"}, + {"apacheBin.meta_lic", "notice"}, + {"lgplLib.meta_lic", "restricted_allows_dynamic_linking"}, }, }, { @@ -644,11 +553,10 @@ func TestResolveTopDownConditions(t *testing.T) { {"apacheBin.meta_lic", "lgplLib.meta_lic", []string{"dynamic"}}, {"apacheBin.meta_lic", "mitLib.meta_lic", []string{"static"}}, }, - expectedResolutions: []res{ - {"apacheBin.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"}, - {"apacheBin.meta_lic", "mitLib.meta_lic", "mitLib.meta_lic", "notice"}, - {"lgplLib.meta_lic", "lgplLib.meta_lic", "lgplLib.meta_lic", "restricted"}, - {"mitLib.meta_lic", "mitLib.meta_lic", "mitLib.meta_lic", "notice"}, + expectedActions: []tcond{ + {"apacheBin.meta_lic", "notice"}, + {"lgplLib.meta_lic", "restricted_allows_dynamic_linking"}, + {"mitLib.meta_lic", "notice"}, }, }, { @@ -658,11 +566,10 @@ func TestResolveTopDownConditions(t *testing.T) { {"apacheContainer.meta_lic", "apacheBin.meta_lic", []string{"static"}}, {"apacheBin.meta_lic", "lgplLib.meta_lic", []string{"dynamic"}}, }, - expectedResolutions: []res{ - {"apacheContainer.meta_lic", "apacheContainer.meta_lic", "apacheContainer.meta_lic", "notice"}, - {"apacheContainer.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"}, - {"apacheBin.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"}, - {"lgplLib.meta_lic", "lgplLib.meta_lic", "lgplLib.meta_lic", "restricted"}, + expectedActions: []tcond{ + {"apacheContainer.meta_lic", "notice"}, + {"apacheBin.meta_lic", "notice"}, + {"lgplLib.meta_lic", "restricted_allows_dynamic_linking"}, }, }, { @@ -672,11 +579,10 @@ func TestResolveTopDownConditions(t *testing.T) { {"apacheContainer.meta_lic", "apacheBin.meta_lic", []string{"static"}}, {"apacheContainer.meta_lic", "lgplLib.meta_lic", []string{"dynamic"}}, }, - expectedResolutions: []res{ - {"apacheContainer.meta_lic", "apacheContainer.meta_lic", "apacheContainer.meta_lic", "notice"}, - {"apacheContainer.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"}, - {"apacheBin.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"}, - {"lgplLib.meta_lic", "lgplLib.meta_lic", "lgplLib.meta_lic", "restricted"}, + expectedActions: []tcond{ + {"apacheContainer.meta_lic", "notice"}, + {"apacheBin.meta_lic", "notice"}, + {"lgplLib.meta_lic", "restricted_allows_dynamic_linking"}, }, }, { @@ -686,15 +592,10 @@ func TestResolveTopDownConditions(t *testing.T) { {"apacheBin.meta_lic", "gplWithClasspathException.meta_lic", []string{"static"}}, {"apacheBin.meta_lic", "mitLib.meta_lic", []string{"static"}}, }, - expectedResolutions: []res{ - {"apacheBin.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"}, - {"apacheBin.meta_lic", "apacheBin.meta_lic", "gplWithClasspathException.meta_lic", "restricted"}, - {"apacheBin.meta_lic", "gplWithClasspathException.meta_lic", "gplWithClasspathException.meta_lic", "restricted"}, - {"apacheBin.meta_lic", "mitLib.meta_lic", "mitLib.meta_lic", "notice"}, - {"apacheBin.meta_lic", "mitLib.meta_lic", "gplWithClasspathException.meta_lic", "restricted"}, - {"gplWithClasspathException.meta_lic", "gplWithClasspathException.meta_lic", "gplWithClasspathException.meta_lic", "restricted"}, - {"mitLib.meta_lic", "mitLib.meta_lic", "gplWithClasspathException.meta_lic", "restricted"}, - {"mitLib.meta_lic", "mitLib.meta_lic", "mitLib.meta_lic", "notice"}, + expectedActions: []tcond{ + {"apacheBin.meta_lic", "notice|restricted_with_classpath_exception"}, + {"gplWithClasspathException.meta_lic", "restricted_with_classpath_exception"}, + {"mitLib.meta_lic", "notice|restricted_with_classpath_exception"}, }, }, { @@ -704,15 +605,10 @@ func TestResolveTopDownConditions(t *testing.T) { {"dependentModule.meta_lic", "gplWithClasspathException.meta_lic", []string{"static"}}, {"dependentModule.meta_lic", "mitLib.meta_lic", []string{"static"}}, }, - expectedResolutions: []res{ - {"dependentModule.meta_lic", "dependentModule.meta_lic", "dependentModule.meta_lic", "notice"}, - {"dependentModule.meta_lic", "dependentModule.meta_lic", "gplWithClasspathException.meta_lic", "restricted"}, - {"dependentModule.meta_lic", "gplWithClasspathException.meta_lic", "gplWithClasspathException.meta_lic", "restricted"}, - {"dependentModule.meta_lic", "mitLib.meta_lic", "mitLib.meta_lic", "notice"}, - {"dependentModule.meta_lic", "mitLib.meta_lic", "gplWithClasspathException.meta_lic", "restricted"}, - {"gplWithClasspathException.meta_lic", "gplWithClasspathException.meta_lic", "gplWithClasspathException.meta_lic", "restricted"}, - {"mitLib.meta_lic", "mitLib.meta_lic", "gplWithClasspathException.meta_lic", "restricted"}, - {"mitLib.meta_lic", "mitLib.meta_lic", "mitLib.meta_lic", "notice"}, + expectedActions: []tcond{ + {"dependentModule.meta_lic", "notice|restricted_with_classpath_exception"}, + {"gplWithClasspathException.meta_lic", "restricted_with_classpath_exception"}, + {"mitLib.meta_lic", "notice|restricted_with_classpath_exception"}, }, }, { @@ -722,11 +618,10 @@ func TestResolveTopDownConditions(t *testing.T) { {"apacheBin.meta_lic", "gplWithClasspathException.meta_lic", []string{"dynamic"}}, {"apacheBin.meta_lic", "mitLib.meta_lic", []string{"static"}}, }, - expectedResolutions: []res{ - {"apacheBin.meta_lic", "apacheBin.meta_lic", "apacheBin.meta_lic", "notice"}, - {"apacheBin.meta_lic", "mitLib.meta_lic", "mitLib.meta_lic", "notice"}, - {"gplWithClasspathException.meta_lic", "gplWithClasspathException.meta_lic", "gplWithClasspathException.meta_lic", "restricted"}, - {"mitLib.meta_lic", "mitLib.meta_lic", "mitLib.meta_lic", "notice"}, + expectedActions: []tcond{ + {"apacheBin.meta_lic", "notice"}, + {"gplWithClasspathException.meta_lic", "restricted_with_classpath_exception"}, + {"mitLib.meta_lic", "notice"}, }, }, { @@ -736,15 +631,10 @@ func TestResolveTopDownConditions(t *testing.T) { {"dependentModule.meta_lic", "gplWithClasspathException.meta_lic", []string{"dynamic"}}, {"dependentModule.meta_lic", "mitLib.meta_lic", []string{"static"}}, }, - expectedResolutions: []res{ - {"dependentModule.meta_lic", "dependentModule.meta_lic", "dependentModule.meta_lic", "notice"}, - {"dependentModule.meta_lic", "dependentModule.meta_lic", "gplWithClasspathException.meta_lic", "restricted"}, - {"dependentModule.meta_lic", "gplWithClasspathException.meta_lic", "gplWithClasspathException.meta_lic", "restricted"}, - {"dependentModule.meta_lic", "mitLib.meta_lic", "mitLib.meta_lic", "notice"}, - {"dependentModule.meta_lic", "mitLib.meta_lic", "gplWithClasspathException.meta_lic", "restricted"}, - {"gplWithClasspathException.meta_lic", "gplWithClasspathException.meta_lic", "gplWithClasspathException.meta_lic", "restricted"}, - {"mitLib.meta_lic", "mitLib.meta_lic", "gplWithClasspathException.meta_lic", "restricted"}, - {"mitLib.meta_lic", "mitLib.meta_lic", "mitLib.meta_lic", "notice"}, + expectedActions: []tcond{ + {"dependentModule.meta_lic", "notice|restricted_with_classpath_exception"}, + {"gplWithClasspathException.meta_lic", "restricted_with_classpath_exception"}, + {"mitLib.meta_lic", "notice|restricted_with_classpath_exception"}, }, }, } @@ -756,9 +646,27 @@ func TestResolveTopDownConditions(t *testing.T) { t.Errorf("unexpected test data error: got %w, want no error", err) return } - expectedRs := toResolutionSet(lg, tt.expectedResolutions) - actualRs := ResolveTopDownConditions(lg) - checkSame(actualRs, expectedRs, t) + + logGraph(lg, t) + + ResolveTopDownConditions(lg) + actual := asActionList(lg) + sort.Sort(actual) + t.Logf("actual: %s", actual.String()) + + expected := toActionList(lg, tt.expectedActions) + sort.Sort(expected) + t.Logf("expected: %s", expected.String()) + + if len(actual) != len(expected) { + t.Errorf("unexpected number of actions: got %d, want %d", len(actual), len(expected)) + return + } + for i := 0; i < len(actual); i++ { + if actual[i] != expected[i] { + t.Errorf("unexpected action at index %d: got %s, want %s", i, actual[i].String(), expected[i].String()) + } + } }) } } diff --git a/tools/compliance/policy/resolvenotices.go b/tools/compliance/policy/resolvenotices.go index 80b5e028cb..99f6d42faa 100644 --- a/tools/compliance/policy/resolvenotices.go +++ b/tools/compliance/policy/resolvenotices.go @@ -15,7 +15,7 @@ package compliance // ResolveNotices implements the policy for notices. -func ResolveNotices(lg *LicenseGraph) *ResolutionSet { - rs := ResolveTopDownConditions(lg) - return WalkResolutionsForCondition(lg, rs, ImpliesNotice) +func ResolveNotices(lg *LicenseGraph) ResolutionSet { + ResolveTopDownConditions(lg) + return WalkResolutionsForCondition(lg, ImpliesNotice) } diff --git a/tools/compliance/policy/resolveprivacy.go b/tools/compliance/policy/resolveprivacy.go index dabbc62c52..2a7992ea78 100644 --- a/tools/compliance/policy/resolveprivacy.go +++ b/tools/compliance/policy/resolveprivacy.go @@ -15,7 +15,7 @@ package compliance // ResolveSourcePrivacy implements the policy for source privacy. -func ResolveSourcePrivacy(lg *LicenseGraph) *ResolutionSet { - rs := ResolveTopDownConditions(lg) - return WalkResolutionsForCondition(lg, rs, ImpliesPrivate) +func ResolveSourcePrivacy(lg *LicenseGraph) ResolutionSet { + ResolveTopDownConditions(lg) + return WalkResolutionsForCondition(lg, ImpliesPrivate) } diff --git a/tools/compliance/policy/resolveprivacy_test.go b/tools/compliance/policy/resolveprivacy_test.go index 25772bbef4..2072d22d58 100644 --- a/tools/compliance/policy/resolveprivacy_test.go +++ b/tools/compliance/policy/resolveprivacy_test.go @@ -81,7 +81,7 @@ func TestResolveSourcePrivacy(t *testing.T) { } expectedRs := toResolutionSet(lg, tt.expectedResolutions) actualRs := ResolveSourcePrivacy(lg) - checkSame(actualRs, expectedRs, t) + checkResolves(actualRs, expectedRs, t) }) } } diff --git a/tools/compliance/policy/resolveshare.go b/tools/compliance/policy/resolveshare.go index 24efd2899a..9b6a8bb108 100644 --- a/tools/compliance/policy/resolveshare.go +++ b/tools/compliance/policy/resolveshare.go @@ -15,7 +15,7 @@ package compliance // ResolveSourceSharing implements the policy for source-sharing. -func ResolveSourceSharing(lg *LicenseGraph) *ResolutionSet { - rs := ResolveTopDownConditions(lg) - return WalkResolutionsForCondition(lg, rs, ImpliesShared) +func ResolveSourceSharing(lg *LicenseGraph) ResolutionSet { + ResolveTopDownConditions(lg) + return WalkResolutionsForCondition(lg, ImpliesShared) } diff --git a/tools/compliance/policy/resolveshare_test.go b/tools/compliance/policy/resolveshare_test.go index ad3630db06..f73888de43 100644 --- a/tools/compliance/policy/resolveshare_test.go +++ b/tools/compliance/policy/resolveshare_test.go @@ -291,7 +291,7 @@ func TestResolveSourceSharing(t *testing.T) { } expectedRs := toResolutionSet(lg, tt.expectedResolutions) actualRs := ResolveSourceSharing(lg) - checkSame(actualRs, expectedRs, t) + checkResolves(actualRs, expectedRs, t) }) } } diff --git a/tools/compliance/policy/shareprivacyconflicts.go b/tools/compliance/policy/shareprivacyconflicts.go index dabdff5dce..279e179db5 100644 --- a/tools/compliance/policy/shareprivacyconflicts.go +++ b/tools/compliance/policy/shareprivacyconflicts.go @@ -28,57 +28,37 @@ type SourceSharePrivacyConflict struct { // Error returns a string describing the conflict. func (conflict SourceSharePrivacyConflict) Error() string { - return fmt.Sprintf("%s %s from %s and must share from %s %s\n", - conflict.SourceNode.name, - conflict.PrivacyCondition.name, conflict.PrivacyCondition.origin.name, - conflict.ShareCondition.name, conflict.ShareCondition.origin.name) + return fmt.Sprintf("%s %s and must share from %s condition\n", conflict.SourceNode.name, + conflict.PrivacyCondition.Name(), conflict.ShareCondition.Name()) } // IsEqualTo returns true when `conflict` and `other` describe the same conflict. func (conflict SourceSharePrivacyConflict) IsEqualTo(other SourceSharePrivacyConflict) bool { return conflict.SourceNode.name == other.SourceNode.name && - conflict.ShareCondition.name == other.ShareCondition.name && - conflict.ShareCondition.origin.name == other.ShareCondition.origin.name && - conflict.PrivacyCondition.name == other.PrivacyCondition.name && - conflict.PrivacyCondition.origin.name == other.PrivacyCondition.origin.name + conflict.ShareCondition == other.ShareCondition && + conflict.PrivacyCondition == other.PrivacyCondition } // ConflictingSharedPrivateSource lists all of the targets where conflicting conditions to // share the source and to keep the source private apply to the target. func ConflictingSharedPrivateSource(lg *LicenseGraph) []SourceSharePrivacyConflict { - // shareSource is the set of all source-sharing resolutions. - shareSource := ResolveSourceSharing(lg) - if shareSource.IsEmpty() { - return []SourceSharePrivacyConflict{} - } - - // privateSource is the set of all source privacy resolutions. - privateSource := ResolveSourcePrivacy(lg) - if privateSource.IsEmpty() { - return []SourceSharePrivacyConflict{} - } + ResolveTopDownConditions(lg) // combined is the combination of source-sharing and source privacy. - combined := JoinResolutionSets(shareSource, privateSource) + combined := WalkActionsForCondition(lg, ImpliesShared.Union(ImpliesPrivate)) // size is the size of the result size := 0 - for _, actsOn := range combined.ActsOn() { - rl := combined.ResolutionsByActsOn(actsOn) - size += rl.CountConditionsByName(ImpliesShared) * rl.CountConditionsByName(ImpliesPrivate) + for _, cs := range combined { + size += cs.Intersection(ImpliesShared).Len() * cs.Intersection(ImpliesPrivate).Len() } if size == 0 { - return []SourceSharePrivacyConflict{} + return nil } result := make([]SourceSharePrivacyConflict, 0, size) - for _, actsOn := range combined.ActsOn() { - rl := combined.ResolutionsByActsOn(actsOn) - if len(rl) == 0 { - continue - } - - pconditions := rl.ByName(ImpliesPrivate).AllConditions().AsList() - ssconditions := rl.ByName(ImpliesShared).AllConditions().AsList() + for actsOn, cs := range combined { + pconditions := cs.Intersection(ImpliesPrivate).AsList() + ssconditions := cs.Intersection(ImpliesShared).AsList() // report all conflicting condition combinations for _, p := range pconditions { diff --git a/tools/compliance/policy/shareprivacyconflicts_test.go b/tools/compliance/policy/shareprivacyconflicts_test.go index 162c1fe3c9..ad3f3f45ce 100644 --- a/tools/compliance/policy/shareprivacyconflicts_test.go +++ b/tools/compliance/policy/shareprivacyconflicts_test.go @@ -33,19 +33,13 @@ func (l byConflict) Swap(i, j int) { l[i], l[j] = l[j], l[i] } // Less returns true when the `i`th element is lexicographically less than // the `j`th element. func (l byConflict) Less(i, j int) bool { - if l[i].SourceNode.name == l[j].SourceNode.name { - if l[i].ShareCondition.origin.name == l[j].ShareCondition.origin.name { - if l[i].ShareCondition.name == l[j].ShareCondition.name { - if l[i].PrivacyCondition.origin.name == l[j].PrivacyCondition.origin.name { - return l[i].PrivacyCondition.name < l[j].PrivacyCondition.name - } - return l[i].PrivacyCondition.origin.name < l[j].PrivacyCondition.origin.name - } - return l[i].ShareCondition.name < l[j].ShareCondition.name + if l[i].SourceNode.Name() == l[j].SourceNode.Name() { + if l[i].ShareCondition.Name() == l[j].ShareCondition.Name() { + return l[i].PrivacyCondition.Name() < l[j].PrivacyCondition.Name() } - return l[i].ShareCondition.origin.name < l[j].ShareCondition.origin.name + return l[i].ShareCondition.Name() < l[j].ShareCondition.Name() } - return l[i].SourceNode.name < l[j].SourceNode.name + return l[i].SourceNode.Name() < l[j].SourceNode.Name() } func TestConflictingSharedPrivateSource(t *testing.T) { diff --git a/tools/compliance/policy/shipped.go b/tools/compliance/policy/shipped.go index 6fbbbd669f..75c8399c23 100644 --- a/tools/compliance/policy/shipped.go +++ b/tools/compliance/policy/shipped.go @@ -26,12 +26,12 @@ func ShippedNodes(lg *LicenseGraph) *TargetNodeSet { tset := make(map[*TargetNode]struct{}) - WalkTopDown(lg, func(lg *LicenseGraph, tn *TargetNode, path TargetEdgePath) bool { + WalkTopDown(NoEdgeContext{}, lg, func(lg *LicenseGraph, tn *TargetNode, path TargetEdgePath) bool { if _, alreadyWalked := tset[tn]; alreadyWalked { return false } if len(path) > 0 { - if !edgeIsDerivation(path[len(path)-1]) { + if !edgeIsDerivation(path[len(path)-1].edge) { return false } } diff --git a/tools/compliance/policy/shipped_test.go b/tools/compliance/policy/shipped_test.go index 53a846928c..718e56fe82 100644 --- a/tools/compliance/policy/shipped_test.go +++ b/tools/compliance/policy/shipped_test.go @@ -17,6 +17,7 @@ package compliance import ( "bytes" "sort" + "strings" "testing" ) @@ -110,19 +111,31 @@ func TestShippedNodes(t *testing.T) { t.Errorf("unexpected test data error: got %w, want no error", err) return } + t.Logf("graph:") + for _, edge := range lg.Edges() { + t.Logf(" %s", edge.String()) + } expectedNodes := append([]string{}, tt.expectedNodes...) - actualNodes := ShippedNodes(lg).Names() + nodeset := ShippedNodes(lg) + t.Logf("shipped node set: %s", nodeset.String()) + + actualNodes := nodeset.Names() + t.Logf("shipped nodes: [%s]", strings.Join(actualNodes, ", ")) + sort.Strings(expectedNodes) sort.Strings(actualNodes) + + t.Logf("sorted nodes: [%s]", strings.Join(actualNodes, ", ")) + t.Logf("expected nodes: [%s]", strings.Join(expectedNodes, ", ")) if len(expectedNodes) != len(actualNodes) { - t.Errorf("unexpected number of shipped nodes: got %v with %d nodes, want %v with %d nodes", - actualNodes, len(actualNodes), expectedNodes, len(expectedNodes)) + t.Errorf("unexpected number of shipped nodes: %d nodes, want %d nodes", + len(actualNodes), len(expectedNodes)) return } for i := 0; i < len(actualNodes); i++ { if expectedNodes[i] != actualNodes[i] { - t.Errorf("unexpected node at index %d: got %q in %v, want %q in %v", - i, actualNodes[i], actualNodes, expectedNodes[i], expectedNodes) + t.Errorf("unexpected node at index %d: got %q, want %q", + i, actualNodes[i], expectedNodes[i]) } } }) diff --git a/tools/compliance/policy/walk.go b/tools/compliance/policy/walk.go index 8b6737d6c5..3e730889ed 100644 --- a/tools/compliance/policy/walk.go +++ b/tools/compliance/policy/walk.go @@ -14,27 +14,60 @@ package compliance +// EdgeContextProvider is an interface for injecting edge-specific context +// into walk paths. +type EdgeContextProvider interface { + // Context returns the context for `edge` when added to `path`. + Context(lg *LicenseGraph, path TargetEdgePath, edge *TargetEdge) interface{} +} + +// NoEdgeContext implements EdgeContextProvider for walks that use no context. +type NoEdgeContext struct{} + +// Context returns nil. +func (ctx NoEdgeContext) Context(lg *LicenseGraph, path TargetEdgePath, edge *TargetEdge) interface{} { + return nil +} + +// ApplicableConditionsContext provides the subset of conditions in `universe` +// that apply to each edge in a path. +type ApplicableConditionsContext struct { + universe LicenseConditionSet +} + +// Context returns the LicenseConditionSet applicable to the edge. +func (ctx ApplicableConditionsContext) Context(lg *LicenseGraph, path TargetEdgePath, edge *TargetEdge) interface{} { + universe := ctx.universe + if len(path) > 0 { + universe = path[len(path)-1].ctx.(LicenseConditionSet) + } + return conditionsAttachingAcrossEdge(lg, edge, universe) +} + // VisitNode is called for each root and for each walked dependency node by // WalkTopDown. When VisitNode returns true, WalkTopDown will proceed to walk // down the dependences of the node -type VisitNode func(*LicenseGraph, *TargetNode, TargetEdgePath) bool +type VisitNode func(lg *LicenseGraph, target *TargetNode, path TargetEdgePath) bool // WalkTopDown does a top-down walk of `lg` calling `visit` and descending // into depenencies when `visit` returns true. -func WalkTopDown(lg *LicenseGraph, visit VisitNode) { +func WalkTopDown(ctx EdgeContextProvider, lg *LicenseGraph, visit VisitNode) { path := NewTargetEdgePath(32) - // must be indexed for fast lookup - lg.indexForward() - - var walk func(f string) - walk = func(f string) { - visitChildren := visit(lg, lg.targets[f], *path) + var walk func(fnode *TargetNode) + walk = func(fnode *TargetNode) { + visitChildren := visit(lg, fnode, *path) if !visitChildren { return } - for _, edge := range lg.index[f] { - path.Push(TargetEdge{lg, edge}) + for _, edge := range fnode.edges { + var edgeContext interface{} + if ctx == nil { + edgeContext = nil + } else { + edgeContext = ctx.Context(lg, *path, edge) + } + path.Push(edge, edgeContext) walk(edge.dependency) path.Pop() } @@ -42,35 +75,164 @@ func WalkTopDown(lg *LicenseGraph, visit VisitNode) { for _, r := range lg.rootFiles { path.Clear() - walk(r) + walk(lg.targets[r]) } } +// resolutionKey identifies results from walking a specific target for a +// specific set of conditions. +type resolutionKey struct { + target *TargetNode + cs LicenseConditionSet +} + // WalkResolutionsForCondition performs a top-down walk of the LicenseGraph -// resolving all distributed works for condition `names`. -func WalkResolutionsForCondition(lg *LicenseGraph, rs *ResolutionSet, names ConditionNames) *ResolutionSet { +// resolving all distributed works for `conditions`. +func WalkResolutionsForCondition(lg *LicenseGraph, conditions LicenseConditionSet) ResolutionSet { shipped := ShippedNodes(lg) // rmap maps 'attachesTo' targets to the `actsOn` targets and applicable conditions - // - // rmap is the resulting ResolutionSet - rmap := make(map[*TargetNode]actionSet) + rmap := make(map[resolutionKey]ActionSet) - WalkTopDown(lg, func(lg *LicenseGraph, tn *TargetNode, _ TargetEdgePath) bool { - if _, ok := rmap[tn]; ok { + // cmap identifies previously walked target/condition pairs. + cmap := make(map[resolutionKey]struct{}) + + // result accumulates the resolutions to return. + result := make(ResolutionSet) + WalkTopDown(ApplicableConditionsContext{conditions}, lg, func(lg *LicenseGraph, tn *TargetNode, path TargetEdgePath) bool { + universe := conditions + if len(path) > 0 { + universe = path[len(path)-1].ctx.(LicenseConditionSet) + } + + if universe.IsEmpty() { + return false + } + key := resolutionKey{tn, universe} + + if _, alreadyWalked := cmap[key]; alreadyWalked { + pure := true + for _, p := range path { + target := p.Target() + tkey := resolutionKey{target, universe} + if _, ok := rmap[tkey]; !ok { + rmap[tkey] = make(ActionSet) + } + // attach prior walk outcome to ancestor + for actsOn, cs := range rmap[key] { + rmap[tkey][actsOn] = cs + } + // if prior walk produced results, copy results + // to ancestor. + if _, ok := result[tn]; ok && pure { + if _, ok := result[target]; !ok { + result[target] = make(ActionSet) + } + for actsOn, cs := range result[tn] { + result[target][actsOn] = cs + } + pure = target.IsContainer() + } + } + // if all ancestors are pure aggregates, attach + // matching prior walk conditions to self. Prior walk + // will not have done so if any ancestor was not an + // aggregate. + if pure { + match := rmap[key][tn].Intersection(universe) + if !match.IsEmpty() { + if _, ok := result[tn]; !ok { + result[tn] = make(ActionSet) + } + result[tn][tn] = match + } + } + return false + } + // no need to walk node or dependencies if not shipped + if !shipped.Contains(tn) { + return false + } + if _, ok := rmap[key]; !ok { + rmap[key] = make(ActionSet) + } + // add self to walk outcome + rmap[key][tn] = tn.resolution + cmap[key] = struct{}{} + cs := tn.resolution + if !cs.IsEmpty() { + cs = cs.Intersection(universe) + pure := true + for _, p := range path { + target := p.Target() + tkey := resolutionKey{target, universe} + if _, ok := rmap[tkey]; !ok { + rmap[tkey] = make(ActionSet) + } + // copy current node's action into ancestor + rmap[tkey][tn] = tn.resolution + // conditionally put matching conditions into + // result + if pure && !cs.IsEmpty() { + if _, ok := result[target]; !ok { + result[target] = make(ActionSet) + } + result[target][tn] = cs + pure = target.IsContainer() + } + } + // if all ancestors are pure aggregates, attach + // matching conditions to self. + if pure && !cs.IsEmpty() { + if _, ok := result[tn]; !ok { + result[tn] = make(ActionSet) + } + result[tn][tn] = cs + } + } + return true + }) + + return result +} + +// WalkActionsForCondition performs a top-down walk of the LicenseGraph +// resolving all distributed works for `conditions`. +func WalkActionsForCondition(lg *LicenseGraph, conditions LicenseConditionSet) ActionSet { + shipped := ShippedNodes(lg) + + // cmap identifies previously walked target/condition pairs. + cmap := make(map[resolutionKey]struct{}) + + // amap maps 'actsOn' targets to the applicable conditions + // + // amap is the resulting ActionSet + amap := make(ActionSet) + WalkTopDown(ApplicableConditionsContext{conditions}, lg, func(lg *LicenseGraph, tn *TargetNode, path TargetEdgePath) bool { + universe := conditions + if len(path) > 0 { + universe = path[len(path)-1].ctx.(LicenseConditionSet) + } + if universe.IsEmpty() { + return false + } + key := resolutionKey{tn, universe} + if _, ok := cmap[key]; ok { return false } if !shipped.Contains(tn) { return false } - if as, ok := rs.resolutions[tn]; ok { - fas := as.byActsOn(shipped).byName(names) - if !fas.isEmpty() { - rmap[tn] = fas + cs := universe.Intersection(tn.resolution) + if !cs.IsEmpty() { + if _, ok := amap[tn]; ok { + amap[tn] = cs + } else { + amap[tn] = amap[tn].Union(cs) } } - return tn.IsContainer() // descend into containers + return true }) - return &ResolutionSet{rmap} + return amap } diff --git a/tools/compliance/policy/walk_test.go b/tools/compliance/policy/walk_test.go index 07710aa90d..a2ec6e7a84 100644 --- a/tools/compliance/policy/walk_test.go +++ b/tools/compliance/policy/walk_test.go @@ -22,7 +22,7 @@ import ( func TestWalkResolutionsForCondition(t *testing.T) { tests := []struct { name string - condition ConditionNames + condition LicenseConditionSet roots []string edges []annotated expectedResolutions []res @@ -624,8 +624,617 @@ func TestWalkResolutionsForCondition(t *testing.T) { return } expectedRs := toResolutionSet(lg, tt.expectedResolutions) - actualRs := WalkResolutionsForCondition(lg, ResolveTopDownConditions(lg), tt.condition) - checkSame(actualRs, expectedRs, t) + ResolveTopDownConditions(lg) + actualRs := WalkResolutionsForCondition(lg, tt.condition) + checkResolves(actualRs, expectedRs, t) + }) + } +} + +func TestWalkActionsForCondition(t *testing.T) { + tests := []struct { + name string + condition LicenseConditionSet + roots []string + edges []annotated + expectedActions []act + }{ + { + name: "firstparty", + condition: ImpliesNotice, + roots: []string{"apacheBin.meta_lic"}, + edges: []annotated{ + {"apacheBin.meta_lic", "apacheLib.meta_lic", []string{"static"}}, + }, + expectedActions: []act{ + {"apacheBin.meta_lic", "apacheBin.meta_lic", "notice"}, + {"apacheLib.meta_lic", "apacheLib.meta_lic", "notice"}, + }, + }, + { + name: "notice", + condition: ImpliesNotice, + roots: []string{"mitBin.meta_lic"}, + edges: []annotated{ + {"mitBin.meta_lic", "mitLib.meta_lic", []string{"static"}}, + }, + expectedActions: []act{ + {"mitBin.meta_lic", "mitBin.meta_lic", "notice"}, + {"mitLib.meta_lic", "mitLib.meta_lic", "notice"}, + }, + }, + { + name: "fponlgplnotice", + condition: ImpliesNotice, + roots: []string{"apacheBin.meta_lic"}, + edges: []annotated{ + {"apacheBin.meta_lic", "lgplLib.meta_lic", []string{"static"}}, + }, + expectedActions: []act{ + {"apacheBin.meta_lic", "apacheBin.meta_lic", "notice"}, + {"apacheBin.meta_lic", "lgplLib.meta_lic", "restricted"}, + {"lgplLib.meta_lic", "lgplLib.meta_lic", "restricted"}, + }, + }, + { + name: "fponlgpldynamicnotice", + condition: ImpliesNotice, + roots: []string{"apacheBin.meta_lic"}, + edges: []annotated{ + {"apacheBin.meta_lic", "lgplLib.meta_lic", []string{"dynamic"}}, + }, + expectedActions: []act{ + {"apacheBin.meta_lic", "apacheBin.meta_lic", "notice"}, + }, + }, + { + name: "independentmodulenotice", + condition: ImpliesNotice, + roots: []string{"apacheBin.meta_lic"}, + edges: []annotated{ + {"apacheBin.meta_lic", "gplWithClasspathException.meta_lic", []string{"dynamic"}}, + }, + expectedActions: []act{ + {"apacheBin.meta_lic", "apacheBin.meta_lic", "notice"}, + }, + }, + { + name: "independentmodulerestricted", + condition: ImpliesRestricted, + roots: []string{"apacheBin.meta_lic"}, + edges: []annotated{ + {"apacheBin.meta_lic", "gplWithClasspathException.meta_lic", []string{"dynamic"}}, + }, + expectedActions: []act{}, + }, + { + name: "independentmodulestaticnotice", + condition: ImpliesNotice, + roots: []string{"apacheBin.meta_lic"}, + edges: []annotated{ + {"apacheBin.meta_lic", "gplWithClasspathException.meta_lic", []string{"static"}}, + }, + expectedActions: []act{ + {"apacheBin.meta_lic", "apacheBin.meta_lic", "notice"}, + {"apacheBin.meta_lic", "gplWithClasspathException.meta_lic", "restricted"}, + {"gplWithClasspathException.meta_lic", "gplWithClasspathException.meta_lic", "restricted"}, + }, + }, + { + name: "independentmodulestaticrestricted", + condition: ImpliesRestricted, + roots: []string{"apacheBin.meta_lic"}, + edges: []annotated{ + {"apacheBin.meta_lic", "gplWithClasspathException.meta_lic", []string{"static"}}, + }, + expectedActions: []act{ + {"apacheBin.meta_lic", "gplWithClasspathException.meta_lic", "restricted"}, + {"gplWithClasspathException.meta_lic", "gplWithClasspathException.meta_lic", "restricted"}, + }, + }, + { + name: "dependentmodulenotice", + condition: ImpliesNotice, + roots: []string{"dependentModule.meta_lic"}, + edges: []annotated{ + {"dependentModule.meta_lic", "gplWithClasspathException.meta_lic", []string{"dynamic"}}, + }, + expectedActions: []act{ + {"dependentModule.meta_lic", "dependentModule.meta_lic", "notice"}, + {"dependentModule.meta_lic", "gplWithClasspathException.meta_lic", "restricted"}, + }, + }, + { + name: "dependentmodulerestricted", + condition: ImpliesRestricted, + roots: []string{"dependentModule.meta_lic"}, + edges: []annotated{ + {"dependentModule.meta_lic", "gplWithClasspathException.meta_lic", []string{"dynamic"}}, + }, + expectedActions: []act{ + {"dependentModule.meta_lic", "gplWithClasspathException.meta_lic", "restricted"}, + }, + }, + { + name: "lgplonfpnotice", + condition: ImpliesNotice, + roots: []string{"lgplBin.meta_lic"}, + edges: []annotated{ + {"lgplBin.meta_lic", "apacheLib.meta_lic", []string{"static"}}, + }, + expectedActions: []act{ + {"lgplBin.meta_lic", "lgplBin.meta_lic", "restricted"}, + {"apacheLib.meta_lic", "apacheLib.meta_lic", "notice"}, + {"apacheLib.meta_lic", "lgplBin.meta_lic", "restricted"}, + }, + }, + { + name: "lgplonfprestricted", + condition: ImpliesRestricted, + roots: []string{"lgplBin.meta_lic"}, + edges: []annotated{ + {"lgplBin.meta_lic", "apacheLib.meta_lic", []string{"static"}}, + }, + expectedActions: []act{ + {"lgplBin.meta_lic", "lgplBin.meta_lic", "restricted"}, + {"apacheLib.meta_lic", "lgplBin.meta_lic", "restricted"}, + }, + }, + { + name: "lgplonfpdynamicnotice", + condition: ImpliesNotice, + roots: []string{"lgplBin.meta_lic"}, + edges: []annotated{ + {"lgplBin.meta_lic", "apacheLib.meta_lic", []string{"dynamic"}}, + }, + expectedActions: []act{ + {"lgplBin.meta_lic", "lgplBin.meta_lic", "restricted"}, + }, + }, + { + name: "lgplonfpdynamicrestricted", + condition: ImpliesRestricted, + roots: []string{"lgplBin.meta_lic"}, + edges: []annotated{ + {"lgplBin.meta_lic", "apacheLib.meta_lic", []string{"dynamic"}}, + }, + expectedActions: []act{ + {"lgplBin.meta_lic", "lgplBin.meta_lic", "restricted"}, + }, + }, + { + name: "gplonfpnotice", + condition: ImpliesNotice, + roots: []string{"gplBin.meta_lic"}, + edges: []annotated{ + {"gplBin.meta_lic", "apacheLib.meta_lic", []string{"static"}}, + }, + expectedActions: []act{ + {"gplBin.meta_lic", "gplBin.meta_lic", "restricted"}, + {"apacheLib.meta_lic", "apacheLib.meta_lic", "notice"}, + {"apacheLib.meta_lic", "gplBin.meta_lic", "restricted"}, + }, + }, + { + name: "gplonfprestricted", + condition: ImpliesRestricted, + roots: []string{"gplBin.meta_lic"}, + edges: []annotated{ + {"gplBin.meta_lic", "apacheLib.meta_lic", []string{"static"}}, + }, + expectedActions: []act{ + {"gplBin.meta_lic", "gplBin.meta_lic", "restricted"}, + {"apacheLib.meta_lic", "gplBin.meta_lic", "restricted"}, + }, + }, + { + name: "gplcontainernotice", + condition: ImpliesNotice, + roots: []string{"gplContainer.meta_lic"}, + edges: []annotated{ + {"gplContainer.meta_lic", "apacheLib.meta_lic", []string{"static"}}, + }, + expectedActions: []act{ + {"gplContainer.meta_lic", "gplContainer.meta_lic", "restricted"}, + {"apacheLib.meta_lic", "apacheLib.meta_lic", "notice"}, + {"apacheLib.meta_lic", "gplContainer.meta_lic", "restricted"}, + {"apacheLib.meta_lic", "apacheLib.meta_lic", "notice"}, + {"apacheLib.meta_lic", "gplContainer.meta_lic", "restricted"}, + }, + }, + { + name: "gplcontainerrestricted", + condition: ImpliesRestricted, + roots: []string{"gplContainer.meta_lic"}, + edges: []annotated{ + {"gplContainer.meta_lic", "apacheLib.meta_lic", []string{"static"}}, + }, + expectedActions: []act{ + {"gplContainer.meta_lic", "gplContainer.meta_lic", "restricted"}, + {"apacheLib.meta_lic", "gplContainer.meta_lic", "restricted"}, + {"apacheLib.meta_lic", "gplContainer.meta_lic", "restricted"}, + }, + }, + { + name: "gploncontainernotice", + condition: ImpliesNotice, + roots: []string{"apacheContainer.meta_lic"}, + edges: []annotated{ + {"apacheContainer.meta_lic", "apacheLib.meta_lic", []string{"static"}}, + {"apacheContainer.meta_lic", "gplLib.meta_lic", []string{"static"}}, + }, + expectedActions: []act{ + {"apacheContainer.meta_lic", "apacheContainer.meta_lic", "notice"}, + {"apacheContainer.meta_lic", "gplLib.meta_lic", "restricted"}, + {"apacheLib.meta_lic", "apacheLib.meta_lic", "notice"}, + {"apacheLib.meta_lic", "apacheLib.meta_lic", "notice"}, + {"gplLib.meta_lic", "gplLib.meta_lic", "restricted"}, + }, + }, + { + name: "gploncontainerrestricted", + condition: ImpliesRestricted, + roots: []string{"apacheContainer.meta_lic"}, + edges: []annotated{ + {"apacheContainer.meta_lic", "apacheLib.meta_lic", []string{"static"}}, + {"apacheContainer.meta_lic", "gplLib.meta_lic", []string{"static"}}, + }, + expectedActions: []act{ + {"apacheContainer.meta_lic", "gplLib.meta_lic", "restricted"}, + {"gplLib.meta_lic", "gplLib.meta_lic", "restricted"}, + }, + }, + { + name: "gplonbinnotice", + condition: ImpliesNotice, + roots: []string{"apacheBin.meta_lic"}, + edges: []annotated{ + {"apacheBin.meta_lic", "apacheLib.meta_lic", []string{"static"}}, + {"apacheBin.meta_lic", "gplLib.meta_lic", []string{"static"}}, + }, + expectedActions: []act{ + {"apacheBin.meta_lic", "apacheBin.meta_lic", "notice"}, + {"apacheBin.meta_lic", "gplLib.meta_lic", "restricted"}, + {"apacheLib.meta_lic", "apacheLib.meta_lic", "notice"}, + {"apacheLib.meta_lic", "gplLib.meta_lic", "restricted"}, + {"gplLib.meta_lic", "gplLib.meta_lic", "restricted"}, + }, + }, + { + name: "gplonbinrestricted", + condition: ImpliesRestricted, + roots: []string{"apacheBin.meta_lic"}, + edges: []annotated{ + {"apacheBin.meta_lic", "apacheLib.meta_lic", []string{"static"}}, + {"apacheBin.meta_lic", "gplLib.meta_lic", []string{"static"}}, + }, + expectedActions: []act{ + {"apacheBin.meta_lic", "gplLib.meta_lic", "restricted"}, + {"apacheLib.meta_lic", "gplLib.meta_lic", "restricted"}, + {"gplLib.meta_lic", "gplLib.meta_lic", "restricted"}, + }, + }, + { + name: "gplonfpdynamicnotice", + condition: ImpliesNotice, + roots: []string{"gplBin.meta_lic"}, + edges: []annotated{ + {"gplBin.meta_lic", "apacheLib.meta_lic", []string{"dynamic"}}, + }, + expectedActions: []act{ + {"gplBin.meta_lic", "gplBin.meta_lic", "restricted"}, + }, + }, + { + name: "gplonfpdynamicrestricted", + condition: ImpliesRestricted, + roots: []string{"gplBin.meta_lic"}, + edges: []annotated{ + {"gplBin.meta_lic", "apacheLib.meta_lic", []string{"dynamic"}}, + }, + expectedActions: []act{ + {"gplBin.meta_lic", "gplBin.meta_lic", "restricted"}, + }, + }, + { + name: "gplonfpdynamicrestrictedshipped", + condition: ImpliesRestricted, + roots: []string{"gplBin.meta_lic", "apacheLib.meta_lic"}, + edges: []annotated{ + {"gplBin.meta_lic", "apacheLib.meta_lic", []string{"dynamic"}}, + }, + expectedActions: []act{ + {"gplBin.meta_lic", "gplBin.meta_lic", "restricted"}, + {"apacheLib.meta_lic", "gplBin.meta_lic", "restricted"}, + }, + }, + { + name: "independentmodulereversenotice", + condition: ImpliesNotice, + roots: []string{"gplWithClasspathException.meta_lic"}, + edges: []annotated{ + {"gplWithClasspathException.meta_lic", "apacheBin.meta_lic", []string{"dynamic"}}, + }, + expectedActions: []act{ + {"gplWithClasspathException.meta_lic", "gplWithClasspathException.meta_lic", "restricted"}, + }, + }, + { + name: "independentmodulereverserestricted", + condition: ImpliesRestricted, + roots: []string{"gplWithClasspathException.meta_lic"}, + edges: []annotated{ + {"gplWithClasspathException.meta_lic", "apacheBin.meta_lic", []string{"dynamic"}}, + }, + expectedActions: []act{ + {"gplWithClasspathException.meta_lic", "gplWithClasspathException.meta_lic", "restricted"}, + }, + }, + { + name: "independentmodulereverserestrictedshipped", + condition: ImpliesRestricted, + roots: []string{"gplWithClasspathException.meta_lic", "apacheBin.meta_lic"}, + edges: []annotated{ + {"gplWithClasspathException.meta_lic", "apacheBin.meta_lic", []string{"dynamic"}}, + }, + expectedActions: []act{ + {"gplWithClasspathException.meta_lic", "gplWithClasspathException.meta_lic", "restricted"}, + }, + }, + { + name: "independentmodulereversestaticnotice", + condition: ImpliesNotice, + roots: []string{"gplWithClasspathException.meta_lic"}, + edges: []annotated{ + {"gplWithClasspathException.meta_lic", "apacheBin.meta_lic", []string{"static"}}, + }, + expectedActions: []act{ + {"gplWithClasspathException.meta_lic", "gplWithClasspathException.meta_lic", "restricted"}, + {"apacheBin.meta_lic", "apacheBin.meta_lic", "notice"}, + {"apacheBin.meta_lic", "gplWithClasspathException.meta_lic", "restricted"}, + }, + }, + { + name: "independentmodulereversestaticrestricted", + condition: ImpliesRestricted, + roots: []string{"gplWithClasspathException.meta_lic"}, + edges: []annotated{ + {"gplWithClasspathException.meta_lic", "apacheBin.meta_lic", []string{"static"}}, + }, + expectedActions: []act{ + {"gplWithClasspathException.meta_lic", "gplWithClasspathException.meta_lic", "restricted"}, + {"apacheBin.meta_lic", "gplWithClasspathException.meta_lic", "restricted"}, + }, + }, + { + name: "dependentmodulereversenotice", + condition: ImpliesNotice, + roots: []string{"gplWithClasspathException.meta_lic"}, + edges: []annotated{ + {"gplWithClasspathException.meta_lic", "dependentModule.meta_lic", []string{"dynamic"}}, + }, + expectedActions: []act{ + {"gplWithClasspathException.meta_lic", "gplWithClasspathException.meta_lic", "restricted"}, + }, + }, + { + name: "dependentmodulereverserestricted", + condition: ImpliesRestricted, + roots: []string{"gplWithClasspathException.meta_lic"}, + edges: []annotated{ + {"gplWithClasspathException.meta_lic", "dependentModule.meta_lic", []string{"dynamic"}}, + }, + expectedActions: []act{ + {"gplWithClasspathException.meta_lic", "gplWithClasspathException.meta_lic", "restricted"}, + }, + }, + { + name: "dependentmodulereverserestrictedshipped", + condition: ImpliesRestricted, + roots: []string{"gplWithClasspathException.meta_lic", "dependentModule.meta_lic"}, + edges: []annotated{ + {"gplWithClasspathException.meta_lic", "dependentModule.meta_lic", []string{"dynamic"}}, + }, + expectedActions: []act{ + {"gplWithClasspathException.meta_lic", "gplWithClasspathException.meta_lic", "restricted"}, + {"dependentModule.meta_lic", "gplWithClasspathException.meta_lic", "restricted"}, + }, + }, + { + name: "ponrnotice", + condition: ImpliesNotice, + roots: []string{"proprietary.meta_lic"}, + edges: []annotated{ + {"proprietary.meta_lic", "gplLib.meta_lic", []string{"static"}}, + }, + expectedActions: []act{ + {"proprietary.meta_lic", "proprietary.meta_lic", "proprietary"}, + {"proprietary.meta_lic", "gplLib.meta_lic", "restricted"}, + {"gplLib.meta_lic", "gplLib.meta_lic", "restricted"}, + }, + }, + { + name: "ponrrestricted", + condition: ImpliesRestricted, + roots: []string{"proprietary.meta_lic"}, + edges: []annotated{ + {"proprietary.meta_lic", "gplLib.meta_lic", []string{"static"}}, + }, + expectedActions: []act{ + {"gplLib.meta_lic", "gplLib.meta_lic", "restricted"}, + {"proprietary.meta_lic", "gplLib.meta_lic", "restricted"}, + }, + }, + { + name: "ponrproprietary", + condition: ImpliesProprietary, + roots: []string{"proprietary.meta_lic"}, + edges: []annotated{ + {"proprietary.meta_lic", "gplLib.meta_lic", []string{"static"}}, + }, + expectedActions: []act{ + {"proprietary.meta_lic", "proprietary.meta_lic", "proprietary"}, + }, + }, + { + name: "ronpnotice", + condition: ImpliesNotice, + roots: []string{"gplBin.meta_lic"}, + edges: []annotated{ + {"gplBin.meta_lic", "proprietary.meta_lic", []string{"static"}}, + }, + expectedActions: []act{ + {"gplBin.meta_lic", "gplBin.meta_lic", "restricted"}, + {"proprietary.meta_lic", "proprietary.meta_lic", "proprietary"}, + {"proprietary.meta_lic", "gplBin.meta_lic", "restricted"}, + }, + }, + { + name: "ronprestricted", + condition: ImpliesRestricted, + roots: []string{"gplBin.meta_lic"}, + edges: []annotated{ + {"gplBin.meta_lic", "proprietary.meta_lic", []string{"static"}}, + }, + expectedActions: []act{ + {"gplBin.meta_lic", "gplBin.meta_lic", "restricted"}, + {"proprietary.meta_lic", "gplBin.meta_lic", "restricted"}, + }, + }, + { + name: "ronpproprietary", + condition: ImpliesProprietary, + roots: []string{"gplBin.meta_lic"}, + edges: []annotated{ + {"gplBin.meta_lic", "proprietary.meta_lic", []string{"static"}}, + }, + expectedActions: []act{ + {"proprietary.meta_lic", "proprietary.meta_lic", "proprietary"}, + }, + }, + { + name: "noticeonb_e_onotice", + condition: ImpliesNotice, + roots: []string{"mitBin.meta_lic"}, + edges: []annotated{ + {"mitBin.meta_lic", "by_exception.meta_lic", []string{"static"}}, + }, + expectedActions: []act{ + {"mitBin.meta_lic", "mitBin.meta_lic", "notice"}, + {"by_exception.meta_lic", "by_exception.meta_lic", "by_exception_only"}, + }, + }, + { + name: "noticeonb_e_orestricted", + condition: ImpliesRestricted, + roots: []string{"mitBin.meta_lic"}, + edges: []annotated{ + {"mitBin.meta_lic", "by_exception.meta_lic", []string{"static"}}, + }, + expectedActions: []act{}, + }, + { + name: "noticeonb_e_ob_e_o", + condition: ImpliesByExceptionOnly, + roots: []string{"mitBin.meta_lic"}, + edges: []annotated{ + {"mitBin.meta_lic", "by_exception.meta_lic", []string{"static"}}, + }, + expectedActions: []act{ + {"by_exception.meta_lic", "by_exception.meta_lic", "by_exception_only"}, + }, + }, + { + name: "b_e_oonnoticenotice", + condition: ImpliesNotice, + roots: []string{"by_exception.meta_lic"}, + edges: []annotated{ + {"by_exception.meta_lic", "mitLib.meta_lic", []string{"static"}}, + }, + expectedActions: []act{ + {"by_exception.meta_lic", "by_exception.meta_lic", "by_exception_only"}, + {"mitLib.meta_lic", "mitLib.meta_lic", "notice"}, + }, + }, + { + name: "b_e_oonnoticerestricted", + condition: ImpliesRestricted, + roots: []string{"by_exception.meta_lic"}, + edges: []annotated{ + {"by_exception.meta_lic", "mitLib.meta_lic", []string{"static"}}, + }, + expectedActions: []act{}, + }, + { + name: "b_e_oonnoticeb_e_o", + condition: ImpliesByExceptionOnly, + roots: []string{"by_exception.meta_lic"}, + edges: []annotated{ + {"by_exception.meta_lic", "mitLib.meta_lic", []string{"static"}}, + }, + expectedActions: []act{ + {"by_exception.meta_lic", "by_exception.meta_lic", "by_exception_only"}, + }, + }, + { + name: "noticeonrecipnotice", + condition: ImpliesNotice, + roots: []string{"mitBin.meta_lic"}, + edges: []annotated{ + {"mitBin.meta_lic", "mplLib.meta_lic", []string{"static"}}, + }, + expectedActions: []act{ + {"mitBin.meta_lic", "mitBin.meta_lic", "notice"}, + {"mplLib.meta_lic", "mplLib.meta_lic", "reciprocal"}, + }, + }, + { + name: "noticeonreciprecip", + condition: ImpliesReciprocal, + roots: []string{"mitBin.meta_lic"}, + edges: []annotated{ + {"mitBin.meta_lic", "mplLib.meta_lic", []string{"static"}}, + }, + expectedActions: []act{ + {"mplLib.meta_lic", "mplLib.meta_lic", "reciprocal"}, + }, + }, + { + name: "reciponnoticenotice", + condition: ImpliesNotice, + roots: []string{"mplBin.meta_lic"}, + edges: []annotated{ + {"mplBin.meta_lic", "mitLib.meta_lic", []string{"static"}}, + }, + expectedActions: []act{ + {"mplBin.meta_lic", "mplBin.meta_lic", "reciprocal"}, + {"mitLib.meta_lic", "mitLib.meta_lic", "notice"}, + }, + }, + { + name: "reciponnoticerecip", + condition: ImpliesReciprocal, + roots: []string{"mplBin.meta_lic"}, + edges: []annotated{ + {"mplBin.meta_lic", "mitLib.meta_lic", []string{"static"}}, + }, + expectedActions: []act{ + {"mplBin.meta_lic", "mplBin.meta_lic", "reciprocal"}, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + stderr := &bytes.Buffer{} + lg, err := toGraph(stderr, tt.roots, tt.edges) + if err != nil { + t.Errorf("unexpected test data error: got %w, want no error", err) + return + } + expectedAs := toActionSet(lg, tt.expectedActions) + ResolveTopDownConditions(lg) + actualAs := WalkActionsForCondition(lg, tt.condition) + checkResolvesActions(lg, actualAs, expectedAs, t) }) } } diff --git a/tools/compliance/readgraph.go b/tools/compliance/readgraph.go index c88b3e6901..c809a96dd9 100644 --- a/tools/compliance/readgraph.go +++ b/tools/compliance/readgraph.go @@ -39,16 +39,13 @@ type result struct { // target contains the parsed metadata or nil if an error target *TargetNode - // edges contains the parsed dependencies - edges []*dependencyEdge - // err is nil unless an error occurs err error } // receiver coordinates the tasks for reading and parsing license metadata files. type receiver struct { - // lg accumulates the read metadata and becomes the final resulting LicensGraph. + // lg accumulates the read metadata and becomes the final resulting LicenseGraph. lg *LicenseGraph // rootFS locates the root of the file system from which to read the files. @@ -138,10 +135,7 @@ func ReadLicenseGraph(rootFS fs.FS, stderr io.Writer, files []string) (*LicenseG // record the parsed metadata (guarded by mutex) recv.lg.mu.Lock() - recv.lg.targets[r.file] = r.target - if len(r.edges) > 0 { - recv.lg.edges = append(recv.lg.edges, r.edges...) - } + lg.targets[r.target.name] = r.target recv.lg.mu.Unlock() } else { // finished -- nil the results channel @@ -150,6 +144,21 @@ func ReadLicenseGraph(rootFS fs.FS, stderr io.Writer, files []string) (*LicenseG } } + if lg != nil { + esize := 0 + for _, tn := range lg.targets { + esize += len(tn.proto.Deps) + } + lg.edges = make(TargetEdgeList, 0, esize) + for _, tn := range lg.targets { + tn.licenseConditions = LicenseConditionSetFromNames(tn, tn.proto.LicenseConditions...) + err = addDependencies(lg, tn) + if err != nil { + return nil, fmt.Errorf("error indexing dependencies for %q: %w", tn.name, err) + } + tn.proto.Deps = []*license_metadata_proto.AnnotatedDependency{} + } + } return lg, err } @@ -158,34 +167,37 @@ func ReadLicenseGraph(rootFS fs.FS, stderr io.Writer, files []string) (*LicenseG type targetNode struct { proto license_metadata_proto.LicenseMetadata - // name is the path to the metadata file + // name is the path to the metadata file. name string -} -// dependencyEdge describes a single edge in the license graph. -type dependencyEdge struct { - // target identifies the target node being built and/or installed. - target string + // lg is the license graph the node belongs to. + lg *LicenseGraph - // dependency identifies the target node being depended on. - // - // i.e. `dependency` is necessary to build `target`. - dependency string + // edges identifies the dependencies of the target. + edges TargetEdgeList - // annotations are a set of text attributes attached to the edge. - // - // Policy prescribes meaning to a limited set of annotations; others - // are preserved and ignored. - annotations TargetEdgeAnnotations + // licenseConditions identifies the set of license conditions originating at the target node. + licenseConditions LicenseConditionSet + + // resolution identifies the set of conditions resolved by acting on the target node. + resolution LicenseConditionSet } // addDependencies converts the proto AnnotatedDependencies into `edges` -func addDependencies(edges *[]*dependencyEdge, target string, dependencies []*license_metadata_proto.AnnotatedDependency) error { - for _, ad := range dependencies { +func addDependencies(lg *LicenseGraph, tn *TargetNode) error { + tn.edges = make(TargetEdgeList, 0,len(tn.proto.Deps)) + for _, ad := range tn.proto.Deps { dependency := ad.GetFile() if len(dependency) == 0 { return fmt.Errorf("missing dependency name") } + dtn, ok := lg.targets[dependency] + if !ok { + return fmt.Errorf("unknown dependency name %q", dependency) + } + if dtn == nil { + return fmt.Errorf("nil dependency for name %q", dependency) + } annotations := newEdgeAnnotations() for _, a := range ad.Annotations { // look up a common constant annotation string from a small map @@ -194,7 +206,9 @@ func addDependencies(edges *[]*dependencyEdge, target string, dependencies []*li annotations.annotations[ann] = struct{}{} } } - *edges = append(*edges, &dependencyEdge{target, dependency, annotations}) + edge := &TargetEdge{tn, dtn, annotations} + lg.edges = append(lg.edges, edge) + tn.edges = append(tn.edges, edge) } return nil } @@ -207,50 +221,44 @@ func readFile(recv *receiver, file string) { go func() { f, err := recv.rootFS.Open(file) if err != nil { - recv.results <- &result{file, nil, nil, fmt.Errorf("error opening license metadata %q: %w", file, err)} + recv.results <- &result{file, nil, fmt.Errorf("error opening license metadata %q: %w", file, err)} return } // read the file data, err := io.ReadAll(f) if err != nil { - recv.results <- &result{file, nil, nil, fmt.Errorf("error reading license metadata %q: %w", file, err)} + recv.results <- &result{file, nil, fmt.Errorf("error reading license metadata %q: %w", file, err)} return } + f.Close() - tn := &TargetNode{name: file} + tn := &TargetNode{lg: recv.lg, name: file} err = prototext.Unmarshal(data, &tn.proto) if err != nil { - recv.results <- &result{file, nil, nil, fmt.Errorf("error license metadata %q: %w", file, err)} + recv.results <- &result{file, nil, fmt.Errorf("error license metadata %q: %w", file, err)} return } - edges := []*dependencyEdge{} - err = addDependencies(&edges, file, tn.proto.Deps) - if err != nil { - recv.results <- &result{file, nil, nil, fmt.Errorf("error license metadata dependency %q: %w", file, err)} - return - } - tn.proto.Deps = []*license_metadata_proto.AnnotatedDependency{} - // send result for this file and release task before scheduling dependencies, // but do not signal done to WaitGroup until dependencies are scheduled. - recv.results <- &result{file, tn, edges, nil} + recv.results <- &result{file, tn, nil} recv.task <- true // schedule tasks as necessary to read dependencies - for _, e := range edges { + for _, ad := range tn.proto.Deps { + dependency := ad.GetFile() // decide, signal and record whether to schedule task in critical section recv.lg.mu.Lock() - _, alreadyScheduled := recv.lg.targets[e.dependency] + _, alreadyScheduled := recv.lg.targets[dependency] if !alreadyScheduled { - recv.lg.targets[e.dependency] = nil + recv.lg.targets[dependency] = nil } recv.lg.mu.Unlock() // schedule task to read dependency file outside critical section if !alreadyScheduled { - readFile(recv, e.dependency) + readFile(recv, dependency) } } diff --git a/tools/compliance/readgraph_test.go b/tools/compliance/readgraph_test.go index 6248209228..6ff7a6c4f8 100644 --- a/tools/compliance/readgraph_test.go +++ b/tools/compliance/readgraph_test.go @@ -108,29 +108,40 @@ func TestReadLicenseGraph(t *testing.T) { } sort.Sort(byEdge(tt.expectedEdges)) sort.Sort(byEdge(actualEdges)) + t.Logf("actualEdges:") + for _, edge := range actualEdges { + t.Logf(" %s", edge.String()) + } + t.Logf("expectedEdges:") + for _, edge := range actualEdges { + t.Logf(" %s", edge.String()) + } if len(tt.expectedEdges) != len(actualEdges) { - t.Errorf("unexpected number of edges: got %v with %d elements, want %v with %d elements", - actualEdges, len(actualEdges), tt.expectedEdges, len(tt.expectedEdges)) + t.Errorf("len(actualEdges): got %d, want %d", len(actualEdges), len(tt.expectedEdges)) } else { for i := 0; i < len(actualEdges); i++ { if tt.expectedEdges[i] != actualEdges[i] { - t.Errorf("unexpected edge at element %d: got %s, want %s", i, actualEdges[i], tt.expectedEdges[i]) + t.Errorf("actualEdges[%d]: got %s, want %s", i, actualEdges[i], tt.expectedEdges[i]) } } } + actualTargets := make([]string, 0) for _, t := range lg.Targets() { actualTargets = append(actualTargets, t.Name()) } sort.Strings(tt.expectedTargets) sort.Strings(actualTargets) + + t.Logf("actualTargets: %v", actualTargets) + t.Logf("expectedTargets: %v", tt.expectedTargets) + if len(tt.expectedTargets) != len(actualTargets) { - t.Errorf("unexpected number of targets: got %v with %d elements, want %v with %d elements", - actualTargets, len(actualTargets), tt.expectedTargets, len(tt.expectedTargets)) + t.Errorf("len(actualTargets): got %d, want %d", len(actualTargets), len(tt.expectedTargets)) } else { for i := 0; i < len(actualTargets); i++ { if tt.expectedTargets[i] != actualTargets[i] { - t.Errorf("unexpected target at element %d: got %s, want %s", i, actualTargets[i], tt.expectedTargets[i]) + t.Errorf("actualTargets[%d]: got %s, want %s", i, actualTargets[i], tt.expectedTargets[i]) } } } diff --git a/tools/compliance/resolution.go b/tools/compliance/resolution.go index 0865ecd0b4..6f15ca350e 100644 --- a/tools/compliance/resolution.go +++ b/tools/compliance/resolution.go @@ -32,7 +32,7 @@ import ( // resolve the restricted condition originating from the GPL code. type Resolution struct { attachesTo, actsOn *TargetNode - cs *LicenseConditionSet + cs LicenseConditionSet } // AttachesTo returns the target node the resolution attaches to. @@ -48,16 +48,16 @@ func (r Resolution) ActsOn() *TargetNode { } // Resolves returns the set of license condition the resolution satisfies. -func (r Resolution) Resolves() *LicenseConditionSet { - return r.cs.Copy() +func (r Resolution) Resolves() LicenseConditionSet { + return r.cs } // asString returns a string representation of the resolution. func (r Resolution) asString() string { var sb strings.Builder - cl := r.cs.AsList() - sort.Sort(cl) - fmt.Fprintf(&sb, "%s -> %s -> %s", r.attachesTo.name, r.actsOn.name, cl.String()) + names := r.cs.Names() + sort.Strings(names) + fmt.Fprintf(&sb, "%s -> %s{%s}", r.attachesTo.name, r.actsOn.name, strings.Join(names, ", ")) return sb.String() } @@ -94,67 +94,32 @@ func (rl ResolutionList) String() string { // AllConditions returns the union of all license conditions resolved by any // element of the list. -func (rl ResolutionList) AllConditions() *LicenseConditionSet { - result := newLicenseConditionSet() +func (rl ResolutionList) AllConditions() LicenseConditionSet { + result := NewLicenseConditionSet() for _, r := range rl { - result.AddSet(r.cs) + result = result.Union(r.cs) } return result } // ByName returns the sub-list of resolutions resolving conditions matching // `names`. -func (rl ResolutionList) ByName(names ConditionNames) ResolutionList { - result := make(ResolutionList, 0, rl.CountByName(names)) +func (rl ResolutionList) Matching(conditions LicenseConditionSet) ResolutionList { + result := make(ResolutionList, 0, rl.CountMatching(conditions)) for _, r := range rl { - if r.Resolves().HasAnyByName(names) { - result = append(result, Resolution{r.attachesTo, r.actsOn, r.cs.ByName(names)}) + if r.Resolves().MatchesAnySet(conditions) { + result = append(result, Resolution{r.attachesTo, r.actsOn, r.cs.MatchingAnySet(conditions)}) } } return result } -// CountByName returns the number of resolutions resolving conditions matching -// `names`. -func (rl ResolutionList) CountByName(names ConditionNames) int { +// CountMatching returns the number of resolutions resolving conditions matching +// `conditions`. +func (rl ResolutionList) CountMatching(conditions LicenseConditionSet) int { c := 0 for _, r := range rl { - if r.Resolves().HasAnyByName(names) { - c++ - } - } - return c -} - -// CountConditionsByName returns a count of distinct resolution/conditions -// pairs matching `names`. -// -// A single resolution might resolve multiple conditions matching `names`. -func (rl ResolutionList) CountConditionsByName(names ConditionNames) int { - c := 0 - for _, r := range rl { - c += r.Resolves().CountByName(names) - } - return c -} - -// ByAttachesTo returns the sub-list of resolutions attached to `attachesTo`. -func (rl ResolutionList) ByAttachesTo(attachesTo *TargetNode) ResolutionList { - result := make(ResolutionList, 0, rl.CountByActsOn(attachesTo)) - for _, r := range rl { - if r.attachesTo == attachesTo { - result = append(result, r) - } - } - return result -} - -// CountByAttachesTo returns the number of resolutions attached to -// `attachesTo`. -func (rl ResolutionList) CountByAttachesTo(attachesTo *TargetNode) int { - c := 0 - for _, r := range rl { - if r.attachesTo == attachesTo { + if r.Resolves().MatchesAnySet(conditions) { c++ } } @@ -182,27 +147,3 @@ func (rl ResolutionList) CountByActsOn(actsOn *TargetNode) int { } return c } - -// ByOrigin returns the sub-list of resolutions resolving license conditions -// originating at `origin`. -func (rl ResolutionList) ByOrigin(origin *TargetNode) ResolutionList { - result := make(ResolutionList, 0, rl.CountByOrigin(origin)) - for _, r := range rl { - if r.Resolves().HasAnyByOrigin(origin) { - result = append(result, Resolution{r.attachesTo, r.actsOn, r.cs.ByOrigin(origin)}) - } - } - return result -} - -// CountByOrigin returns the number of resolutions resolving license conditions -// originating at `origin`. -func (rl ResolutionList) CountByOrigin(origin *TargetNode) int { - c := 0 - for _, r := range rl { - if r.Resolves().HasAnyByOrigin(origin) { - c++ - } - } - return c -} diff --git a/tools/compliance/resolutionset.go b/tools/compliance/resolutionset.go index 29f321272e..893ef26971 100644 --- a/tools/compliance/resolutionset.go +++ b/tools/compliance/resolutionset.go @@ -19,34 +19,6 @@ import ( "strings" ) -// JoinResolutionSets returns a new ResolutionSet combining the resolutions from -// multiple resolution sets. All sets must be derived from the same license -// graph. -// -// e.g. combine "restricted", "reciprocal", and "proprietary" resolutions. -func JoinResolutionSets(resolutions ...*ResolutionSet) *ResolutionSet { - if len(resolutions) < 1 { - panic(fmt.Errorf("attempt to join 0 resolution sets")) - } - rmap := make(map[*TargetNode]actionSet) - for _, r := range resolutions { - if len(r.resolutions) < 1 { - continue - } - for attachesTo, as := range r.resolutions { - if as.isEmpty() { - continue - } - if _, ok := rmap[attachesTo]; !ok { - rmap[attachesTo] = as.copy() - continue - } - rmap[attachesTo].addSet(as) - } - } - return &ResolutionSet{rmap} -} - // ResolutionSet describes an immutable set of targets and the license // conditions each target must satisfy or "resolve" in a specific context. // @@ -68,8 +40,8 @@ func JoinResolutionSets(resolutions ...*ResolutionSet) *ResolutionSet { // // An "unencumbered" condition would originate from the binary, and a "notice" // condition would originate from the .a library. A ResolutionSet for the -// context of the Notice policy might apply both conditions to the binary while -// preserving the origin of each condition. By applying the notice condition to +// context of the Notice policy might attach both conditions to the binary to +// act on the origin of each condition. By attaching the notice condition to // the binary, the ResolutionSet stipulates the policy that the release of the // unencumbered binary must provide suitable notice for the .a library. // @@ -77,228 +49,71 @@ func JoinResolutionSets(resolutions ...*ResolutionSet) *ResolutionSet { // validating that a suitable notice has been built into the distribution, or // for reporting what notices need to be given. // -// Resolutions for different contexts may be combined in a new ResolutionSet -// using JoinResolutions(...). -// -// See: resolve.go for: -// * ResolveBottomUpConditions(...) -// * ResolveTopDownForCondition(...) -// See also: policy.go for: -// * ResolveSourceSharing(...) -// * ResolveSourcePrivacy(...) -type ResolutionSet struct { - // resolutions maps names of target with applicable conditions to the set of conditions that apply. - resolutions map[*TargetNode]actionSet +// The action is defined by the context. In the above example, the action is +// providing notice for the module acted on. In another context, the action +// might be sharing the source-code or preserving the privacy of the module +// acted on. +type ResolutionSet map[*TargetNode]ActionSet + +// AttachesTo identifies the list of targets triggering action to resolve +// conditions. (unordered) +func (rs ResolutionSet) AttachesTo() TargetNodeList { + result := make(TargetNodeList, 0, len(rs)) + for attachesTo := range rs { + result = append(result, attachesTo) + } + return result } -// String returns a string representation of the set. -func (rs *ResolutionSet) String() string { + +// AttachesToTarget returns true if the set contains conditions that +// are `attachedTo`. +func (rs ResolutionSet) AttachesToTarget(target *TargetNode) bool { + _, isPresent := rs[target] + return isPresent +} + + +// Resolutions returns the list of resolutions that `attachedTo` +// target must resolve. Returns empty list if no conditions apply. +func (rs ResolutionSet) Resolutions(attachesTo *TargetNode) ResolutionList { + as, ok := rs[attachesTo] + if !ok { + return nil + } + result := make(ResolutionList, 0, len(as)) + for actsOn, cs := range as { + result = append(result, Resolution{attachesTo, actsOn, cs}) + } + return result +} + +// String returns a human-readable string representation of the set. +func (rs ResolutionSet) String() string { var sb strings.Builder fmt.Fprintf(&sb, "{") sep := "" - for attachesTo, as := range rs.resolutions { - fmt.Fprintf(&sb, "%s%s -> %s", sep, attachesTo.name, as.String()) + for attachesTo, as := range rs { + fmt.Fprintf(&sb, "%s%s -> %s", sep, attachesTo.Name(), as.String()) sep = ", " } fmt.Fprintf(&sb, "}") return sb.String() } -// AttachesTo identifies the list of targets triggering action to resolve -// conditions. (unordered) -func (rs *ResolutionSet) AttachesTo() TargetNodeList { - targets := make(TargetNodeList, 0, len(rs.resolutions)) - for attachesTo := range rs.resolutions { - targets = append(targets, attachesTo) - } - return targets -} +// ActionSet identifies a set of targets to act on and the license conditions +// the action will resolve. +type ActionSet map[*TargetNode]LicenseConditionSet -// ActsOn identifies the list of targets to act on (share, give notice etc.) -// to resolve conditions. (unordered) -func (rs *ResolutionSet) ActsOn() TargetNodeList { - tset := make(map[*TargetNode]struct{}) - for _, as := range rs.resolutions { - for actsOn := range as { - tset[actsOn] = struct{}{} - } - } - targets := make(TargetNodeList, 0, len(tset)) - for target := range tset { - targets = append(targets, target) - } - return targets -} - -// Origins identifies the list of targets originating conditions to resolve. -// (unordered) -func (rs *ResolutionSet) Origins() TargetNodeList { - tset := make(map[*TargetNode]struct{}) - for _, as := range rs.resolutions { - for _, cs := range as { - for _, origins := range cs.conditions { - for origin := range origins { - tset[origin] = struct{}{} - } - } - } - } - targets := make(TargetNodeList, 0, len(tset)) - for target := range tset { - targets = append(targets, target) - } - return targets -} - -// Resolutions returns the list of resolutions that `attachedTo` -// target must resolve. Returns empty list if no conditions apply. -// -// Panics if `attachedTo` does not appear in the set. -func (rs *ResolutionSet) Resolutions(attachedTo *TargetNode) ResolutionList { - as, ok := rs.resolutions[attachedTo] - if !ok { - return ResolutionList{} - } - result := make(ResolutionList, 0, len(as)) +// String returns a human-readable string representation of the set. +func (as ActionSet) String() string { + var sb strings.Builder + fmt.Fprintf(&sb, "{") + sep := "" for actsOn, cs := range as { - result = append(result, Resolution{attachedTo, actsOn, cs.Copy()}) - } - return result -} - -// ResolutionsByActsOn returns the list of resolutions that must `actOn` to -// resolvee. Returns empty list if no conditions apply. -// -// Panics if `actOn` does not appear in the set. -func (rs *ResolutionSet) ResolutionsByActsOn(actOn *TargetNode) ResolutionList { - c := 0 - for _, as := range rs.resolutions { - if _, ok := as[actOn]; ok { - c++ - } - } - result := make(ResolutionList, 0, c) - for attachedTo, as := range rs.resolutions { - if cs, ok := as[actOn]; ok { - result = append(result, Resolution{attachedTo, actOn, cs.Copy()}) - } - } - return result -} - -// AttachesToByOrigin identifies the list of targets requiring action to -// resolve conditions originating at `origin`. (unordered) -func (rs *ResolutionSet) AttachesToByOrigin(origin *TargetNode) TargetNodeList { - tset := make(map[*TargetNode]struct{}) - for attachesTo, as := range rs.resolutions { - for _, cs := range as { - if cs.HasAnyByOrigin(origin) { - tset[attachesTo] = struct{}{} - break - } - } - } - targets := make(TargetNodeList, 0, len(tset)) - for target := range tset { - targets = append(targets, target) - } - return targets -} - -// AttachesToTarget returns true if the set contains conditions that -// are `attachedTo`. -func (rs *ResolutionSet) AttachesToTarget(attachedTo *TargetNode) bool { - _, isPresent := rs.resolutions[attachedTo] - return isPresent -} - -// AnyByNameAttachToTarget returns true if the set contains conditions matching -// `names` that attach to `attachedTo`. -func (rs *ResolutionSet) AnyByNameAttachToTarget(attachedTo *TargetNode, names ...ConditionNames) bool { - as, isPresent := rs.resolutions[attachedTo] - if !isPresent { - return false - } - for _, cs := range as { - for _, cn := range names { - for _, name := range cn { - _, isPresent = cs.conditions[name] - if isPresent { - return true - } - } - } - } - return false -} - -// AllByNameAttachTo returns true if the set contains at least one condition -// matching each element of `names` for `attachedTo`. -func (rs *ResolutionSet) AllByNameAttachToTarget(attachedTo *TargetNode, names ...ConditionNames) bool { - as, isPresent := rs.resolutions[attachedTo] - if !isPresent { - return false - } - for _, cn := range names { - found := false - asloop: - for _, cs := range as { - for _, name := range cn { - _, isPresent = cs.conditions[name] - if isPresent { - found = true - break asloop - } - } - } - if !found { - return false - } - } - return true -} - -// IsEmpty returns true if the set contains no conditions to resolve. -func (rs *ResolutionSet) IsEmpty() bool { - for _, as := range rs.resolutions { - if !as.isEmpty() { - return false - } - } - return true -} - -// compliance-only ResolutionSet methods - -// newResolutionSet constructs a new, empty instance of resolutionSetImp for graph `lg`. -func newResolutionSet() *ResolutionSet { - return &ResolutionSet{make(map[*TargetNode]actionSet)} -} - -// addConditions attaches all of the license conditions in `as` to `attachTo` to act on the originating node if not already applied. -func (rs *ResolutionSet) addConditions(attachTo *TargetNode, as actionSet) { - _, ok := rs.resolutions[attachTo] - if !ok { - rs.resolutions[attachTo] = as.copy() - return - } - rs.resolutions[attachTo].addSet(as) -} - -// add attaches all of the license conditions in `as` to `attachTo` to act on `attachTo` if not already applied. -func (rs *ResolutionSet) addSelf(attachTo *TargetNode, as actionSet) { - for _, cs := range as { - if cs.IsEmpty() { - return - } - _, ok := rs.resolutions[attachTo] - if !ok { - rs.resolutions[attachTo] = make(actionSet) - } - _, ok = rs.resolutions[attachTo][attachTo] - if !ok { - rs.resolutions[attachTo][attachTo] = newLicenseConditionSet() - } - rs.resolutions[attachTo][attachTo].AddSet(cs) + fmt.Fprintf(&sb, "%s%s%s", sep, actsOn.Name(), cs.String()) + sep = ", " } + fmt.Fprintf(&sb, "}") + return sb.String() } diff --git a/tools/compliance/resolutionset_test.go b/tools/compliance/resolutionset_test.go index e50e8230a7..89cdfebb8f 100644 --- a/tools/compliance/resolutionset_test.go +++ b/tools/compliance/resolutionset_test.go @@ -77,113 +77,46 @@ var ( proprietary = []res{} ) -func TestResolutionSet_JoinResolutionSets(t *testing.T) { - lg := newLicenseGraph() - - rsNotice := toResolutionSet(lg, notice) - rsShare := toResolutionSet(lg, share) - rsExpected := toResolutionSet(lg, append(notice, share...)) - - rsActual := JoinResolutionSets(rsNotice, rsShare) - checkSame(rsActual, rsExpected, t) -} - -func TestResolutionSet_JoinResolutionsEmpty(t *testing.T) { - lg := newLicenseGraph() - - rsShare := toResolutionSet(lg, share) - rsProprietary := toResolutionSet(lg, proprietary) - rsExpected := toResolutionSet(lg, append(share, proprietary...)) - - rsActual := JoinResolutionSets(rsShare, rsProprietary) - checkSame(rsActual, rsExpected, t) -} - -func TestResolutionSet_Origins(t *testing.T) { +func TestResolutionSet_AttachesTo(t *testing.T) { lg := newLicenseGraph() rsShare := toResolutionSet(lg, share) - origins := make([]string, 0) - for _, target := range rsShare.Origins() { - origins = append(origins, target.Name()) - } - sort.Strings(origins) - if len(origins) != 2 { - t.Errorf("unexpected number of origins: got %v with %d elements, want [\"bin1\", \"bin2\"] with 2 elements", origins, len(origins)) - } - if origins[0] != "bin1" { - t.Errorf("unexpected origin at element 0: got %s, want \"bin1\"", origins[0]) - } - if origins[1] != "bin2" { - t.Errorf("unexpected origin at element 0: got %s, want \"bin2\"", origins[0]) - } -} + t.Logf("checking resolution set %s", rsShare.String()) -func TestResolutionSet_AttachedToTarget(t *testing.T) { - lg := newLicenseGraph() + actual := rsShare.AttachesTo().Names() + sort.Strings(actual) - rsShare := toResolutionSet(lg, share) + expected := []string{"bin1", "bin2", "image"} - if rsShare.AttachesToTarget(newTestNode(lg, "binc")) { - t.Errorf("unexpected AttachedToTarget(\"binc\"): got true, want false") - } - if !rsShare.AttachesToTarget(newTestNode(lg, "image")) { - t.Errorf("unexpected AttachedToTarget(\"image\"): got false want true") - } -} + t.Logf("actual rsShare: %v", actual) + t.Logf("expected rsShare: %v", expected) -func TestResolutionSet_AnyByNameAttachToTarget(t *testing.T) { - lg := newLicenseGraph() + if len(actual) != len(expected) { + t.Errorf("rsShare: wrong number of targets: got %d, want %d", len(actual), len(expected)) + return + } + for i := 0; i < len(actual); i++ { + if actual[i] != expected[i] { + t.Errorf("rsShare: unexpected target at index %d: got %s, want %s", i, actual[i], expected[i]) + } + } - rs := toResolutionSet(lg, bottomUp) + rsPrivate := toResolutionSet(lg, proprietary) + actual = rsPrivate.AttachesTo().Names() + expected = []string{} - pandp := ConditionNames{"permissive", "proprietary"} - pandn := ConditionNames{"permissive", "notice"} - p := ConditionNames{"proprietary"} - r := ConditionNames{"restricted"} + t.Logf("actual rsPrivate: %v", actual) + t.Logf("expected rsPrivate: %v", expected) - if rs.AnyByNameAttachToTarget(newTestNode(lg, "image"), pandp, p) { - t.Errorf("unexpected AnyByNameAttachToTarget(\"image\", \"proprietary\", \"permissive\"): want false, got true") + if len(actual) != len(expected) { + t.Errorf("rsPrivate: wrong number of targets: got %d, want %d", len(actual), len(expected)) + return } - if !rs.AnyByNameAttachToTarget(newTestNode(lg, "binc"), p) { - t.Errorf("unexpected AnyByNameAttachToTarget(\"binc\", \"proprietary\"): want true, got false") - } - if !rs.AnyByNameAttachToTarget(newTestNode(lg, "image"), pandn) { - t.Errorf("unexpected AnyByNameAttachToTarget(\"image\", \"permissive\", \"notice\"): want true, got false") - } - if !rs.AnyByNameAttachToTarget(newTestNode(lg, "image"), r, pandn) { - t.Errorf("unexpected AnyByNameAttachToTarget(\"image\", \"restricted\", \"notice\"): want true, got false") - } - if !rs.AnyByNameAttachToTarget(newTestNode(lg, "image"), r, p) { - t.Errorf("unexpected AnyByNameAttachToTarget(\"image\", \"restricted\", \"proprietary\"): want true, got false") - } -} - -func TestResolutionSet_AllByNameAttachToTarget(t *testing.T) { - lg := newLicenseGraph() - - rs := toResolutionSet(lg, bottomUp) - - pandp := ConditionNames{"permissive", "proprietary"} - pandn := ConditionNames{"permissive", "notice"} - p := ConditionNames{"proprietary"} - r := ConditionNames{"restricted"} - - if rs.AllByNameAttachToTarget(newTestNode(lg, "image"), pandp, p) { - t.Errorf("unexpected AllByNameAttachToTarget(\"image\", \"proprietary\", \"permissive\"): want false, got true") - } - if !rs.AllByNameAttachToTarget(newTestNode(lg, "binc"), p) { - t.Errorf("unexpected AllByNameAttachToTarget(\"binc\", \"proprietary\"): want true, got false") - } - if !rs.AllByNameAttachToTarget(newTestNode(lg, "image"), pandn) { - t.Errorf("unexpected AllByNameAttachToTarget(\"image\", \"notice\"): want true, got false") - } - if !rs.AllByNameAttachToTarget(newTestNode(lg, "image"), r, pandn) { - t.Errorf("unexpected AllByNameAttachToTarget(\"image\", \"restricted\", \"notice\"): want true, got false") - } - if rs.AllByNameAttachToTarget(newTestNode(lg, "image"), r, p) { - t.Errorf("unexpected AllByNameAttachToTarget(\"image\", \"restricted\", \"proprietary\"): want false, got true") + for i := 0; i < len(actual); i++ { + if actual[i] != expected[i] { + t.Errorf("rsPrivate: unexpected target at index %d: got %s, want %s", i, actual[i], expected[i]) + } } } @@ -192,10 +125,12 @@ func TestResolutionSet_AttachesToTarget(t *testing.T) { rsShare := toResolutionSet(lg, share) + t.Logf("checking resolution set %s", rsShare.String()) + if rsShare.AttachesToTarget(newTestNode(lg, "binc")) { - t.Errorf("unexpected hasTarget(\"binc\"): got true, want false") + t.Errorf("actual.AttachesToTarget(\"binc\"): got true, want false") } if !rsShare.AttachesToTarget(newTestNode(lg, "image")) { - t.Errorf("unexpected AttachesToTarget(\"image\"): got false want true") + t.Errorf("actual.AttachesToTarget(\"image\"): got false want true") } } diff --git a/tools/compliance/test_util.go b/tools/compliance/test_util.go index a183b9014f..8f4088ab7f 100644 --- a/tools/compliance/test_util.go +++ b/tools/compliance/test_util.go @@ -86,7 +86,6 @@ license_conditions: "proprietary" license_kinds: "legacy_by_exception_only" license_conditions: "by_exception_only" ` - ) var ( @@ -111,23 +110,39 @@ var ( } ) -// toConditionList converts a test data map of condition name to origin names into a ConditionList. -func toConditionList(lg *LicenseGraph, conditions map[string][]string) ConditionList { - cl := make(ConditionList, 0) - for name, origins := range conditions { - for _, origin := range origins { - cl = append(cl, LicenseCondition{name, newTestNode(lg, origin)}) - } - } - return cl -} - // newTestNode constructs a test node in the license graph. func newTestNode(lg *LicenseGraph, targetName string) *TargetNode { - if _, ok := lg.targets[targetName]; !ok { - lg.targets[targetName] = &TargetNode{name: targetName} + if tn, alreadyExists := lg.targets[targetName]; alreadyExists { + return tn } - return lg.targets[targetName] + tn := &TargetNode{name: targetName} + lg.targets[targetName] = tn + return tn +} + +// newTestCondition constructs a test license condition in the license graph. +func newTestCondition(lg *LicenseGraph, targetName string, conditionName string) LicenseCondition { + tn := newTestNode(lg, targetName) + cl := LicenseConditionSetFromNames(tn, conditionName).AsList() + if len(cl) == 0 { + panic(fmt.Errorf("attempt to create unrecognized condition: %q", conditionName)) + } else if len(cl) != 1 { + panic(fmt.Errorf("unexpected multiple conditions from condition name: %q: got %d, want 1", conditionName, len(cl))) + } + lc := cl[0] + tn.licenseConditions = tn.licenseConditions.Plus(lc) + return lc +} + +// newTestConditionSet constructs a test license condition set in the license graph. +func newTestConditionSet(lg *LicenseGraph, targetName string, conditionName []string) LicenseConditionSet { + tn := newTestNode(lg, targetName) + cs := LicenseConditionSetFromNames(tn, conditionName...) + if cs.IsEmpty() { + panic(fmt.Errorf("attempt to create unrecognized condition: %q", conditionName)) + } + tn.licenseConditions = tn.licenseConditions.Union(cs) + return cs } // testFS implements a test file system (fs.FS) simulated by a map from filename to []byte content. @@ -270,6 +285,21 @@ func toGraph(stderr io.Writer, roots []string, edges []annotated) (*LicenseGraph return ReadLicenseGraph(&fs, stderr, roots) } +// logGraph outputs a representation of the graph to a test log. +func logGraph(lg *LicenseGraph, t *testing.T) { + t.Logf("license graph:") + t.Logf(" targets:") + for _, target := range lg.Targets() { + t.Logf(" %s%s in package %q", target.Name(), target.LicenseConditions().String(), target.PackageName()) + } + t.Logf(" /targets") + t.Logf(" edges:") + for _, edge := range lg.Edges() { + t.Logf(" %s", edge.String()) + } + t.Logf(" /edges") + t.Logf("/license graph") +} // byAnnotatedEdge orders edges by target then dep name then annotations. type byAnnotatedEdge []annotated @@ -296,33 +326,137 @@ func (l byAnnotatedEdge) Less(i, j int) bool { return l[i].target < l[j].target } +// act describes test data resolution actions to define test action sets. +type act struct { + actsOn, origin, condition string +} + +// String returns a human-readable string representing the test action. +func (a act) String() string { + return fmt.Sprintf("%s{%s:%s}", a.actsOn, a.origin, a.condition) +} + +// toActionSet converts a list of act test data into a test action set. +func toActionSet(lg *LicenseGraph, data []act) ActionSet { + as := make(ActionSet) + for _, a := range data { + actsOn := newTestNode(lg, a.actsOn) + cs := newTestConditionSet(lg, a.origin, strings.Split(a.condition, "|")) + as[actsOn] = cs + } + return as +} + // res describes test data resolutions to define test resolution sets. type res struct { attachesTo, actsOn, origin, condition string } // toResolutionSet converts a list of res test data into a test resolution set. -func toResolutionSet(lg *LicenseGraph, data []res) *ResolutionSet { - rmap := make(map[*TargetNode]actionSet) +func toResolutionSet(lg *LicenseGraph, data []res) ResolutionSet { + rmap := make(ResolutionSet) for _, r := range data { attachesTo := newTestNode(lg, r.attachesTo) actsOn := newTestNode(lg, r.actsOn) - origin := newTestNode(lg, r.origin) if _, ok := rmap[attachesTo]; !ok { - rmap[attachesTo] = make(actionSet) + rmap[attachesTo] = make(ActionSet) } - if _, ok := rmap[attachesTo][actsOn]; !ok { - rmap[attachesTo][actsOn] = newLicenseConditionSet() - } - rmap[attachesTo][actsOn].add(origin, r.condition) + cs := newTestConditionSet(lg, r.origin, strings.Split(r.condition, ":")) + rmap[attachesTo][actsOn] |= cs } - return &ResolutionSet{rmap} + return rmap } +// tcond associates a target name with '|' separated string conditions. +type tcond struct { + target, conditions string +} + +// action represents a single element of an ActionSet for testing. +type action struct { + target *TargetNode + cs LicenseConditionSet +} + +// String returns a human-readable string representation of the action. +func (a action) String() string { + return fmt.Sprintf("%s%s", a.target.Name(), a.cs.String()) +} + +// actionList represents an array of actions and a total order defined by +// target name followed by license condition set. +type actionList []action + +// String returns a human-readable string representation of the list. +func (l actionList) String() string { + var sb strings.Builder + fmt.Fprintf(&sb, "[") + sep := "" + for _, a := range l { + fmt.Fprintf(&sb, "%s%s", sep, a.String()) + sep = ", " + } + fmt.Fprintf(&sb, "]") + return sb.String() +} + +// Len returns the count of elements in the slice. +func (l actionList) Len() int { return len(l) } + +// Swap rearranges 2 elements of the slice so that each occupies the other's +// former position. +func (l actionList) Swap(i, j int) { l[i], l[j] = l[j], l[i] } + +// Less returns true when the `i`th element is lexicographically less than +// the `j`th element. +func (l actionList) Less(i, j int) bool { + if l[i].target == l[j].target { + return l[i].cs < l[j].cs + } + return l[i].target.Name() < l[j].target.Name() +} + +// asActionList represents the resolved license conditions in a license graph +// as an actionList for comparison in a test. +func asActionList(lg *LicenseGraph) actionList { + result := make(actionList, 0, len(lg.targets)) + for _, target := range lg.targets { + cs := target.resolution + if cs.IsEmpty() { + continue + } + result = append(result, action{target, cs}) + } + return result +} + +// toActionList converts an array of tcond into an actionList for comparison +// in a test. +func toActionList(lg *LicenseGraph, actions []tcond) actionList { + result := make(actionList, 0, len(actions)) + for _, actn := range actions { + target := newTestNode(lg, actn.target) + cs := NewLicenseConditionSet() + for _, name := range strings.Split(actn.conditions, "|") { + lc, ok := RecognizedConditionNames[name] + if !ok { + panic(fmt.Errorf("Unrecognized test condition name: %q", name)) + } + cs = cs.Plus(lc) + } + result = append(result, action{target, cs}) + } + return result +} + +// confl defines test data for a SourceSharePrivacyConflict as a target name, +// source condition name, privacy condition name triple. type confl struct { sourceNode, share, privacy string } +// toConflictList converts confl test data into an array of +// SourceSharePrivacyConflict for comparison in a test. func toConflictList(lg *LicenseGraph, data []confl) []SourceSharePrivacyConflict { result := make([]SourceSharePrivacyConflict, 0, len(data)) for _, c := range data { @@ -334,30 +468,40 @@ func toConflictList(lg *LicenseGraph, data []confl) []SourceSharePrivacyConflict cprivacy := fields[1] result = append(result, SourceSharePrivacyConflict{ newTestNode(lg, c.sourceNode), - LicenseCondition{cshare, newTestNode(lg, oshare)}, - LicenseCondition{cprivacy, newTestNode(lg, oprivacy)}, + newTestCondition(lg, oshare, cshare), + newTestCondition(lg, oprivacy, cprivacy), }) } return result } // checkSameActions compares an actual action set to an expected action set for a test. -func checkSameActions(lg *LicenseGraph, asActual, asExpected actionSet, t *testing.T) { - rsActual := ResolutionSet{make(map[*TargetNode]actionSet)} - rsExpected := ResolutionSet{make(map[*TargetNode]actionSet)} +func checkSameActions(lg *LicenseGraph, asActual, asExpected ActionSet, t *testing.T) { + rsActual := make(ResolutionSet) + rsExpected := make(ResolutionSet) testNode := newTestNode(lg, "test") - rsActual.resolutions[testNode] = asActual - rsExpected.resolutions[testNode] = asExpected - checkSame(&rsActual, &rsExpected, t) + rsActual[testNode] = asActual + rsExpected[testNode] = asExpected + checkSame(rsActual, rsExpected, t) } // checkSame compares an actual resolution set to an expected resolution set for a test. -func checkSame(rsActual, rsExpected *ResolutionSet, t *testing.T) { +func checkSame(rsActual, rsExpected ResolutionSet, t *testing.T) { + t.Logf("actual resolution set: %s", rsActual.String()) + t.Logf("expected resolution set: %s", rsExpected.String()) + + actualTargets := rsActual.AttachesTo() + sort.Sort(actualTargets) + expectedTargets := rsExpected.AttachesTo() sort.Sort(expectedTargets) + + t.Logf("actual targets: %s", actualTargets.String()) + t.Logf("expected targets: %s", expectedTargets.String()) + for _, target := range expectedTargets { if !rsActual.AttachesToTarget(target) { - t.Errorf("unexpected missing target: got AttachesToTarget(%q) is false in %s, want true in %s", target.name, rsActual, rsExpected) + t.Errorf("unexpected missing target: got AttachesToTarget(%q) is false, want true", target.name) continue } expectedRl := rsExpected.Resolutions(target) @@ -365,8 +509,8 @@ func checkSame(rsActual, rsExpected *ResolutionSet, t *testing.T) { actualRl := rsActual.Resolutions(target) sort.Sort(actualRl) if len(expectedRl) != len(actualRl) { - t.Errorf("unexpected number of resolutions attach to %q: got %s with %d elements, want %s with %d elements", - target.name, actualRl, len(actualRl), expectedRl, len(expectedRl)) + t.Errorf("unexpected number of resolutions attach to %q: %d elements, %d elements", + target.name, len(actualRl), len(expectedRl)) continue } for i := 0; i < len(expectedRl); i++ { @@ -375,34 +519,86 @@ func checkSame(rsActual, rsExpected *ResolutionSet, t *testing.T) { target.name, i, actualRl[i].asString(), expectedRl[i].asString()) continue } - expectedConditions := expectedRl[i].Resolves().AsList() - actualConditions := actualRl[i].Resolves().AsList() - sort.Sort(expectedConditions) - sort.Sort(actualConditions) - if len(expectedConditions) != len(actualConditions) { - t.Errorf("unexpected number of conditions apply to %q acting on %q: got %s with %d elements, want %s with %d elements", + expectedConditions := expectedRl[i].Resolves() + actualConditions := actualRl[i].Resolves() + if expectedConditions != actualConditions { + t.Errorf("unexpected conditions apply to %q acting on %q: got %04x with names %s, want %04x with names %s", target.name, expectedRl[i].actsOn.name, - actualConditions, len(actualConditions), - expectedConditions, len(expectedConditions)) + actualConditions, actualConditions.Names(), + expectedConditions, expectedConditions.Names()) continue } - for j := 0; j < len(expectedConditions); j++ { - if expectedConditions[j] != actualConditions[j] { - t.Errorf("unexpected condition attached to %q acting on %q at index %d: got %s at index %d in %s, want %s in %s", - target.name, expectedRl[i].actsOn.name, i, - actualConditions[j].asString(":"), j, actualConditions, - expectedConditions[j].asString(":"), expectedConditions) - } - } } } - actualTargets := rsActual.AttachesTo() - sort.Sort(actualTargets) - for i, target := range actualTargets { + for _, target := range actualTargets { if !rsExpected.AttachesToTarget(target) { - t.Errorf("unexpected target: got %q element %d in AttachesTo() %s with %d elements in %s, want %s with %d elements in %s", - target.name, i, actualTargets, len(actualTargets), rsActual, expectedTargets, len(expectedTargets), rsExpected) + t.Errorf("unexpected extra target: got expected.AttachesTo(%q) is false, want true", target.name) + } + } +} + +// checkResolvesActions compares an actual action set to an expected action set for a test verifying the actual set +// resolves all of the expected conditions. +func checkResolvesActions(lg *LicenseGraph, asActual, asExpected ActionSet, t *testing.T) { + rsActual := make(ResolutionSet) + rsExpected := make(ResolutionSet) + testNode := newTestNode(lg, "test") + rsActual[testNode] = asActual + rsExpected[testNode] = asExpected + checkResolves(rsActual, rsExpected, t) +} + +// checkResolves compares an actual resolution set to an expected resolution set for a test verifying the actual set +// resolves all of the expected conditions. +func checkResolves(rsActual, rsExpected ResolutionSet, t *testing.T) { + t.Logf("actual resolution set: %s", rsActual.String()) + t.Logf("expected resolution set: %s", rsExpected.String()) + + actualTargets := rsActual.AttachesTo() + sort.Sort(actualTargets) + + expectedTargets := rsExpected.AttachesTo() + sort.Sort(expectedTargets) + + t.Logf("actual targets: %s", actualTargets.String()) + t.Logf("expected targets: %s", expectedTargets.String()) + + for _, target := range expectedTargets { + if !rsActual.AttachesToTarget(target) { + t.Errorf("unexpected missing target: got AttachesToTarget(%q) is false, want true", target.name) + continue + } + expectedRl := rsExpected.Resolutions(target) + sort.Sort(expectedRl) + actualRl := rsActual.Resolutions(target) + sort.Sort(actualRl) + if len(expectedRl) != len(actualRl) { + t.Errorf("unexpected number of resolutions attach to %q: %d elements, %d elements", + target.name, len(actualRl), len(expectedRl)) + continue + } + for i := 0; i < len(expectedRl); i++ { + if expectedRl[i].attachesTo.name != actualRl[i].attachesTo.name || expectedRl[i].actsOn.name != actualRl[i].actsOn.name { + t.Errorf("unexpected resolution attaches to %q at index %d: got %s, want %s", + target.name, i, actualRl[i].asString(), expectedRl[i].asString()) + continue + } + expectedConditions := expectedRl[i].Resolves() + actualConditions := actualRl[i].Resolves() + if expectedConditions != (expectedConditions & actualConditions) { + t.Errorf("expected conditions missing from %q acting on %q: got %04x with names %s, want %04x with names %s", + target.name, expectedRl[i].actsOn.name, + actualConditions, actualConditions.Names(), + expectedConditions, expectedConditions.Names()) + continue + } + } + + } + for _, target := range actualTargets { + if !rsExpected.AttachesToTarget(target) { + t.Errorf("unexpected extra target: got expected.AttachesTo(%q) is false, want true", target.name) } } }