github.com/CycloneDX/sbom-utility@v0.16.0/cmd/license_policy_test.go (about) 1 // SPDX-License-Identifier: Apache-2.0 2 /* 3 * Licensed to the Apache Software Foundation (ASF) under one or more 4 * contributor license agreements. See the NOTICE file distributed with 5 * this work for additional information regarding copyright ownership. 6 * The ASF licenses this file to You under the Apache License, Version 2.0 7 * (the "License"); you may not use this file except in compliance with 8 * the License. You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 */ 18 19 package cmd 20 21 import ( 22 "bufio" 23 "bytes" 24 "fmt" 25 "testing" 26 27 "github.com/CycloneDX/sbom-utility/common" 28 "github.com/CycloneDX/sbom-utility/log" 29 "github.com/CycloneDX/sbom-utility/schema" 30 "github.com/CycloneDX/sbom-utility/utils" 31 ) 32 33 const ( 34 // TODO: use the following file to test license expressions with "needs-review" usage policy value 35 TEST_LICENSE_EXPRESSION_USAGE_POLICIES = "test/policy/license-policy-license-expression-test-data.json" 36 ) 37 38 // Alternative license policy files for testing 39 const ( 40 POLICY_FILE_GOOD_BAD_MAYBE = "test/policy/license-policy-license-expression-test-data.json" 41 // TODO: to confirm this conflict is caught as part of "license policy" command 42 // TODO: to confirm this conflict is caught as part of "license list" command (with AND/OR as well) 43 POLICY_FILE_FAMILY_NAME_USAGE_CONFLICT = "test/policy/license-policy-family-name-usage-conflict.json" 44 ) 45 46 // Corresponding license IDs for testing (i.e., within POLICY_FILE_GOOD_BAD_MAYBE) 47 const ( 48 LICENSE_ID_GOOD = "Good" 49 LICENSE_ID_BAD = "Bad" 50 LICENSE_ID_MAYBE = "Maybe" 51 ) 52 53 // ------------------------------------------- 54 // license test helper functions 55 // ------------------------------------------- 56 57 func NewLicensePolicyTestInfoBasic(format string, listLineWrap bool) *LicenseTestInfo { 58 lti := NewLicenseTestInfo("", format, TI_LIST_SUMMARY_FALSE) 59 lti.ListLineWrap = listLineWrap 60 return lti 61 } 62 63 func LoadCustomPolicyFile(policyFile string) (customPolicyConfig *schema.LicensePolicyConfig, err error) { 64 // Do not pass a default file, it should fail if custom policy cannot be loaded 65 if policyFile != "" { 66 customPolicyConfig = new(schema.LicensePolicyConfig) 67 err = customPolicyConfig.LoadHashPolicyConfigurationFile(policyFile, "") 68 if err != nil { 69 getLogger().Warningf("unable to load policy configuration file: %v", err.Error()) 70 return 71 } 72 } 73 return 74 } 75 76 func innerTestLicensePolicyListCustomAndBuffered(testInfo *LicenseTestInfo, whereFilters []common.WhereFilter) (outputBuffer bytes.Buffer, err error) { 77 // Declare an output outputBuffer/outputWriter to use used during tests 78 var outputWriter = bufio.NewWriter(&outputBuffer) 79 // ensure all data is written to buffer before further validation 80 defer outputWriter.Flush() 81 82 // Use the test data to set the BOM input file and output format 83 utils.GlobalFlags.ConfigLicensePolicyFile = testInfo.PolicyFile 84 utils.GlobalFlags.PersistentFlags.InputFile = testInfo.InputFile 85 utils.GlobalFlags.PersistentFlags.OutputFormat = testInfo.OutputFormat 86 utils.GlobalFlags.LicenseFlags.Summary = testInfo.ListSummary 87 88 // TODO: pass GlobalConfig to every Command to allow per-instance changes for tests 89 // !!! IMPORTANT MUST explicitly set the global value for every single test 90 utils.GlobalFlags.LicenseFlags.ListLineWrap = testInfo.ListLineWrap 91 92 // set license policy config. per-test 93 var policyConfig *schema.LicensePolicyConfig = LicensePolicyConfig 94 if testInfo.PolicyFile != "" && testInfo.PolicyFile != DEFAULT_LICENSE_POLICY_CONFIG { 95 policyConfig = new(schema.LicensePolicyConfig) 96 err = policyConfig.LoadHashPolicyConfigurationFile(testInfo.PolicyFile, "") 97 if err != nil { 98 getLogger().Warningf("unable to load policy configuration file: %v", err.Error()) 99 return 100 } 101 } 102 103 // Invoke the actual List command (API) 104 err = ListLicensePolicies(outputWriter, policyConfig, 105 utils.GlobalFlags.PersistentFlags, utils.GlobalFlags.LicenseFlags, 106 whereFilters) 107 108 return 109 } 110 111 func innerTestLicensePolicyList(t *testing.T, testInfo *LicenseTestInfo) (outputBuffer bytes.Buffer, err error) { 112 113 // Parse out --where filters and exit out if error detected 114 whereFilters, err := prepareWhereFilters(t, &testInfo.CommonTestInfo) 115 if err != nil { 116 return 117 } 118 119 // Perform the test with buffered output 120 outputBuffer, err = innerTestLicensePolicyListCustomAndBuffered(testInfo, whereFilters) 121 122 // Run all common tests against "result" values in the CommonTestInfo struct 123 err = innerRunReportResultTests(t, &testInfo.CommonTestInfo, outputBuffer, err) 124 125 return 126 } 127 128 //------------------------------------------------------ 129 // Policy Expression: test 3-state logic combinations 130 // NOTE: uses a custom policy file with min. number 131 // of entries to represent the 3 supported states 132 //------------------------------------------------------ 133 134 // The policy config. has 3 states: { "allow", "deny", "needs-review" }; n=3 135 // which are always paired with a conjunctions; r=2 136 // and for evaluation, we do not care about order. This means we have to 137 // account for 6 combinations with unique results (policy determinations) 138 // 1. schema.POLICY_DENY AND schema.POLICY_ALLOW 139 // 2. schema.POLICY_DENY AND schema.POLICY_NEEDS_REVIEW 140 // 3. schema.POLICY_DENY AND schema.POLICY_DENY 141 // 4. schema.POLICY_NEEDS_REVIEW AND schema.POLICY_ALLOW 142 // 5. schema.POLICY_NEEDS_REVIEW AND schema.POLICY_NEEDS_REVIEW 143 // 6. schema.POLICY_ALLOW AND schema.POLICY_ALLOW 144 func TestLicensePolicyUsageConjunctionsANDCombinations(t *testing.T) { 145 // Set the policy file to the reduced, 3-entry policy file used to test the 3 policy states 146 testPolicyConfig, err := LoadCustomPolicyFile(POLICY_FILE_GOOD_BAD_MAYBE) 147 if err != nil { 148 t.Errorf(err.Error()) 149 } 150 151 // 1. schema.POLICY_DENY AND schema.POLICY_ALLOW 152 EXP := "Bad AND Good" 153 EXPECTED_USAGE_POLICY := schema.POLICY_DENY 154 parsedExpression, err := schema.ParseExpression(testPolicyConfig, EXP) 155 if err != nil { 156 t.Errorf(err.Error()) 157 } 158 resolvedPolicy := parsedExpression.CompoundUsagePolicy 159 if resolvedPolicy != EXPECTED_USAGE_POLICY { 160 t.Errorf("schema.ParseExpression(): \"%s\" returned: `%s`; expected: `%s`", EXP, resolvedPolicy, EXPECTED_USAGE_POLICY) 161 } 162 163 // 2. schema.POLICY_DENY AND schema.POLICY_NEEDS_REVIEW 164 EXP = "Bad AND Maybe" 165 EXPECTED_USAGE_POLICY = schema.POLICY_DENY 166 parsedExpression, err = schema.ParseExpression(testPolicyConfig, EXP) 167 if err != nil { 168 t.Errorf(err.Error()) 169 } 170 resolvedPolicy = parsedExpression.CompoundUsagePolicy 171 if resolvedPolicy != EXPECTED_USAGE_POLICY { 172 t.Errorf("schema.ParseExpression(): \"%s\" returned: `%s`; expected: `%s`", EXP, resolvedPolicy, EXPECTED_USAGE_POLICY) 173 } 174 175 // 3. schema.POLICY_DENY AND schema.POLICY_DENY 176 EXP = "Bad AND Bad" 177 EXPECTED_USAGE_POLICY = schema.POLICY_DENY 178 parsedExpression, err = schema.ParseExpression(testPolicyConfig, EXP) 179 if err != nil { 180 t.Errorf(err.Error()) 181 } 182 resolvedPolicy = parsedExpression.CompoundUsagePolicy 183 if resolvedPolicy != EXPECTED_USAGE_POLICY { 184 t.Errorf("schema.ParseExpression(): \"%s\" returned: `%s`; expected: `%s`", EXP, resolvedPolicy, EXPECTED_USAGE_POLICY) 185 } 186 187 // 4. schema.POLICY_NEEDS_REVIEW AND schema.POLICY_ALLOW 188 EXP = "Maybe AND Good" 189 EXPECTED_USAGE_POLICY = schema.POLICY_NEEDS_REVIEW 190 parsedExpression, err = schema.ParseExpression(testPolicyConfig, EXP) 191 if err != nil { 192 t.Errorf(err.Error()) 193 } 194 resolvedPolicy = parsedExpression.CompoundUsagePolicy 195 if resolvedPolicy != EXPECTED_USAGE_POLICY { 196 t.Errorf("schema.ParseExpression(): \"%s\" returned: `%s`; expected: `%s`", EXP, resolvedPolicy, EXPECTED_USAGE_POLICY) 197 } 198 199 // 5. schema.POLICY_NEEDS_REVIEW AND schema.POLICY_NEEDS_REVIEW 200 EXP = "Maybe AND Maybe" 201 EXPECTED_USAGE_POLICY = schema.POLICY_NEEDS_REVIEW 202 parsedExpression, err = schema.ParseExpression(testPolicyConfig, EXP) 203 if err != nil { 204 t.Errorf(err.Error()) 205 } 206 resolvedPolicy = parsedExpression.CompoundUsagePolicy 207 if resolvedPolicy != EXPECTED_USAGE_POLICY { 208 t.Errorf("schema.ParseExpression(): \"%s\" returned: `%s`; expected: `%s`", EXP, resolvedPolicy, EXPECTED_USAGE_POLICY) 209 } 210 211 // 6. schema.POLICY_ALLOW AND schema.POLICY_ALLOW 212 EXP = "Good AND Good" 213 EXPECTED_USAGE_POLICY = schema.POLICY_ALLOW 214 parsedExpression, err = schema.ParseExpression(testPolicyConfig, EXP) 215 if err != nil { 216 t.Errorf(err.Error()) 217 } 218 resolvedPolicy = parsedExpression.CompoundUsagePolicy 219 if resolvedPolicy != EXPECTED_USAGE_POLICY { 220 t.Errorf("schema.ParseExpression(): \"%s\" returned: `%s`; expected: `%s`", EXP, resolvedPolicy, EXPECTED_USAGE_POLICY) 221 } 222 } 223 224 // The policy config. has 3 states: { "allow", "deny", "needs-review" }; n=3 225 // which are always paired with a conjunctions; r=2 226 // and for evaluation, we do not care about order. This means we have to 227 // account for 6 combinations with unique results (policy determinations) 228 // 1. schema.POLICY_ALLOW OR schema.POLICY_DENY 229 // 2. schema.POLICY_ALLOW OR schema.POLICY_NEEDS_REVIEW 230 // 3. schema.POLICY_ALLOW OR schema.POLICY_ALLOW 231 // 4. schema.POLICY_NEEDS_REVIEW OR schema.POLICY_DENY 232 // 5. schema.POLICY_NEEDS_REVIEW OR schema.POLICY_NEEDS_REVIEW 233 // 6. schema.POLICY_DENY OR schema.POLICY_DENY 234 func TestLicensePolicyUsageConjunctionsORCombinations(t *testing.T) { 235 // Set the policy file to the reduced, 3-entry policy file used to test the 3 policy states 236 testPolicyConfig, err := LoadCustomPolicyFile(POLICY_FILE_GOOD_BAD_MAYBE) 237 if err != nil { 238 t.Errorf(err.Error()) 239 } 240 241 // 1. schema.POLICY_ALLOW OR schema.POLICY_DENY 242 EXP := "Good OR Bad" 243 EXPECTED_USAGE_POLICY := schema.POLICY_ALLOW 244 parsedExpression, err := schema.ParseExpression(testPolicyConfig, EXP) 245 if err != nil { 246 t.Errorf(err.Error()) 247 } 248 resolvedPolicy := parsedExpression.CompoundUsagePolicy 249 if resolvedPolicy != EXPECTED_USAGE_POLICY { 250 t.Errorf("schema.ParseExpression(): \"%s\" returned: `%s`; expected: `%s`", EXP, resolvedPolicy, EXPECTED_USAGE_POLICY) 251 } 252 253 // 2. schema.POLICY_ALLOW OR schema.POLICY_NEEDS_REVIEW 254 EXP = "Good OR Maybe" 255 EXPECTED_USAGE_POLICY = schema.POLICY_ALLOW 256 parsedExpression, err = schema.ParseExpression(testPolicyConfig, EXP) 257 if err != nil { 258 t.Errorf(err.Error()) 259 } 260 resolvedPolicy = parsedExpression.CompoundUsagePolicy 261 if resolvedPolicy != EXPECTED_USAGE_POLICY { 262 t.Errorf("schema.ParseExpression(): \"%s\" returned: `%s`; expected: `%s`", EXP, resolvedPolicy, EXPECTED_USAGE_POLICY) 263 } 264 265 // 3. schema.POLICY_ALLOW OR schema.POLICY_ALLOW 266 EXP = "Good OR Good" 267 EXPECTED_USAGE_POLICY = schema.POLICY_ALLOW 268 parsedExpression, err = schema.ParseExpression(testPolicyConfig, EXP) 269 if err != nil { 270 t.Errorf(err.Error()) 271 } 272 resolvedPolicy = parsedExpression.CompoundUsagePolicy 273 if resolvedPolicy != EXPECTED_USAGE_POLICY { 274 t.Errorf("schema.ParseExpression(): \"%s\" returned: `%s`; expected: `%s`", EXP, resolvedPolicy, EXPECTED_USAGE_POLICY) 275 } 276 277 // 4. schema.POLICY_NEEDS_REVIEW OR schema.POLICY_DENY 278 EXP = "Maybe OR Bad" 279 EXPECTED_USAGE_POLICY = schema.POLICY_NEEDS_REVIEW 280 parsedExpression, err = schema.ParseExpression(testPolicyConfig, EXP) 281 if err != nil { 282 t.Errorf(err.Error()) 283 } 284 resolvedPolicy = parsedExpression.CompoundUsagePolicy 285 if resolvedPolicy != EXPECTED_USAGE_POLICY { 286 t.Errorf("schema.ParseExpression(): \"%s\" returned: `%s`; expected: `%s`", EXP, resolvedPolicy, EXPECTED_USAGE_POLICY) 287 } 288 289 // 5. schema.POLICY_NEEDS_REVIEW OR schema.POLICY_NEEDS_REVIEW 290 EXP = "Maybe OR Maybe" 291 EXPECTED_USAGE_POLICY = schema.POLICY_NEEDS_REVIEW 292 parsedExpression, err = schema.ParseExpression(testPolicyConfig, EXP) 293 if err != nil { 294 t.Errorf(err.Error()) 295 } 296 resolvedPolicy = parsedExpression.CompoundUsagePolicy 297 if resolvedPolicy != EXPECTED_USAGE_POLICY { 298 t.Errorf("schema.ParseExpression(): \"%s\" returned: `%s`; expected: `%s`", EXP, resolvedPolicy, EXPECTED_USAGE_POLICY) 299 } 300 301 // 6. schema.POLICY_DENY OR schema.POLICY_DENY 302 EXP = "Bad OR Bad" 303 EXPECTED_USAGE_POLICY = schema.POLICY_DENY 304 parsedExpression, err = schema.ParseExpression(testPolicyConfig, EXP) 305 if err != nil { 306 t.Errorf(err.Error()) 307 } 308 resolvedPolicy = parsedExpression.CompoundUsagePolicy 309 if resolvedPolicy != EXPECTED_USAGE_POLICY { 310 t.Errorf("schema.ParseExpression(): \"%s\" returned: `%s`; expected: `%s`", EXP, resolvedPolicy, EXPECTED_USAGE_POLICY) 311 } 312 } 313 314 //-------------------------------------------------------------- 315 // Custom policy file tests (i.e., loads non-default policy files) 316 //-------------------------------------------------------------- 317 318 // Use test file "test/policy/license-policy-family-name-usage-conflict.json" 319 // TODO: to confirm this conflict is caught at hash time (not load time) 320 func TestLicensePolicyFamilyUsagePolicyConflict(t *testing.T) { 321 // Load custom policy file that contains a license usage policy conflict 322 _, err := LoadCustomPolicyFile(POLICY_FILE_FAMILY_NAME_USAGE_CONFLICT) 323 324 // Note: the conflict is only encountered on the "hash"; load only loads what policies are defined in the config. 325 if err != nil { 326 t.Errorf(err.Error()) 327 } 328 } 329 330 func TestLicensePolicyCustomListGoodBadMaybe(t *testing.T) { 331 lti := NewLicensePolicyTestInfoBasic(FORMAT_TEXT, true) 332 lti.PolicyFile = POLICY_FILE_GOOD_BAD_MAYBE 333 334 outputBuffer, err := innerTestLicensePolicyList(t, lti) 335 336 if err != nil { 337 t.Errorf(err.Error()) 338 return 339 } 340 341 // test for sep. row 342 TEST_LINE_NUM := 1 343 TEST_VALUES := []string{REPORT_LIST_TITLE_ROW_SEPARATOR} 344 matchFoundLine, matchFound := bufferLineContainsValues(outputBuffer, TEST_LINE_NUM, TEST_VALUES...) 345 if !matchFound { 346 t.Errorf("policy file does not contain expected values: `%v` at line: %v\n", TEST_VALUES, TEST_LINE_NUM) 347 return 348 } else { 349 getLogger().Tracef("policy file contains expected values: `%v` at line: %v\n", TEST_VALUES, matchFoundLine) 350 } 351 352 // Assure "bad" policy has usage "deny" 353 TEST_LINE_NUM = 2 354 TEST_VALUES = []string{LICENSE_ID_BAD, schema.POLICY_DENY} 355 matchFoundLine, matchFound = bufferLineContainsValues(outputBuffer, TEST_LINE_NUM, TEST_VALUES...) 356 if !matchFound { 357 t.Errorf("policy file does not contain expected values: `%v` at line: %v\n", TEST_VALUES, TEST_LINE_NUM) 358 return 359 } else { 360 getLogger().Tracef("policy file contains expected values: `%v` at line: %v\n", TEST_VALUES, matchFoundLine) 361 } 362 363 // Assure "good" policy has usage "allow" 364 TEST_LINE_NUM = 3 365 TEST_VALUES = []string{LICENSE_ID_GOOD, schema.POLICY_ALLOW} 366 matchFoundLine, matchFound = bufferLineContainsValues(outputBuffer, TEST_LINE_NUM, TEST_VALUES...) 367 if !matchFound { 368 t.Errorf("policy file does not contain expected values: `%v` at line: %v\n", TEST_VALUES, TEST_LINE_NUM) 369 return 370 } else { 371 getLogger().Tracef("policy file contains expected values: `%v` at line: %v\n", TEST_VALUES, matchFoundLine) 372 } 373 374 // Assure "maybe" policy has usage "needs-review" 375 TEST_LINE_NUM = 4 376 TEST_VALUES = []string{LICENSE_ID_MAYBE, schema.POLICY_NEEDS_REVIEW} 377 matchFoundLine, matchFound = bufferLineContainsValues(outputBuffer, TEST_LINE_NUM, TEST_VALUES...) 378 if !matchFound { 379 t.Errorf("policy file does not contain expected values: `%v` at line: %v\n", TEST_VALUES, TEST_LINE_NUM) 380 return 381 } else { 382 getLogger().Tracef("policy file contains expected values: `%v` at line: %v\n", TEST_VALUES, matchFoundLine) 383 } 384 } 385 386 //------------------------------------------------------ 387 // Policy Find: by ID tests 388 // - NOTE: uses the default policy file (license.json) 389 //------------------------------------------------------ 390 391 func TestLicensePolicyMatchByIdAllow(t *testing.T) { 392 ID := "Apache-2.0" 393 EXPECTED_POLICY := schema.POLICY_ALLOW 394 395 value, policy, err := LicensePolicyConfig.FindPolicyBySpdxId(ID) 396 if err != nil { 397 t.Error(err) 398 } 399 400 if value != EXPECTED_POLICY { 401 t.Errorf("FindPolicyBySpdxId(): id: %s, returned: %v; expected: %v", ID, value, EXPECTED_POLICY) 402 } else { 403 getLogger().Tracef("FindPolicyBySpdxId(): id: %s (%s), policy: %s\n", ID, policy.Name, value) 404 } 405 } 406 407 func TestLicensePolicyMatchByIdDeny(t *testing.T) { 408 ID := "CC-BY-NC-1.0" 409 EXPECTED_POLICY := schema.POLICY_DENY 410 411 value, policy, err := LicensePolicyConfig.FindPolicyBySpdxId(ID) 412 if err != nil { 413 t.Error(err) 414 } 415 416 if value != EXPECTED_POLICY { 417 t.Errorf("FindPolicyBySpdxId(): id: %s, returned: %v; expected: %v", ID, value, EXPECTED_POLICY) 418 } else { 419 getLogger().Tracef("FindPolicyBySpdxId(): id: %s (%s), policy: %s\n", ID, policy.Name, value) 420 } 421 } 422 423 func TestLicensePolicyMatchByIdFailureEmpty(t *testing.T) { 424 ID := "" 425 EXPECTED_POLICY := schema.POLICY_UNDEFINED 426 427 value, policy, err := LicensePolicyConfig.FindPolicyBySpdxId(ID) 428 if err != nil { 429 t.Error(err) 430 } 431 432 if value != EXPECTED_POLICY { 433 t.Errorf("FindPolicyBySpdxId(): id: %s, returned: %v; expected: %v", ID, value, EXPECTED_POLICY) 434 } else { 435 getLogger().Tracef("FindPolicyBySpdxId(): id: %s (%s), policy: %s\n", ID, policy.Name, value) 436 } 437 } 438 439 func TestLicensePolicyMatchByIdFailureFoo(t *testing.T) { 440 ID := "Foo" 441 EXPECTED_POLICY := schema.POLICY_UNDEFINED 442 443 value, policy, err := LicensePolicyConfig.FindPolicyBySpdxId(ID) 444 if err != nil { 445 t.Error(err) 446 } 447 448 if value != EXPECTED_POLICY { 449 t.Errorf("FindPolicyBySpdxId(): id: %s, returned: %v; expected: %v", ID, value, EXPECTED_POLICY) 450 } else { 451 getLogger().Tracef("FindPolicyBySpdxId(): id: %s (%s), policy: %s\n", ID, policy.Name, value) 452 } 453 } 454 455 //------------------------------------------------------ 456 // Policy Find: by Family Name tests 457 // - NOTE: uses the default policy file (license.json) 458 //------------------------------------------------------ 459 460 func TestLicensePolicyMatchByFamilyNameBadExpression(t *testing.T) { 461 // Assure OR appearance results in UNDEFINED 462 NAME := "CC-BY-NC-1.0 OR Apache-2.0" 463 EXPECTED_POLICY := schema.POLICY_UNDEFINED 464 465 value, policy, err := LicensePolicyConfig.FindPolicyByFamilyName(NAME) 466 if err != nil { 467 t.Error(err) 468 } 469 getLogger().Tracef("policy: %v", policy) 470 471 if value != EXPECTED_POLICY { 472 t.Errorf("FindPolicyByFamilyName(): contains expression: %s, returned: %v; expected: %v", NAME, value, EXPECTED_POLICY) 473 } else { 474 getLogger().Tracef("FindPolicyByFamilyName(): contains expression: %s, policy: %s\n", NAME, value) 475 } 476 477 // Assure AND appearance results in UNDEFINED 478 NAME = "CC-BY-NC-1.0 AND Apache-2.0" 479 value, policy, err = LicensePolicyConfig.FindPolicyByFamilyName(NAME) 480 if err != nil { 481 t.Error(err) 482 } 483 getLogger().Tracef("policy: %v", policy) 484 485 if value != EXPECTED_POLICY { 486 t.Errorf("FindPolicyByFamilyName(): contains expression: %s, returned: %v; expected: %v", NAME, value, EXPECTED_POLICY) 487 } else { 488 getLogger().Tracef("FindPolicyByFamilyName(): contains expression: %s, policy: %s\n", NAME, value) 489 } 490 491 // Assure WITH appearance results in UNDEFINED 492 NAME = "CC-BY-NC-1.0 WITH some-clause" 493 value, policy, err = LicensePolicyConfig.FindPolicyByFamilyName(NAME) 494 if err != nil { 495 t.Error(err) 496 } 497 getLogger().Tracef("policy: %v", policy) 498 499 if value != EXPECTED_POLICY { 500 t.Errorf("FindPolicyByFamilyName(): contains expression: %s, returned: %v; expected: %v", NAME, value, EXPECTED_POLICY) 501 } else { 502 getLogger().Tracef("FindPolicyByFamilyName(): contains expression: %s, policy: %s\n", NAME, value) 503 } 504 } 505 506 //----------------------------------------------------------------------------- 507 // Test --wrap flag 508 // i.e., wraps policy (lines) where multiple URLs, Notes or Annotations are found 509 //----------------------------------------------------------------------------- 510 511 func TestLicensePolicyListWrapFalse(t *testing.T) { 512 lti := NewLicensePolicyTestInfoBasic(FORMAT_TEXT, false) 513 lti.ResultExpectedLineCount = 250 // title and data rows 514 // Verify first data row has expected values 515 // sanity (spot) check row values 516 lti.ResultLineContainsValuesAtLineNum = 2 517 lti.ResultLineContainsValues = []string{"0BSD", schema.POLICY_ALLOW} 518 _, err := innerTestLicensePolicyList(t, lti) 519 if err != nil { 520 t.Error(err) 521 } 522 } 523 524 func TestLicensePolicyListWrapTrue(t *testing.T) { 525 lti := NewLicensePolicyTestInfoBasic(FORMAT_TEXT, true) 526 lti.ResultExpectedLineCount = 377 // title and data rows 527 // sanity (spot) check row values 528 lti.ResultLineContainsValuesAtLineNum = 2 529 lti.ResultLineContainsValues = []string{"0BSD", schema.POLICY_ALLOW} 530 _, err := innerTestLicensePolicyList(t, lti) 531 if err != nil { 532 t.Error(err) 533 } 534 } 535 536 //-------------------------------------------------------------- 537 // --where tests (using custom good|bad|maybe policy file) 538 //-------------------------------------------------------------- 539 540 // Test using custom policy file with just 3 entries: good|bad|maybe 541 func TestLicensePolicyCustomListWhereTestUsagePolicyAllow(t *testing.T) { 542 lti := NewLicensePolicyTestInfoBasic(FORMAT_TEXT, false) 543 lti.PolicyFile = POLICY_FILE_GOOD_BAD_MAYBE 544 lti.WhereClause = "usage-policy=allow" 545 lti.ResultExpectedLineCount = 4 546 _, err := innerTestLicensePolicyList(t, lti) 547 if err != nil { 548 t.Error(err) 549 } 550 } 551 552 // Test using custom policy file with just 3 entries: good|bad|maybe 553 func TestLicensePolicyListCustomWhereTestUsagePolicyDeny(t *testing.T) { 554 lti := NewLicensePolicyTestInfoBasic(FORMAT_TEXT, false) 555 lti.PolicyFile = POLICY_FILE_GOOD_BAD_MAYBE 556 lti.WhereClause = "usage-policy=deny" 557 lti.ResultExpectedLineCount = 4 558 _, err := innerTestLicensePolicyList(t, lti) 559 if err != nil { 560 t.Error(err) 561 } 562 } 563 564 // Test using custom policy file with just 3 entries: good|bad|maybe 565 func TestLicensePolicyListCustomWhereTestUsagePolicyNeedsReview(t *testing.T) { 566 lti := NewLicensePolicyTestInfoBasic(FORMAT_TEXT, false) 567 lti.PolicyFile = POLICY_FILE_GOOD_BAD_MAYBE 568 lti.WhereClause = "usage-policy=needs-review" 569 lti.ResultExpectedLineCount = 4 570 _, err := innerTestLicensePolicyList(t, lti) 571 if err != nil { 572 t.Error(err) 573 } 574 } 575 576 // Test using custom policy file with just 3 entries: good|bad|maybe 577 func TestLicensePolicyListCustomCSVWhereTestUsagePolicyAllow(t *testing.T) { 578 lti := NewLicensePolicyTestInfoBasic(FORMAT_CSV, false) 579 lti.PolicyFile = POLICY_FILE_GOOD_BAD_MAYBE 580 lti.WhereClause = "usage-policy=allow" 581 lti.ResultExpectedLineCount = 3 582 _, err := innerTestLicensePolicyList(t, lti) 583 if err != nil { 584 t.Error(err) 585 } 586 } 587 588 // Test using custom policy file with just 3 entries: good|bad|maybe 589 func TestLicensePolicyListCustomMarkdownWhereTestUsagePolicyAllow(t *testing.T) { 590 lti := NewLicensePolicyTestInfoBasic(FORMAT_MARKDOWN, false) 591 lti.PolicyFile = POLICY_FILE_GOOD_BAD_MAYBE 592 lti.WhereClause = "usage-policy=allow" 593 lti.ResultExpectedLineCount = 4 594 _, err := innerTestLicensePolicyList(t, lti) 595 if err != nil { 596 t.Error(err) 597 } 598 } 599 600 //-------------------------------------------------------------- 601 // --where tests (using default policy file) 602 //-------------------------------------------------------------- 603 604 func TestLicensePolicyListTextWhereId0BSD(t *testing.T) { 605 lti := NewLicensePolicyTestInfoBasic(FORMAT_TEXT, false) 606 lti.WhereClause = "id=0B" 607 lti.ResultLineContainsValuesAtLineNum = 3 608 lti.ResultExpectedLineCount = 4 609 _, err := innerTestLicensePolicyList(t, lti) 610 if err != nil { 611 t.Error(err) 612 } 613 } 614 615 func TestLicensePolicyListWhereUsagePolicyDeny(t *testing.T) { 616 lti := NewLicensePolicyTestInfoBasic(FORMAT_TEXT, false) 617 lti.WhereClause = "usage-policy=deny" 618 lti.ResultExpectedLineCount = 6 619 _, err := innerTestLicensePolicyList(t, lti) 620 if err != nil { 621 t.Error(err) 622 } 623 } 624 625 func TestLicensePolicyListWhereAnnotationNeedsIPApproval(t *testing.T) { 626 lti := NewLicensePolicyTestInfoBasic(FORMAT_TEXT, false) 627 lti.WhereClause = "annotations=NEEDS-IP" 628 lti.ResultExpectedLineCount = 23 629 // sanity (spot) check row values 630 lti.ResultLineContainsValuesAtLineNum = 2 631 lti.ResultLineContainsValues = []string{"BSD-2-Clause", schema.POLICY_NEEDS_REVIEW} 632 _, err := innerTestLicensePolicyList(t, lti) 633 if err != nil { 634 s, _ := log.FormatStruct(lti) 635 fmt.Printf(">>> %s\n", s) 636 } 637 } 638 639 func TestLicensePolicyListWhereAnnotation0BSDNeedsIPApproval(t *testing.T) { 640 lti := NewLicensePolicyTestInfoBasic(FORMAT_TEXT, false) 641 lti.WhereClause = "annotations=NEEDS-IP,id=BSD-4" 642 lti.ResultExpectedLineCount = 7 643 // sanity (spot) check row values 644 lti.ResultLineContainsValuesAtLineNum = 2 645 lti.ResultLineContainsValues = []string{"BSD-4-Clause", schema.POLICY_NEEDS_REVIEW} 646 _, err := innerTestLicensePolicyList(t, lti) 647 if err != nil { 648 s, _ := log.FormatStruct(lti) 649 fmt.Printf(">>> %s\n", s) 650 } 651 } 652 653 func TestLicensePolicyListWhereFamilyApache(t *testing.T) { 654 lti := NewLicensePolicyTestInfoBasic(FORMAT_TEXT, false) 655 lti.WhereClause = "family=Apache" 656 lti.ResultExpectedLineCount = 6 657 // sanity (spot) check row values 658 lti.ResultLineContainsValuesAtLineNum = 2 659 lti.ResultLineContainsValues = []string{"Apache v1.0", schema.POLICY_ALLOW} 660 _, err := innerTestLicensePolicyList(t, lti) 661 if err != nil { 662 t.Error(err) 663 } 664 } 665 666 func TestLicensePolicyListWhereAliases(t *testing.T) { 667 lti := NewLicensePolicyTestInfoBasic(FORMAT_TEXT, false) 668 lti.WhereClause = "aliases=Apache" 669 lti.ResultExpectedLineCount = 4 670 _, err := innerTestLicensePolicyList(t, lti) 671 if err != nil { 672 t.Error(err) 673 } 674 } 675 676 func TestLicensePolicyListWhereDeprecatedTrue(t *testing.T) { 677 lti := NewLicensePolicyTestInfoBasic(FORMAT_TEXT, false) 678 lti.WhereClause = "deprecated=true" 679 lti.ResultExpectedLineCount = 18 // 15 matches + 2 title rows + newline 680 _, err := innerTestLicensePolicyList(t, lti) 681 if err != nil { 682 t.Error(err) 683 } 684 } 685 686 //------------------------------------------------ 687 // Policy Expression: parser & usage policy tests 688 //------------------------------------------------ 689 690 func TestLicensePolicyMatchByExpFailureInvalidRightExp(t *testing.T) { 691 692 EXP := "(Apache-1.0 OR Apache-1.1) AND Foobar" 693 EXPECTED_POLICY := schema.POLICY_UNDEFINED 694 695 expressionTree, err := schema.ParseExpression(LicensePolicyConfig, EXP) 696 697 if err != nil { 698 t.Errorf(err.Error()) 699 } 700 701 getLogger().Tracef("Parsed expression:\n%v", expressionTree) 702 resolvedPolicy := expressionTree.CompoundUsagePolicy 703 704 if resolvedPolicy != EXPECTED_POLICY { 705 t.Errorf("FindPolicyBySpdxId(): expression: %s, returned: %v; expected: %v", EXP, resolvedPolicy, EXPECTED_POLICY) 706 } else { 707 getLogger().Tracef("FindPolicyBySpdxId(): id: %s, policy: %s\n", EXP, resolvedPolicy) 708 } 709 } 710 711 func TestLicensePolicyMatchByExpFailureInvalidLeftExp(t *testing.T) { 712 713 EXP := "Foobar AND ( Apache-1.0 OR Apache-1.1 )" 714 EXPECTED_POLICY := schema.POLICY_UNDEFINED 715 716 expressionTree, err := schema.ParseExpression(LicensePolicyConfig, EXP) 717 718 if err != nil { 719 t.Errorf(err.Error()) 720 } 721 722 getLogger().Tracef("Parsed expression:\n%v", expressionTree) 723 resolvedPolicy := expressionTree.CompoundUsagePolicy 724 725 if resolvedPolicy != EXPECTED_POLICY { 726 t.Errorf("FindPolicyBySpdxId(): expression: %s, returned: %v; expected: %v", EXP, resolvedPolicy, EXPECTED_POLICY) 727 } else { 728 getLogger().Tracef("FindPolicyBySpdxId(): id: %s, policy: %s\n", EXP, resolvedPolicy) 729 } 730 } 731 732 func TestLicensePolicyExpressionBSD3OrMIT(t *testing.T) { 733 734 EXP := "BSD-3-Clause OR MIT" 735 EXPECTED_POLICY := schema.POLICY_ALLOW 736 737 expressionTree, err := schema.ParseExpression(LicensePolicyConfig, EXP) 738 739 if err != nil { 740 t.Errorf(err.Error()) 741 } 742 743 getLogger().Tracef("Parsed expression:\n%v", expressionTree) 744 resolvedPolicy := expressionTree.CompoundUsagePolicy 745 746 if resolvedPolicy != EXPECTED_POLICY { 747 t.Errorf("FindPolicyBySpdxId(): expression: %s, returned: %v; expected: %v", EXP, resolvedPolicy, EXPECTED_POLICY) 748 } else { 749 getLogger().Tracef("FindPolicyBySpdxId(): id: %s, policy: %s\n", EXP, resolvedPolicy) 750 } 751 } 752 753 // NOTE: we need more tests that verify support of multiple conjunctions without 754 // parenthetical groups 755 func TestLicensePolicyExpressionMultipleConjunctions(t *testing.T) { 756 EXP := "BSD-3-Clause OR MIT AND GPL" 757 EXPECTED_POLICY := schema.POLICY_UNDEFINED 758 759 expressionTree, err := schema.ParseExpression(LicensePolicyConfig, EXP) 760 761 if err != nil { 762 t.Errorf(err.Error()) 763 } 764 765 getLogger().Tracef("Parsed expression:\n%v", expressionTree) 766 resolvedPolicy := expressionTree.CompoundUsagePolicy 767 768 if resolvedPolicy != EXPECTED_POLICY { 769 t.Errorf("FindPolicyBySpdxId(): expression: %s, returned: %v; expected: %v", EXP, resolvedPolicy, EXPECTED_POLICY) 770 } else { 771 getLogger().Tracef("FindPolicyBySpdxId(): id: %s, policy: %s\n", EXP, resolvedPolicy) 772 } 773 774 EXP = "BSD-3-Clause OR MIT OR GPL" 775 EXPECTED_POLICY = schema.POLICY_ALLOW 776 777 expressionTree, err = schema.ParseExpression(LicensePolicyConfig, EXP) 778 779 if err != nil { 780 t.Errorf(err.Error()) 781 } 782 783 getLogger().Tracef("Parsed expression:\n%v", expressionTree) 784 resolvedPolicy = expressionTree.CompoundUsagePolicy 785 786 if resolvedPolicy != EXPECTED_POLICY { 787 t.Errorf("FindPolicyBySpdxId(): expression: %s, returned: %v; expected: %v", EXP, resolvedPolicy, EXPECTED_POLICY) 788 } else { 789 getLogger().Tracef("FindPolicyBySpdxId(): id: %s, policy: %s\n", EXP, resolvedPolicy) 790 } 791 }