diff --git a/CHANGELOG.md b/CHANGELOG.md index d75d27e08..781addae6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ - Fixed small ambiguity in the order of license match evaluation. - Resolve `analysis_options.yaml` dev dependency to expose transitive formatter options. - Fixed license coverage calculation. +- Fixed license match post-filtering. ## 0.22.23 diff --git a/lib/src/license_detection/license_detector.dart b/lib/src/license_detection/license_detector.dart index 8925e84fe..cc6897a25 100644 --- a/lib/src/license_detection/license_detector.dart +++ b/lib/src/license_detection/license_detector.dart @@ -268,25 +268,33 @@ double calculateUnclaimedTokenPercentage( /// Returns the number of tokens in the longest unclaimed token /// sequence. int findLongestUnclaimedTokenRange(List matches, int end) { - var ranges = []; if (matches.isEmpty) return end; - for (var match in matches) { - ranges.add(Range(match.tokenRange.start, match.tokenRange.end)); - } - - ranges.sort(sortRangeOnStartValue); - var maxTokenSequence = ranges.first.start - 0; + var maxUnclaimed = 0; + + // create an end-of-range marker at the end of ranges for easier computation + final ranges = [...matches.map((m) => m.tokenRange), Range(end, end)]; + + // move position from the start up to the end, checking uncovered ranges + for (var pos = 0; pos < end;) { + // check if inside a range + final skipToEnd = ranges + .where((r) => r.containsIndex(pos)) + .map((r) => r.end) + .fold(-1, max); + if (skipToEnd > -1) { + assert(pos < skipToEnd); + pos = skipToEnd; + continue; + } - for (var i = 1; i < ranges.length; i++) { - maxTokenSequence = max( - ranges[i].start - ranges[i - 1].end, - maxTokenSequence, - ); + // jump to next range + final nextRange = ranges + .where((r) => r.start > pos) + .reduce((a, b) => a.start.compareTo(b.start) <= 0 ? a : b); + maxUnclaimed = max(maxUnclaimed, nextRange.start - pos); + pos = nextRange.end; } - maxTokenSequence = max(maxTokenSequence, end - ranges.last.end); - return maxTokenSequence; + return maxUnclaimed; } - -int sortRangeOnStartValue(Range a, Range b) => a.start - b.start; diff --git a/lib/src/license_detection/token_matcher.dart b/lib/src/license_detection/token_matcher.dart index 0b8dd8822..d5fd5907b 100644 --- a/lib/src/license_detection/token_matcher.dart +++ b/lib/src/license_detection/token_matcher.dart @@ -54,6 +54,8 @@ class Range { (end >= other.start && end <= other.end); } + bool containsIndex(int value) => start <= value && value < end; + @override String toString() => 'Range($start-$end)'; } diff --git a/test/license_detector_test.dart b/test/license_detector_test.dart index d582ac972..29f29077d 100644 --- a/test/license_detector_test.dart +++ b/test/license_detector_test.dart @@ -258,6 +258,16 @@ void main() { 160, 1000, ); + + _testLongestUnclaimedTokenRange( + 'Trailing contained range', + [ + _dummyLicenseMatchInstance(0.9, '', start: 30, end: 940), + _dummyLicenseMatchInstance(0.9, '', start: 50, end: 70), + ], + 60, + 1000, + ); }); } diff --git a/test/licenses/license_coverage_test.dart b/test/licenses/license_coverage_test.dart index fdd9507fe..339056df0 100644 --- a/test/licenses/license_coverage_test.dart +++ b/test/licenses/license_coverage_test.dart @@ -16,10 +16,6 @@ void main() { license.content, relativePath: 'LICENSE', ); - // TODO: fix detection and return at least one match (https://github.com/dart-lang/pana/issues/1484) - if (license.identifier == 'SSH-OpenSSH') { - continue; - } final match = detected .where((l) => l.spdxIdentifier == license.identifier) .single;