xref: /aosp_15_r20/external/spdx-tools/rdfloader/parser2v3/parse_license_test.go (revision ba677afa8f67bb56cbc794f4d0e378e0da058e16)
1// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
2
3package parser2v3
4
5import (
6	"reflect"
7	"sort"
8	"testing"
9
10	gordfParser "github.com/spdx/gordf/rdfloader/parser"
11)
12
13func Test_rdfParser2_3_getAnyLicenseFromNode(t *testing.T) {
14	// since this function is a mux, we just have to make sure that with each
15	// type of input, it is able to redirect the request to an appropriate
16	// license getter.
17
18	// TestCase 1: input node is just a node string without any associated
19	//			   triple (either a NONE|NOASSERTION) because for other case,
20	//			   the license should've been associated with other triples
21	parser, _ := parserFromBodyContent(``)
22	inputNode := &gordfParser.Node{
23		NodeType: gordfParser.IRI,
24		ID:       NS_SPDX + "NONE",
25	}
26	lic, err := parser.getAnyLicenseFromNode(inputNode)
27	if err != nil {
28		t.Errorf("error parsing a valid license input: %v", err)
29	}
30	// checking if the return type is a SpecialLicense
31	switch lic.(type) {
32	case SpecialLicense:
33	default:
34		t.Errorf("expected license to be of type SpecialLicense, found %v", reflect.TypeOf(lic))
35	}
36
37	// TestCase 2: DisjunctiveLicenseSet:
38	parser, _ = parserFromBodyContent(`
39		<spdx:DisjunctiveLicenseSet>
40			<spdx:member rdf:resource="http://spdx.org/licenses/Nokia"/>
41			<spdx:member rdf:resource="http://spdx.org/licenses/LGPL-2.0"/>
42		</spdx:DisjunctiveLicenseSet>
43	`)
44	inputNode = parser.gordfParserObj.Triples[0].Subject
45	lic, err = parser.getAnyLicenseFromNode(inputNode)
46	if err != nil {
47		t.Errorf("error parsing a valid license input: %v", err)
48	}
49	// checking if the return type is a DisjunctiveLicenseSet
50	switch lic.(type) {
51	case DisjunctiveLicenseSet:
52	default:
53		t.Errorf("expected license to be of type DisjunctiveLicenseSet, found %v", reflect.TypeOf(lic))
54	}
55
56	// TestCase 3: ConjunctiveLicenseSet:
57	parser, _ = parserFromBodyContent(`
58		<spdx:ConjunctiveLicenseSet>
59			<spdx:member rdf:resource="http://spdx.org/licenses/Nokia"/>
60			<spdx:member rdf:resource="http://spdx.org/licenses/LGPL-2.0"/>
61		</spdx:ConjunctiveLicenseSet>
62	`)
63	inputNode = parser.gordfParserObj.Triples[0].Subject
64	lic, err = parser.getAnyLicenseFromNode(inputNode)
65	if err != nil {
66		t.Errorf("error parsing a valid license input: %v", err)
67	}
68	// checking if the return type is a ConjunctiveLicenseSet
69	switch lic.(type) {
70	case ConjunctiveLicenseSet:
71	default:
72		t.Errorf("expected license to be of type ConjunctiveLicenseSet, found %v", reflect.TypeOf(lic))
73	}
74
75	// TestCase 4: ExtractedLicensingInfo
76	parser, _ = parserFromBodyContent(`
77		<spdx:ExtractedLicensingInfo rdf:about="http://spdx.dev/spdx.rdf#LicenseRef-Freeware">
78			<spdx:licenseId>LicenseRef-Freeware</spdx:licenseId>
79			<spdx:name>freeware</spdx:name>
80			<spdx:extractedText><![CDATA[...]]></spdx:extractedText>
81	  	</spdx:ExtractedLicensingInfo>
82	`)
83	inputNode = parser.gordfParserObj.Triples[0].Subject
84	lic, err = parser.getAnyLicenseFromNode(inputNode)
85	if err != nil {
86		t.Errorf("error parsing a valid license input: %v", err)
87	}
88	// checking if the return type is a ExtractedLicensingInfo
89	switch lic.(type) {
90	case ExtractedLicensingInfo:
91	default:
92		t.Errorf("expected license to be of type ExtractedLicensingInfo, found %v", reflect.TypeOf(lic))
93	}
94
95	// TestCase 4: ExtractedLicensingInfo
96	parser, _ = parserFromBodyContent(`
97		<spdx:ExtractedLicensingInfo rdf:about="http://spdx.dev/spdx.rdf#LicenseRef-Freeware">
98			<spdx:licenseId>LicenseRef-Freeware</spdx:licenseId>
99			<spdx:name>freeware</spdx:name>
100			<spdx:extractedText><![CDATA[...]]></spdx:extractedText>
101	  	</spdx:ExtractedLicensingInfo>
102	`)
103	inputNode = parser.gordfParserObj.Triples[0].Subject
104	lic, err = parser.getAnyLicenseFromNode(inputNode)
105	if err != nil {
106		t.Errorf("error parsing a valid license input: %v", err)
107	}
108	// checking if the return type is a ExtractedLicensingInfo
109	switch lic.(type) {
110	case ExtractedLicensingInfo:
111	default:
112		t.Errorf("expected license to be of type ExtractedLicensingInfo, found %v", reflect.TypeOf(lic))
113	}
114
115	// TestCase 5: License
116	parser, _ = parserFromBodyContent(`
117		<spdx:License rdf:about="http://spdx.org/licenses/Apache-2.0">
118			<spdx:standardLicenseTemplate>&lt;&gt; Apache License Version 2.0, January 2004 http://www.apache.org/licenses/&lt;&gt;&lt;&gt; TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION&lt;&gt; &lt;&gt; Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. &lt;&gt; Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. &lt;&gt; Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. &lt;&gt; Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: &lt;&gt; You must give any other recipients of the Work or Derivative Works a copy of this License; and &lt;&gt; You must cause any modified files to carry prominent notices stating that You changed the files; and &lt;&gt; You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and &lt;&gt; If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. &lt;&gt; Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. &lt;&gt; Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. &lt;&gt; Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. &lt;&gt; Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. &lt;&gt; Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability.&lt;&gt; END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright &lt;&gt; 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.&lt;&gt;</spdx:standardLicenseTemplate>
119			<rdfs:seeAlso>http://www.apache.org/licenses/LICENSE-2.0</rdfs:seeAlso>
120			<spdx:name>Apache License 2.0</spdx:name>
121			<spdx:licenseId>Apache-2.0</spdx:licenseId>
122			<spdx:isOsiApproved>true</spdx:isOsiApproved>
123			<rdfs:seeAlso>http://www.opensource.org/licenses/Apache-2.0</rdfs:seeAlso>
124			<spdx:licenseText>...</spdx:licenseText>
125			<spdx:standardLicenseHeader>...</spdx:standardLicenseHeader>
126	  </spdx:License>
127	`)
128	inputNode = parser.gordfParserObj.Triples[0].Subject
129	lic, err = parser.getAnyLicenseFromNode(inputNode)
130	if err != nil {
131		t.Errorf("error parsing a valid license input: %v", err)
132	}
133	// checking if the return type is a License
134	switch lic.(type) {
135	case License:
136	default:
137		t.Errorf("expected license to be of type License, found %v", reflect.TypeOf(lic))
138	}
139
140	// TestCase 5: WithExceptionOperator
141	parser, _ = parserFromBodyContent(`
142		<spdx:WithExceptionOperator>
143			<spdx:licenseException>
144				<spdx:LicenseException rdf:nodeID="A1">
145					<spdx:example></spdx:example>
146					<spdx:licenseExceptionId>Libtool-exception</spdx:licenseExceptionId>
147					<rdfs:comment></rdfs:comment>
148				</spdx:LicenseException>
149			</spdx:licenseException>
150			<spdx:member rdf:resource="http://spdx.org/licenses/GPL-2.0-or-later"/>
151		</spdx:WithExceptionOperator>
152	`)
153	inputNode = parser.gordfParserObj.Triples[0].Subject
154	lic, err = parser.getAnyLicenseFromNode(inputNode)
155	if err != nil {
156		t.Errorf("error parsing a valid license input: %v", err)
157	}
158	// checking if the return type is a WithExceptionOperator
159	switch lic.(type) {
160	case WithExceptionOperator:
161	default:
162		t.Errorf("expected license to be of type WithExceptionOperator, found %v", reflect.TypeOf(lic))
163	}
164
165	// TestCase 6: OrLaterOperator
166	parser, _ = parserFromBodyContent(`
167		<spdx:OrLaterOperator>
168			<spdx:member>
169				<spdx:SimpleLicensingInfo>
170					<spdx:licenseId>LicenseRef-Freeware</spdx:licenseId>
171					<spdx:name>freeware</spdx:name>
172				</spdx:SimpleLicensingInfo>
173			</spdx:member>
174		</spdx:OrLaterOperator>
175	`)
176	inputNode = parser.gordfParserObj.Triples[0].Subject
177	lic, err = parser.getAnyLicenseFromNode(inputNode)
178	if err != nil {
179		t.Errorf("error parsing a valid license input: %v", err)
180	}
181	// checking if the return type is a OrLaterOperator
182	switch lic.(type) {
183	case OrLaterOperator:
184	default:
185		t.Errorf("expected license to be of type OrLaterOperator, found %v", reflect.TypeOf(lic))
186	}
187
188	// TestCase 7: checking if an unknown license raises an error.
189	parser, _ = parserFromBodyContent(`
190		<spdx:UnknownLicense>
191			<spdx:unknownTag />
192		</spdx:UnknownLicense>
193	`)
194	node := parser.gordfParserObj.Triples[0].Subject
195	_, err = parser.getAnyLicenseFromNode(node)
196	t.Log(err)
197	if err == nil {
198		t.Errorf("should've raised an error for invalid input")
199	}
200
201	// TestCase 8: cyclic dependent license must raise an error.
202	parser, _ = parserFromBodyContent(`
203		<spdx:ConjunctiveLicenseSet rdf:about="#SPDXRef-RecursiveLicense">
204			<spdx:member rdf:resource="http://spdx.org/licenses/GPL-2.0-or-later"/>
205			<spdx:member>
206				<spdx:ConjunctiveLicenseSet rdf:about="#SPDXRef-RecursiveLicense">
207					<spdx:member rdf:resource="http://spdx.org/licenses/LGPL-2.0"/>
208					<spdx:member rdf:resource="http://spdx.org/spdxdocs/spdx-example-444504E0-4F89-41D3-9A0C-0305E82C3301#SPDXRef-RecursiveLicense"/>
209				</spdx:ConjunctiveLicenseSet>
210			</spdx:member>
211		</spdx:ConjunctiveLicenseSet>
212	`)
213	node = parser.gordfParserObj.Triples[0].Subject
214	_, err = parser.getAnyLicenseFromNode(node)
215	if err == nil {
216		t.Errorf("expected an error due to cyclic dependent license. found %v", err)
217	}
218}
219
220func Test_rdfParser2_3_getConjunctiveLicenseSetFromNode(t *testing.T) {
221	var parser *rdfParser2_3
222	var err error
223	var licenseNode *gordfParser.Node
224	var license ConjunctiveLicenseSet
225
226	// TestCase 1: invalid license member
227	parser, _ = parserFromBodyContent(`
228		<spdx:ConjunctiveLicenseSet>
229			<spdx:member rdf:resource="http://spdx.org/licenses/Unknown"/>
230			<spdx:member rdf:resource="http://spdx.org/licenses/LGPL-2.0"/>
231		</spdx:ConjunctiveLicenseSet>
232	`)
233	licenseNode = parser.gordfParserObj.Triples[0].Subject
234	_, err = parser.getConjunctiveLicenseSetFromNode(licenseNode)
235	if err == nil {
236		t.Errorf("expected an error saying invalid license member, found <nil>")
237	}
238
239	// TestCase 2: invalid predicate in the licenseSet.
240	parser, _ = parserFromBodyContent(`
241		<spdx:ConjunctiveLicenseSet>
242			<spdx:member rdf:resource="http://spdx.org/licenses/CC0-1.0"/>
243			<spdx:member rdf:resource="http://spdx.org/licenses/LGPL-2.0"/>
244			<spdx:unknownTag />
245		</spdx:ConjunctiveLicenseSet>
246	`)
247	licenseNode = parser.gordfParserObj.Triples[0].Subject
248	_, err = parser.getConjunctiveLicenseSetFromNode(licenseNode)
249	if err == nil {
250		t.Errorf("expected an error saying invalid predicate found")
251	}
252
253	// TestCase 3: valid example.
254	parser, _ = parserFromBodyContent(`
255		<spdx:ConjunctiveLicenseSet>
256			<spdx:member rdf:resource="http://spdx.org/licenses/Nokia"/>
257			<spdx:member rdf:resource="http://spdx.org/licenses/LGPL-2.0"/>
258		</spdx:ConjunctiveLicenseSet>
259	`)
260	licenseNode = parser.gordfParserObj.Triples[0].Subject
261	license, err = parser.getConjunctiveLicenseSetFromNode(licenseNode)
262	if err != nil {
263		t.Errorf("unexpected error parsing licenseSet: %v", err)
264	}
265	nMembers := len(license.members)
266	if nMembers != 2 {
267		t.Errorf("expected licenseSet to have 2 members, found %d", nMembers)
268	}
269	licenseMembers := mapLicensesToStrings(license.members)
270	expectedLicenseMembers := []string{"LGPL-2.0", "Nokia"}
271	sort.Strings(licenseMembers)
272	if !reflect.DeepEqual(licenseMembers, expectedLicenseMembers) {
273		t.Errorf("expected %v, found %v", expectedLicenseMembers, licenseMembers)
274	}
275}
276
277func Test_rdfParser2_3_getDisjunctiveLicenseSetFromNode(t *testing.T) {
278	var parser *rdfParser2_3
279	var err error
280	var licenseNode *gordfParser.Node
281	var license DisjunctiveLicenseSet
282
283	// TestCase 1: invalid license member
284	parser, _ = parserFromBodyContent(`
285		<spdx:DisjunctiveLicenseSet>
286			<spdx:member rdf:resource="http://spdx.org/licenses/Unknown"/>
287			<spdx:member rdf:resource="http://spdx.org/licenses/LGPL-2.0"/>
288		</spdx:DisjunctiveLicenseSet>
289	`)
290	licenseNode = parser.gordfParserObj.Triples[0].Subject
291	_, err = parser.getDisjunctiveLicenseSetFromNode(licenseNode)
292	if err == nil {
293		t.Errorf("expected an error saying invalid license member, found <nil>")
294	}
295
296	// TestCase 2: invalid predicate in the licenseSet.
297	parser, _ = parserFromBodyContent(`
298		<spdx:DisjunctiveLicenseSet>
299			<spdx:member rdf:resource="http://spdx.org/licenses/Unknown"/>
300			<spdx:member rdf:resource="http://spdx.org/licenses/LGPL-2.0"/>
301			<spdx:unknownTag />
302		</spdx:DisjunctiveLicenseSet>
303	`)
304	licenseNode = parser.gordfParserObj.Triples[0].Subject
305	_, err = parser.getDisjunctiveLicenseSetFromNode(licenseNode)
306	if err == nil {
307		t.Errorf("expected an error saying invalid predicate found")
308	}
309
310	// TestCase 3: valid example.
311	parser, _ = parserFromBodyContent(`
312		<spdx:DisjunctiveLicenseSet>
313			<spdx:member rdf:resource="http://spdx.org/licenses/Nokia"/>
314			<spdx:member rdf:resource="http://spdx.org/licenses/LGPL-2.0"/>
315		</spdx:DisjunctiveLicenseSet>
316	`)
317	licenseNode = parser.gordfParserObj.Triples[0].Subject
318	license, err = parser.getDisjunctiveLicenseSetFromNode(licenseNode)
319	if err != nil {
320		t.Errorf("unexpected error parsing licenseSet: %v", err)
321	}
322	nMembers := len(license.members)
323	if nMembers != 2 {
324		t.Errorf("expected licenseSet to have 2 members, found %d", nMembers)
325	}
326	licenseMembers := mapLicensesToStrings(license.members)
327	expectedLicenseMembers := []string{"LGPL-2.0", "Nokia"}
328	sort.Strings(licenseMembers)
329	if !reflect.DeepEqual(licenseMembers, expectedLicenseMembers) {
330		t.Errorf("expected %v, found %v", expectedLicenseMembers, licenseMembers)
331	}
332}
333
334func Test_rdfParser2_3_getLicenseExceptionFromNode(t *testing.T) {
335	var licenseException LicenseException
336	var err error
337	var node *gordfParser.Node
338	var parser *rdfParser2_3
339
340	// TestCase 1: invalid value for rdf:seeAlso
341	parser, _ = parserFromBodyContent(`
342		<spdx:LicenseException>
343			<rdfs:seeAlso>see-also</rdfs:seeAlso>
344			<spdx:example></spdx:example>
345			<spdx:licenseExceptionId>Libtool-exception</spdx:licenseExceptionId>
346			<rdfs:comment></rdfs:comment>
347		</spdx:LicenseException>
348	`)
349	node = parser.gordfParserObj.Triples[0].Subject
350	_, err = parser.getLicenseExceptionFromNode(node)
351	if err == nil {
352		t.Errorf("should've raised an error due to invalid uri for rdfs:seeAlso")
353	}
354
355	// TestCase 2: invalid predicate for licenseException
356	// TestCase 1: invalid value for rdf:seeAlso
357	parser, _ = parserFromBodyContent(`
358		<spdx:LicenseException>
359			<spdx:example></spdx:example>
360			<spdx:licenseExceptionId>Libtool-exception</spdx:licenseExceptionId>
361			<rdfs:unknown></rdfs:unknown>
362		</spdx:LicenseException>
363	`)
364	node = parser.gordfParserObj.Triples[0].Subject
365	_, err = parser.getLicenseExceptionFromNode(node)
366	if err == nil {
367		t.Errorf("should've raised an error due to invalid predicate")
368	}
369
370	// TestCase 3: everything valid
371	// TestCase 1: invalid value for rdf:seeAlso
372	parser, _ = parserFromBodyContent(`
373		<spdx:LicenseException>
374			<rdfs:seeAlso rdf:resource="http://www.opensource.org/licenses/GPL-3.0"/>
375			<spdx:example>no example</spdx:example>
376			<spdx:licenseExceptionId>Libtool-exception</spdx:licenseExceptionId>
377			<rdfs:comment>no comments</rdfs:comment>
378			<spdx:licenseExceptionText>text</spdx:licenseExceptionText>
379			<spdx:name>name</spdx:name>
380		</spdx:LicenseException>
381	`)
382	node = parser.gordfParserObj.Triples[0].Subject
383	licenseException, err = parser.getLicenseExceptionFromNode(node)
384	if err != nil {
385		t.Fatalf("unexpected error while parsing a valid licenseException")
386	}
387	expectedCrossReference := "http://www.opensource.org/licenses/GPL-3.0"
388	if licenseException.seeAlso != expectedCrossReference {
389		t.Errorf("expected: %s, found: %s", expectedCrossReference, licenseException.seeAlso)
390	}
391	expectedExample := "no example"
392	if licenseException.example != expectedExample {
393		t.Errorf("expected: %s, got: %s", expectedExample, licenseException.example)
394	}
395	if licenseException.licenseExceptionId != "Libtool-exception" {
396		t.Errorf("expected: %s, got: %s", "Libtool-exception", licenseException.licenseExceptionId)
397	}
398	if licenseException.comment != "no comments" {
399		t.Errorf("expected: %s, got: %s", "no comments", licenseException.comment)
400	}
401	if licenseException.licenseExceptionText != "text" {
402		t.Errorf("expected: '%s', got: '%s'", "text", licenseException.licenseExceptionText)
403	}
404	if licenseException.name != "name" {
405		t.Errorf("expected: '%s', got: '%s'", "name", licenseException.name)
406	}
407}
408
409func Test_rdfParser2_3_getLicenseFromNode(t *testing.T) {
410	var parser *rdfParser2_3
411	var node *gordfParser.Node
412	var license License
413	var err error
414
415	// TestCase 1: isOsiApproved is not a valid boolean
416	parser, _ = parserFromBodyContent(`
417		<spdx:License>
418			<spdx:isOsiApproved>no</spdx:isOsiApproved>
419		</spdx:License>
420	`)
421	node = parser.gordfParserObj.Triples[0].Subject
422	license, err = parser.getLicenseFromNode(node)
423	if err == nil {
424		t.Errorf("expected function to raise an error stating isOsiApproved should be a valid boolean type")
425	}
426
427	// TestCase 2: rdf:seeAlso not a valid uri must raise an error
428	parser, _ = parserFromBodyContent(`
429		<spdx:License>
430			<rdfs:seeAlso>uri</rdfs:seeAlso>
431		</spdx:License>
432	`)
433	node = parser.gordfParserObj.Triples[0].Subject
434	license, err = parser.getLicenseFromNode(node)
435	if err == nil {
436		t.Errorf("expected function to raise an error stating invalid uri for rdfs:seeAlso")
437	}
438
439	// TestCase 3: isDeprecatedLicenseId is not a valid boolean
440	parser, _ = parserFromBodyContent(`
441		<spdx:License>
442			<spdx:isDeprecatedLicenseId>yes</spdx:isDeprecatedLicenseId>
443		</spdx:License>
444	`)
445	node = parser.gordfParserObj.Triples[0].Subject
446	license, err = parser.getLicenseFromNode(node)
447	if err == nil {
448		t.Errorf("expected function to raise an error stating isDeprecatedLicenseId should be a valid boolean type")
449	}
450
451	// TestCase 4: isFsfLibre is not a valid boolean
452	parser, _ = parserFromBodyContent(`
453		<spdx:License>
454			<spdx:isFsfLibre>no</spdx:isFsfLibre>
455		</spdx:License>
456	`)
457	node = parser.gordfParserObj.Triples[0].Subject
458	license, err = parser.getLicenseFromNode(node)
459	if err == nil {
460		t.Errorf("expected function to raise an error stating isFsfLibre should be a valid boolean type")
461	}
462
463	// TestCase 5: invalid triple for License:
464	parser, _ = parserFromBodyContent(`
465		<spdx:License>
466			<spdx:unknown />
467		</spdx:License>
468	`)
469	node = parser.gordfParserObj.Triples[0].Subject
470	license, err = parser.getLicenseFromNode(node)
471	if err == nil {
472		t.Errorf("invalid predicate should've raised an error, got <nil>")
473	}
474
475	// TestCase 5: everything valid:
476	parser, _ = parserFromBodyContent(`
477		<spdx:License rdf:about="http://spdx.org/licenses/GPL-3.0-or-later">
478			<rdfs:seeAlso>http://www.opensource.org/licenses/GPL-3.0</rdfs:seeAlso>
479			<spdx:isOsiApproved>true</spdx:isOsiApproved>
480			<spdx:licenseText>GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007</spdx:licenseText>
481			<spdx:name>GNU General Public License v3.0 or later</spdx:name>
482			<spdx:standardLicenseHeaderTemplate>...</spdx:standardLicenseHeaderTemplate>
483			<spdx:licenseId>GPL-3.0-or-later</spdx:licenseId>
484			<rdfs:comment>This license was released: 29 June 2007</rdfs:comment>
485			<spdx:isFsfLibre>true</spdx:isFsfLibre>
486			<spdx:standardLicenseHeader>...</spdx:standardLicenseHeader>
487			<spdx:standardLicenseTemplate>....</spdx:standardLicenseTemplate>
488		</spdx:License>
489	`)
490	node = parser.gordfParserObj.Triples[0].Subject
491	license, err = parser.getLicenseFromNode(node)
492	if err != nil {
493		t.Errorf("error parsing a valid input: %v", err)
494	}
495	expectedSeeAlso := "http://www.opensource.org/licenses/GPL-3.0"
496	if len(license.seeAlso) != 1 {
497		t.Fatalf("expected seeAlso to have 1 element, got %d", len(license.seeAlso))
498	}
499	if license.seeAlso[len(license.seeAlso)-1] != expectedSeeAlso {
500		t.Errorf("expected %s, got %s", expectedSeeAlso, license.seeAlso)
501	}
502	if license.isOsiApproved != true {
503		t.Errorf("expected %t, got %t", true, license.isOsiApproved)
504	}
505	expectedLicenseText := "GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007"
506	if license.licenseText != expectedLicenseText {
507		t.Errorf("expected %s, got %s", expectedSeeAlso, license.licenseText)
508	}
509	expectedName := "GNU General Public License v3.0 or later"
510	if license.name != expectedName {
511		t.Errorf("expected %s, got %s", expectedName, license.name)
512	}
513	expectedstdLicHeader := "..."
514	if license.standardLicenseHeader != expectedstdLicHeader {
515		t.Errorf("expected %s, got %s", expectedstdLicHeader, license.standardLicenseHeader)
516	}
517	expectedLicenseId := "GPL-3.0-or-later"
518	if expectedLicenseId != license.licenseID {
519		t.Errorf("expected %s, got %s", expectedLicenseId, license.licenseID)
520	}
521	expectedLicenseComment := "This license was released: 29 June 2007"
522	if expectedLicenseComment != license.comment {
523		t.Errorf("expected %s, got %s", expectedLicenseComment, license.comment)
524	}
525	expectedstdLicTemplate := "..."
526	if license.standardLicenseHeader != expectedstdLicTemplate {
527		t.Errorf("expected %s, got %s", expectedstdLicTemplate, license.standardLicenseTemplate)
528	}
529	expectedstdLicHeaderTemplate := "..."
530	if license.standardLicenseHeaderTemplate != expectedstdLicHeaderTemplate {
531		t.Errorf("expected %s, got %s", expectedstdLicHeaderTemplate, license.standardLicenseHeaderTemplate)
532	}
533	if license.isFsfLibre != true {
534		t.Errorf("expected %t, got %t", true, license.isFsfLibre)
535	}
536}
537
538func Test_rdfParser2_3_getOrLaterOperatorFromNode(t *testing.T) {
539	var parser *rdfParser2_3
540	var node *gordfParser.Node
541	var err error
542
543	// TestCase 1: more than one member in the OrLaterOperator tag must raise an error
544	parser, _ = parserFromBodyContent(`
545		<spdx:OrLaterOperator>
546			<spdx:member>
547				<spdx:SimpleLicensingInfo>
548					<spdx:licenseId>LicenseRef-Freeware</spdx:licenseId>
549					<spdx:name>freeware</spdx:name>
550				</spdx:SimpleLicensingInfo>
551			</spdx:member>
552			<spdx:member rdf:resource="http://spdx.org/licenses/Nokia"/>
553		</spdx:OrLaterOperator>
554	`)
555	node = parser.gordfParserObj.Triples[0].Subject
556	_, err = parser.getOrLaterOperatorFromNode(node)
557	if err == nil {
558		t.Error("expected an error due to more than one members, got <nil>")
559	}
560
561	// TestCase 2: Invalid predicate must raise an error
562	parser, _ = parserFromBodyContent(`
563		<spdx:OrLaterOperator>
564			<spdx:members>
565				<spdx:SimpleLicensingInfo>
566					<spdx:licenseId>LicenseRef-Freeware</spdx:licenseId>
567					<spdx:name>freeware</spdx:name>
568				</spdx:SimpleLicensingInfo>
569			</spdx:members>
570		</spdx:OrLaterOperator>
571	`)
572	node = parser.gordfParserObj.Triples[0].Subject
573	_, err = parser.getOrLaterOperatorFromNode(node)
574	if err == nil {
575		t.Error("expected an error due to invalid predicate, got <nil>")
576	}
577
578	// TestCase 5: invalid member
579	parser, _ = parserFromBodyContent(`
580		<spdx:OrLaterOperator>
581			<spdx:member>
582				<spdx:SimpleLicensingInfo>
583					<spdx:invalidTag />
584					<spdx:licenseId>LicenseRef-Freeware</spdx:licenseId>
585					<spdx:name>freeware</spdx:name>
586				</spdx:SimpleLicensingInfo>
587			</spdx:member>
588		</spdx:OrLaterOperator>
589	`)
590	node = parser.gordfParserObj.Triples[0].Subject
591	_, err = parser.getOrLaterOperatorFromNode(node)
592	if err == nil {
593		t.Errorf("expected an error parsing invalid license member, got %v", err)
594	}
595
596	// TestCase 4: valid input
597	parser, _ = parserFromBodyContent(`
598		<spdx:OrLaterOperator>
599			<spdx:member>
600				<spdx:SimpleLicensingInfo>
601					<spdx:licenseId>LicenseRef-Freeware</spdx:licenseId>
602					<spdx:name>freeware</spdx:name>
603				</spdx:SimpleLicensingInfo>
604			</spdx:member>
605		</spdx:OrLaterOperator>
606	`)
607	node = parser.gordfParserObj.Triples[0].Subject
608	_, err = parser.getOrLaterOperatorFromNode(node)
609	if err != nil {
610		t.Errorf("unexpected error parsing a valid input: %v", err)
611	}
612}
613
614func Test_rdfParser2_3_getSimpleLicensingInfoFromNode(t *testing.T) {
615	// nothing to test. The just provides an interface to call function that
616	// uses triples to render a SimpleLicensingInfo.
617	parser, _ := parserFromBodyContent(`
618		<spdx:SimpleLicensingInfo>
619			<spdx:licenseId>LicenseRef-Freeware</spdx:licenseId>
620			<spdx:name>freeware</spdx:name>
621		</spdx:SimpleLicensingInfo>
622	`)
623	node := parser.gordfParserObj.Triples[0].Subject
624	_, err := parser.getSimpleLicensingInfoFromNode(node)
625	if err != nil {
626		t.Errorf("error parsing a valid input: %v", err)
627	}
628}
629
630func Test_rdfParser2_3_getSimpleLicensingInfoFromTriples(t *testing.T) {
631	var parser *rdfParser2_3
632	var err error
633	var license SimpleLicensingInfo
634
635	// TestCase 1: invalid rdf:seeAlso attribute
636	parser, _ = parserFromBodyContent(`
637		<spdx:SimpleLicensingInfo>
638			<rdfs:seeAlso>an invalid uri</rdfs:seeAlso>
639		</spdx:SimpleLicensingInfo>
640    `)
641	_, err = parser.getSimpleLicensingInfoFromTriples(parser.gordfParserObj.Triples)
642	if err == nil {
643		t.Error("expected an error reporting invalid uri for rdf:seeAlso, got <nil>")
644	}
645
646	// TestCase 2: invalid predicate must raise an error
647	parser, _ = parserFromBodyContent(`
648		<spdx:SimpleLicensingInfo>
649			<rdfs:invalidPredicate />
650		</spdx:SimpleLicensingInfo>
651    `)
652	_, err = parser.getSimpleLicensingInfoFromTriples(parser.gordfParserObj.Triples)
653	if err == nil {
654		t.Error("expected an error reporting invalid predicate, got <nil>")
655	}
656
657	// TestCase 3: valid example
658	parser, _ = parserFromBodyContent(`
659		<spdx:SimpleLicensingInfo>
660			<rdfs:comment>comment</rdfs:comment>
661			<spdx:licenseId>lid</spdx:licenseId>
662			<spdx:name>name</spdx:name>
663			<rdfs:seeAlso>https://opensource.org/licenses/MPL-1.0</rdfs:seeAlso>
664			<spdx:example>example</spdx:example>
665		</spdx:SimpleLicensingInfo>
666    `)
667	license, err = parser.getSimpleLicensingInfoFromTriples(parser.gordfParserObj.Triples)
668	if err != nil {
669		t.Fatalf("unexpected error: %v", err)
670	}
671	expectedComment := "comment"
672	expectedLicenseId := "lid"
673	expectedName := "name"
674	expectedSeeAlso := "https://opensource.org/licenses/MPL-1.0"
675	expectedExample := "example"
676	if expectedComment != license.comment {
677		t.Errorf("expected %v, got %v", expectedComment, license.comment)
678	}
679	if expectedLicenseId != license.licenseID {
680		t.Errorf("expected %v, got %v", expectedLicenseId, license.licenseID)
681	}
682	if expectedName != license.name {
683		t.Errorf("expected %v, got %v", expectedName, license.name)
684	}
685	if len(license.seeAlso) != 1 {
686		t.Fatalf("expected seeAlso to have 1 element, found %d", len(license.seeAlso))
687	}
688	if license.seeAlso[0] != expectedSeeAlso {
689		t.Errorf("expected %v, got %v", expectedSeeAlso, license.seeAlso[0])
690	}
691	if license.example != expectedExample {
692		t.Errorf("expected %v, got %v", expectedExample, license.example)
693	}
694}
695
696func Test_rdfParser2_3_getSpecialLicenseFromNode(t *testing.T) {
697	var parser *rdfParser2_3
698	var node *gordfParser.Node
699	var license SpecialLicense
700
701	// TestCase 1: NONE
702	parser, _ = parserFromBodyContent(``)
703	node = &gordfParser.Node{
704		NodeType: gordfParser.IRI,
705		ID:       NS_SPDX + "NONE",
706	}
707	license, err := parser.getSpecialLicenseFromNode(node)
708	if err != nil {
709		t.Errorf("error parsing a valid node: %v", err)
710	}
711	if license.value != "NONE" {
712		t.Errorf("expected %s, got %s", "NONE", license.value)
713	}
714
715	// TestCase 2: NOASSERTION
716	parser, _ = parserFromBodyContent(``)
717	node = &gordfParser.Node{
718		NodeType: gordfParser.IRI,
719		ID:       NS_SPDX + "NOASSERTION",
720	}
721	license, err = parser.getSpecialLicenseFromNode(node)
722	if err != nil {
723		t.Errorf("error parsing a valid node: %v", err)
724	}
725	if license.value != "NOASSERTION" {
726		t.Errorf("expected %s, got %s", "NOASSERTION", license.value)
727	}
728
729	// TestCase 4: undefined standard license
730	parser, _ = parserFromBodyContent(``)
731	node = &gordfParser.Node{
732		NodeType: gordfParser.IRI,
733		ID:       "https://opensource.org/licenses/unknown",
734	}
735	_, err = parser.getSpecialLicenseFromNode(node)
736	if err == nil {
737		t.Errorf("expected an error saying invalid license")
738	}
739
740	// TestCase 4: valid standard license
741	parser, _ = parserFromBodyContent(``)
742	node = &gordfParser.Node{
743		NodeType: gordfParser.IRI,
744		ID:       "https://opensource.org/licenses/MPL-1.0",
745	}
746	license, err = parser.getSpecialLicenseFromNode(node)
747	if err != nil {
748		t.Errorf("error parsing a valid node: %v", err)
749	}
750	if license.value != "MPL-1.0" {
751		t.Errorf("expected %s, got %s", "MPL-1.0", license.value)
752	}
753}
754
755func Test_rdfParser2_3_getWithExceptionOperatorFromNode(t *testing.T) {
756	var parser *rdfParser2_3
757	var node *gordfParser.Node
758	var err error
759
760	// TestCase 1: more than one member in the OrLaterOperator tag must raise an error
761	parser, _ = parserFromBodyContent(`
762		<spdx:WithExceptionOperator>
763			<spdx:member>
764				<spdx:SimpleLicensingInfo>
765					<spdx:licenseId>LicenseRef-Freeware</spdx:licenseId>
766					<spdx:name>freeware</spdx:name>
767				</spdx:SimpleLicensingInfo>
768			</spdx:member>
769			<spdx:member rdf:resource="http://spdx.org/licenses/Nokia"/>
770		</spdx:WithExceptionOperator>
771	`)
772	node = parser.gordfParserObj.Triples[0].Subject
773	_, err = parser.getWithExceptionOperatorFromNode(node)
774	if err == nil {
775		t.Error("expected an error due to more than one members, got <nil>")
776	}
777
778	// TestCase 2: Invalid predicate must raise an error
779	parser, _ = parserFromBodyContent(`
780		<spdx:WithExceptionOperator>
781			<spdx:members>
782				<spdx:SimpleLicensingInfo>
783					<spdx:licenseId>LicenseRef-Freeware</spdx:licenseId>
784					<spdx:name>freeware</spdx:name>
785				</spdx:SimpleLicensingInfo>
786			</spdx:members>
787		</spdx:WithExceptionOperator>
788	`)
789	node = parser.gordfParserObj.Triples[0].Subject
790	_, err = parser.getWithExceptionOperatorFromNode(node)
791	if err == nil {
792		t.Error("expected an error due to invalid predicate, got <nil>")
793	}
794
795	// TestCase 3: Invalid member
796	parser, _ = parserFromBodyContent(`
797		<spdx:WithExceptionOperator>
798			<spdx:member>
799				<spdx:License rdf:about="http://spdx.org/licenses/GPL-2.0-or-later">
800					<spdx:unknownTag />
801				</spdx:License>
802			</spdx:member>
803		</spdx:WithExceptionOperator>
804	`)
805	node = parser.gordfParserObj.Triples[0].Subject
806	_, err = parser.getWithExceptionOperatorFromNode(node)
807	if err == nil {
808		t.Error("expected an error due to error parsing a member, got <nil>")
809	}
810
811	// TestCase 4: Invalid licenseException
812	parser, _ = parserFromBodyContent(`
813		<spdx:WithExceptionOperator>
814			<spdx:member>
815				<spdx:License rdf:about="http://spdx.org/licenses/GPL-2.0-or-later"/>
816			</spdx:member>
817			<spdx:licenseException>
818				<spdx:LicenseException>
819					<spdx:invalidTag />
820					<spdx:example>example</spdx:example>
821					<spdx:licenseExceptionId>Libtool-exception</spdx:licenseExceptionId>
822					<rdfs:comment>comment</rdfs:comment>
823				</spdx:LicenseException>
824			</spdx:licenseException>
825		</spdx:WithExceptionOperator>
826	`)
827	node = parser.gordfParserObj.Triples[0].Subject
828	_, err = parser.getWithExceptionOperatorFromNode(node)
829	if err == nil {
830		t.Error("expected an error due to invalid licenseException, got <nil>")
831	}
832
833	// TestCase 5: valid input
834	parser, _ = parserFromBodyContent(`
835		<spdx:WithExceptionOperator>
836			<spdx:member>
837				<spdx:License rdf:about="http://spdx.org/licenses/GPL-2.0-or-later"/>
838			</spdx:member>
839			<spdx:licenseException>
840				<spdx:LicenseException>
841					<spdx:example>example</spdx:example>
842					<spdx:licenseExceptionId>Libtool-exception</spdx:licenseExceptionId>
843					<rdfs:comment>comment</rdfs:comment>
844				</spdx:LicenseException>
845			</spdx:licenseException>
846		</spdx:WithExceptionOperator>
847	`)
848	node = parser.gordfParserObj.Triples[0].Subject
849	_, err = parser.getWithExceptionOperatorFromNode(node)
850	if err != nil {
851		t.Errorf("error parsing a valid input: %v", err)
852	}
853}
854