@@ -25,12 +25,28 @@ import io.kotest.matchers.shouldBe
25
25
26
26
import io.mockk.mockk
27
27
28
+ import kotlin.time.Duration.Companion.seconds
29
+
30
+ import kotlinx.coroutines.DelicateCoroutinesApi
31
+ import kotlinx.coroutines.GlobalScope
32
+ import kotlinx.coroutines.async
33
+
28
34
import org.ossreviewtoolkit.model.Identifier
35
+ import org.ossreviewtoolkit.model.LicenseFinding
29
36
import org.ossreviewtoolkit.model.LicenseSource
37
+ import org.ossreviewtoolkit.model.TextLocation
38
+ import org.ossreviewtoolkit.model.UnknownProvenance
39
+ import org.ossreviewtoolkit.model.config.CopyrightGarbage
40
+ import org.ossreviewtoolkit.model.config.LicenseFilePatterns
41
+ import org.ossreviewtoolkit.model.licenses.LicenseView.Companion.CONCLUDED_OR_DECLARED_AND_DETECTED
42
+ import org.ossreviewtoolkit.utils.ort.ProcessedDeclaredLicense
43
+ import org.ossreviewtoolkit.utils.spdx.SpdxExpression
44
+ import org.ossreviewtoolkit.utils.spdx.SpdxLicense
30
45
import org.ossreviewtoolkit.utils.spdx.SpdxLicenseChoice
31
46
import org.ossreviewtoolkit.utils.spdx.SpdxSingleLicenseExpression
32
47
import org.ossreviewtoolkit.utils.spdx.toSpdx
33
48
49
+ @DelicateCoroutinesApi
34
50
class ResolvedLicenseInfoTest : WordSpec ({
35
51
" effectiveLicense()" should {
36
52
" apply choices for LicenseView.ALL on all resolved licenses" {
@@ -81,7 +97,7 @@ class ResolvedLicenseInfoTest : WordSpec({
81
97
)
82
98
83
99
val effectiveLicense = RESOLVED_LICENSE_INFO .effectiveLicense(
84
- LicenseView . CONCLUDED_OR_DECLARED_AND_DETECTED ,
100
+ CONCLUDED_OR_DECLARED_AND_DETECTED ,
85
101
choices
86
102
)
87
103
@@ -119,6 +135,28 @@ class ResolvedLicenseInfoTest : WordSpec({
119
135
120
136
effectiveLicense shouldBe " $APACHE and ($MIT or $GPL ) and $BSD " .toSpdx()
121
137
}
138
+
139
+ " execute in reasonable time for large license info with several OR operators" .config(
140
+ blockingTest = true,
141
+ timeout = 1.seconds
142
+ ) {
143
+ runCancellable {
144
+ COMPUTATION_HEAVY_RESOLVED_LICENSE_INFO .effectiveLicense(CONCLUDED_OR_DECLARED_AND_DETECTED )
145
+ }
146
+ }
147
+ }
148
+
149
+ " toCompoundExpression()" should {
150
+ " execute in reasonable time for large license info with several OR operators" .config(
151
+ blockingTest = true,
152
+ timeout = 1.seconds
153
+ ) {
154
+ // Run non-cancellable operation in such a way that cancellation does not wait for completion, see also
155
+ // https://github.com/Kotlin/kotlinx.coroutines/issues/1449#issuecomment-522907869.
156
+ runCancellable {
157
+ COMPUTATION_HEAVY_RESOLVED_LICENSE_INFO .toCompoundExpression()
158
+ }
159
+ }
122
160
}
123
161
124
162
" applyChoices(licenseChoices)" should {
@@ -187,3 +225,99 @@ private val RESOLVED_LICENSE_INFO: ResolvedLicenseInfo by lazy {
187
225
unmatchedCopyrights = emptyMap()
188
226
)
189
227
}
228
+
229
+ /* *
230
+ * A (detected) resolved license info found in a real world scan, which makes several class members, for example
231
+ * effectiveLicense(), rather computation-heavy.
232
+ */
233
+ private val COMPUTATION_HEAVY_RESOLVED_LICENSE_INFO : ResolvedLicenseInfo by lazy {
234
+ val licensesWithoutChoice = SpdxLicense .values()
235
+ .toList()
236
+ .subList(0 , 200 )
237
+ .map { SpdxExpression .parse(it.id) }
238
+
239
+ // expressions take from a real world scan with swapped identifiers.
240
+ val licensesWithChoice = listOf (
241
+ " AAL OR Abstyles" ,
242
+ " AdaCore-doc OR Adobe-2006" ,
243
+ " Adobe-Display-PostScript OR Adobe-Glyph" ,
244
+ " Adobe-Display-PostScript OR AAL" ,
245
+ " Adobe-Utopia OR Adobe-2006" ,
246
+ " Adobe-Display-PostScript OR Adobe-2006" ,
247
+ " (Adobe-2006 OR AdaCore-doc) AND ADSL AND AFL-1.1 AND AFL-1.2 AND AFL-2.0 AND AFL-2.1" ,
248
+ " AFL-3.0 OR Afmparse" ,
249
+ " AGPL-1.0 OR Abstyles" ,
250
+ " AFL-3.0 OR AGPL-1.0-only" ,
251
+ " AGPL-1.0-or-later OR AGPL-3.0" ,
252
+ " AAL OR Adobe-Glyph" ,
253
+ " (AGPL-3.0-only OR AAL) AND AAL" ,
254
+ " AGPL-3.0-or-later OR AGPL-1.0-or-later" ,
255
+ " AAL OR AGPL-1.0-or-later" ,
256
+ " AGPL-3.0-only OR Adobe-2006" ,
257
+ " Adobe-Display-PostScript OR Aladdin" ,
258
+ " AMDPLPA OR AFL-3.0" ,
259
+ " AMD-newlib OR AAL" ,
260
+ " AML OR AML OR AML OR AML OR AML OR AML" ,
261
+ " AML-glslang OR AAL" ,
262
+ " AMPAS OR ANTLR-PD" ,
263
+ " AAL OR ANTLR-PD-fallback" ,
264
+ " any-OSI OR AML-glslang" ,
265
+ " Adobe-2006 OR AML-glslang"
266
+ ).map { SpdxExpression .parse(it) }
267
+
268
+ val licenseFindings = (licensesWithoutChoice + licensesWithChoice).mapTo(mutableSetOf ()) { license ->
269
+ LicenseFinding (
270
+ license = license,
271
+ location = TextLocation (
272
+ path = " path" ,
273
+ startLine = 1 ,
274
+ endLine = 2
275
+ )
276
+ )
277
+ }
278
+
279
+ val licenseInfo = LicenseInfo (
280
+ id = Identifier .EMPTY ,
281
+ declaredLicenseInfo = DeclaredLicenseInfo (
282
+ authors = emptySet(),
283
+ licenses = emptySet(),
284
+ appliedCurations = emptyList(),
285
+ processed = ProcessedDeclaredLicense (SpdxExpression .parse(" NONE" ))
286
+ ),
287
+ detectedLicenseInfo = DetectedLicenseInfo (
288
+ findings = listOf (
289
+ Findings (
290
+ provenance = UnknownProvenance ,
291
+ licenses = licenseFindings,
292
+ copyrights = emptySet(),
293
+ licenseFindingCurations = emptyList(),
294
+ pathExcludes = emptyList(),
295
+ relativeFindingsPath = " "
296
+ )
297
+ )
298
+ ),
299
+ concludedLicenseInfo = ConcludedLicenseInfo (
300
+ concludedLicense = null ,
301
+ appliedCurations = emptyList()
302
+ )
303
+ )
304
+
305
+ val resolver = LicenseInfoResolver (
306
+ provider = SimpleLicenseInfoProvider (listOf (licenseInfo)),
307
+ copyrightGarbage = CopyrightGarbage (emptySet()),
308
+ archiver = null ,
309
+ licenseFilePatterns = LicenseFilePatterns .DEFAULT ,
310
+ addAuthorsToCopyrights = false
311
+ )
312
+
313
+ resolver.resolveLicenseInfo(licenseInfo.id)
314
+ }
315
+
316
+ @DelicateCoroutinesApi
317
+ private suspend fun runCancellable (nonCancellableBlock : () -> Unit ) {
318
+ // Run non-cancellable operation in such a way that cancellation does not wait for completion, see also
319
+ // https://github.com/Kotlin/kotlinx.coroutines/issues/1449#issuecomment-522907869.
320
+ GlobalScope .async {
321
+ nonCancellableBlock()
322
+ }.await()
323
+ }
0 commit comments