• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (C) 2024 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 use spdx::LicenseReq;
16 use std::collections::BTreeSet;
17 
18 use crate::Error;
19 
20 /// The result of parsing and evaluating an SPDX license expression.
21 #[derive(Debug, PartialEq)]
22 pub(crate) struct LicenseTerms {
23     /// The license terms we are required to follow.
24     pub required: BTreeSet<LicenseReq>,
25     /// Additional terms mentioned in the license expression that we
26     /// do not need to follow.
27     pub not_required: BTreeSet<LicenseReq>,
28 }
29 
30 impl LicenseTerms {
try_from( expr: spdx::Expression, preferences: &Vec<spdx::Licensee>, ) -> Result<LicenseTerms, Error>31     pub fn try_from(
32         expr: spdx::Expression,
33         preferences: &Vec<spdx::Licensee>,
34     ) -> Result<LicenseTerms, Error> {
35         let required = BTreeSet::from_iter(expr.minimized_requirements(preferences)?);
36         let not_required = expr
37             .requirements()
38             .filter_map(
39                 |req| if !required.contains(&req.req) { Some(req.req.clone()) } else { None },
40             )
41             .collect::<BTreeSet<_>>();
42         Ok(LicenseTerms { required, not_required })
43     }
44 }
45 
46 #[cfg(test)]
47 mod tests {
48     use spdx::Licensee;
49 
50     use super::*;
51 
52     #[test]
try_from()53     fn try_from() {
54         assert_eq!(
55             LicenseTerms::try_from(
56                 spdx::Expression::parse("Apache-2.0").unwrap(),
57                 &vec![spdx::Licensee::parse("Apache-2.0").unwrap()]
58             )
59             .unwrap(),
60             LicenseTerms {
61                 required: BTreeSet::from([Licensee::parse("Apache-2.0").unwrap().into_req()]),
62                 not_required: BTreeSet::new()
63             },
64             "Simple case"
65         );
66         assert_eq!(
67             LicenseTerms::try_from(
68                 spdx::Expression::parse("Apache-2.0 OR MIT").unwrap(),
69                 &vec![spdx::Licensee::parse("Apache-2.0").unwrap()]
70             )
71             .unwrap(),
72             LicenseTerms {
73                 required: BTreeSet::from([Licensee::parse("Apache-2.0").unwrap().into_req()]),
74                 not_required: BTreeSet::from([Licensee::parse("MIT").unwrap().into_req()])
75             },
76             "Preference"
77         );
78         assert!(
79             matches!(
80                 LicenseTerms::try_from(
81                     spdx::Expression::parse("Apache-2.0").unwrap(),
82                     &vec![spdx::Licensee::parse("MIT").unwrap()]
83                 ),
84                 Err(Error::MinimizeError(_))
85             ),
86             "No acceptable licenses"
87         );
88         assert_eq!(
89             LicenseTerms::try_from(
90                 spdx::Expression::parse("Apache-2.0 AND MIT").unwrap(),
91                 &vec![
92                     spdx::Licensee::parse("Apache-2.0").unwrap(),
93                     spdx::Licensee::parse("MIT").unwrap()
94                 ]
95             )
96             .unwrap(),
97             LicenseTerms {
98                 required: BTreeSet::from([
99                     Licensee::parse("Apache-2.0").unwrap().into_req(),
100                     Licensee::parse("MIT").unwrap().into_req()
101                 ]),
102                 not_required: BTreeSet::new(),
103             },
104             "AND"
105         );
106         assert_eq!(
107             LicenseTerms::try_from(
108                 spdx::Expression::parse("MIT AND (MIT OR Apache-2.0)").unwrap(),
109                 &vec![
110                     spdx::Licensee::parse("Apache-2.0").unwrap(),
111                     spdx::Licensee::parse("MIT").unwrap()
112                 ]
113             )
114             .unwrap(),
115             LicenseTerms {
116                 required: BTreeSet::from([Licensee::parse("MIT").unwrap().into_req()]),
117                 not_required: BTreeSet::from([Licensee::parse("Apache-2.0").unwrap().into_req(),]),
118             },
119             "Complex expression from libm 0.2.11"
120         );
121     }
122 }
123