spdx__tools-python METASEP

tests/data/formats/SPDXYamlExample.yaml METASEP
Document:
  annotations:
    - annotationDate: '2012-06-13T00:00:00Z'
      annotationType: REVIEW
      annotator: 'Person: Jim Reviewer'
      comment: This is just an example. Some of the non-standard licenses look like
        they are actually BSD 3 clause licenses
  comment: This is a sample spreadsheet
  creationInfo:
    comment: This is an example of an SPDX spreadsheet format
    created: '2010-02-03T00:00:00Z'
    creators:
      - 'Tool: SourceAuditor-V1.2'
      - 'Organization: Source Auditor Inc.'
      - 'Person: Gary O''Neall'
    licenseListVersion: '3.6'
  dataLicense: CC0-1.0
  documentDescribes:
    - SPDXRef-Package
  packages:
    - SPDXID: SPDXRef-Package
      checksums:
        - algorithm: SHA1
          checksumValue: 2fd4e1c67a2d28fced849ee1bb76e7391b93eb12
      copyrightText: ' Copyright 2010, 2011 Source Auditor Inc.'
      description: This utility translates and SPDX RDF XML document to a spreadsheet,
        translates a spreadsheet to an SPDX RDF XML document and translates an SPDX
        RDFa document to an SPDX RDF XML document.
      downloadLocation: http://www.spdx.org/tools
      attributionTexts:
        - "The GNU C Library is free software.  See the file COPYING.LIB for copying conditions,\
        \ and LICENSES for notices about a few contributions that require these additional\
        \ notices to be distributed.  License copyright years may be listed using range\
        \ notation, e.g., 1996-2015, indicating that every year in the range, inclusive,\
        \ is a copyrightable year that would otherwise be listed individually."
      licenseComments: The declared license information can be found in the NOTICE
        file at the root of the archive file
      licenseConcluded: (LicenseRef-3 AND LicenseRef-1 AND MPL-1.1 AND Apache-2.0
        AND LicenseRef-2 AND Apache-1.0 AND LicenseRef-4)
      licenseDeclared: (MPL-1.1 AND LicenseRef-4 AND LicenseRef-2 AND LicenseRef-1
        AND Apache-2.0 AND LicenseRef-3)
      licenseInfoFromFiles:
        - Apache-2.0
        - MPL-1.1
        - LicenseRef-3
        - LicenseRef-1
        - LicenseRef-4
        - Apache-1.0
        - LicenseRef-2
      name: SPDX Translator
      originator: 'Organization: SPDX'
      packageFileName: spdxtranslator-1.0.zip
      hasFiles:
        - SPDXRef-File1
        - SPDXRef-File2
      packageVerificationCode:
        packageVerificationCodeExcludedFiles:
          - SpdxTranslatorSpdx.txt
          - SpdxTranslatorSpdx.rdf
        packageVerificationCodeValue: 4e3211c67a2d28fced849ee1bb76e7391b93feba
      sourceInfo: Version 1.0 of the SPDX Translator application
      summary: SPDX Translator utility
      supplier: 'Organization: Linux Foundation'
      versionInfo: Version 0.9.2
      primaryPackagePurpose: OPERATING-SYSTEM
      builtDate: '2020-01-01T12:00:00Z'
      releaseDate: '2021-01-01T12:00:00Z'
      validUntilDate: '2022-01-01T12:00:00Z'
  externalDocumentRefs:
    - checksum:
        algorithm: SHA1
        checksumValue: d6a770ba38583ed4bb4525bd96e50461655d2759
      externalDocumentId: DocumentRef-spdx-tool-2.1
      spdxDocument: https://spdx.org/spdxdocs/spdx-tools-v2.1-3F2504E0-4F89-41D3-9A0C-0305E82C3301
  hasExtractedLicensingInfos:
    - comment: This is tye CyperNeko License
      extractedText: "The CyberNeko Software License, Version 1.0\n\n\n(C) Copyright\
      \ 2002-2005, Andy Clark.  All rights reserved.\n\nRedistribution and use in\
      \ source and binary forms, with or without\nmodification, are permitted provided\
      \ that the following conditions\nare met:\n\n1. Redistributions of source code\
      \ must retain the above copyright\n   notice, this list of conditions and the\
      \ following disclaimer.\n\n2. Redistributions in binary form must reproduce\
      \ the above copyright\n   notice, this list of conditions and the following\
      \ disclaimer in\n   the documentation and/or other materials provided with the\n\
      \   distribution.\n\n3. The end-user documentation included with the redistribution,\n\
      \   if any, must include the following acknowledgment:\n     \"This product\
      \ includes software developed by Andy Clark.\"\n   Alternately, this acknowledgment\
      \ may appear in the software itself,\n   if and wherever such third-party acknowledgments\
      \ normally appear.\n\n4. The names \"CyberNeko\" and \"NekoHTML\" must not be\
      \ used to endorse\n   or promote products derived from this software without\
      \ prior\n   written permission. For written permission, please contact\n \
      \  andyc@cyberneko.net.\n\n5. Products derived from this software may not be\
      \ called \"CyberNeko\",\n   nor may \"CyberNeko\" appear in their name, without\
      \ prior written\n   permission of the author.\n\nTHIS SOFTWARE IS PROVIDED ``AS\
      \ IS'' AND ANY EXPRESSED OR IMPLIED\nWARRANTIES, INCLUDING, BUT NOT LIMITED\
      \ TO, THE IMPLIED WARRANTIES\nOF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\
      \ PURPOSE ARE\nDISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS\n\
      BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,\nOR CONSEQUENTIAL\
      \ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\nOF SUBSTITUTE GOODS\
      \ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR\nBUSINESS INTERRUPTION) HOWEVER\
      \ CAUSED AND ON ANY THEORY OF LIABILITY,\nWHETHER IN CONTRACT, STRICT LIABILITY,\
      \ OR TORT (INCLUDING NEGLIGENCE\nOR OTHERWISE) ARISING IN ANY WAY OUT OF THE\
      \ USE OF THIS SOFTWARE,\nEVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
      licenseId: LicenseRef-3
      name: CyberNeko License
      seeAlsos:
        - http://justasample.url.com
        - http://people.apache.org/~andyc/neko/LICENSE
    - extractedText: "/*\n * (c) Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006,\
      \ 2007, 2008, 2009 Hewlett-Packard Development Company, LP\n * All rights reserved.\n\
      \ *\n * Redistribution and use in source and binary forms, with or without\n\
      \ * modification, are permitted provided that the following conditions\n * are\
      \ met:\n * 1. Redistributions of source code must retain the above copyright\n\
      \ *    notice, this list of conditions and the following disclaimer.\n * 2.\
      \ Redistributions in binary form must reproduce the above copyright\n *    notice,\
      \ this list of conditions and the following disclaimer in the\n *    documentation\
      \ and/or other materials provided with the distribution.\n * 3. The name of\
      \ the author may not be used to endorse or promote products\n *    derived from\
      \ this software without specific prior written permission.\n *\n * THIS SOFTWARE\
      \ IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR\n * IMPLIED WARRANTIES,\
      \ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n * OF MERCHANTABILITY\
      \ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL\
      \ THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,\n * INCIDENTAL, SPECIAL, EXEMPLARY,\
      \ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\n * NOT LIMITED TO, PROCUREMENT OF\
      \ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS\
      \ INTERRUPTION) HOWEVER CAUSED AND ON ANY\n * THEORY OF LIABILITY, WHETHER IN\
      \ CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE)\
      \ ARISING IN ANY WAY OUT OF THE USE OF\n * THIS SOFTWARE, EVEN IF ADVISED OF\
      \ THE POSSIBILITY OF SUCH DAMAGE.\n */"
      licenseId: LicenseRef-1
    - extractedText: "This package includes the GRDDL parser developed by Hewlett Packard\
      \ under the following license:\n\xA9 Copyright 2007 Hewlett-Packard Development\
      \ Company, LP\n\nRedistribution and use in source and binary forms, with or\
      \ without modification, are permitted provided that the following conditions\
      \ are met:\n\nRedistributions of source code must retain the above copyright\
      \ notice, this list of conditions and the following disclaimer.\nRedistributions\
      \ in binary form must reproduce the above copyright notice, this list of conditions\
      \ and the following disclaimer in the documentation and/or other materials provided\
      \ with the distribution.\nThe name of the author may not be used to endorse\
      \ or promote products derived from this software without specific prior written\
      \ permission.\nTHIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS\
      \ OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\
      \ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN\
      \ NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\
      \ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\
      \ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;\
      \ OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\
      \ IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\
      \ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\
      \ POSSIBILITY OF SUCH DAMAGE. "
      licenseId: LicenseRef-2
    - extractedText: "/*\n * (c) Copyright 2009 University of Bristol\n * All rights\
      \ reserved.\n *\n * Redistribution and use in source and binary forms, with\
      \ or without\n * modification, are permitted provided that the following conditions\n\
      \ * are met:\n * 1. Redistributions of source code must retain the above copyright\n\
      \ *    notice, this list of conditions and the following disclaimer.\n * 2.\
      \ Redistributions in binary form must reproduce the above copyright\n *    notice,\
      \ this list of conditions and the following disclaimer in the\n *    documentation\
      \ and/or other materials provided with the distribution.\n * 3. The name of\
      \ the author may not be used to endorse or promote products\n *    derived from\
      \ this software without specific prior written permission.\n *\n * THIS SOFTWARE\
      \ IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR\n * IMPLIED WARRANTIES,\
      \ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n * OF MERCHANTABILITY\
      \ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL\
      \ THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,\n * INCIDENTAL, SPECIAL, EXEMPLARY,\
      \ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\n * NOT LIMITED TO, PROCUREMENT OF\
      \ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS\
      \ INTERRUPTION) HOWEVER CAUSED AND ON ANY\n * THEORY OF LIABILITY, WHETHER IN\
      \ CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE)\
      \ ARISING IN ANY WAY OUT OF THE USE OF\n * THIS SOFTWARE, EVEN IF ADVISED OF\
      \ THE POSSIBILITY OF SUCH DAMAGE.\n */  "
      licenseId: LicenseRef-4
  SPDXID: SPDXRef-DOCUMENT
  name: Sample_Document-V2.1
  documentNamespace: https://spdx.org/spdxdocs/spdx-example-444504E0-4F89-41D3-9A0C-0305E82C3301
  reviewers:
    - comment: Another example reviewer.
      reviewDate: '2011-03-13T00:00:00Z'
      reviewer: 'Person: Suzanne Reviewer'
    - comment: This is just an example.  Some of the non-standard licenses look like
        they are actually BSD 3 clause licenses
      reviewDate: '2010-02-10T00:00:00Z'
      reviewer: 'Person: Joe Reviewer'
  snippets:
    - comment: This snippet was identified as significant and highlighted in this Apache-2.0
        file, when a commercial scanner identified it as being derived from file foo.c
        in package xyz which is licensed under GPL-2.0-or-later.
      copyrightText: Copyright 2008-2010 John Smith
      snippetFromFile: SPDXRef-DoapSource
      SPDXID: SPDXRef-Snippet
      licenseComments: The concluded license was taken from package xyz, from which
        the snippet was copied into the current file. The concluded license information
        was found in the COPYING.txt file in package xyz.
      licenseConcluded: Apache-2.0
      licenseInfoInSnippets:
        - Apache-2.0
        - GPL-2.0-only
      name: from linux kernel
      ranges:
        - endPointer:
            offset: 420
            reference: "SPDXRef-DoapSource"
          startPointer:
            offset: 310
            reference: "SPDXRef-DoapSource"
        - endPointer:
            lineNumber: 23
            reference: "SPDXRef-DoapSource"
          startPointer:
            lineNumber: 5
            reference: "SPDXRef-DoapSource"
  spdxVersion: SPDX-2.1
  files:
    - SPDXID: SPDXRef-File1
      checksums:
        - algorithm: SHA1
          checksumValue: 3ab4e1c67a2d28fced849ee1bb76e7391b93f125
        - algorithm: SHA256
          checksumValue: 3ab4e1c67a2d28fced849ee1bb76e7391b93f1250000000000000000
      comment: This file belongs to Jena
      copyrightText: (c) Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
        2008, 2009 Hewlett-Packard Development Company, LP
      artifactOf:
        - name: "Jena"
          homePage: "http://www.openjena.org/"
          projectUri: "http://subversion.apache.org/doap.rdf"
      fileTypes:
        - ARCHIVE
        - OTHER
      licenseComments: This license is used by Jena
      licenseConcluded: LicenseRef-1
      licenseInfoInFiles:
        - LicenseRef-1
      fileName: Jenna-2.6.3/jena-2.6.3-sources.jar

    - SPDXID: SPDXRef-File2
      checksums:
        - algorithm: SHA1
          checksumValue: 2fd4e1c67a2d28fced849ee1bb76e7391b93eb12
      copyrightText: Copyright 2010, 2011 Source Auditor Inc.
      fileTypes:
        - SOURCE
        - TEXT
      licenseConcluded: Apache-2.0
      licenseInfoInFiles:
        - Apache-2.0
      fileName: src/org/spdx/parser/DOAPProject.java

tests/data/formats/SPDXYAMLExample-2.3.spdx.yaml METASEP
---
SPDXID: "SPDXRef-DOCUMENT"
spdxVersion: "SPDX-2.3"
creationInfo:
  comment: "This package has been shipped in source and binary form.\nThe binaries\
    \ were created with gcc 4.5.1 and expect to link to\ncompatible system run time\
    \ libraries."
  created: "2010-01-29T18:30:22Z"
  creators:
  - "Tool: LicenseFind-1.0"
  - "Organization: ExampleCodeInspect ()"
  - "Person: Jane Doe ()"
  licenseListVersion: "3.17"
name: "SPDX-Tools-v2.0"
dataLicense: "CC0-1.0"
comment: "This document was created using SPDX 2.0 using licenses from the web site."
externalDocumentRefs:
- externalDocumentId: "DocumentRef-spdx-tool-1.2"
  checksum:
    algorithm: "SHA1"
    checksumValue: "d6a770ba38583ed4bb4525bd96e50461655d2759"
  spdxDocument: "http://spdx.org/spdxdocs/spdx-tools-v1.2-3F2504E0-4F89-41D3-9A0C-0305E82C3301"
hasExtractedLicensingInfos:
- licenseId: "LicenseRef-1"
  extractedText: "/*\n * (c) Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,\
    \ 2008, 2009 Hewlett-Packard Development Company, LP\n * All rights reserved.\n\
    \ *\n * Redistribution and use in source and binary forms, with or without\n *\
    \ modification, are permitted provided that the following conditions\n * are met:\n\
    \ * 1. Redistributions of source code must retain the above copyright\n *    notice,\
    \ this list of conditions and the following disclaimer.\n * 2. Redistributions\
    \ in binary form must reproduce the above copyright\n *    notice, this list of\
    \ conditions and the following disclaimer in the\n *    documentation and/or other\
    \ materials provided with the distribution.\n * 3. The name of the author may\
    \ not be used to endorse or promote products\n *    derived from this software\
    \ without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED\
    \ BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR\n * IMPLIED WARRANTIES, INCLUDING,\
    \ BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n * OF MERCHANTABILITY AND FITNESS\
    \ FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE AUTHOR BE\
    \ LIABLE FOR ANY DIRECT, INDIRECT,\n * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\
    \ DAMAGES (INCLUDING, BUT\n * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\
    \ OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\
    \ CAUSED AND ON ANY\n * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\
    \ OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE\
    \ USE OF\n * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\
    */"
- licenseId: "LicenseRef-2"
  extractedText: "This package includes the GRDDL parser developed by Hewlett Packard\
    \ under the following license:\n© Copyright 2007 Hewlett-Packard Development Company,\
    \ LP\n\nRedistribution and use in source and binary forms, with or without modification,\
    \ are permitted provided that the following conditions are met: \n\nRedistributions\
    \ of source code must retain the above copyright notice, this list of conditions\
    \ and the following disclaimer. \nRedistributions in binary form must reproduce\
    \ the above copyright notice, this list of conditions and the following disclaimer\
    \ in the documentation and/or other materials provided with the distribution.\
    \ \nThe name of the author may not be used to endorse or promote products derived\
    \ from this software without specific prior written permission. \nTHIS SOFTWARE\
    \ IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\
    \ BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\
    \ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE\
    \ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\
    \ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\
    \ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\
    \ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\
    \ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\
    \ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
- licenseId: "LicenseRef-4"
  extractedText: "/*\n * (c) Copyright 2009 University of Bristol\n * All rights reserved.\n\
    \ *\n * Redistribution and use in source and binary forms, with or without\n *\
    \ modification, are permitted provided that the following conditions\n * are met:\n\
    \ * 1. Redistributions of source code must retain the above copyright\n *    notice,\
    \ this list of conditions and the following disclaimer.\n * 2. Redistributions\
    \ in binary form must reproduce the above copyright\n *    notice, this list of\
    \ conditions and the following disclaimer in the\n *    documentation and/or other\
    \ materials provided with the distribution.\n * 3. The name of the author may\
    \ not be used to endorse or promote products\n *    derived from this software\
    \ without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED\
    \ BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR\n * IMPLIED WARRANTIES, INCLUDING,\
    \ BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n * OF MERCHANTABILITY AND FITNESS\
    \ FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE AUTHOR BE\
    \ LIABLE FOR ANY DIRECT, INDIRECT,\n * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\
    \ DAMAGES (INCLUDING, BUT\n * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\
    \ OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\
    \ CAUSED AND ON ANY\n * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\
    \ OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE\
    \ USE OF\n * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\
    */"
- licenseId: "LicenseRef-Beerware-4.2"
  comment: "The beerware license has a couple of other standard variants."
  extractedText: "\"THE BEER-WARE LICENSE\" (Revision 42):\nphk@FreeBSD.ORG wrote\
    \ this file. As long as you retain this notice you\ncan do whatever you want with\
    \ this stuff. If we meet some day, and you think this stuff is worth it, you can\
    \ buy me a beer in return Poul-Henning Kamp"
  name: "Beer-Ware License (Version 42)"
  seeAlsos:
  - "http://people.freebsd.org/~phk/"
- licenseId: "LicenseRef-3"
  comment: "This is tye CyperNeko License"
  extractedText: "The CyberNeko Software License, Version 1.0\n\n \n(C) Copyright\
    \ 2002-2005, Andy Clark.  All rights reserved.\n \nRedistribution and use in source\
    \ and binary forms, with or without\nmodification, are permitted provided that\
    \ the following conditions\nare met:\n\n1. Redistributions of source code must\
    \ retain the above copyright\n   notice, this list of conditions and the following\
    \ disclaimer. \n\n2. Redistributions in binary form must reproduce the above copyright\n\
    \   notice, this list of conditions and the following disclaimer in\n   the documentation\
    \ and/or other materials provided with the\n   distribution.\n\n3. The end-user\
    \ documentation included with the redistribution,\n   if any, must include the\
    \ following acknowledgment:  \n     \"This product includes software developed\
    \ by Andy Clark.\"\n   Alternately, this acknowledgment may appear in the software\
    \ itself,\n   if and wherever such third-party acknowledgments normally appear.\n\
    \n4. The names \"CyberNeko\" and \"NekoHTML\" must not be used to endorse\n  \
    \ or promote products derived from this software without prior \n   written permission.\
    \ For written permission, please contact \n   andyc@cyberneko.net.\n\n5. Products\
    \ derived from this software may not be called \"CyberNeko\",\n   nor may \"CyberNeko\"\
    \ appear in their name, without prior written\n   permission of the author.\n\n\
    THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED\nWARRANTIES,\
    \ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\nOF MERCHANTABILITY AND\
    \ FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED.  IN NO EVENT SHALL THE AUTHOR\
    \ OR OTHER CONTRIBUTORS\nBE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\
    \ EXEMPLARY, \nOR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\
    \ \nOF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR \nBUSINESS\
    \ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, \nWHETHER IN CONTRACT,\
    \ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE \nOR OTHERWISE) ARISING IN ANY\
    \ WAY OUT OF THE USE OF THIS SOFTWARE, \nEVEN IF ADVISED OF THE POSSIBILITY OF\
    \ SUCH DAMAGE."
  name: "CyberNeko License"
  seeAlsos:
  - "http://people.apache.org/~andyc/neko/LICENSE"
  - "http://justasample.url.com"
annotations:
- annotationDate: "2010-01-29T18:30:22Z"
  annotationType: "OTHER"
  annotator: "Person: Jane Doe ()"
  comment: "Document level annotation"
- annotationDate: "2010-02-10T00:00:00Z"
  annotationType: "REVIEW"
  annotator: "Person: Joe Reviewer"
  comment: "This is just an example.  Some of the non-standard licenses look like\
    \ they are actually BSD 3 clause licenses"
- annotationDate: "2011-03-13T00:00:00Z"
  annotationType: "REVIEW"
  annotator: "Person: Suzanne Reviewer"
  comment: "Another example reviewer."
documentDescribes:
- "SPDXRef-File"
- "SPDXRef-Package"
documentNamespace: "http://spdx.org/spdxdocs/spdx-example-444504E0-4F89-41D3-9A0C-0305E82C3301"
packages:
- SPDXID: "SPDXRef-Package"
  annotations:
  - annotationDate: "2011-01-29T18:30:22Z"
    annotationType: "OTHER"
    annotator: "Person: Package Commenter"
    comment: "Package level annotation"
  attributionTexts:
  - "The GNU C Library is free software.  See the file COPYING.LIB for copying conditions,\
    \ and LICENSES for notices about a few contributions that require these additional\
    \ notices to be distributed.  License copyright years may be listed using range\
    \ notation, e.g., 1996-2015, indicating that every year in the range, inclusive,\
    \ is a copyrightable year that would otherwise be listed individually."
  builtDate: "2011-01-29T18:30:22Z"
  checksums:
  - algorithm: "MD5"
    checksumValue: "624c1abb3664f4b35547e7c73864ad24"
  - algorithm: "SHA1"
    checksumValue: "85ed0817af83a24ad8da68c2b5094de69833983c"
  - algorithm: "SHA256"
    checksumValue: "11b6d3ee554eedf79299905a98f9b9a04e498210b59f15094c916c91d150efcd"
  - algorithm: "BLAKE2b-384"
    checksumValue: "aaabd89c926ab525c242e6621f2f5fa73aa4afe3d9e24aed727faaadd6af38b620bdb623dd2b4788b1c8086984af8706"
  copyrightText: "Copyright 2008-2010 John Smith"
  description: "The GNU C Library defines functions that are specified by the ISO\
    \ C standard, as well as additional features specific to POSIX and other derivatives\
    \ of the Unix operating system, and extensions specific to GNU systems."
  downloadLocation: "http://ftp.gnu.org/gnu/glibc/glibc-ports-2.15.tar.gz"
  externalRefs:
  - referenceCategory: "SECURITY"
    referenceLocator: "cpe:2.3:a:pivotal_software:spring_framework:4.1.0:*:*:*:*:*:*:*"
    referenceType: "cpe23Type"
  - comment: "This is the external ref for Acme"
    referenceCategory: "OTHER"
    referenceLocator: "acmecorp/acmenator/4.1.3-alpha"
    referenceType: "http://spdx.org/spdxdocs/spdx-example-444504E0-4F89-41D3-9A0C-0305E82C3301#LocationRef-acmeforge"
  filesAnalyzed: true
  homepage: "http://ftp.gnu.org/gnu/glibc"
  licenseComments: "The license for this project changed with the release of version\
    \ x.y.  The version of the project included here post-dates the license change."
  licenseConcluded: "(LGPL-2.0-only OR LicenseRef-3)"
  licenseDeclared: "(LGPL-2.0-only AND LicenseRef-3)"
  licenseInfoFromFiles:
  - "GPL-2.0-only"
  - "LicenseRef-2"
  - "LicenseRef-1"
  name: "glibc"
  originator: "Organization: ExampleCodeInspect (contact@example.com)"
  packageFileName: "glibc-2.11.1.tar.gz"
  packageVerificationCode:
    packageVerificationCodeExcludedFiles:
    - "./package.spdx"
    packageVerificationCodeValue: "d6a770ba38583ed4bb4525bd96e50461655d2758"
  primaryPackagePurpose: "SOURCE"
  hasFiles:
  - "SPDXRef-Specification"
  - "SPDXRef-Specification"
  - "SPDXRef-CommonsLangSrc"
  - "SPDXRef-Specification"
  - "SPDXRef-CommonsLangSrc"
  - "SPDXRef-JenaLib"
  - "SPDXRef-Specification"
  - "SPDXRef-CommonsLangSrc"
  - "SPDXRef-JenaLib"
  - "SPDXRef-DoapSource"
  - "SPDXRef-Specification"
  - "SPDXRef-CommonsLangSrc"
  - "SPDXRef-JenaLib"
  - "SPDXRef-DoapSource"
  releaseDate: "2012-01-29T18:30:22Z"
  sourceInfo: "uses glibc-2_11-branch from git://sourceware.org/git/glibc.git."
  summary: "GNU C library."
  supplier: "Person: Jane Doe (jane.doe@example.com)"
  validUntilDate: "2014-01-29T18:30:22Z"
  versionInfo: "2.11.1"
- SPDXID: "SPDXRef-fromDoap-1"
  copyrightText: "NOASSERTION"
  downloadLocation: "NOASSERTION"
  filesAnalyzed: false
  homepage: "http://commons.apache.org/proper/commons-lang/"
  licenseConcluded: "NOASSERTION"
  licenseDeclared: "NOASSERTION"
  name: "Apache Commons Lang"
- SPDXID: "SPDXRef-fromDoap-0"
  downloadLocation: "https://search.maven.org/remotecontent?filepath=org/apache/jena/apache-jena/3.12.0/apache-jena-3.12.0.tar.gz"
  externalRefs:
  - referenceCategory: "PACKAGE-MANAGER"
    referenceLocator: "pkg:maven/org.apache.jena/apache-jena@3.12.0"
    referenceType: "purl"
  filesAnalyzed: false
  homepage: "http://www.openjena.org/"
  name: "Jena"
  versionInfo: "3.12.0"
- SPDXID: "SPDXRef-Saxon"
  checksums:
  - algorithm: "SHA1"
    checksumValue: "85ed0817af83a24ad8da68c2b5094de69833983c"
  copyrightText: "Copyright Saxonica Ltd"
  description: "The Saxon package is a collection of tools for processing XML documents."
  downloadLocation: "https://sourceforge.net/projects/saxon/files/Saxon-B/8.8.0.7/saxonb8-8-0-7j.zip/download"
  filesAnalyzed: false
  homepage: "http://saxon.sourceforge.net/"
  licenseComments: "Other versions available for a commercial license"
  licenseConcluded: "MPL-1.0"
  licenseDeclared: "MPL-1.0"
  name: "Saxon"
  packageFileName: "saxonB-8.8.zip"
  versionInfo: "8.8"
files:
- SPDXID: "SPDXRef-DoapSource"
  checksums:
  - algorithm: "SHA1"
    checksumValue: "2fd4e1c67a2d28fced849ee1bb76e7391b93eb12"
  copyrightText: "Copyright 2010, 2011 Source Auditor Inc."
  fileContributors:
  - "Protecode Inc."
  - "SPDX Technical Team Members"
  - "Open Logic Inc."
  - "Source Auditor Inc."
  - "Black Duck Software In.c"
  fileName: "./src/org/spdx/parser/DOAPProject.java"
  fileTypes:
  - "SOURCE"
  licenseConcluded: "Apache-2.0"
  licenseInfoInFiles:
  - "Apache-2.0"
- SPDXID: "SPDXRef-CommonsLangSrc"
  checksums:
  - algorithm: "SHA1"
    checksumValue: "c2b4e1c67a2d28fced849ee1bb76e7391b93f125"
  comment: "This file is used by Jena"
  copyrightText: "Copyright 2001-2011 The Apache Software Foundation"
  fileContributors:
  - "Apache Software Foundation"
  fileName: "./lib-source/commons-lang3-3.1-sources.jar"
  fileTypes:
  - "ARCHIVE"
  licenseConcluded: "Apache-2.0"
  licenseInfoInFiles:
  - "Apache-2.0"
  noticeText: "Apache Commons Lang\nCopyright 2001-2011 The Apache Software Foundation\n\
    \nThis product includes software developed by\nThe Apache Software Foundation\
    \ (http://www.apache.org/).\n\nThis product includes software from the Spring\
    \ Framework,\nunder the Apache License 2.0 (see: StringUtils.containsWhitespace())"
- SPDXID: "SPDXRef-JenaLib"
  checksums:
  - algorithm: "SHA1"
    checksumValue: "3ab4e1c67a2d28fced849ee1bb76e7391b93f125"
  comment: "This file belongs to Jena"
  copyrightText: "(c) Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,\
    \ 2009 Hewlett-Packard Development Company, LP"
  fileContributors:
  - "Apache Software Foundation"
  - "Hewlett Packard Inc."
  fileName: "./lib-source/jena-2.6.3-sources.jar"
  fileTypes:
  - "ARCHIVE"
  licenseComments: "This license is used by Jena"
  licenseConcluded: "LicenseRef-1"
  licenseInfoInFiles:
  - "LicenseRef-1"
- SPDXID: "SPDXRef-Specification"
  checksums:
  - algorithm: "SHA1"
    checksumValue: "fff4e1c67a2d28fced849ee1bb76e7391b93f125"
  comment: "Specification Documentation"
  fileName: "./docs/myspec.pdf"
  fileTypes:
  - "DOCUMENTATION"
- SPDXID: "SPDXRef-File"
  annotations:
  - annotationDate: "2011-01-29T18:30:22Z"
    annotationType: "OTHER"
    annotator: "Person: File Commenter"
    comment: "File level annotation"
  checksums:
  - algorithm: "SHA1"
    checksumValue: "d6a770ba38583ed4bb4525bd96e50461655d2758"
  - algorithm: "MD5"
    checksumValue: "624c1abb3664f4b35547e7c73864ad24"
  comment: "The concluded license was taken from the package level that the file was\
    \ included in.\nThis information was found in the COPYING.txt file in the xyz\
    \ directory."
  copyrightText: "Copyright 2008-2010 John Smith"
  fileContributors:
  - "The Regents of the University of California"
  - "Modified by Paul Mundt lethal@linux-sh.org"
  - "IBM Corporation"
  fileName: "./package/foo.c"
  fileTypes:
  - "SOURCE"
  licenseComments: "The concluded license was taken from the package level that the\
    \ file was included in."
  licenseConcluded: "(LGPL-2.0-only OR LicenseRef-2)"
  licenseInfoInFiles:
  - "GPL-2.0-only"
  - "LicenseRef-2"
  noticeText: "Copyright (c) 2001 Aaron Lehmann aaroni@vitelus.com\n\nPermission is\
    \ hereby granted, free of charge, to any person obtaining a copy of this software\
    \ and associated documentation files (the \"Software\"), to deal in the Software\
    \ without restriction, including without limitation the rights to use, copy, modify,\
    \ merge, publish, distribute, sublicense, and/or sell copies of the Software,\
    \ and to permit persons to whom the Software is furnished to do so, subject to\
    \ the following conditions: \nThe above copyright notice and this permission notice\
    \ shall be included in all copies or substantial portions of the Software.\n\n\
    THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\
    \ INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR\
    \ A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR\
    \ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\
    \ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\
    \ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE."
snippets:
- SPDXID: "SPDXRef-Snippet"
  comment: "This snippet was identified as significant and highlighted in this Apache-2.0\
    \ file, when a commercial scanner identified it as being derived from file foo.c\
    \ in package xyz which is licensed under GPL-2.0."
  copyrightText: "Copyright 2008-2010 John Smith"
  licenseComments: "The concluded license was taken from package xyz, from which the\
    \ snippet was copied into the current file. The concluded license information\
    \ was found in the COPYING.txt file in package xyz."
  licenseConcluded: "GPL-2.0-only"
  licenseInfoInSnippets:
  - "GPL-2.0-only"
  name: "from linux kernel"
  ranges:
  - endPointer:
      offset: 420
      reference: "SPDXRef-DoapSource"
    startPointer:
      offset: 310
      reference: "SPDXRef-DoapSource"
  - endPointer:
      lineNumber: 23
      reference: "SPDXRef-DoapSource"
    startPointer:
      lineNumber: 5
      reference: "SPDXRef-DoapSource"
  snippetFromFile: "SPDXRef-DoapSource"
relationships:
- spdxElementId: "SPDXRef-DOCUMENT"
  relationshipType: "CONTAINS"
  relatedSpdxElement: "SPDXRef-Package"
- spdxElementId: "SPDXRef-DOCUMENT"
  relationshipType: "COPY_OF"
  relatedSpdxElement: "DocumentRef-spdx-tool-1.2:SPDXRef-ToolsElement"
- spdxElementId: "SPDXRef-Package"
  relationshipType: "DYNAMIC_LINK"
  relatedSpdxElement: "SPDXRef-Saxon"
- spdxElementId: "SPDXRef-CommonsLangSrc"
  relationshipType: "GENERATED_FROM"
  relatedSpdxElement: "NOASSERTION"
- spdxElementId: "SPDXRef-JenaLib"
  relationshipType: "CONTAINS"
  relatedSpdxElement: "SPDXRef-Package"
- spdxElementId: "SPDXRef-Specification"
  relationshipType: "SPECIFICATION_FOR"
  relatedSpdxElement: "SPDXRef-fromDoap-0"
- spdxElementId: "SPDXRef-File"
  relationshipType: "GENERATED_FROM"
  relatedSpdxElement: "SPDXRef-fromDoap-0"

tests/data/formats/SPDXYAMLExample-2.2.spdx.yaml METASEP
---
SPDXID: "SPDXRef-DOCUMENT"
spdxVersion: "SPDX-2.2"
creationInfo:
  comment: "This package has been shipped in source and binary form.\nThe binaries\
    \ were created with gcc 4.5.1 and expect to link to\ncompatible system run time\
    \ libraries."
  created: "2010-01-29T18:30:22Z"
  creators:
  - "Tool: LicenseFind-1.0"
  - "Organization: ExampleCodeInspect ()"
  - "Person: Jane Doe ()"
  licenseListVersion: "3.9"
name: "SPDX-Tools-v2.0"
dataLicense: "CC0-1.0"
comment: "This document was created using SPDX 2.0 using licenses from the web site."
externalDocumentRefs:
- externalDocumentId: "DocumentRef-spdx-tool-1.2"
  checksum:
    algorithm: "SHA1"
    checksumValue: "d6a770ba38583ed4bb4525bd96e50461655d2759"
  spdxDocument: "http://spdx.org/spdxdocs/spdx-tools-v1.2-3F2504E0-4F89-41D3-9A0C-0305E82C3301"
hasExtractedLicensingInfos:
- licenseId: "LicenseRef-1"
  extractedText: "/*\n * (c) Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,\
    \ 2008, 2009 Hewlett-Packard Development Company, LP\n * All rights reserved.\n\
    \ *\n * Redistribution and use in source and binary forms, with or without\n *\
    \ modification, are permitted provided that the following conditions\n * are met:\n\
    \ * 1. Redistributions of source code must retain the above copyright\n *    notice,\
    \ this list of conditions and the following disclaimer.\n * 2. Redistributions\
    \ in binary form must reproduce the above copyright\n *    notice, this list of\
    \ conditions and the following disclaimer in the\n *    documentation and/or other\
    \ materials provided with the distribution.\n * 3. The name of the author may\
    \ not be used to endorse or promote products\n *    derived from this software\
    \ without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED\
    \ BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR\n * IMPLIED WARRANTIES, INCLUDING,\
    \ BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n * OF MERCHANTABILITY AND FITNESS\
    \ FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE AUTHOR BE\
    \ LIABLE FOR ANY DIRECT, INDIRECT,\n * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\
    \ DAMAGES (INCLUDING, BUT\n * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\
    \ OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\
    \ CAUSED AND ON ANY\n * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\
    \ OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE\
    \ USE OF\n * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\
    */"
- licenseId: "LicenseRef-2"
  extractedText: "This package includes the GRDDL parser developed by Hewlett Packard\
    \ under the following license:\n� Copyright 2007 Hewlett-Packard Development Company,\
    \ LP\n\nRedistribution and use in source and binary forms, with or without modification,\
    \ are permitted provided that the following conditions are met: \n\nRedistributions\
    \ of source code must retain the above copyright notice, this list of conditions\
    \ and the following disclaimer. \nRedistributions in binary form must reproduce\
    \ the above copyright notice, this list of conditions and the following disclaimer\
    \ in the documentation and/or other materials provided with the distribution.\
    \ \nThe name of the author may not be used to endorse or promote products derived\
    \ from this software without specific prior written permission. \nTHIS SOFTWARE\
    \ IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\
    \ BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\
    \ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE\
    \ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\
    \ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\
    \ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\
    \ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\
    \ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\
    \ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
- licenseId: "LicenseRef-4"
  extractedText: "/*\n * (c) Copyright 2009 University of Bristol\n * All rights reserved.\n\
    \ *\n * Redistribution and use in source and binary forms, with or without\n *\
    \ modification, are permitted provided that the following conditions\n * are met:\n\
    \ * 1. Redistributions of source code must retain the above copyright\n *    notice,\
    \ this list of conditions and the following disclaimer.\n * 2. Redistributions\
    \ in binary form must reproduce the above copyright\n *    notice, this list of\
    \ conditions and the following disclaimer in the\n *    documentation and/or other\
    \ materials provided with the distribution.\n * 3. The name of the author may\
    \ not be used to endorse or promote products\n *    derived from this software\
    \ without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED\
    \ BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR\n * IMPLIED WARRANTIES, INCLUDING,\
    \ BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n * OF MERCHANTABILITY AND FITNESS\
    \ FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE AUTHOR BE\
    \ LIABLE FOR ANY DIRECT, INDIRECT,\n * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\
    \ DAMAGES (INCLUDING, BUT\n * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\
    \ OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\
    \ CAUSED AND ON ANY\n * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\
    \ OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE\
    \ USE OF\n * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\
    */"
- licenseId: "LicenseRef-Beerware-4.2"
  comment: "The beerware license has a couple of other standard variants."
  extractedText: "\"THE BEER-WARE LICENSE\" (Revision 42):\nphk@FreeBSD.ORG wrote\
    \ this file. As long as you retain this notice you\ncan do whatever you want with\
    \ this stuff. If we meet some day, and you think this stuff is worth it, you can\
    \ buy me a beer in return Poul-Henning Kamp"
  name: "Beer-Ware License (Version 42)"
  seeAlsos:
  - "http://people.freebsd.org/~phk/"
- licenseId: "LicenseRef-3"
  comment: "This is tye CyperNeko License"
  extractedText: "The CyberNeko Software License, Version 1.0\n\n \n(C) Copyright\
    \ 2002-2005, Andy Clark.  All rights reserved.\n \nRedistribution and use in source\
    \ and binary forms, with or without\nmodification, are permitted provided that\
    \ the following conditions\nare met:\n\n1. Redistributions of source code must\
    \ retain the above copyright\n   notice, this list of conditions and the following\
    \ disclaimer. \n\n2. Redistributions in binary form must reproduce the above copyright\n\
    \   notice, this list of conditions and the following disclaimer in\n   the documentation\
    \ and/or other materials provided with the\n   distribution.\n\n3. The end-user\
    \ documentation included with the redistribution,\n   if any, must include the\
    \ following acknowledgment:  \n     \"This product includes software developed\
    \ by Andy Clark.\"\n   Alternately, this acknowledgment may appear in the software\
    \ itself,\n   if and wherever such third-party acknowledgments normally appear.\n\
    \n4. The names \"CyberNeko\" and \"NekoHTML\" must not be used to endorse\n  \
    \ or promote products derived from this software without prior \n   written permission.\
    \ For written permission, please contact \n   andyc@cyberneko.net.\n\n5. Products\
    \ derived from this software may not be called \"CyberNeko\",\n   nor may \"CyberNeko\"\
    \ appear in their name, without prior written\n   permission of the author.\n\n\
    THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED\nWARRANTIES,\
    \ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\nOF MERCHANTABILITY AND\
    \ FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED.  IN NO EVENT SHALL THE AUTHOR\
    \ OR OTHER CONTRIBUTORS\nBE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\
    \ EXEMPLARY, \nOR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\
    \ \nOF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR \nBUSINESS\
    \ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, \nWHETHER IN CONTRACT,\
    \ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE \nOR OTHERWISE) ARISING IN ANY\
    \ WAY OUT OF THE USE OF THIS SOFTWARE, \nEVEN IF ADVISED OF THE POSSIBILITY OF\
    \ SUCH DAMAGE."
  name: "CyberNeko License"
  seeAlsos:
  - "http://people.apache.org/~andyc/neko/LICENSE"
  - "http://justasample.url.com"
annotations:
- annotationDate: "2010-01-29T18:30:22Z"
  annotationType: "OTHER"
  annotator: "Person: Jane Doe ()"
  comment: "Document level annotation"
- annotationDate: "2010-02-10T00:00:00Z"
  annotationType: "REVIEW"
  annotator: "Person: Joe Reviewer"
  comment: "This is just an example.  Some of the non-standard licenses look like\
    \ they are actually BSD 3 clause licenses"
- annotationDate: "2011-03-13T00:00:00Z"
  annotationType: "REVIEW"
  annotator: "Person: Suzanne Reviewer"
  comment: "Another example reviewer."
documentNamespace: "http://spdx.org/spdxdocs/spdx-example-444504E0-4F89-41D3-9A0C-0305E82C3301"
documentDescribes:
- "SPDXRef-File"
- "SPDXRef-Package"
packages:
- SPDXID: "SPDXRef-Package"
  annotations:
  - annotationDate: "2011-01-29T18:30:22Z"
    annotationType: "OTHER"
    annotator: "Person: Package Commenter"
    comment: "Package level annotation"
  attributionTexts:
  - "The GNU C Library is free software.  See the file COPYING.LIB for copying conditions,\
    \ and LICENSES for notices about a few contributions that require these additional\
    \ notices to be distributed.  License copyright years may be listed using range\
    \ notation, e.g., 1996-2015, indicating that every year in the range, inclusive,\
    \ is a copyrightable year that would otherwise be listed individually."
  checksums:
  - algorithm: "MD5"
    checksumValue: "624c1abb3664f4b35547e7c73864ad24"
  - algorithm: "SHA1"
    checksumValue: "85ed0817af83a24ad8da68c2b5094de69833983c"
  - algorithm: "SHA256"
    checksumValue: "11b6d3ee554eedf79299905a98f9b9a04e498210b59f15094c916c91d150efcd"
  copyrightText: "Copyright 2008-2010 John Smith"
  description: "The GNU C Library defines functions that are specified by the ISO\
    \ C standard, as well as additional features specific to POSIX and other derivatives\
    \ of the Unix operating system, and extensions specific to GNU systems."
  downloadLocation: "http://ftp.gnu.org/gnu/glibc/glibc-ports-2.15.tar.gz"
  externalRefs:
  - referenceCategory: "SECURITY"
    referenceLocator: "cpe:2.3:a:pivotal_software:spring_framework:4.1.0:*:*:*:*:*:*:*"
    referenceType: "cpe23Type"
  - comment: "This is the external ref for Acme"
    referenceCategory: "OTHER"
    referenceLocator: "acmecorp/acmenator/4.1.3-alpha"
    referenceType: "http://spdx.org/spdxdocs/spdx-example-444504E0-4F89-41D3-9A0C-0305E82C3301#LocationRef-acmeforge"
  filesAnalyzed: true
  hasFiles:
  - "SPDXRef-CommonsLangSrc"
  - "SPDXRef-JenaLib"
  - "SPDXRef-DoapSource"
  homepage: "http://ftp.gnu.org/gnu/glibc"
  licenseComments: "The license for this project changed with the release of version\
    \ x.y.  The version of the project included here post-dates the license change."
  licenseConcluded: "(LGPL-2.0-only OR LicenseRef-3)"
  licenseDeclared: "(LGPL-2.0-only AND LicenseRef-3)"
  licenseInfoFromFiles:
  - "GPL-2.0-only"
  - "LicenseRef-2"
  - "LicenseRef-1"
  name: "glibc"
  originator: "Organization: ExampleCodeInspect (contact@example.com)"
  packageFileName: "glibc-2.11.1.tar.gz"
  packageVerificationCode:
    packageVerificationCodeExcludedFiles:
    - "./package.spdx"
    packageVerificationCodeValue: "d6a770ba38583ed4bb4525bd96e50461655d2758"
  sourceInfo: "uses glibc-2_11-branch from git://sourceware.org/git/glibc.git."
  summary: "GNU C library."
  supplier: "Person: Jane Doe (jane.doe@example.com)"
  versionInfo: "2.11.1"
- SPDXID: "SPDXRef-fromDoap-1"
  copyrightText: "NOASSERTION"
  downloadLocation: "NOASSERTION"
  filesAnalyzed: false
  homepage: "http://commons.apache.org/proper/commons-lang/"
  licenseConcluded: "NOASSERTION"
  licenseDeclared: "NOASSERTION"
  name: "Apache Commons Lang"
- SPDXID: "SPDXRef-fromDoap-0"
  copyrightText: "NOASSERTION"
  downloadLocation: "https://search.maven.org/remotecontent?filepath=org/apache/jena/apache-jena/3.12.0/apache-jena-3.12.0.tar.gz"
  externalRefs:
  - referenceCategory: "PACKAGE_MANAGER"
    referenceLocator: "pkg:maven/org.apache.jena/apache-jena@3.12.0"
    referenceType: "purl"
  filesAnalyzed: false
  homepage: "http://www.openjena.org/"
  licenseConcluded: "NOASSERTION"
  licenseDeclared: "NOASSERTION"
  name: "Jena"
  versionInfo: "3.12.0"
- SPDXID: "SPDXRef-Saxon"
  checksums:
  - algorithm: "SHA1"
    checksumValue: "85ed0817af83a24ad8da68c2b5094de69833983c"
  copyrightText: "Copyright Saxonica Ltd"
  description: "The Saxon package is a collection of tools for processing XML documents."
  downloadLocation: "https://sourceforge.net/projects/saxon/files/Saxon-B/8.8.0.7/saxonb8-8-0-7j.zip/download"
  filesAnalyzed: false
  homepage: "http://saxon.sourceforge.net/"
  licenseComments: "Other versions available for a commercial license"
  licenseConcluded: "MPL-1.0"
  licenseDeclared: "MPL-1.0"
  name: "Saxon"
  packageFileName: "saxonB-8.8.zip"
  versionInfo: "8.8"
files:
- SPDXID: "SPDXRef-DoapSource"
  checksums:
  - algorithm: "SHA1"
    checksumValue: "2fd4e1c67a2d28fced849ee1bb76e7391b93eb12"
  copyrightText: "Copyright 2010, 2011 Source Auditor Inc."
  fileContributors:
  - "Protecode Inc."
  - "SPDX Technical Team Members"
  - "Open Logic Inc."
  - "Source Auditor Inc."
  - "Black Duck Software In.c"
  fileName: "./src/org/spdx/parser/DOAPProject.java"
  fileTypes:
  - "SOURCE"
  licenseConcluded: "Apache-2.0"
  licenseInfoInFiles:
  - "Apache-2.0"
- SPDXID: "SPDXRef-CommonsLangSrc"
  checksums:
  - algorithm: "SHA1"
    checksumValue: "c2b4e1c67a2d28fced849ee1bb76e7391b93f125"
  comment: "This file is used by Jena"
  copyrightText: "Copyright 2001-2011 The Apache Software Foundation"
  fileContributors:
  - "Apache Software Foundation"
  fileName: "./lib-source/commons-lang3-3.1-sources.jar"
  fileTypes:
  - "ARCHIVE"
  licenseConcluded: "Apache-2.0"
  licenseInfoInFiles:
  - "Apache-2.0"
  noticeText: "Apache Commons Lang\nCopyright 2001-2011 The Apache Software Foundation\n\
    \nThis product includes software developed by\nThe Apache Software Foundation\
    \ (http://www.apache.org/).\n\nThis product includes software from the Spring\
    \ Framework,\nunder the Apache License 2.0 (see: StringUtils.containsWhitespace())"
- SPDXID: "SPDXRef-JenaLib"
  checksums:
  - algorithm: "SHA1"
    checksumValue: "3ab4e1c67a2d28fced849ee1bb76e7391b93f125"
  comment: "This file belongs to Jena"
  copyrightText: "(c) Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,\
    \ 2009 Hewlett-Packard Development Company, LP"
  fileContributors:
  - "Apache Software Foundation"
  - "Hewlett Packard Inc."
  fileName: "./lib-source/jena-2.6.3-sources.jar"
  fileTypes:
  - "ARCHIVE"
  licenseComments: "This license is used by Jena"
  licenseConcluded: "LicenseRef-1"
  licenseInfoInFiles:
  - "LicenseRef-1"
- SPDXID: "SPDXRef-File"
  annotations:
  - annotationDate: "2011-01-29T18:30:22Z"
    annotationType: "OTHER"
    annotator: "Person: File Commenter"
    comment: "File level annotation"
  checksums:
  - algorithm: "SHA1"
    checksumValue: "d6a770ba38583ed4bb4525bd96e50461655d2758"
  - algorithm: "MD5"
    checksumValue: "624c1abb3664f4b35547e7c73864ad24"
  comment: "The concluded license was taken from the package level that the file was\
    \ included in.\nThis information was found in the COPYING.txt file in the xyz\
    \ directory."
  copyrightText: "Copyright 2008-2010 John Smith"
  fileContributors:
  - "The Regents of the University of California"
  - "Modified by Paul Mundt lethal@linux-sh.org"
  - "IBM Corporation"
  fileName: "./package/foo.c"
  fileTypes:
  - "SOURCE"
  licenseComments: "The concluded license was taken from the package level that the\
    \ file was included in."
  licenseConcluded: "(LGPL-2.0-only OR LicenseRef-2)"
  licenseInfoInFiles:
  - "GPL-2.0-only"
  - "LicenseRef-2"
  noticeText: "Copyright (c) 2001 Aaron Lehmann aaroni@vitelus.com\n\nPermission is\
    \ hereby granted, free of charge, to any person obtaining a copy of this software\
    \ and associated documentation files (the �Software�), to deal in the Software\
    \ without restriction, including without limitation the rights to use, copy, modify,\
    \ merge, publish, distribute, sublicense, and/or sell copies of the Software,\
    \ and to permit persons to whom the Software is furnished to do so, subject to\
    \ the following conditions: \nThe above copyright notice and this permission notice\
    \ shall be included in all copies or substantial portions of the Software.\n\n\
    THE SOFTWARE IS PROVIDED �AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\
    \ INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR\
    \ A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR\
    \ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\
    \ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\
    \ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE."
snippets:
- SPDXID: "SPDXRef-Snippet"
  comment: "This snippet was identified as significant and highlighted in this Apache-2.0\
    \ file, when a commercial scanner identified it as being derived from file foo.c\
    \ in package xyz which is licensed under GPL-2.0."
  copyrightText: "Copyright 2008-2010 John Smith"
  licenseComments: "The concluded license was taken from package xyz, from which the\
    \ snippet was copied into the current file. The concluded license information\
    \ was found in the COPYING.txt file in package xyz."
  licenseConcluded: "GPL-2.0-only"
  licenseInfoInSnippets:
  - "GPL-2.0-only"
  name: "from linux kernel"
  ranges:
  - endPointer:
      offset: 420
      reference: "SPDXRef-DoapSource"
    startPointer:
      offset: 310
      reference: "SPDXRef-DoapSource"
  - endPointer:
      lineNumber: 23
      reference: "SPDXRef-DoapSource"
    startPointer:
      lineNumber: 5
      reference: "SPDXRef-DoapSource"
  snippetFromFile: "SPDXRef-DoapSource"
relationships:
- spdxElementId: "SPDXRef-DOCUMENT"
  relatedSpdxElement: "SPDXRef-Package"
  relationshipType: "CONTAINS"
- spdxElementId: "SPDXRef-DOCUMENT"
  relatedSpdxElement: "DocumentRef-spdx-tool-1.2:SPDXRef-ToolsElement"
  relationshipType: "COPY_OF"
- spdxElementId: "SPDXRef-DOCUMENT"
  relatedSpdxElement: "SPDXRef-File"
  relationshipType: "DESCRIBES"
- spdxElementId: "SPDXRef-DOCUMENT"
  relatedSpdxElement: "SPDXRef-Package"
  relationshipType: "DESCRIBES"
- spdxElementId: "SPDXRef-Package"
  relatedSpdxElement: "SPDXRef-JenaLib"
  relationshipType: "CONTAINS"
- spdxElementId: "SPDXRef-Package"
  relatedSpdxElement: "SPDXRef-Saxon"
  relationshipType: "DYNAMIC_LINK"
- spdxElementId: "SPDXRef-CommonsLangSrc"
  relatedSpdxElement: "NOASSERTION"
  relationshipType: "GENERATED_FROM"
- spdxElementId: "SPDXRef-JenaLib"
  relatedSpdxElement: "SPDXRef-Package"
  relationshipType: "CONTAINS"
- spdxElementId: "SPDXRef-File"
  relatedSpdxElement: "SPDXRef-fromDoap-0"
  relationshipType: "GENERATED_FROM"

tests/data/formats/SPDXXmlExample.xml METASEP
<?xml version="1.0" encoding="utf-8"?>
	<Document>
		<comment>This is a sample spreadsheet</comment>
		<name>Sample_Document-V2.1</name>
        <documentDescribes>SPDXRef-Package</documentDescribes>
        <packages>
            <SPDXID>SPDXRef-Package</SPDXID>
            <originator>Organization: SPDX</originator>
             <attributionTexts>The GNU C Library is free software.  See the file COPYING.LIB for copying conditions, and LICENSES for notices about a few contributions that require these additional notices to be distributed.  License copyright years may be listed using range notation, e.g., 1996-2015, indicating that every year in the range, inclusive, is a copyrightable year that would otherwise be listed individually.</attributionTexts>
            <licenseInfoFromFiles>LicenseRef-3</licenseInfoFromFiles>
            <licenseInfoFromFiles>LicenseRef-1</licenseInfoFromFiles>
            <licenseInfoFromFiles>Apache-1.0</licenseInfoFromFiles>
            <licenseInfoFromFiles>LicenseRef-4</licenseInfoFromFiles>
            <licenseInfoFromFiles>Apache-2.0</licenseInfoFromFiles>
            <licenseInfoFromFiles>LicenseRef-2</licenseInfoFromFiles>
            <licenseInfoFromFiles>MPL-1.1</licenseInfoFromFiles>
            <name>SPDX Translator</name>
            <hasFiles>SPDXRef-File1</hasFiles>
            <hasFiles>SPDXRef-File2</hasFiles>
            <packageFileName>spdxtranslator-1.0.zip</packageFileName>
            <licenseComments>The declared license information can be found in the NOTICE file at the root of the archive file</licenseComments>
            <summary>SPDX Translator utility</summary>
            <sourceInfo>Version 1.0 of the SPDX Translator application</sourceInfo>
            <copyrightText> Copyright 2010, 2011 Source Auditor Inc.</copyrightText>
            <packageVerificationCode>
                <packageVerificationCodeValue>4e3211c67a2d28fced849ee1bb76e7391b93feba</packageVerificationCodeValue>
                <packageVerificationCodeExcludedFiles>SpdxTranslatorSpdx.rdf</packageVerificationCodeExcludedFiles>
                <packageVerificationCodeExcludedFiles>SpdxTranslatorSpdx.txt</packageVerificationCodeExcludedFiles>
            </packageVerificationCode>
            <licenseConcluded>(LicenseRef-1 AND MPL-1.1 AND LicenseRef-2 AND LicenseRef-3 AND Apache-2.0 AND LicenseRef-4 AND Apache-1.0)</licenseConcluded>
            <supplier>Organization: Linux Foundation</supplier>
            <checksums>
                <checksumValue>2fd4e1c67a2d28fced849ee1bb76e7391b93eb12</checksumValue>
                <algorithm>SHA1</algorithm>
            </checksums>
            <versionInfo>Version 0.9.2</versionInfo>
            <licenseDeclared>(LicenseRef-3 AND LicenseRef-2 AND Apache-2.0 AND MPL-1.1 AND LicenseRef-1 AND LicenseRef-4)</licenseDeclared>
            <downloadLocation>http://www.spdx.org/tools</downloadLocation>
            <description>This utility translates and SPDX RDF XML document to a spreadsheet, translates a spreadsheet to an SPDX RDF XML document and translates an SPDX RDFa document to an SPDX RDF XML document.</description>
            <primaryPackagePurpose>OPERATING-SYSTEM</primaryPackagePurpose>
            <builtDate>2020-01-01T12:00:00Z</builtDate>
            <releaseDate>2021-01-01T12:00:00Z</releaseDate>
            <validUntilDate>2022-01-01T12:00:00Z</validUntilDate>
        </packages>
		<creationInfo>
			<comment>This is an example of an SPDX spreadsheet format</comment>
			<creators>Tool: SourceAuditor-V1.2</creators>
			<creators>Person: Gary O'Neall</creators>
			<creators>Organization: Source Auditor Inc.</creators>
			<licenseListVersion>3.6</licenseListVersion>
			<created>2010-02-03T00:00:00Z</created>
		</creationInfo>
		<externalDocumentRefs>
			<checksum>
				<checksumValue>d6a770ba38583ed4bb4525bd96e50461655d2759</checksumValue>
				<algorithm>SHA1</algorithm>
			</checksum>
			<spdxDocument>https://spdx.org/spdxdocs/spdx-tools-v2.1-3F2504E0-4F89-41D3-9A0C-0305E82C3301</spdxDocument>
			<externalDocumentId>DocumentRef-spdx-tool-2.1</externalDocumentId>
		</externalDocumentRefs>
		<documentNamespace>https://spdx.org/spdxdocs/spdx-example-444504E0-4F89-41D3-9A0C-0305E82C3301</documentNamespace>
		<annotations>
			<comment>This is just an example. Some of the non-standard licenses look like they are actually BSD 3 clause licenses</comment>
			<annotationType>REVIEW</annotationType>
			<annotationDate>2012-06-13T00:00:00Z</annotationDate>
			<annotator>Person: Jim Reviewer</annotator>
		</annotations>
        <dataLicense>CC0-1.0</dataLicense>
		<reviewers>
			<comment>This is just an example.  Some of the non-standard licenses look like they are actually BSD 3 clause licenses</comment>
			<reviewer>Person: Joe Reviewer</reviewer>
			<reviewDate>2010-02-10T00:00:00Z</reviewDate>
		</reviewers>
		<reviewers>
			<comment>Another example reviewer.</comment>
			<reviewer>Person: Suzanne Reviewer</reviewer>
			<reviewDate>2011-03-13T00:00:00Z</reviewDate>
		</reviewers>
		<hasExtractedLicensingInfos>
			<extractedText>/*
 * (c) Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Hewlett-Packard Development Company, LP
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */</extractedText>
			<licenseId>LicenseRef-1</licenseId>
		</hasExtractedLicensingInfos>
		<hasExtractedLicensingInfos>
			<extractedText>This package includes the GRDDL parser developed by Hewlett Packard under the following license:
© Copyright 2007 Hewlett-Packard Development Company, LP

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. </extractedText>
			<licenseId>LicenseRef-2</licenseId>
		</hasExtractedLicensingInfos>
		<hasExtractedLicensingInfos>
			<extractedText>The CyberNeko Software License, Version 1.0


(C) Copyright 2002-2005, Andy Clark.  All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

1. Redistributions of source code must retain the above copyright
   notice, this list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright
   notice, this list of conditions and the following disclaimer in
   the documentation and/or other materials provided with the
   distribution.

3. The end-user documentation included with the redistribution,
   if any, must include the following acknowledgment:
     "This product includes software developed by Andy Clark."
   Alternately, this acknowledgment may appear in the software itself,
   if and wherever such third-party acknowledgments normally appear.

4. The names "CyberNeko" and "NekoHTML" must not be used to endorse
   or promote products derived from this software without prior
   written permission. For written permission, please contact
   andyc@cyberneko.net.

5. Products derived from this software may not be called "CyberNeko",
   nor may "CyberNeko" appear in their name, without prior written
   permission of the author.

THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.</extractedText>
			<comment>This is tye CyperNeko License</comment>
			<licenseId>LicenseRef-3</licenseId>
			<name>CyberNeko License</name>
			<seeAlsos>http://justasample.url.com</seeAlsos>
			<seeAlsos>http://people.apache.org/~andyc/neko/LICENSE</seeAlsos>
		</hasExtractedLicensingInfos>
		<hasExtractedLicensingInfos>
			<extractedText>/*
 * (c) Copyright 2009 University of Bristol
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */  </extractedText>
			<licenseId>LicenseRef-4</licenseId>
		</hasExtractedLicensingInfos>
		<spdxVersion>SPDX-2.1</spdxVersion>
		<SPDXID>SPDXRef-DOCUMENT</SPDXID>
        <files>
            <licenseInfoInFiles>Apache-2.0</licenseInfoInFiles>
            <fileName>src/org/spdx/parser/DOAPProject.java</fileName>
            <copyrightText>Copyright 2010, 2011 Source Auditor Inc.</copyrightText>
            <licenseConcluded>Apache-2.0</licenseConcluded>
            <licenseComments></licenseComments>
            <checksums>
                <checksumValue>2fd4e1c67a2d28fced849ee1bb76e7391b93eb12</checksumValue>
                <algorithm>SHA1</algorithm>
            </checksums>
            <fileTypes>SOURCE</fileTypes>
            <fileTypes>TEXT</fileTypes>
            <SPDXID>SPDXRef-File2</SPDXID>
        </files>
        <files>
            <comment>This file belongs to Jena</comment>
            <licenseInfoInFiles>LicenseRef-1</licenseInfoInFiles>
            <fileName>Jenna-2.6.3/jena-2.6.3-sources.jar</fileName>
            <copyrightText>(c) Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Hewlett-Packard Development Company, LP</copyrightText>
            <artifactOf>
                <name>Jena</name>
                <homePage>http://www.openjena.org/</homePage>
                <projectUri>http://subversion.apache.org/doap.rdf</projectUri>
            </artifactOf>
            <licenseConcluded>LicenseRef-1</licenseConcluded>
            <licenseComments>This license is used by Jena</licenseComments>
            <checksums>
                <checksumValue>3ab4e1c67a2d28fced849ee1bb76e7391b93f125</checksumValue>
                <algorithm>SHA1</algorithm>
            </checksums>
            <checksums>
                <checksumValue>3ab4e1c67a2d28fced849ee1bb76e7391b93f1250000000000000000</checksumValue>
                <algorithm>SHA256</algorithm>
            </checksums>
            <fileTypes>ARCHIVE</fileTypes>
            <fileTypes>OTHER</fileTypes>
            <SPDXID>SPDXRef-File1</SPDXID>
        </files>
		<snippets>
			<comment>This snippet was identified as significant and highlighted in this Apache-2.0 file, when a commercial scanner identified it as being derived from file foo.c in package xyz which is licensed under GPL-2.0-or-later.</comment>
			<name>from linux kernel</name>
			<copyrightText>Copyright 2008-2010 John Smith</copyrightText>
			<licenseConcluded>Apache-2.0</licenseConcluded>
			<licenseInfoInSnippets>Apache-2.0</licenseInfoInSnippets>
			<licenseInfoInSnippets>GPL-2.0-only</licenseInfoInSnippets>
			<licenseComments>The concluded license was taken from package xyz, from which the snippet was copied into the current file. The concluded license information was found in the COPYING.txt file in package xyz.</licenseComments>
			<SPDXID>SPDXRef-Snippet</SPDXID>
			<snippetFromFile>SPDXRef-DoapSource</snippetFromFile>
            <ranges>
                <endPointer>
                    <offset>420</offset>
                    <reference>SPDXRef-DoapSource</reference>
                </endPointer>
                <startPointer>
                    <offset>310</offset>
                    <reference>SPDXRef-DoapSource</reference>
                </startPointer>
            </ranges>
            <ranges>
                <endPointer>
                    <lineNumber>23</lineNumber>
                    <reference>SPDXRef-DoapSource</reference>
                </endPointer>
                <startPointer>
                    <lineNumber>5</lineNumber>
                    <reference>SPDXRef-DoapSource</reference>
                </startPointer>
            </ranges>
        </snippets>
	</Document>

tests/data/formats/SPDXXMLExample-v2.3.spdx.xml METASEP
<?xml version='1.0' encoding='UTF-8'?>
<Document>
  <SPDXID>SPDXRef-DOCUMENT</SPDXID>
  <spdxVersion>SPDX-2.3</spdxVersion>
  <creationInfo>
    <comment>This package has been shipped in source and binary form.
The binaries were created with gcc 4.5.1 and expect to link to
compatible system run time libraries.</comment>
    <created>2010-01-29T18:30:22Z</created>
    <creators>Tool: LicenseFind-1.0</creators>
    <creators>Organization: ExampleCodeInspect ()</creators>
    <creators>Person: Jane Doe ()</creators>
    <licenseListVersion>3.17</licenseListVersion>
  </creationInfo>
  <name>SPDX-Tools-v2.0</name>
  <dataLicense>CC0-1.0</dataLicense>
  <comment>This document was created using SPDX 2.0 using licenses from the web site.</comment>
  <externalDocumentRefs>
    <externalDocumentId>DocumentRef-spdx-tool-1.2</externalDocumentId>
    <checksum>
      <algorithm>SHA1</algorithm>
      <checksumValue>d6a770ba38583ed4bb4525bd96e50461655d2759</checksumValue>
    </checksum>
    <spdxDocument>http://spdx.org/spdxdocs/spdx-tools-v1.2-3F2504E0-4F89-41D3-9A0C-0305E82C3301</spdxDocument>
  </externalDocumentRefs>
  <hasExtractedLicensingInfos>
    <licenseId>LicenseRef-1</licenseId>
    <extractedText>/*
 * (c) Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Hewlett-Packard Development Company, LP
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/</extractedText>
  </hasExtractedLicensingInfos>
  <hasExtractedLicensingInfos>
    <licenseId>LicenseRef-2</licenseId>
    <extractedText>This package includes the GRDDL parser developed by Hewlett Packard under the following license:
© Copyright 2007 Hewlett-Packard Development Company, LP

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 

Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 
Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 
The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. 
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.</extractedText>
  </hasExtractedLicensingInfos>
  <hasExtractedLicensingInfos>
    <licenseId>LicenseRef-4</licenseId>
    <extractedText>/*
 * (c) Copyright 2009 University of Bristol
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/</extractedText>
  </hasExtractedLicensingInfos>
  <hasExtractedLicensingInfos>
    <licenseId>LicenseRef-Beerware-4.2</licenseId>
    <comment>The beerware license has a couple of other standard variants.</comment>
    <extractedText>"THE BEER-WARE LICENSE" (Revision 42):
phk@FreeBSD.ORG wrote this file. As long as you retain this notice you
can do whatever you want with this stuff. If we meet some day, and you think this stuff is worth it, you can buy me a beer in return Poul-Henning Kamp</extractedText>
    <name>Beer-Ware License (Version 42)</name>
    <seeAlsos>http://people.freebsd.org/~phk/</seeAlsos>
  </hasExtractedLicensingInfos>
  <hasExtractedLicensingInfos>
    <licenseId>LicenseRef-3</licenseId>
    <comment>This is tye CyperNeko License</comment>
    <extractedText>The CyberNeko Software License, Version 1.0

 
(C) Copyright 2002-2005, Andy Clark.  All rights reserved.
 
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

1. Redistributions of source code must retain the above copyright
   notice, this list of conditions and the following disclaimer. 

2. Redistributions in binary form must reproduce the above copyright
   notice, this list of conditions and the following disclaimer in
   the documentation and/or other materials provided with the
   distribution.

3. The end-user documentation included with the redistribution,
   if any, must include the following acknowledgment:  
     "This product includes software developed by Andy Clark."
   Alternately, this acknowledgment may appear in the software itself,
   if and wherever such third-party acknowledgments normally appear.

4. The names "CyberNeko" and "NekoHTML" must not be used to endorse
   or promote products derived from this software without prior 
   written permission. For written permission, please contact 
   andyc@cyberneko.net.

5. Products derived from this software may not be called "CyberNeko",
   nor may "CyberNeko" appear in their name, without prior written
   permission of the author.

THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.</extractedText>
    <name>CyberNeko License</name>
    <seeAlsos>http://people.apache.org/~andyc/neko/LICENSE</seeAlsos>
    <seeAlsos>http://justasample.url.com</seeAlsos>
  </hasExtractedLicensingInfos>
  <annotations>
    <annotationDate>2010-01-29T18:30:22Z</annotationDate>
    <annotationType>OTHER</annotationType>
    <annotator>Person: Jane Doe ()</annotator>
    <comment>Document level annotation</comment>
  </annotations>
  <annotations>
    <annotationDate>2010-02-10T00:00:00Z</annotationDate>
    <annotationType>REVIEW</annotationType>
    <annotator>Person: Joe Reviewer</annotator>
    <comment>This is just an example.  Some of the non-standard licenses look like they are actually BSD 3 clause licenses</comment>
  </annotations>
  <annotations>
    <annotationDate>2011-03-13T00:00:00Z</annotationDate>
    <annotationType>REVIEW</annotationType>
    <annotator>Person: Suzanne Reviewer</annotator>
    <comment>Another example reviewer.</comment>
  </annotations>
  <documentDescribes>SPDXRef-File</documentDescribes>
  <documentDescribes>SPDXRef-Package</documentDescribes>
  <documentNamespace>http://spdx.org/spdxdocs/spdx-example-444504E0-4F89-41D3-9A0C-0305E82C3301</documentNamespace>
  <packages>
    <SPDXID>SPDXRef-Package</SPDXID>
    <annotations>
      <annotationDate>2011-01-29T18:30:22Z</annotationDate>
      <annotationType>OTHER</annotationType>
      <annotator>Person: Package Commenter</annotator>
      <comment>Package level annotation</comment>
    </annotations>
    <attributionTexts>The GNU C Library is free software.  See the file COPYING.LIB for copying conditions, and LICENSES for notices about a few contributions that require these additional notices to be distributed.  License copyright years may be listed using range notation, e.g., 1996-2015, indicating that every year in the range, inclusive, is a copyrightable year that would otherwise be listed individually.</attributionTexts>
    <builtDate>2011-01-29T18:30:22Z</builtDate>
    <checksums>
      <algorithm>MD5</algorithm>
      <checksumValue>624c1abb3664f4b35547e7c73864ad24</checksumValue>
    </checksums>
    <checksums>
      <algorithm>SHA1</algorithm>
      <checksumValue>85ed0817af83a24ad8da68c2b5094de69833983c</checksumValue>
    </checksums>
    <checksums>
      <algorithm>SHA256</algorithm>
      <checksumValue>11b6d3ee554eedf79299905a98f9b9a04e498210b59f15094c916c91d150efcd</checksumValue>
    </checksums>
    <checksums>
      <algorithm>BLAKE2b-384</algorithm>
      <checksumValue>aaabd89c926ab525c242e6621f2f5fa73aa4afe3d9e24aed727faaadd6af38b620bdb623dd2b4788b1c8086984af8706</checksumValue>
    </checksums>
    <copyrightText>Copyright 2008-2010 John Smith</copyrightText>
    <description>The GNU C Library defines functions that are specified by the ISO C standard, as well as additional features specific to POSIX and other derivatives of the Unix operating system, and extensions specific to GNU systems.</description>
    <downloadLocation>http://ftp.gnu.org/gnu/glibc/glibc-ports-2.15.tar.gz</downloadLocation>
    <externalRefs>
      <referenceCategory>SECURITY</referenceCategory>
      <referenceLocator>cpe:2.3:a:pivotal_software:spring_framework:4.1.0:*:*:*:*:*:*:*</referenceLocator>
      <referenceType>cpe23Type</referenceType>
    </externalRefs>
    <externalRefs>
      <comment>This is the external ref for Acme</comment>
      <referenceCategory>OTHER</referenceCategory>
      <referenceLocator>acmecorp/acmenator/4.1.3-alpha</referenceLocator>
      <referenceType>http://spdx.org/spdxdocs/spdx-example-444504E0-4F89-41D3-9A0C-0305E82C3301#LocationRef-acmeforge</referenceType>
    </externalRefs>
    <filesAnalyzed>true</filesAnalyzed>
    <homepage>http://ftp.gnu.org/gnu/glibc</homepage>
    <licenseComments>The license for this project changed with the release of version x.y.  The version of the project included here post-dates the license change.</licenseComments>
    <licenseConcluded>(LGPL-2.0-only OR LicenseRef-3)</licenseConcluded>
    <licenseDeclared>(LGPL-2.0-only AND LicenseRef-3)</licenseDeclared>
    <licenseInfoFromFiles>GPL-2.0-only</licenseInfoFromFiles>
    <licenseInfoFromFiles>LicenseRef-2</licenseInfoFromFiles>
    <licenseInfoFromFiles>LicenseRef-1</licenseInfoFromFiles>
    <name>glibc</name>
    <originator>Organization: ExampleCodeInspect (contact@example.com)</originator>
    <packageFileName>glibc-2.11.1.tar.gz</packageFileName>
    <packageVerificationCode>
      <packageVerificationCodeExcludedFiles>./package.spdx</packageVerificationCodeExcludedFiles>
      <packageVerificationCodeValue>d6a770ba38583ed4bb4525bd96e50461655d2758</packageVerificationCodeValue>
    </packageVerificationCode>
    <primaryPackagePurpose>SOURCE</primaryPackagePurpose>
    <hasFiles>SPDXRef-Specification</hasFiles>
    <hasFiles>SPDXRef-Specification</hasFiles>
    <hasFiles>SPDXRef-CommonsLangSrc</hasFiles>
    <hasFiles>SPDXRef-Specification</hasFiles>
    <hasFiles>SPDXRef-CommonsLangSrc</hasFiles>
    <hasFiles>SPDXRef-JenaLib</hasFiles>
    <hasFiles>SPDXRef-Specification</hasFiles>
    <hasFiles>SPDXRef-CommonsLangSrc</hasFiles>
    <hasFiles>SPDXRef-JenaLib</hasFiles>
    <hasFiles>SPDXRef-DoapSource</hasFiles>
    <hasFiles>SPDXRef-Specification</hasFiles>
    <hasFiles>SPDXRef-CommonsLangSrc</hasFiles>
    <hasFiles>SPDXRef-JenaLib</hasFiles>
    <hasFiles>SPDXRef-DoapSource</hasFiles>
    <releaseDate>2012-01-29T18:30:22Z</releaseDate>
    <sourceInfo>uses glibc-2_11-branch from git://sourceware.org/git/glibc.git.</sourceInfo>
    <summary>GNU C library.</summary>
    <supplier>Person: Jane Doe (jane.doe@example.com)</supplier>
    <validUntilDate>2014-01-29T18:30:22Z</validUntilDate>
    <versionInfo>2.11.1</versionInfo>
  </packages>
  <packages>
    <SPDXID>SPDXRef-fromDoap-1</SPDXID>
    <copyrightText>NOASSERTION</copyrightText>
    <downloadLocation>NOASSERTION</downloadLocation>
    <filesAnalyzed>false</filesAnalyzed>
    <homepage>http://commons.apache.org/proper/commons-lang/</homepage>
    <licenseConcluded>NOASSERTION</licenseConcluded>
    <licenseDeclared>NOASSERTION</licenseDeclared>
    <name>Apache Commons Lang</name>
  </packages>
  <packages>
    <SPDXID>SPDXRef-fromDoap-0</SPDXID>
    <downloadLocation>https://search.maven.org/remotecontent?filepath=org/apache/jena/apache-jena/3.12.0/apache-jena-3.12.0.tar.gz</downloadLocation>
    <externalRefs>
      <referenceCategory>PACKAGE-MANAGER</referenceCategory>
      <referenceLocator>pkg:maven/org.apache.jena/apache-jena@3.12.0</referenceLocator>
      <referenceType>purl</referenceType>
    </externalRefs>
    <filesAnalyzed>false</filesAnalyzed>
    <homepage>http://www.openjena.org/</homepage>
    <name>Jena</name>
    <versionInfo>3.12.0</versionInfo>
  </packages>
  <packages>
    <SPDXID>SPDXRef-Saxon</SPDXID>
    <checksums>
      <algorithm>SHA1</algorithm>
      <checksumValue>85ed0817af83a24ad8da68c2b5094de69833983c</checksumValue>
    </checksums>
    <copyrightText>Copyright Saxonica Ltd</copyrightText>
    <description>The Saxon package is a collection of tools for processing XML documents.</description>
    <downloadLocation>https://sourceforge.net/projects/saxon/files/Saxon-B/8.8.0.7/saxonb8-8-0-7j.zip/download</downloadLocation>
    <filesAnalyzed>false</filesAnalyzed>
    <homepage>http://saxon.sourceforge.net/</homepage>
    <licenseComments>Other versions available for a commercial license</licenseComments>
    <licenseConcluded>MPL-1.0</licenseConcluded>
    <licenseDeclared>MPL-1.0</licenseDeclared>
    <name>Saxon</name>
    <packageFileName>saxonB-8.8.zip</packageFileName>
    <versionInfo>8.8</versionInfo>
  </packages>
  <files>
    <SPDXID>SPDXRef-DoapSource</SPDXID>
    <checksums>
      <algorithm>SHA1</algorithm>
      <checksumValue>2fd4e1c67a2d28fced849ee1bb76e7391b93eb12</checksumValue>
    </checksums>
    <copyrightText>Copyright 2010, 2011 Source Auditor Inc.</copyrightText>
    <fileContributors>Protecode Inc.</fileContributors>
    <fileContributors>SPDX Technical Team Members</fileContributors>
    <fileContributors>Open Logic Inc.</fileContributors>
    <fileContributors>Source Auditor Inc.</fileContributors>
    <fileContributors>Black Duck Software In.c</fileContributors>
    <fileName>./src/org/spdx/parser/DOAPProject.java</fileName>
    <fileTypes>SOURCE</fileTypes>
    <licenseConcluded>Apache-2.0</licenseConcluded>
    <licenseInfoInFiles>Apache-2.0</licenseInfoInFiles>
  </files>
  <files>
    <SPDXID>SPDXRef-CommonsLangSrc</SPDXID>
    <checksums>
      <algorithm>SHA1</algorithm>
      <checksumValue>c2b4e1c67a2d28fced849ee1bb76e7391b93f125</checksumValue>
    </checksums>
    <comment>This file is used by Jena</comment>
    <copyrightText>Copyright 2001-2011 The Apache Software Foundation</copyrightText>
    <fileContributors>Apache Software Foundation</fileContributors>
    <fileName>./lib-source/commons-lang3-3.1-sources.jar</fileName>
    <fileTypes>ARCHIVE</fileTypes>
    <licenseConcluded>Apache-2.0</licenseConcluded>
    <licenseInfoInFiles>Apache-2.0</licenseInfoInFiles>
    <noticeText>Apache Commons Lang
Copyright 2001-2011 The Apache Software Foundation

This product includes software developed by
The Apache Software Foundation (http://www.apache.org/).

This product includes software from the Spring Framework,
under the Apache License 2.0 (see: StringUtils.containsWhitespace())</noticeText>
  </files>
  <files>
    <SPDXID>SPDXRef-JenaLib</SPDXID>
    <checksums>
      <algorithm>SHA1</algorithm>
      <checksumValue>3ab4e1c67a2d28fced849ee1bb76e7391b93f125</checksumValue>
    </checksums>
    <comment>This file belongs to Jena</comment>
    <copyrightText>(c) Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Hewlett-Packard Development Company, LP</copyrightText>
    <fileContributors>Apache Software Foundation</fileContributors>
    <fileContributors>Hewlett Packard Inc.</fileContributors>
    <fileName>./lib-source/jena-2.6.3-sources.jar</fileName>
    <fileTypes>ARCHIVE</fileTypes>
    <licenseComments>This license is used by Jena</licenseComments>
    <licenseConcluded>LicenseRef-1</licenseConcluded>
    <licenseInfoInFiles>LicenseRef-1</licenseInfoInFiles>
  </files>
  <files>
    <SPDXID>SPDXRef-Specification</SPDXID>
    <checksums>
      <algorithm>SHA1</algorithm>
      <checksumValue>fff4e1c67a2d28fced849ee1bb76e7391b93f125</checksumValue>
    </checksums>
    <comment>Specification Documentation</comment>
    <fileName>./docs/myspec.pdf</fileName>
    <fileTypes>DOCUMENTATION</fileTypes>
  </files>
  <files>
    <SPDXID>SPDXRef-File</SPDXID>
    <annotations>
      <annotationDate>2011-01-29T18:30:22Z</annotationDate>
      <annotationType>OTHER</annotationType>
      <annotator>Person: File Commenter</annotator>
      <comment>File level annotation</comment>
    </annotations>
    <checksums>
      <algorithm>SHA1</algorithm>
      <checksumValue>d6a770ba38583ed4bb4525bd96e50461655d2758</checksumValue>
    </checksums>
    <checksums>
      <algorithm>MD5</algorithm>
      <checksumValue>624c1abb3664f4b35547e7c73864ad24</checksumValue>
    </checksums>
    <comment>The concluded license was taken from the package level that the file was included in.
This information was found in the COPYING.txt file in the xyz directory.</comment>
    <copyrightText>Copyright 2008-2010 John Smith</copyrightText>
    <fileContributors>The Regents of the University of California</fileContributors>
    <fileContributors>Modified by Paul Mundt lethal@linux-sh.org</fileContributors>
    <fileContributors>IBM Corporation</fileContributors>
    <fileName>./package/foo.c</fileName>
    <fileTypes>SOURCE</fileTypes>
    <licenseComments>The concluded license was taken from the package level that the file was included in.</licenseComments>
    <licenseConcluded>(LGPL-2.0-only OR LicenseRef-2)</licenseConcluded>
    <licenseInfoInFiles>GPL-2.0-only</licenseInfoInFiles>
    <licenseInfoInFiles>LicenseRef-2</licenseInfoInFiles>
    <noticeText>Copyright (c) 2001 Aaron Lehmann aaroni@vitelus.com

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.</noticeText>
  </files>
  <snippets>
    <SPDXID>SPDXRef-Snippet</SPDXID>
    <comment>This snippet was identified as significant and highlighted in this Apache-2.0 file, when a commercial scanner identified it as being derived from file foo.c in package xyz which is licensed under GPL-2.0.</comment>
    <copyrightText>Copyright 2008-2010 John Smith</copyrightText>
    <licenseComments>The concluded license was taken from package xyz, from which the snippet was copied into the current file. The concluded license information was found in the COPYING.txt file in package xyz.</licenseComments>
    <licenseConcluded>GPL-2.0-only</licenseConcluded>
    <licenseInfoInSnippets>GPL-2.0-only</licenseInfoInSnippets>
    <name>from linux kernel</name>
    <ranges>
      <endPointer>
        <offset>420</offset>
        <reference>SPDXRef-DoapSource</reference>
      </endPointer>
      <startPointer>
        <offset>310</offset>
        <reference>SPDXRef-DoapSource</reference>
      </startPointer>
    </ranges>
    <ranges>
      <endPointer>
        <lineNumber>23</lineNumber>
        <reference>SPDXRef-DoapSource</reference>
      </endPointer>
      <startPointer>
        <lineNumber>5</lineNumber>
        <reference>SPDXRef-DoapSource</reference>
      </startPointer>
    </ranges>
    <snippetFromFile>SPDXRef-DoapSource</snippetFromFile>
  </snippets>
  <relationships>
    <spdxElementId>SPDXRef-DOCUMENT</spdxElementId>
    <relationshipType>CONTAINS</relationshipType>
    <relatedSpdxElement>SPDXRef-Package</relatedSpdxElement>
  </relationships>
  <relationships>
    <spdxElementId>SPDXRef-DOCUMENT</spdxElementId>
    <relationshipType>COPY_OF</relationshipType>
    <relatedSpdxElement>DocumentRef-spdx-tool-1.2:SPDXRef-ToolsElement</relatedSpdxElement>
  </relationships>
  <relationships>
    <spdxElementId>SPDXRef-Package</spdxElementId>
    <relationshipType>DYNAMIC_LINK</relationshipType>
    <relatedSpdxElement>SPDXRef-Saxon</relatedSpdxElement>
  </relationships>
  <relationships>
    <spdxElementId>SPDXRef-CommonsLangSrc</spdxElementId>
    <relationshipType>GENERATED_FROM</relationshipType>
    <relatedSpdxElement>NOASSERTION</relatedSpdxElement>
  </relationships>
  <relationships>
    <spdxElementId>SPDXRef-JenaLib</spdxElementId>
    <relationshipType>CONTAINS</relationshipType>
    <relatedSpdxElement>SPDXRef-Package</relatedSpdxElement>
  </relationships>
  <relationships>
    <spdxElementId>SPDXRef-Specification</spdxElementId>
    <relationshipType>SPECIFICATION_FOR</relationshipType>
    <relatedSpdxElement>SPDXRef-fromDoap-0</relatedSpdxElement>
  </relationships>
  <relationships>
    <spdxElementId>SPDXRef-File</spdxElementId>
    <relationshipType>GENERATED_FROM</relationshipType>
    <relatedSpdxElement>SPDXRef-fromDoap-0</relatedSpdxElement>
  </relationships>
</Document>

tests/data/formats/SPDXXMLExample-v2.2.spdx.xml METASEP
<?xml version='1.0' encoding='UTF-8'?>
<Document>
  <SPDXID>SPDXRef-DOCUMENT</SPDXID>
  <spdxVersion>SPDX-2.2</spdxVersion>
  <creationInfo>
    <comment>This package has been shipped in source and binary form.
The binaries were created with gcc 4.5.1 and expect to link to
compatible system run time libraries.</comment>
    <created>2010-01-29T18:30:22Z</created>
    <creators>Tool: LicenseFind-1.0</creators>
    <creators>Organization: ExampleCodeInspect ()</creators>
    <creators>Person: Jane Doe ()</creators>
    <licenseListVersion>3.9</licenseListVersion>
  </creationInfo>
  <name>SPDX-Tools-v2.0</name>
  <dataLicense>CC0-1.0</dataLicense>
  <comment>This document was created using SPDX 2.0 using licenses from the web site.</comment>
  <externalDocumentRefs>
    <externalDocumentId>DocumentRef-spdx-tool-1.2</externalDocumentId>
    <checksum>
      <algorithm>SHA1</algorithm>
      <checksumValue>d6a770ba38583ed4bb4525bd96e50461655d2759</checksumValue>
    </checksum>
    <spdxDocument>http://spdx.org/spdxdocs/spdx-tools-v1.2-3F2504E0-4F89-41D3-9A0C-0305E82C3301</spdxDocument>
  </externalDocumentRefs>
  <hasExtractedLicensingInfos>
    <licenseId>LicenseRef-1</licenseId>
    <extractedText>/*
 * (c) Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Hewlett-Packard Development Company, LP
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/</extractedText>
  </hasExtractedLicensingInfos>
  <hasExtractedLicensingInfos>
    <licenseId>LicenseRef-2</licenseId>
    <extractedText>This package includes the GRDDL parser developed by Hewlett Packard under the following license:
� Copyright 2007 Hewlett-Packard Development Company, LP

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 

Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 
Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 
The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. 
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.</extractedText>
  </hasExtractedLicensingInfos>
  <hasExtractedLicensingInfos>
    <licenseId>LicenseRef-4</licenseId>
    <extractedText>/*
 * (c) Copyright 2009 University of Bristol
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/</extractedText>
  </hasExtractedLicensingInfos>
  <hasExtractedLicensingInfos>
    <licenseId>LicenseRef-Beerware-4.2</licenseId>
    <comment>The beerware license has a couple of other standard variants.</comment>
    <extractedText>"THE BEER-WARE LICENSE" (Revision 42):
phk@FreeBSD.ORG wrote this file. As long as you retain this notice you
can do whatever you want with this stuff. If we meet some day, and you think this stuff is worth it, you can buy me a beer in return Poul-Henning Kamp</extractedText>
    <name>Beer-Ware License (Version 42)</name>
    <seeAlsos>http://people.freebsd.org/~phk/</seeAlsos>
  </hasExtractedLicensingInfos>
  <hasExtractedLicensingInfos>
    <licenseId>LicenseRef-3</licenseId>
    <comment>This is tye CyperNeko License</comment>
    <extractedText>The CyberNeko Software License, Version 1.0

 
(C) Copyright 2002-2005, Andy Clark.  All rights reserved.
 
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

1. Redistributions of source code must retain the above copyright
   notice, this list of conditions and the following disclaimer. 

2. Redistributions in binary form must reproduce the above copyright
   notice, this list of conditions and the following disclaimer in
   the documentation and/or other materials provided with the
   distribution.

3. The end-user documentation included with the redistribution,
   if any, must include the following acknowledgment:  
     "This product includes software developed by Andy Clark."
   Alternately, this acknowledgment may appear in the software itself,
   if and wherever such third-party acknowledgments normally appear.

4. The names "CyberNeko" and "NekoHTML" must not be used to endorse
   or promote products derived from this software without prior 
   written permission. For written permission, please contact 
   andyc@cyberneko.net.

5. Products derived from this software may not be called "CyberNeko",
   nor may "CyberNeko" appear in their name, without prior written
   permission of the author.

THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.</extractedText>
    <name>CyberNeko License</name>
    <seeAlsos>http://people.apache.org/~andyc/neko/LICENSE</seeAlsos>
    <seeAlsos>http://justasample.url.com</seeAlsos>
  </hasExtractedLicensingInfos>
  <annotations>
    <annotationDate>2010-01-29T18:30:22Z</annotationDate>
    <annotationType>OTHER</annotationType>
    <annotator>Person: Jane Doe ()</annotator>
    <comment>Document level annotation</comment>
  </annotations>
  <annotations>
    <annotationDate>2010-02-10T00:00:00Z</annotationDate>
    <annotationType>REVIEW</annotationType>
    <annotator>Person: Joe Reviewer</annotator>
    <comment>This is just an example.  Some of the non-standard licenses look like they are actually BSD 3 clause licenses</comment>
  </annotations>
  <annotations>
    <annotationDate>2011-03-13T00:00:00Z</annotationDate>
    <annotationType>REVIEW</annotationType>
    <annotator>Person: Suzanne Reviewer</annotator>
    <comment>Another example reviewer.</comment>
  </annotations>
  <documentNamespace>http://spdx.org/spdxdocs/spdx-example-444504E0-4F89-41D3-9A0C-0305E82C3301</documentNamespace>
  <documentDescribes>SPDXRef-File</documentDescribes>
  <documentDescribes>SPDXRef-Package</documentDescribes>
  <packages>
    <SPDXID>SPDXRef-Package</SPDXID>
    <annotations>
      <annotationDate>2011-01-29T18:30:22Z</annotationDate>
      <annotationType>OTHER</annotationType>
      <annotator>Person: Package Commenter</annotator>
      <comment>Package level annotation</comment>
    </annotations>
    <attributionTexts>The GNU C Library is free software.  See the file COPYING.LIB for copying conditions, and LICENSES for notices about a few contributions that require these additional notices to be distributed.  License copyright years may be listed using range notation, e.g., 1996-2015, indicating that every year in the range, inclusive, is a copyrightable year that would otherwise be listed individually.</attributionTexts>
    <checksums>
      <algorithm>MD5</algorithm>
      <checksumValue>624c1abb3664f4b35547e7c73864ad24</checksumValue>
    </checksums>
    <checksums>
      <algorithm>SHA1</algorithm>
      <checksumValue>85ed0817af83a24ad8da68c2b5094de69833983c</checksumValue>
    </checksums>
    <checksums>
      <algorithm>SHA256</algorithm>
      <checksumValue>11b6d3ee554eedf79299905a98f9b9a04e498210b59f15094c916c91d150efcd</checksumValue>
    </checksums>
    <copyrightText>Copyright 2008-2010 John Smith</copyrightText>
    <description>The GNU C Library defines functions that are specified by the ISO C standard, as well as additional features specific to POSIX and other derivatives of the Unix operating system, and extensions specific to GNU systems.</description>
    <downloadLocation>http://ftp.gnu.org/gnu/glibc/glibc-ports-2.15.tar.gz</downloadLocation>
    <externalRefs>
      <referenceCategory>SECURITY</referenceCategory>
      <referenceLocator>cpe:2.3:a:pivotal_software:spring_framework:4.1.0:*:*:*:*:*:*:*</referenceLocator>
      <referenceType>cpe23Type</referenceType>
    </externalRefs>
    <externalRefs>
      <comment>This is the external ref for Acme</comment>
      <referenceCategory>OTHER</referenceCategory>
      <referenceLocator>acmecorp/acmenator/4.1.3-alpha</referenceLocator>
      <referenceType>http://spdx.org/spdxdocs/spdx-example-444504E0-4F89-41D3-9A0C-0305E82C3301#LocationRef-acmeforge</referenceType>
    </externalRefs>
    <filesAnalyzed>true</filesAnalyzed>
    <hasFiles>SPDXRef-CommonsLangSrc</hasFiles>
    <hasFiles>SPDXRef-JenaLib</hasFiles>
    <hasFiles>SPDXRef-DoapSource</hasFiles>
    <homepage>http://ftp.gnu.org/gnu/glibc</homepage>
    <licenseComments>The license for this project changed with the release of version x.y.  The version of the project included here post-dates the license change.</licenseComments>
    <licenseConcluded>(LGPL-2.0-only OR LicenseRef-3)</licenseConcluded>
    <licenseDeclared>(LGPL-2.0-only AND LicenseRef-3)</licenseDeclared>
    <licenseInfoFromFiles>GPL-2.0-only</licenseInfoFromFiles>
    <licenseInfoFromFiles>LicenseRef-2</licenseInfoFromFiles>
    <licenseInfoFromFiles>LicenseRef-1</licenseInfoFromFiles>
    <name>glibc</name>
    <originator>Organization: ExampleCodeInspect (contact@example.com)</originator>
    <packageFileName>glibc-2.11.1.tar.gz</packageFileName>
    <packageVerificationCode>
      <packageVerificationCodeExcludedFiles>./package.spdx</packageVerificationCodeExcludedFiles>
      <packageVerificationCodeValue>d6a770ba38583ed4bb4525bd96e50461655d2758</packageVerificationCodeValue>
    </packageVerificationCode>
    <sourceInfo>uses glibc-2_11-branch from git://sourceware.org/git/glibc.git.</sourceInfo>
    <summary>GNU C library.</summary>
    <supplier>Person: Jane Doe (jane.doe@example.com)</supplier>
    <versionInfo>2.11.1</versionInfo>
  </packages>
  <packages>
    <SPDXID>SPDXRef-fromDoap-1</SPDXID>
    <copyrightText>NOASSERTION</copyrightText>
    <downloadLocation>NOASSERTION</downloadLocation>
    <filesAnalyzed>false</filesAnalyzed>
    <homepage>http://commons.apache.org/proper/commons-lang/</homepage>
    <licenseConcluded>NOASSERTION</licenseConcluded>
    <licenseDeclared>NOASSERTION</licenseDeclared>
    <name>Apache Commons Lang</name>
  </packages>
  <packages>
    <SPDXID>SPDXRef-fromDoap-0</SPDXID>
    <copyrightText>NOASSERTION</copyrightText>
    <downloadLocation>https://search.maven.org/remotecontent?filepath=org/apache/jena/apache-jena/3.12.0/apache-jena-3.12.0.tar.gz</downloadLocation>
    <externalRefs>
      <referenceCategory>PACKAGE_MANAGER</referenceCategory>
      <referenceLocator>pkg:maven/org.apache.jena/apache-jena@3.12.0</referenceLocator>
      <referenceType>purl</referenceType>
    </externalRefs>
    <filesAnalyzed>false</filesAnalyzed>
    <homepage>http://www.openjena.org/</homepage>
    <licenseConcluded>NOASSERTION</licenseConcluded>
    <licenseDeclared>NOASSERTION</licenseDeclared>
    <name>Jena</name>
    <versionInfo>3.12.0</versionInfo>
  </packages>
  <packages>
    <SPDXID>SPDXRef-Saxon</SPDXID>
    <checksums>
      <algorithm>SHA1</algorithm>
      <checksumValue>85ed0817af83a24ad8da68c2b5094de69833983c</checksumValue>
    </checksums>
    <copyrightText>Copyright Saxonica Ltd</copyrightText>
    <description>The Saxon package is a collection of tools for processing XML documents.</description>
    <downloadLocation>https://sourceforge.net/projects/saxon/files/Saxon-B/8.8.0.7/saxonb8-8-0-7j.zip/download</downloadLocation>
    <filesAnalyzed>false</filesAnalyzed>
    <homepage>http://saxon.sourceforge.net/</homepage>
    <licenseComments>Other versions available for a commercial license</licenseComments>
    <licenseConcluded>MPL-1.0</licenseConcluded>
    <licenseDeclared>MPL-1.0</licenseDeclared>
    <name>Saxon</name>
    <packageFileName>saxonB-8.8.zip</packageFileName>
    <versionInfo>8.8</versionInfo>
  </packages>
  <files>
    <SPDXID>SPDXRef-DoapSource</SPDXID>
    <checksums>
      <algorithm>SHA1</algorithm>
      <checksumValue>2fd4e1c67a2d28fced849ee1bb76e7391b93eb12</checksumValue>
    </checksums>
    <copyrightText>Copyright 2010, 2011 Source Auditor Inc.</copyrightText>
    <fileContributors>Protecode Inc.</fileContributors>
    <fileContributors>SPDX Technical Team Members</fileContributors>
    <fileContributors>Open Logic Inc.</fileContributors>
    <fileContributors>Source Auditor Inc.</fileContributors>
    <fileContributors>Black Duck Software In.c</fileContributors>
    <fileName>./src/org/spdx/parser/DOAPProject.java</fileName>
    <fileTypes>SOURCE</fileTypes>
    <licenseConcluded>Apache-2.0</licenseConcluded>
    <licenseInfoInFiles>Apache-2.0</licenseInfoInFiles>
  </files>
  <files>
    <SPDXID>SPDXRef-CommonsLangSrc</SPDXID>
    <checksums>
      <algorithm>SHA1</algorithm>
      <checksumValue>c2b4e1c67a2d28fced849ee1bb76e7391b93f125</checksumValue>
    </checksums>
    <comment>This file is used by Jena</comment>
    <copyrightText>Copyright 2001-2011 The Apache Software Foundation</copyrightText>
    <fileContributors>Apache Software Foundation</fileContributors>
    <fileName>./lib-source/commons-lang3-3.1-sources.jar</fileName>
    <fileTypes>ARCHIVE</fileTypes>
    <licenseConcluded>Apache-2.0</licenseConcluded>
    <licenseInfoInFiles>Apache-2.0</licenseInfoInFiles>
    <noticeText>Apache Commons Lang
Copyright 2001-2011 The Apache Software Foundation

This product includes software developed by
The Apache Software Foundation (http://www.apache.org/).

This product includes software from the Spring Framework,
under the Apache License 2.0 (see: StringUtils.containsWhitespace())</noticeText>
  </files>
  <files>
    <SPDXID>SPDXRef-JenaLib</SPDXID>
    <checksums>
      <algorithm>SHA1</algorithm>
      <checksumValue>3ab4e1c67a2d28fced849ee1bb76e7391b93f125</checksumValue>
    </checksums>
    <comment>This file belongs to Jena</comment>
    <copyrightText>(c) Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Hewlett-Packard Development Company, LP</copyrightText>
    <fileContributors>Apache Software Foundation</fileContributors>
    <fileContributors>Hewlett Packard Inc.</fileContributors>
    <fileName>./lib-source/jena-2.6.3-sources.jar</fileName>
    <fileTypes>ARCHIVE</fileTypes>
    <licenseComments>This license is used by Jena</licenseComments>
    <licenseConcluded>LicenseRef-1</licenseConcluded>
    <licenseInfoInFiles>LicenseRef-1</licenseInfoInFiles>
  </files>
  <files>
    <SPDXID>SPDXRef-File</SPDXID>
    <annotations>
      <annotationDate>2011-01-29T18:30:22Z</annotationDate>
      <annotationType>OTHER</annotationType>
      <annotator>Person: File Commenter</annotator>
      <comment>File level annotation</comment>
    </annotations>
    <checksums>
      <algorithm>SHA1</algorithm>
      <checksumValue>d6a770ba38583ed4bb4525bd96e50461655d2758</checksumValue>
    </checksums>
    <checksums>
      <algorithm>MD5</algorithm>
      <checksumValue>624c1abb3664f4b35547e7c73864ad24</checksumValue>
    </checksums>
    <comment>The concluded license was taken from the package level that the file was included in.
This information was found in the COPYING.txt file in the xyz directory.</comment>
    <copyrightText>Copyright 2008-2010 John Smith</copyrightText>
    <fileContributors>The Regents of the University of California</fileContributors>
    <fileContributors>Modified by Paul Mundt lethal@linux-sh.org</fileContributors>
    <fileContributors>IBM Corporation</fileContributors>
    <fileName>./package/foo.c</fileName>
    <fileTypes>SOURCE</fileTypes>
    <licenseComments>The concluded license was taken from the package level that the file was included in.</licenseComments>
    <licenseConcluded>(LGPL-2.0-only OR LicenseRef-2)</licenseConcluded>
    <licenseInfoInFiles>GPL-2.0-only</licenseInfoInFiles>
    <licenseInfoInFiles>LicenseRef-2</licenseInfoInFiles>
    <noticeText>Copyright (c) 2001 Aaron Lehmann aaroni@vitelus.com

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the �Software�), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED �AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.</noticeText>
  </files>
  <snippets>
    <SPDXID>SPDXRef-Snippet</SPDXID>
    <comment>This snippet was identified as significant and highlighted in this Apache-2.0 file, when a commercial scanner identified it as being derived from file foo.c in package xyz which is licensed under GPL-2.0.</comment>
    <copyrightText>Copyright 2008-2010 John Smith</copyrightText>
    <licenseComments>The concluded license was taken from package xyz, from which the snippet was copied into the current file. The concluded license information was found in the COPYING.txt file in package xyz.</licenseComments>
    <licenseConcluded>GPL-2.0-only</licenseConcluded>
    <licenseInfoInSnippets>GPL-2.0-only</licenseInfoInSnippets>
    <name>from linux kernel</name>
    <ranges>
      <endPointer>
        <offset>420</offset>
        <reference>SPDXRef-DoapSource</reference>
      </endPointer>
      <startPointer>
        <offset>310</offset>
        <reference>SPDXRef-DoapSource</reference>
      </startPointer>
    </ranges>
    <ranges>
      <endPointer>
        <lineNumber>23</lineNumber>
        <reference>SPDXRef-DoapSource</reference>
      </endPointer>
      <startPointer>
        <lineNumber>5</lineNumber>
        <reference>SPDXRef-DoapSource</reference>
      </startPointer>
    </ranges>
    <snippetFromFile>SPDXRef-DoapSource</snippetFromFile>
  </snippets>
  <relationships>
    <spdxElementId>SPDXRef-DOCUMENT</spdxElementId>
    <relatedSpdxElement>SPDXRef-Package</relatedSpdxElement>
    <relationshipType>CONTAINS</relationshipType>
  </relationships>
  <relationships>
    <spdxElementId>SPDXRef-DOCUMENT</spdxElementId>
    <relatedSpdxElement>DocumentRef-spdx-tool-1.2:SPDXRef-ToolsElement</relatedSpdxElement>
    <relationshipType>COPY_OF</relationshipType>
  </relationships>
  <relationships>
    <spdxElementId>SPDXRef-DOCUMENT</spdxElementId>
    <relatedSpdxElement>SPDXRef-File</relatedSpdxElement>
    <relationshipType>DESCRIBES</relationshipType>
  </relationships>
  <relationships>
    <spdxElementId>SPDXRef-DOCUMENT</spdxElementId>
    <relatedSpdxElement>SPDXRef-Package</relatedSpdxElement>
    <relationshipType>DESCRIBES</relationshipType>
  </relationships>
  <relationships>
    <spdxElementId>SPDXRef-Package</spdxElementId>
    <relatedSpdxElement>SPDXRef-JenaLib</relatedSpdxElement>
    <relationshipType>CONTAINS</relationshipType>
  </relationships>
  <relationships>
    <spdxElementId>SPDXRef-Package</spdxElementId>
    <relatedSpdxElement>SPDXRef-Saxon</relatedSpdxElement>
    <relationshipType>DYNAMIC_LINK</relationshipType>
  </relationships>
  <relationships>
    <spdxElementId>SPDXRef-CommonsLangSrc</spdxElementId>
    <relatedSpdxElement>NOASSERTION</relatedSpdxElement>
    <relationshipType>GENERATED_FROM</relationshipType>
  </relationships>
  <relationships>
    <spdxElementId>SPDXRef-JenaLib</spdxElementId>
    <relatedSpdxElement>SPDXRef-Package</relatedSpdxElement>
    <relationshipType>CONTAINS</relationshipType>
  </relationships>
  <relationships>
    <spdxElementId>SPDXRef-File</spdxElementId>
    <relatedSpdxElement>SPDXRef-fromDoap-0</relatedSpdxElement>
    <relationshipType>GENERATED_FROM</relationshipType>
  </relationships>
</Document>

tests/data/formats/SPDXTagExample.tag METASEP
SPDXVersion: SPDX-2.1
DataLicense: CC0-1.0
DocumentName: Sample_Document-V2.1
SPDXID: SPDXRef-DOCUMENT
DocumentNamespace: https://spdx.org/spdxdocs/spdx-example-444504E0-4F89-41D3-9A0C-0305E82C3301
DocumentComment: <text>This is a sample spreadsheet</text>

## Creation Information
Creator: Person: Gary O'Neall
Creator: Organization: Source Auditor Inc.
Creator: Tool: SourceAuditor-V1.2
Created: 2010-02-03T00:00:00Z
CreatorComment: <text>This is an example of an SPDX spreadsheet format</text>

## Review Information
Reviewer: Person: Joe Reviewer
ReviewDate: 2010-02-10T00:00:00Z
ReviewComment: <text>This is just an example.  Some of the non-standard licenses look like they are actually BSD 3 clause licenses</text>

Reviewer: Person: Suzanne Reviewer
ReviewDate: 2011-03-13T00:00:00Z
ReviewComment: <text>Another example reviewer.</text>

## Annotation Information
Annotator: Person: Jim Annotator
AnnotationType: REVIEW
AnnotationDate: 2012-03-11T00:00:00Z
AnnotationComment: <text>An example annotation comment.</text>
SPDXREF: SPDXRef-45

## Relationships
Relationship: SPDXRef-DOCUMENT DESCRIBES SPDXRef-File
Relationship: SPDXRef-DOCUMENT DESCRIBES SPDXRef-Package
Relationship: SPDXRef-DOCUMENT COPY_OF DocumentRef-spdx-tool-1.2:SPDXRef-ToolsElement
Relationship: SPDXRef-DOCUMENT CONTAINS SPDXRef-Package

## Package Information
PackageName: SPDX Translator
SPDXID: SPDXRef-Package
PackageVersion: Version 0.9.2
PackageDownloadLocation: http://www.spdx.org/tools
PackageSummary: <text>SPDX Translator utility</text>
PackageSourceInfo: <text>Version 1.0 of the SPDX Translator application</text>
PackageFileName: spdxtranslator-1.0.zip
PackageAttributionText: <text>The GNU C Library is free software.  See the file COPYING.LIB for copying conditions, and LICENSES for notices about a few contributions that require these additional notices to be distributed.  License copyright years may be listed using range notation, e.g., 1996-2015, indicating that every year in the range, inclusive, is a copyrightable year that would otherwise be listed individually.</text>
PackageSupplier: Organization:Linux Foundation
PackageOriginator: Organization:SPDX
PackageChecksum: SHA1: 2fd4e1c67a2d28fced849ee1bb76e7391b93eb12
PackageVerificationCode: 4e3211c67a2d28fced849ee1bb76e7391b93feba (SpdxTranslatorSpdx.rdf, SpdxTranslatorSpdx.txt)
PackageDescription: <text>This utility translates and SPDX RDF XML document to a spreadsheet, translates a spreadsheet to an SPDX RDF XML document and translates an SPDX RDFa document to an SPDX RDF XML document.</text>
PackageAttributionText: <text>The GNU C Library is free software.  See the file COPYING.LIB for copying conditions, and LICENSES for notices about a few contributions that require these additional notices to be distributed.  License copyright years may be listed using range notation, e.g., 1996-2015, indicating that every year in the range, inclusive, is a copyrightable year that would otherwise be listed individually.</text>
PackageComment: <text>This package includes several sub-packages.</text>

PackageCopyrightText: <text>Copyright 2010, 2011 Source Auditor Inc.</text>

PackageLicenseDeclared: (LicenseRef-3 AND LicenseRef-4 AND Apache-2.0 AND MPL-1.1 AND LicenseRef-1 AND LicenseRef-2)
PackageLicenseConcluded: (LicenseRef-3 AND LicenseRef-4 AND Apache-1.0 AND Apache-2.0 AND MPL-1.1 AND LicenseRef-1 AND LicenseRef-2)

PackageLicenseInfoFromFiles: Apache-1.0
PackageLicenseInfoFromFiles: LicenseRef-3
PackageLicenseInfoFromFiles: Apache-2.0
PackageLicenseInfoFromFiles: LicenseRef-4
PackageLicenseInfoFromFiles: LicenseRef-2
PackageLicenseInfoFromFiles: LicenseRef-1
PackageLicenseInfoFromFiles: MPL-1.1
PackageLicenseComments: <text>The declared license information can be found in the NOTICE file at the root of the archive file</text>

ExternalRef: SECURITY cpe23Type cpe:2.3:a:pivotal_software:spring_framework:4.1.0:*:*:*:*:*:*:
ExternalRefComment: <text>NIST National Vulnerability Database (NVD) describes security vulnerabilities (CVEs) which affect Vendor Product Version acmecorp:acmenator:6.6.6.</text>

## File Information
FileName: src/org/spdx/parser/DOAPProject.java
SPDXID: SPDXRef-File1
FileType: SOURCE
FileType: TEXT
FileChecksum: SHA1: 2fd4e1c67a2d28fced849ee1bb76e7391b93eB12
FileChecksum: SHA256: 2fd4e1c67a2d28fced849ee1bb76e7391b93eb120000000000000000
LicenseConcluded: Apache-2.0
LicenseInfoInFile: Apache-2.0
FileCopyrightText: <text>Copyright 2010, 2011 Source Auditor Inc.</text>

FileName: Jenna-2.6.3/jena-2.6.3-sources.jar
SPDXID: SPDXRef-File2
FileType: ARCHIVE
FileType: OTHER
FileChecksum: SHA1: 3ab4e1c67a2d28fced849ee1bb76e7391b93f125
FileChecksum: SHA256: 3ab4e1c67a2d28fced849ee1bb76e7391b93f1250000000000000000
LicenseConcluded: LicenseRef-1
LicenseInfoInFile: LicenseRef-1
LicenseComments: <text>This license is used by Jena</text>
FileCopyrightText: <text>(c) Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Hewlett-Packard Development Company, LP</text>
ArtifactOfProjectName: Jena
ArtifactOfProjectHomePage: http://www.openjena.org/
ArtifactOfProjectURI: http://www.openjena.org/doap.rdf
FileComment: <text>This file belongs to Jena</text>

## Snippet Information
SnippetSPDXID: SPDXRef-Snippet
SnippetFromFileSPDXID: SPDXRef-DoapSource
SnippetLicenseComments: <text>The concluded license was taken from package xyz, from which the snippet was copied into the current file. The concluded license information was found in the COPYING.txt file in package xyz.</text>
SnippetCopyrightText: <text>Copyright 2008-2010 John Smith</text>
SnippetComment: <text>This snippet was identified as significant and highlighted in this Apache-2.0 file, when a commercial scanner identified it as being derived from file foo.c in package xyz which is licensed under GPL-2.0-or-later.</text>
SnippetName: from linux kernel
SnippetLicenseConcluded: Apache-2.0
LicenseInfoInSnippet: Apache-2.0
SnippetByteRange: 310:420

## License Information
LicenseID: LicenseRef-3
ExtractedText: <text>The CyberNeko Software License, Version 1.0

 
(C) Copyright 2002-2005, Andy Clark.  All rights reserved.
 
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

1. Redistributions of source code must retain the above copyright
   notice, this list of conditions and the following disclaimer. 

2. Redistributions in binary form must reproduce the above copyright
   notice, this list of conditions and the following disclaimer in
   the documentation and/or other materials provided with the
   distribution.

3. The end-user documentation included with the redistribution,
   if any, must include the following acknowledgment:  
     "This product includes software developed by Andy Clark."
   Alternately, this acknowledgment may appear in the software itself,
   if and wherever such third-party acknowledgments normally appear.

4. The names "CyberNeko" and "NekoHTML" must not be used to endorse
   or promote products derived from this software without prior 
   written permission. For written permission, please contact 
   andyc@cyberneko.net.

5. Products derived from this software may not be called "CyberNeko",
   nor may "CyberNeko" appear in their name, without prior written
   permission of the author.

THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.</text>
LicenseName: CyberNeko License
LicenseCrossReference: http://people.apache.org/~andyc/neko/LICENSE
LicenseCrossReference: http://justasample.url.com
LicenseComment: <text>This is tye CyperNeko License</text>

LicenseID: LicenseRef-1
ExtractedText: <text>/*
 * (c) Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Hewlett-Packard Development Company, LP
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */</text>

LicenseID: LicenseRef-2
ExtractedText: <text>This package includes the GRDDL parser developed by Hewlett Packard under the following license:
© Copyright 2007 Hewlett-Packard Development Company, LP

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 

Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 
Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 
The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. 
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. </text>

LicenseID: LicenseRef-4
ExtractedText: <text>/*
 * (c) Copyright 2009 University of Bristol
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */  </text>


tests/data/formats/SPDXTagExample-v2.3.spdx METASEP
SPDXVersion: SPDX-2.3
DataLicense: CC0-1.0
DocumentNamespace: http://spdx.org/spdxdocs/spdx-example-444504E0-4F89-41D3-9A0C-0305E82C3301
DocumentName: SPDX-Tools-v2.0
SPDXID: SPDXRef-DOCUMENT
DocumentComment: <text>This document was created using SPDX 2.0 using licenses from the web site.</text>

## External Document References
ExternalDocumentRef: DocumentRef-spdx-tool-1.2 http://spdx.org/spdxdocs/spdx-tools-v1.2-3F2504E0-4F89-41D3-9A0C-0305E82C3301 SHA1: d6a770ba38583ed4bb4525bd96e50461655d2759
## Creation Information
Creator: Tool: LicenseFind-1.0
Creator: Organization: ExampleCodeInspect ()
Creator: Person: Jane Doe ()
Created: 2010-01-29T18:30:22Z
CreatorComment: <text>This package has been shipped in source and binary form.
The binaries were created with gcc 4.5.1 and expect to link to
compatible system run time libraries.</text>
LicenseListVersion: 3.17
## Annotations
Annotator: Person: Jane Doe ()
AnnotationDate: 2010-01-29T18:30:22Z
AnnotationComment: <text>Document level annotation</text>
AnnotationType: OTHER
SPDXREF: SPDXRef-DOCUMENT
Annotator: Person: Joe Reviewer
AnnotationDate: 2010-02-10T00:00:00Z
AnnotationComment: <text>This is just an example.  Some of the non-standard licenses look like they are actually BSD 3 clause licenses</text>
AnnotationType: REVIEW
SPDXREF: SPDXRef-DOCUMENT
Annotator: Person: Suzanne Reviewer
AnnotationDate: 2011-03-13T00:00:00Z
AnnotationComment: <text>Another example reviewer.</text>
AnnotationType: REVIEW
SPDXREF: SPDXRef-DOCUMENT
## Relationships
Relationship: SPDXRef-DOCUMENT CONTAINS SPDXRef-Package
Relationship: SPDXRef-DOCUMENT COPY_OF DocumentRef-spdx-tool-1.2:SPDXRef-ToolsElement
Relationship: SPDXRef-DOCUMENT DESCRIBES SPDXRef-File
Relationship: SPDXRef-DOCUMENT DESCRIBES SPDXRef-Package

FileName: ./package/foo.c
SPDXID: SPDXRef-File
FileComment: <text>The concluded license was taken from the package level that the file was included in.
This information was found in the COPYING.txt file in the xyz directory.</text>
FileType: SOURCE
FileChecksum: SHA1: d6a770ba38583ed4bb4525bd96e50461655d2758
FileChecksum: MD5: 624c1abb3664f4b35547e7c73864ad24
LicenseConcluded: (LGPL-2.0-only OR LicenseRef-2)
LicenseInfoInFile: GPL-2.0-only
LicenseInfoInFile: LicenseRef-2
LicenseComments: The concluded license was taken from the package level that the file was included in.
FileCopyrightText: <text>Copyright 2008-2010 John Smith</text>
FileNotice: <text>Copyright (c) 2001 Aaron Lehmann aaroni@vitelus.com

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.</text>
FileContributor: The Regents of the University of California
FileContributor: Modified by Paul Mundt lethal@linux-sh.org
FileContributor: IBM Corporation
## Annotations
Annotator: Person: File Commenter
AnnotationDate: 2011-01-29T18:30:22Z
AnnotationComment: <text>File level annotation</text>
AnnotationType: OTHER
SPDXREF: SPDXRef-File
## Relationships
Relationship: SPDXRef-File GENERATED_FROM SPDXRef-fromDoap-0
## Package Information
PackageName: glibc
SPDXID: SPDXRef-Package
PackageVersion: 2.11.1
PackageFileName: glibc-2.11.1.tar.gz
PackageSupplier: Person: Jane Doe (jane.doe@example.com)
PackageOriginator: Organization: ExampleCodeInspect (contact@example.com)
PackageDownloadLocation: http://ftp.gnu.org/gnu/glibc/glibc-ports-2.15.tar.gz
PackageVerificationCode: d6a770ba38583ed4bb4525bd96e50461655d2758(./package.spdx)
PackageChecksum: MD5: 624c1abb3664f4b35547e7c73864ad24
PackageChecksum: SHA1: 85ed0817af83a24ad8da68c2b5094de69833983c
PackageChecksum: SHA256: 11b6d3ee554eedf79299905a98f9b9a04e498210b59f15094c916c91d150efcd
PackageChecksum: BLAKE2b-384: aaabd89c926ab525c242e6621f2f5fa73aa4afe3d9e24aed727faaadd6af38b620bdb623dd2b4788b1c8086984af8706
PackageHomePage: http://ftp.gnu.org/gnu/glibc
PackageSourceInfo: <text>uses glibc-2_11-branch from git://sourceware.org/git/glibc.git.</text>
PrimaryPackagePurpose: SOURCE
BuiltDate: 2011-01-29T18:30:22Z
ReleaseDate: 2012-01-29T18:30:22Z
ValidUntilDate: 2014-01-29T18:30:22Z
PackageLicenseConcluded: (LGPL-2.0-only OR LicenseRef-3)
## License information from files
PackageLicenseInfoFromFiles: GPL-2.0-only
PackageLicenseInfoFromFiles: LicenseRef-2
PackageLicenseInfoFromFiles: LicenseRef-1
PackageLicenseDeclared: (LGPL-2.0-only AND LicenseRef-3)
PackageLicenseComments: <text>The license for this project changed with the release of version x.y.  The version of the project included here post-dates the license change.</text>
PackageCopyrightText: <text>Copyright 2008-2010 John Smith</text>
PackageSummary: <text>GNU C library.</text>
PackageDescription: <text>The GNU C Library defines functions that are specified by the ISO C standard, as well as additional features specific to POSIX and other derivatives of the Unix operating system, and extensions specific to GNU systems.</text>
PackageAttributionText: <text>The GNU C Library is free software.  See the file COPYING.LIB for copying conditions, and LICENSES for notices about a few contributions that require these additional notices to be distributed.  License copyright years may be listed using range notation, e.g., 1996-2015, indicating that every year in the range, inclusive, is a copyrightable year that would otherwise be listed individually.</text>
ExternalRef: SECURITY cpe23Type cpe:2.3:a:pivotal_software:spring_framework:4.1.0:*:*:*:*:*:*:*
ExternalRef: OTHER LocationRef-acmeforge acmecorp/acmenator/4.1.3-alpha
ExternalRefComment: This is the external ref for Acme
## Annotations
Annotator: Person: Package Commenter
AnnotationDate: 2011-01-29T18:30:22Z
AnnotationComment: <text>Package level annotation</text>
AnnotationType: OTHER
SPDXREF: SPDXRef-Package
## Relationships
Relationship: SPDXRef-Package CONTAINS SPDXRef-JenaLib
Relationship: SPDXRef-Package DYNAMIC_LINK SPDXRef-Saxon

## File Information
FileName: ./docs/myspec.pdf
SPDXID: SPDXRef-Specification
FileComment: <text>Specification Documentation</text>
FileType: DOCUMENTATION
FileChecksum: SHA1: fff4e1c67a2d28fced849ee1bb76e7391b93f125
Relationship: SPDXRef-Specification SPECIFICATION_FOR SPDXRef-fromDoap-0

## File Information
FileName: ./lib-source/commons-lang3-3.1-sources.jar
SPDXID: SPDXRef-CommonsLangSrc
FileComment: <text>This file is used by Jena</text>
FileType: ARCHIVE
FileChecksum: SHA1: c2b4e1c67a2d28fced849ee1bb76e7391b93f125
LicenseConcluded: Apache-2.0
LicenseInfoInFile: Apache-2.0
FileCopyrightText: <text>Copyright 2001-2011 The Apache Software Foundation</text>
FileNotice: <text>Apache Commons Lang
Copyright 2001-2011 The Apache Software Foundation

This product includes software developed by
The Apache Software Foundation (http://www.apache.org/).

This product includes software from the Spring Framework,
under the Apache License 2.0 (see: StringUtils.containsWhitespace())</text>
FileContributor: Apache Software Foundation
## Relationships
Relationship: SPDXRef-CommonsLangSrc GENERATED_FROM NOASSERTION

FileName: ./lib-source/jena-2.6.3-sources.jar
SPDXID: SPDXRef-JenaLib
FileComment: <text>This file belongs to Jena</text>
FileType: ARCHIVE
FileChecksum: SHA1: 3ab4e1c67a2d28fced849ee1bb76e7391b93f125
LicenseConcluded: LicenseRef-1
LicenseInfoInFile: LicenseRef-1
LicenseComments: This license is used by Jena
FileCopyrightText: <text>(c) Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Hewlett-Packard Development Company, LP</text>
FileContributor: Apache Software Foundation
FileContributor: Hewlett Packard Inc.
## Relationships
Relationship: SPDXRef-JenaLib CONTAINS SPDXRef-Package

FileName: ./src/org/spdx/parser/DOAPProject.java
SPDXID: SPDXRef-DoapSource
FileType: SOURCE
FileChecksum: SHA1: 2fd4e1c67a2d28fced849ee1bb76e7391b93eb12
LicenseConcluded: Apache-2.0
LicenseInfoInFile: Apache-2.0
FileCopyrightText: <text>Copyright 2010, 2011 Source Auditor Inc.</text>
FileContributor: Protecode Inc.
FileContributor: SPDX Technical Team Members
FileContributor: Open Logic Inc.
FileContributor: Source Auditor Inc.
FileContributor: Black Duck Software In.c

## Package Information
PackageName: Apache Commons Lang
SPDXID: SPDXRef-fromDoap-1
PackageDownloadLocation: NOASSERTION
PackageHomePage: http://commons.apache.org/proper/commons-lang/
PackageLicenseConcluded: NOASSERTION
PackageLicenseDeclared: NOASSERTION
PackageCopyrightText: NOASSERTION
FilesAnalyzed: false

## Package Information
PackageName: Jena
SPDXID: SPDXRef-fromDoap-0
PackageVersion: 3.12.0
PackageDownloadLocation: https://search.maven.org/remotecontent?filepath=org/apache/jena/apache-jena/3.12.0/apache-jena-3.12.0.tar.gz
PackageHomePage: http://www.openjena.org/
ExternalRef: PACKAGE-MANAGER purl pkg:maven/org.apache.jena/apache-jena@3.12.0
FilesAnalyzed: false

## Package Information
PackageName: Saxon
SPDXID: SPDXRef-Saxon
PackageVersion: 8.8
PackageFileName: saxonB-8.8.zip
PackageDownloadLocation: https://sourceforge.net/projects/saxon/files/Saxon-B/8.8.0.7/saxonb8-8-0-7j.zip/download
PackageChecksum: SHA1: 85ed0817af83a24ad8da68c2b5094de69833983c
PackageHomePage: http://saxon.sourceforge.net/
PackageLicenseConcluded: MPL-1.0
PackageLicenseDeclared: MPL-1.0
PackageLicenseComments: <text>Other versions available for a commercial license</text>
PackageCopyrightText: <text>Copyright Saxonica Ltd</text>
PackageDescription: <text>The Saxon package is a collection of tools for processing XML documents.</text>
FilesAnalyzed: false

## Snippet Information
SnippetSPDXID: SPDXRef-Snippet
SnippetFromFileSPDXID: SPDXRef-DoapSource
SnippetByteRange: 310:420
SnippetLineRange: 5:23
SnippetLicenseConcluded: GPL-2.0-only
LicenseInfoInSnippet: GPL-2.0-only
SnippetLicenseComments: The concluded license was taken from package xyz, from which the snippet was copied into the current file. The concluded license information was found in the COPYING.txt file in package xyz.
SnippetCopyrightText: Copyright 2008-2010 John Smith
SnippetComment: This snippet was identified as significant and highlighted in this Apache-2.0 file, when a commercial scanner identified it as being derived from file foo.c in package xyz which is licensed under GPL-2.0.
SnippetName: from linux kernel


## License Information
LicenseID: LicenseRef-1
ExtractedText: <text>/*
 * (c) Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Hewlett-Packard Development Company, LP
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/</text>

LicenseID: LicenseRef-2
ExtractedText: <text>This package includes the GRDDL parser developed by Hewlett Packard under the following license:
© Copyright 2007 Hewlett-Packard Development Company, LP

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 

Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 
Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 
The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. 
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.</text>

LicenseID: LicenseRef-4
ExtractedText: <text>/*
 * (c) Copyright 2009 University of Bristol
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/</text>

LicenseID: LicenseRef-Beerware-4.2
ExtractedText: <text>"THE BEER-WARE LICENSE" (Revision 42):
phk@FreeBSD.ORG wrote this file. As long as you retain this notice you
can do whatever you want with this stuff. If we meet some day, and you think this stuff is worth it, you can buy me a beer in return Poul-Henning Kamp</text>
LicenseName: Beer-Ware License (Version 42)
LicenseCrossReference:  http://people.freebsd.org/~phk/
LicenseComment: The beerware license has a couple of other standard variants.

LicenseID: LicenseRef-3
ExtractedText: <text>The CyberNeko Software License, Version 1.0

 
(C) Copyright 2002-2005, Andy Clark.  All rights reserved.
 
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

1. Redistributions of source code must retain the above copyright
   notice, this list of conditions and the following disclaimer. 

2. Redistributions in binary form must reproduce the above copyright
   notice, this list of conditions and the following disclaimer in
   the documentation and/or other materials provided with the
   distribution.

3. The end-user documentation included with the redistribution,
   if any, must include the following acknowledgment:  
     "This product includes software developed by Andy Clark."
   Alternately, this acknowledgment may appear in the software itself,
   if and wherever such third-party acknowledgments normally appear.

4. The names "CyberNeko" and "NekoHTML" must not be used to endorse
   or promote products derived from this software without prior 
   written permission. For written permission, please contact 
   andyc@cyberneko.net.

5. Products derived from this software may not be called "CyberNeko",
   nor may "CyberNeko" appear in their name, without prior written
   permission of the author.

THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.</text>
LicenseName: CyberNeko License
LicenseCrossReference: http://people.apache.org/~andyc/neko/LICENSE, http://justasample.url.com
LicenseComment: <text>This is tye CyperNeko License</text>


tests/data/formats/SPDXTagExample-v2.2.spdx METASEP
SPDXVersion: SPDX-2.2
DataLicense: CC0-1.0
DocumentNamespace: http://spdx.org/spdxdocs/spdx-example-444504E0-4F89-41D3-9A0C-0305E82C3301
DocumentName: SPDX-Tools-v2.0
SPDXID: SPDXRef-DOCUMENT
DocumentComment: <text>This document was created using SPDX 2.0 using licenses from the web site.</text>

## External Document References
ExternalDocumentRef: DocumentRef-spdx-tool-1.2 http://spdx.org/spdxdocs/spdx-tools-v1.2-3F2504E0-4F89-41D3-9A0C-0305E82C3301 SHA1: d6a770ba38583ed4bb4525bd96e50461655d2759
## Creation Information
Creator: Tool: LicenseFind-1.0
Creator: Organization: ExampleCodeInspect ()
Creator: Person: Jane Doe ()
Created: 2010-01-29T18:30:22Z
CreatorComment: <text>This package has been shipped in source and binary form.
The binaries were created with gcc 4.5.1 and expect to link to
compatible system run time libraries.</text>
LicenseListVersion: 3.9
## Annotations
Annotator: Person: Jane Doe ()
AnnotationDate: 2010-01-29T18:30:22Z
AnnotationComment: <text>Document level annotation</text>
AnnotationType: OTHER
SPDXREF: SPDXRef-DOCUMENT
Annotator: Person: Joe Reviewer
AnnotationDate: 2010-02-10T00:00:00Z
AnnotationComment: <text>This is just an example.  Some of the non-standard licenses look like they are actually BSD 3 clause licenses</text>
AnnotationType: REVIEW
SPDXREF: SPDXRef-DOCUMENT
Annotator: Person: Suzanne Reviewer
AnnotationDate: 2011-03-13T00:00:00Z
AnnotationComment: <text>Another example reviewer.</text>
AnnotationType: REVIEW
SPDXREF: SPDXRef-DOCUMENT
## Relationships
Relationship: SPDXRef-DOCUMENT CONTAINS SPDXRef-Package
Relationship: SPDXRef-DOCUMENT COPY_OF DocumentRef-spdx-tool-1.2:SPDXRef-ToolsElement
Relationship: SPDXRef-DOCUMENT DESCRIBES SPDXRef-File
Relationship: SPDXRef-DOCUMENT DESCRIBES SPDXRef-Package

FileName: ./package/foo.c
SPDXID: SPDXRef-File
FileComment: <text>The concluded license was taken from the package level that the file was included in.
This information was found in the COPYING.txt file in the xyz directory.</text>
FileType: SOURCE
FileChecksum: SHA1: d6a770ba38583ed4bb4525bd96e50461655d2758
FileChecksum: MD5: 624c1abb3664f4b35547e7c73864ad24
LicenseConcluded: (LGPL-2.0-only OR LicenseRef-2)
LicenseInfoInFile: GPL-2.0-only
LicenseInfoInFile: LicenseRef-2
LicenseComments: The concluded license was taken from the package level that the file was included in.
FileCopyrightText: <text>Copyright 2008-2010 John Smith</text>
FileNotice: <text>Copyright (c) 2001 Aaron Lehmann aaroni@vitelus.com

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the �Software�), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED �AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.</text>
FileContributor: The Regents of the University of California
FileContributor: Modified by Paul Mundt lethal@linux-sh.org
FileContributor: IBM Corporation
## Annotations
Annotator: Person: File Commenter
AnnotationDate: 2011-01-29T18:30:22Z
AnnotationComment: <text>File level annotation</text>
AnnotationType: OTHER
SPDXREF: SPDXRef-File
## Relationships
Relationship: SPDXRef-File GENERATED_FROM SPDXRef-fromDoap-0
## Package Information
PackageName: glibc
SPDXID: SPDXRef-Package
PackageVersion: 2.11.1
PackageFileName: glibc-2.11.1.tar.gz
PackageSupplier: Person: Jane Doe (jane.doe@example.com)
PackageOriginator: Organization: ExampleCodeInspect (contact@example.com)
PackageDownloadLocation: http://ftp.gnu.org/gnu/glibc/glibc-ports-2.15.tar.gz
PackageVerificationCode: d6a770ba38583ed4bb4525bd96e50461655d2758(./package.spdx)
PackageChecksum: MD5: 624c1abb3664f4b35547e7c73864ad24
PackageChecksum: SHA1: 85ed0817af83a24ad8da68c2b5094de69833983c
PackageChecksum: SHA256: 11b6d3ee554eedf79299905a98f9b9a04e498210b59f15094c916c91d150efcd
PackageHomePage: http://ftp.gnu.org/gnu/glibc
PackageSourceInfo: <text>uses glibc-2_11-branch from git://sourceware.org/git/glibc.git.</text>
PackageLicenseConcluded: (LGPL-2.0-only OR LicenseRef-3)
## License information from files
PackageLicenseInfoFromFiles: GPL-2.0-only
PackageLicenseInfoFromFiles: LicenseRef-2
PackageLicenseInfoFromFiles: LicenseRef-1
PackageLicenseDeclared: (LGPL-2.0-only AND LicenseRef-3)
PackageLicenseComments: <text>The license for this project changed with the release of version x.y.  The version of the project included here post-dates the license change.</text>
PackageCopyrightText: <text>Copyright 2008-2010 John Smith</text>
PackageSummary: <text>GNU C library.</text>
PackageDescription: <text>The GNU C Library defines functions that are specified by the ISO C standard, as well as additional features specific to POSIX and other derivatives of the Unix operating system, and extensions specific to GNU systems.</text>
PackageAttributionText: <text>The GNU C Library is free software.  See the file COPYING.LIB for copying conditions, and LICENSES for notices about a few contributions that require these additional notices to be distributed.  License copyright years may be listed using range notation, e.g., 1996-2015, indicating that every year in the range, inclusive, is a copyrightable year that would otherwise be listed individually.</text>
ExternalRef: SECURITY cpe23Type cpe:2.3:a:pivotal_software:spring_framework:4.1.0:*:*:*:*:*:*:*
ExternalRef: OTHER LocationRef-acmeforge acmecorp/acmenator/4.1.3-alpha
ExternalRefComment: This is the external ref for Acme
## Annotations
Annotator: Person: Package Commenter
AnnotationDate: 2011-01-29T18:30:22Z
AnnotationComment: <text>Package level annotation</text>
AnnotationType: OTHER
SPDXREF: SPDXRef-Package
## Relationships
Relationship: SPDXRef-Package CONTAINS SPDXRef-JenaLib
Relationship: SPDXRef-Package DYNAMIC_LINK SPDXRef-Saxon

## File Information
FileName: ./lib-source/commons-lang3-3.1-sources.jar
SPDXID: SPDXRef-CommonsLangSrc
FileComment: <text>This file is used by Jena</text>
FileType: ARCHIVE
FileChecksum: SHA1: c2b4e1c67a2d28fced849ee1bb76e7391b93f125
LicenseConcluded: Apache-2.0
LicenseInfoInFile: Apache-2.0
FileCopyrightText: <text>Copyright 2001-2011 The Apache Software Foundation</text>
FileNotice: <text>Apache Commons Lang
Copyright 2001-2011 The Apache Software Foundation

This product includes software developed by
The Apache Software Foundation (http://www.apache.org/).

This product includes software from the Spring Framework,
under the Apache License 2.0 (see: StringUtils.containsWhitespace())</text>
FileContributor: Apache Software Foundation
## Relationships
Relationship: SPDXRef-CommonsLangSrc GENERATED_FROM NOASSERTION

FileName: ./lib-source/jena-2.6.3-sources.jar
SPDXID: SPDXRef-JenaLib
FileComment: <text>This file belongs to Jena</text>
FileType: ARCHIVE
FileChecksum: SHA1: 3ab4e1c67a2d28fced849ee1bb76e7391b93f125
LicenseConcluded: LicenseRef-1
LicenseInfoInFile: LicenseRef-1
LicenseComments: This license is used by Jena
FileCopyrightText: <text>(c) Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Hewlett-Packard Development Company, LP</text>
FileContributor: Apache Software Foundation
FileContributor: Hewlett Packard Inc.
## Relationships
Relationship: SPDXRef-JenaLib CONTAINS SPDXRef-Package

FileName: ./src/org/spdx/parser/DOAPProject.java
SPDXID: SPDXRef-DoapSource
FileType: SOURCE
FileChecksum: SHA1: 2fd4e1c67a2d28fced849ee1bb76e7391b93eb12
LicenseConcluded: Apache-2.0
LicenseInfoInFile: Apache-2.0
FileCopyrightText: <text>Copyright 2010, 2011 Source Auditor Inc.</text>
FileContributor: Protecode Inc.
FileContributor: SPDX Technical Team Members
FileContributor: Open Logic Inc.
FileContributor: Source Auditor Inc.
FileContributor: Black Duck Software In.c

## Package Information
PackageName: Apache Commons Lang
SPDXID: SPDXRef-fromDoap-1
PackageDownloadLocation: NOASSERTION
PackageHomePage: http://commons.apache.org/proper/commons-lang/
PackageLicenseConcluded: NOASSERTION
PackageLicenseDeclared: NOASSERTION
PackageCopyrightText: <text>NOASSERTION</text>
FilesAnalyzed: false

## Package Information
PackageName: Jena
SPDXID: SPDXRef-fromDoap-0
PackageVersion: 3.12.0
PackageDownloadLocation: https://search.maven.org/remotecontent?filepath=org/apache/jena/apache-jena/3.12.0/apache-jena-3.12.0.tar.gz
PackageHomePage: http://www.openjena.org/
PackageLicenseConcluded: NOASSERTION
PackageLicenseDeclared: NOASSERTION
PackageCopyrightText: <text>NOASSERTION</text>
ExternalRef: PACKAGE-MANAGER purl pkg:maven/org.apache.jena/apache-jena@3.12.0
FilesAnalyzed: false

## Package Information
PackageName: Saxon
SPDXID: SPDXRef-Saxon
PackageVersion: 8.8
PackageFileName: saxonB-8.8.zip
PackageDownloadLocation: https://sourceforge.net/projects/saxon/files/Saxon-B/8.8.0.7/saxonb8-8-0-7j.zip/download
PackageChecksum: SHA1: 85ed0817af83a24ad8da68c2b5094de69833983c
PackageHomePage: http://saxon.sourceforge.net/
PackageLicenseConcluded: MPL-1.0
PackageLicenseDeclared: MPL-1.0
PackageLicenseComments: <text>Other versions available for a commercial license</text>
PackageCopyrightText: <text>Copyright Saxonica Ltd</text>
PackageDescription: <text>The Saxon package is a collection of tools for processing XML documents.</text>
FilesAnalyzed: false

## Snippet Information
SnippetSPDXID: SPDXRef-Snippet
SnippetFromFileSPDXID: SPDXRef-DoapSource
SnippetByteRange: 310:420
SnippetLineRange: 5:23
SnippetLicenseConcluded: GPL-2.0-only
LicenseInfoInSnippet: GPL-2.0-only
SnippetLicenseComments: The concluded license was taken from package xyz, from which the snippet was copied into the current file. The concluded license information was found in the COPYING.txt file in package xyz.
SnippetCopyrightText: Copyright 2008-2010 John Smith
SnippetComment: This snippet was identified as significant and highlighted in this Apache-2.0 file, when a commercial scanner identified it as being derived from file foo.c in package xyz which is licensed under GPL-2.0.
SnippetName: from linux kernel


## License Information
LicenseID: LicenseRef-1
ExtractedText: <text>/*
 * (c) Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Hewlett-Packard Development Company, LP
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/</text>

LicenseID: LicenseRef-2
ExtractedText: <text>This package includes the GRDDL parser developed by Hewlett Packard under the following license:
� Copyright 2007 Hewlett-Packard Development Company, LP

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 

Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 
Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 
The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. 
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.</text>

LicenseID: LicenseRef-4
ExtractedText: <text>/*
 * (c) Copyright 2009 University of Bristol
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/</text>

LicenseID: LicenseRef-Beerware-4.2
ExtractedText: <text>"THE BEER-WARE LICENSE" (Revision 42):
phk@FreeBSD.ORG wrote this file. As long as you retain this notice you
can do whatever you want with this stuff. If we meet some day, and you think this stuff is worth it, you can buy me a beer in return Poul-Henning Kamp</text>
LicenseName: Beer-Ware License (Version 42)
LicenseCrossReference:  http://people.freebsd.org/~phk/
LicenseComment: The beerware license has a couple of other standard variants.

LicenseID: LicenseRef-3
ExtractedText: <text>The CyberNeko Software License, Version 1.0

 
(C) Copyright 2002-2005, Andy Clark.  All rights reserved.
 
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

1. Redistributions of source code must retain the above copyright
   notice, this list of conditions and the following disclaimer. 

2. Redistributions in binary form must reproduce the above copyright
   notice, this list of conditions and the following disclaimer in
   the documentation and/or other materials provided with the
   distribution.

3. The end-user documentation included with the redistribution,
   if any, must include the following acknowledgment:  
     "This product includes software developed by Andy Clark."
   Alternately, this acknowledgment may appear in the software itself,
   if and wherever such third-party acknowledgments normally appear.

4. The names "CyberNeko" and "NekoHTML" must not be used to endorse
   or promote products derived from this software without prior 
   written permission. For written permission, please contact 
   andyc@cyberneko.net.

5. Products derived from this software may not be called "CyberNeko",
   nor may "CyberNeko" appear in their name, without prior written
   permission of the author.

THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.</text>
LicenseName: CyberNeko License
LicenseCrossReference: http://people.apache.org/~andyc/neko/LICENSE, http://justasample.url.com
LicenseComment: <text>This is tye CyperNeko License</text>


tests/data/formats/SPDXSimpleTag.tag METASEP
# Document info
SPDXVersion: SPDX-2.1
DataLicense: CC0-1.0
DocumentName: Sample_Document-V2.1
SPDXID: SPDXRef-DOCUMENT
DocumentNamespace: https://spdx.org/spdxdocs/spdx-example-444504E0-4F89-41D3-9A0C-0305E82C3301
DocumentComment: <text>Sample Comment</text>
ExternalDocumentRef:DocumentRef-spdx-tool-2.1 https://spdx.org/spdxdocs/spdx-tools-v2.1-3F2504E0-4F89-41D3-9A0C-0305E82C3301 SHA1: d6a770ba38583ed4bb4525bd96e50461655d2759

# Creation info
Creator: Person: Bob (bob@example.com)
Creator: Organization: Acme
Created: 2014-02-03T00:00:00Z
CreatorComment: <text>Sample Comment</text>

# Review #1
Reviewer: Person: Bob the Reviewer
ReviewDate: 2014-02-10T00:00:00Z
ReviewComment: <text>Bob was Here.</text>

# Review #2
Reviewer: Person: Alice the Reviewer
ReviewDate: 2014-04-10T00:00:00Z
ReviewComment: <text>Alice was also here.</text>


# Package info
PackageName: Test
SPDXID: SPDXRef-Package
PackageVersion: Version 0.9.2
PackageDownloadLocation: http://example.com/test
PackageSummary: <text>Test package</text>
PackageSourceInfo: <text>Version 1.0 of test</text>
PackageFileName: test-1.0.zip
PackageSupplier: Organization:ACME
PackageOriginator: Organization:ACME
PackageAttributionText: <text>The GNU C Library is free software.  See the file COPYING.LIB for copying conditions, and LICENSES for notices about a few contributions that require these additional notices to be distributed.  License copyright years may be listed using range notation, e.g., 1996-2015, indicating that every year in the range, inclusive, is a copyrightable year that would otherwise be listed individually.</text>
PackageChecksum: SHA1: 2fd4e1c67a2d28fced849ee1bb76e7391b93eb12
PackageVerificationCode: 4e3211c67a2d28fced849ee1bb76e7391b93feba (something.rdf, something.txt)
PackageDescription: <text>A package.</text>
PackageAttributionText: <text>The GNU C Library is free software.  See the file COPYING.LIB for copying conditions, and LICENSES for notices about a few contributions that require these additional notices to be distributed.  License copyright years may be listed using range notation, e.g., 1996-2015, indicating that every year in the range, inclusive, is a copyrightable year that would otherwise be listed individually.</text>
PackageCopyrightText: <text>Copyright 2010, 2011 Acme Inc.</text>
PackageLicenseDeclared: Apache-2.0
PackageLicenseConcluded: (LicenseRef-2.0 and Apache-2.0)
PackageLicenseInfoFromFiles: Apache-1.0
PackageLicenseInfoFromFiles: Apache-2.0
PackageLicenseComments: <text>License Comments</text>

# File Info

FileName: testfile.java
SPDXID: SPDXRef-File
FileType: SOURCE
FileChecksum: SHA1: 2fd4e1c67a2d28fced849ee1bb76e7391b93eb12
LicenseConcluded: Apache-2.0
LicenseInfoInFile: Apache-2.0
FileCopyrightText: <text>Copyright 2014 Acme Inc.</text>
ArtifactOfProjectName: AcmeTest
ArtifactOfProjectHomePage: http://www.acme.org/
ArtifactOfProjectURI: http://www.acme.org/
FileComment: <text>Very long file</text>





tests/data/formats/SPDXSBOMExample.tag METASEP
# Document Information

SPDXVersion: SPDX-2.2
DataLicense: CC0-1.0
DocumentNamespace: http://spdx.org/spdxdocs/spdx-document-xyz
DocumentName: xyz-0.1.0
SPDXID: SPDXRef-DOCUMENT


# Creation Info

Creator: Organization: Example Inc.
Creator: Person: Thomas Steenbergen
Created: 2020-07-23T18:30:22Z


# Relationships

Relationship: SPDXRef-Package-xyz CONTAINS SPDXRef-Package-curl
Relationship: SPDXRef-Package-xyz CONTAINS SPDXRef-Package-openssl


# Package

PackageName: xyz
SPDXID: SPDXRef-Package-xyz
PackageVersion: 0.1.0
PackageDownloadLocation: git+ssh://gitlab.example.com:3389/products/xyz.git@b2c358080011af6a366d2512a25a379fbe7b1f78
FilesAnalyzed: False
PackageSummary: <text>Awesome product created by Example Inc.</text>
PackageLicenseDeclared: (Apache-2.0 AND curl AND LicenseRef-Proprietary-ExampleInc)
PackageLicenseConcluded: NOASSERTION
PackageCopyrightText: <text>copyright 2004-2020 Example Inc. All Rights Reserved.</text>
PackageHomePage: https://example.com/products/xyz


# Package

PackageName: curl
SPDXID: SPDXRef-Package-curl
PackageVersion: 7.70.0
PackageDownloadLocation: https://github.com/curl/curl/releases/download/curl-7_70_0/curl-7.70.0.tar.gz
FilesAnalyzed: False
PackageFileName: ./libs/curl
PackageDescription: <text>A command line tool and library for transferring data with URL syntax, supporting HTTP, HTTPS, FTP, FTPS, GOPHER, TFTP, SCP, SFTP, SMB, TELNET, DICT, LDAP, LDAPS, MQTT, FILE, IMAP, SMTP, POP3, RTSP and RTMP. libcurl offers a myriad of powerful features.</text>
PackageLicenseDeclared: curl
PackageLicenseConcluded: NOASSERTION
PackageCopyrightText: <text>Copyright (c) 1996 - 2020, Daniel Stenberg, <daniel@haxx.se>, and many contributors, see the THANKS file.</text>
PackageHomePage: https://curl.haxx.se/


# Package

PackageName: openssl
SPDXID: SPDXRef-Package-openssl
PackageVersion: 1.1.1g
PackageDownloadLocation: git+ssh://github.com/openssl/openssl.git@e2e09d9fba1187f8d6aafaa34d4172f56f1ffb72
FilesAnalyzed: False
PackageFileName: ./libs/openssl
PackageDescription: <text>OpenSSL is a robust, commercial-grade, full-featured Open Source Toolkit for the Transport Layer Security (TLS) protocol formerly known as the Secure Sockets Layer (SSL) protocol. The protocol implementation is based on a full-strength general purpose cryptographic library, which can also be used stand-alone.</text>
PackageLicenseDeclared: Apache-2.0
PackageLicenseConcluded: NOASSERTION
PackageCopyrightText: <text>copyright 2004-2020 The OpenSSL Project Authors. All Rights Reserved.</text>
PackageHomePage: https://www.openssl.org/

tests/data/formats/SPDXSBOMExample.spdx.yml METASEP
# example of an SBOM with several packages and filesAnalyzed=False
# from https://github.com/spdx/spdx-spec/issues/439
SPDXID: "SPDXRef-DOCUMENT"
spdxVersion: "SPDX-2.2"
creationInfo:
  created: "2020-07-23T18:30:22Z"
  creators:
  - "Organization: Example Inc."
  - "Person: Thomas Steenbergen"
  licenseListVersion: "3.9"
name: "xyz-0.1.0"
dataLicense: "CC0-1.0"
documentNamespace: "http://spdx.org/spdxdocs/spdx-document-xyz"
documentDescribes:
- "SPDXRef-Package-xyz"
packages:
- SPDXID: "SPDXRef-Package-xyz"
  summary: "Awesome product created by Example Inc."
  checksums:
    - algorithm: SHA1
      checksumValue: SOME-SHA1
  copyrightText: "copyright 2004-2020 Example Inc. All Rights Reserved."
  downloadLocation: "git+ssh://gitlab.example.com:3389/products/xyz.git@b2c358080011af6a366d2512a25a379fbe7b1f78"
  filesAnalyzed: false
  homepage: "https://example.com/products/xyz"
  licenseConcluded:  "NOASSERTION"
  licenseDeclared: "Apache-2.0 AND curl AND LicenseRef-Proprietary-ExampleInc"
  name: "xyz"
  versionInfo: "0.1.0"
- SPDXID: "SPDXRef-Package-curl"
  description: "A command line tool and library for transferring data with URL syntax, supporting \
     HTTP, HTTPS, FTP, FTPS, GOPHER, TFTP, SCP, SFTP, SMB, TELNET, DICT, LDAP, LDAPS, MQTT, FILE, \
     IMAP, SMTP, POP3, RTSP and RTMP. libcurl offers a myriad of powerful features."
  checksums:
    - algorithm: SHA1
      checksumValue: SOME-SHA1
  copyrightText: "Copyright (c) 1996 - 2020, Daniel Stenberg, <daniel@haxx.se>, and many
    contributors, see the THANKS file."
  downloadLocation: "https://github.com/curl/curl/releases/download/curl-7_70_0/curl-7.70.0.tar.gz"
  filesAnalyzed: false
  homepage: "https://curl.haxx.se/"
  licenseConcluded: "NOASSERTION"
  licenseDeclared: "curl"
  name: "curl"
  packageFileName: "./libs/curl"
  versionInfo: "7.70.0"
- SPDXID: "SPDXRef-Package-openssl"
  description: "OpenSSL is a robust, commercial-grade, full-featured Open Source Toolkit for the Transport Layer Security (TLS) protocol formerly known as the Secure Sockets Layer (SSL) protocol. The protocol implementation is based on a full-strength general purpose cryptographic library, which can also be used stand-alone."
  copyrightText: "copyright 2004-2020 The OpenSSL Project Authors. All Rights Reserved."
  checksums:
    - algorithm: SHA1
      checksumValue: SOME-SHA1
  downloadLocation: "git+ssh://github.com/openssl/openssl.git@e2e09d9fba1187f8d6aafaa34d4172f56f1ffb72"
  filesAnalyzed: false
  homepage: "https://www.openssl.org/"
  licenseConcluded: "NOASSERTION"
  licenseDeclared: "Apache-2.0"
  packageFileName: "./libs/openssl"
  name: "openssl"
  versionInfo: "1.1.1g"
relationships:
- spdxElementId: "SPDXRef-Package-xyz"
  relatedSpdxElement: "SPDXRef-Package-curl"
  relationshipType: "CONTAINS"
- spdxElementId: "SPDXRef-Package-xyz"
  relatedSpdxElement: "SPDXRef-Package-openssl"
  relationshipType: "CONTAINS"
tests/data/formats/SPDXRdfExample.rdf METASEP
<rdf:RDF
    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
    xmlns:j.0="http://usefulinc.com/ns/doap#"
    xmlns="http://spdx.org/rdf/terms#"
    xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#">
  <Snippet rdf:about="http://spdx.org/spdxdocs/spdx-example-444504E0-4F89-41D3-9A0C-0305E82C3301#SPDXRef-Snippet">
    <snippetFromFile>
      <File rdf:about="http://spdx.org/spdxdocs/spdx-example-444504E0-4F89-41D3-9A0C-0305E82C3301#SPDXRef-DoapSource"/>
    </snippetFromFile>
    <name>from linux kernel</name>
    <copyrightText>Copyright 2008-2010 John Smith</copyrightText>
    <licenseComments>The concluded license was taken from package xyz, from which the snippet was copied into the current file. The concluded license information was found in the COPYING.txt file in package xyz.</licenseComments>
    <rdfs:comment>This snippet was identified as significant and highlighted in this Apache-2.0 file, when a commercial scanner identified it as being derived from file foo.c in package xyz which is licensed under GPL-2.0-or-later.</rdfs:comment>
    <licenseConcluded rdf:resource="http://spdx.org/licenses/Apache-2.0"/>
    <licenseInfoInSnippet rdf:resource="http://spdx.org/licenses/Apache-2.0"/>
  </Snippet>
  <SpdxDocument rdf:about="https://spdx.org/spdxdocs/spdx-example-444504E0-4F89-41D3-9A0C-0305E82C3301#SPDXRef-DOCUMENT">
    <name>Sample_Document-V2.1</name>
    <creationInfo>
      <CreationInfo>
        <created>2010-02-03T00:00:00Z</created>
        <rdfs:comment>This is an example of an SPDX spreadsheet format</rdfs:comment>
        <creator>Tool: SourceAuditor-V1.2</creator>
        <creator>Organization: Source Auditor Inc.</creator>
        <creator>Person: Gary O'Neall</creator>
      </CreationInfo>
    </creationInfo>
    <specVersion>SPDX-2.1</specVersion>
    <externalDocumentRef>
      <ExternalDocumentRef>
        <externalDocumentId>DocumentRef-spdx-tool-2.1</externalDocumentId>
        <spdxDocument rdf:resource="https://spdx.org/spdxdocs/spdx-tools-v2.1-3F2504E0-4F89-41D3-9A0C-0305E82C3301"/>
        <checksum>
          <Checksum>
            <checksumValue>d6a770ba38583ed4bb4525bd96e50461655d2759</checksumValue>
            <algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/>
          </Checksum>
        </checksum>
      </ExternalDocumentRef>
    </externalDocumentRef>
    <referencesFile>
      <File rdf:about="https://spdx.org/spdxdocs/spdx-example-444504E0-4F89-41D3-9A0C-0305E82C3301#SPDXRef-File1">>
        <licenseConcluded>
          <ExtractedLicensingInfo rdf:nodeID="A1">
            <extractedText>/*
 * (c) Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Hewlett-Packard Development Company, LP
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */</extractedText>
            <licenseId>LicenseRef-1</licenseId>
          </ExtractedLicensingInfo>
        </licenseConcluded>
        <artifactOf>
          <j.0:Project>
            <j.0:homepage>http://www.openjena.org/</j.0:homepage>
            <j.0:name>Jena</j.0:name>
          </j.0:Project>
        </artifactOf>
        <licenseComments>This license is used by Jena</licenseComments>
        <fileName>Jenna-2.6.3/jena-2.6.3-sources.jar</fileName>
        <fileType rdf:resource="http://spdx.org/rdf/terms#fileType_archive"/>
        <fileType rdf:resource="http://spdx.org/rdf/terms#fileType_other"/>
        <copyrightText>(c) Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Hewlett-Packard Development Company, LP</copyrightText>
        <licenseInfoInFile rdf:nodeID="A1"/>
        <rdfs:comment>This file belongs to Jena</rdfs:comment>
        <checksum>
          <Checksum>
            <checksumValue>3ab4e1c67a2d28fced849ee1bb76e7391b93f125</checksumValue>
            <algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/>
          </Checksum>
        </checksum>
        <checksum>
          <Checksum>
            <checksumValue>3ab4e1c67a2d28fced849ee1bb76e7391b93f1250000000000000000</checksumValue>
            <algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha256"/>
          </Checksum>
        </checksum>
      </File>
    </referencesFile>
    <reviewed>
      <Review>
        <rdfs:comment>This is just an example.  Some of the non-standard licenses look like they are actually BSD 3 clause licenses</rdfs:comment>
        <reviewDate>2010-02-10T00:00:00Z</reviewDate>
        <reviewer>Person: Joe Reviewer</reviewer>
      </Review>
    </reviewed>
    <dataLicense rdf:resource="http://spdx.org/licenses/CC0-1.0"/>
    <hasExtractedLicensingInfo rdf:nodeID="A1"/>
    <reviewed>
      <Review>
        <rdfs:comment>Another example reviewer.</rdfs:comment>
        <reviewDate>2011-03-13T00:00:00Z</reviewDate>
        <reviewer>Person: Suzanne Reviewer</reviewer>
      </Review>
    </reviewed>
    <annotation>
      <Annotation rdf:about="https://spdx.org/spdxdocs/spdx-example-444504E0-4F89-41D3-9A0C-0305E82C3301#SPDXRef-45">
        <annotationType rdf:resource="http://spdx.org/rdf/terms#annotationType_review"/>
        <rdfs:comment>This is just an example. Some of the non-standard licenses look like they are actually BSD 3 clause licenses</rdfs:comment>
        <annotationDate>2012-06-13T00:00:00Z</annotationDate>
        <annotator>Person: Jim Reviewer</annotator>
      </Annotation>
    </annotation>
    <relationship>
      <Relationship>
        <relationshipType rdf:resource="http://spdx.org/rdf/terms#relationshipType_describes"/>
        <relatedSpdxElement rdf:resource="http://spdx.org/spdxdocs/spdx-example-444504E0-4F89-41D3-9A0C-0305E82C3301#SPDXRef-Package"/>
      </Relationship>
    </relationship>
    <referencesFile>
      <File rdf:about="https://spdx.org/spdxdocs/spdx-example-444504E0-4F89-41D3-9A0C-0305E82C3301#SPDXRef-File2">
        <copyrightText>Copyright 2010, 2011 Source Auditor Inc.</copyrightText>
        <licenseInfoInFile rdf:resource="http://spdx.org/licenses/Apache-2.0"/>
        <licenseConcluded rdf:resource="http://spdx.org/licenses/Apache-2.0"/>
        <fileType rdf:resource="http://spdx.org/rdf/terms#fileType_source"/>
        <fileType rdf:resource="http://spdx.org/rdf/terms#fileType_text"/>
        <checksum>
          <Checksum>
            <checksumValue>2fd4e1c67a2d28fced849ee1bb76e7391b93eb12</checksumValue>
            <algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/>
          </Checksum>
        </checksum>
        <checksum>
          <Checksum>
            <checksumValue>2fd4e1c67a2d28fced849ee1bb76e7391b93eb120000000000000000</checksumValue>
            <algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha256"/>
          </Checksum>
        </checksum>
        <fileName>src/org/spdx/parser/DOAPProject.java</fileName>
      </File>
    </referencesFile>
    <describesPackage>
      <Package rdf:about="http://www.spdx.org/tools#SPDXRef-Package">
        <licenseInfoFromFiles rdf:resource="http://spdx.org/licenses/Apache-1.0"/>
        <downloadLocation>http://www.spdx.org/tools</downloadLocation>
        <filesAnalyzed>true</filesAnalyzed>
        <supplier>Organization:Linux Foundation</supplier>
        <hasFile rdf:nodeID="A0"/>
        <licenseInfoFromFiles rdf:resource="http://spdx.org/licenses/Apache-2.0"/>
        <packageVerificationCode>
          <PackageVerificationCode>
            <packageVerificationCodeValue>4e3211c67a2d28fced849ee1bb76e7391b93feba</packageVerificationCodeValue>
            <packageVerificationCodeExcludedFile>SpdxTranslatorSpdx.txt</packageVerificationCodeExcludedFile>
            <packageVerificationCodeExcludedFile>SpdxTranslatorSpdx.rdf</packageVerificationCodeExcludedFile>
          </PackageVerificationCode>
        </packageVerificationCode>
        <checksum>
          <Checksum>
            <checksumValue>2fd4e1c67a2d28fced849ee1bb76e7391b93eb12</checksumValue>
            <algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/>
          </Checksum>
        </checksum>
        <licenseConcluded>
          <ConjunctiveLicenseSet>
            <member>
              <ExtractedLicensingInfo rdf:nodeID="A3">
                <extractedText>This package includes the GRDDL parser developed by Hewlett Packard under the following license:
© Copyright 2007 Hewlett-Packard Development Company, LP

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 

Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 
Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 
The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. 
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. </extractedText>
                <licenseId>LicenseRef-2</licenseId>
              </ExtractedLicensingInfo>
            </member>
            <member rdf:nodeID="A1"/>
            <member rdf:resource="http://spdx.org/licenses/Apache-2.0"/>
            <member rdf:resource="http://spdx.org/licenses/MPL-1.1"/>
            <member rdf:resource="http://spdx.org/licenses/Apache-1.0"/>
            <member>
              <ExtractedLicensingInfo rdf:nodeID="A4">
                <extractedText>/*
 * (c) Copyright 2009 University of Bristol
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */  </extractedText>
                <licenseId>LicenseRef-4</licenseId>
              </ExtractedLicensingInfo>
            </member>
            <member>
              <ExtractedLicensingInfo rdf:nodeID="A5">
                <rdfs:seeAlso>http://justasample.url.com</rdfs:seeAlso>
                <rdfs:seeAlso>http://people.apache.org/~andyc/neko/LICENSE</rdfs:seeAlso>
                <licenseName>CyberNeko License</licenseName>
                <rdfs:comment>This is tye CyperNeko License</rdfs:comment>
                <extractedText>The CyberNeko Software License, Version 1.0

 
(C) Copyright 2002-2005, Andy Clark.  All rights reserved.
 
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

1. Redistributions of source code must retain the above copyright
   notice, this list of conditions and the following disclaimer. 

2. Redistributions in binary form must reproduce the above copyright
   notice, this list of conditions and the following disclaimer in
   the documentation and/or other materials provided with the
   distribution.

3. The end-user documentation included with the redistribution,
   if any, must include the following acknowledgment:  
     "This product includes software developed by Andy Clark."
   Alternately, this acknowledgment may appear in the software itself,
   if and wherever such third-party acknowledgments normally appear.

4. The names "CyberNeko" and "NekoHTML" must not be used to endorse
   or promote products derived from this software without prior 
   written permission. For written permission, please contact 
   andyc@cyberneko.net.

5. Products derived from this software may not be called "CyberNeko",
   nor may "CyberNeko" appear in their name, without prior written
   permission of the author.

THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.</extractedText>
                <licenseId>LicenseRef-3</licenseId>
              </ExtractedLicensingInfo>
            </member>
          </ConjunctiveLicenseSet>
        </licenseConcluded>
        <sourceInfo>Version 1.0 of the SPDX Translator application</sourceInfo>
        <checksum>
          <Checksum>
            <checksumValue>2fd4e1c67a2d28fced849ee1bb76e7391b93eb12</checksumValue>
            <algorithm rdf:resource="http://spdx.org/rdf/terms#checksumAlgorithm_sha1"/>
          </Checksum>
        </checksum>
        <packageFileName>spdxtranslator-1.0.zip</packageFileName>
        <description>This utility translates and SPDX RDF XML document to a spreadsheet, translates a spreadsheet to an SPDX RDF XML document and translates an SPDX RDFa document to an SPDX RDF XML document.</description>
        <licenseInfoFromFiles rdf:nodeID="A4"/>
        <name>SPDX Translator</name>
        <versionInfo>Version 0.9.2</versionInfo>
        <licenseInfoFromFiles rdf:nodeID="A1"/>
        <hasFile rdf:nodeID="A2"/>
        <licenseInfoFromFiles rdf:nodeID="A3"/>
        <copyrightText> Copyright 2010, 2011 Source Auditor Inc.</copyrightText>
        <licenseDeclared>
          <ConjunctiveLicenseSet>
            <member rdf:nodeID="A3"/>
            <member rdf:nodeID="A1"/>
            <member rdf:resource="http://spdx.org/licenses/Apache-2.0"/>
            <member rdf:resource="http://spdx.org/licenses/MPL-1.1"/>
            <member rdf:nodeID="A4"/>
            <member rdf:nodeID="A5"/>
          </ConjunctiveLicenseSet>
        </licenseDeclared>
        <licenseInfoFromFiles rdf:nodeID="A5"/>
        <originator>Organization:SPDX</originator>
        <licenseComments>The declared license information can be found in the NOTICE file at the root of the archive file</licenseComments>
        <summary>SPDX Translator utility</summary>
        <licenseInfoFromFiles rdf:resource="http://spdx.org/licenses/MPL-1.1"/>
        <externalRef>
          <ExternalRef>
            <referenceCategory rdf:resource="http://spdx.org/rdf/terms#referenceCategory_packageManager"/>
            <referenceType rdf:resource="http://spdx.org/rdf/references/maven-central"/>
            <referenceLocator>org.apache.commons:commons-lang:3.2.1</referenceLocator>
            <rdfs:comment>NIST National Vulnerability Database (NVD) describes security vulnerabilities (CVEs) which affect Vendor Product Version acmecorp:acmenator:6.6.6</rdfs:comment>
          </ExternalRef>
        </externalRef>
      </Package>
    </describesPackage>
    <rdfs:comment>This is a sample spreadsheet</rdfs:comment>
    <hasExtractedLicensingInfo rdf:nodeID="A4"/>
    <hasExtractedLicensingInfo rdf:nodeID="A5"/>
    <hasExtractedLicensingInfo rdf:nodeID="A3"/>
  </SpdxDocument>
</rdf:RDF>

tests/data/formats/SPDXJsonExample.json METASEP
{
  "comment": "This is a sample spreadsheet",
  "name": "Sample_Document-V2.1",
  "documentDescribes": [
    "SPDXRef-Package"
  ],
  "packages": [
    {
      "SPDXID": "SPDXRef-Package",
      "originator": "Organization: SPDX",
      "hasFiles": [
        "SPDXRef-File1",
        "SPDXRef-File2"
      ],
      "licenseInfoFromFiles": [
        "Apache-1.0",
        "LicenseRef-3",
        "MPL-1.1",
        "LicenseRef-2",
        "LicenseRef-4",
        "Apache-2.0",
        "LicenseRef-1"
      ],
      "name": "SPDX Translator",
      "packageFileName": "spdxtranslator-1.0.zip",
      "licenseComments": "The declared license information can be found in the NOTICE file at the root of the archive file",
      "summary": "SPDX Translator utility",
      "sourceInfo": "Version 1.0 of the SPDX Translator application",
      "copyrightText": " Copyright 2010, 2011 Source Auditor Inc.",
      "packageVerificationCode": {
        "packageVerificationCodeValue": "4e3211c67a2d28fced849ee1bb76e7391b93feba",
        "packageVerificationCodeExcludedFiles": [
          "SpdxTranslatorSpdx.rdf",
          "SpdxTranslatorSpdx.txt"
        ]
      },
      "licenseConcluded": "(Apache-1.0 AND LicenseRef-2 AND MPL-1.1 AND LicenseRef-3 AND LicenseRef-4 AND Apache-2.0 AND LicenseRef-1)",
      "supplier": "Organization: Linux Foundation",
      "attributionTexts": [
        "The GNU C Library is free software.  See the file COPYING.LIB for copying conditions, and LICENSES for notices about a few contributions that require these additional notices to be distributed.  License copyright years may be listed using range notation, e.g., 1996-2015, indicating that every year in the range, inclusive, is a copyrightable year that would otherwise be listed individually."
      ],
      "checksums": [
        {
          "checksumValue": "2fd4e1c67a2d28fced849ee1bb76e7391b93eb12",
          "algorithm": "SHA1"
        }
      ],
      "versionInfo": "Version 0.9.2",
      "licenseDeclared": "(LicenseRef-4 AND LicenseRef-3 AND Apache-2.0 AND LicenseRef-2 AND MPL-1.1 AND LicenseRef-1)",
      "downloadLocation": "http://www.spdx.org/tools",
      "description": "This utility translates and SPDX RDF XML document to a spreadsheet, translates a spreadsheet to an SPDX RDF XML document and translates an SPDX RDFa document to an SPDX RDF XML document.",
      "primaryPackagePurpose": "OPERATING-SYSTEM",
      "builtDate": "2020-01-01T12:00:00Z",
      "releaseDate": "2021-01-01T12:00:00Z",
      "validUntilDate": "2022-01-01T12:00:00Z"
    }
  ],
  "files": [
    {
      "comment": "This file belongs to Jena",
      "licenseInfoInFiles": [
        "LicenseRef-1"
      ],
      "fileName": "Jenna-2.6.3/jena-2.6.3-sources.jar",
      "copyrightText": "(c) Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Hewlett-Packard Development Company, LP",
      "artifactOf": [
        {
          "name": "Jena",
          "homePage": "http://www.openjena.org/",
          "projectUri": "http://subversion.apache.org/doap.rdf"
        }
      ],
      "licenseConcluded": "LicenseRef-1",
      "licenseComments": "This license is used by Jena",
    "checksums": [
        {
            "checksumValue": "3ab4e1c67a2d28fced849ee1bb76e7391b93f125",
            "algorithm": "SHA1"
        },
        {
            "checksumValue": "3ab4e1c67a2d28fced849ee1bb76e7391b93f1250000000000000000",
            "algorithm": "SHA256"
        }
        ],
      "fileTypes": [
        "ARCHIVE",
        "OTHER"
      ],
      "SPDXID": "SPDXRef-File1"
    },
    {
      "licenseInfoInFiles": [
        "Apache-2.0"
      ],
      "fileName": "src/org/spdx/parser/DOAPProject.java",
      "copyrightText": "Copyright 2010, 2011 Source Auditor Inc.",
      "licenseConcluded": "Apache-2.0",
      "checksums": [
        {
          "checksumValue": "2fd4e1c67a2d28fced849ee1bb76e7391b93eb12",
          "algorithm": "SHA1"
        }
      ],
      "fileTypes": [
        "SOURCE",
        "TEXT"
      ],
      "SPDXID": "SPDXRef-File2"
    }
  ],
  "creationInfo": {
    "comment": "This is an example of an SPDX spreadsheet format",
    "creators": [
      "Tool: SourceAuditor-V1.2",
      "Person: Gary O'Neall",
      "Organization: Source Auditor Inc."
    ],
    "licenseListVersion": "3.6",
    "created": "2010-02-03T00:00:00Z"
  },
  "externalDocumentRefs": [
    {
      "checksum": {
        "checksumValue": "d6a770ba38583ed4bb4525bd96e50461655d2759",
        "algorithm": "SHA1"
      },
      "spdxDocument": "https://spdx.org/spdxdocs/spdx-tools-v2.1-3F2504E0-4F89-41D3-9A0C-0305E82C3301",
      "externalDocumentId": "DocumentRef-spdx-tool-2.1"
    }
  ],
  "documentNamespace": "https://spdx.org/spdxdocs/spdx-example-444504E0-4F89-41D3-9A0C-0305E82C3301",
  "annotations": [
    {
      "comment": "This is just an example. Some of the non-standard licenses look like they are actually BSD 3 clause licenses",
      "annotationType": "REVIEW",
      "annotationDate": "2012-06-13T00:00:00Z",
      "annotator": "Person: Jim Reviewer"
    }
  ],
  "dataLicense": "CC0-1.0",
  "reviewers": [
    {
      "comment": "This is just an example.  Some of the non-standard licenses look like they are actually BSD 3 clause licenses",
      "reviewer": "Person: Joe Reviewer",
      "reviewDate": "2010-02-10T00:00:00Z"
    },
    {
      "comment": "Another example reviewer.",
      "reviewer": "Person: Suzanne Reviewer",
      "reviewDate": "2011-03-13T00:00:00Z"
    }
  ],
  "hasExtractedLicensingInfos": [
    {
      "extractedText": "This package includes the GRDDL parser developed by Hewlett Packard under the following license:\n\u00a9 Copyright 2007 Hewlett-Packard Development Company, LP\n\nRedistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:\n\nRedistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.\nRedistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.\nThe name of the author may not be used to endorse or promote products derived from this software without specific prior written permission.\nTHIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ",
      "licenseId": "LicenseRef-2"
    },
    {
      "extractedText": "The CyberNeko Software License, Version 1.0\n\n\n(C) Copyright 2002-2005, Andy Clark.  All rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions\nare met:\n\n1. Redistributions of source code must retain the above copyright\n   notice, this list of conditions and the following disclaimer.\n\n2. Redistributions in binary form must reproduce the above copyright\n   notice, this list of conditions and the following disclaimer in\n   the documentation and/or other materials provided with the\n   distribution.\n\n3. The end-user documentation included with the redistribution,\n   if any, must include the following acknowledgment:\n     \"This product includes software developed by Andy Clark.\"\n   Alternately, this acknowledgment may appear in the software itself,\n   if and wherever such third-party acknowledgments normally appear.\n\n4. The names \"CyberNeko\" and \"NekoHTML\" must not be used to endorse\n   or promote products derived from this software without prior\n   written permission. For written permission, please contact\n   andyc@cyberneko.net.\n\n5. Products derived from this software may not be called \"CyberNeko\",\n   nor may \"CyberNeko\" appear in their name, without prior written\n   permission of the author.\n\nTHIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED\nWARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\nOF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS\nBE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,\nOR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\nOF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR\nBUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\nWHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\nOR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\nEVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.",
      "comment": "This is tye CyperNeko License",
      "licenseId": "LicenseRef-3",
      "name": "CyberNeko License",
      "seeAlsos": [
        "http://justasample.url.com",
        "http://people.apache.org/~andyc/neko/LICENSE"
      ]
    },
    {
      "extractedText": "/*\n * (c) Copyright 2009 University of Bristol\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n * 3. The name of the author may not be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR\n * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,\n * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\n * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\n * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */  ",
      "licenseId": "LicenseRef-4"
    },
    {
      "extractedText": "/*\n * (c) Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Hewlett-Packard Development Company, LP\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n * 3. The name of the author may not be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR\n * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,\n * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\n * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\n * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */",
      "licenseId": "LicenseRef-1"
    }
  ],
  "spdxVersion": "SPDX-2.1",
  "SPDXID": "SPDXRef-DOCUMENT",
  "snippets": [
    {
      "comment": "This snippet was identified as significant and highlighted in this Apache-2.0 file, when a commercial scanner identified it as being derived from file foo.c in package xyz which is licensed under GPL-2.0-or-later.",
      "name": "from linux kernel",
      "copyrightText": "Copyright 2008-2010 John Smith",
      "licenseConcluded": "Apache-2.0",
      "licenseInfoInSnippets": [
        "Apache-2.0",
        "GPL-2.0-only"
      ],
      "licenseComments": "The concluded license was taken from package xyz, from which the snippet was copied into the current file. The concluded license information was found in the COPYING.txt file in package xyz.",
      "SPDXID": "SPDXRef-Snippet",
      "snippetFromFile": "SPDXRef-DoapSource",
        "ranges": [
            {
                "endPointer": {
                    "offset": 420,
                    "reference": "SPDXRef-DoapSource"
                },
                "startPointer": {
                    "offset": 310,
                    "reference": "SPDXRef-DoapSource"
                }
            },
            {
                "endPointer": {
                    "lineNumber": 23,
                    "reference": "SPDXRef-DoapSource"
                },
                "startPointer": {
                    "lineNumber": 5,
                    "reference": "SPDXRef-DoapSource"
                }
            }
        ]
    }
  ]
}

tests/data/formats/SPDXJSONExample-v2.3.spdx.json METASEP
{
  "SPDXID" : "SPDXRef-DOCUMENT",
  "spdxVersion" : "SPDX-2.3",
  "creationInfo" : {
    "comment" : "This package has been shipped in source and binary form.\nThe binaries were created with gcc 4.5.1 and expect to link to\ncompatible system run time libraries.",
    "created" : "2010-01-29T18:30:22Z",
    "creators" : [ "Tool: LicenseFind-1.0", "Organization: ExampleCodeInspect ()", "Person: Jane Doe ()" ],
    "licenseListVersion" : "3.17"
  },
  "name" : "SPDX-Tools-v2.0",
  "dataLicense" : "CC0-1.0",
  "comment" : "This document was created using SPDX 2.0 using licenses from the web site.",
  "externalDocumentRefs" : [ {
    "externalDocumentId" : "DocumentRef-spdx-tool-1.2",
    "checksum" : {
      "algorithm" : "SHA1",
      "checksumValue" : "d6a770ba38583ed4bb4525bd96e50461655d2759"
    },
    "spdxDocument" : "http://spdx.org/spdxdocs/spdx-tools-v1.2-3F2504E0-4F89-41D3-9A0C-0305E82C3301"
  } ],
  "hasExtractedLicensingInfos" : [ {
    "licenseId" : "LicenseRef-1",
    "extractedText" : "/*\n * (c) Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Hewlett-Packard Development Company, LP\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n * 3. The name of the author may not be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR\n * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,\n * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\n * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\n * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/"
  }, {
    "licenseId" : "LicenseRef-2",
    "extractedText" : "This package includes the GRDDL parser developed by Hewlett Packard under the following license:\n© Copyright 2007 Hewlett-Packard Development Company, LP\n\nRedistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: \n\nRedistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. \nRedistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. \nThe name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. \nTHIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
  }, {
    "licenseId" : "LicenseRef-4",
    "extractedText" : "/*\n * (c) Copyright 2009 University of Bristol\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n * 3. The name of the author may not be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR\n * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,\n * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\n * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\n * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/"
  }, {
    "licenseId" : "LicenseRef-Beerware-4.2",
    "comment" : "The beerware license has a couple of other standard variants.",
    "extractedText" : "\"THE BEER-WARE LICENSE\" (Revision 42):\nphk@FreeBSD.ORG wrote this file. As long as you retain this notice you\ncan do whatever you want with this stuff. If we meet some day, and you think this stuff is worth it, you can buy me a beer in return Poul-Henning Kamp",
    "name" : "Beer-Ware License (Version 42)",
    "seeAlsos" : [ "http://people.freebsd.org/~phk/" ]
  }, {
    "licenseId" : "LicenseRef-3",
    "comment" : "This is tye CyperNeko License",
    "extractedText" : "The CyberNeko Software License, Version 1.0\n\n \n(C) Copyright 2002-2005, Andy Clark.  All rights reserved.\n \nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions\nare met:\n\n1. Redistributions of source code must retain the above copyright\n   notice, this list of conditions and the following disclaimer. \n\n2. Redistributions in binary form must reproduce the above copyright\n   notice, this list of conditions and the following disclaimer in\n   the documentation and/or other materials provided with the\n   distribution.\n\n3. The end-user documentation included with the redistribution,\n   if any, must include the following acknowledgment:  \n     \"This product includes software developed by Andy Clark.\"\n   Alternately, this acknowledgment may appear in the software itself,\n   if and wherever such third-party acknowledgments normally appear.\n\n4. The names \"CyberNeko\" and \"NekoHTML\" must not be used to endorse\n   or promote products derived from this software without prior \n   written permission. For written permission, please contact \n   andyc@cyberneko.net.\n\n5. Products derived from this software may not be called \"CyberNeko\",\n   nor may \"CyberNeko\" appear in their name, without prior written\n   permission of the author.\n\nTHIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED\nWARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\nOF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS\nBE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, \nOR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT \nOF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR \nBUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, \nWHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE \nOR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, \nEVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.",
    "name" : "CyberNeko License",
    "seeAlsos" : [ "http://people.apache.org/~andyc/neko/LICENSE", "http://justasample.url.com" ]
  } ],
  "annotations" : [ {
    "annotationDate" : "2010-01-29T18:30:22Z",
    "annotationType" : "OTHER",
    "annotator" : "Person: Jane Doe ()",
    "comment" : "Document level annotation"
  }, {
    "annotationDate" : "2010-02-10T00:00:00Z",
    "annotationType" : "REVIEW",
    "annotator" : "Person: Joe Reviewer",
    "comment" : "This is just an example.  Some of the non-standard licenses look like they are actually BSD 3 clause licenses"
  }, {
    "annotationDate" : "2011-03-13T00:00:00Z",
    "annotationType" : "REVIEW",
    "annotator" : "Person: Suzanne Reviewer",
    "comment" : "Another example reviewer."
  } ],
  "documentDescribes" : [ "SPDXRef-File", "SPDXRef-Package" ],
  "documentNamespace" : "http://spdx.org/spdxdocs/spdx-example-444504E0-4F89-41D3-9A0C-0305E82C3301",
  "packages" : [ {
    "SPDXID" : "SPDXRef-Package",
    "annotations" : [ {
      "annotationDate" : "2011-01-29T18:30:22Z",
      "annotationType" : "OTHER",
      "annotator" : "Person: Package Commenter",
      "comment" : "Package level annotation"
    } ],
    "attributionTexts" : [ "The GNU C Library is free software.  See the file COPYING.LIB for copying conditions, and LICENSES for notices about a few contributions that require these additional notices to be distributed.  License copyright years may be listed using range notation, e.g., 1996-2015, indicating that every year in the range, inclusive, is a copyrightable year that would otherwise be listed individually." ],
    "builtDate" : "2011-01-29T18:30:22Z",
    "checksums" : [ {
      "algorithm" : "MD5",
      "checksumValue" : "624c1abb3664f4b35547e7c73864ad24"
    }, {
      "algorithm" : "SHA1",
      "checksumValue" : "85ed0817af83a24ad8da68c2b5094de69833983c"
    }, {
      "algorithm" : "SHA256",
      "checksumValue" : "11b6d3ee554eedf79299905a98f9b9a04e498210b59f15094c916c91d150efcd"
    }, {
      "algorithm" : "BLAKE2b-384",
      "checksumValue" : "aaabd89c926ab525c242e6621f2f5fa73aa4afe3d9e24aed727faaadd6af38b620bdb623dd2b4788b1c8086984af8706"
    } ],
    "copyrightText" : "Copyright 2008-2010 John Smith",
    "description" : "The GNU C Library defines functions that are specified by the ISO C standard, as well as additional features specific to POSIX and other derivatives of the Unix operating system, and extensions specific to GNU systems.",
    "downloadLocation" : "http://ftp.gnu.org/gnu/glibc/glibc-ports-2.15.tar.gz",
    "externalRefs" : [ {
      "referenceCategory" : "SECURITY",
      "referenceLocator" : "cpe:2.3:a:pivotal_software:spring_framework:4.1.0:*:*:*:*:*:*:*",
      "referenceType" : "cpe23Type"
    }, {
      "comment" : "This is the external ref for Acme",
      "referenceCategory" : "OTHER",
      "referenceLocator" : "acmecorp/acmenator/4.1.3-alpha",
      "referenceType" : "http://spdx.org/spdxdocs/spdx-example-444504E0-4F89-41D3-9A0C-0305E82C3301#LocationRef-acmeforge"
    } ],
    "filesAnalyzed" : true,
    "homepage" : "http://ftp.gnu.org/gnu/glibc",
    "licenseComments" : "The license for this project changed with the release of version x.y.  The version of the project included here post-dates the license change.",
    "licenseConcluded" : "(LGPL-2.0-only OR LicenseRef-3)",
    "licenseDeclared" : "(LGPL-2.0-only AND LicenseRef-3)",
    "licenseInfoFromFiles" : [ "GPL-2.0-only", "LicenseRef-2", "LicenseRef-1" ],
    "name" : "glibc",
    "originator" : "Organization: ExampleCodeInspect (contact@example.com)",
    "packageFileName" : "glibc-2.11.1.tar.gz",
    "packageVerificationCode" : {
      "packageVerificationCodeExcludedFiles" : [ "./package.spdx" ],
      "packageVerificationCodeValue" : "d6a770ba38583ed4bb4525bd96e50461655d2758"
    },
    "primaryPackagePurpose" : "SOURCE",
    "hasFiles" : [ "SPDXRef-Specification", "SPDXRef-Specification", "SPDXRef-CommonsLangSrc", "SPDXRef-Specification", "SPDXRef-CommonsLangSrc", "SPDXRef-JenaLib", "SPDXRef-Specification", "SPDXRef-CommonsLangSrc", "SPDXRef-JenaLib", "SPDXRef-DoapSource", "SPDXRef-Specification", "SPDXRef-CommonsLangSrc", "SPDXRef-JenaLib", "SPDXRef-DoapSource" ],
    "releaseDate" : "2012-01-29T18:30:22Z",
    "sourceInfo" : "uses glibc-2_11-branch from git://sourceware.org/git/glibc.git.",
    "summary" : "GNU C library.",
    "supplier" : "Person: Jane Doe (jane.doe@example.com)",
    "validUntilDate" : "2014-01-29T18:30:22Z",
    "versionInfo" : "2.11.1"
  }, {
    "SPDXID" : "SPDXRef-fromDoap-1",
    "copyrightText" : "NOASSERTION",
    "downloadLocation" : "NOASSERTION",
    "filesAnalyzed" : false,
    "homepage" : "http://commons.apache.org/proper/commons-lang/",
    "licenseConcluded" : "NOASSERTION",
    "licenseDeclared" : "NOASSERTION",
    "name" : "Apache Commons Lang"
  }, {
    "SPDXID" : "SPDXRef-fromDoap-0",
    "downloadLocation" : "https://search.maven.org/remotecontent?filepath=org/apache/jena/apache-jena/3.12.0/apache-jena-3.12.0.tar.gz",
    "externalRefs" : [ {
      "referenceCategory" : "PACKAGE-MANAGER",
      "referenceLocator" : "pkg:maven/org.apache.jena/apache-jena@3.12.0",
      "referenceType" : "purl"
    } ],
    "filesAnalyzed" : false,
    "homepage" : "http://www.openjena.org/",
    "name" : "Jena",
    "versionInfo" : "3.12.0"
  }, {
    "SPDXID" : "SPDXRef-Saxon",
    "checksums" : [ {
      "algorithm" : "SHA1",
      "checksumValue" : "85ed0817af83a24ad8da68c2b5094de69833983c"
    } ],
    "copyrightText" : "Copyright Saxonica Ltd",
    "description" : "The Saxon package is a collection of tools for processing XML documents.",
    "downloadLocation" : "https://sourceforge.net/projects/saxon/files/Saxon-B/8.8.0.7/saxonb8-8-0-7j.zip/download",
    "filesAnalyzed" : false,
    "homepage" : "http://saxon.sourceforge.net/",
    "licenseComments" : "Other versions available for a commercial license",
    "licenseConcluded" : "MPL-1.0",
    "licenseDeclared" : "MPL-1.0",
    "name" : "Saxon",
    "packageFileName" : "saxonB-8.8.zip",
    "versionInfo" : "8.8"
  } ],
  "files" : [ {
    "SPDXID" : "SPDXRef-DoapSource",
    "checksums" : [ {
      "algorithm" : "SHA1",
      "checksumValue" : "2fd4e1c67a2d28fced849ee1bb76e7391b93eb12"
    } ],
    "copyrightText" : "Copyright 2010, 2011 Source Auditor Inc.",
    "fileContributors" : [ "Protecode Inc.", "SPDX Technical Team Members", "Open Logic Inc.", "Source Auditor Inc.", "Black Duck Software In.c" ],
    "fileName" : "./src/org/spdx/parser/DOAPProject.java",
    "fileTypes" : [ "SOURCE" ],
    "licenseConcluded" : "Apache-2.0",
    "licenseInfoInFiles" : [ "Apache-2.0" ]
  }, {
    "SPDXID" : "SPDXRef-CommonsLangSrc",
    "checksums" : [ {
      "algorithm" : "SHA1",
      "checksumValue" : "c2b4e1c67a2d28fced849ee1bb76e7391b93f125"
    } ],
    "comment" : "This file is used by Jena",
    "copyrightText" : "Copyright 2001-2011 The Apache Software Foundation",
    "fileContributors" : [ "Apache Software Foundation" ],
    "fileName" : "./lib-source/commons-lang3-3.1-sources.jar",
    "fileTypes" : [ "ARCHIVE" ],
    "licenseConcluded" : "Apache-2.0",
    "licenseInfoInFiles" : [ "Apache-2.0" ],
    "noticeText" : "Apache Commons Lang\nCopyright 2001-2011 The Apache Software Foundation\n\nThis product includes software developed by\nThe Apache Software Foundation (http://www.apache.org/).\n\nThis product includes software from the Spring Framework,\nunder the Apache License 2.0 (see: StringUtils.containsWhitespace())"
  }, {
    "SPDXID" : "SPDXRef-JenaLib",
    "checksums" : [ {
      "algorithm" : "SHA1",
      "checksumValue" : "3ab4e1c67a2d28fced849ee1bb76e7391b93f125"
    } ],
    "comment" : "This file belongs to Jena",
    "copyrightText" : "(c) Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Hewlett-Packard Development Company, LP",
    "fileContributors" : [ "Apache Software Foundation", "Hewlett Packard Inc." ],
    "fileName" : "./lib-source/jena-2.6.3-sources.jar",
    "fileTypes" : [ "ARCHIVE" ],
    "licenseComments" : "This license is used by Jena",
    "licenseConcluded" : "LicenseRef-1",
    "licenseInfoInFiles" : [ "LicenseRef-1" ]
  }, {
    "SPDXID" : "SPDXRef-Specification",
    "checksums" : [ {
      "algorithm" : "SHA1",
      "checksumValue" : "fff4e1c67a2d28fced849ee1bb76e7391b93f125"
    } ],
    "comment" : "Specification Documentation",
    "fileName" : "./docs/myspec.pdf",
    "fileTypes" : [ "DOCUMENTATION" ]
  }, {
    "SPDXID" : "SPDXRef-File",
    "annotations" : [ {
      "annotationDate" : "2011-01-29T18:30:22Z",
      "annotationType" : "OTHER",
      "annotator" : "Person: File Commenter",
      "comment" : "File level annotation"
    } ],
    "checksums" : [ {
      "algorithm" : "SHA1",
      "checksumValue" : "d6a770ba38583ed4bb4525bd96e50461655d2758"
    }, {
      "algorithm" : "MD5",
      "checksumValue" : "624c1abb3664f4b35547e7c73864ad24"
    } ],
    "comment" : "The concluded license was taken from the package level that the file was included in.\nThis information was found in the COPYING.txt file in the xyz directory.",
    "copyrightText" : "Copyright 2008-2010 John Smith",
    "fileContributors" : [ "The Regents of the University of California", "Modified by Paul Mundt lethal@linux-sh.org", "IBM Corporation" ],
    "fileName" : "./package/foo.c",
    "fileTypes" : [ "SOURCE" ],
    "licenseComments" : "The concluded license was taken from the package level that the file was included in.",
    "licenseConcluded" : "(LGPL-2.0-only OR LicenseRef-2)",
    "licenseInfoInFiles" : [ "GPL-2.0-only", "LicenseRef-2" ],
    "noticeText" : "Copyright (c) 2001 Aaron Lehmann aaroni@vitelus.com\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: \nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE."
  } ],
  "snippets" : [ {
    "SPDXID" : "SPDXRef-Snippet",
    "comment" : "This snippet was identified as significant and highlighted in this Apache-2.0 file, when a commercial scanner identified it as being derived from file foo.c in package xyz which is licensed under GPL-2.0.",
    "copyrightText" : "Copyright 2008-2010 John Smith",
    "licenseComments" : "The concluded license was taken from package xyz, from which the snippet was copied into the current file. The concluded license information was found in the COPYING.txt file in package xyz.",
    "licenseConcluded" : "GPL-2.0-only",
    "licenseInfoInSnippets" : [ "GPL-2.0-only" ],
    "name" : "from linux kernel",
    "ranges" : [ {
      "endPointer" : {
        "offset" : 420,
        "reference" : "SPDXRef-DoapSource"
      },
      "startPointer" : {
        "offset" : 310,
        "reference" : "SPDXRef-DoapSource"
      }
    }, {
      "endPointer" : {
        "lineNumber" : 23,
        "reference" : "SPDXRef-DoapSource"
      },
      "startPointer" : {
        "lineNumber" : 5,
        "reference" : "SPDXRef-DoapSource"
      }
    } ],
    "snippetFromFile" : "SPDXRef-DoapSource"
  } ],
  "relationships" : [ {
    "spdxElementId" : "SPDXRef-DOCUMENT",
    "relationshipType" : "CONTAINS",
    "relatedSpdxElement" : "SPDXRef-Package"
  }, {
    "spdxElementId" : "SPDXRef-DOCUMENT",
    "relationshipType" : "COPY_OF",
    "relatedSpdxElement" : "DocumentRef-spdx-tool-1.2:SPDXRef-ToolsElement"
  }, {
    "spdxElementId" : "SPDXRef-Package",
    "relationshipType" : "DYNAMIC_LINK",
    "relatedSpdxElement" : "SPDXRef-Saxon"
  }, {
    "spdxElementId" : "SPDXRef-CommonsLangSrc",
    "relationshipType" : "GENERATED_FROM",
    "relatedSpdxElement" : "NOASSERTION"
  }, {
    "spdxElementId" : "SPDXRef-JenaLib",
    "relationshipType" : "CONTAINS",
    "relatedSpdxElement" : "SPDXRef-Package"
  }, {
    "spdxElementId" : "SPDXRef-Specification",
    "relationshipType" : "SPECIFICATION_FOR",
    "relatedSpdxElement" : "SPDXRef-fromDoap-0"
  }, {
    "spdxElementId" : "SPDXRef-File",
    "relationshipType" : "GENERATED_FROM",
    "relatedSpdxElement" : "SPDXRef-fromDoap-0"
  } ]
}
tests/data/formats/SPDXJSONExample-v2.2.spdx.json METASEP
{
  "SPDXID" : "SPDXRef-DOCUMENT",
  "spdxVersion" : "SPDX-2.2",
  "creationInfo" : {
    "comment" : "This package has been shipped in source and binary form.\nThe binaries were created with gcc 4.5.1 and expect to link to\ncompatible system run time libraries.",
    "created" : "2010-01-29T18:30:22Z",
    "creators" : [ "Tool: LicenseFind-1.0", "Organization: ExampleCodeInspect ()", "Person: Jane Doe ()" ],
    "licenseListVersion" : "3.9"
  },
  "name" : "SPDX-Tools-v2.0",
  "dataLicense" : "CC0-1.0",
  "comment" : "This document was created using SPDX 2.0 using licenses from the web site.",
  "externalDocumentRefs" : [ {
    "externalDocumentId" : "DocumentRef-spdx-tool-1.2",
    "checksum" : {
      "algorithm" : "SHA1",
      "checksumValue" : "d6a770ba38583ed4bb4525bd96e50461655d2759"
    },
    "spdxDocument" : "http://spdx.org/spdxdocs/spdx-tools-v1.2-3F2504E0-4F89-41D3-9A0C-0305E82C3301"
  } ],
  "hasExtractedLicensingInfos" : [ {
    "licenseId" : "LicenseRef-1",
    "extractedText" : "/*\n * (c) Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Hewlett-Packard Development Company, LP\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n * 3. The name of the author may not be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR\n * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,\n * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\n * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\n * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/"
  }, {
    "licenseId" : "LicenseRef-2",
    "extractedText" : "This package includes the GRDDL parser developed by Hewlett Packard under the following license:\n� Copyright 2007 Hewlett-Packard Development Company, LP\n\nRedistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: \n\nRedistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. \nRedistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. \nThe name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. \nTHIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
  }, {
    "licenseId" : "LicenseRef-4",
    "extractedText" : "/*\n * (c) Copyright 2009 University of Bristol\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n * 3. The name of the author may not be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR\n * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,\n * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\n * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\n * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/"
  }, {
    "licenseId" : "LicenseRef-Beerware-4.2",
    "comment" : "The beerware license has a couple of other standard variants.",
    "extractedText" : "\"THE BEER-WARE LICENSE\" (Revision 42):\nphk@FreeBSD.ORG wrote this file. As long as you retain this notice you\ncan do whatever you want with this stuff. If we meet some day, and you think this stuff is worth it, you can buy me a beer in return Poul-Henning Kamp",
    "name" : "Beer-Ware License (Version 42)",
    "seeAlsos" : [ "http://people.freebsd.org/~phk/" ]
  }, {
    "licenseId" : "LicenseRef-3",
    "comment" : "This is tye CyperNeko License",
    "extractedText" : "The CyberNeko Software License, Version 1.0\n\n \n(C) Copyright 2002-2005, Andy Clark.  All rights reserved.\n \nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions\nare met:\n\n1. Redistributions of source code must retain the above copyright\n   notice, this list of conditions and the following disclaimer. \n\n2. Redistributions in binary form must reproduce the above copyright\n   notice, this list of conditions and the following disclaimer in\n   the documentation and/or other materials provided with the\n   distribution.\n\n3. The end-user documentation included with the redistribution,\n   if any, must include the following acknowledgment:  \n     \"This product includes software developed by Andy Clark.\"\n   Alternately, this acknowledgment may appear in the software itself,\n   if and wherever such third-party acknowledgments normally appear.\n\n4. The names \"CyberNeko\" and \"NekoHTML\" must not be used to endorse\n   or promote products derived from this software without prior \n   written permission. For written permission, please contact \n   andyc@cyberneko.net.\n\n5. Products derived from this software may not be called \"CyberNeko\",\n   nor may \"CyberNeko\" appear in their name, without prior written\n   permission of the author.\n\nTHIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED\nWARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\nOF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS\nBE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, \nOR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT \nOF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR \nBUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, \nWHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE \nOR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, \nEVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.",
    "name" : "CyberNeko License",
    "seeAlsos" : [ "http://people.apache.org/~andyc/neko/LICENSE", "http://justasample.url.com" ]
  } ],
  "annotations" : [ {
    "annotationDate" : "2010-01-29T18:30:22Z",
    "annotationType" : "OTHER",
    "annotator" : "Person: Jane Doe ()",
    "comment" : "Document level annotation"
  }, {
    "annotationDate" : "2010-02-10T00:00:00Z",
    "annotationType" : "REVIEW",
    "annotator" : "Person: Joe Reviewer",
    "comment" : "This is just an example.  Some of the non-standard licenses look like they are actually BSD 3 clause licenses"
  }, {
    "annotationDate" : "2011-03-13T00:00:00Z",
    "annotationType" : "REVIEW",
    "annotator" : "Person: Suzanne Reviewer",
    "comment" : "Another example reviewer."
  } ],
  "documentNamespace" : "http://spdx.org/spdxdocs/spdx-example-444504E0-4F89-41D3-9A0C-0305E82C3301",
  "documentDescribes" : [ "SPDXRef-File", "SPDXRef-Package" ],
  "packages" : [ {
    "SPDXID" : "SPDXRef-Package",
    "annotations" : [ {
      "annotationDate" : "2011-01-29T18:30:22Z",
      "annotationType" : "OTHER",
      "annotator" : "Person: Package Commenter",
      "comment" : "Package level annotation"
    } ],
    "attributionTexts" : [ "The GNU C Library is free software.  See the file COPYING.LIB for copying conditions, and LICENSES for notices about a few contributions that require these additional notices to be distributed.  License copyright years may be listed using range notation, e.g., 1996-2015, indicating that every year in the range, inclusive, is a copyrightable year that would otherwise be listed individually." ],
    "checksums" : [ {
      "algorithm" : "MD5",
      "checksumValue" : "624c1abb3664f4b35547e7c73864ad24"
    }, {
      "algorithm" : "SHA1",
      "checksumValue" : "85ed0817af83a24ad8da68c2b5094de69833983c"
    }, {
      "algorithm" : "SHA256",
      "checksumValue" : "11b6d3ee554eedf79299905a98f9b9a04e498210b59f15094c916c91d150efcd"
    } ],
    "copyrightText" : "Copyright 2008-2010 John Smith",
    "description" : "The GNU C Library defines functions that are specified by the ISO C standard, as well as additional features specific to POSIX and other derivatives of the Unix operating system, and extensions specific to GNU systems.",
    "downloadLocation" : "http://ftp.gnu.org/gnu/glibc/glibc-ports-2.15.tar.gz",
    "externalRefs" : [ {
      "referenceCategory" : "SECURITY",
      "referenceLocator" : "cpe:2.3:a:pivotal_software:spring_framework:4.1.0:*:*:*:*:*:*:*",
      "referenceType" : "cpe23Type"
    }, {
      "comment" : "This is the external ref for Acme",
      "referenceCategory" : "OTHER",
      "referenceLocator" : "acmecorp/acmenator/4.1.3-alpha",
      "referenceType" : "http://spdx.org/spdxdocs/spdx-example-444504E0-4F89-41D3-9A0C-0305E82C3301#LocationRef-acmeforge"
    } ],
    "filesAnalyzed" : true,
    "hasFiles" : [ "SPDXRef-CommonsLangSrc", "SPDXRef-JenaLib", "SPDXRef-DoapSource" ],
    "homepage" : "http://ftp.gnu.org/gnu/glibc",
    "licenseComments" : "The license for this project changed with the release of version x.y.  The version of the project included here post-dates the license change.",
    "licenseConcluded" : "(LGPL-2.0-only OR LicenseRef-3)",
    "licenseDeclared" : "(LGPL-2.0-only AND LicenseRef-3)",
    "licenseInfoFromFiles" : [ "GPL-2.0-only", "LicenseRef-2", "LicenseRef-1" ],
    "name" : "glibc",
    "originator" : "Organization: ExampleCodeInspect (contact@example.com)",
    "packageFileName" : "glibc-2.11.1.tar.gz",
    "packageVerificationCode" : {
      "packageVerificationCodeExcludedFiles" : [ "./package.spdx" ],
      "packageVerificationCodeValue" : "d6a770ba38583ed4bb4525bd96e50461655d2758"
    },
    "sourceInfo" : "uses glibc-2_11-branch from git://sourceware.org/git/glibc.git.",
    "summary" : "GNU C library.",
    "supplier" : "Person: Jane Doe (jane.doe@example.com)",
    "versionInfo" : "2.11.1"
  }, {
    "SPDXID" : "SPDXRef-fromDoap-1",
    "copyrightText" : "NOASSERTION",
    "downloadLocation" : "NOASSERTION",
    "filesAnalyzed" : false,
    "homepage" : "http://commons.apache.org/proper/commons-lang/",
    "licenseConcluded" : "NOASSERTION",
    "licenseDeclared" : "NOASSERTION",
    "name" : "Apache Commons Lang"
  }, {
    "SPDXID" : "SPDXRef-fromDoap-0",
    "copyrightText" : "NOASSERTION",
    "downloadLocation" : "https://search.maven.org/remotecontent?filepath=org/apache/jena/apache-jena/3.12.0/apache-jena-3.12.0.tar.gz",
    "externalRefs" : [ {
      "referenceCategory" : "PACKAGE_MANAGER",
      "referenceLocator" : "pkg:maven/org.apache.jena/apache-jena@3.12.0",
      "referenceType" : "purl"
    } ],
    "filesAnalyzed" : false,
    "homepage" : "http://www.openjena.org/",
    "licenseConcluded" : "NOASSERTION",
    "licenseDeclared" : "NOASSERTION",
    "name" : "Jena",
    "versionInfo" : "3.12.0"
  }, {
    "SPDXID" : "SPDXRef-Saxon",
    "checksums" : [ {
      "algorithm" : "SHA1",
      "checksumValue" : "85ed0817af83a24ad8da68c2b5094de69833983c"
    } ],
    "copyrightText" : "Copyright Saxonica Ltd",
    "description" : "The Saxon package is a collection of tools for processing XML documents.",
    "downloadLocation" : "https://sourceforge.net/projects/saxon/files/Saxon-B/8.8.0.7/saxonb8-8-0-7j.zip/download",
    "filesAnalyzed" : false,
    "homepage" : "http://saxon.sourceforge.net/",
    "licenseComments" : "Other versions available for a commercial license",
    "licenseConcluded" : "MPL-1.0",
    "licenseDeclared" : "MPL-1.0",
    "name" : "Saxon",
    "packageFileName" : "saxonB-8.8.zip",
    "versionInfo" : "8.8"
  } ],
  "files" : [ {
    "SPDXID" : "SPDXRef-DoapSource",
    "checksums" : [ {
      "algorithm" : "SHA1",
      "checksumValue" : "2fd4e1c67a2d28fced849ee1bb76e7391b93eb12"
    } ],
    "copyrightText" : "Copyright 2010, 2011 Source Auditor Inc.",
    "fileContributors" : [ "Protecode Inc.", "SPDX Technical Team Members", "Open Logic Inc.", "Source Auditor Inc.", "Black Duck Software In.c" ],
    "fileName" : "./src/org/spdx/parser/DOAPProject.java",
    "fileTypes" : [ "SOURCE" ],
    "licenseConcluded" : "Apache-2.0",
    "licenseInfoInFiles" : [ "Apache-2.0" ]
  }, {
    "SPDXID" : "SPDXRef-CommonsLangSrc",
    "checksums" : [ {
      "algorithm" : "SHA1",
      "checksumValue" : "c2b4e1c67a2d28fced849ee1bb76e7391b93f125"
    } ],
    "comment" : "This file is used by Jena",
    "copyrightText" : "Copyright 2001-2011 The Apache Software Foundation",
    "fileContributors" : [ "Apache Software Foundation" ],
    "fileName" : "./lib-source/commons-lang3-3.1-sources.jar",
    "fileTypes" : [ "ARCHIVE" ],
    "licenseConcluded" : "Apache-2.0",
    "licenseInfoInFiles" : [ "Apache-2.0" ],
    "noticeText" : "Apache Commons Lang\nCopyright 2001-2011 The Apache Software Foundation\n\nThis product includes software developed by\nThe Apache Software Foundation (http://www.apache.org/).\n\nThis product includes software from the Spring Framework,\nunder the Apache License 2.0 (see: StringUtils.containsWhitespace())"
  }, {
    "SPDXID" : "SPDXRef-JenaLib",
    "checksums" : [ {
      "algorithm" : "SHA1",
      "checksumValue" : "3ab4e1c67a2d28fced849ee1bb76e7391b93f125"
    } ],
    "comment" : "This file belongs to Jena",
    "copyrightText" : "(c) Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Hewlett-Packard Development Company, LP",
    "fileContributors" : [ "Apache Software Foundation", "Hewlett Packard Inc." ],
    "fileName" : "./lib-source/jena-2.6.3-sources.jar",
    "fileTypes" : [ "ARCHIVE" ],
    "licenseComments" : "This license is used by Jena",
    "licenseConcluded" : "LicenseRef-1",
    "licenseInfoInFiles" : [ "LicenseRef-1" ]
  }, {
    "SPDXID" : "SPDXRef-File",
    "annotations" : [ {
      "annotationDate" : "2011-01-29T18:30:22Z",
      "annotationType" : "OTHER",
      "annotator" : "Person: File Commenter",
      "comment" : "File level annotation"
    } ],
    "checksums" : [ {
      "algorithm" : "SHA1",
      "checksumValue" : "d6a770ba38583ed4bb4525bd96e50461655d2758"
    }, {
      "algorithm" : "MD5",
      "checksumValue" : "624c1abb3664f4b35547e7c73864ad24"
    } ],
    "comment" : "The concluded license was taken from the package level that the file was included in.\nThis information was found in the COPYING.txt file in the xyz directory.",
    "copyrightText" : "Copyright 2008-2010 John Smith",
    "fileContributors" : [ "The Regents of the University of California", "Modified by Paul Mundt lethal@linux-sh.org", "IBM Corporation" ],
    "fileName" : "./package/foo.c",
    "fileTypes" : [ "SOURCE" ],
    "licenseComments" : "The concluded license was taken from the package level that the file was included in.",
    "licenseConcluded" : "(LGPL-2.0-only OR LicenseRef-2)",
    "licenseInfoInFiles" : [ "GPL-2.0-only", "LicenseRef-2" ],
    "noticeText" : "Copyright (c) 2001 Aaron Lehmann aaroni@vitelus.com\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the �Software�), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: \nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED �AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE."
  } ],
  "snippets" : [ {
    "SPDXID" : "SPDXRef-Snippet",
    "comment" : "This snippet was identified as significant and highlighted in this Apache-2.0 file, when a commercial scanner identified it as being derived from file foo.c in package xyz which is licensed under GPL-2.0.",
    "copyrightText" : "Copyright 2008-2010 John Smith",
    "licenseComments" : "The concluded license was taken from package xyz, from which the snippet was copied into the current file. The concluded license information was found in the COPYING.txt file in package xyz.",
    "licenseConcluded" : "GPL-2.0-only",
    "licenseInfoInSnippets" : [ "GPL-2.0-only" ],
    "name" : "from linux kernel",
    "ranges" : [ {
      "endPointer" : {
        "offset" : 420,
        "reference" : "SPDXRef-DoapSource"
      },
      "startPointer" : {
        "offset" : 310,
        "reference" : "SPDXRef-DoapSource"
      }
    }, {
      "endPointer" : {
        "lineNumber" : 23,
        "reference" : "SPDXRef-DoapSource"
      },
      "startPointer" : {
        "lineNumber" : 5,
        "reference" : "SPDXRef-DoapSource"
      }
    } ],
    "snippetFromFile" : "SPDXRef-DoapSource"
  } ],
  "relationships" : [ {
    "spdxElementId" : "SPDXRef-DOCUMENT",
    "relatedSpdxElement" : "SPDXRef-Package",
    "relationshipType" : "CONTAINS"
  }, {
    "spdxElementId" : "SPDXRef-DOCUMENT",
    "relatedSpdxElement" : "DocumentRef-spdx-tool-1.2:SPDXRef-ToolsElement",
    "relationshipType" : "COPY_OF"
  }, {
    "spdxElementId" : "SPDXRef-DOCUMENT",
    "relatedSpdxElement" : "SPDXRef-File",
    "relationshipType" : "DESCRIBES"
  }, {
    "spdxElementId" : "SPDXRef-DOCUMENT",
    "relatedSpdxElement" : "SPDXRef-Package",
    "relationshipType" : "DESCRIBES"
  }, {
    "spdxElementId" : "SPDXRef-Package",
    "relatedSpdxElement" : "SPDXRef-JenaLib",
    "relationshipType" : "CONTAINS"
  }, {
    "spdxElementId" : "SPDXRef-Package",
    "relatedSpdxElement" : "SPDXRef-Saxon",
    "relationshipType" : "DYNAMIC_LINK"
  }, {
    "spdxElementId" : "SPDXRef-CommonsLangSrc",
    "relatedSpdxElement" : "NOASSERTION",
    "relationshipType" : "GENERATED_FROM"
  }, {
    "spdxElementId" : "SPDXRef-JenaLib",
    "relatedSpdxElement" : "SPDXRef-Package",
    "relationshipType" : "CONTAINS"
  }, {
    "spdxElementId" : "SPDXRef-File",
    "relatedSpdxElement" : "SPDXRef-fromDoap-0",
    "relationshipType" : "GENERATED_FROM"
  } ]
}

tests/data/doc_write/yaml-simple.yaml METASEP
SPDXID: SPDXRef-DOCUMENT
creationInfo:
  created: '2021-11-15T00:00:00Z'
  creators:
  - 'Organization: SPDX'
  licenseListVersion: '3.6'
dataLicense: CC0-1.0
documentDescribes:
- SPDXRef-Package
documentNamespace: https://spdx.org/spdxdocs/spdx-example-444504E0-4F89-41D3-9A0C-0305E82C3301
files:
- SPDXID: SPDXRef-File
  checksums:
  - algorithm: SHA1
    checksumValue: SOME-SHA1
  - algorithm: SHA256
    checksumValue: SOME-SHA256
  copyrightText: NOASSERTION
  fileName: ./some/path/tofile
  licenseConcluded: NOASSERTION
  licenseInfoInFiles:
  - LGPL-2.1-only
  fileTypes:
  - SOURCE
  - OTHER

name: Sample_Document-V2.1
packages:
- SPDXID: SPDXRef-Package
  checksums:
  - algorithm: SHA1
    checksumValue: SOME-SHA1
  - algorithm: SHA256
    checksumValue: SOME-SHA256
  copyrightText: Some copyright
  downloadLocation: NOASSERTION
  hasFiles:
  - SPDXRef-File
  licenseConcluded: NOASSERTION
  licenseDeclared: NOASSERTION
  licenseInfoFromFiles:
  - LGPL-2.1-only
  name: some/path
  packageVerificationCode:
    packageVerificationCodeValue: SOME code
  primaryPackagePurpose: FILE
  releaseDate: '2021-01-01T12:00:00Z'
  builtDate: '2021-01-01T12:00:00Z'
  validUntilDate: '2022-01-01T12:00:00Z'
spdxVersion: SPDX-2.1

tests/data/doc_write/yaml-simple-plus.yaml METASEP
SPDXID: SPDXRef-DOCUMENT
creationInfo:
  created: '2021-11-15T00:00:00Z'
  creators:
  - 'Organization: SPDX'
  licenseListVersion: '3.6'
dataLicense: CC0-1.0
documentDescribes:
- SPDXRef-Package
documentNamespace: https://spdx.org/spdxdocs/spdx-example-444504E0-4F89-41D3-9A0C-0305E82C3301
files:
- SPDXID: SPDXRef-File
  checksums:
  - algorithm: SHA1
    checksumValue: SOME-SHA1
  - algorithm: SHA256
    checksumValue: SOME-SHA256
  copyrightText: NOASSERTION
  fileName: ./some/path/tofile
  licenseConcluded: NOASSERTION
  licenseInfoInFiles:
  - LGPL-2.1-or-later
  fileTypes:
  - SOURCE
  - OTHER
name: Sample_Document-V2.1
packages:
- SPDXID: SPDXRef-Package
  checksums:
  - algorithm: SHA1
    checksumValue: SOME-SHA1
  - algorithm: SHA256
    checksumValue: SOME-SHA256
  copyrightText: Some copyright
  downloadLocation: NOASSERTION
  hasFiles:
  - SPDXRef-File
  licenseConcluded: NOASSERTION
  licenseDeclared: NOASSERTION
  licenseInfoFromFiles:
  - LGPL-2.1-or-later
  name: some/path
  packageVerificationCode:
    packageVerificationCodeValue: SOME code
  primaryPackagePurpose: FILE
  releaseDate: '2021-01-01T12:00:00Z'
  builtDate: '2021-01-01T12:00:00Z'
  validUntilDate: '2022-01-01T12:00:00Z'
spdxVersion: SPDX-2.1

tests/data/doc_write/yaml-simple-multi-package.yaml METASEP
SPDXID: SPDXRef-DOCUMENT
creationInfo:
  created: '2021-10-21T16:46:56Z'
  creators:
    - 'Tool: ScanCode'
  licenseListVersion: '3.6'
dataLicense: CC0-1.0
documentDescribes:
  - SPDXRef-Package1
  - SPDXRef-Package2
  - SPDXRef-Package3
packages:
  - SPDXID: SPDXRef-Package1
    copyrightText: Some copyright
    downloadLocation: NOASSERTION
    filesAnalyzed: false
    licenseConcluded: NOASSERTION
    licenseDeclared: NOASSERTION
    name: some/path1
  - SPDXID: SPDXRef-Package2
    copyrightText: Some copyright
    downloadLocation: NOASSERTION
    hasFiles:
      - SPDXRef-File
    licenseConcluded: NOASSERTION
    licenseDeclared: NOASSERTION
    licenseInfoFromFiles:
      - LGPL-2.1-or-later
    name: some/path2
    packageVerificationCode:
      packageVerificationCodeValue: SOME code
  - SPDXID: SPDXRef-Package3
    copyrightText: Some copyright
    downloadLocation: NOASSERTION
    hasFiles:
      - SPDXRef-File
    licenseConcluded: NOASSERTION
    licenseDeclared: NOASSERTION
    licenseInfoFromFiles:
      - LGPL-2.1-or-later
    name: some/path3
documentNamespace: https://spdx.org/spdxdocs/spdx-example-444504E0-4F89-41D3-9A0C-0305E82C3301
name: Sample_Document-V2.1
spdxVersion: SPDX-2.1
files:
  - SPDXID: SPDXRef-File
    checksums:
      - algorithm: SHA1
        checksumValue: SOME-SHA1
    copyrightText: NOASSERTION
    licenseConcluded: NOASSERTION
    licenseInfoInFiles:
      - LGPL-2.1-or-later
    fileName: ./some/path/tofile
tests/data/doc_write/xml-simple.xml METASEP
<?xml version="1.0" encoding="utf-8"?>
<Document>
    <spdxVersion>SPDX-2.1</spdxVersion>
    <dataLicense>CC0-1.0</dataLicense>
    <name>Sample_Document-V2.1</name>
    <SPDXID>SPDXRef-DOCUMENT</SPDXID>
    <documentNamespace>https://spdx.org/spdxdocs/spdx-example-444504E0-4F89-41D3-9A0C-0305E82C3301</documentNamespace>
    <documentDescribes>SPDXRef-Package</documentDescribes>
    <packages>
        <SPDXID>SPDXRef-Package</SPDXID>
        <name>some/path</name>
        <downloadLocation>NOASSERTION</downloadLocation>
        <copyrightText>Some copyright</copyrightText>
        <packageVerificationCode>
            <packageVerificationCodeValue>SOME code</packageVerificationCodeValue>
        </packageVerificationCode>
        <checksums>
            <checksumValue>SOME-SHA1</checksumValue>
            <algorithm>SHA1</algorithm>
        </checksums>
        <checksums>
            <checksumValue>SOME-SHA256</checksumValue>
            <algorithm>SHA256</algorithm>
        </checksums>
        <licenseDeclared>NOASSERTION</licenseDeclared>
        <licenseConcluded>NOASSERTION</licenseConcluded>
        <licenseInfoFromFiles>LGPL-2.1-only</licenseInfoFromFiles>
        <hasFiles>SPDXRef-File</hasFiles>
        <primaryPackagePurpose>FILE</primaryPackagePurpose>
        <releaseDate>2021-01-01T12:00:00Z</releaseDate>
        <builtDate>2021-01-01T12:00:00Z</builtDate>
        <validUntilDate>2022-01-01T12:00:00Z</validUntilDate>
    </packages>
    <files>
        <fileName>./some/path/tofile</fileName>
        <SPDXID>SPDXRef-File</SPDXID>
        <checksums>
            <checksumValue>SOME-SHA1</checksumValue>
            <algorithm>SHA1</algorithm>
        </checksums>
        <checksums>
            <checksumValue>SOME-SHA256</checksumValue>
            <algorithm>SHA256</algorithm>
        </checksums>
        <licenseConcluded>NOASSERTION</licenseConcluded>
        <copyrightText>NOASSERTION</copyrightText>
        <licenseInfoInFiles>LGPL-2.1-only</licenseInfoInFiles>
        <fileTypes>SOURCE</fileTypes>
        <fileTypes>OTHER</fileTypes>
    </files>
</Document>

tests/data/doc_write/xml-simple-plus.xml METASEP
<?xml version="1.0" encoding="utf-8"?>
<Document>
    <spdxVersion>SPDX-2.1</spdxVersion>
    <dataLicense>CC0-1.0</dataLicense>
    <name>Sample_Document-V2.1</name>
    <SPDXID>SPDXRef-DOCUMENT</SPDXID>
    <documentNamespace>https://spdx.org/spdxdocs/spdx-example-444504E0-4F89-41D3-9A0C-0305E82C3301</documentNamespace>
    <documentDescribes>SPDXRef-Package</documentDescribes>
    <packages>
        <SPDXID>SPDXRef-Package</SPDXID>
        <name>some/path</name>
        <downloadLocation>NOASSERTION</downloadLocation>
        <copyrightText>Some copyright</copyrightText>
        <packageVerificationCode>
            <packageVerificationCodeValue>SOME code</packageVerificationCodeValue>
        </packageVerificationCode>
        <checksums>
            <checksumValue>SOME-SHA1</checksumValue>
            <algorithm>SHA1</algorithm>
        </checksums>
        <checksums>
            <checksumValue>SOME-SHA256</checksumValue>
            <algorithm>SHA256</algorithm>
        </checksums>
        <licenseDeclared>NOASSERTION</licenseDeclared>
        <licenseConcluded>NOASSERTION</licenseConcluded>
        <licenseInfoFromFiles>LGPL-2.1-or-later</licenseInfoFromFiles>
        <hasFiles>SPDXRef-File</hasFiles>
        <primaryPackagePurpose>FILE</primaryPackagePurpose>
        <releaseDate>2021-01-01T12:00:00Z</releaseDate>
        <builtDate>2021-01-01T12:00:00Z</builtDate>
        <validUntilDate>2022-01-01T12:00:00Z</validUntilDate>
    </packages>
    <files>
        <fileName>./some/path/tofile</fileName>
        <SPDXID>SPDXRef-File</SPDXID>
        <checksums>
            <checksumValue>SOME-SHA1</checksumValue>
            <algorithm>SHA1</algorithm>
        </checksums>
        <checksums>
            <checksumValue>SOME-SHA256</checksumValue>
            <algorithm>SHA256</algorithm>
        </checksums>
        <licenseConcluded>NOASSERTION</licenseConcluded>
        <copyrightText>NOASSERTION</copyrightText>
        <licenseInfoInFiles>LGPL-2.1-or-later</licenseInfoInFiles>
        <fileTypes>SOURCE</fileTypes>
        <fileTypes>OTHER</fileTypes>
    </files>
</Document>

tests/data/doc_write/xml-simple-multi-package.xml METASEP
<?xml version="1.0" encoding="utf-8"?>
<Document>
    <spdxVersion>SPDX-2.1</spdxVersion>
    <documentNamespace>https://spdx.org/spdxdocs/spdx-example-444504E0-4F89-41D3-9A0C-0305E82C3301</documentNamespace>
    <creationInfo>
        <creators>Tool: ScanCode</creators>
        <created>2021-10-21T17:02:23Z</created>
        <licenseListVersion>3.6</licenseListVersion>
    </creationInfo>
    <dataLicense>CC0-1.0</dataLicense>
    <SPDXID>SPDXRef-DOCUMENT</SPDXID>
    <name>Sample_Document-V2.1</name>
    <documentDescribes>SPDXRef-Package1</documentDescribes>
    <documentDescribes>SPDXRef-Package2</documentDescribes>
    <documentDescribes>SPDXRef-Package3</documentDescribes>
    <packages>
        <SPDXID>SPDXRef-Package1</SPDXID>
        <name>some/path1</name>
        <downloadLocation>NOASSERTION</downloadLocation>
        <filesAnalyzed>false</filesAnalyzed>
        <licenseConcluded>NOASSERTION</licenseConcluded>
        <licenseDeclared>NOASSERTION</licenseDeclared>
        <copyrightText>Some copyright</copyrightText>
    </packages>
    <packages>
        <SPDXID>SPDXRef-Package2</SPDXID>
        <name>some/path2</name>
        <downloadLocation>NOASSERTION</downloadLocation>
        <packageVerificationCode>
            <packageVerificationCodeValue>SOME code</packageVerificationCodeValue>
        </packageVerificationCode>
        <licenseInfoFromFiles>LGPL-2.1-or-later</licenseInfoFromFiles>
        <licenseConcluded>NOASSERTION</licenseConcluded>
        <licenseDeclared>NOASSERTION</licenseDeclared>
        <copyrightText>Some copyright</copyrightText>
        <hasFiles>SPDXRef-File</hasFiles>
    </packages>
    <packages>
        <SPDXID>SPDXRef-Package3</SPDXID>
        <name>some/path3</name>
        <downloadLocation>NOASSERTION</downloadLocation>
        <licenseInfoFromFiles>LGPL-2.1-or-later</licenseInfoFromFiles>
        <licenseConcluded>NOASSERTION</licenseConcluded>
        <licenseDeclared>NOASSERTION</licenseDeclared>
        <copyrightText>Some copyright</copyrightText>
        <hasFiles>SPDXRef-File</hasFiles>
    </packages>
    <files>
        <fileName>./some/path/tofile</fileName>
        <SPDXID>SPDXRef-File</SPDXID>
        <checksums>
            <algorithm>SHA1</algorithm>
            <checksumValue>SOME-SHA1</checksumValue>
        </checksums>
        <licenseConcluded>NOASSERTION</licenseConcluded>
        <licenseInfoInFiles>LGPL-2.1-or-later</licenseInfoInFiles>
        <copyrightText>NOASSERTION</copyrightText>
    </files>
</Document>

tests/data/doc_write/tv-simple.tv METASEP
# Document Information
SPDXVersion: SPDX-2.1
DataLicense: CC0-1.0
DocumentNamespace: https://spdx.org/spdxdocs/spdx-example-444504E0-4F89-41D3-9A0C-0305E82C3301
DocumentName: Sample_Document-V2.1
LicenseListVersion: 3.6
SPDXID: SPDXRef-DOCUMENT
# Creation Info
# Relationships
Relationship: SPDXRef-DOCUMENT DESCRIBES SPDXRef-Package
# Package
PackageName: some/path
SPDXID: SPDXRef-Package
PackageDownloadLocation: NOASSERTION
PackageChecksum: SHA1: SOME-SHA1
PackageChecksum: SHA256: SOME-SHA256
PackageVerificationCode: SOME code
PackageLicenseDeclared: NOASSERTION
PackageLicenseConcluded: NOASSERTION
PackageLicenseInfoFromFiles: LGPL-2.1-only
PackageCopyrightText: Some copyright
PrimaryPackagePurpose: FILE
BuiltDate: 2021-01-01T12:00:00Z
ReleaseDate: 2021-01-01T12:00:00Z
ValidUntilDate: 2022-01-01T12:00:00Z
# File
FileName: ./some/path/tofile
SPDXID: SPDXRef-File
FileType: OTHER
FileType: SOURCE
FileChecksum: SHA1: SOME-SHA1
FileChecksum: SHA256: SOME-SHA256
LicenseConcluded: NOASSERTION
LicenseInfoInFile: LGPL-2.1-only
FileCopyrightText: NOASSERTION

tests/data/doc_write/tv-simple-plus.tv METASEP
# Document Information
SPDXVersion: SPDX-2.1
DataLicense: CC0-1.0
DocumentNamespace: https://spdx.org/spdxdocs/spdx-example-444504E0-4F89-41D3-9A0C-0305E82C3301
DocumentName: Sample_Document-V2.1
LicenseListVersion: 3.6
SPDXID: SPDXRef-DOCUMENT
# Creation Info
# Relationships
Relationship: SPDXRef-DOCUMENT DESCRIBES SPDXRef-Package
# Package
PackageName: some/path
SPDXID: SPDXRef-Package
PackageDownloadLocation: NOASSERTION
PackageChecksum: SHA1: SOME-SHA1
PackageChecksum: SHA256: SOME-SHA256
PackageVerificationCode: SOME code
PackageLicenseDeclared: NOASSERTION
PackageLicenseConcluded: NOASSERTION
PackageLicenseInfoFromFiles: LGPL-2.1-or-later
PackageCopyrightText: Some copyright
PrimaryPackagePurpose: FILE
BuiltDate: 2021-01-01T12:00:00Z
ReleaseDate: 2021-01-01T12:00:00Z
ValidUntilDate: 2022-01-01T12:00:00Z
# File
FileName: ./some/path/tofile
SPDXID: SPDXRef-File
FileType: OTHER
FileType: SOURCE
FileChecksum: SHA1: SOME-SHA1
FileChecksum: SHA256: SOME-SHA256
LicenseConcluded: NOASSERTION
LicenseInfoInFile: LGPL-2.1-or-later
FileCopyrightText: NOASSERTION

tests/data/doc_write/tv-mini.tv METASEP
# Document Information
SPDXVersion: SPDX-2.1
DataLicense: CC0-1.0
LicenseListVersion: 3.6
SPDXID: SPDXRef-DOCUMENT
# Creation Info


tests/data/doc_write/rdf-simple.json METASEP
{
  "rdf:RDF": {
    "@xmlns:ns1": "http://spdx.org/rdf/terms#", 
    "@xmlns:rdf": "http://www.w3.org/1999/02/22-rdf-syntax-ns#", 
    "ns1:SpdxDocument": {
      "ns1:describesPackage": {
        "ns1:Package": {
          "@rdf:about": "http://www.spdx.org/tools#SPDXRef-Package",
          "ns1:Package": {
            "@rdf:resource": "SPDXRef-Package"
          },
          "ns1:hasFile": {
            "@rdf:resource": "http://www.spdx.org/files#SPDXRef-File"
          },
          "ns1:downloadLocation": {
            "@rdf:resource": "http://spdx.org/rdf/terms#noassertion"
          }, 
          "ns1:licenseDeclared": {
            "@rdf:resource": "http://spdx.org/rdf/terms#noassertion"
          }, 
          "ns1:name": "some/path",
          "ns1:licenseInfoFromFiles": {
            "@rdf:resource": "http://spdx.org/licenses/LGPL-2.1-only"
          }, 
          "ns1:licenseConcluded": {
            "@rdf:resource": "http://spdx.org/rdf/terms#noassertion"
          }, 
          "ns1:copyrightText": "Some copyright",
            "ns1:checksum": [
                {
                    "ns1:Checksum": {
                        "ns1:algorithm": "http://spdx.org/rdf/terms#checksumAlgorithm_sha1",
                        "ns1:checksumValue": "SOME-SHA1"
                    }
                },
                {
                    "ns1:Checksum": {
                        "ns1:algorithm": "http://spdx.org/rdf/terms#checksumAlgorithm_sha256",
                        "ns1:checksumValue": "SOME-SHA256"
                    }
                }
            ]
        }
      }, 
      "ns1:specVersion": "SPDX-2.1", 
      "ns1:dataLicense": {
        "@rdf:resource": "http://spdx.org/licenses/CC0-1.0"
      },
      "ns1:name": {
        "@rdf:resource": "Sample_Document-V2.1"
      },
      "ns1:referencesFile": {
        "ns1:File": {
          "@rdf:about": "http://www.spdx.org/files#SPDXRef-File",
          "ns1:licenseInfoInFile": {
            "@rdf:resource": "http://spdx.org/licenses/LGPL-2.1-only"
          },
          "ns1:checksum": [
            {
              "ns1:Checksum": {
                "ns1:checksumValue": "SOME-SHA1",
                "ns1:algorithm": "http://spdx.org/rdf/terms#checksumAlgorithm_sha1"
              }
            }, {
          "ns1:Checksum": {
              "ns1:checksumValue": "SOME-SHA256",
              "ns1:algorithm": "http://spdx.org/rdf/terms#checksumAlgorithm_sha256"
            }
            }
          ],
          "ns1:licenseConcluded": {
            "@rdf:resource": "http://spdx.org/rdf/terms#noassertion"
          }, 
          "ns1:copyrightText": {
            "@rdf:resource": "http://spdx.org/rdf/terms#noassertion"
          }, 
          "ns1:fileName": "./some/path/tofile",
          "ns1:fileType": [{"@rdf:resource": "http://spdx.org/rdf/terms#fileType_other"},
                           {"@rdf:resource": "http://spdx.org/rdf/terms#fileType_source"}]
        }
      },
        "ns1:relationship": [
                {
                    "ns1:Relationship": {
                        "ns1:spdxElementId": "SPDXRef-DOCUMENT",
                        "ns1:relatedSpdxElement": "SPDXRef-Package",
                        "ns1:relationshipType": {
                            "@rdf:resource": "http://spdx.org/rdf/terms#relationshipType_describes"
                        }
                    }
                },
                {
                    "ns1:Relationship": {
                        "ns1:spdxElementId": "SPDXRef-Package",
                        "ns1:relatedSpdxElement": "SPDXRef-File",
                        "ns1:relationshipType": {
                            "@rdf:resource": "http://spdx.org/rdf/terms#relationshipType_contains"
                        }
                    }
                }
            ],
      "@rdf:about": "http://www.spdx.org/tools#SPDXRef-DOCUMENT"
    }
  }
}

tests/data/doc_write/rdf-simple-plus.json METASEP
{
  "rdf:RDF": {
    "@xmlns:ns1": "http://spdx.org/rdf/terms#", 
    "@xmlns:rdf": "http://www.w3.org/1999/02/22-rdf-syntax-ns#", 
    "ns1:SpdxDocument": {
      "ns1:describesPackage": {
        "ns1:Package": {
          "@rdf:about": "http://www.spdx.org/tools#SPDXRef-Package",
          "ns1:Package": {
            "@rdf:resource": "SPDXRef-Package"
          },
          "ns1:hasFile": {
            "@rdf:resource": "http://www.spdx.org/files#SPDXRef-File"
          },
          "ns1:name": "some/path",
          "ns1:licenseDeclared": {
            "@rdf:resource": "http://spdx.org/rdf/terms#noassertion"
          }, 
          "ns1:downloadLocation": {
            "@rdf:resource": "http://spdx.org/rdf/terms#noassertion"
          }, 
          "ns1:licenseInfoFromFiles": {
            "@rdf:resource": "http://spdx.org/licenses/LGPL-2.1-or-later"
          }, 
          "ns1:licenseConcluded": {
            "@rdf:resource": "http://spdx.org/rdf/terms#noassertion"
          }, 
          "ns1:copyrightText": "Some copyright",
            "ns1:checksum": [
                {
                    "ns1:Checksum": {
                        "ns1:algorithm": "http://spdx.org/rdf/terms#checksumAlgorithm_sha1",
                        "ns1:checksumValue": "SOME-SHA1"
                    }
                },
                {
                    "ns1:Checksum": {
                        "ns1:algorithm": "http://spdx.org/rdf/terms#checksumAlgorithm_sha256",
                        "ns1:checksumValue": "SOME-SHA256"
                    }
                }
            ]
        }
      }, 
      "ns1:specVersion": "SPDX-2.1", 
      "ns1:dataLicense": {
        "@rdf:resource": "http://spdx.org/licenses/CC0-1.0"
      },
      "ns1:name": {
        "@rdf:resource": "Sample_Document-V2.1"
      },
      "ns1:referencesFile": {
        "ns1:File": {
          "@rdf:about": "http://www.spdx.org/files#SPDXRef-File",
          "ns1:fileName": "./some/path/tofile", 
          "ns1:checksum": [
            {
              "ns1:Checksum": {
                "ns1:checksumValue": "SOME-SHA1",
                "ns1:algorithm": "http://spdx.org/rdf/terms#checksumAlgorithm_sha1"
              }
            }, {
              "ns1:Checksum": {
                "ns1:checksumValue": "SOME-SHA256",
                "ns1:algorithm": "http://spdx.org/rdf/terms#checksumAlgorithm_sha256"
              }
            }
          ],
          "ns1:licenseConcluded": {
            "@rdf:resource": "http://spdx.org/rdf/terms#noassertion"
          }, 
          "ns1:copyrightText": {
            "@rdf:resource": "http://spdx.org/rdf/terms#noassertion"
          }, 
          "ns1:licenseInfoInFile": {
            "@rdf:resource": "http://spdx.org/licenses/LGPL-2.1-or-later"
          },
          "ns1:fileType": [{"@rdf:resource": "http://spdx.org/rdf/terms#fileType_other"},
                           {"@rdf:resource": "http://spdx.org/rdf/terms#fileType_source"}]
        }
      },
        "ns1:relationship": [
                {
                    "ns1:Relationship": {
                        "ns1:spdxElementId": "SPDXRef-DOCUMENT",
                        "ns1:relatedSpdxElement": "SPDXRef-Package",
                        "ns1:relationshipType": {
                            "@rdf:resource": "http://spdx.org/rdf/terms#relationshipType_describes"
                        }
                    }
                },
                {
                    "ns1:Relationship": {
                        "ns1:spdxElementId": "SPDXRef-Package",
                        "ns1:relatedSpdxElement": "SPDXRef-File",
                        "ns1:relationshipType": {
                            "@rdf:resource": "http://spdx.org/rdf/terms#relationshipType_contains"
                        }
                    }
                }
            ],
            "@rdf:about": "http://www.spdx.org/tools#SPDXRef-DOCUMENT"
        }
    }
}

tests/data/doc_write/rdf-mini.json METASEP
{
  "rdf:RDF": {
    "@xmlns:ns1": "http://spdx.org/rdf/terms#",
    "@xmlns:rdf": "http://www.w3.org/1999/02/22-rdf-syntax-ns#",
    "ns1:SpdxDocument": {
      "@rdf:about": "http://www.spdx.org/tools#SPDXRef-DOCUMENT",
      "ns1:specVersion": "SPDX-2.1",
      "ns1:dataLicense": {
        "@rdf:resource": "http://spdx.org/licenses/CC0-1.0"
      }
    }
  }
}

tests/data/doc_write/json-simple.json METASEP
{
    "spdxVersion": "SPDX-2.1",
    "dataLicense": "CC0-1.0",
    "name": "Sample_Document-V2.1",
    "SPDXID": "SPDXRef-DOCUMENT",
    "documentNamespace": "https://spdx.org/spdxdocs/spdx-example-444504E0-4F89-41D3-9A0C-0305E82C3301",
    "creationInfo": {
        "creators": [
            "Organization: SPDX"
        ],
        "created": "2021-11-15T00:00:00Z",
        "licenseListVersion": "3.6"
    },
    "documentDescribes": [
        "SPDXRef-Package"
    ],
    "packages": [
        {
            "SPDXID": "SPDXRef-Package",
            "name": "some/path",
            "downloadLocation": "NOASSERTION",
            "copyrightText": "Some copyright",
            "packageVerificationCode": {
                "packageVerificationCodeValue": "SOME code"
            },
            "checksums": [
                {
                    "algorithm": "SHA1",
                    "checksumValue": "SOME-SHA1"
                },
                {
                    "algorithm": "SHA256",
                    "checksumValue": "SOME-SHA256"
                }
            ],
            "licenseDeclared": "NOASSERTION",
            "licenseConcluded": "NOASSERTION",
            "licenseInfoFromFiles": [
                "LGPL-2.1-only"
            ],
            "hasFiles": [
                "SPDXRef-File"
            ],
            "primaryPackagePurpose": "FILE",
            "releaseDate": "2021-01-01T12:00:00Z",
            "builtDate": "2021-01-01T12:00:00Z",
            "validUntilDate": "2022-01-01T12:00:00Z"
        }
    ],
    "files": [
        {
            "SPDXID": "SPDXRef-File",
            "checksums": [
                {
                    "algorithm": "SHA1",
                    "checksumValue": "SOME-SHA1"
                },
                {
                    "algorithm": "SHA256",
                    "checksumValue": "SOME-SHA256"
                }
            ],
            "licenseConcluded": "NOASSERTION",
            "copyrightText": "NOASSERTION",
            "fileName": "./some/path/tofile",
            "licenseInfoInFiles": [
                "LGPL-2.1-only"
            ],
            "fileTypes": ["OTHER", "SOURCE"]
        }
    ]
}

tests/data/doc_write/json-simple-plus.json METASEP
{
    "spdxVersion": "SPDX-2.1",
    "dataLicense": "CC0-1.0",
    "name": "Sample_Document-V2.1",
    "SPDXID": "SPDXRef-DOCUMENT",
    "documentNamespace": "https://spdx.org/spdxdocs/spdx-example-444504E0-4F89-41D3-9A0C-0305E82C3301",
    "creationInfo": {
        "creators": [
            "Organization: SPDX"
        ],
        "created": "2021-11-15T00:00:00Z",
        "licenseListVersion": "3.6"
    },
    "documentDescribes": [
        "SPDXRef-Package"
    ],
    "packages": [
        {
            "SPDXID": "SPDXRef-Package",
            "name": "some/path",
            "downloadLocation": "NOASSERTION",
            "copyrightText": "Some copyright",
            "packageVerificationCode": {
                "packageVerificationCodeValue": "SOME code"
            },
            "checksums": [
                {
                    "algorithm": "SHA1",
                    "checksumValue": "SOME-SHA1"
                },
                {
                    "algorithm": "SHA256",
                    "checksumValue": "SOME-SHA256"
                }
            ],
            "licenseDeclared": "NOASSERTION",
            "licenseConcluded": "NOASSERTION",
            "licenseInfoFromFiles": [
                "LGPL-2.1-or-later"
            ],
            "hasFiles": [
                "SPDXRef-File"
            ],
            "primaryPackagePurpose": "FILE",
            "releaseDate": "2021-01-01T12:00:00Z",
            "builtDate": "2021-01-01T12:00:00Z",
            "validUntilDate": "2022-01-01T12:00:00Z"
        }
    ],
    "files": [
        {
            "SPDXID": "SPDXRef-File",
            "checksums": [
                {
                    "algorithm": "SHA1",
                    "checksumValue": "SOME-SHA1"
                },
                {
                    "algorithm": "SHA256",
                    "checksumValue": "SOME-SHA256"
                }
            ],
            "licenseConcluded": "NOASSERTION",
            "copyrightText": "NOASSERTION",
            "fileName": "./some/path/tofile",
            "licenseInfoInFiles": [
                "LGPL-2.1-or-later"
            ],
            "fileTypes": ["OTHER", "SOURCE"]
        }
    ]
}

tests/data/doc_write/json-simple-multi-package.json METASEP
{
  "spdxVersion": "SPDX-2.1",
  "documentNamespace": "https://spdx.org/spdxdocs/spdx-example-444504E0-4F89-41D3-9A0C-0305E82C3301",
  "creationInfo": {
    "creators": [
      "Tool: ScanCode"
    ],
    "created": "2021-10-21T17:09:37Z",
    "licenseListVersion": "3.6"
  },
  "dataLicense": "CC0-1.0",
  "SPDXID": "SPDXRef-DOCUMENT",
  "name": "Sample_Document-V2.1",
  "documentDescribes": [
    "SPDXRef-Package1",
    "SPDXRef-Package2",
    "SPDXRef-Package3"
  ],
  "packages": [
    {
      "SPDXID": "SPDXRef-Package1",
      "name": "some/path1",
      "downloadLocation": "NOASSERTION",
      "filesAnalyzed": false,
      "licenseConcluded": "NOASSERTION",
      "licenseDeclared": "NOASSERTION",
      "copyrightText": "Some copyright"
    },
    {
      "SPDXID": "SPDXRef-Package2",
      "name": "some/path2",
      "downloadLocation": "NOASSERTION",
      "packageVerificationCode": {
        "packageVerificationCodeValue": "SOME code"
      },
      "licenseInfoFromFiles": [
        "LGPL-2.1-or-later"
      ],
      "licenseConcluded": "NOASSERTION",
      "licenseDeclared": "NOASSERTION",
      "copyrightText": "Some copyright",
      "hasFiles": [
        "SPDXRef-File"
      ]
    },
    {
      "SPDXID": "SPDXRef-Package3",
      "name": "some/path3",
      "downloadLocation": "NOASSERTION",
      "licenseInfoFromFiles": [
        "LGPL-2.1-or-later"
      ],
      "licenseConcluded": "NOASSERTION",
      "licenseDeclared": "NOASSERTION",
      "copyrightText": "Some copyright",
      "hasFiles": [
        "SPDXRef-File"
      ]
    }
  ],
  "files": [
    {
      "fileName": "./some/path/tofile",
      "SPDXID": "SPDXRef-File",
      "checksums": [
        {
          "algorithm": "SHA1",
          "checksumValue": "SOME-SHA1"
        }
      ],
      "licenseConcluded": "NOASSERTION",
      "licenseInfoInFiles": [
        "LGPL-2.1-or-later"
      ],
      "copyrightText": "NOASSERTION"
    }
  ]
}

tests/data/doc_parse/spdx-expected.json METASEP
{
    "id": "https://spdx.org/spdxdocs/spdx-example-444504E0-4F89-41D3-9A0C-0305E82C3301#SPDXRef-DOCUMENT",
    "specVersion": {
        "major": 2,
        "minor": 1
    },
    "documentNamespace": "https://spdx.org/spdxdocs/spdx-example-444504E0-4F89-41D3-9A0C-0305E82C3301",
    "name": "Sample_Document-V2.1",
    "comment": "This is a sample spreadsheet",
    "dataLicense": {
        "type": "Single",
        "identifier": "CC0-1.0",
        "name": "Creative Commons Zero v1.0 Universal"
    },
    "licenseListVersion": {
        "major": 3,
        "minor": 6
    },
    "creators": [
        {
            "name": "Gary O'Neall",
            "email": null,
            "type": "Person"
        },
        {
            "name": "Source Auditor Inc.",
            "email": null,
            "type": "Organization"
        },
        {
            "name": "SourceAuditor-V1.2",
            "type": "Tool"
        }
    ],
    "created": "2010-02-03T00:00:00Z",
    "creatorComment": "This is an example of an SPDX spreadsheet format",
    "files": [
        {
            "id": "https://spdx.org/spdxdocs/spdx-example-444504E0-4F89-41D3-9A0C-0305E82C3301#SPDXRef-File1",
            "fileName": "Jenna-2.6.3/jena-2.6.3-sources.jar",
            "fileTypes": ["ARCHIVE", "OTHER"],
            "comment": "This file belongs to Jena",
            "licenseConcluded": {
                "type": "Single",
                "identifier": "LicenseRef-1",
                "name": "LicenseRef-1"
            },
            "copyrightText": "(c) Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Hewlett-Packard Development Company, LP",
            "licenseComment": "This license is used by Jena",
            "notice": null,
            "checksums": [
                {
                    "identifier": "SHA1",
                    "value": "3ab4e1c67a2d28fced849ee1bb76e7391b93f125"
                },
                {
                    "identifier": "SHA256",
                    "value": "3ab4e1c67a2d28fced849ee1bb76e7391b93f1250000000000000000"
                }
            ],
            "licenseInfoInFiles": [
                {
                    "type": "Single",
                    "identifier": "LicenseRef-1",
                    "name": "LicenseRef-1"
                }
            ],
            "contributors": [],
            "dependencies": [],
            "artifactOfProjectName": [
                "Jena"
            ],
            "artifactOfProjectHome": [
                "http://www.openjena.org/"
            ],
            "artifactOfProjectURI": []
        },
        {
            "id": "https://spdx.org/spdxdocs/spdx-example-444504E0-4F89-41D3-9A0C-0305E82C3301#SPDXRef-File2",
            "fileName": "src/org/spdx/parser/DOAPProject.java",
            "fileTypes": ["SOURCE", "TEXT"],
            "comment": null,
            "licenseConcluded": {
                "type": "Single",
                "identifier": "Apache-2.0",
                "name": "Apache License 2.0"
            },
            "copyrightText": "Copyright 2010, 2011 Source Auditor Inc.",
            "licenseComment": null,
            "notice": null,
            "checksums": [
                {
                    "identifier": "SHA1",
                    "value": "2fd4e1c67a2d28fced849ee1bb76e7391b93eb12"
                },
                {
                    "identifier": "SHA256",
                    "value": "2fd4e1c67a2d28fced849ee1bb76e7391b93eb120000000000000000"
                }
            ],
            "licenseInfoInFiles": [
                {
                    "type": "Single",
                    "identifier": "Apache-2.0",
                    "name": "Apache License 2.0"
                }
            ],
            "contributors": [],
            "dependencies": [],
            "artifactOfProjectName": [],
            "artifactOfProjectHome": [],
            "artifactOfProjectURI": []
        }
    ],
    "packages": [
        {
            "id": "SPDXRef-Package",
            "name": "SPDX Translator",
            "packageFileName": "spdxtranslator-1.0.zip",
            "summary": "SPDX Translator utility",
            "description": "This utility translates and SPDX RDF XML document to a spreadsheet, translates a spreadsheet to an SPDX RDF XML document and translates an SPDX RDFa document to an SPDX RDF XML document.",
            "versionInfo": "Version 0.9.2",
            "sourceInfo": "Version 1.0 of the SPDX Translator application",
            "downloadLocation": "http://www.spdx.org/tools",
            "homepage": null,
            "originator": {
                "name": "SPDX",
                "email": null,
                "type": "Organization"
            },
            "supplier": {
                "name": "Linux Foundation",
                "email": null,
                "type": "Organization"
            },
            "licenseConcluded": {
                "type": "Conjunction",
                "identifier": [
                    "Apache-1.0",
                    "Apache-2.0",
                    "LicenseRef-1",
                    "LicenseRef-2",
                    "LicenseRef-3",
                    "LicenseRef-4",
                    "MPL-1.1"
                ],
                "name": [
                    "Apache License 1.0",
                    "Apache License 2.0",
                    "CyberNeko License",
                    "LicenseRef-1",
                    "LicenseRef-2",
                    "LicenseRef-4",
                    "Mozilla Public License 1.1"
                ]
            },
            "licenseDeclared": {
                "type": "Conjunction",
                "identifier": [
                    "Apache-2.0",
                    "LicenseRef-1",
                    "LicenseRef-2",
                    "LicenseRef-3",
                    "LicenseRef-4",
                    "MPL-1.1"
                ],
                "name": [
                    "Apache License 2.0",
                    "CyberNeko License",
                    "LicenseRef-1",
                    "LicenseRef-2",
                    "LicenseRef-4",
                    "Mozilla Public License 1.1"
                ]
            },
            "copyrightText": " Copyright 2010, 2011 Source Auditor Inc.",
            "licenseComment": "The declared license information can be found in the NOTICE file at the root of the archive file",
            "checksums": [
                {
                    "identifier": "SHA1",
                    "value": "2fd4e1c67a2d28fced849ee1bb76e7391b93eb12"
                }
            ],
            "licenseInfoFromFiles": [
                {
                    "type": "Single",
                    "identifier": "Apache-1.0",
                    "name": "Apache License 1.0"
                },
                {
                    "type": "Single",
                    "identifier": "Apache-2.0",
                    "name": "Apache License 2.0"
                },
                {
                    "type": "Single",
                    "identifier": "LicenseRef-1",
                    "name": "LicenseRef-1"
                },
                {
                    "type": "Single",
                    "identifier": "LicenseRef-2",
                    "name": "LicenseRef-2"
                },
                {
                    "type": "Single",
                    "identifier": "LicenseRef-3",
                    "name": "CyberNeko License"
                },
                {
                    "type": "Single",
                    "identifier": "LicenseRef-4",
                    "name": "LicenseRef-4"
                },
                {
                    "type": "Single",
                    "identifier": "MPL-1.1",
                    "name": "Mozilla Public License 1.1"
                }
            ],
            "verificationCode": {
                "value": "4e3211c67a2d28fced849ee1bb76e7391b93feba",
                "excludedFilesNames": [
                    "SpdxTranslatorSpdx.rdf",
                    "SpdxTranslatorSpdx.txt"
                ]
            }
        }
    ],
    "externalDocumentRefs": [
        {
            "externalDocumentId": "DocumentRef-spdx-tool-2.1",
            "spdxDocument": "https://spdx.org/spdxdocs/spdx-tools-v2.1-3F2504E0-4F89-41D3-9A0C-0305E82C3301",
            "checksum": {
                "identifier": "SHA1",
                "value": "d6a770ba38583ed4bb4525bd96e50461655d2759"
            }
        }
    ],
    "extractedLicenses": [
        {
            "name": "LicenseRef-1",
            "identifier": "LicenseRef-1",
            "text": "/*\n * (c) Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Hewlett-Packard Development Company, LP\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n * 3. The name of the author may not be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR\n * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,\n * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\n * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\n * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */",
            "comment": null,
            "cross_refs": []
        },
        {
            "name": "LicenseRef-2",
            "identifier": "LicenseRef-2",
            "text": "This package includes the GRDDL parser developed by Hewlett Packard under the following license:\n\u00a9 Copyright 2007 Hewlett-Packard Development Company, LP\n\nRedistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: \n\nRedistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. \nRedistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. \nThe name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. \nTHIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ",
            "comment": null,
            "cross_refs": []
        },
        {
            "name": "CyberNeko License",
            "identifier": "LicenseRef-3",
            "text": "The CyberNeko Software License, Version 1.0\n\n \n(C) Copyright 2002-2005, Andy Clark.  All rights reserved.\n \nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions\nare met:\n\n1. Redistributions of source code must retain the above copyright\n   notice, this list of conditions and the following disclaimer. \n\n2. Redistributions in binary form must reproduce the above copyright\n   notice, this list of conditions and the following disclaimer in\n   the documentation and/or other materials provided with the\n   distribution.\n\n3. The end-user documentation included with the redistribution,\n   if any, must include the following acknowledgment:  \n     \"This product includes software developed by Andy Clark.\"\n   Alternately, this acknowledgment may appear in the software itself,\n   if and wherever such third-party acknowledgments normally appear.\n\n4. The names \"CyberNeko\" and \"NekoHTML\" must not be used to endorse\n   or promote products derived from this software without prior \n   written permission. For written permission, please contact \n   andyc@cyberneko.net.\n\n5. Products derived from this software may not be called \"CyberNeko\",\n   nor may \"CyberNeko\" appear in their name, without prior written\n   permission of the author.\n\nTHIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED\nWARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\nOF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS\nBE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, \nOR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT \nOF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR \nBUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, \nWHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE \nOR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, \nEVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.",
            "comment": "This is tye CyperNeko License",
            "cross_refs": [
                "http://justasample.url.com",
                "http://people.apache.org/~andyc/neko/LICENSE"
            ]
        },
        {
            "name": "LicenseRef-4",
            "identifier": "LicenseRef-4",
            "text": "/*\n * (c) Copyright 2009 University of Bristol\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n * 3. The name of the author may not be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR\n * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,\n * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\n * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\n * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */  ",
            "comment": null,
            "cross_refs": []
        }
    ],
    "annotations": [
        {
            "id": "https://spdx.org/spdxdocs/spdx-example-444504E0-4F89-41D3-9A0C-0305E82C3301#SPDXRef-45",
            "comment": "This is just an example. Some of the non-standard licenses look like they are actually BSD 3 clause licenses",
            "type": "REVIEW",
            "annotator": {
                "name": "Jim Reviewer",
                "email": null,
                "type": "Person"
            },
            "date": "2012-06-13T00:00:00Z"
        }
    ],
    "reviews": [
        {
            "comment": "This is just an example.  Some of the non-standard licenses look like they are actually BSD 3 clause licenses",
            "reviewer": {
                "name": "Joe Reviewer",
                "email": null,
                "type": "Person"
            },
            "date": "2010-02-10T00:00:00Z"
        },
        {
            "comment": "Another example reviewer.",
            "reviewer": {
                "name": "Suzanne Reviewer",
                "email": null,
                "type": "Person"
            },
            "date": "2011-03-13T00:00:00Z"
        }
    ],
    "snippets": [
        {
            "id": "SPDXRef-Snippet",
            "name": "from linux kernel",
            "comment": "This snippet was identified as significant and highlighted in this Apache-2.0 file, when a commercial scanner identified it as being derived from file foo.c in package xyz which is licensed under GPL-2.0-or-later.",
            "copyrightText": "Copyright 2008-2010 John Smith",
            "licenseComments": "The concluded license was taken from package xyz, from which the snippet was copied into the current file. The concluded license information was found in the COPYING.txt file in package xyz.",
            "snippetFromFile": "SPDXRef-DoapSource",
            "licenseConcluded": {
                "type": "Single",
                "identifier": "Apache-2.0",
                "name": "Apache License 2.0"
            },
            "licenseInfoInSnippets": [
                {
                    "type": "Single",
                    "identifier": "Apache-2.0",
                    "name": "Apache License 2.0"
                }
            ]
        }
    ],
    "relationships": [
        {
            "spdx_element_id": "SPDXRef-DOCUMENT",
            "relationship_type": "DESCRIBES",
            "related_spdx_element": "SPDXRef-Package"
        }
    ]
}

tests/data/doc_parse/expected.json METASEP
{
    "id": "SPDXRef-DOCUMENT",
    "specVersion": {
        "major": 2,
        "minor": 1
    },
    "documentNamespace": "https://spdx.org/spdxdocs/spdx-example-444504E0-4F89-41D3-9A0C-0305E82C3301",
    "name": "Sample_Document-V2.1",
    "comment": "This is a sample spreadsheet",
    "dataLicense": {
        "type": "Single",
        "identifier": "CC0-1.0",
        "name": "Creative Commons Zero v1.0 Universal"
    },
    "licenseListVersion": {
        "major": 3,
        "minor": 6
    },
    "creators": [
        {
            "name": "Gary O'Neall",
            "email": null,
            "type": "Person"
        },
        {
            "name": "Source Auditor Inc.",
            "email": null,
            "type": "Organization"
        },
        {
            "name": "SourceAuditor-V1.2",
            "type": "Tool"
        }
    ],
    "created": "2010-02-03T00:00:00Z",
    "creatorComment": "This is an example of an SPDX spreadsheet format",
    "files": [
        {
            "id": "SPDXRef-File1",
            "fileName": "Jenna-2.6.3/jena-2.6.3-sources.jar",
            "fileTypes": ["ARCHIVE", "OTHER"],
            "comment": "This file belongs to Jena",
            "licenseConcluded": {
                "type": "Single",
                "identifier": "LicenseRef-1",
                "name": "LicenseRef-1"
            },
            "copyrightText": "(c) Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Hewlett-Packard Development Company, LP",
            "licenseComment": "This license is used by Jena",
            "notice": null,
          "checksums": [{
            "identifier": "SHA1",
            "value": "3ab4e1c67a2d28fced849ee1bb76e7391b93f125"
          },{
            "identifier": "SHA256",
            "value": "3ab4e1c67a2d28fced849ee1bb76e7391b93f1250000000000000000"
          }],
            "licenseInfoInFiles": [
                {
                    "type": "Single",
                    "identifier": "LicenseRef-1",
                    "name": "LicenseRef-1"
                }
            ],
            "contributors": [],
            "dependencies": [],
            "artifactOfProjectName": [
                "Jena"
            ],
            "artifactOfProjectHome": [
                "http://www.openjena.org/"
            ],
            "artifactOfProjectURI": [
                "http://subversion.apache.org/doap.rdf"
            ]
        },
        {
            "id": "SPDXRef-File2",
            "fileName": "src/org/spdx/parser/DOAPProject.java",
            "fileTypes": ["SOURCE", "TEXT"],
            "comment": null,
            "licenseConcluded": {
                "type": "Single",
                "identifier": "Apache-2.0",
                "name": "Apache License 2.0"
            },
            "copyrightText": "Copyright 2010, 2011 Source Auditor Inc.",
            "licenseComment": null,
            "notice": null,
            "checksums": [{
                "identifier": "SHA1",
                "value": "2fd4e1c67a2d28fced849ee1bb76e7391b93eb12"
            }],
            "licenseInfoInFiles": [
                {
                    "type": "Single",
                    "identifier": "Apache-2.0",
                    "name": "Apache License 2.0"
                }
            ],
            "contributors": [],
            "dependencies": [],
            "artifactOfProjectName": [],
            "artifactOfProjectHome": [],
            "artifactOfProjectURI": []
        }
    ],
    "packages": [
        {
            "id": "SPDXRef-Package",
            "name": "SPDX Translator",
            "packageFileName": "spdxtranslator-1.0.zip",
            "summary": "SPDX Translator utility",
            "description": "This utility translates and SPDX RDF XML document to a spreadsheet, translates a spreadsheet to an SPDX RDF XML document and translates an SPDX RDFa document to an SPDX RDF XML document.",
            "versionInfo": "Version 0.9.2",
            "sourceInfo": "Version 1.0 of the SPDX Translator application",
            "downloadLocation": "http://www.spdx.org/tools",
            "homepage": null,
            "originator": {
                "name": "SPDX",
                "email": null,
                "type": "Organization"
            },
            "supplier": {
                "name": "Linux Foundation",
                "email": null,
                "type": "Organization"
            },
            "licenseConcluded": {
                "type": "Conjunction",
                "identifier": [
                    "Apache-1.0",
                    "Apache-2.0",
                    "LicenseRef-1",
                    "LicenseRef-2",
                    "LicenseRef-3",
                    "LicenseRef-4",
                    "MPL-1.1"
                ],
                "name": [
                    "Apache License 1.0",
                    "Apache License 2.0",
                    "CyberNeko License",
                    "LicenseRef-1",
                    "LicenseRef-2",
                    "LicenseRef-4",
                    "Mozilla Public License 1.1"
                ]
            },
            "licenseDeclared": {
                "type": "Conjunction",
                "identifier": [
                    "Apache-2.0",
                    "LicenseRef-1",
                    "LicenseRef-2",
                    "LicenseRef-3",
                    "LicenseRef-4",
                    "MPL-1.1"
                ],
                "name": [
                    "Apache License 2.0",
                    "CyberNeko License",
                    "LicenseRef-1",
                    "LicenseRef-2",
                    "LicenseRef-4",
                    "Mozilla Public License 1.1"
                ]
            },
            "copyrightText": " Copyright 2010, 2011 Source Auditor Inc.",
            "licenseComment": "The declared license information can be found in the NOTICE file at the root of the archive file",
            "checksums": [{
                "identifier": "SHA1",
                "value": "2fd4e1c67a2d28fced849ee1bb76e7391b93eb12"
            }],
            "licenseInfoFromFiles": [
                {
                    "type": "Single",
                    "identifier": "Apache-1.0",
                    "name": "Apache License 1.0"
                },
                {
                    "type": "Single",
                    "identifier": "Apache-2.0",
                    "name": "Apache License 2.0"
                },
                {
                    "type": "Single",
                    "identifier": "LicenseRef-1",
                    "name": "LicenseRef-1"
                },
                {
                    "type": "Single",
                    "identifier": "LicenseRef-2",
                    "name": "LicenseRef-2"
                },
                {
                    "type": "Single",
                    "identifier": "LicenseRef-3",
                    "name": "CyberNeko License"
                },
                {
                    "type": "Single",
                    "identifier": "LicenseRef-4",
                    "name": "LicenseRef-4"
                },
                {
                    "type": "Single",
                    "identifier": "MPL-1.1",
                    "name": "Mozilla Public License 1.1"
                }
            ],
            "verificationCode": {
                "value": "4e3211c67a2d28fced849ee1bb76e7391b93feba",
                "excludedFilesNames": [
                    "SpdxTranslatorSpdx.rdf",
                    "SpdxTranslatorSpdx.txt"
                ]
            },
      "builtDate": "2020-01-01T12:00:00Z",
      "releaseDate": "2021-01-01T12:00:00Z",
      "validUntilDate": "2022-01-01T12:00:00Z",
      "primaryPackagePurpose": "OPERATING-SYSTEM"}
    ],
    "externalDocumentRefs": [
        {
            "externalDocumentId": "DocumentRef-spdx-tool-2.1",
            "spdxDocument": "https://spdx.org/spdxdocs/spdx-tools-v2.1-3F2504E0-4F89-41D3-9A0C-0305E82C3301",
            "checksum": {
                "identifier": "SHA1",
                "value": "d6a770ba38583ed4bb4525bd96e50461655d2759"
            }
        }
    ],
    "extractedLicenses": [
        {
            "name": "LicenseRef-1",
            "identifier": "LicenseRef-1",
            "text": "/*\n * (c) Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Hewlett-Packard Development Company, LP\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n * 3. The name of the author may not be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR\n * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,\n * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\n * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\n * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */",
            "comment": null,
            "cross_refs": []
        },
        {
            "name": "LicenseRef-2",
            "identifier": "LicenseRef-2",
            "text": "This package includes the GRDDL parser developed by Hewlett Packard under the following license:\n\u00a9 Copyright 2007 Hewlett-Packard Development Company, LP\n\nRedistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:\n\nRedistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.\nRedistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.\nThe name of the author may not be used to endorse or promote products derived from this software without specific prior written permission.\nTHIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ",
            "comment": null,
            "cross_refs": []
        },
        {
            "name": "CyberNeko License",
            "identifier": "LicenseRef-3",
            "text": "The CyberNeko Software License, Version 1.0\n\n\n(C) Copyright 2002-2005, Andy Clark.  All rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions\nare met:\n\n1. Redistributions of source code must retain the above copyright\n   notice, this list of conditions and the following disclaimer.\n\n2. Redistributions in binary form must reproduce the above copyright\n   notice, this list of conditions and the following disclaimer in\n   the documentation and/or other materials provided with the\n   distribution.\n\n3. The end-user documentation included with the redistribution,\n   if any, must include the following acknowledgment:\n     \"This product includes software developed by Andy Clark.\"\n   Alternately, this acknowledgment may appear in the software itself,\n   if and wherever such third-party acknowledgments normally appear.\n\n4. The names \"CyberNeko\" and \"NekoHTML\" must not be used to endorse\n   or promote products derived from this software without prior\n   written permission. For written permission, please contact\n   andyc@cyberneko.net.\n\n5. Products derived from this software may not be called \"CyberNeko\",\n   nor may \"CyberNeko\" appear in their name, without prior written\n   permission of the author.\n\nTHIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED\nWARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\nOF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS\nBE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,\nOR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\nOF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR\nBUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\nWHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\nOR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\nEVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.",
            "comment": "This is tye CyperNeko License",
            "cross_refs": [
                "http://justasample.url.com",
                "http://people.apache.org/~andyc/neko/LICENSE"
            ]
        },
        {
            "name": "LicenseRef-4",
            "identifier": "LicenseRef-4",
            "text": "/*\n * (c) Copyright 2009 University of Bristol\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n * 3. The name of the author may not be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR\n * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,\n * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\n * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\n * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */  ",
            "comment": null,
            "cross_refs": []
        }
    ],
    "annotations": [
        {
            "id": "SPDXRef-DOCUMENT",
            "comment": "This is just an example. Some of the non-standard licenses look like they are actually BSD 3 clause licenses",
            "type": "REVIEW",
            "annotator": {
                "name": "Jim Reviewer",
                "email": null,
                "type": "Person"
            },
            "date": "2012-06-13T00:00:00Z"
        }
    ],
    "reviews": [
        {
            "comment": "This is just an example.  Some of the non-standard licenses look like they are actually BSD 3 clause licenses",
            "reviewer": {
                "name": "Joe Reviewer",
                "email": null,
                "type": "Person"
            },
            "date": "2010-02-10T00:00:00Z"
        },
        {
            "comment": "Another example reviewer.",
            "reviewer": {
                "name": "Suzanne Reviewer",
                "email": null,
                "type": "Person"
            },
            "date": "2011-03-13T00:00:00Z"
        }
    ],
    "snippets": [
        {
            "id": "SPDXRef-Snippet",
            "name": "from linux kernel",
            "comment": "This snippet was identified as significant and highlighted in this Apache-2.0 file, when a commercial scanner identified it as being derived from file foo.c in package xyz which is licensed under GPL-2.0-or-later.",
            "copyrightText": "Copyright 2008-2010 John Smith",
            "licenseComments": "The concluded license was taken from package xyz, from which the snippet was copied into the current file. The concluded license information was found in the COPYING.txt file in package xyz.",
            "snippetFromFile": "SPDXRef-DoapSource",
            "licenseConcluded": {
                "type": "Single",
                "identifier": "Apache-2.0",
                "name": "Apache License 2.0"
            },
            "licenseInfoInSnippets": [
                {
                    "type": "Single",
                    "identifier": "Apache-2.0",
                    "name": "Apache License 2.0"},
        {
          "type": "Single",
          "identifier": "GPL-2.0-only",
          "name": "GNU General Public License v2.0 only"
                }
            ]
        }
    ],
    "relationships": [
        {
            "spdx_element_id": "SPDXRef-Package",
            "relationship_type": "CONTAINS",
            "related_spdx_element": "SPDXRef-File1"
        },
        {
            "spdx_element_id": "SPDXRef-Package",
            "relationship_type": "CONTAINS",
            "related_spdx_element": "SPDXRef-File2"
        },
        {
            "spdx_element_id": "SPDXRef-DOCUMENT",
            "relationship_type": "DESCRIBES",
            "related_spdx_element": "SPDXRef-Package"
        }
    ]
}

tests/data/doc_parse/SBOMexpected.json METASEP
{
    "id": "SPDXRef-DOCUMENT",
    "specVersion": {
        "major": 2,
        "minor": 2
    },
    "documentNamespace": "http://spdx.org/spdxdocs/spdx-document-xyz",
    "name": "xyz-0.1.0",
    "comment": null,
    "dataLicense": {
        "type": "Single",
        "identifier": "CC0-1.0",
        "name": "Creative Commons Zero v1.0 Universal"
    },
    "licenseListVersion": {
        "major": 3,
        "minor": 9
    },
    "creators": [
        {
            "name": "Example Inc.",
            "email": null,
            "type": "Organization"
        },
        {
            "name": "Thomas Steenbergen",
            "email": null,
            "type": "Person"
        }
    ],
    "created": "2020-07-23T18:30:22Z",
    "creatorComment": null,
    "files": [],
    "packages": [
        {
            "id": "SPDXRef-Package-xyz",
            "name": "xyz",
            "packageFileName": null,
            "summary": "Awesome product created by Example Inc.",
            "description": null,
            "versionInfo": "0.1.0",
            "sourceInfo": null,
            "downloadLocation": "git+ssh://gitlab.example.com:3389/products/xyz.git@b2c358080011af6a366d2512a25a379fbe7b1f78",
            "homepage": "https://example.com/products/xyz",
            "originator": null,
            "supplier": null,
            "licenseConcluded": {
                "type": "Single",
                "identifier": "NOASSERTION",
                "name": "NOASSERTION"
            },
            "licenseDeclared": {
                "type": "Conjunction",
                "identifier": [
                    "Apache-2.0",
                    "LicenseRef-Proprietary-ExampleInc",
                    "curl"
                ],
                "name": [
                    "Apache License 2.0",
                    "LicenseRef-Proprietary-ExampleInc",
                    "curl License"
                ]
            },
            "copyrightText": "copyright 2004-2020 Example Inc. All Rights Reserved.",
            "licenseComment": null,
            "checksums": [{
        "identifier": "SHA1",
        "value": "SOME-SHA1"
      }],
            "licenseInfoFromFiles": [],
            "verificationCode": {
                "value": null,
                "excludedFilesNames": []
            }
        },
        {
            "id": "SPDXRef-Package-curl",
            "name": "curl",
            "packageFileName": "./libs/curl",
            "summary": null,
            "description": "A command line tool and library for transferring data with URL syntax, supporting HTTP, HTTPS, FTP, FTPS, GOPHER, TFTP, SCP, SFTP, SMB, TELNET, DICT, LDAP, LDAPS, MQTT, FILE, IMAP, SMTP, POP3, RTSP and RTMP. libcurl offers a myriad of powerful features.",
            "versionInfo": "7.70.0",
            "sourceInfo": null,
            "downloadLocation": "https://github.com/curl/curl/releases/download/curl-7_70_0/curl-7.70.0.tar.gz",
            "homepage": "https://curl.haxx.se/",
            "originator": null,
            "supplier": null,
            "licenseConcluded": {
                "type": "Single",
                "identifier": "NOASSERTION",
                "name": "NOASSERTION"
            },
            "licenseDeclared": {
                "type": "Single",
                "identifier": "curl",
                "name": "curl License"
            },
            "copyrightText": "Copyright (c) 1996 - 2020, Daniel Stenberg, <daniel@haxx.se>, and many contributors, see the THANKS file.",
            "licenseComment": null,
            "checksums": [{
        "identifier": "SHA1",
        "value": "SOME-SHA1"
      }],
            "licenseInfoFromFiles": [],
            "verificationCode": {
                "value": null,
                "excludedFilesNames": []
            }
        },
        {
            "id": "SPDXRef-Package-openssl",
            "name": "openssl",
            "packageFileName": "./libs/openssl",
            "summary": null,
            "description": "OpenSSL is a robust, commercial-grade, full-featured Open Source Toolkit for the Transport Layer Security (TLS) protocol formerly known as the Secure Sockets Layer (SSL) protocol. The protocol implementation is based on a full-strength general purpose cryptographic library, which can also be used stand-alone.",
            "versionInfo": "1.1.1g",
            "sourceInfo": null,
            "downloadLocation": "git+ssh://github.com/openssl/openssl.git@e2e09d9fba1187f8d6aafaa34d4172f56f1ffb72",
            "homepage": "https://www.openssl.org/",
            "originator": null,
            "supplier": null,
            "licenseConcluded": {
                "type": "Single",
                "identifier": "NOASSERTION",
                "name": "NOASSERTION"
            },
            "licenseDeclared": {
                "type": "Single",
                "identifier": "Apache-2.0",
                "name": "Apache License 2.0"
            },
            "copyrightText": "copyright 2004-2020 The OpenSSL Project Authors. All Rights Reserved.",
            "licenseComment": null,
            "checksums": [{
        "identifier": "SHA1",
        "value": "SOME-SHA1"
      }],
            "licenseInfoFromFiles": [],
            "verificationCode": {
                "value": null,
                "excludedFilesNames": []
            }
        }
    ],
    "externalDocumentRefs": [],
    "extractedLicenses": [],
    "annotations": [],
    "reviews": [],
    "snippets": [],
     "relationships": [
        {
            "spdx_element_id": "SPDXRef-Package-xyz",
            "relationship_type": "CONTAINS",
            "related_spdx_element": "SPDXRef-Package-curl"
        },
        {
            "spdx_element_id": "SPDXRef-Package-xyz",
            "relationship_type": "CONTAINS",
            "related_spdx_element": "SPDXRef-Package-openssl"
        },
        {
            "spdx_element_id": "SPDXRef-DOCUMENT",
            "relationship_type": "DESCRIBES",
            "related_spdx_element": "SPDXRef-Package-xyz"
        }
    ]
}

tests/validation/test_uri_validators.py METASEP
#  Copyright (c) 2022 spdx contributors
#  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.

import pytest

from src.validation.uri_validators import validate_url, validate_download_location, validate_uri


@pytest.mark.parametrize("input_value", ["https://some.url",
                                         "https://spdx.org/spdxdocs/spdx-tools-v1.2-3F2504E0-4F89-41D3-9A0C-0305E82...",
                                         "http://some.url", "http://ftp.gnu.org/gnu/glibc/glibc-ports-2.15.tar.gz"])
def test_valid_url(input_value):
    assert validate_url(input_value) == []


# TODO: more negative examples: https://github.com/spdx/tools-python/issues/377
@pytest.mark.parametrize("input_value", [":::::", ])
def test_invalid_url(input_value):
    assert validate_url(input_value) == [f"must be a valid URL, but is: {input_value}"]


@pytest.mark.parametrize("input_value", ["http://ftp.gnu.org/gnu/glibc/glibc-ports-2.15.tar.gz",
                                         "git://git.myproject.org/MyProject",
                                         "git+https://git.myproject.org/MyProject.git",
                                         "git+http://git.myproject.org/MyProject",
                                         "git+ssh://git.myproject.org/MyProject.git",
                                         "git+git://git.myproject.org/MyProject",
                                         "git+git@git.myproject.org:MyProject",
                                         "git://git.myproject.org/MyProject#src/somefile.c",
                                         "git+https://git.myproject.org/MyProject#src/Class.java",
                                         "git://git.myproject.org/MyProject.git@master",
                                         "git+https://git.myproject.org/MyProject.git@v1.0",
                                         "git://git.myproject.org/MyProject.git@da39a3ee5e6b4b0d3255bfef95601890afd80709",
                                         "git+https://git.myproject.org/MyProject.git@master#/src/MyClass.cpp",
                                         "git+https://git.myproject.org/MyProject@da39a3ee5e6b4b0d3255bfef95601890afd80709#lib/variable.rb",
                                         "hg+http://hg.myproject.org/MyProject",
                                         "hg+https://hg.myproject.org/MyProject",
                                         "hg+ssh://hg.myproject.org/MyProject",
                                         "hg+https://hg.myproject.org/MyProject#src/somefile.c",
                                         "hg+https://hg.myproject.org/MyProject#src/Class.java",
                                         "hg+https://hg.myproject.org/MyProject@da39a3ee5e6b",
                                         "hg+https://hg.myproject.org/MyProject@2019",
                                         "hg+https://hg.myproject.org/MyProject@v1.0",
                                         "hg+https://hg.myproject.org/MyProject@special_feature",
                                         "hg+https://hg.myproject.org/MyProject@master#/src/MyClass.cpp",
                                         "hg+https://hg.myproject.org/MyProject@da39a3ee5e6b#lib/variable.rb",
                                         "svn://svn.myproject.org/svn/MyProject",
                                         "svn+svn://svn.myproject.org/svn/MyProject",
                                         "svn+http://svn.myproject.org/svn/MyProject/trunk",
                                         "svn+https://svn.myproject.org/svn/MyProject/trunk",
                                         "svn+https://svn.myproject.org/MyProject#src/somefile.c",
                                         "svn+https://svn.myproject.org/MyProject#src/Class.java",
                                         "svn+https://svn.myproject.org/MyProject/trunk#src/somefile.c",
                                         "svn+https://svn.myproject.org/MyProject/trunk/src/somefile.c",
                                         "svn+https://svn.myproject.org/svn/MyProject/trunk@2019",
                                         "svn+https://svn.myproject.org/MyProject@123#/src/MyClass.cpp",
                                         "svn+https://svn.myproject.org/MyProject/trunk@1234#lib/variable/variable.rb",
                                         "bzr+https://bzr.myproject.org/MyProject/trunk",
                                         "bzr+http://bzr.myproject.org/MyProject/trunk",
                                         "bzr+sftp://myproject.org/MyProject/trunk",
                                         "bzr+ssh://myproject.org/MyProject/trunk",
                                         "bzr+ftp://myproject.org/MyProject/trunk",
                                         "bzr+lp:MyProject",
                                         "bzr+https://bzr.myproject.org/MyProject/trunk#src/somefile.c",
                                         "bzr+https://bzr.myproject.org/MyProject/trunk#src/Class.java",
                                         "bzr+https://bzr.myproject.org/MyProject/trunk@2019",
                                         "bzr+http://bzr.myproject.org/MyProject/trunk@v1.0",
                                         "bzr+https://bzr.myproject.org/MyProject/trunk@2019#src/somefile.c",
                                         ])
def test_valid_package_download_location(input_value):
    assert validate_download_location(input_value) == []


# TODO: more negative examples: https://github.com/spdx/tools-python/issues/377
@pytest.mark.parametrize("input_value", [":::::", ])
def test_invalid_package_download_location(input_value):
    assert validate_download_location(input_value) == [
        f"must be a valid download location according to the specification, but is: {input_value}"]


@pytest.mark.parametrize("input_value", ["https://some.uri", "http:////some",
                                         "https://spdx.org/spdxdocs/spdx-tools-v1.2-3F2504E0-4F89-41D3-9A0C-0305E82...",
                                         "h://someweirdtest^?", "https://some.uri that goes on!?"])
def test_valid_uri(input_value):
    message = validate_uri(input_value)

    assert message == []


@pytest.mark.parametrize("input_value", ["/invalid/uri", "http//uri", "http://some#uri", "some/uri", "some weird test"])
def test_invalid_uri(input_value):
    message = validate_uri(input_value)

    assert message == [f"must be a valid URI specified in RFC-3986, but is: {input_value}"]


@pytest.mark.parametrize("input_value", ["://spdx.org/spdxdocs/spdx-tools-v1.2-3F2504E0-4F89-41D3-9A0C-0305E82..."])
@pytest.mark.skip(
    "validate_uri() seems to invalidate URIs without scheme, so it does not run into this case. But I'm not sure yet if this covers all scheme-less examples."
    "https://github.com/spdx/tools-python/issues/377")
def test_uri_without_scheme(input_value):
    message = validate_uri(input_value)

    assert message == [f"must have a URI scheme, but is: {input_value}"]

tests/validation/test_spdx_id_validators.py METASEP
#  Copyright (c) 2022 spdx contributors
#  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.

# TODO: https://github.com/spdx/tools-python/issues/376

tests/validation/test_snippet_validator.py METASEP
#  Copyright (c) 2022 spdx contributors
#  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.

from typing import List

import pytest

from src.model.document import Document
from src.model.license_expression import LicenseExpression
from src.model.snippet import Snippet
from src.model.spdx_no_assertion import SpdxNoAssertion
from src.validation.snippet_validator import validate_snippet_within_document
from src.validation.validation_message import ValidationMessage, ValidationContext, SpdxElementType
from tests.valid_defaults import get_snippet, get_document, get_file


def test_valid_snippet():
    document: Document = get_document(files=[get_file(spdx_id="SPDXRef-File")])

    snippet = Snippet("SPDXRef-Snippet", "SPDXRef-File", (200, 400), (20, 40), LicenseExpression("some_license"),
                      SpdxNoAssertion(), "comment on license",
                      "copyright", "comment", "name", ["attribution"])
    validation_messages: List[ValidationMessage] = validate_snippet_within_document(snippet, document)

    assert validation_messages == []


@pytest.mark.parametrize("snippet_input, expected_message",
                         [(get_snippet(byte_range=(-12, 45)),
                           "byte_range values must be greater than or equal to 1, but is: (-12, 45)"),
                          (get_snippet(byte_range=(45, 23)),
                           "the first value of byte_range must be less than or equal to the second, but is: (45, 23)"),
                          (get_snippet(line_range=(-12, 45)),
                           "line_range values must be greater than or equal to 1, but is: (-12, 45)"),
                          (get_snippet(line_range=(45, 23)),
                           "the first value of line_range must be less than or equal to the second, but is: (45, 23)")
                          ])
def test_invalid_ranges(snippet_input, expected_message):
    validation_messages: List[ValidationMessage] = validate_snippet_within_document(snippet_input,
                                                                                    get_document(files=[get_file()]))

    expected = ValidationMessage(expected_message,
                                 ValidationContext(spdx_id=snippet_input.spdx_id,
                                                   parent_id=get_document().creation_info.spdx_id,
                                                   element_type=SpdxElementType.SNIPPET,
                                                   full_element=snippet_input))

    assert validation_messages == [expected]

tests/validation/test_relationship_validator.py METASEP
#  Copyright (c) 2022 spdx contributors
#  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.

from typing import List

import pytest

from src.model.document import Document
from src.model.relationship import Relationship, RelationshipType
from src.validation.relationship_validator import validate_relationship
from src.validation.validation_message import ValidationMessage, SpdxElementType, ValidationContext
from tests.valid_defaults import get_document, get_package, get_relationship, get_file


def test_valid_relationship():
    document: Document = get_document(packages=[get_package(spdx_id="SPDXRef-Package")])

    relationship = Relationship("SPDXRef-DOCUMENT", RelationshipType.AMENDS, "SPDXRef-Package", comment="comment")
    validation_messages: List[ValidationMessage] = validate_relationship(relationship, document, "2.3")

    assert validation_messages == []


@pytest.mark.parametrize("spdx_element_id, related_spdx_element_id, expected_message",
                         [("SPDXRef-unknownFile", "SPDXRef-File",
                           'did not find the referenced spdx_id SPDXRef-unknownFile in the SPDX document'),
                          ("SPDXRef-File", "SPDXRef-unknownFile",
                           'did not find the referenced spdx_id SPDXRef-unknownFile in the SPDX document'),
                          ])
def test_unknown_spdx_id(spdx_element_id, related_spdx_element_id, expected_message):
    relationship: Relationship = get_relationship(spdx_element_id=spdx_element_id,
                                                  related_spdx_element_id=related_spdx_element_id)
    document: Document = get_document(files=[get_file(spdx_id="SPDXRef-File")])
    validation_messages: List[ValidationMessage] = validate_relationship(relationship, document, "2.3")

    expected = ValidationMessage(expected_message,
                                 ValidationContext(element_type=SpdxElementType.RELATIONSHIP,
                                                   full_element=relationship))

    assert validation_messages == [expected]


@pytest.mark.parametrize("relationship, expected_message",
                         [(Relationship("SPDXRef-DOCUMENT", RelationshipType.SPECIFICATION_FOR, "SPDXRef-Package"),
                           "RelationshipType.SPECIFICATION_FOR is not supported for SPDX versions below 2.3"),
                          (Relationship("SPDXRef-DOCUMENT", RelationshipType.REQUIREMENT_DESCRIPTION_FOR,
                                        "SPDXRef-Package"),
                           "RelationshipType.REQUIREMENT_DESCRIPTION_FOR is not supported for SPDX versions below 2.3")])
def test_v2_3_only_types(relationship, expected_message):
    document: Document = get_document(packages=[get_package(spdx_id="SPDXRef-Package")])

    validation_message: List[ValidationMessage] = validate_relationship(relationship, document, "2.2")

    expected = [ValidationMessage(expected_message,
                                  ValidationContext(element_type=SpdxElementType.RELATIONSHIP,
                                                    full_element=relationship))]

    assert validation_message == expected

tests/validation/test_package_validator.py METASEP
#  Copyright (c) 2022 spdx contributors
#  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.

from datetime import datetime
from typing import List

import pytest

from src.model.license_expression import LicenseExpression
from src.model.package import Package, PackagePurpose
from src.model.spdx_no_assertion import SpdxNoAssertion
from src.model.spdx_none import SpdxNone
from src.validation.package_validator import validate_package_within_document
from src.validation.validation_message import ValidationMessage, ValidationContext, SpdxElementType
from tests.valid_defaults import get_checksum, get_external_package_ref, get_actor, get_package_verification_code, \
    get_package, get_document


def test_valid_package():
    package = Package("SPDXRef-Package", "package name", "www.download.com", "version", "file_name", SpdxNoAssertion(),
                      get_actor(), True,
                      get_package_verification_code(), [get_checksum()], "https://homepage.com", "source_info", None,
                      [LicenseExpression("expression")],
                      SpdxNone(), "comment on license", "copyright", "summary", "description", "comment",
                      [get_external_package_ref()], ["text"], PackagePurpose.OTHER, datetime(2022, 1, 1), None, None)
    validation_messages: List[ValidationMessage] = validate_package_within_document(package, get_document())

    assert validation_messages == []


@pytest.mark.parametrize("package_input, expected_message",
                         [(get_package(files_analyzed=False, verification_code=get_package_verification_code()),
                           f'verification_code must be None if files_analyzed is False, but is: {get_package_verification_code()}'),
                          (get_package(files_analyzed=False, license_info_from_files=SpdxNone()),
                           'license_info_from_files must be None if files_analyzed is False, but is: NONE'),
                          (get_package(files_analyzed=False, license_info_from_files=SpdxNoAssertion()),
                           'license_info_from_files must be None if files_analyzed is False, but is: NOASSERTION'),
                          (get_package(files_analyzed=False,
                                       license_info_from_files=[LicenseExpression("some_license")]),
                           'license_info_from_files must be None if files_analyzed is False, but is: [LicenseExpression(expression_string=\'some_license\')]')
                          ])
def test_invalid_package(package_input, expected_message):
    validation_messages: List[ValidationMessage] = validate_package_within_document(package_input, get_document())

    expected = ValidationMessage(expected_message,
                                 ValidationContext(spdx_id=package_input.spdx_id, parent_id="SPDXRef-DOCUMENT",
                                                   element_type=SpdxElementType.PACKAGE,
                                                   full_element=package_input))

    assert validation_messages == [expected]

tests/validation/test_license_expression_validator.py METASEP
#  Copyright (c) 2022 spdx contributors
#  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.

from typing import List

from src.model.license_expression import LicenseExpression
from src.validation.license_expression_validator import validate_license_expression
from src.validation.validation_message import ValidationMessage


def test_valid_license_expression():
    license_expression = LicenseExpression("LicenseRef-1")
    validation_messages: List[ValidationMessage] = validate_license_expression(license_expression)

    assert validation_messages == []

tests/validation/test_file_validator.py METASEP
#  Copyright (c) 2022 spdx contributors
#  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.

from typing import List

import pytest

from src.model.checksum import Checksum, ChecksumAlgorithm
from src.model.file import File, FileType
from src.model.spdx_no_assertion import SpdxNoAssertion
from src.model.spdx_none import SpdxNone
from src.validation.file_validator import validate_file_within_document
from src.validation.validation_message import ValidationMessage, ValidationContext, SpdxElementType
from tests.valid_defaults import get_checksum, get_file, get_document


def test_valid_file():
    file = File("./file/name.py", "SPDXRef-File", [get_checksum()], [FileType.OTHER, FileType.SPDX], SpdxNone(),
                SpdxNoAssertion(),
                "comment on license", "copyright", "comment", "notice", ["contributor"], ["attribution"])
    validation_messages: List[ValidationMessage] = validate_file_within_document(file, get_document())

    assert validation_messages == []


@pytest.mark.parametrize("file_input, spdx_id, expected_message",
                         [(get_file(name="invalid file name"), get_file().spdx_id,
                           'file name must be a relative path to the file, starting with "./", but is: invalid file name'),
                          (get_file(checksums=[Checksum(ChecksumAlgorithm.MD2, "d4c41ce30a517d6ce9d79c8c17bb4b66")]),
                           get_file().spdx_id,
                           f'checksums must contain a SHA1 algorithm checksum, but only contains: [<ChecksumAlgorithm.MD2: 13>]')
                          ])
def test_invalid_file(file_input, spdx_id, expected_message):
    validation_messages: List[ValidationMessage] = validate_file_within_document(file_input, get_document())

    expected = ValidationMessage(expected_message,
                                 ValidationContext(spdx_id=spdx_id,
                                                   parent_id=get_document().creation_info.spdx_id,
                                                   element_type=SpdxElementType.FILE,
                                                   full_element=file_input))

    assert validation_messages == [expected]

tests/validation/test_extracted_licensing_info_validator.py METASEP
#  Copyright (c) 2022 spdx contributors
#  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.

from typing import List

import pytest

from src.model.extracted_licensing_info import ExtractedLicensingInfo
from src.validation.extracted_licensing_info_validator import validate_extracted_licensing_info
from src.validation.validation_message import ValidationMessage, ValidationContext, SpdxElementType
from tests.valid_defaults import get_extracted_licensing_info


def test_valid_extracted_licensing_info():
    extracted_licensing_info = ExtractedLicensingInfo("LicenseRef-1", "extracted text", "license name",
                                                      ["http://some.url"], "comment")
    validation_messages: List[ValidationMessage] = validate_extracted_licensing_info(extracted_licensing_info)

    assert validation_messages == []


# TODO: tests for licenses not on the SPDX License list (i.e. they must provide id, name and cross-references)
@pytest.mark.parametrize("extracted_licensing_info, expected_message",
                         [(get_extracted_licensing_info(extracted_text=None),
                           'extracted_text must be provided if there is a license_id assigned'),
                          (get_extracted_licensing_info(cross_references=["invalid_url"]),
                           'cross_reference must be a valid URL, but is: invalid_url')
                          ])
def test_invalid_extracted_licensing_info(extracted_licensing_info, expected_message):
    validation_messages: List[ValidationMessage] = validate_extracted_licensing_info(extracted_licensing_info)

    expected = ValidationMessage(expected_message,
                                 ValidationContext(element_type=SpdxElementType.EXTRACTED_LICENSING_INFO,
                                                   full_element=extracted_licensing_info))

    assert validation_messages == [expected]

tests/validation/test_external_package_ref_validator.py METASEP
#  Copyright (c) 2022 spdx contributors
#  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.

from typing import List

import pytest

from src.model.package import ExternalPackageRef, ExternalPackageRefCategory
from src.validation.external_package_ref_validator import validate_external_package_ref
from src.validation.validation_message import ValidationMessage, ValidationContext, SpdxElementType
from tests.valid_defaults import get_external_package_ref


def test_valid_external_package_ref():

    external_package_ref = ExternalPackageRef(ExternalPackageRefCategory.OTHER, "swh",
                                              "swh:1:cnt:94a9ed024d3859793618152ea559a168bbcbb5e2", "comment")
    validation_messages: List[ValidationMessage] = validate_external_package_ref(external_package_ref, "parent_id")

    assert validation_messages == []


@pytest.mark.parametrize("external_package_ref, expected_message",
                         [(get_external_package_ref(),
                           "TBD"),
                          ])
@pytest.mark.skip("add tests once external package ref validation is implemented: https://github.com/spdx/tools-python/issues/373")
def test_invalid_external_package_ref(external_package_ref, expected_message):
    parent_id = "SPDXRef-Package"
    validation_messages: List[ValidationMessage] = validate_external_package_ref(external_package_ref, parent_id)

    expected = ValidationMessage(expected_message,
                                 ValidationContext(parent_id=parent_id,
                                                   element_type=SpdxElementType.EXTERNAL_PACKAGE_REF,
                                                   full_element=external_package_ref))

    assert validation_messages == [expected]

tests/validation/test_external_document_ref_validator.py METASEP
#  Copyright (c) 2022 spdx contributors
#  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.

from typing import List

import pytest

from src.model.external_document_ref import ExternalDocumentRef
from src.validation.external_document_ref_validator import validate_external_document_ref
from src.validation.validation_message import ValidationMessage, ValidationContext, SpdxElementType
from tests.valid_defaults import get_checksum, get_external_document_ref


def test_valid_external_document_ref():

    external_document_ref = ExternalDocumentRef("DocumentRef-id", "http://some.uri", get_checksum())
    validation_messages: List[ValidationMessage] = validate_external_document_ref(external_document_ref, "parent_id")

    assert validation_messages == []

tests/validation/test_document_validator.py METASEP
#  Copyright (c) 2022 spdx contributors
#  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.

from typing import List

from src.model.document import Document
from src.validation.document_validator import validate_full_spdx_document
from src.validation.validation_message import ValidationMessage
from tests.valid_defaults import get_creation_info, get_package, get_file, get_snippet, get_annotation, \
    get_relationship, get_extracted_licensing_info


def test_valid_document():
    document = Document(get_creation_info(), [get_package(), get_package()], [get_file(), get_file()],
                        [get_snippet(), get_snippet()], [get_annotation(), get_annotation()],
                        [get_relationship(), get_relationship()],
                        [get_extracted_licensing_info(), get_extracted_licensing_info()])
    validation_messages: List[ValidationMessage] = validate_full_spdx_document(document, "2.3")

    assert validation_messages == []

# TODO: https://github.com/spdx/tools-python/issues/375

tests/validation/test_creation_info_validator.py METASEP
#  Copyright (c) 2022 spdx contributors
#  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.

from datetime import datetime
from typing import List

import pytest

from src.model.document import CreationInfo
from src.model.version import Version
from src.validation.creation_info_validator import validate_creation_info
from src.validation.validation_message import ValidationMessage, ValidationContext, SpdxElementType
from tests.valid_defaults import get_actor, get_external_document_ref, get_creation_info


def test_valid_creation_info():
    creation_info = CreationInfo("SPDX-2.3", "SPDXRef-DOCUMENT", "document name", "https://some.uri",
                                 [get_actor(), get_actor()], datetime(2022, 1, 1), "creator_comment",
                                 "CC0-1.0", [get_external_document_ref(), get_external_document_ref()], Version(6, 3),
                                 "doc_comment")
    validation_messages: List[ValidationMessage] = validate_creation_info(creation_info)

    assert validation_messages == []


@pytest.mark.parametrize \
        ("creation_info_input, spdx_id, expected_message",
         [(get_creation_info(spdx_version="version-2.3"), "SPDXRef-DOCUMENT",
           'spdx_version must be of the form "SPDX-[major].[minor]" but is: version-2.3'),
          (get_creation_info(spdx_id="SPDXRef-doc"), "SPDXRef-doc",
           'spdx_id must be "SPDXRef-DOCUMENT", but is: SPDXRef-doc'),
          (get_creation_info(data_license="MIT"), "SPDXRef-DOCUMENT",
           'data_license must be "CC0-1.0", but is: MIT'),
          (get_creation_info(document_namespace="some_namespace"), "SPDXRef-DOCUMENT",
           "document_namespace must be a valid URI specified in RFC-3986, but is: some_namespace"),
          ])
def test_invalid_creation_info(creation_info_input, expected_message, spdx_id):
    validation_messages: List[ValidationMessage] = validate_creation_info(creation_info_input)

    expected = ValidationMessage(expected_message, ValidationContext(spdx_id, None, SpdxElementType.DOCUMENT))

    assert validation_messages == [expected]

tests/validation/test_checksum_validator.py METASEP
#  Copyright (c) 2022 spdx contributors
#  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.

from typing import List

import pytest

from src.model.checksum import Checksum, ChecksumAlgorithm
from src.validation.checksum_validator import validate_checksum
from src.validation.validation_message import ValidationMessage, ValidationContext, SpdxElementType


@pytest.mark.parametrize("checksum",
                         [Checksum(ChecksumAlgorithm.SHA1, "71c4025dd9897b364f3ebbb42c484ff43d00791c"),
                          Checksum(ChecksumAlgorithm.SHA224,
                                   "9c9f4e27d957a123cc32d86afe33ae53b1184192cccb23b0f257f588"),
                          Checksum(ChecksumAlgorithm.SHA256,
                                   "fbea580d286bbbbb41314430d58ba887716a74d7134119c5307cdc9f0c7a4299"),
                          Checksum(ChecksumAlgorithm.SHA384,
                                   "73b4ad9a34e5f76cb2525ea6bb8b1dcf9ba79426b3295bd18bc6d148cba4fcc2ca3cf2630fd481b47caaac9127103933"),
                          Checksum(ChecksumAlgorithm.SHA512,
                                   "c2aa8a5d297f5e888ce9a30d3745ccc5a628533449a9f98524de3d23695a268f394a67faf8ef370727c2946f1dbbec34aeb7ac10f15af43e7cb5547f1a464053"),
                          Checksum(ChecksumAlgorithm.SHA3_256,
                                   "1e772489c042f49aeaae32b00fc5ef170a25afa741cffaafadde597d4d1727ce"),
                          Checksum(ChecksumAlgorithm.SHA3_384,
                                   "dd9e30747551865b483bd76bd967384dce0e5670d1b1c3f701cffac7f49b1c46791253493835136b3aa5f679e364c166"),
                          Checksum(ChecksumAlgorithm.SHA3_512,
                                   "906bca5580be8c95ae44f775363fb69968ad568898dfb03e0ff96cd9445a0b75f817b68e5c1e80ad624031f851cfddd3a101e1d111310266a5d46e2bc1ffbb36"),
                          Checksum(ChecksumAlgorithm.BLAKE2B_256,
                                   "a0eb3ddfa5807780a562b9c313b2537f1e8dc621e9a524f8c1ffcf07a79e35c7"),
                          Checksum(ChecksumAlgorithm.BLAKE2B_384,
                                   "902511afc8939c0193d87857f45a19eddfd7e0413b0f8701a3baaf1b025f882b45a8fbf623fa0ad79b64850ac7a4d0b2"),
                          Checksum(ChecksumAlgorithm.BLAKE2B_512,
                                   "72c23b0160e1af3cb159f0cc96210c5e9aecc5a65d4618566776fa6117bf84929dcef56c7f8b087691c23000c945470842d90b5e8c4af74dce531ca8ebd8824c"),
                          Checksum(ChecksumAlgorithm.BLAKE3,
                                   "a872cac2efd29ed2ad8b5faa79b63f983341bea41183582b8863d952f6ac3e1cdfe0189967a13006857d3b9985174bf67239874dcec4cbbc9839496179feafeda872cac2efd29ed2ad8b5faa79b63f983341bea41183582b8863d952f6ac3e1cdfe0189967a13006857d3b9985174bf67239874dcec4cbbc9839496179feafed"),
                          Checksum(ChecksumAlgorithm.MD2, "af1eec2a1b18886c3f3cc244349d91d8"),
                          Checksum(ChecksumAlgorithm.MD4, "d4c41ce30a517d6ce9d79c8c17bb4b66"),
                          Checksum(ChecksumAlgorithm.MD5, "0d7f61beb7018b3924c6b8f96549fa39"),
                          Checksum(ChecksumAlgorithm.MD6,
                                   "af1eec2a1b18886c3f3cc244349d91d8d4c41ce30a517d6ce9d79c8c17bb4b660d7f61beb7018b3924c6b8f96549fa39"),
                          Checksum(ChecksumAlgorithm.ADLER32, "02ec0130")])
def test_valid_checksum(checksum):
    validation_messages: List[ValidationMessage] = validate_checksum(checksum, "parent_id")

    assert validation_messages == []


@pytest.mark.parametrize("checksum, expected_message",
                         [(Checksum(ChecksumAlgorithm.SHA1, "af1eec2a1b18886c3f3cc244349d91d8"),
                           "value of ChecksumAlgorithm.SHA1 must consist of 40 hexadecimal digits, but is: af1eec2a1b18886c3f3cc244349d91d8 (length: 32 digits)"),
                          (Checksum(ChecksumAlgorithm.SHA224, "af1eec2a1b18886c3f3cc244349d91d8"),
                           "value of ChecksumAlgorithm.SHA224 must consist of 56 hexadecimal digits, but is: af1eec2a1b18886c3f3cc244349d91d8 (length: 32 digits)"),
                          (Checksum(ChecksumAlgorithm.SHA256, "af1eec2a1b18886c3f3cc244349d91d8"),
                           "value of ChecksumAlgorithm.SHA256 must consist of 64 hexadecimal digits, but is: af1eec2a1b18886c3f3cc244349d91d8 (length: 32 digits)"),
                          (Checksum(ChecksumAlgorithm.SHA384, "af1eec2a1b18886c3f3cc244349d91d8"),
                           "value of ChecksumAlgorithm.SHA384 must consist of 96 hexadecimal digits, but is: af1eec2a1b18886c3f3cc244349d91d8 (length: 32 digits)"),
                          (Checksum(ChecksumAlgorithm.SHA512, "af1eec2a1b18886c3f3cc244349d91d8"),
                           "value of ChecksumAlgorithm.SHA512 must consist of 128 hexadecimal digits, but is: af1eec2a1b18886c3f3cc244349d91d8 (length: 32 digits)"),
                          (Checksum(ChecksumAlgorithm.SHA3_256, "af1eec2a1b18886c3f3cc244349d91d8"),
                           "value of ChecksumAlgorithm.SHA3_256 must consist of 64 hexadecimal digits, but is: af1eec2a1b18886c3f3cc244349d91d8 (length: 32 digits)"),
                          (Checksum(ChecksumAlgorithm.SHA3_384, "af1eec2a1b18886c3f3cc244349d91d8"),
                           "value of ChecksumAlgorithm.SHA3_384 must consist of 96 hexadecimal digits, but is: af1eec2a1b18886c3f3cc244349d91d8 (length: 32 digits)"),
                          (Checksum(ChecksumAlgorithm.SHA3_512, "af1eec2a1b18886c3f3cc244349d91d8"),
                           "value of ChecksumAlgorithm.SHA3_512 must consist of 128 hexadecimal digits, but is: af1eec2a1b18886c3f3cc244349d91d8 (length: 32 digits)"),
                          (Checksum(ChecksumAlgorithm.BLAKE2B_256, "af1eec2a1b18886c3f3cc244349d91d8"),
                           "value of ChecksumAlgorithm.BLAKE2B_256 must consist of 64 hexadecimal digits, but is: af1eec2a1b18886c3f3cc244349d91d8 (length: 32 digits)"),
                          (Checksum(ChecksumAlgorithm.BLAKE2B_384, "af1eec2a1b18886c3f3cc244349d91d8"),
                           "value of ChecksumAlgorithm.BLAKE2B_384 must consist of 96 hexadecimal digits, but is: af1eec2a1b18886c3f3cc244349d91d8 (length: 32 digits)"),
                          (Checksum(ChecksumAlgorithm.BLAKE2B_512, "af1eec2a1b18886c3f3cc244349d91d8"),
                           "value of ChecksumAlgorithm.BLAKE2B_512 must consist of 128 hexadecimal digits, but is: af1eec2a1b18886c3f3cc244349d91d8 (length: 32 digits)"),
                          (Checksum(ChecksumAlgorithm.BLAKE3, "af1eec2a1b18886c3f3cc244349d91d8"),
                           "value of ChecksumAlgorithm.BLAKE3 must consist of at least 256 hexadecimal digits, but is: af1eec2a1b18886c3f3cc244349d91d8 (length: 32 digits)"),
                          (Checksum(ChecksumAlgorithm.MD2, "71c4025dd9897b364f3ebbb42c484ff43d00791c"),
                           "value of ChecksumAlgorithm.MD2 must consist of 32 hexadecimal digits, but is: 71c4025dd9897b364f3ebbb42c484ff43d00791c (length: 40 digits)"),
                          (Checksum(ChecksumAlgorithm.MD4, "71c4025dd9897b364f3ebbb42c484ff43d00791c"),
                           "value of ChecksumAlgorithm.MD4 must consist of 32 hexadecimal digits, but is: 71c4025dd9897b364f3ebbb42c484ff43d00791c (length: 40 digits)"),
                          (Checksum(ChecksumAlgorithm.MD5, "71c4025dd9897b364f3ebbb42c484ff43d00791c"),
                           "value of ChecksumAlgorithm.MD5 must consist of 32 hexadecimal digits, but is: 71c4025dd9897b364f3ebbb42c484ff43d00791c (length: 40 digits)"),
                          (Checksum(ChecksumAlgorithm.MD6,
                                    "a872cac2efd29ed2ad8b5faa79b63f983341bea41183582b8863d952f6ac3e1cdfe0189967a13006857d3b9985174bf67239874dcec4cbbc9839496179feafeda872cac2efd29ed2ad8b5faa79b63f983341bea41183582b8863d952f6ac3e1cdfe0189967a13006857d3b9985174bf67239874dcec4cbbc9839496179feafeda872cac2efd29ed2ad8b5faa79b63f983341bea41183582b8863d952f6ac3e1cdfe0189967a13006857d3b9985174bf67239874dcec4cbbc9839496179feafeda872cac2efd29ed2ad8b5faa79b63f983341bea41183582b8863d952f6ac3e1cdfe0189967a13006857d3b9985174bf67239874dcec4cbbc9839496179feafed5"),
                           "value of ChecksumAlgorithm.MD6 must consist of between 0 and 512 hexadecimal digits, but is: a872cac2efd29ed2ad8b5faa79b63f983341bea41183582b8863d952f6ac3e1cdfe0189967a13006857d3b9985174bf67239874dcec4cbbc9839496179feafeda872cac2efd29ed2ad8b5faa79b63f983341bea41183582b8863d952f6ac3e1cdfe0189967a13006857d3b9985174bf67239874dcec4cbbc9839496179feafeda872cac2efd29ed2ad8b5faa79b63f983341bea41183582b8863d952f6ac3e1cdfe0189967a13006857d3b9985174bf67239874dcec4cbbc9839496179feafeda872cac2efd29ed2ad8b5faa79b63f983341bea41183582b8863d952f6ac3e1cdfe0189967a13006857d3b9985174bf67239874dcec4cbbc9839496179feafed5 (length: 513 digits)"),
                          (Checksum(ChecksumAlgorithm.ADLER32, "af1eec2a1b18886c3f3cc244349d91d8"),
                           "value of ChecksumAlgorithm.ADLER32 must consist of 8 hexadecimal digits, but is: af1eec2a1b18886c3f3cc244349d91d8 (length: 32 digits)"),
                          ])
def test_invalid_checksum(checksum, expected_message):
    parent_id = "parent_id"
    validation_messages: List[ValidationMessage] = validate_checksum(checksum, parent_id)

    expected = ValidationMessage(expected_message,
                                 ValidationContext(parent_id=parent_id, element_type=SpdxElementType.CHECKSUM,
                                                   full_element=checksum))

    assert validation_messages == [expected]

tests/validation/test_annotation_validator.py METASEP
#  Copyright (c) 2022 spdx contributors
#  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.

from datetime import datetime
from typing import List

import pytest

from src.model.annotation import Annotation, AnnotationType
from src.model.document import Document
from src.validation.annotation_validator import validate_annotation
from src.validation.validation_message import ValidationMessage, ValidationContext, SpdxElementType
from tests.valid_defaults import get_actor, get_annotation, get_document, get_file


def test_valid_annotation():
    document: Document = get_document(files=[get_file(spdx_id="SPDXRef-File")])

    annotation = Annotation("SPDXRef-File", AnnotationType.OTHER, get_actor(), datetime(2022, 1, 1), "comment")
    validation_messages: List[ValidationMessage] = validate_annotation(annotation, document)

    assert validation_messages == []


@pytest.mark.parametrize("annotation_id, file_id, expected_message",
                         [("SPDXRef-File", "SPDXRef-hiddenFile",
                           "did not find the referenced spdx_id SPDXRef-File in the SPDX document")
                          ])
def test_invalid_annotation(annotation_id, file_id, expected_message):
    annotation: Annotation = get_annotation(spdx_id=annotation_id)
    document: Document = get_document(files=[get_file(spdx_id=file_id)])
    validation_messages: List[ValidationMessage] = validate_annotation(annotation, document)

    expected = ValidationMessage(expected_message,
                                 ValidationContext(element_type=SpdxElementType.ANNOTATION,
                                                   full_element=annotation))

    assert validation_messages == [expected]

tests/validation/test_actor_validator.py METASEP
#  Copyright (c) 2022 spdx contributors
#  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.

from typing import List

import pytest

from src.model.actor import ActorType, Actor
from src.validation.actor_validator import validate_actor
from src.validation.validation_message import ValidationMessage, ValidationContext, SpdxElementType
from tests.valid_defaults import get_actor


def test_valid_actor_person():
    actor = Actor(ActorType.PERSON, "person name", "mail@mail.com")
    validation_messages: List[ValidationMessage] = validate_actor(actor, "SPDXRef-DOCUMENT")

    assert validation_messages == []


@pytest.mark.parametrize("actor, expected_message",
                         [(get_actor(actor_type=ActorType.TOOL, mail="mail@mail.com"),
                           "email must be None if actor_type is TOOL, but is: mail@mail.com"),
                          ])
def test_invalid_actor(actor, expected_message):
    parent_id = "SPDXRef-DOCUMENT"
    validation_messages: List[ValidationMessage] = validate_actor(actor, parent_id)

    expected = ValidationMessage(expected_message,
                                 ValidationContext(parent_id=parent_id, element_type=SpdxElementType.ACTOR,
                                                   full_element=actor))

    assert validation_messages == [expected]

tests/validation/__init__.py METASEP

tests/model/test_version.py METASEP
# Copyright (c) 2022 spdx contributors
# 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.


import pytest

from src.model.version import Version


@pytest.mark.parametrize("input_string,expected", [("1.2", Version(1, 2)), ("12.345", Version(12, 345))])
def test_version_from_string(input_string, expected):
    assert Version.is_valid_version_string(input_string)
    version: Version = Version.from_string(input_string)
    assert version == expected


@pytest.mark.parametrize("input_string", ["1", "1-2", "1.a", "a", "a.b", "a.1", "v1.2", "1.2v"])
def test_invalid_version_string(input_string):
    assert not Version.is_valid_version_string(input_string)
    with pytest.raises(ValueError) as error:
        Version.from_string(input_string)
    assert str(error.value) == f"{input_string} is not a valid version string"

tests/model/test_snippet.py METASEP
import pytest

from src.model.snippet import Snippet
from src.model.spdx_no_assertion import SpdxNoAssertion
from src.model.spdx_none import SpdxNone


def test_correct_initialization():
    snippet = Snippet("id", "file_id", (200, 400), (20, 40), SpdxNone(), SpdxNoAssertion(), "comment on license",
                      "copyright", "comment", "name", ["attribution"])
    assert snippet.spdx_id == "id"
    assert snippet.file_spdx_id == "file_id"
    assert snippet.byte_range == (200, 400)
    assert snippet.line_range == (20, 40)
    assert snippet.concluded_license == SpdxNone()
    assert snippet.license_info_in_snippet == SpdxNoAssertion()
    assert snippet.license_comment == "comment on license"
    assert snippet.copyright_text == "copyright"
    assert snippet.comment == "comment"
    assert snippet.name == "name"
    assert snippet.attribution_texts == ["attribution"]


def test_correct_initialization_with_default_values():
    snippet = Snippet("id", "file_id", (200, 400))
    assert snippet.spdx_id == "id"
    assert snippet.file_spdx_id == "file_id"
    assert snippet.byte_range == (200, 400)
    assert snippet.line_range is None
    assert snippet.concluded_license is None
    assert snippet.license_info_in_snippet is None
    assert snippet.license_comment is None
    assert snippet.copyright_text is None
    assert snippet.comment is None
    assert snippet.name is None
    assert snippet.attribution_texts == []


def test_wrong_type_in_spdx_id():
    with pytest.raises(TypeError):
        Snippet(42, "file_id", (200, 400))


def test_wrong_type_in_file_spdx_id():
    with pytest.raises(TypeError):
        Snippet("id", 42, (200, 400))


def test_wrong_type_in_byte_range():
    with pytest.raises(TypeError):
        Snippet("id", "file_id", (200, 300, 400))


def test_wrong_type_in_line_range():
    with pytest.raises(TypeError):
        Snippet("id", "file_id", (200, 400), line_range=(20, "40"))


def test_wrong_type_in_concluded_license():
    with pytest.raises(TypeError):
        Snippet("id", "file_id", (200, 400), concluded_license="NONE")


def test_wrong_type_in_license_info_in_snippet():
    with pytest.raises(TypeError):
        Snippet("id", "file_id", (200, 400), license_info_in_snippet=[SpdxNoAssertion()])


def test_wrong_type_in_license_comment():
    with pytest.raises(TypeError):
        Snippet("id", "file_id", (200, 400), license_comment=[])


def test_wrong_type_in_copyright_text():
    with pytest.raises(TypeError):
        Snippet("id", "file_id", (200, 400), copyright_text=["copyright"])


def test_wrong_type_in_comment():
    with pytest.raises(TypeError):
        Snippet("id", "file_id", (200, 400), comment=["comment"])


def test_wrong_type_in_name():
    with pytest.raises(TypeError):
        Snippet("id", "file_id", (200, 400), name=42)


def test_wrong_type_in_attribution_texts():
    with pytest.raises(TypeError):
        Snippet("id", "file_id", (200, 400), attribution_texts="attribution")

tests/model/test_relationship.py METASEP
import pytest

from src.model.relationship import Relationship, RelationshipType


def test_correct_initialization():
    relationship = Relationship("id", RelationshipType.OTHER, "other_id", "comment")
    assert relationship.spdx_element_id == "id"
    assert relationship.relationship_type == RelationshipType.OTHER
    assert relationship.related_spdx_element_id == "other_id"
    assert relationship.comment == "comment"


def test_wrong_type_in_spdx_element_id():
    with pytest.raises(TypeError):
        Relationship(42, RelationshipType.OTHER, "other_id")


def test_wrong_type_in_relationship_type():
    with pytest.raises(TypeError):
        Relationship("id", 42, "other_id")


def test_wrong_type_in_related_spdx_element_id():
    with pytest.raises(TypeError):
        Relationship("id", RelationshipType.OTHER, 42)


def test_wrong_type_in_comment():
    with pytest.raises(TypeError):
        Relationship("id", RelationshipType.OTHER, "other_id", 42)

tests/model/test_package_verification_code.py METASEP
import pytest

from src.model.package import PackageVerificationCode


def test_correct_initialization():
    package_verification_code = PackageVerificationCode("value", ["file1", "file2"])
    assert package_verification_code.value == "value"
    assert package_verification_code.excluded_files == ["file1", "file2"]


def test_wrong_type_in_value():
    with pytest.raises(TypeError):
        PackageVerificationCode(42, ["file1", "file2"])


def test_wrong_type_in_excluded_files():
    with pytest.raises(TypeError):
        PackageVerificationCode("value", "file1")

tests/model/test_package.py METASEP
from datetime import datetime
from unittest import mock

import pytest

from src.model.checksum import Checksum, ChecksumAlgorithm
from src.model.license_expression import LicenseExpression
from src.model.package import Package, PackagePurpose
from src.model.spdx_no_assertion import SpdxNoAssertion
from src.model.spdx_none import SpdxNone


@mock.patch('src.model.actor.Actor', autospec=True)
@mock.patch('src.model.package.PackageVerificationCode', autospec=True)
@mock.patch('src.model.checksum.Checksum', autospec=True)
@mock.patch('src.model.package.ExternalPackageRef', autospec=True)
def test_correct_initialization(actor, verif_code, checksum, ext_ref):
    package = Package("id", "name", SpdxNoAssertion(), "version", "file_name", SpdxNoAssertion(), actor, True,
                      verif_code, [checksum], "homepage", "source_info", None, [LicenseExpression("expression")],
                      SpdxNone(), "comment on license", "copyright", "summary", "description", "comment",
                      [ext_ref, ext_ref], ["text"], PackagePurpose.OTHER, datetime(2022, 1, 1), None, None)
    assert package.spdx_id == "id"
    assert package.name == "name"
    assert package.download_location == SpdxNoAssertion()
    assert package.version == "version"
    assert package.file_name == "file_name"
    assert package.supplier == SpdxNoAssertion()
    assert package.originator == actor
    assert package.files_analyzed
    assert package.verification_code == verif_code
    assert package.checksums == [checksum]
    assert package.homepage == "homepage"
    assert package.source_info == "source_info"
    assert package.license_concluded is None
    assert package.license_info_from_files == [LicenseExpression("expression")]
    assert package.license_declared == SpdxNone()
    assert package.license_comment == "comment on license"
    assert package.copyright_text == "copyright"
    assert package.summary == "summary"
    assert package.description == "description"
    assert package.comment == "comment"
    assert package.external_references == [ext_ref, ext_ref]
    assert package.attribution_texts == ["text"]
    assert package.primary_package_purpose == PackagePurpose.OTHER
    assert package.release_date == datetime(2022, 1, 1)
    assert package.built_date is None
    assert package.valid_until_date is None


def test_correct_initialization_with_default_values():
    package = Package("id", "name", "location")
    assert package.spdx_id == "id"
    assert package.name == "name"
    assert package.download_location == "location"
    assert package.version is None
    assert package.file_name is None
    assert package.supplier is None
    assert package.originator is None
    assert package.files_analyzed
    assert package.verification_code is None
    assert package.checksums == []
    assert package.homepage is None
    assert package.source_info is None
    assert package.license_concluded is None
    assert package.license_info_from_files == []
    assert package.license_declared is None
    assert package.license_comment is None
    assert package.copyright_text is None
    assert package.summary is None
    assert package.description is None
    assert package.comment is None
    assert package.external_references == []
    assert package.attribution_texts == []
    assert package.primary_package_purpose is None
    assert package.release_date is None
    assert package.built_date is None
    assert package.valid_until_date is None


def test_wrong_type_in_spdx_id():
    with pytest.raises(TypeError):
        Package(42, "name", "location")


def test_wrong_type_in_name():
    with pytest.raises(TypeError):
        Package("id", 42, "location")


def test_wrong_type_in_download_location():
    with pytest.raises(TypeError):
        Package("id", "name", 42)


def test_wrong_type_in_version():
    with pytest.raises(TypeError):
        Package("id", "name", "location", version=42)


def test_wrong_type_in_file_name():
    with pytest.raises(TypeError):
        Package("id", "name", "location", file_name=42)


def test_wrong_type_in_supplier():
    with pytest.raises(TypeError):
        Package("id", "name", "location", supplier=SpdxNone())


def test_wrong_type_in_originator():
    with pytest.raises(TypeError):
        Package("id", "name", "location", originator=SpdxNone())


def test_wrong_type_in_files_analyzed():
    with pytest.raises(TypeError):
        Package("id", "name", "location", files_analyzed=None)


def test_wrong_type_in_verification_code():
    with pytest.raises(TypeError):
        Package("id", "name", "location", verification_code=[])


def test_wrong_type_in_checksums():
    with pytest.raises(TypeError):
        Package("id", "name", "location", checksums=Checksum(ChecksumAlgorithm.MD2, "value"))


def test_wrong_type_in_homepage():
    with pytest.raises(TypeError):
        Package("id", "name", "location", homepage=42)


def test_wrong_type_in_source_info():
    with pytest.raises(TypeError):
        Package("id", "name", "location", source_info=42)


def test_wrong_type_in_license_concluded():
    with pytest.raises(TypeError):
        Package("id", "name", "location", license_concluded=[])


def test_wrong_type_in_license_info_from_files():
    with pytest.raises(TypeError):
        Package("id", "name", "location", license_info_from_files=LicenseExpression("string"))


def test_wrong_type_in_license_declared():
    with pytest.raises(TypeError):
        Package("id", "name", "location", license_declared=[])


def test_wrong_type_in_license_comment():
    with pytest.raises(TypeError):
        Package("id", "name", "location", license_comment=42)


def test_wrong_type_in_copyright_text():
    with pytest.raises(TypeError):
        Package("id", "name", "location", copyright_text=42)


def test_wrong_type_in_summary():
    with pytest.raises(TypeError):
        Package("id", "name", "location", summary=42)


def test_wrong_type_in_description():
    with pytest.raises(TypeError):
        Package("id", "name", "location", description=42)


def test_wrong_type_in_comment():
    with pytest.raises(TypeError):
        Package("id", "name", "location", comment=[])


def test_wrong_type_in_external_references():
    with pytest.raises(TypeError):
        Package("id", "name", "location", external_references=["external_ref"])


def test_wrong_type_in_attribution_texts():
    with pytest.raises(TypeError):
        Package("id", "name", "location", attribution_texts="text")


def test_wrong_type_in_primary_package_purpose():
    with pytest.raises(TypeError):
        Package("id", "name", "location", primary_package_purpose=[])


def test_wrong_type_in_release_date():
    with pytest.raises(TypeError):
        Package("id", "name", "location", release_date=42)


def test_wrong_type_in_built_date():
    with pytest.raises(TypeError):
        Package("id", "name", "location", built_date="2022-01-01")


def test_wrong_type_in_valid_until_date():
    with pytest.raises(TypeError):
        Package("id", "name", "location", valid_until_date=SpdxNone())

tests/model/test_license.py METASEP
# Copyright (c) 2022 spdx contributors
# 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.


import pytest

from src.model.license import determine_full_name, determine_identifier


@pytest.mark.parametrize("identifier,full_name,expected",
                         [("0BSD", "full_name", "full_name"), (None, "full_name", "full_name"),
                          (None, "BSD Zero Clause License", "BSD Zero Clause License"),
                          ("0BSD", None, "BSD Zero Clause License"), ("identifier", None, "identifier")])
def test_determine_full_name(identifier, full_name, expected):
    assert determine_full_name(identifier, full_name) == expected


@pytest.mark.parametrize("identifier,full_name,expected",
                         [("identifier", "BSD Zero Clause License", "identifier"), (None, "full_name", "full_name"),
                          (None, "BSD Zero Clause License", "0BSD"), ("0BSD", None, "0BSD"),
                          ("identifier", None, "identifier")])
def test_determine_identifier(identifier, full_name, expected):
    assert determine_identifier(identifier, full_name) == expected

tests/model/test_file.py METASEP
from unittest import mock

import pytest

from src.model.checksum import Checksum, ChecksumAlgorithm
from src.model.file import File, FileType
from src.model.spdx_no_assertion import SpdxNoAssertion
from src.model.spdx_none import SpdxNone


@mock.patch('src.model.checksum.Checksum', autospec=True)
def test_correct_initialization(checksum):
    file = File("name", "id", [checksum, checksum], [FileType.OTHER, FileType.SPDX], SpdxNone(), SpdxNoAssertion(),
                "comment on license", "copyright", "comment", "notice", ["contributor"], ["attribution"])
    assert file.name == "name"
    assert file.spdx_id == "id"
    assert file.checksums == [checksum, checksum]
    assert file.file_type == [FileType.OTHER, FileType.SPDX]
    assert file.concluded_license == SpdxNone()
    assert file.license_info_in_file == SpdxNoAssertion()
    assert file.license_comment == "comment on license"
    assert file.copyright_text == "copyright"
    assert file.comment == "comment"
    assert file.notice == "notice"
    assert file.contributors == ["contributor"]
    assert file.attribution_texts == ["attribution"]


@mock.patch('src.model.checksum.Checksum', autospec=True)
def test_correct_initialization_with_default_values(checksum):
    file = File("name", "id", [checksum, checksum])
    assert file.name == "name"
    assert file.spdx_id == "id"
    assert file.checksums == [checksum, checksum]
    assert file.file_type == []
    assert file.concluded_license is None
    assert file.license_info_in_file == []
    assert file.license_comment is None
    assert file.copyright_text is None
    assert file.comment is None
    assert file.notice is None
    assert file.contributors == []
    assert file.attribution_texts == []


@mock.patch('src.model.checksum.Checksum', autospec=True)
def test_wrong_type_in_name(checksum):
    with pytest.raises(TypeError):
        File(42, "id", [checksum])


@mock.patch('src.model.checksum.Checksum', autospec=True)
def test_wrong_type_in_spdx_id(checksum):
    with pytest.raises(TypeError):
        File("name", 42, [checksum])


def test_wrong_type_in_checksum():
    checksum = Checksum(ChecksumAlgorithm.BLAKE2B_256, "value")
    with pytest.raises(TypeError):
        File("name", "id", checksum)


@mock.patch('src.model.checksum.Checksum', autospec=True)
def test_wrong_type_in_file_type(checksum):
    with pytest.raises(TypeError):
        File("name", "id", [checksum], file_type=FileType.OTHER)


@mock.patch('src.model.checksum.Checksum', autospec=True)
def test_wrong_type_in_concluded_license(checksum):
    with pytest.raises(TypeError):
        File("name", "id", [checksum], concluded_license="NONE")


@mock.patch('src.model.checksum.Checksum', autospec=True)
def test_wrong_type_in_license_info_in_file(checksum):
    with pytest.raises(TypeError):
        File("name", "id", [checksum], license_info_in_file=[SpdxNone])


@mock.patch('src.model.checksum.Checksum', autospec=True)
def test_wrong_type_in_license_comment(checksum):
    with pytest.raises(TypeError):
        File("name", "id", [checksum], license_comment=42)


@mock.patch('src.model.checksum.Checksum', autospec=True)
def test_wrong_type_in_copyright_text(checksum):
    with pytest.raises(TypeError):
        File("name", "id", [checksum], copyright_text=[SpdxNone()])


@mock.patch('src.model.checksum.Checksum', autospec=True)
def test_wrong_type_in_comment(checksum):
    with pytest.raises(TypeError):
        File("name", "id", [checksum], comment=42)


@mock.patch('src.model.checksum.Checksum', autospec=True)
def test_wrong_type_in_notice(checksum):
    with pytest.raises(TypeError):
        File("name", "id", [checksum], notice=["notice"])


@mock.patch('src.model.checksum.Checksum', autospec=True)
def test_wrong_type_in_contributors(checksum):
    with pytest.raises(TypeError):
        File("name", "id", [checksum], contributors="contributor")


@mock.patch('src.model.checksum.Checksum', autospec=True)
def test_wrong_type_in_attribution_texts(checksum):
    with pytest.raises(TypeError):
        File("name", "id", [checksum], attribution_texts=["attribution", 42])

tests/model/test_extracted_licensing_info.py METASEP
import pytest

from src.model.extracted_licensing_info import ExtractedLicensingInfo


def test_correct_initialization():
    extracted_licensing_info = ExtractedLicensingInfo("id", "text", "name", ["reference"], "comment")
    assert extracted_licensing_info.license_id == "id"
    assert extracted_licensing_info.extracted_text == "text"
    assert extracted_licensing_info.license_name == "name"
    assert extracted_licensing_info.cross_references == ["reference"]
    assert extracted_licensing_info.comment == "comment"


def test_wrong_type_in_license_id():
    with pytest.raises(TypeError):
        ExtractedLicensingInfo(license_id=42)


def test_wrong_type_in_extracted_text():
    with pytest.raises(TypeError):
        ExtractedLicensingInfo(extracted_text=42)


def test_wrong_type_in_license_name():
    with pytest.raises(TypeError):
        ExtractedLicensingInfo(license_name=42)


def test_wrong_type_in_cross_references():
    with pytest.raises(TypeError):
        ExtractedLicensingInfo(cross_references=["ref", 42])


def test_wrong_type_in_comment():
    with pytest.raises(TypeError):
        ExtractedLicensingInfo(comment=42)

tests/model/test_external_package_reference.py METASEP
import pytest

from src.model.package import ExternalPackageRef, ExternalPackageRefCategory


def test_correct_initialization():
    external_package_reference = ExternalPackageRef(ExternalPackageRefCategory.OTHER, "type", "locator",
                                                          "comment")
    assert external_package_reference.category == ExternalPackageRefCategory.OTHER
    assert external_package_reference.reference_type == "type"
    assert external_package_reference.locator == "locator"
    assert external_package_reference.comment == "comment"


def test_wrong_type_in_category():
    with pytest.raises(TypeError):
        ExternalPackageRef([ExternalPackageRefCategory.OTHER], "type", "locator")


def test_wrong_type_in_reference_type():
    with pytest.raises(TypeError):
        ExternalPackageRef(ExternalPackageRefCategory.OTHER, 42, "locator")


def test_wrong_type_in_locator():
    with pytest.raises(TypeError):
        ExternalPackageRef(ExternalPackageRefCategory.OTHER, "type", 42)


def test_wrong_type_in_comment():
    with pytest.raises(TypeError):
        ExternalPackageRef(ExternalPackageRefCategory.OTHER, "type", "locator", [])

tests/model/test_external_document_ref.py METASEP
from unittest import mock

import pytest

from src.model.external_document_ref import ExternalDocumentRef


@mock.patch('src.model.checksum.Checksum', autospec=True)
def test_correct_initialization(checksum):
    external_document_ref = ExternalDocumentRef("id", "uri", checksum)
    assert external_document_ref.document_ref_id == "id"
    assert external_document_ref.document_uri == "uri"
    assert external_document_ref.checksum == checksum


@mock.patch('src.model.checksum.Checksum', autospec=True)
def test_wrong_type_in_spdx_id(checksum):
    with pytest.raises(TypeError):
        ExternalDocumentRef(42, "uri", checksum)


@mock.patch('src.model.checksum.Checksum', autospec=True)
def test_wrong_type_in_document_uri(checksum):
    with pytest.raises(TypeError):
        ExternalDocumentRef("id", 42, checksum)


def test_wrong_type_in_checksum():
    with pytest.raises(TypeError):
        ExternalDocumentRef("id", "uri", 42)

tests/model/test_document.py METASEP
from unittest import mock

import pytest

from src.model.document import Document


@mock.patch('src.model.document.CreationInfo', autospec=True)
@mock.patch('src.model.package.Package', autospec=True)
@mock.patch('src.model.file.File', autospec=True)
@mock.patch('src.model.snippet.Snippet', autospec=True)
@mock.patch('src.model.annotation.Annotation', autospec=True)
@mock.patch('src.model.relationship.Relationship', autospec=True)
@mock.patch('src.model.extracted_licensing_info.ExtractedLicensingInfo', autospec=True)
def test_correct_initialization(creation_info, package, file, snippet, annotation, relationship,
                                extracted_lic):
    document = Document(creation_info, [package, package], [file, file], [snippet, snippet], [annotation, annotation],
                        [relationship, relationship], [extracted_lic, extracted_lic])
    assert document.creation_info == creation_info
    assert document.packages == [package, package]
    assert document.files == [file, file]
    assert document.snippets == [snippet, snippet]
    assert document.annotations == [annotation, annotation]
    assert document.relationships == [relationship, relationship]
    assert document.extracted_licensing_info == [extracted_lic, extracted_lic]


@mock.patch('src.model.document.CreationInfo', autospec=True)
def test_correct_initialization_with_default_values(creation_info):
    document = Document(creation_info)
    assert document.creation_info == creation_info
    assert document.packages == []
    assert document.files == []
    assert document.snippets == []
    assert document.annotations == []
    assert document.relationships == []
    assert document.extracted_licensing_info == []


def test_wrong_type_in_creation_info():
    with pytest.raises(TypeError):
        Document("string")


@mock.patch('src.model.document.CreationInfo', autospec=True)
def test_wrong_type_in_packages(creation_info):
    with pytest.raises(TypeError):
        Document(creation_info, packages=["string"])


@mock.patch('src.model.document.CreationInfo', autospec=True)
def test_wrong_type_in_files(creation_info):
    with pytest.raises(TypeError):
        Document(creation_info, files={})


@mock.patch('src.model.document.CreationInfo', autospec=True)
def test_wrong_type_in_snippets(creation_info):
    with pytest.raises(TypeError):
        Document(creation_info, snippets=())


@mock.patch('src.model.document.CreationInfo', autospec=True)
def test_wrong_type_in_annotations(creation_info):
    with pytest.raises(TypeError):
        Document(creation_info, annotations=["string"])


@mock.patch('src.model.document.CreationInfo', autospec=True)
def test_wrong_type_in_relationships(creation_info):
    with pytest.raises(TypeError):
        Document(creation_info, relationships="string")


@mock.patch('src.model.document.CreationInfo', autospec=True)
def test_wrong_type_in_extracted_licensing_info(creation_info):
    with pytest.raises(TypeError):
        Document(creation_info, extracted_licensing_info=42)

tests/model/test_creation_info.py METASEP
from datetime import datetime
from unittest import mock

import pytest

from src.model.document import CreationInfo
from src.model.version import Version


@mock.patch('src.model.actor.Actor', autospec=True)
@mock.patch('src.model.external_document_ref.ExternalDocumentRef', autospec=True)
def test_correct_initialization(actor, ext_ref):
    creation_info = CreationInfo("version", "id", "name", "namespace", [actor, actor], datetime(2022, 1, 1),
                                 "creator_comment", "CC0-1.1", [ext_ref, ext_ref], Version(6, 3), "doc_comment")
    assert creation_info.spdx_version == "version"
    assert creation_info.spdx_id == "id"
    assert creation_info.name == "name"
    assert creation_info.document_namespace == "namespace"
    assert creation_info.creators == [actor, actor]
    assert creation_info.created == datetime(2022, 1, 1)
    assert creation_info.creator_comment == "creator_comment"
    assert creation_info.data_license == "CC0-1.1"
    assert creation_info.external_document_refs == [ext_ref, ext_ref]
    assert creation_info.license_list_version == Version(6, 3)
    assert creation_info.document_comment == "doc_comment"


@mock.patch('src.model.actor.Actor', autospec=True)
def test_wrong_type_in_spdx_version(actor):
    with pytest.raises(TypeError):
        CreationInfo(42, "id", "name", "namespace", [actor, actor], datetime(2022, 1, 1))


@mock.patch('src.model.actor.Actor', autospec=True)
def test_wrong_type_in_spdx_id(actor):
    with pytest.raises(TypeError):
        CreationInfo("version", 42, "name", "namespace", [actor, actor], datetime(2022, 1, 1))


@mock.patch('src.model.actor.Actor', autospec=True)
def test_wrong_type_in_name(actor):
    with pytest.raises(TypeError):
        CreationInfo("version", "id", 42, "namespace", [actor, actor], datetime(2022, 1, 1))


@mock.patch('src.model.actor.Actor', autospec=True)
def test_wrong_type_in_document_namespace(actor):
    with pytest.raises(TypeError):
        CreationInfo("version", "id", "name", 42, [actor, actor], datetime(2022, 1, 1))


def test_wrong_type_in_creators():
    with pytest.raises(TypeError):
        CreationInfo("version", "id", "name", "namespace", ["person"], datetime(2022, 1, 1))


@mock.patch('src.model.actor.Actor', autospec=True)
def test_wrong_type_in_created(actor):
    with pytest.raises(TypeError):
        CreationInfo("version", "id", "name", "namespace", [actor, actor], "2022-01-01")


@mock.patch('src.model.actor.Actor', autospec=True)
def test_wrong_type_in_creator_comment(actor):
    with pytest.raises(TypeError):
        CreationInfo("version", "id", "name", "namespace", [actor, actor], datetime(2022, 1, 1),
                     creator_comment=["string"])


@mock.patch('src.model.actor.Actor', autospec=True)
def test_wrong_type_in_data_license(actor):
    with pytest.raises(TypeError):
        CreationInfo("version", "id", "name", "namespace", [actor, actor], datetime(2022, 1, 1), data_license=42)


@mock.patch('src.model.actor.Actor', autospec=True)
def test_wrong_type_in_external_document_refs(actor):
    with pytest.raises(TypeError):
        CreationInfo("version", "id", "name", "namespace", [actor, actor], datetime(2022, 1, 1),
                     external_document_refs=())


@mock.patch('src.model.actor.Actor', autospec=True)
def test_wrong_type_in_license_list_version(actor):
    with pytest.raises(TypeError):
        CreationInfo("version", "id", "name", "namespace", [actor, actor], datetime(2022, 1, 1),
                     license_list_version="6.4")


@mock.patch('src.model.actor.Actor', autospec=True)
def test_wrong_type_in_document_comment(actor):
    with pytest.raises(TypeError):
        CreationInfo("version", "id", "name", "namespace", [actor, actor], datetime(2022, 1, 1), document_comment=["1"])

tests/model/test_checksum.py METASEP
import pytest

from src.model.checksum import Checksum, ChecksumAlgorithm


def test_correct_initialization():
    checksum = Checksum(ChecksumAlgorithm.BLAKE2B_256, "value")
    assert checksum.algorithm == ChecksumAlgorithm.BLAKE2B_256
    assert checksum.value == "value"


def test_wrong_type_in_algorithm():
    with pytest.raises(TypeError):
        Checksum(42, "value")


def test_wrong_type_in_value():
    with pytest.raises(TypeError):
        Checksum(ChecksumAlgorithm.BLAKE2B_256, 42)

tests/model/test_annotation.py METASEP
from datetime import datetime
from unittest import mock

import pytest

from src.model.annotation import Annotation, AnnotationType


@mock.patch('src.model.actor.Actor', autospec=True)
def test_correct_initialization(actor):
    annotation = Annotation("id", AnnotationType.OTHER, actor, datetime(2022, 1, 1), "comment")
    assert annotation.spdx_id == "id"
    assert annotation.annotation_type == AnnotationType.OTHER
    assert annotation.annotator == actor
    assert annotation.annotation_date == datetime(2022, 1, 1)
    assert annotation.annotation_comment == "comment"


@mock.patch('src.model.actor.Actor', autospec=True)
def test_wrong_type_in_spdx_id(actor):
    with pytest.raises(TypeError):
        Annotation(42, AnnotationType.OTHER, actor, datetime(2022, 1, 1), "comment")


@mock.patch('src.model.actor.Actor', autospec=True)
def test_wrong_type_in_annotation_type(actor):
    with pytest.raises(TypeError):
        Annotation("id", 42, actor, datetime(2022, 1, 1), "comment")


@mock.patch('src.model.actor.Actor', autospec=True)
def test_wrong_type_in_annotator(actor):
    with pytest.raises(TypeError):
        Annotation("id", AnnotationType.OTHER, 42, datetime(2022, 1, 1), "comment")


@mock.patch('src.model.actor.Actor', autospec=True)
def test_wrong_type_in_annotation_date(actor):
    with pytest.raises(TypeError):
        Annotation("id", AnnotationType.OTHER, actor, 42, "comment")


@mock.patch('src.model.actor.Actor', autospec=True)
def test_wrong_type_in_annotation_comment(actor):
    with pytest.raises(TypeError):
        Annotation("id", AnnotationType.OTHER, actor, datetime(2022, 1, 1), 42)

tests/model/test_actor.py METASEP
import pytest

from src.model.actor import Actor, ActorType


def test_correct_initialization():
    actor = Actor(ActorType.TOOL, "tool_name", "mail")
    assert actor.actor_type == ActorType.TOOL
    assert actor.name == "tool_name"
    assert actor.email == "mail"


def test_correct_initialization_with_optional_as_none():
    actor = Actor(ActorType.TOOL, "tool_name", None)
    assert actor.actor_type == ActorType.TOOL
    assert actor.name == "tool_name"
    assert actor.email is None


def test_wrong_type_in_actor_type():
    with pytest.raises(TypeError):
        Actor("PERSON", "name")


def test_wrong_type_in_name():
    with pytest.raises(TypeError):
        Actor(ActorType.PERSON, 42)


def test_wrong_type_in_email():
    with pytest.raises(TypeError):
        Actor(ActorType.PERSON, "name", [])


def test_wrong_type_in_email_after_initializing():
    with pytest.raises(TypeError):
        actor = Actor(ActorType.PERSON, "name")
        actor.email = []

tests/model/__init__.py METASEP

tests/clitools/test_cli_convertor.py METASEP
# Copyright (c) 2022 spdx tool contributors
# 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.

from unittest import TestCase

import pytest

from src.clitools.convertor import determine_infile_and_outfile


class TestConvertor(TestCase):
    maxDiff = None

    def test_determine_input_with_known_i_o_format(self):
        infile_given = 'infile.rdf'
        outfile_given = 'outfile.json'
        src = ()
        from_ = None
        to = None

        infile, outfile = determine_infile_and_outfile(infile_given, outfile_given, src, from_, to)

        assert infile == infile_given
        assert outfile == outfile_given

    def test_determine_input_with_unknown_i_o_format(self):
        infile_given = None
        outfile_given = None
        src = ('infile.in', 'outfile.out')
        from_ = 'rdf'
        to = 'json'
        expected_infile = 'infile.rdf'
        expected_outfile = 'outfile.json'

        infile, outfile = determine_infile_and_outfile(infile_given, outfile_given, src, from_, to)

        assert infile == expected_infile
        assert outfile == expected_outfile

    def test_determine_input_with_known_i_format_unknown_o_format(self):
        infile_given = 'infile.rdf'
        outfile_given = None
        src = ('outfile',)
        from_ = None
        to = 'json'
        expected_outfile = 'outfile.json'

        infile, outfile = determine_infile_and_outfile(infile_given, outfile_given, src, from_, to)

        assert infile == infile_given
        assert outfile == expected_outfile

    def test_determine_input_with_unknown_i_format_known_o_format(self):
        infile_given = None
        outfile_given = 'outfile.json'
        src = ('infile',)
        from_ = 'rdf'
        to = None
        expected_infile = 'infile.rdf'

        infile, outfile = determine_infile_and_outfile(infile_given, outfile_given, src, from_, to)

        assert infile == expected_infile
        assert outfile == outfile_given

    def test_determine_input_with_invalid_arguments(self):
        infile_given = None
        outfile_given = None
        src = ()
        from_ = None
        to = None

        with pytest.raises(ValueError):
            determine_infile_and_outfile(infile_given, outfile_given, src, from_, to)

tests/clitools/__init__.py METASEP

src/model/typing/type_checks.py METASEP
from typing import Any, Dict

from src.model.typing.constructor_type_errors import ConstructorTypeErrors


def check_types_and_set_values(instance_under_construction: Any, local_variables: Dict) -> None:
    """
    Helper method to accumulate all type errors encountered during a constructor call and return them in a
    ConstructorTypeErrors instance.
    Background: Our setters are enhanced with runtime typechecks using typeguard. However, this means that by
    default, a TypeError is raised on the first type violation that is encountered. We consider it more helpful to
    return all type violations in one go.
    As an aside, defining constructors "manually" using this utility method helps avoid a nasty PyCharm bug:
    https://youtrack.jetbrains.com/issue/PY-34569
    """
    errors = []
    for key, value_type in instance_under_construction.__annotations__.items():
        value = local_variables.get(key)
        try:
            setattr(instance_under_construction, key, value)
        except TypeError as err:
            error_message: str = err.args[0]
            errors.append(error_message)
    if errors:
        raise ConstructorTypeErrors(errors)

src/model/typing/dataclass_with_properties.py METASEP
from dataclasses import dataclass

from typeguard import typechecked


def dataclass_with_properties(cls):
    """Decorator to generate a dataclass with properties out of the class' value:type list.
    Their getters and setters will be subjected to the @typechecked decorator to ensure type conformity."""
    data_cls = dataclass(cls)
    for field_name, field_type in data_cls.__annotations__.items():
        set_field = make_setter(field_name, field_type)
        get_field = make_getter(field_name, field_type)

        setattr(data_cls, field_name, property(get_field, set_field))

    return data_cls


def make_setter(field_name, field_type):
    """helper method to avoid late binding when generating functions in a for loop"""

    @typechecked
    def set_field(self, value: field_type):
        setattr(self, f"_{field_name}", value)

    def set_field_with_better_error_message(self, value: field_type):
        try:
            set_field(self, value)
        except TypeError as err:
            error_message: str = f"SetterError {self.__class__.__name__}: {err.args[0]}"
            # As setters are created dynamically, their argument name is always "value". We replace it by the
            # actual name so the error message is more helpful.
            raise TypeError(error_message.replace("value", field_name, 1) + f": {value}")

    return set_field_with_better_error_message


def make_getter(field_name, field_type):
    """helper method to avoid late binding when generating functions in a for loop"""

    @typechecked
    def get_field(self) -> field_type:
        return getattr(self, f"_{field_name}")

    def get_field_with_better_error_message(self) -> field_type:
        try:
            return get_field(self)
        except TypeError as err:
            error_message: str = f"GetterError {self.__class__.__name__}: {err.args[0]}"
            # As getters are created dynamically, their argument name is always "the return value". We replace it by the
            # actual name so the error message is more helpful.
            raise TypeError(
                error_message.replace("the return value", field_name, 1) + f': {getattr(self, f"_{field_name}")}')

    return get_field_with_better_error_message

src/model/typing/constructor_type_errors.py METASEP
from typing import List


class ConstructorTypeErrors(TypeError):
    """
    Helper class that holds a list of error messages. Intended to capture all TypeErrors encountered during a
    constructor call, instead of raising only the first one.
    """
    messages: List[str]

    def __init__(self, messages: List[str]):
        self.messages = messages

src/model/typing/__init__.py METASEP

tests/valid_defaults.py METASEP
#  Copyright (c) 2022 spdx contributors
#  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.

from datetime import datetime

from src.model.actor import Actor, ActorType
from src.model.annotation import AnnotationType, Annotation
from src.model.checksum import Checksum, ChecksumAlgorithm
from src.model.document import CreationInfo, Document
from src.model.external_document_ref import ExternalDocumentRef
from src.model.extracted_licensing_info import ExtractedLicensingInfo
from src.model.file import File
from src.model.package import Package, PackageVerificationCode, ExternalPackageRef, ExternalPackageRefCategory
from src.model.relationship import Relationship, RelationshipType
from src.model.snippet import Snippet
from src.model.spdx_none import SpdxNone


def get_actor(actor_type=ActorType.PERSON, name="person name", mail=None) -> Actor:
    return Actor(actor_type, name, mail)


def get_annotation(spdx_id="SPDXRef-DOCUMENT", annotation_type=AnnotationType.OTHER, annotator=get_actor(),
                   annotation_date=datetime(2022, 1, 1), annotation_comment="annotation comment") -> Annotation:
    return Annotation(spdx_id, annotation_type, annotator, annotation_date, annotation_comment)


def get_checksum(algorithm=ChecksumAlgorithm.SHA1, value="85ed0817af83a24ad8da68c2b5094de69833983c") -> Checksum:
    return Checksum(algorithm, value)


def get_creation_info(spdx_version="SPDX-2.3", spdx_id="SPDXRef-DOCUMENT", name="document_name",
                      document_namespace="https://some.uri",
                      creators=None, created=datetime(2022, 1, 1), creator_comment=None, data_license="CC0-1.0",
                      external_document_refs=None, license_list_version=None, document_comment=None) -> CreationInfo:
    if creators is None:
        creators = [get_actor()]

    return CreationInfo(spdx_version, spdx_id, name, document_namespace, creators, created, creator_comment,
                        data_license, external_document_refs, license_list_version, document_comment)


def get_document(creation_info=get_creation_info(), packages=None, files=None, snippets=None, annotations=None,
                 relationships=None, extracted_licensing_info=None) -> Document:

    return Document(creation_info, packages, files, snippets, annotations, relationships, extracted_licensing_info)


def get_external_document_ref(document_ref_id="DocumentRef-idstring", document_uri="https://some.uri",
                              checksum=get_checksum()) -> ExternalDocumentRef:
    return ExternalDocumentRef(document_ref_id, document_uri, checksum)


def get_extracted_licensing_info(license_id="LicenseRef-1", extracted_text="extracted text",
                                 license_name="license name", cross_references=None,
                                 comment=None, ) -> ExtractedLicensingInfo:
    if cross_references is None:
        cross_references = ["http://some.url"]
    return ExtractedLicensingInfo(license_id, extracted_text, license_name, cross_references, comment)


def get_file(name="./file/name.py", spdx_id="SPDXRef-File", checksums=None, file_type=None, concluded_license=None,
             license_info_in_file=None, license_comment=None, copyright_text=None, comment=None, notice=None,
             contributors=None, attribution_texts=None) -> File:
    if checksums is None:
        checksums = [get_checksum()]

    return File(name, spdx_id, checksums, file_type, concluded_license, license_info_in_file, license_comment,
                copyright_text, comment, notice, contributors, attribution_texts)


def get_package_verification_code(value="85ed0817af83a24ad8da68c2b5094de69833983c",
                                  excluded_files=None) -> PackageVerificationCode:

    return PackageVerificationCode(value, excluded_files)


def get_external_package_ref(category=ExternalPackageRefCategory.SECURITY, reference_type="cpe22Type",
                             locator="cpe:/o:canonical:ubuntu_linux:10.04:-:lts",
                             comment="external package ref comment") -> ExternalPackageRef:
    return ExternalPackageRef(category, reference_type, locator, comment)


def get_package(spdx_id="SPDXRef-Package", name="package name", download_location=SpdxNone(), version=None,
                file_name=None, supplier=None, originator=None, files_analyzed=False, verification_code=None,
                checksums=None, homepage=None, source_info=None, license_concluded=None, license_info_from_files=None,
                license_declared=None, license_comment=None, copyright_text=None, summary=None, description=None,
                comment=None, external_references=None, attribution_texts=None, primary_package_purpose=None,
                release_date=None, built_date=None, valid_until_date=None) -> Package:

    return Package(spdx_id, name, download_location, version, file_name, supplier, originator, files_analyzed,
                   verification_code, checksums, homepage, source_info, license_concluded, license_info_from_files,
                   license_declared, license_comment, copyright_text, summary, description, comment,
                   external_references, attribution_texts, primary_package_purpose, release_date, built_date,
                   valid_until_date)


def get_relationship(spdx_element_id="SPDXRef-DOCUMENT", relationship_type=RelationshipType.DESCRIBES,
                     related_spdx_element_id="SPDXRef-File", comment=None) -> Relationship:
    return Relationship(spdx_element_id, relationship_type, related_spdx_element_id, comment)


def get_snippet(spdx_id="SPDXRef-Snippet", file_spdx_id="SPDXRef-File", byte_range=(200, 400), line_range=None,
                concluded_license=None, license_info_in_snippet=None, license_comment=None, copyright_text=None,
                comment=None, name=None, attribution_texts=None) -> Snippet:

    return Snippet(spdx_id, file_spdx_id, byte_range, line_range, concluded_license, license_info_in_snippet,
                   license_comment, copyright_text, comment, name, attribution_texts)

tests/__init__.py METASEP

tox.ini METASEP
[tox]
envlist =
    py{37,38,39,310,311,py,py3}
skipsdist = True

[testenv]
commands =
    {envbindir}/python -m pip install '{toxinidir}[format]'
    {envbindir}/coverage run --rcfile={toxinidir}/.coveragerc -m unittest discover -s tests
    {envbindir}/coverage report --rcfile={toxinidir}/.coveragerc --show-missing
    {envbindir}/coverage html --directory={envtmpdir}/htmlcov --rcfile={toxinidir}/.coveragerc {posargs}
deps =
    coverage
    pytest
    xmltodict

[testenv:coverage]
setenv =
    COVERAGE_DEBUG_FILE={envtmpdir}/coverage-debug
    COVERAGE_FILE={envtmpdir}/coverage-data
commands =
    {envbindir}/python -m pip install '{toxinidir}[format]'
    {envbindir}/coverage run --rcfile={toxinidir}/.coveragerc {envbindir}/trial jsonschema
    {envbindir}/coverage report --rcfile={toxinidir}/.coveragerc --show-missing
    {envbindir}/coverage html --directory={envtmpdir}/htmlcov --rcfile={toxinidir}/.coveragerc {posargs}

stdeb.cfg METASEP
[DEFAULT]
Depends = python-rdflib (>= 4.1.2), python-ply (>= 3.4)
Copyright-File = LICENSE 


pyproject.toml METASEP
[build-system]
requires = ["setuptools>=61.2", "setuptools_scm[toml]>=3.4.3"]
build-backend = "setuptools.build_meta"

[project]
name = "spdx-tools"
authors = [{name = "Ahmed H. Ismail", email = "ahm3d.hisham@gmail.com"}]
maintainers = [
    {name = "Philippe Ombredanne", email = "pombredanne@gmail.com"},
    {name = "SPDX group at the Linux Foundation and others"},
]
license = {text = "Apache-2.0"}
description = "SPDX parser and tools."
readme = "README.md"
classifiers = [
    "Intended Audience :: Developers",
    "Intended Audience :: System Administrators",
    "License :: OSI Approved :: Apache Software License",
    "Programming Language :: Python :: 3.7",
    "Programming Language :: Python :: 3.8",
    "Programming Language :: Python :: 3.9",
    "Programming Language :: Python :: 3.10",
    "Programming Language :: Python :: 3.11",
]
urls = {Homepage = "https://github.com/spdx/tools-python"}
requires-python = ">=3.7"
dependencies = ["ply", "rdflib", "click", "pyyaml", "xmltodict", "typeguard", "uritools"]
dynamic = ["version"]

[project.optional-dependencies]
test = ["pytest"]

[project.scripts]
pyspdxtools_convertor = "src.clitools.convertor:main"
pyspdxtools_parser = "src.clitools.parser:main"

[tool.setuptools]
zip-safe = false  # because of the uses of __file__: https://github.com/spdx/tools-python/issues/257
include-package-data = true

[tool.setuptools.packages.find]
where = ["src"]

[tool.setuptools_scm]
git_describe_command = ["git", "describe", "--dirty", "--tags", "--long", "--match",  "v[0-9]*"]  # `python3.6` tag falsely matches to the default one, clrearly a bug in setuptools_scm

[tool.aliases]
release = "clean --all sdist --formats=gztar bdist_wheel"

appveyor.yml METASEP
version: "{build}"
image:
  - Visual Studio 2019
environment:
  matrix:
    - PYTHON_EXE: "C:\\Python37-x64\\python.exe"
    - PYTHON_EXE: "C:\\Python38-x64\\python.exe"
    - PYTHON_EXE: "C:\\Python39-x64\\python.exe"
    - PYTHON_EXE: "C:\\Python310-x64\\python.exe"

install:
  - "%PYTHON_EXE% --version"
  - "%PYTHON_EXE% -m pip install --upgrade pip"
  - "%PYTHON_EXE% -m pip install --upgrade setuptools setuptools_scm wheel build pytest"
  - "%PYTHON_EXE% -m pip install --upgrade -e ."

build: off

test_script:
  - "%PYTHON_EXE% -m pytest"

README.md METASEP
# Python library to parse, validate and create SPDX documents

| Linux                          | macOS                         | Windows                         |
|:-------------------------------|:------------------------------|:--------------------------------|
| [ ![Linux build status][1]][2] | [![macOS build status][3]][4] | [![Windows build status][5]][6] |

[1]: https://travis-ci.org/spdx/tools-python.svg?branch=master

[2]: https://travis-ci.org/spdx/tools-python

[3]: https://circleci.com/gh/spdx/tools-python/tree/master.svg?style=shield&circle-token=36cca2dfa3639886fc34e22d92495a6773bdae6d

[4]: https://circleci.com/gh/spdx/tools-python/tree/master

[5]: https://ci.appveyor.com/api/projects/status/0bf9glha2yg9x8ef/branch/master?svg=true

[6]: https://ci.appveyor.com/project/spdx/tools-python/branch/master

# CURRENT STATE

A major refactoring of large parts of the codebase is currently in progress. It is expected that functionality on `main`
is severely limited during this process. Please check out
the [latest release](https://github.com/spdx/tools-python/releases/tag/v0.7.0) if you are looking for a working version.

# Information

This library implements SPDX parsers, convertors, validators and handlers in Python.

- Home: https://github.com/spdx/tools-python
- Issues: https://github.com/spdx/tools-python/issues
- PyPI: https://pypi.python.org/pypi/spdx-tools

# History

This is the result of an initial GSoC contribution by @[ah450](https://github.com/ah450)
(or https://github.com/a-h-i) and is maintained by a community of SPDX adopters and enthusiasts.

# License

[Apache-2.0](LICENSE)

# Features

* API to create and manipulate SPDX v2.3 documents.
* Parse, convert, create and validate Tag/Value, RDF, JSON, YAML, XML format SPDX files

### Known Limitations

* No full 2.3 support for RDF format [#295](https://github.com/spdx/tools-python/issues/295)
* No full license expression support [#10](https://github.com/spdx/tools-python/issues/10)
* Output of the CLI parser is incomplete [#268](https://github.com/spdx/tools-python/issues/268)

# TODOs

* Include specialized validation for SPDX v2.2.1(ISO 5962:2021)

# How to use

## Command-line usage:

1. **PARSER** (for parsing any format):

* Use `pyspdxtools_parser --file <filename>` where `<filename>` is the location of the file.              
If you are using a source distribution, try running: `pyspdxtools_parser --file tests/data/formats/SPDXRdfExample.rdf`.

* Or you can use `pyspdxtools_parser` only, and it will automatically prompt/ask for `filename`.

* For help use `pyspdxtools_parser --help`


2. **CONVERTOR** (for converting one format to another):

* If I/O formats are known:

    * Use `pyspdxtools_convertor --infile/-i <input_file> --outfile/-o <output_file>` where `<input_file>` is the location of the file to be converted
    and `<output_file>` is the location of the output file.  
    If you are using a source distribution, try running : `pyspdxtools_convertor --infile tests/data/formats/SPDXRdfExample.rdf --outfile output.json` 

* If I/O formats are not known:

    * Use `pyspdxtools_convertor --from/-f <input_format> <input_file> --to/-t <output_format> <output_file>` where `<input_format>` is the manually entered format of the input file
    and `<out_format>` is the manually entered format of the output file. 
    If you are using a source distribution, try running : `pyspdxtools_convertor --from tag tests/data/formats/SPDXTagExample.in --to yaml output.out` 

* If one of the formats is known and the other is not, you can use a mixture of the above two points.  
Example (if you are using a source distribution): `pyspdxtools_convertor -f rdf tests/data/formats/SPDXRdfExample.xyz -o output.xml`

* For help use `pyspdxtools_convertor --help`

# Installation

As always you should work in a virtualenv (venv). You can install a local clone
of this repo with `yourenv/bin/pip install .` or install it from PyPI with
`yourenv/bin/pip install spdx-tools`. Note that on Windows it would be `Scripts`
instead of `bin`.

# Dependencies

* PLY: https://pypi.python.org/pypi/ply/ used for parsing.
* rdflib: https://pypi.python.org/pypi/rdflib/ for handling RDF.
* PyYAML: https://pypi.org/project/PyYAML/ for handling YAML.
* xmltodict: https://pypi.org/project/xmltodict/ for handling XML.
* click: https://pypi.org/project/click/ for creating the CLI interface.

# Support

* Submit issues, questions or feedback at https://github.com/spdx/tools-python/issues
* Join the chat at https://gitter.im/spdx-org/Lobby
* Join the discussion on https://lists.spdx.org/g/spdx-tech and
  https://spdx.dev/participate/tech/

# Contributing

Contributions are very welcome! See [CONTRIBUTING.md](./CONTRIBUTING.md) for instructions on how to contribute to the
codebase.

MANIFEST.in METASEP
graft data
graft examples
graft spdx
graft tests

prune src/spdx_tools.egg-info

include spdx/licenses.json
include README.md
include CHANGELOG.rst
include LICENSE
include MANIFEST.in
include setup.py
include setup.cfg
include .gitignore
include MANIFEST.in
include .travis.yml
include circle.yml
include appveyor.yml

global-exclude *.py[co] __pycache__ *.*~

CONTRIBUTING.md METASEP
# Contributing

Thank you for your interest in `tools-python`. The project is open-source software, and bug reports, suggestions, and
most especially patches are welcome.

## Issues

`tools-python` has a [project page on GitHub](https://github.com/spdx/tools-python/) where you
can [create an issue](https://github.com/spdx/tools-python/issues/new) to report a bug, make a suggestion, or propose a
substantial change or improvement. You may also wish to contact the SPDX working group technical team through its
mailing list, [spdx-tech@lists.spdx.org](mailto:spdx-tech@lists.spdx.org).

If you would like to work on a fix for any issue, please assign the issue to yourself or write a comment indicating your
intention prior to creating a patch.

## Development process

We use the GitHub flow that is described here: https://guides.github.com/introduction/flow/

Here's the process to make changes to the codebase:

1. Find or [file an issue](#issues) you'd like to address. Every change should be made to fix or close an issue. Please
   try to keep issues reasonably small, focusing on one aspect, or split off sub-issues if possible. Large pull requests
   that fix many things at the same time tend to cause a lot of conflicts.

2. Review [open pull requests](https://github.com/spdx/tools-python/pulls) before committing time to a substantial
   revision. Work along similar lines may already be in progress.

3. Create a new branch:
   ```sh
   git checkout -b fix-or-improve-something
   ```
4. Make some changes and commit them to the branch:
   ```sh
   git commit --signoff -m 'description of my changes'
   ```

   #### Licensing

   Please sign off in each of your commits that you license your contributions under the terms
   of [the Developer Certificate of Origin](https://developercertificate.org/). Git has utilities for signing off on
   commits: `git commit -s` or `--signoff` signs a current commit, and `git rebase --signoff <revision-range>`
   retroactively signs a range of past commits.

5. Test your changes:
   ```sh
   python setup.py test # in the repo root
   ```
   You may use other test runners, such as `pytest` or `nose` at your preference.
6. Push the branch to your fork on GitHub:
   ```sh
   git push origin fix-or-improve-something
   ```
7. Make a pull request on GitHub.
8. Continue making more changes and commits on the branch, with `git commit --signoff` and `git push`.
9. When done, write a comment on the PR asking for a code review.
10. Some other developer will review your changes and accept your PR. The merge should be done with `rebase`, if
    possible, or with `squash`.
11. The temporary branch on GitHub should be deleted (there is a button for deleting it).
12. Delete the local branch as well:
    ```sh
    git checkout master
    git pull -p
    git branch -a
    git branch -d fix-or-improve-something
    ```

# How to run tests

The tests framework is using pytest:

```
pip install pytest
pytest -vvs
```

CHANGELOG.md METASEP
# Changelog


## v0.7.0 (2022-12-08)

Starting a Changelog.

### New features and changes

* Dropped Python 2 support. Python >= 3.6 is now required.
* Added `pyspdxtools_convertor` and `pyspdxtools_parser` CLI scripts. See [the readme](README.md) for usage instructions.
* Updated the tools to support SPDX versions up to 2.3 and to conform with the specification. Apart from many bugfixes 
  and new properties, some of the more significant changes include:
    * Support for multiple packages per document
    * Support for multiple checksums for packages and files
    * Support for files outside a package
* **Note**: Validation was updated to follow the 2.3 specification. Since there is currently no support for 
  version-specific handling, some details may be handled incorrectly for documents using lower
  versions. The changes are mostly restricted to properties becoming optional and new property values becoming
  available, and should be of limited impact. See https://spdx.github.io/spdx-spec/v2.3/diffs-from-previous-editions/
  for a list of changes between the versions.
* **Note**: RDF support for 2.3 is not completed, see https://github.com/spdx/tools-python/issues/295
* Removed example documents from production code. Added additional up-to-date examples to test files.
* Introduced pytest as the preferred test framework.
* Improved error message handling and display.
* Extended the contribution guidelines.
* Improved tag/value output structure.
* Added .editorconfig and pyproject.toml.
* Improved handling of JSON-specific properties `documentDescribes` and `hasFiles`.
* Added new LicenseListVersion tag.
* Fixed annotation handling for the JSON and Tag/Value formats.
* Free form text values in Tag/Value no longer require `<text>` tags if they don't span multiple lines.

### Contributors

This release was made possible by the following contributors. Thank you very much!

* Meret Behrens @meretp
* Philippe Ombredanne @pombredanne
* Pierre Tardy @tardyp
* Nicolaus Weidner @nicoweidner
* Jeff Licquia @licquia
* Armin Tänzer @armintaenzertng
* Alberto Pianon @alpianon
* Rodney Richardson @RodneyRichardson
* Lon Hohberger @lhh
* Nathan Voss @njv299
* Gary O'Neall @goneall
* Jeffrey Otterson @jotterson
* KOLANICH @KOLANICH
* Yash Varshney @Yash-Varshney
* HARDIK @HARDIK-TSH1392
* Jose Quaresma @quaresmajose
* Santiago Torres @SantiagoTorres
* Shubham Kumar Jha @ShubhamKJha
* Steven Kalt @SKalt
* Cole Helbling @cole-h
* Daniel Holth @dholth
* John Vandenberg @jayvdb
* Kate Stewart @kestewart
* Alexios Zavras @zvr
* Maximilian Huber @maxhbr
* Kyle Altendorf @altendky
* alpianon @alpianon
* kbermude @kbermude
* mzfr @mzfr

src/validation/validation_message.py METASEP
#  Copyright (c) 2022 spdx contributors
#  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.

from dataclasses import dataclass
from enum import Enum, auto
from typing import Optional, Any


class SpdxElementType(Enum):
    PACKAGE_VERIFICATION_CODE = auto()
    EXTERNAL_DOCUMENT_REF = auto()
    CHECKSUM = auto()
    EXTERNAL_PACKAGE_REF = auto()
    ACTOR = auto()
    DOCUMENT = auto()
    CREATION_INFO = auto()
    PACKAGE = auto()
    FILE = auto()
    SNIPPET = auto()
    LICENSE = auto()
    ANNOTATION = auto()
    RELATIONSHIP = auto()
    EXTRACTED_LICENSING_INFO = auto()


@dataclass(frozen=True)
class ValidationContext:
    spdx_id: Optional[str] = None  # not every type has an id, or it might be missing
    parent_id: Optional[str] = None  # if a parent is known and has a valid id
    element_type: Optional[SpdxElementType] = None
    full_element: Any = None  # can be any class of the data model


@dataclass(frozen=True)
class ValidationMessage:
    validation_message: str
    context: ValidationContext

src/validation/uri_validators.py METASEP
#  Copyright (c) 2022 spdx contributors
#  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.

import re
from typing import List

from uritools import isabsuri, urisplit

url_pattern = "(http:\\/\\/www\\.|https:\\/\\/www\\.|http:\\/\\/|https:\\/\\/|ssh:\\/\\/|git:\\/\\/|svn:\\/\\/|sftp:\\/\\/|ftp:\\/\\/)?[a-z0-9]+([\\-\\.]{1}[a-z0-9]+){0,100}\\.[a-z]{2,5}(:[0-9]{1,5})?(\\/.*)?"
supported_download_repos: str = "(git|hg|svn|bzr)"
git_pattern = "(git\\+git@[a-zA-Z0-9\\.\\-]+:[a-zA-Z0-9/\\\\.@\\-]+)"
bazaar_pattern = "(bzr\\+lp:[a-zA-Z0-9\\.\\-]+)"
download_location_pattern = (
    "^(((" + supported_download_repos + "\\+)?" + url_pattern + ")|" + git_pattern + "|" + bazaar_pattern + ")$")


def validate_url(url: str) -> List[str]:
    if not re.match(url_pattern, url):
        return [f"must be a valid URL, but is: {url}"]

    return []


def validate_download_location(location: str) -> List[str]:
    if not re.match(download_location_pattern, location):
        return [f"must be a valid download location according to the specification, but is: {location}"]

    return []


def validate_uri(uri: str) -> List[str]:
    if not isabsuri(uri):
        return [f"must be a valid URI specified in RFC-3986, but is: {uri}"]
    else:
        split = urisplit(uri)
        if split.scheme is None:
            return [f"must have a URI scheme, but is: {uri}"]

    return []

src/validation/spdx_id_validators.py METASEP
#  Copyright (c) 2022 spdx contributors
#  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.

import re
from typing import List

from src.model.document import Document
from src.model.file import File


def is_valid_internal_spdx_id(spdx_id: str) -> bool:
    return bool(re.match(r"^SPDXRef-[\da-zA-Z.-]+$", spdx_id))


def is_valid_external_doc_ref_id(external_ref_id: str) -> bool:
    return bool(re.match(r"^DocumentRef-[\da-zA-Z.+-]+$", external_ref_id))


def is_spdx_id_present_in_files(spdx_id: str, files: List[File]) -> bool:
    return spdx_id in [file.spdx_id for file in files]


def is_spdx_id_present_in_document(spdx_id: str, document: Document) -> bool:
    all_spdx_ids_in_document: List[str] = get_list_of_all_spdx_ids(document)

    return spdx_id in all_spdx_ids_in_document


def get_list_of_all_spdx_ids(document: Document) -> List[str]:
    all_spdx_ids_in_document: List[str] = [document.creation_info.spdx_id]

    all_spdx_ids_in_document.extend([package.spdx_id for package in document.packages])
    all_spdx_ids_in_document.extend([file.spdx_id for file in document.files])
    all_spdx_ids_in_document.extend([snippet.spdx_id for snippet in document.snippets])

    return all_spdx_ids_in_document


def is_external_doc_ref_present_in_document(external_ref_id: str, document: Document) -> bool:
    all_external_doc_ref_ids_in_document = [external_doc_ref.document_ref_id for external_doc_ref in
                                            document.creation_info.external_document_refs]

    return external_ref_id in all_external_doc_ref_ids_in_document


def validate_spdx_id(spdx_id: str, document: Document, check_document: bool = False, check_files: bool = False) -> List[
    str]:
    """ Test that the given spdx_id (and a potential DocumentRef to an external document) is valid
    and, if it is a reference, actually exists in the document. Optionally checks files or the whole document
    for the existence of the spdx_id (i.e. if it is used as a reference). Returns a list of validation messages,
    and the external document ref part and id part of the provided spdx_id. """

    validation_messages: List[str] = []
    split_id: List[str] = spdx_id.split(":")

    # # # invalid case # # #
    if len(split_id) > 2:
        return [
            f"spdx_id must not contain more than one colon in order to separate the external document reference id from the internal SPDX id, but is: {spdx_id}"]

    # # # case with external document ref prefix # # #
    if len(split_id) == 2:
        if not is_valid_external_doc_ref_id(split_id[0]):
            validation_messages.append(
                f'the external document reference part of spdx_id must only contain letters, numbers, ".", "-" and "+" and must begin with "DocumentRef-", but is: {split_id[0]}')
        if not is_valid_internal_spdx_id(split_id[1]):
            validation_messages.append(
                f'the internal SPDX id part of spdx_id must only contain letters, numbers, "." and "-" and must begin with "SPDXRef-", but is: {split_id[1]}')
        if not is_external_doc_ref_present_in_document(split_id[0], document):
            validation_messages.append(
                f"did not find the external document reference {split_id[0]} in the SPDX document")

        return validation_messages

    # # # "normal" case # # #
    if not is_valid_internal_spdx_id(spdx_id):
        validation_messages.append(
            f'spdx_id must only contain letters, numbers, "." and "-" and must begin with "SPDXRef-", but is: {spdx_id}')

    if check_document:
        if not is_spdx_id_present_in_document(spdx_id, document):
            validation_messages.append(f"did not find the referenced spdx_id {spdx_id} in the SPDX document")

    if check_files:
        if not is_spdx_id_present_in_files(spdx_id, document.files):
            validation_messages.append(f"did not find the referenced spdx_id {spdx_id} in the SPDX document's files")

    return validation_messages

src/validation/snippet_validator.py METASEP
#  Copyright (c) 2022 spdx contributors
#  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.

from typing import List, Optional

from src.model.document import Document
from src.model.snippet import Snippet
from src.validation.license_expression_validator import validate_license_expression, \
    validate_license_expressions
from src.validation.spdx_id_validators import validate_spdx_id
from src.validation.validation_message import ValidationMessage, ValidationContext, SpdxElementType


def validate_snippets(snippets: List[Snippet], document: Optional[Document] = None) -> List[ValidationMessage]:
    validation_messages = []
    if document:
        for snippet in snippets:
            validation_messages.extend(validate_snippet_within_document(snippet, document))
    else:
        for snippet in snippets:
            validation_messages.extend(validate_snippet(snippet))

    return validation_messages


def validate_snippet_within_document(snippet: Snippet, document: Document) -> List[ValidationMessage]:
    validation_messages: List[ValidationMessage] = []
    context = ValidationContext(spdx_id=snippet.spdx_id, parent_id=document.creation_info.spdx_id,
                                element_type=SpdxElementType.SNIPPET, full_element=snippet)

    messages: List[str] = validate_spdx_id(snippet.spdx_id, document)
    for message in messages:
        validation_messages.append(ValidationMessage(message, context))

    messages: List[str] = validate_spdx_id(snippet.file_spdx_id, document, check_files=True)
    for message in messages:
        validation_messages.append(ValidationMessage(message, context))

    validation_messages.extend(validate_snippet(snippet, context))

    return validation_messages


def validate_snippet(snippet: Snippet, context: Optional[ValidationContext] = None) -> List[ValidationMessage]:
    validation_messages = []
    if not context:
        context = ValidationContext(spdx_id=snippet.spdx_id, element_type=SpdxElementType.SNIPPET, full_element=snippet)

    if snippet.byte_range[0] < 1:
        validation_messages.append(
            ValidationMessage(
                f"byte_range values must be greater than or equal to 1, but is: {snippet.byte_range}",
                context)
        )

    if snippet.byte_range[0] > snippet.byte_range[1]:
        validation_messages.append(
            ValidationMessage(
                f"the first value of byte_range must be less than or equal to the second, but is: {snippet.byte_range}",
                context)
        )

    if snippet.line_range:
        if snippet.line_range[0] < 1:
            validation_messages.append(
                ValidationMessage(
                    f"line_range values must be greater than or equal to 1, but is: {snippet.line_range}",
                    context)
            )

        if snippet.line_range[0] > snippet.line_range[1]:
            validation_messages.append(
                ValidationMessage(
                    f"the first value of line_range must be less than or equal to the second, but is: {snippet.line_range}",
                    context)
            )

    validation_messages.extend(validate_license_expression(snippet.concluded_license))

    validation_messages.extend(validate_license_expressions(snippet.license_info_in_snippet))

    return validation_messages

src/validation/relationship_validator.py METASEP
#  Copyright (c) 2022 spdx contributors
#  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.

from typing import List

from src.model.document import Document
from src.model.relationship import Relationship, RelationshipType
from src.validation.spdx_id_validators import validate_spdx_id
from src.validation.validation_message import ValidationMessage, ValidationContext, SpdxElementType


def validate_relationships(relationships: List[Relationship], document: Document, spdx_version: str) -> List[ValidationMessage]:
    validation_messages = []
    for relationship in relationships:
        validation_messages.extend(validate_relationship(relationship, document, spdx_version))

    return validation_messages


def validate_relationship(relationship: Relationship, document: Document, spdx_version: str) -> List[ValidationMessage]:
    validation_messages = []
    context = ValidationContext(element_type=SpdxElementType.RELATIONSHIP,
                                full_element=relationship)

    first_id: str = relationship.spdx_element_id
    second_id: str = relationship.related_spdx_element_id
    relationship_type: RelationshipType = relationship.relationship_type

    for spdx_id in [first_id, second_id]:
        messages: List[str] = validate_spdx_id(spdx_id, document, check_document=True)
        for message in messages:
            validation_messages.append(ValidationMessage(message, context))

    if spdx_version != "2.3":
        if relationship_type == RelationshipType.SPECIFICATION_FOR or relationship_type == RelationshipType.REQUIREMENT_DESCRIPTION_FOR:
            validation_messages.append(
                ValidationMessage(f"{relationship_type} is not supported for SPDX versions below 2.3", context))

    return validation_messages

src/validation/package_verification_code_validator.py METASEP
#  Copyright (c) 2022 spdx contributors
#  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.

import re
from typing import List

from src.model.package import PackageVerificationCode
from src.validation.validation_message import ValidationMessage, ValidationContext, SpdxElementType


# TODO: make test for this (https://github.com/spdx/tools-python/issues/386)
def validate_verification_code(verification_code: PackageVerificationCode, parent_id: str) -> List[ValidationMessage]:
    validation_messages: List[ValidationMessage] = []
    context = ValidationContext(parent_id=parent_id, element_type=SpdxElementType.PACKAGE_VERIFICATION_CODE,
                                full_element=verification_code)

    for file in verification_code.excluded_files:
        if not file.startswith("./"):
            validation_messages.append(
                ValidationMessage(
                    f'file name must be a relative path to the file, starting with "./", but is: {file}', context)
            )

    value: str = verification_code.value
    if not re.match("^[0-9a-f]{40}$", value):
        validation_messages.append(
            ValidationMessage(
                f"value of verification_code must consist of 40 hexadecimal digits, but is: {value} (length: {len(value)} digits)",
                context)
        )

    return validation_messages

src/validation/package_validator.py METASEP
#  Copyright (c) 2022 spdx contributors
#  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.

from typing import List, Optional

from src.model.document import Document
from src.model.package import Package
from src.model.relationship import RelationshipType
from src.validation.checksum_validator import validate_checksums
from src.validation.external_package_ref_validator import validate_external_package_refs
from src.validation.license_expression_validator import validate_license_expression, validate_license_expressions
from src.validation.package_verification_code_validator import validate_verification_code
from src.validation.spdx_id_validators import validate_spdx_id
from src.validation.uri_validators import validate_url, validate_download_location
from src.validation.validation_message import ValidationMessage, ValidationContext, SpdxElementType


def validate_packages(packages: List[Package], document: Optional[Document] = None) -> List[ValidationMessage]:
    validation_messages: List[ValidationMessage] = []
    if document:
        for package in packages:
            validation_messages.extend(validate_package_within_document(package, document))
    else:
        for package in packages:
            validation_messages.extend(validate_package(package))

    return validation_messages


def validate_package_within_document(package: Package, document: Document) -> List[ValidationMessage]:
    validation_messages: List[ValidationMessage] = []
    context = ValidationContext(spdx_id=package.spdx_id, parent_id=document.creation_info.spdx_id,
                                element_type=SpdxElementType.PACKAGE, full_element=package)

    for message in validate_spdx_id(package.spdx_id, document):
        validation_messages.append(ValidationMessage(message, context))

    # TODO: make test for this (https://github.com/spdx/tools-python/issues/386)
    if not package.files_analyzed:
        package_contains_relationships = [relationship for relationship in document.relationships if
                                          relationship.relationship_type == RelationshipType.CONTAINS and relationship.spdx_element_id == package.spdx_id]
        if package_contains_relationships:
            validation_messages.append(
                ValidationMessage(
                    f"package must contain no elements if files_analyzed is False, but found {package_contains_relationships}",
                    context)
            )

        contained_in_package_relationships = [relationship for relationship in document.relationships if
                                              relationship.relationship_type == RelationshipType.CONTAINED_BY and relationship.related_spdx_element_id == package.spdx_id]
        if contained_in_package_relationships:
            validation_messages.append(
                ValidationMessage(
                    f"package must contain no elements if files_analyzed is False, but found {contained_in_package_relationships}",
                    context)
            )

    validation_messages.extend(validate_package(package, context))

    return validation_messages


def validate_package(package: Package, context: Optional[ValidationContext] = None) -> List[ValidationMessage]:
    validation_messages: List[ValidationMessage] = []
    if not context:
        context = ValidationContext(spdx_id=package.spdx_id, element_type=SpdxElementType.PACKAGE, full_element=package)

    download_location = package.download_location
    if isinstance(download_location, str):
        for message in validate_download_location(download_location):
            validation_messages.append(ValidationMessage("package download_location " + message, context))

    homepage = package.homepage
    if isinstance(homepage, str):
        for message in validate_url(homepage):
            validation_messages.append(ValidationMessage("homepage " + message, context))

    # TODO: is verification_code required if files_analyzed=True? (https://github.com/spdx/tools-python/issues/386)
    verification_code = package.verification_code
    if verification_code:
        if not package.files_analyzed:
            validation_messages.append(
                ValidationMessage(
                    f"verification_code must be None if files_analyzed is False, but is: {verification_code}",
                    context))
        else:
            validation_messages.extend(validate_verification_code(verification_code, package.spdx_id))

    validation_messages.extend(validate_checksums(package.checksums, package.spdx_id))

    validation_messages.extend(validate_license_expression(package.license_concluded))

    license_info_from_files = package.license_info_from_files
    if license_info_from_files:
        if not package.files_analyzed:
            validation_messages.append(
                ValidationMessage(
                    f"license_info_from_files must be None if files_analyzed is False, but is: {license_info_from_files}",
                    context)
            )
        else:
            validation_messages.extend(validate_license_expressions(license_info_from_files))

    validation_messages.extend(validate_license_expression(package.license_declared))

    validation_messages.extend(validate_external_package_refs(package.external_references, package.spdx_id))

    return validation_messages

src/validation/license_expression_validator.py METASEP
#  Copyright (c) 2022 spdx contributors
#  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.

from typing import List, Optional, Union

from src.model.license_expression import LicenseExpression
from src.model.spdx_no_assertion import SpdxNoAssertion
from src.model.spdx_none import SpdxNone
from src.validation.validation_message import ValidationMessage


def validate_license_expressions(license_expressions: Optional[
    Union[List[LicenseExpression], SpdxNoAssertion, SpdxNone]]) -> List[ValidationMessage]:
    if license_expressions in [SpdxNoAssertion(), SpdxNone(), None]:
        return []

    error_messages = []

    for license_expression in license_expressions:
        error_messages.extend(validate_license_expression(license_expression))

    return error_messages


def validate_license_expression(license_expression: LicenseExpression) -> List[ValidationMessage]:
    # TODO: implement this once we have a better license expression model: https://github.com/spdx/tools-python/issues/374
    return []

src/validation/file_validator.py METASEP
#  Copyright (c) 2022 spdx contributors
#  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.

from typing import List, Optional

from src.model.checksum import ChecksumAlgorithm
from src.model.document import Document
from src.model.file import File
from src.validation.checksum_validator import validate_checksums
from src.validation.license_expression_validator import validate_license_expressions, validate_license_expression
from src.validation.spdx_id_validators import validate_spdx_id
from src.validation.validation_message import ValidationMessage, ValidationContext, SpdxElementType


def validate_files(files: List[File], document: Optional[Document] = None) -> List[ValidationMessage]:
    validation_messages = []
    if document:
        for file in files:
            validation_messages.extend(validate_file_within_document(file, document))
    else:
        for file in files:
            validation_messages.extend(validate_file(file))

    return validation_messages


def validate_file_within_document(file: File, document: Document) -> List[ValidationMessage]:
    validation_messages: List[ValidationMessage] = []
    context = ValidationContext(spdx_id=file.spdx_id, parent_id=document.creation_info.spdx_id,
                                element_type=SpdxElementType.FILE, full_element=file)

    for message in validate_spdx_id(file.spdx_id, document):
        validation_messages.append(ValidationMessage(message, context))

    validation_messages.extend(validate_file(file, context))

    return validation_messages


def validate_file(file: File, context: Optional[ValidationContext] = None) -> List[ValidationMessage]:
    validation_messages = []
    if not context:
        context = ValidationContext(spdx_id=file.spdx_id, element_type=SpdxElementType.FILE, full_element=file)

    if not file.name.startswith("./"):
        validation_messages.append(
            ValidationMessage(
                f'file name must be a relative path to the file, starting with "./", but is: {file.name}', context)
        )

    if ChecksumAlgorithm.SHA1 not in [checksum.algorithm for checksum in file.checksums]:
        validation_messages.append(
            ValidationMessage(
                f"checksums must contain a SHA1 algorithm checksum, but only contains: {[checksum.algorithm for checksum in file.checksums]}",
                context)
        )

    validation_messages.extend(validate_checksums(file.checksums, file.spdx_id))

    validation_messages.extend(validate_license_expression(file.concluded_license))

    validation_messages.extend(validate_license_expressions(file.license_info_in_file))

    return validation_messages

src/validation/extracted_licensing_info_validator.py METASEP
#  Copyright (c) 2022 spdx contributors
#  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.

import re
from typing import List, Optional

from src.model.extracted_licensing_info import ExtractedLicensingInfo
from src.validation.uri_validators import validate_url
from src.validation.validation_message import ValidationMessage, ValidationContext, SpdxElementType


def validate_extracted_licensing_infos(extracted_licensing_infos: Optional[List[ExtractedLicensingInfo]]) -> List[ValidationMessage]:
    validation_messages = []
    for extracted_licensing_info in extracted_licensing_infos:
        validation_messages.extend(validate_extracted_licensing_info(extracted_licensing_info))

    return validation_messages


def validate_extracted_licensing_info(extracted_licensing_infos: ExtractedLicensingInfo) -> List[
    ValidationMessage]:
    validation_messages: List[ValidationMessage] = []
    context = ValidationContext(element_type=SpdxElementType.EXTRACTED_LICENSING_INFO,
                                full_element=extracted_licensing_infos)

    license_id: str = extracted_licensing_infos.license_id
    if license_id and not re.match(r"^LicenseRef-[\da-zA-Z.-]+$", license_id):
        validation_messages.append(
            ValidationMessage(
                f'license_id must only contain letters, numbers, "." and "-" and must begin with "LicenseRef-", but is: {license_id}',
                context)
        )

    if license_id and not extracted_licensing_infos.extracted_text:
        validation_messages.append(
            ValidationMessage("extracted_text must be provided if there is a license_id assigned", context)
        )

    for cross_reference in extracted_licensing_infos.cross_references:
        for message in validate_url(cross_reference):
            validation_messages.append(
                ValidationMessage("cross_reference " + message, context)
            )

    return validation_messages

src/validation/external_package_ref_validator.py METASEP
#  Copyright (c) 2022 spdx contributors
#  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.

from typing import List

from src.model.package import ExternalPackageRef
from src.validation.validation_message import ValidationMessage


def validate_external_package_refs(external_package_refs: List[ExternalPackageRef], parent_id: str) -> List[
    ValidationMessage]:
    validation_messages = []
    for external_package_ref in external_package_refs:
        validation_messages.extend(validate_external_package_ref(external_package_ref, parent_id))

    return validation_messages


def validate_external_package_ref(external_package_ref: ExternalPackageRef, parent_id: str) -> List[ValidationMessage]:
    # TODO: https://github.com/spdx/tools-python/issues/373
    return []

src/validation/external_document_ref_validator.py METASEP
#  Copyright (c) 2022 spdx contributors
#  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.

from typing import List

from src.model.external_document_ref import ExternalDocumentRef
from src.validation.checksum_validator import validate_checksum
from src.validation.spdx_id_validators import is_valid_external_doc_ref_id
from src.validation.uri_validators import validate_uri
from src.validation.validation_message import ValidationMessage, ValidationContext, SpdxElementType


def validate_external_document_refs(external_document_refs: List[ExternalDocumentRef], parent_id: str) -> List[
    ValidationMessage]:
    validation_messages = []
    for external_document_ref in external_document_refs:
        validation_messages.extend(validate_external_document_ref(external_document_ref, parent_id))

    return validation_messages


def validate_external_document_ref(external_document_ref: ExternalDocumentRef, parent_id: str) -> List[ValidationMessage]:
    validation_messages = []
    context = ValidationContext(parent_id=parent_id, element_type=SpdxElementType.EXTERNAL_DOCUMENT_REF,
                                full_element=external_document_ref)

    if not is_valid_external_doc_ref_id(external_document_ref.document_ref_id):
        validation_messages.append(
            ValidationMessage(
                f'document_ref_id must only contain letters, numbers, ".", "-" and "+" and must begin with "DocumentRef-", but is: {external_document_ref.document_ref_id}',
                context
            )
        )

    for message in validate_uri(external_document_ref.document_uri):
        validation_messages.append(
            ValidationMessage(
                "document_uri " + message, context
            )
        )

    validation_messages.extend(validate_checksum(external_document_ref.checksum, parent_id))

    return validation_messages

src/validation/document_validator.py METASEP
#  Copyright (c) 2022 spdx contributors
#  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.

from typing import List

from src.model.document import Document
from src.model.relationship import RelationshipType
from src.validation.annotation_validator import validate_annotations
from src.validation.creation_info_validator import validate_creation_info
from src.validation.extracted_licensing_info_validator import validate_extracted_licensing_infos
from src.validation.file_validator import validate_files
from src.validation.package_validator import validate_packages
from src.validation.relationship_validator import validate_relationships
from src.validation.snippet_validator import validate_snippets
from src.validation.validation_message import ValidationMessage, ValidationContext, SpdxElementType


def validate_full_spdx_document(document: Document, spdx_version: str) -> List[ValidationMessage]:
    validation_messages: List[ValidationMessage] = []

    validation_messages.extend(validate_creation_info(document.creation_info))
    validation_messages.extend(validate_packages(document.packages, document))
    validation_messages.extend(validate_files(document.files, document))
    validation_messages.extend(validate_snippets(document.snippets, document))
    validation_messages.extend(validate_annotations(document.annotations, document))
    validation_messages.extend(validate_relationships(document.relationships, document, spdx_version))
    validation_messages.extend(validate_extracted_licensing_infos(document.extracted_licensing_info))

    document_id = document.creation_info.spdx_id
    document_describes_relationships = [relationship for relationship in document.relationships if
                                        relationship.relationship_type == RelationshipType.DESCRIBES and relationship.spdx_element_id == document_id]
    described_by_document_relationships = [relationship for relationship in document.relationships if
                                           relationship.relationship_type == RelationshipType.DESCRIBED_BY and relationship.related_spdx_element_id == document_id]

    if not document_describes_relationships + described_by_document_relationships:
        validation_messages.append(
            ValidationMessage(
                f'there must be at least one relationship "{document_id} DESCRIBES ..." or "... DESCRIBED_BY {document_id}"',
                ValidationContext(spdx_id=document_id,
                                  element_type=SpdxElementType.DOCUMENT)))

    return validation_messages

src/validation/creation_info_validator.py METASEP
#  Copyright (c) 2022 spdx contributors
#  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.

import re
from typing import List

from src.model.document import CreationInfo
from src.validation.actor_validator import validate_actors
from src.validation.external_document_ref_validator import validate_external_document_refs
from src.validation.uri_validators import validate_uri
from src.validation.validation_message import ValidationMessage, ValidationContext, SpdxElementType


def validate_creation_info(creation_info: CreationInfo) -> List[ValidationMessage]:
    validation_messages: List[ValidationMessage] = []

    context = ValidationContext(spdx_id=creation_info.spdx_id, element_type=SpdxElementType.DOCUMENT)

    if not re.match(r"^SPDX-\d+.\d+$", creation_info.spdx_version):
        validation_messages.append(
            ValidationMessage(
                f'spdx_version must be of the form "SPDX-[major].[minor]" but is: {creation_info.spdx_version}',
                context
            )
        )

    if creation_info.spdx_id != "SPDXRef-DOCUMENT":
        validation_messages.append(
            ValidationMessage(
                f'spdx_id must be "SPDXRef-DOCUMENT", but is: {creation_info.spdx_id}',
                context
            )
        )

    if creation_info.data_license != "CC0-1.0":
        validation_messages.append(
            ValidationMessage(
                f'data_license must be "CC0-1.0", but is: {creation_info.data_license}',
                context
            )
        )

    for message in validate_uri(creation_info.document_namespace):
        validation_messages.append(
            ValidationMessage(
                "document_namespace " + message, context
            )
        )

    validation_messages.extend(validate_actors(creation_info.creators, creation_info.spdx_id))

    validation_messages.extend(validate_external_document_refs(creation_info.external_document_refs, creation_info.spdx_id))

    return validation_messages

src/validation/checksum_validator.py METASEP
#  Copyright (c) 2022 spdx contributors
#  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.

import re
from typing import List, Dict

from src.model.checksum import Checksum, ChecksumAlgorithm
from src.validation.validation_message import ValidationMessage, ValidationContext, SpdxElementType

# in hexadecimal digits
algorithm_length: Dict = {
    ChecksumAlgorithm.SHA1: "40",
    ChecksumAlgorithm.SHA224: "56",
    ChecksumAlgorithm.SHA256: "64",
    ChecksumAlgorithm.SHA384: "96",
    ChecksumAlgorithm.SHA512: "128",
    ChecksumAlgorithm.SHA3_256: "64",
    ChecksumAlgorithm.SHA3_384: "96",
    ChecksumAlgorithm.SHA3_512: "128",
    ChecksumAlgorithm.BLAKE2B_256: "64",
    ChecksumAlgorithm.BLAKE2B_384: "96",
    ChecksumAlgorithm.BLAKE2B_512: "128",
    ChecksumAlgorithm.BLAKE3: "256,",  # at least 256 bits
    ChecksumAlgorithm.MD2: "32",
    ChecksumAlgorithm.MD4: "32",
    ChecksumAlgorithm.MD5: "32",
    ChecksumAlgorithm.MD6: "0,512",  # between 0 and 512 bits
    ChecksumAlgorithm.ADLER32: "8",
}


def validate_checksums(checksums: List[Checksum], parent_id: str) -> List[ValidationMessage]:
    validation_messages = []
    for checksum in checksums:
        validation_messages.extend(validate_checksum(checksum, parent_id))

    return validation_messages


def validate_checksum(checksum: Checksum, parent_id: str) -> List[ValidationMessage]:
    validation_messages = []
    algorithm = checksum.algorithm
    context = ValidationContext(parent_id=parent_id, element_type=SpdxElementType.CHECKSUM,
                                full_element=checksum)

    if not re.match("^[0-9a-f]{" + algorithm_length[algorithm] + "}$", checksum.value):
        if algorithm == ChecksumAlgorithm.BLAKE3:
            length = "at least 256"
        elif algorithm == ChecksumAlgorithm.MD6:
            length = "between 0 and 512"
        else:
            length = algorithm_length[algorithm]
        validation_messages.append(
            ValidationMessage(
                f"value of {algorithm} must consist of {length} hexadecimal digits, but is: {checksum.value} (length: {len(checksum.value)} digits)",
                context)
        )

    return validation_messages

src/validation/annotation_validator.py METASEP
#  Copyright (c) 2022 spdx contributors
#  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.

from typing import List

from src.model.annotation import Annotation
from src.model.document import Document
from src.validation.actor_validator import validate_actor
from src.validation.spdx_id_validators import validate_spdx_id
from src.validation.validation_message import ValidationMessage, ValidationContext, SpdxElementType


def validate_annotations(annotations: List[Annotation], document: Document) -> List[ValidationMessage]:
    validation_messages = []
    for annotation in annotations:
        validation_messages.extend(validate_annotation(annotation, document))

    return validation_messages


def validate_annotation(annotation: Annotation, document: Document) -> List[ValidationMessage]:
    validation_messages = []
    context = ValidationContext(element_type=SpdxElementType.ANNOTATION,
                                full_element=annotation)

    validation_messages.extend(validate_actor(annotation.annotator, "annotation"))

    messages: List[str] = validate_spdx_id(annotation.spdx_id, document, check_document=True)
    for message in messages:
        validation_messages.append(ValidationMessage(message, context))

    return validation_messages

src/validation/actor_validator.py METASEP
#  Copyright (c) 2022 spdx contributors
#  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.

from typing import List

from src.model.actor import Actor, ActorType
from src.validation.validation_message import ValidationMessage, ValidationContext, SpdxElementType


def validate_actors(actors: List[Actor], parent_id: str) -> List[ValidationMessage]:
    validation_messages = []
    for actor in actors:
        validation_messages.extend(validate_actor(actor, parent_id))

    return validation_messages


def validate_actor(actor: Actor, parent_id: str) -> List[ValidationMessage]:
    validation_messages = []

    if actor.actor_type == ActorType.TOOL and actor.email is not None:
        validation_messages.append(
            ValidationMessage(
                f"email must be None if actor_type is TOOL, but is: {actor.email}",
                ValidationContext(parent_id=parent_id, element_type=SpdxElementType.ACTOR, full_element=actor)
            )
        )

    return validation_messages

src/validation/__init__.py METASEP

src/model/version.py METASEP
# Copyright (c) 2022 spdx contributors
# 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.


import re
from re import Pattern


class Version:
    VERSION_REGEX: Pattern = re.compile(r"^(\d+)\.(\d+)$")

    major: int
    minor: int

    @classmethod
    def is_valid_version_string(cls, value: str) -> bool:
        return cls.VERSION_REGEX.match(value) is not None

    # No type hint for Python reasons.
    # See https://stackoverflow.com/questions/33533148/how-do-i-type-hint-a-method-with-the-type-of-the-enclosing-class
    @classmethod
    def from_string(cls, value: str):
        if not Version.is_valid_version_string(value):
            raise ValueError(f"{value} is not a valid version string")

        match = cls.VERSION_REGEX.match(value)
        return cls(int(match.group(1)), int(match.group(2)))

    def __init__(self, major: int, minor: int):
        self.major = major
        self.minor = minor

    def __str__(self):
        return f"{self.major}.{self.minor}"

    def __eq__(self, other):
        if not isinstance(other, Version):
            return False
        return self.major == other.major and self.minor == other.minor

src/model/spdx_none.py METASEP
# Copyright (c) 2022 spdx contributors
# 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.


class SpdxNone:
    """
    Represents the SPDX NONE value.
    """

    _string_value = "NONE"

    def __str__(self):
        return self._string_value

    def __repr__(self):
        return self._string_value

    def __eq__(self, other):
        return isinstance(other, SpdxNone)

src/model/spdx_no_assertion.py METASEP
# Copyright (c) 2022 spdx contributors
# 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.


class SpdxNoAssertion:
    """
    Represents the SPDX NOASSERTION value.
    """

    _string_value: str = "NOASSERTION"

    def __str__(self):
        return self._string_value

    def __repr__(self):
        return self._string_value

    def __eq__(self, other):
        return isinstance(other, SpdxNoAssertion)

src/model/snippet.py METASEP
# Copyright (c) 2022 spdx contributors
# 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.
from dataclasses import field
from typing import Tuple, Optional, List, Union

from src.model.typing.dataclass_with_properties import dataclass_with_properties
from src.model.license_expression import LicenseExpression
from src.model.spdx_no_assertion import SpdxNoAssertion
from src.model.spdx_none import SpdxNone
from src.model.typing.type_checks import check_types_and_set_values


@dataclass_with_properties
class Snippet:
    spdx_id: str
    file_spdx_id: str
    byte_range: Tuple[int, int]
    line_range: Optional[Tuple[int, int]] = None
    concluded_license: Optional[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]] = None
    license_info_in_snippet: Optional[Union[List[LicenseExpression], SpdxNoAssertion, SpdxNone]] = None
    license_comment: Optional[str] = None
    copyright_text: Optional[str] = None
    comment: Optional[str] = None
    name: Optional[str] = None
    attribution_texts: List[str] = field(default_factory=list)

    def __init__(self, spdx_id: str, file_spdx_id: str, byte_range: Tuple[int, int],
                 line_range: Optional[Tuple[int, int]] = None,
                 concluded_license: Optional[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]] = None,
                 license_info_in_snippet: Optional[Union[List[LicenseExpression], SpdxNoAssertion, SpdxNone]] = None,
                 license_comment: Optional[str] = None, copyright_text: Optional[str] = None,
                 comment: Optional[str] = None, name: Optional[str] = None, attribution_texts: List[str] = None):
        attribution_texts = [] if attribution_texts is None else attribution_texts
        check_types_and_set_values(self, locals())

src/model/relationship.py METASEP
# Copyright (c) 2022 spdx contributors
# 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.
from enum import auto, Enum
from typing import Optional

from src.model.typing.dataclass_with_properties import dataclass_with_properties
from src.model.typing.type_checks import check_types_and_set_values


class RelationshipType(Enum):
    AMENDS = auto()
    ANCESTOR_OF = auto()
    BUILD_DEPENDENCY_OF = auto()
    BUILD_TOOL_OF = auto()
    CONTAINED_BY = auto()
    CONTAINS = auto()
    COPY_OF = auto()
    DATA_FILE_OF = auto()
    DEPENDENCY_MANIFEST_OF = auto()
    DEPENDENCY_OF = auto()
    DEPENDS_ON = auto()
    DESCENDANT_OF = auto()
    DESCRIBED_BY = auto()
    DESCRIBES = auto()
    DEV_DEPENDENCY_OF = auto()
    DEV_TOOL_OF = auto()
    DISTRIBUTION_ARTIFACT = auto()
    DOCUMENTATION_OF = auto()
    DYNAMIC_LINK = auto()
    EXAMPLE_OF = auto()
    EXPANDED_FROM_ARCHIVE = auto()
    FILE_ADDED = auto()
    FILE_DELETED = auto()
    FILE_MODIFIED = auto()
    GENERATED_FROM = auto()
    GENERATES = auto()
    HAS_PREREQUISITE = auto()
    METAFILE_OF = auto()
    OPTIONAL_COMPONENT_OF = auto()
    OPTIONAL_DEPENDENCY_OF = auto()
    OTHER = auto()
    PACKAGE_OF = auto()
    PATCH_APPLIED = auto()
    PATCH_FOR = auto()
    PREREQUISITE_FOR = auto()
    PROVIDED_DEPENDENCY_OF = auto()
    REQUIREMENT_DESCRIPTION_FOR = auto()
    RUNTIME_DEPENDENCY_OF = auto()
    SPECIFICATION_FOR = auto()
    STATIC_LINK = auto()
    TEST_CASE_OF = auto()
    TEST_DEPENDENCY_OF = auto()
    TEST_OF = auto()
    TEST_TOOL_OF = auto()
    VARIANT_OF = auto()


@dataclass_with_properties
class Relationship:
    spdx_element_id: str
    relationship_type: RelationshipType
    related_spdx_element_id: str
    comment: Optional[str] = None

    def __init__(self, spdx_element_id: str, relationship_type: RelationshipType, related_spdx_element_id: str,
                 comment: Optional[str] = None):
        check_types_and_set_values(self, locals())

src/model/package.py METASEP
# Copyright (c) 2022 spdx contributors
# 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.
from dataclasses import field
from datetime import datetime
from enum import Enum, auto
from typing import Optional, Union, List

from src.model.actor import Actor
from src.model.checksum import Checksum
from src.model.typing.dataclass_with_properties import dataclass_with_properties
from src.model.license_expression import LicenseExpression
from src.model.spdx_no_assertion import SpdxNoAssertion
from src.model.spdx_none import SpdxNone
from src.model.typing.type_checks import check_types_and_set_values


class PackagePurpose(Enum):
    APPLICATION = auto()
    FRAMEWORK = auto()
    LIBRARY = auto()
    CONTAINER = auto()
    OPERATING_SYSTEM = auto()
    DEVICE = auto()
    FIRMWARE = auto()
    SOURCE = auto()
    ARCHIVE = auto()
    FILE = auto()
    INSTALL = auto()
    OTHER = auto()


@dataclass_with_properties
class PackageVerificationCode:
    value: str
    excluded_files: List[str] = field(default_factory=list)

    def __init__(self, value: str, excluded_files: List[str] = None):
        excluded_files = [] if excluded_files is None else excluded_files
        check_types_and_set_values(self, locals())


class ExternalPackageRefCategory(Enum):
    SECURITY = auto()
    PACKAGE_MANAGER = auto()
    PERSISTENT_ID = auto()
    OTHER = auto()


@dataclass_with_properties
class ExternalPackageRef:
    category: ExternalPackageRefCategory
    # In theory, once could refine the typing,
    # see https://spdx.github.io/spdx-spec/v2.3/external-repository-identifiers/. But it's probably not worth the
    # effort.
    reference_type: str
    locator: str
    comment: Optional[str] = None

    def __init__(self, category: ExternalPackageRefCategory, reference_type: str, locator: str,
                 comment: Optional[str] = None):
        check_types_and_set_values(self, locals())


@dataclass_with_properties
class Package:
    spdx_id: str
    name: str
    download_location: Union[str, SpdxNoAssertion, SpdxNone]
    version: Optional[str] = None
    file_name: Optional[str] = None
    supplier: Optional[Union[Actor, SpdxNoAssertion]] = None
    originator: Optional[Union[Actor, SpdxNoAssertion]] = None
    files_analyzed: bool = True
    verification_code: Optional[PackageVerificationCode] = None
    checksums: List[Checksum] = field(default_factory=list)
    homepage: Optional[Union[str, SpdxNoAssertion, SpdxNone]] = None
    source_info: Optional[str] = None
    license_concluded: Optional[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]] = None
    license_info_from_files: Optional[Union[List[LicenseExpression], SpdxNoAssertion, SpdxNone]] = field(
        default_factory=list)
    license_declared: Optional[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]] = None
    license_comment: Optional[str] = None
    copyright_text: Optional[Union[str, SpdxNoAssertion, SpdxNone]] = None
    summary: Optional[str] = None
    description: Optional[str] = None
    comment: Optional[str] = None
    external_references: List[ExternalPackageRef] = field(default_factory=list)
    attribution_texts: List[str] = field(default_factory=list)
    primary_package_purpose: Optional[PackagePurpose] = None
    release_date: Optional[datetime] = None
    built_date: Optional[datetime] = None
    valid_until_date: Optional[datetime] = None

    def __init__(self, spdx_id: str, name: str, download_location: Union[str, SpdxNoAssertion, SpdxNone],
                 version: Optional[str] = None, file_name: Optional[str] = None,
                 supplier: Optional[Union[Actor, SpdxNoAssertion]] = None,
                 originator: Optional[Union[Actor, SpdxNoAssertion]] = None,
                 files_analyzed: bool = True, verification_code: Optional[PackageVerificationCode] = None,
                 checksums: List[Checksum] = None, homepage: Optional[Union[str, SpdxNoAssertion, SpdxNone]] = None,
                 source_info: Optional[str] = None,
                 license_concluded: Optional[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]] = None,
                 license_info_from_files: Optional[Union[List[LicenseExpression], SpdxNoAssertion, SpdxNone]] = None,
                 license_declared: Optional[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]] = None,
                 license_comment: Optional[str] = None,
                 copyright_text: Optional[Union[str, SpdxNoAssertion, SpdxNone]] = None,
                 summary: Optional[str] = None, description: Optional[str] = None, comment: Optional[str] = None,
                 external_references: List[ExternalPackageRef] = None, attribution_texts: List[str] = None,
                 primary_package_purpose: Optional[PackagePurpose] = None, release_date: Optional[datetime] = None,
                 built_date: Optional[datetime] = None, valid_until_date: Optional[datetime] = None):
        checksums = [] if checksums is None else checksums
        license_info_from_files = [] if license_info_from_files is None else license_info_from_files
        external_references = [] if external_references is None else external_references
        attribution_texts = [] if attribution_texts is None else attribution_texts
        check_types_and_set_values(self, locals())

src/model/license_expression.py METASEP
# Copyright (c) 2022 spdx contributors
# 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.

from src.model.typing.dataclass_with_properties import dataclass_with_properties
from src.model.typing.type_checks import check_types_and_set_values


@dataclass_with_properties
class LicenseExpression:
    """So far, this just holds a string with the license expression. The ticket for adding license expression support
    is https://github.com/spdx/tools-python/issues/10."""
    expression_string: str

    def __init__(self, expression_string: str):
        check_types_and_set_values(self, locals())

src/model/license.py METASEP
# Copyright (c) 2022 spdx contributors
# 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.


from src import config


def determine_full_name(identifier: str, full_name: str):
    if full_name is not None:
        return full_name
    # Note: the license map contains both the ids and names of licenses as keys, with the name resp. id as value
    if identifier in config.LICENSE_MAP:
        return config.LICENSE_MAP[identifier]
    return identifier


def determine_identifier(identifier: str, full_name: str):
    if identifier is not None:
        return identifier
    # Note: the license map contains both the ids and names of licenses as keys, with the name resp. id as value
    if full_name in config.LICENSE_MAP:
        return config.LICENSE_MAP[full_name]
    return full_name


class License:
    identifier: str
    full_name: str

    def __init__(self, identifier: str = None, full_name: str = None):
        """Create a new license from identifier, full name or both. If only either identifier or full name is
        provided, we try to retrieve the other value from the list of known licenses. If the license is unknown and
        only one value is provided, both identifier and full name are set to this value."""
        if identifier is None and full_name is None:
            raise ValueError("Must provide either identifier or full name for a license")
        self.identifier = determine_identifier(identifier, full_name)
        self.full_name = determine_full_name(identifier, full_name)

src/model/file.py METASEP
# Copyright (c) 2022 spdx contributors
# 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.
from dataclasses import field
from enum import Enum, auto
from typing import Optional, List, Union

from src.model.checksum import Checksum
from src.model.typing.dataclass_with_properties import dataclass_with_properties
from src.model.license_expression import LicenseExpression
from src.model.spdx_no_assertion import SpdxNoAssertion
from src.model.spdx_none import SpdxNone
from src.model.typing.type_checks import check_types_and_set_values


class FileType(Enum):
    SOURCE = auto()
    BINARY = auto()
    ARCHIVE = auto()
    APPLICATION = auto()
    AUDIO = auto()
    IMAGE = auto()
    TEXT = auto()
    VIDEO = auto()
    DOCUMENTATION = auto()
    SPDX = auto()
    OTHER = auto()


@dataclass_with_properties
class File:
    name: str
    spdx_id: str
    checksums: List[Checksum]
    file_type: List[FileType] = field(default_factory=list)
    concluded_license: Optional[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]] = None
    license_info_in_file: Optional[Union[List[LicenseExpression], SpdxNoAssertion, SpdxNone]] = field(
        default_factory=list)
    license_comment: Optional[str] = None
    copyright_text: Optional[Union[str, SpdxNoAssertion, SpdxNone]] = None
    comment: Optional[str] = None
    notice: Optional[str] = None
    contributors: List[str] = field(default_factory=list)
    attribution_texts: List[str] = field(default_factory=list)

    # Deprecated properties that should be replaced during parsing:
    # - file dependencies: replace by a DEPENDENCY_OF relationship (or one of the more precise versions)
    # - artifact of (3 properties): replace by an external package reference and a GENERATED_FROM relationship
    #   between the file and this package

    def __init__(self, name: str, spdx_id: str, checksums: List[Checksum], file_type: List[FileType] = None,
                 concluded_license: Optional[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]] = None,
                 license_info_in_file: Optional[Union[List[LicenseExpression], SpdxNoAssertion, SpdxNone]] = None,
                 license_comment: Optional[str] = None,
                 copyright_text: Optional[Union[str, SpdxNoAssertion, SpdxNone]] = None,
                 comment: str = None, notice: Optional[str] = None,
                 contributors: List[str] = None, attribution_texts: List[str] = None):
        file_type = [] if file_type is None else file_type
        license_info_in_file = [] if license_info_in_file is None else license_info_in_file
        contributors = [] if contributors is None else contributors
        attribution_texts = [] if attribution_texts is None else attribution_texts
        check_types_and_set_values(self, locals())

src/model/extracted_licensing_info.py METASEP
# Copyright (c) 2022 spdx contributors
# 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.
from dataclasses import field
from typing import Optional, List, Union

from src.model.spdx_no_assertion import SpdxNoAssertion
from src.model.typing.dataclass_with_properties import dataclass_with_properties
from src.model.typing.type_checks import check_types_and_set_values


@dataclass_with_properties
class ExtractedLicensingInfo:
    license_id: Optional[str] = None
    extracted_text: Optional[str] = None
    license_name: Optional[Union[str, SpdxNoAssertion]] = None
    cross_references: List[str] = field(default_factory=list)
    comment: Optional[str] = None

    def __init__(self, license_id: Optional[str] = None, extracted_text: Optional[str] = None,
                 license_name: Optional[Union[str, SpdxNoAssertion]] = None, cross_references: List[str] = None,
                 comment: Optional[str] = None):
        cross_references = [] if cross_references is None else cross_references
        check_types_and_set_values(self, locals())

src/model/external_document_ref.py METASEP
# Copyright (c) 2022 spdx contributors
# 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.

from src.model.checksum import Checksum
from src.model.typing.dataclass_with_properties import dataclass_with_properties
from src.model.typing.type_checks import check_types_and_set_values


@dataclass_with_properties
class ExternalDocumentRef:
    document_ref_id: str  # of the form "DocumentRef-[idstring]"
    document_uri: str
    checksum: Checksum

    def __init__(self, document_ref_id: str, document_uri: str, checksum: Checksum):
        check_types_and_set_values(self, locals())

src/model/document.py METASEP
# Copyright (c) 2022 spdx contributors
# 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.
from dataclasses import field
from datetime import datetime
from typing import List, Optional

from src.model.actor import Actor
from src.model.annotation import Annotation
from src.model.typing.dataclass_with_properties import dataclass_with_properties
from src.model.external_document_ref import ExternalDocumentRef
from src.model.extracted_licensing_info import ExtractedLicensingInfo
from src.model.file import File
from src.model.package import Package
from src.model.relationship import Relationship
from src.model.snippet import Snippet
from src.model.typing.type_checks import check_types_and_set_values
from src.model.version import Version


@dataclass_with_properties
class CreationInfo:
    spdx_version: str
    spdx_id: str
    name: str
    document_namespace: str
    creators: List[Actor]
    created: datetime
    creator_comment: Optional[str] = None
    data_license: str = "CC0-1.0"
    external_document_refs: List[ExternalDocumentRef] = field(default_factory=list)
    license_list_version: Optional[Version] = None
    document_comment: Optional[str] = None

    def __init__(self, spdx_version: str, spdx_id: str, name: str, document_namespace: str, creators: List[Actor],
                 created: datetime, creator_comment: Optional[str] = None, data_license: str = "CC0-1.0",
                 external_document_refs: List[ExternalDocumentRef] = None,
                 license_list_version: Optional[Version] = None, document_comment: Optional[str] = None):
        external_document_refs = [] if external_document_refs is None else external_document_refs
        check_types_and_set_values(self, locals())


@dataclass_with_properties
class Document:
    creation_info: CreationInfo

    packages: List[Package] = field(default_factory=list)
    files: List[File] = field(default_factory=list)
    snippets: List[Snippet] = field(default_factory=list)
    annotations: List[Annotation] = field(default_factory=list)
    relationships: List[Relationship] = field(default_factory=list)
    extracted_licensing_info: List[ExtractedLicensingInfo] = field(default_factory=list)

    def __init__(self, creation_info: CreationInfo, packages: List[Package] = None, files: List[File] = None,
                 snippets: List[Snippet] = None, annotations: List[Annotation] = None,
                 relationships: List[Relationship] = None,
                 extracted_licensing_info: List[ExtractedLicensingInfo] = None):
        packages = [] if packages is None else packages
        files = [] if files is None else files
        snippets = [] if snippets is None else snippets
        annotations = [] if annotations is None else annotations
        relationships = [] if relationships is None else relationships
        extracted_licensing_info = [] if extracted_licensing_info is None else extracted_licensing_info
        check_types_and_set_values(self, locals())

src/model/checksum.py METASEP
# Copyright (c) 2022 spdx contributors
# 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.
from enum import auto, Enum

from src.model.typing.dataclass_with_properties import dataclass_with_properties
from src.model.typing.type_checks import check_types_and_set_values


class ChecksumAlgorithm(Enum):
    SHA1 = auto()
    SHA224 = auto()
    SHA256 = auto()
    SHA384 = auto()
    SHA512 = auto()
    SHA3_256 = auto()
    SHA3_384 = auto()
    SHA3_512 = auto()
    BLAKE2B_256 = auto()
    BLAKE2B_384 = auto()
    BLAKE2B_512 = auto()
    BLAKE3 = auto()
    MD2 = auto()
    MD4 = auto()
    MD5 = auto()
    MD6 = auto()
    ADLER32 = auto()


@dataclass_with_properties
class Checksum:
    algorithm: ChecksumAlgorithm
    value: str

    def __init__(self, algorithm: ChecksumAlgorithm, value: str):
        check_types_and_set_values(self, locals())

src/model/annotation.py METASEP
# Copyright (c) 2022 spdx contributors
# 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.
from datetime import datetime
from enum import Enum, auto

from src.model.actor import Actor
from src.model.typing.dataclass_with_properties import dataclass_with_properties
from src.model.typing.type_checks import check_types_and_set_values


class AnnotationType(Enum):
    REVIEW = auto()
    OTHER = auto()


@dataclass_with_properties
class Annotation:
    spdx_id: str
    annotation_type: AnnotationType
    annotator: Actor
    annotation_date: datetime
    annotation_comment: str

    def __init__(self, spdx_id: str, annotation_type: AnnotationType, annotator: Actor, annotation_date: datetime,
                 annotation_comment: str):
        check_types_and_set_values(self, locals())

src/model/actor.py METASEP
# Copyright (c) 2022 spdx contributors
# 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.
from enum import Enum, auto
from typing import Optional

from src.model.typing.dataclass_with_properties import dataclass_with_properties
from src.model.typing.type_checks import check_types_and_set_values


class ActorType(Enum):
    PERSON = auto()
    ORGANIZATION = auto()
    TOOL = auto()


@dataclass_with_properties
class Actor:
    actor_type: ActorType
    name: str
    email: Optional[str] = None

    def __init__(self, actor_type: ActorType, name: str, email: Optional[str] = None):
        check_types_and_set_values(self, locals())

src/model/__init__.py METASEP

src/clitools/parser.py METASEP
#!/usr/bin/env python3

# Copyright (c) 2020 Yash Varshney
# 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.

import click

from src.model.spdx_no_assertion import SpdxNoAssertion
from src.model.spdx_none import SpdxNone


@click.command()
@click.option("--file", prompt="File name", help="The file to be parsed")
@click.option("--force", is_flag=True, help="print information even if there are some parsing errors")
def main(file, force):
    """
    COMMAND-LINE TOOL for parsing file of RDF, XML, JSON, YAML and XML format.

    To use : run `pyspdxtools_parser` using terminal or run `pyspdxtools_parser --file <file name>`

    """
    raise NotImplementedError("Currently, no parsers are implemented")

    # Parse document
    # First one to implement is the Json parser: https://github.com/spdx/tools-python/issues/305

    # Print all document properties - or possibly a selection of them. Should be human-readable, so using indentation
    # for nested properties is probably a good idea.


if __name__ == "__main__":
    main()

src/clitools/convertor.py METASEP
#!/usr/bin/env python3

# Copyright (c) 2020 Yash Varshney
# 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.

import os

import click


def print_help_msg(command):
    with click.Context(command) as ctx:
        click.echo(command.get_help(ctx))


def determine_infile_and_outfile(infile, outfile, src, from_, to):
    if infile is not None and outfile is not None:
        """
        when the CLI is of given format:
        ' pyspdxtools_convertor ---infile <input_file> ---outfile <output_file>.
        """
        return infile, outfile

    elif infile is None and outfile is None and len(src) == 2:
        """
        ' pyspdxtools_convertor -f/--from <type> <input_file> -t/--to <type> <output_file>.
        """
        infile = src[0]
        outfile = src[1]
        if from_ is not None:
            infile_path = os.path.splitext(infile)[0]
            infile = infile_path + "." + from_
        if to is not None:
            outfile_path = os.path.splitext(outfile)[0]
            outfile = outfile_path + "." + to
        return infile, outfile

    elif infile is None and outfile is not None:
        """
        ' pyspdxtools_convertor -f/--from <type> <input_file> --outfile <output_file> '
        """
        infile = src[0]
        if from_ is not None:
            infile_path = os.path.splitext(infile)[0]
            infile = infile_path + "." + from_
        return infile, outfile

    elif infile is not None and outfile is None:
        """
        ' pyspdxtools_convertor --infile <input_file> -t/--to <type> <output_file>'
        """
        outfile = src[0]
        if to is not None:
            outfile_path = os.path.splitext(outfile)[0]
            outfile = outfile_path + "." + to
        return infile, outfile

    else:
        raise ValueError("Given arguments for convertor are invalid.")


@click.command()
@click.argument("src", nargs=-1)
@click.option("--infile", "-i", help="The file to be converted ")
@click.option("--outfile", "-o", help="The file after converting")
@click.option(
    "--to",
    "-t",
    type=click.Choice(["json", "rdf", "yaml", "xml", "tag"], case_sensitive=False)
)
@click.option(
    "--from",
    "-f",
    "from_",
    type=click.Choice(["tag", "rdf"], case_sensitive=False))
@click.option("--force", is_flag=True, help="convert even if there are some parsing errors or inconsistencies")
def main(infile, outfile, src, from_, to, force):
    """
    CLI-TOOL for converting a RDF or TAG file to RDF, JSON, YAML, TAG or XML format.

    To use : run 'pyspdxtools_convertor -f <from_TYPE> <input file> -t <to_TYPE> <output_file>' command on terminal
    or use ' pyspdxtools_convertor --infile <input file name> --outfile <output file name> '

    """
    try:
        infile, outfile = determine_infile_and_outfile(infile, outfile, src, from_, to)
    except ValueError as err:
        print(err)
        print_help_msg(main)
        return

    raise NotImplementedError("Currently, conversion is not implemented")

    # Parse document from infile
    # First one to implement is the Json parser: https://github.com/spdx/tools-python/issues/305

    # Write document to outfile
    # First writer to implement is the Json writer: https://github.com/spdx/tools-python/issues/359


if __name__ == "__main__":
    main()

src/clitools/__init__.py METASEP

setup.py METASEP
#!/usr/bin/python

from setuptools import setup

if __name__ == "__main__":
    setup()

src/exceptions.json METASEP
{
    "licenseListVersion": "3.6",
    "releaseDate": "2019-07-10",
    "exceptions": [
        {
            "reference": "./Libtool-exception.html",
            "isDeprecatedLicenseId": false,
            "detailsUrl": "http://spdx.org/licenses/Libtool-exception.json",
            "referenceNumber": "1",
            "name": "Libtool Exception",
            "seeAlso": [
                "http://git.savannah.gnu.org/cgit/libtool.git/tree/m4/libtool.m4"
            ],
            "licenseExceptionId": "Libtool-exception"
        },
        {
            "reference": "./Linux-syscall-note.html",
            "isDeprecatedLicenseId": false,
            "detailsUrl": "http://spdx.org/licenses/Linux-syscall-note.json",
            "referenceNumber": "2",
            "name": "Linux Syscall Note",
            "seeAlso": [
                "https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/COPYING"
            ],
            "licenseExceptionId": "Linux-syscall-note"
        },
        {
            "reference": "./Autoconf-exception-3.0.html",
            "isDeprecatedLicenseId": false,
            "detailsUrl": "http://spdx.org/licenses/Autoconf-exception-3.0.json",
            "referenceNumber": "3",
            "name": "Autoconf exception 3.0",
            "seeAlso": [
                "http://www.gnu.org/licenses/autoconf-exception-3.0.html"
            ],
            "licenseExceptionId": "Autoconf-exception-3.0"
        },
        {
            "reference": "./OCCT-exception-1.0.html",
            "isDeprecatedLicenseId": false,
            "detailsUrl": "http://spdx.org/licenses/OCCT-exception-1.0.json",
            "referenceNumber": "4",
            "name": "Open CASCADE Exception 1.0",
            "seeAlso": [
                "http://www.opencascade.com/content/licensing"
            ],
            "licenseExceptionId": "OCCT-exception-1.0"
        },
        {
            "reference": "./openvpn-openssl-exception.html",
            "isDeprecatedLicenseId": false,
            "detailsUrl": "http://spdx.org/licenses/openvpn-openssl-exception.json",
            "referenceNumber": "5",
            "name": "OpenVPN OpenSSL Exception",
            "seeAlso": [
                "http://openvpn.net/index.php/license.html"
            ],
            "licenseExceptionId": "openvpn-openssl-exception"
        },
        {
            "reference": "./gnu-javamail-exception.html",
            "isDeprecatedLicenseId": false,
            "detailsUrl": "http://spdx.org/licenses/gnu-javamail-exception.json",
            "referenceNumber": "6",
            "name": "GNU JavaMail exception",
            "seeAlso": [
                "http://www.gnu.org/software/classpathx/javamail/javamail.html"
            ],
            "licenseExceptionId": "gnu-javamail-exception"
        },
        {
            "reference": "./OpenJDK-assembly-exception-1.0.html",
            "isDeprecatedLicenseId": false,
            "detailsUrl": "http://spdx.org/licenses/OpenJDK-assembly-exception-1.0.json",
            "referenceNumber": "7",
            "name": "OpenJDK Assembly exception 1.0",
            "seeAlso": [
                "http://openjdk.java.net/legal/assembly-exception.html"
            ],
            "licenseExceptionId": "OpenJDK-assembly-exception-1.0"
        },
        {
            "reference": "./Bison-exception-2.2.html",
            "isDeprecatedLicenseId": false,
            "detailsUrl": "http://spdx.org/licenses/Bison-exception-2.2.json",
            "referenceNumber": "8",
            "name": "Bison exception 2.2",
            "seeAlso": [
                "http://git.savannah.gnu.org/cgit/bison.git/tree/data/yacc.c?id\u003d193d7c7054ba7197b0789e14965b739162319b5e#n141"
            ],
            "licenseExceptionId": "Bison-exception-2.2"
        },
        {
            "reference": "./i2p-gpl-java-exception.html",
            "isDeprecatedLicenseId": false,
            "detailsUrl": "http://spdx.org/licenses/i2p-gpl-java-exception.json",
            "referenceNumber": "9",
            "name": "i2p GPL+Java Exception",
            "seeAlso": [
                "http://geti2p.net/en/get-involved/develop/licenses#java_exception"
            ],
            "licenseExceptionId": "i2p-gpl-java-exception"
        },
        {
            "reference": "./Universal-FOSS-exception-1.0.html",
            "isDeprecatedLicenseId": false,
            "detailsUrl": "http://spdx.org/licenses/Universal-FOSS-exception-1.0.json",
            "referenceNumber": "10",
            "name": "Universal FOSS Exception, Version 1.0",
            "seeAlso": [
                "https://oss.oracle.com/licenses/universal-foss-exception/"
            ],
            "licenseExceptionId": "Universal-FOSS-exception-1.0"
        },
        {
            "reference": "./Qt-LGPL-exception-1.1.html",
            "isDeprecatedLicenseId": false,
            "detailsUrl": "http://spdx.org/licenses/Qt-LGPL-exception-1.1.json",
            "referenceNumber": "11",
            "name": "Qt LGPL exception 1.1",
            "seeAlso": [
                "http://code.qt.io/cgit/qt/qtbase.git/tree/LGPL_EXCEPTION.txt"
            ],
            "licenseExceptionId": "Qt-LGPL-exception-1.1"
        },
        {
            "reference": "./389-exception.html",
            "isDeprecatedLicenseId": false,
            "detailsUrl": "http://spdx.org/licenses/389-exception.json",
            "referenceNumber": "12",
            "name": "389 Directory Server Exception",
            "seeAlso": [
                "http://directory.fedoraproject.org/wiki/GPL_Exception_License_Text"
            ],
            "licenseExceptionId": "389-exception"
        },
        {
            "reference": "./Classpath-exception-2.0.html",
            "isDeprecatedLicenseId": false,
            "detailsUrl": "http://spdx.org/licenses/Classpath-exception-2.0.json",
            "referenceNumber": "13",
            "name": "Classpath exception 2.0",
            "seeAlso": [
                "http://www.gnu.org/software/classpath/license.html",
                "https://fedoraproject.org/wiki/Licensing/GPL_Classpath_Exception"
            ],
            "licenseExceptionId": "Classpath-exception-2.0"
        },
        {
            "reference": "./Fawkes-Runtime-exception.html",
            "isDeprecatedLicenseId": false,
            "detailsUrl": "http://spdx.org/licenses/Fawkes-Runtime-exception.json",
            "referenceNumber": "14",
            "name": "Fawkes Runtime Exception",
            "seeAlso": [
                "http://www.fawkesrobotics.org/about/license/"
            ],
            "licenseExceptionId": "Fawkes-Runtime-exception"
        },
        {
            "reference": "./PS-or-PDF-font-exception-20170817.html",
            "isDeprecatedLicenseId": false,
            "detailsUrl": "http://spdx.org/licenses/PS-or-PDF-font-exception-20170817.json",
            "referenceNumber": "15",
            "name": "PS/PDF font exception (2017-08-17)",
            "seeAlso": [
                "https://github.com/ArtifexSoftware/urw-base35-fonts/blob/65962e27febc3883a17e651cdb23e783668c996f/LICENSE"
            ],
            "licenseExceptionId": "PS-or-PDF-font-exception-20170817"
        },
        {
            "reference": "./Qt-GPL-exception-1.0.html",
            "isDeprecatedLicenseId": false,
            "detailsUrl": "http://spdx.org/licenses/Qt-GPL-exception-1.0.json",
            "referenceNumber": "16",
            "name": "Qt GPL exception 1.0",
            "seeAlso": [
                "http://code.qt.io/cgit/qt/qtbase.git/tree/LICENSE.GPL3-EXCEPT"
            ],
            "licenseExceptionId": "Qt-GPL-exception-1.0"
        },
        {
            "reference": "./LZMA-exception.html",
            "isDeprecatedLicenseId": false,
            "detailsUrl": "http://spdx.org/licenses/LZMA-exception.json",
            "referenceNumber": "17",
            "name": "LZMA exception",
            "seeAlso": [
                "http://nsis.sourceforge.net/Docs/AppendixI.html#I.6"
            ],
            "licenseExceptionId": "LZMA-exception"
        },
        {
            "reference": "./freertos-exception-2.0.html",
            "isDeprecatedLicenseId": false,
            "detailsUrl": "http://spdx.org/licenses/freertos-exception-2.0.json",
            "referenceNumber": "18",
            "name": "FreeRTOS Exception 2.0",
            "seeAlso": [
                "https://web.archive.org/web/20060809182744/http://www.freertos.org/a00114.html"
            ],
            "licenseExceptionId": "freertos-exception-2.0"
        },
        {
            "reference": "./Qwt-exception-1.0.html",
            "isDeprecatedLicenseId": false,
            "detailsUrl": "http://spdx.org/licenses/Qwt-exception-1.0.json",
            "referenceNumber": "19",
            "name": "Qwt exception 1.0",
            "seeAlso": [
                "http://qwt.sourceforge.net/qwtlicense.html"
            ],
            "licenseExceptionId": "Qwt-exception-1.0"
        },
        {
            "reference": "./CLISP-exception-2.0.html",
            "isDeprecatedLicenseId": false,
            "detailsUrl": "http://spdx.org/licenses/CLISP-exception-2.0.json",
            "referenceNumber": "20",
            "name": "CLISP exception 2.0",
            "seeAlso": [
                "http://sourceforge.net/p/clisp/clisp/ci/default/tree/COPYRIGHT"
            ],
            "licenseExceptionId": "CLISP-exception-2.0"
        },
        {
            "reference": "./FLTK-exception.html",
            "isDeprecatedLicenseId": false,
            "detailsUrl": "http://spdx.org/licenses/FLTK-exception.json",
            "referenceNumber": "21",
            "name": "FLTK exception",
            "seeAlso": [
                "http://www.fltk.org/COPYING.php"
            ],
            "licenseExceptionId": "FLTK-exception"
        },
        {
            "reference": "./Bootloader-exception.html",
            "isDeprecatedLicenseId": false,
            "detailsUrl": "http://spdx.org/licenses/Bootloader-exception.json",
            "referenceNumber": "22",
            "name": "Bootloader Distribution Exception",
            "seeAlso": [
                "https://github.com/pyinstaller/pyinstaller/blob/develop/COPYING.txt"
            ],
            "licenseExceptionId": "Bootloader-exception"
        },
        {
            "reference": "./Nokia-Qt-exception-1.1.html",
            "isDeprecatedLicenseId": true,
            "detailsUrl": "http://spdx.org/licenses/Nokia-Qt-exception-1.1.json",
            "referenceNumber": "23",
            "name": "Nokia Qt LGPL exception 1.1",
            "seeAlso": [
                "https://www.keepassx.org/dev/projects/keepassx/repository/revisions/b8dfb9cc4d5133e0f09cd7533d15a4f1c19a40f2/entry/LICENSE.NOKIA-LGPL-EXCEPTION"
            ],
            "licenseExceptionId": "Nokia-Qt-exception-1.1"
        },
        {
            "reference": "./LLVM-exception.html",
            "isDeprecatedLicenseId": false,
            "detailsUrl": "http://spdx.org/licenses/LLVM-exception.json",
            "referenceNumber": "24",
            "name": "LLVM Exception",
            "seeAlso": [
                "http://llvm.org/foundation/relicensing/LICENSE.txt"
            ],
            "licenseExceptionId": "LLVM-exception"
        },
        {
            "reference": "./WxWindows-exception-3.1.html",
            "isDeprecatedLicenseId": false,
            "detailsUrl": "http://spdx.org/licenses/WxWindows-exception-3.1.json",
            "referenceNumber": "25",
            "name": "WxWindows Library Exception 3.1",
            "seeAlso": [
                "http://www.opensource.org/licenses/WXwindows"
            ],
            "licenseExceptionId": "WxWindows-exception-3.1"
        },
        {
            "reference": "./DigiRule-FOSS-exception.html",
            "isDeprecatedLicenseId": false,
            "detailsUrl": "http://spdx.org/licenses/DigiRule-FOSS-exception.json",
            "referenceNumber": "26",
            "name": "DigiRule FOSS License Exception",
            "seeAlso": [
                "http://www.digirulesolutions.com/drupal/foss"
            ],
            "licenseExceptionId": "DigiRule-FOSS-exception"
        },
        {
            "reference": "./Swift-exception.html",
            "isDeprecatedLicenseId": false,
            "detailsUrl": "http://spdx.org/licenses/Swift-exception.json",
            "referenceNumber": "27",
            "name": "Swift Exception",
            "seeAlso": [
                "https://swift.org/LICENSE.txt",
                "https://github.com/apple/swift-package-manager/blob/7ab2275f447a5eb37497ed63a9340f8a6d1e488b/LICENSE.txt#L205"
            ],
            "licenseExceptionId": "Swift-exception"
        },
        {
            "reference": "./GCC-exception-3.1.html",
            "isDeprecatedLicenseId": false,
            "detailsUrl": "http://spdx.org/licenses/GCC-exception-3.1.json",
            "referenceNumber": "28",
            "name": "GCC Runtime Library exception 3.1",
            "seeAlso": [
                "http://www.gnu.org/licenses/gcc-exception-3.1.html"
            ],
            "licenseExceptionId": "GCC-exception-3.1"
        },
        {
            "reference": "./eCos-exception-2.0.html",
            "isDeprecatedLicenseId": false,
            "detailsUrl": "http://spdx.org/licenses/eCos-exception-2.0.json",
            "referenceNumber": "29",
            "name": "eCos exception 2.0",
            "seeAlso": [
                "http://ecos.sourceware.org/license-overview.html"
            ],
            "licenseExceptionId": "eCos-exception-2.0"
        },
        {
            "reference": "./Autoconf-exception-2.0.html",
            "isDeprecatedLicenseId": false,
            "detailsUrl": "http://spdx.org/licenses/Autoconf-exception-2.0.json",
            "referenceNumber": "30",
            "name": "Autoconf exception 2.0",
            "seeAlso": [
                "http://ac-archive.sourceforge.net/doc/copyright.html",
                "http://ftp.gnu.org/gnu/autoconf/autoconf-2.59.tar.gz"
            ],
            "licenseExceptionId": "Autoconf-exception-2.0"
        },
        {
            "reference": "./GPL-CC-1.0.html",
            "isDeprecatedLicenseId": false,
            "detailsUrl": "http://spdx.org/licenses/GPL-CC-1.0.json",
            "referenceNumber": "31",
            "name": "GPL Cooperation Commitment 1.0",
            "seeAlso": [
                "https://github.com/gplcc/gplcc/blob/master/Project/COMMITMENT",
                "https://gplcc.github.io/gplcc/Project/README-PROJECT.html"
            ],
            "licenseExceptionId": "GPL-CC-1.0"
        },
        {
            "reference": "./Font-exception-2.0.html",
            "isDeprecatedLicenseId": false,
            "detailsUrl": "http://spdx.org/licenses/Font-exception-2.0.json",
            "referenceNumber": "32",
            "name": "Font exception 2.0",
            "seeAlso": [
                "http://www.gnu.org/licenses/gpl-faq.html#FontException"
            ],
            "licenseExceptionId": "Font-exception-2.0"
        },
        {
            "reference": "./u-boot-exception-2.0.html",
            "isDeprecatedLicenseId": false,
            "detailsUrl": "http://spdx.org/licenses/u-boot-exception-2.0.json",
            "referenceNumber": "33",
            "name": "U-Boot exception 2.0",
            "seeAlso": [
                "http://git.denx.de/?p\u003du-boot.git;a\u003dblob;f\u003dLicenses/Exceptions"
            ],
            "licenseExceptionId": "u-boot-exception-2.0"
        },
        {
            "reference": "./GCC-exception-2.0.html",
            "isDeprecatedLicenseId": false,
            "detailsUrl": "http://spdx.org/licenses/GCC-exception-2.0.json",
            "referenceNumber": "34",
            "name": "GCC Runtime Library exception 2.0",
            "seeAlso": [
                "https://gcc.gnu.org/git/?p\u003dgcc.git;a\u003dblob;f\u003dgcc/libgcc1.c;h\u003d762f5143fc6eed57b6797c82710f3538aa52b40b;hb\u003dcb143a3ce4fb417c68f5fa2691a1b1b1053dfba9#l10"
            ],
            "licenseExceptionId": "GCC-exception-2.0"
        },
        {
            "reference": "./mif-exception.html",
            "isDeprecatedLicenseId": false,
            "detailsUrl": "http://spdx.org/licenses/mif-exception.json",
            "referenceNumber": "35",
            "name": "Macros and Inline Functions Exception",
            "seeAlso": [
                "http://www.scs.stanford.edu/histar/src/lib/cppsup/exception",
                "http://dev.bertos.org/doxygen/",
                "https://www.threadingbuildingblocks.org/licensing"
            ],
            "licenseExceptionId": "mif-exception"
        },
        {
            "reference": "./OCaml-LGPL-linking-exception.html",
            "isDeprecatedLicenseId": false,
            "detailsUrl": "http://spdx.org/licenses/OCaml-LGPL-linking-exception.json",
            "referenceNumber": "36",
            "name": "OCaml LGPL Linking Exception",
            "seeAlso": [
                "https://caml.inria.fr/ocaml/license.en.html"
            ],
            "licenseExceptionId": "OCaml-LGPL-linking-exception"
        }
    ]
}

src/config.py METASEP
# Copyright (c) 2014 Ahmed H. Ismail
# 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.

import codecs
import json
import os

from src.model.version import Version

_base_dir = os.path.dirname(__file__)
_licenses = os.path.join(_base_dir, "licenses.json")
_exceptions = os.path.join(_base_dir, "exceptions.json")


def _load_list(file_name, object_type="licenses", id_attribute="licenseId"):
    """
    Return a list version tuple and a mapping of licenses
    name->id and id->name loaded from a JSON file
    from https://github.com/spdx/license-list-data
    """
    licenses_map = {}
    with codecs.open(file_name, "rb", encoding="utf-8") as lics:
        licenses = json.load(lics)
    version = tuple(licenses["licenseListVersion"].split("."))
    for lic in licenses[object_type]:
        if lic.get("isDeprecatedLicenseId"):
            continue
        name = lic["name"]
        identifier = lic[id_attribute]
        licenses_map[name] = identifier
        licenses_map[identifier] = name
    return version, licenses_map


def load_license_list(file_name):
    """
    Return the licenses list version tuple and a mapping of licenses
    name->id and id->name loaded from a JSON file
    from https://github.com/spdx/license-list-data
    """
    return _load_list(file_name, object_type="licenses", id_attribute="licenseId")


def load_exception_list(file_name):
    """
    Return the exceptions list version tuple and a mapping of exceptions
    name->id and id->name loaded from a JSON file
    from https://github.com/spdx/license-list-data
    """
    return _load_list(
        file_name, object_type="exceptions", id_attribute="licenseExceptionId"
    )


(_lmajor, _lminor), LICENSE_MAP = load_license_list(_licenses)
LICENSE_LIST_VERSION = Version(major=_lmajor, minor=_lminor)

(_emajor, _eminor), EXCEPTION_MAP = load_exception_list(_exceptions)
EXCEPTION_LIST_VERSION = Version(major=_emajor, minor=_eminor)

assert LICENSE_LIST_VERSION == EXCEPTION_LIST_VERSION
del _emajor, _eminor, EXCEPTION_LIST_VERSION

src/__init__.py METASEP

src/parser/json/package_parser.py METASEP

# Copyright (c) 2022 spdx contributors
# 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.
from datetime import datetime
from typing import Dict, List, Optional, Union

from src.model.actor import Actor
from src.model.checksum import Checksum
from src.model.license_expression import LicenseExpression
from src.model.package import Package, ExternalPackageRef, PackageVerificationCode, PackagePurpose, \
    ExternalPackageRefCategory
from src.model.spdx_no_assertion import SpdxNoAssertion
from src.model.spdx_none import SpdxNone
from src.model.typing.constructor_type_errors import ConstructorTypeErrors
from src.parser.error import SPDXParsingError
from src.parser.json.actor_parser import ActorParser
from src.parser.json.checksum_parser import ChecksumParser
from src.parser.json.dict_parsing_functions import datetime_from_str, parse_optional_field, \
    transform_json_str_to_enum_name
from src.parser.json.license_expression_parser import LicenseExpressionParser
from src.parser.logger import Logger


class PackageParser:
    logger: Logger
    actor_parser: ActorParser
    checksum_parser: ChecksumParser
    license_expression_parser: LicenseExpressionParser

    def __init__(self):
        self.actor_parser = ActorParser()
        self.checksum_parser = ChecksumParser()
        self.license_expression_parser = LicenseExpressionParser()
        self.logger = Logger()

    def parse_packages(self, packages_dict_list: List[Dict]) -> List[Package]:
        packages_list = []
        for package_dict in packages_dict_list:
            try:
                package: Package = self.parse_package(package_dict)
                packages_list.append(package)
            except SPDXParsingError as err:
                self.logger.append_all(err.get_messages())
                continue
        if self.logger.has_messages():
            raise SPDXParsingError(self.logger.get_messages())

        return packages_list

    def parse_package(self, package_dict: Dict) -> Package:
        logger = Logger()
        name: str = package_dict.get("name")
        spdx_id: str = package_dict.get("SPDXID")
        attribution_texts: List[str] = package_dict.get("attributionTexts")
        try:
            built_date: Optional[datetime] = parse_optional_field(package_dict.get("builtDate"), datetime_from_str)
        except ValueError:
            logger.append("ValueError while parsing builtDate.")
            built_date = None
        try:
            checksums: List[Checksum] = parse_optional_field(package_dict.get("checksums"),
                                                             self.checksum_parser.parse_checksums, default=[])
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            checksums = []
        comment: Optional[str] = package_dict.get("comment")
        copyright_text: Optional[str] = package_dict.get("copyrightText")
        description: Optional[str] = package_dict.get("description")
        download_location: Union[str, SpdxNoAssertion, SpdxNone] = self.parse_download_location(
            package_dict.get("downloadLocation"))
        try:
            external_refs: List[ExternalPackageRef] = parse_optional_field(package_dict.get("externalRefs"),
                                                                           self.parse_external_refs)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            external_refs = []
        files_analyzed: Optional[bool] = parse_optional_field(package_dict.get("filesAnalyzed"), default=True)
        homepage: Optional[str] = package_dict.get("homepage")
        license_comments: Optional[str] = package_dict.get("licenseComments")
        try:
            license_concluded: Optional[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]] = parse_optional_field(
                package_dict.get("licenseConcluded"),
                self.license_expression_parser.parse_license_expression)
        except ConstructorTypeErrors as err:
            logger.append_all(err.get_messages())
            license_concluded = None
        try:
            license_declared: Optional[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]] = parse_optional_field(
                package_dict.get("licenseDeclared"),
                self.license_expression_parser.parse_license_expression)
        except ConstructorTypeErrors as err:
            logger.append_all(err.get_messages())
            license_declared = None
        try:
            license_info_from_file: Optional[
                Union[List[LicenseExpression], SpdxNoAssertion, SpdxNone]] = parse_optional_field(
                package_dict.get("licenseInfoFromFiles"),
                self.license_expression_parser.parse_license_expression)
        except ConstructorTypeErrors as err:
            logger.append_all(err.get_messages())
            license_info_from_file = None
        try:
            originator: Optional[Union[Actor, SpdxNoAssertion]] = parse_optional_field(package_dict.get("originator"),
                                                                                       self.actor_parser.parse_actor_or_no_assert)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            originator = None
        package_file_name: Optional[str] = package_dict.get("packageFileName")
        try:
            package_verification_code: Optional[PackageVerificationCode] = parse_optional_field(
                package_dict.get("packageVerificationCode"), self.parse_package_verification_code)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            package_verification_code = None

        try:
            primary_package_purpose: Optional[PackagePurpose] = parse_optional_field(
                package_dict.get("primaryPackagePurpose"), self.parse_primary_package_purpose)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            primary_package_purpose = None

        try:
            release_date: Optional[datetime] = parse_optional_field(package_dict.get("releaseDate"), datetime_from_str)
        except ValueError:
            logger.append("ValueError while parsing releaseDate.")
            release_date = None
        source_info: Optional[str] = package_dict.get("sourceInfo")
        summary: Optional[str] = package_dict.get("summary")
        try:
            supplier: Optional[Union[Actor, SpdxNoAssertion]] = parse_optional_field(package_dict.get("supplier"),
                                                                                     self.actor_parser.parse_actor_or_no_assert)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            supplier = None
        try:
            valid_until_date: Optional[datetime] = parse_optional_field(package_dict.get("validUntilDate"),
                                                                        datetime_from_str)
        except ValueError:
            logger.append("ValueError while parsing validUntilDate.")
            valid_until_date = None

        version_info: Optional[str] = package_dict.get("versionInfo")
        if logger.has_messages():
            raise SPDXParsingError([f"Error while parsing Package {name}: {logger.get_messages()}"])

        try:
            package = Package(spdx_id=spdx_id, name=name, download_location=download_location, version=version_info,
                              file_name=package_file_name, supplier=supplier, originator=originator,
                              files_analyzed=files_analyzed,
                              verification_code=package_verification_code, checksums=checksums, homepage=homepage,
                              source_info=source_info,
                              license_concluded=license_concluded, license_info_from_files=license_info_from_file,
                              license_declared=license_declared,
                              license_comment=license_comments, copyright_text=copyright_text, summary=summary,
                              description=description,
                              comment=comment, external_references=external_refs, attribution_texts=attribution_texts,
                              primary_package_purpose=primary_package_purpose,
                              release_date=release_date, built_date=built_date, valid_until_date=valid_until_date)

        except ConstructorTypeErrors as err:
            raise SPDXParsingError([f"Error while constructing Package {name}: {err.get_messages()}"])

        return package

    def parse_external_refs(self, external_ref_dicts: List[Dict]) -> List[ExternalPackageRef]:
        external_refs = []
        for external_ref_dict in external_ref_dicts:
            try:
                external_ref: ExternalPackageRef = self.parse_external_ref(external_ref_dict)
                external_refs.append(external_ref)
            except SPDXParsingError as err:
                self.logger.append_all(err.get_messages())
        return external_refs

    def parse_external_ref(self, external_ref_dict: Dict) -> ExternalPackageRef:
        logger = Logger()
        try:
infile
# Copyright (c) 2022 spdx contributors
# 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.
from datetime import datetime
from typing import Dict, List, Optional, Union

from src.model.actor import Actor
from src.model.checksum import Checksum
from src.model.license_expression import LicenseExpression
from src.model.package import Package, ExternalPackageRef, PackageVerificationCode, PackagePurpose, \
    ExternalPackageRefCategory
from src.model.spdx_no_assertion import SpdxNoAssertion
from src.model.spdx_none import SpdxNone
from src.model.typing.constructor_type_errors import ConstructorTypeErrors
from src.parser.error import SPDXParsingError
from src.parser.json.actor_parser import ActorParser
from src.parser.json.checksum_parser import ChecksumParser
from src.parser.json.dict_parsing_functions import datetime_from_str, parse_optional_field, \
    transform_json_str_to_enum_name
from src.parser.json.license_expression_parser import LicenseExpressionParser
from src.parser.logger import Logger


class PackageParser:
    logger: Logger
    actor_parser: ActorParser
    checksum_parser: ChecksumParser
    license_expression_parser: LicenseExpressionParser

    def __init__(self):
        self.actor_parser = ActorParser()
        self.checksum_parser = ChecksumParser()
        self.license_expression_parser = LicenseExpressionParser()
        self.logger = Logger()

    def parse_packages(self, packages_dict_list: List[Dict]) -> List[Package]:
        packages_list = []
        for package_dict in packages_dict_list:
            try:
                package: Package = self.parse_package(package_dict)
                packages_list.append(package)
            except SPDXParsingError as err:
                self.logger.append_all(err.get_messages())
                continue
        if self.logger.has_messages():
            raise SPDXParsingError(self.logger.get_messages())

        return packages_list

    def parse_package(self, package_dict: Dict) -> Package:
        logger = Logger()
        name: str = package_dict.get("name")
        spdx_id: str = package_dict.get("SPDXID")
        attribution_texts: List[str] = package_dict.get("attributionTexts")
        try:
            built_date: Optional[datetime] = parse_optional_field(package_dict.get("builtDate"), datetime_from_str)
        except ValueError:
            logger.append("ValueError while parsing builtDate.")
            built_date = None
        try:
            checksums: List[Checksum] = parse_optional_field(package_dict.get("checksums"),
                                                             self.checksum_parser.parse_checksums, default=[])
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            checksums = []
        comment: Optional[str] = package_dict.get("comment")
        copyright_text: Optional[str] = package_dict.get("copyrightText")
        description: Optional[str] = package_dict.get("description")
        download_location: Union[str, SpdxNoAssertion, SpdxNone] = self.parse_download_location(
            package_dict.get("downloadLocation"))
        try:
            external_refs: List[ExternalPackageRef] = parse_optional_field(package_dict.get("externalRefs"),
                                                                           self.parse_external_refs)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            external_refs = []
        files_analyzed: Optional[bool] = parse_optional_field(package_dict.get("filesAnalyzed"), default=True)
        homepage: Optional[str] = package_dict.get("homepage")
        license_comments: Optional[str] = package_dict.get("licenseComments")
        try:
            license_concluded: Optional[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]] = parse_optional_field(
                package_dict.get("licenseConcluded"),
                self.license_expression_parser.parse_license_expression)
        except ConstructorTypeErrors as err:
            logger.append_all(err.get_messages())
            license_concluded = None
        try:
            license_declared: Optional[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]] = parse_optional_field(
                package_dict.get("licenseDeclared"),
                self.license_expression_parser.parse_license_expression)
        except ConstructorTypeErrors as err:
            logger.append_all(err.get_messages())
            license_declared = None
        try:
            license_info_from_file: Optional[
                Union[List[LicenseExpression], SpdxNoAssertion, SpdxNone]] = parse_optional_field(
                package_dict.get("licenseInfoFromFiles"),
                self.license_expression_parser.parse_license_expression)
        except ConstructorTypeErrors as err:
            logger.append_all(err.get_messages())
            license_info_from_file = None
        try:
            originator: Optional[Union[Actor, SpdxNoAssertion]] = parse_optional_field(package_dict.get("originator"),
                                                                                       self.actor_parser.parse_actor_or_no_assert)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            originator = None
        package_file_name: Optional[str] = package_dict.get("packageFileName")
        try:
            package_verification_code: Optional[PackageVerificationCode] = parse_optional_field(
                package_dict.get("packageVerificationCode"), self.parse_package_verification_code)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            package_verification_code = None

        try:
            primary_package_purpose: Optional[PackagePurpose] = parse_optional_field(
infile
# Copyright (c) 2022 spdx contributors
# 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.
from datetime import datetime
from typing import Dict, List, Optional, Union

from src.model.actor import Actor
from src.model.checksum import Checksum
from src.model.license_expression import LicenseExpression
from src.model.package import Package, ExternalPackageRef, PackageVerificationCode, PackagePurpose, \
    ExternalPackageRefCategory
from src.model.spdx_no_assertion import SpdxNoAssertion
from src.model.spdx_none import SpdxNone
from src.model.typing.constructor_type_errors import ConstructorTypeErrors
from src.parser.error import SPDXParsingError
from src.parser.json.actor_parser import ActorParser
from src.parser.json.checksum_parser import ChecksumParser
from src.parser.json.dict_parsing_functions import datetime_from_str, parse_optional_field, \
    transform_json_str_to_enum_name
from src.parser.json.license_expression_parser import LicenseExpressionParser
from src.parser.logger import Logger


class PackageParser:
    logger: Logger
    actor_parser: ActorParser
    checksum_parser: ChecksumParser
    license_expression_parser: LicenseExpressionParser

    def __init__(self):
        self.actor_parser = ActorParser()
        self.checksum_parser = ChecksumParser()
        self.license_expression_parser = LicenseExpressionParser()
        self.logger = Logger()

    def parse_packages(self, packages_dict_list: List[Dict]) -> List[Package]:
        packages_list = []
        for package_dict in packages_dict_list:
            try:
                package: Package = self.parse_package(package_dict)
                packages_list.append(package)
            except SPDXParsingError as err:
                self.logger.append_all(err.get_messages())
                continue
        if self.logger.has_messages():
            raise SPDXParsingError(self.logger.get_messages())

        return packages_list

    def parse_package(self, package_dict: Dict) -> Package:
        logger = Logger()
        name: str = package_dict.get("name")
        spdx_id: str = package_dict.get("SPDXID")
        attribution_texts: List[str] = package_dict.get("attributionTexts")
        try:
            built_date: Optional[datetime] = parse_optional_field(package_dict.get("builtDate"), datetime_from_str)
        except ValueError:
            logger.append("ValueError while parsing builtDate.")
            built_date = None
        try:
            checksums: List[Checksum] = parse_optional_field(package_dict.get("checksums"),
                                                             self.checksum_parser.parse_checksums, default=[])
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            checksums = []
        comment: Optional[str] = package_dict.get("comment")
        copyright_text: Optional[str] = package_dict.get("copyrightText")
        description: Optional[str] = package_dict.get("description")
        download_location: Union[str, SpdxNoAssertion, SpdxNone] = self.parse_download_location(
            package_dict.get("downloadLocation"))
        try:
            external_refs: List[ExternalPackageRef] = parse_optional_field(package_dict.get("externalRefs"),
                                                                           self.parse_external_refs)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            external_refs = []
        files_analyzed: Optional[bool] = parse_optional_field(package_dict.get("filesAnalyzed"), default=True)
        homepage: Optional[str] = package_dict.get("homepage")
        license_comments: Optional[str] = package_dict.get("licenseComments")
        try:
            license_concluded: Optional[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]] = parse_optional_field(
                package_dict.get("licenseConcluded"),
                self.license_expression_parser.parse_license_expression)
        except ConstructorTypeErrors as err:
            logger.append_all(err.get_messages())
            license_concluded = None
        try:
            license_declared: Optional[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]] = parse_optional_field(
                package_dict.get("licenseDeclared"),
                self.license_expression_parser.parse_license_expression)
        except ConstructorTypeErrors as err:
            logger.append_all(err.get_messages())
            license_declared = None
        try:
            license_info_from_file: Optional[
                Union[List[LicenseExpression], SpdxNoAssertion, SpdxNone]] = parse_optional_field(
                package_dict.get("licenseInfoFromFiles"),
                self.license_expression_parser.parse_license_expression)
        except ConstructorTypeErrors as err:
            logger.append_all(err.get_messages())
            license_info_from_file = None
        try:
            originator: Optional[Union[Actor, SpdxNoAssertion]] = parse_optional_field(package_dict.get("originator"),
                                                                                       self.actor_parser.parse_actor_or_no_assert)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            originator = None
        package_file_name: Optional[str] = package_dict.get("packageFileName")
        try:
            package_verification_code: Optional[PackageVerificationCode] = parse_optional_field(
infile
# Copyright (c) 2022 spdx contributors
# 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.
from datetime import datetime
from typing import Dict, List, Optional, Union

from src.model.actor import Actor
from src.model.checksum import Checksum
from src.model.license_expression import LicenseExpression
from src.model.package import Package, ExternalPackageRef, PackageVerificationCode, PackagePurpose, \
    ExternalPackageRefCategory
from src.model.spdx_no_assertion import SpdxNoAssertion
from src.model.spdx_none import SpdxNone
from src.model.typing.constructor_type_errors import ConstructorTypeErrors
from src.parser.error import SPDXParsingError
from src.parser.json.actor_parser import ActorParser
from src.parser.json.checksum_parser import ChecksumParser
from src.parser.json.dict_parsing_functions import datetime_from_str, parse_optional_field, \
    transform_json_str_to_enum_name
from src.parser.json.license_expression_parser import LicenseExpressionParser
from src.parser.logger import Logger


class PackageParser:
    logger: Logger
    actor_parser: ActorParser
    checksum_parser: ChecksumParser
    license_expression_parser: LicenseExpressionParser

    def __init__(self):
        self.actor_parser = ActorParser()
        self.checksum_parser = ChecksumParser()
        self.license_expression_parser = LicenseExpressionParser()
        self.logger = Logger()

    def parse_packages(self, packages_dict_list: List[Dict]) -> List[Package]:
        packages_list = []
        for package_dict in packages_dict_list:
            try:
                package: Package = self.parse_package(package_dict)
                packages_list.append(package)
            except SPDXParsingError as err:
                self.logger.append_all(err.get_messages())
                continue
        if self.logger.has_messages():
            raise SPDXParsingError(self.logger.get_messages())

        return packages_list

    def parse_package(self, package_dict: Dict) -> Package:
        logger = Logger()
        name: str = package_dict.get("name")
        spdx_id: str = package_dict.get("SPDXID")
        attribution_texts: List[str] = package_dict.get("attributionTexts")
        try:
            built_date: Optional[datetime] = parse_optional_field(package_dict.get("builtDate"), datetime_from_str)
        except ValueError:
            logger.append("ValueError while parsing builtDate.")
            built_date = None
        try:
            checksums: List[Checksum] = parse_optional_field(package_dict.get("checksums"),
                                                             self.checksum_parser.parse_checksums, default=[])
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            checksums = []
        comment: Optional[str] = package_dict.get("comment")
        copyright_text: Optional[str] = package_dict.get("copyrightText")
        description: Optional[str] = package_dict.get("description")
        download_location: Union[str, SpdxNoAssertion, SpdxNone] = self.parse_download_location(
            package_dict.get("downloadLocation"))
        try:
            external_refs: List[ExternalPackageRef] = parse_optional_field(package_dict.get("externalRefs"),
infile
# Copyright (c) 2022 spdx contributors
# 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.
from datetime import datetime
from typing import Dict, List, Optional, Union

from src.model.actor import Actor
from src.model.checksum import Checksum
from src.model.license_expression import LicenseExpression
from src.model.package import Package, ExternalPackageRef, PackageVerificationCode, PackagePurpose, \
    ExternalPackageRefCategory
from src.model.spdx_no_assertion import SpdxNoAssertion
from src.model.spdx_none import SpdxNone
from src.model.typing.constructor_type_errors import ConstructorTypeErrors
from src.parser.error import SPDXParsingError
from src.parser.json.actor_parser import ActorParser
from src.parser.json.checksum_parser import ChecksumParser
from src.parser.json.dict_parsing_functions import datetime_from_str, parse_optional_field, \
    transform_json_str_to_enum_name
from src.parser.json.license_expression_parser import LicenseExpressionParser
from src.parser.logger import Logger


class PackageParser:
    logger: Logger
    actor_parser: ActorParser
    checksum_parser: ChecksumParser
    license_expression_parser: LicenseExpressionParser

    def __init__(self):
        self.actor_parser = ActorParser()
        self.checksum_parser = ChecksumParser()
        self.license_expression_parser = LicenseExpressionParser()
        self.logger = Logger()

    def parse_packages(self, packages_dict_list: List[Dict]) -> List[Package]:
        packages_list = []
        for package_dict in packages_dict_list:
            try:
                package: Package = self.parse_package(package_dict)
                packages_list.append(package)
            except SPDXParsingError as err:
                self.logger.append_all(err.get_messages())
                continue
        if self.logger.has_messages():
            raise SPDXParsingError(self.logger.get_messages())

        return packages_list

    def parse_package(self, package_dict: Dict) -> Package:
        logger = Logger()
        name: str = package_dict.get("name")
        spdx_id: str = package_dict.get("SPDXID")
        attribution_texts: List[str] = package_dict.get("attributionTexts")
        try:
            built_date: Optional[datetime] = parse_optional_field(package_dict.get("builtDate"), datetime_from_str)
        except ValueError:
            logger.append("ValueError while parsing builtDate.")
            built_date = None
        try:
            checksums: List[Checksum] = parse_optional_field(package_dict.get("checksums"),
                                                             self.checksum_parser.parse_checksums, default=[])
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            checksums = []
        comment: Optional[str] = package_dict.get("comment")
        copyright_text: Optional[str] = package_dict.get("copyrightText")
        description: Optional[str] = package_dict.get("description")
        download_location: Union[str, SpdxNoAssertion, SpdxNone] = self.parse_download_location(
            package_dict.get("downloadLocation"))
        try:
            external_refs: List[ExternalPackageRef] = parse_optional_field(package_dict.get("externalRefs"),
                                                                           self.parse_external_refs)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            external_refs = []
        files_analyzed: Optional[bool] = parse_optional_field(package_dict.get("filesAnalyzed"), default=True)
        homepage: Optional[str] = package_dict.get("homepage")
        license_comments: Optional[str] = package_dict.get("licenseComments")
        try:
            license_concluded: Optional[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]] = parse_optional_field(
                package_dict.get("licenseConcluded"),
                self.license_expression_parser.parse_license_expression)
        except ConstructorTypeErrors as err:
            logger.append_all(err.get_messages())
            license_concluded = None
        try:
            license_declared: Optional[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]] = parse_optional_field(
                package_dict.get("licenseDeclared"),
                self.license_expression_parser.parse_license_expression)
        except ConstructorTypeErrors as err:
            logger.append_all(err.get_messages())
            license_declared = None
        try:
            license_info_from_file: Optional[
                Union[List[LicenseExpression], SpdxNoAssertion, SpdxNone]] = parse_optional_field(
                package_dict.get("licenseInfoFromFiles"),
                self.license_expression_parser.parse_license_expression)
        except ConstructorTypeErrors as err:
            logger.append_all(err.get_messages())
            license_info_from_file = None
        try:
            originator: Optional[Union[Actor, SpdxNoAssertion]] = parse_optional_field(package_dict.get("originator"),
                                                                                       self.actor_parser.parse_actor_or_no_assert)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            originator = None
        package_file_name: Optional[str] = package_dict.get("packageFileName")
        try:
            package_verification_code: Optional[PackageVerificationCode] = parse_optional_field(
                package_dict.get("packageVerificationCode"), self.parse_package_verification_code)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            package_verification_code = None

        try:
            primary_package_purpose: Optional[PackagePurpose] = parse_optional_field(
                package_dict.get("primaryPackagePurpose"), self.parse_primary_package_purpose)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            primary_package_purpose = None

        try:
            release_date: Optional[datetime] = parse_optional_field(package_dict.get("releaseDate"), datetime_from_str)
        except ValueError:
            logger.append("ValueError while parsing releaseDate.")
            release_date = None
        source_info: Optional[str] = package_dict.get("sourceInfo")
        summary: Optional[str] = package_dict.get("summary")
        try:
inproject
# Copyright (c) 2022 spdx contributors
# 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.
from datetime import datetime
from typing import Dict, List, Optional, Union

from src.model.actor import Actor
from src.model.checksum import Checksum
from src.model.license_expression import LicenseExpression
from src.model.package import Package, ExternalPackageRef, PackageVerificationCode, PackagePurpose, \
inproject
# Copyright (c) 2022 spdx contributors
# 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.
from datetime import datetime
from typing import Dict, List, Optional, Union

from src.model.actor import Actor
from src.model.checksum import Checksum
from src.model.license_expression import LicenseExpression
from src.model.package import Package, ExternalPackageRef, PackageVerificationCode, PackagePurpose, \
    ExternalPackageRefCategory
from src.model.spdx_no_assertion import SpdxNoAssertion
from src.model.spdx_none import SpdxNone
from src.model.typing.constructor_type_errors import ConstructorTypeErrors
from src.parser.error import SPDXParsingError
from src.parser.json.actor_parser import ActorParser
from src.parser.json.checksum_parser import ChecksumParser
from src.parser.json.dict_parsing_functions import datetime_from_str, parse_optional_field, \
    transform_json_str_to_enum_name
from src.parser.json.license_expression_parser import LicenseExpressionParser
from src.parser.logger import Logger


class PackageParser:
    logger: Logger
    actor_parser: ActorParser
    checksum_parser: ChecksumParser
    license_expression_parser: LicenseExpressionParser

    def __init__(self):
        self.actor_parser = ActorParser()
        self.checksum_parser = ChecksumParser()
        self.license_expression_parser = LicenseExpressionParser()
        self.logger = Logger()

    def parse_packages(self, packages_dict_list: List[Dict]) -> List[Package]:
        packages_list = []
        for package_dict in packages_dict_list:
            try:
                package: Package = self.parse_package(package_dict)
                packages_list.append(package)
            except SPDXParsingError as err:
                self.logger.append_all(err.get_messages())
                continue
        if self.logger.has_messages():
            raise SPDXParsingError(self.logger.get_messages())

        return packages_list

    def parse_package(self, package_dict: Dict) -> Package:
        logger = Logger()
        name: str = package_dict.get("name")
        spdx_id: str = package_dict.get("SPDXID")
        attribution_texts: List[str] = package_dict.get("attributionTexts")
        try:
            built_date: Optional[datetime] = parse_optional_field(package_dict.get("builtDate"), datetime_from_str)
        except ValueError:
            logger.append("ValueError while parsing builtDate.")
            built_date = None
        try:
            checksums: List[Checksum] = parse_optional_field(package_dict.get("checksums"),
                                                             self.checksum_parser.parse_checksums, default=[])
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            checksums = []
        comment: Optional[str] = package_dict.get("comment")
        copyright_text: Optional[str] = package_dict.get("copyrightText")
        description: Optional[str] = package_dict.get("description")
        download_location: Union[str, SpdxNoAssertion, SpdxNone] = self.parse_download_location(
            package_dict.get("downloadLocation"))
        try:
            external_refs: List[ExternalPackageRef] = parse_optional_field(package_dict.get("externalRefs"),
                                                                           self.parse_external_refs)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            external_refs = []
        files_analyzed: Optional[bool] = parse_optional_field(package_dict.get("filesAnalyzed"), default=True)
        homepage: Optional[str] = package_dict.get("homepage")
        license_comments: Optional[str] = package_dict.get("licenseComments")
        try:
            license_concluded: Optional[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]] = parse_optional_field(
                package_dict.get("licenseConcluded"),
                self.license_expression_parser.parse_license_expression)
        except ConstructorTypeErrors as err:
            logger.append_all(err.get_messages())
            license_concluded = None
        try:
            license_declared: Optional[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]] = parse_optional_field(
                package_dict.get("licenseDeclared"),
                self.license_expression_parser.parse_license_expression)
        except ConstructorTypeErrors as err:
            logger.append_all(err.get_messages())
            license_declared = None
        try:
            license_info_from_file: Optional[
                Union[List[LicenseExpression], SpdxNoAssertion, SpdxNone]] = parse_optional_field(
                package_dict.get("licenseInfoFromFiles"),
                self.license_expression_parser.parse_license_expression)
        except ConstructorTypeErrors as err:
            logger.append_all(err.get_messages())
            license_info_from_file = None
        try:
            originator: Optional[Union[Actor, SpdxNoAssertion]] = parse_optional_field(package_dict.get("originator"),
                                                                                       self.actor_parser.parse_actor_or_no_assert)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            originator = None
        package_file_name: Optional[str] = package_dict.get("packageFileName")
        try:
            package_verification_code: Optional[PackageVerificationCode] = parse_optional_field(
                package_dict.get("packageVerificationCode"), self.parse_package_verification_code)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            package_verification_code = None

        try:
            primary_package_purpose: Optional[PackagePurpose] = parse_optional_field(
                package_dict.get("primaryPackagePurpose"), self.parse_primary_package_purpose)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            primary_package_purpose = None

        try:
            release_date: Optional[datetime] = parse_optional_field(package_dict.get("releaseDate"), datetime_from_str)
        except ValueError:
            logger.append("ValueError while parsing releaseDate.")
            release_date = None
        source_info: Optional[str] = package_dict.get("sourceInfo")
        summary: Optional[str] = package_dict.get("summary")
        try:
            supplier: Optional[Union[Actor, SpdxNoAssertion]] = parse_optional_field(package_dict.get("supplier"),
                                                                                     self.actor_parser.parse_actor_or_no_assert)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            supplier = None
        try:
            valid_until_date: Optional[datetime] = parse_optional_field(package_dict.get("validUntilDate"),
                                                                        datetime_from_str)
        except ValueError:
            logger.append("ValueError while parsing validUntilDate.")
            valid_until_date = None

        version_info: Optional[str] = package_dict.get("versionInfo")
        if logger.has_messages():
            raise SPDXParsingError([f"Error while parsing Package {name}: {logger.get_messages()}"])

        try:
inproject
# Copyright (c) 2022 spdx contributors
# 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.
from datetime import datetime
from typing import Dict, List, Optional, Union

from src.model.actor import Actor
from src.model.checksum import Checksum
from src.model.license_expression import LicenseExpression
from src.model.package import Package, ExternalPackageRef, PackageVerificationCode, PackagePurpose, \
    ExternalPackageRefCategory
from src.model.spdx_no_assertion import SpdxNoAssertion
from src.model.spdx_none import SpdxNone
from src.model.typing.constructor_type_errors import ConstructorTypeErrors
from src.parser.error import SPDXParsingError
from src.parser.json.actor_parser import ActorParser
from src.parser.json.checksum_parser import ChecksumParser
from src.parser.json.dict_parsing_functions import datetime_from_str, parse_optional_field, \
    transform_json_str_to_enum_name
from src.parser.json.license_expression_parser import LicenseExpressionParser
from src.parser.logger import Logger


class PackageParser:
    logger: Logger
    actor_parser: ActorParser
    checksum_parser: ChecksumParser
    license_expression_parser: LicenseExpressionParser

    def __init__(self):
        self.actor_parser = ActorParser()
        self.checksum_parser = ChecksumParser()
        self.license_expression_parser = LicenseExpressionParser()
        self.logger = Logger()

    def parse_packages(self, packages_dict_list: List[Dict]) -> List[Package]:
        packages_list = []
        for package_dict in packages_dict_list:
            try:
                package: Package = self.parse_package(package_dict)
                packages_list.append(package)
            except SPDXParsingError as err:
                self.logger.append_all(err.get_messages())
                continue
        if self.logger.has_messages():
            raise SPDXParsingError(self.logger.get_messages())

        return packages_list

    def parse_package(self, package_dict: Dict) -> Package:
        logger = Logger()
        name: str = package_dict.get("name")
        spdx_id: str = package_dict.get("SPDXID")
        attribution_texts: List[str] = package_dict.get("attributionTexts")
        try:
            built_date: Optional[datetime] = parse_optional_field(package_dict.get("builtDate"), datetime_from_str)
        except ValueError:
            logger.append("ValueError while parsing builtDate.")
            built_date = None
        try:
            checksums: List[Checksum] = parse_optional_field(package_dict.get("checksums"),
                                                             self.checksum_parser.parse_checksums, default=[])
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            checksums = []
        comment: Optional[str] = package_dict.get("comment")
        copyright_text: Optional[str] = package_dict.get("copyrightText")
        description: Optional[str] = package_dict.get("description")
        download_location: Union[str, SpdxNoAssertion, SpdxNone] = self.parse_download_location(
            package_dict.get("downloadLocation"))
        try:
            external_refs: List[ExternalPackageRef] = parse_optional_field(package_dict.get("externalRefs"),
                                                                           self.parse_external_refs)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            external_refs = []
        files_analyzed: Optional[bool] = parse_optional_field(package_dict.get("filesAnalyzed"), default=True)
        homepage: Optional[str] = package_dict.get("homepage")
        license_comments: Optional[str] = package_dict.get("licenseComments")
        try:
            license_concluded: Optional[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]] = parse_optional_field(
                package_dict.get("licenseConcluded"),
                self.license_expression_parser.parse_license_expression)
        except ConstructorTypeErrors as err:
            logger.append_all(err.get_messages())
            license_concluded = None
        try:
            license_declared: Optional[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]] = parse_optional_field(
                package_dict.get("licenseDeclared"),
                self.license_expression_parser.parse_license_expression)
        except ConstructorTypeErrors as err:
            logger.append_all(err.get_messages())
            license_declared = None
        try:
            license_info_from_file: Optional[
                Union[List[LicenseExpression], SpdxNoAssertion, SpdxNone]] = parse_optional_field(
                package_dict.get("licenseInfoFromFiles"),
                self.license_expression_parser.parse_license_expression)
        except ConstructorTypeErrors as err:
            logger.append_all(err.get_messages())
            license_info_from_file = None
        try:
            originator: Optional[Union[Actor, SpdxNoAssertion]] = parse_optional_field(package_dict.get("originator"),
                                                                                       self.actor_parser.parse_actor_or_no_assert)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            originator = None
        package_file_name: Optional[str] = package_dict.get("packageFileName")
        try:
            package_verification_code: Optional[PackageVerificationCode] = parse_optional_field(
                package_dict.get("packageVerificationCode"), self.parse_package_verification_code)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            package_verification_code = None

        try:
            primary_package_purpose: Optional[PackagePurpose] = parse_optional_field(
                package_dict.get("primaryPackagePurpose"), self.parse_primary_package_purpose)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            primary_package_purpose = None

        try:
            release_date: Optional[datetime] = parse_optional_field(package_dict.get("releaseDate"), datetime_from_str)
        except ValueError:
            logger.append("ValueError while parsing releaseDate.")
            release_date = None
        source_info: Optional[str] = package_dict.get("sourceInfo")
        summary: Optional[str] = package_dict.get("summary")
        try:
            supplier: Optional[Union[Actor, SpdxNoAssertion]] = parse_optional_field(package_dict.get("supplier"),
                                                                                     self.actor_parser.parse_actor_or_no_assert)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            supplier = None
        try:
            valid_until_date: Optional[datetime] = parse_optional_field(package_dict.get("validUntilDate"),
                                                                        datetime_from_str)
        except ValueError:
            logger.append("ValueError while parsing validUntilDate.")
            valid_until_date = None

        version_info: Optional[str] = package_dict.get("versionInfo")
        if logger.has_messages():
            raise SPDXParsingError([f"Error while parsing Package {name}: {logger.get_messages()}"])

        try:
            package = Package(spdx_id=spdx_id, name=name, download_location=download_location, version=version_info,
                              file_name=package_file_name, supplier=supplier, originator=originator,
                              files_analyzed=files_analyzed,
                              verification_code=package_verification_code, checksums=checksums, homepage=homepage,
                              source_info=source_info,
                              license_concluded=license_concluded, license_info_from_files=license_info_from_file,
                              license_declared=license_declared,
                              license_comment=license_comments, copyright_text=copyright_text, summary=summary,
                              description=description,
                              comment=comment, external_references=external_refs, attribution_texts=attribution_texts,
                              primary_package_purpose=primary_package_purpose,
                              release_date=release_date, built_date=built_date, valid_until_date=valid_until_date)

inproject
# Copyright (c) 2022 spdx contributors
# 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.
from datetime import datetime
from typing import Dict, List, Optional, Union

from src.model.actor import Actor
from src.model.checksum import Checksum
from src.model.license_expression import LicenseExpression
from src.model.package import Package, ExternalPackageRef, PackageVerificationCode, PackagePurpose, \
    ExternalPackageRefCategory
from src.model.spdx_no_assertion import SpdxNoAssertion
from src.model.spdx_none import SpdxNone
from src.model.typing.constructor_type_errors import ConstructorTypeErrors
from src.parser.error import SPDXParsingError
from src.parser.json.actor_parser import ActorParser
from src.parser.json.checksum_parser import ChecksumParser
from src.parser.json.dict_parsing_functions import datetime_from_str, parse_optional_field, \
    transform_json_str_to_enum_name
from src.parser.json.license_expression_parser import LicenseExpressionParser
from src.parser.logger import Logger


class PackageParser:
    logger: Logger
    actor_parser: ActorParser
    checksum_parser: ChecksumParser
    license_expression_parser: LicenseExpressionParser

    def __init__(self):
        self.actor_parser = ActorParser()
        self.checksum_parser = ChecksumParser()
        self.license_expression_parser = LicenseExpressionParser()
        self.logger = Logger()

    def parse_packages(self, packages_dict_list: List[Dict]) -> List[Package]:
        packages_list = []
        for package_dict in packages_dict_list:
            try:
inproject
# Copyright (c) 2022 spdx contributors
# 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.
from datetime import datetime
from typing import Dict, List, Optional, Union

from src.model.actor import Actor
from src.model.checksum import Checksum
from src.model.license_expression import LicenseExpression
from src.model.package import Package, ExternalPackageRef, PackageVerificationCode, PackagePurpose, \
    ExternalPackageRefCategory
from src.model.spdx_no_assertion import SpdxNoAssertion
from src.model.spdx_none import SpdxNone
from src.model.typing.constructor_type_errors import ConstructorTypeErrors
from src.parser.error import SPDXParsingError
from src.parser.json.actor_parser import ActorParser
from src.parser.json.checksum_parser import ChecksumParser
from src.parser.json.dict_parsing_functions import datetime_from_str, parse_optional_field, \
    transform_json_str_to_enum_name
from src.parser.json.license_expression_parser import LicenseExpressionParser
from src.parser.logger import Logger


class PackageParser:
    logger: Logger
    actor_parser: ActorParser
    checksum_parser: ChecksumParser
    license_expression_parser: LicenseExpressionParser

    def __init__(self):
        self.actor_parser = ActorParser()
        self.checksum_parser = ChecksumParser()
        self.license_expression_parser = LicenseExpressionParser()
        self.logger = Logger()

    def parse_packages(self, packages_dict_list: List[Dict]) -> List[Package]:
        packages_list = []
        for package_dict in packages_dict_list:
            try:
                package: Package = self.parse_package(package_dict)
                packages_list.append(package)
            except SPDXParsingError as err:
                self.logger.append_all(err.get_messages())
                continue
        if self.logger.has_messages():
            raise SPDXParsingError(self.logger.get_messages())

        return packages_list

    def parse_package(self, package_dict: Dict) -> Package:
        logger = Logger()
        name: str = package_dict.get("name")
        spdx_id: str = package_dict.get("SPDXID")
        attribution_texts: List[str] = package_dict.get("attributionTexts")
        try:
            built_date: Optional[datetime] = parse_optional_field(package_dict.get("builtDate"), datetime_from_str)
        except ValueError:
            logger.append("ValueError while parsing builtDate.")
            built_date = None
        try:
            checksums: List[Checksum] = parse_optional_field(package_dict.get("checksums"),
                                                             self.checksum_parser.parse_checksums, default=[])
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            checksums = []
        comment: Optional[str] = package_dict.get("comment")
        copyright_text: Optional[str] = package_dict.get("copyrightText")
        description: Optional[str] = package_dict.get("description")
        download_location: Union[str, SpdxNoAssertion, SpdxNone] = self.parse_download_location(
            package_dict.get("downloadLocation"))
        try:
            external_refs: List[ExternalPackageRef] = parse_optional_field(package_dict.get("externalRefs"),
                                                                           self.parse_external_refs)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            external_refs = []
        files_analyzed: Optional[bool] = parse_optional_field(package_dict.get("filesAnalyzed"), default=True)
        homepage: Optional[str] = package_dict.get("homepage")
        license_comments: Optional[str] = package_dict.get("licenseComments")
        try:
            license_concluded: Optional[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]] = parse_optional_field(
                package_dict.get("licenseConcluded"),
                self.license_expression_parser.parse_license_expression)
        except ConstructorTypeErrors as err:
            logger.append_all(err.get_messages())
            license_concluded = None
        try:
            license_declared: Optional[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]] = parse_optional_field(
                package_dict.get("licenseDeclared"),
                self.license_expression_parser.parse_license_expression)
        except ConstructorTypeErrors as err:
            logger.append_all(err.get_messages())
            license_declared = None
        try:
            license_info_from_file: Optional[
                Union[List[LicenseExpression], SpdxNoAssertion, SpdxNone]] = parse_optional_field(
                package_dict.get("licenseInfoFromFiles"),
                self.license_expression_parser.parse_license_expression)
        except ConstructorTypeErrors as err:
            logger.append_all(err.get_messages())
            license_info_from_file = None
        try:
            originator: Optional[Union[Actor, SpdxNoAssertion]] = parse_optional_field(package_dict.get("originator"),
                                                                                       self.actor_parser.parse_actor_or_no_assert)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            originator = None
        package_file_name: Optional[str] = package_dict.get("packageFileName")
        try:
            package_verification_code: Optional[PackageVerificationCode] = parse_optional_field(
                package_dict.get("packageVerificationCode"), self.parse_package_verification_code)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            package_verification_code = None

        try:
            primary_package_purpose: Optional[PackagePurpose] = parse_optional_field(
                package_dict.get("primaryPackagePurpose"), self.parse_primary_package_purpose)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            primary_package_purpose = None

        try:
            release_date: Optional[datetime] = parse_optional_field(package_dict.get("releaseDate"), datetime_from_str)
        except ValueError:
            logger.append("ValueError while parsing releaseDate.")
            release_date = None
        source_info: Optional[str] = package_dict.get("sourceInfo")
        summary: Optional[str] = package_dict.get("summary")
        try:
            supplier: Optional[Union[Actor, SpdxNoAssertion]] = parse_optional_field(package_dict.get("supplier"),
                                                                                     self.actor_parser.parse_actor_or_no_assert)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            supplier = None
        try:
            valid_until_date: Optional[datetime] = parse_optional_field(package_dict.get("validUntilDate"),
                                                                        datetime_from_str)
        except ValueError:
            logger.append("ValueError while parsing validUntilDate.")
            valid_until_date = None

        version_info: Optional[str] = package_dict.get("versionInfo")
        if logger.has_messages():
            raise SPDXParsingError([f"Error while parsing Package {name}: {logger.get_messages()}"])

        try:
            package = Package(spdx_id=spdx_id, name=name, download_location=download_location, version=version_info,
                              file_name=package_file_name, supplier=supplier, originator=originator,
                              files_analyzed=files_analyzed,
                              verification_code=package_verification_code, checksums=checksums, homepage=homepage,
                              source_info=source_info,
                              license_concluded=license_concluded, license_info_from_files=license_info_from_file,
                              license_declared=license_declared,
                              license_comment=license_comments, copyright_text=copyright_text, summary=summary,
                              description=description,
                              comment=comment, external_references=external_refs, attribution_texts=attribution_texts,
                              primary_package_purpose=primary_package_purpose,
                              release_date=release_date, built_date=built_date, valid_until_date=valid_until_date)

        except ConstructorTypeErrors as err:
            raise SPDXParsingError([f"Error while constructing Package {name}: {err.get_messages()}"])

        return package

    def parse_external_refs(self, external_ref_dicts: List[Dict]) -> List[ExternalPackageRef]:
        external_refs = []
        for external_ref_dict in external_ref_dicts:
            try:
inproject
# Copyright (c) 2022 spdx contributors
# 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.
from datetime import datetime
from typing import Dict, List, Optional, Union

from src.model.actor import Actor
from src.model.checksum import Checksum
from src.model.license_expression import LicenseExpression
from src.model.package import Package, ExternalPackageRef, PackageVerificationCode, PackagePurpose, \
    ExternalPackageRefCategory
from src.model.spdx_no_assertion import SpdxNoAssertion
from src.model.spdx_none import SpdxNone
from src.model.typing.constructor_type_errors import ConstructorTypeErrors
from src.parser.error import SPDXParsingError
from src.parser.json.actor_parser import ActorParser
from src.parser.json.checksum_parser import ChecksumParser
from src.parser.json.dict_parsing_functions import datetime_from_str, parse_optional_field, \
    transform_json_str_to_enum_name
from src.parser.json.license_expression_parser import LicenseExpressionParser
from src.parser.logger import Logger


class PackageParser:
    logger: Logger
    actor_parser: ActorParser
    checksum_parser: ChecksumParser
    license_expression_parser: LicenseExpressionParser

    def __init__(self):
        self.actor_parser = ActorParser()
        self.checksum_parser = ChecksumParser()
        self.license_expression_parser = LicenseExpressionParser()
        self.logger = Logger()

    def parse_packages(self, packages_dict_list: List[Dict]) -> List[Package]:
        packages_list = []
        for package_dict in packages_dict_list:
            try:
                package: Package = self.parse_package(package_dict)
                packages_list.append(package)
            except SPDXParsingError as err:
                self.logger.append_all(err.get_messages())
                continue
        if self.logger.has_messages():
            raise SPDXParsingError(self.logger.get_messages())

        return packages_list

    def parse_package(self, package_dict: Dict) -> Package:
        logger = Logger()
        name: str = package_dict.get("name")
        spdx_id: str = package_dict.get("SPDXID")
        attribution_texts: List[str] = package_dict.get("attributionTexts")
        try:
            built_date: Optional[datetime] = parse_optional_field(package_dict.get("builtDate"), datetime_from_str)
        except ValueError:
            logger.append("ValueError while parsing builtDate.")
            built_date = None
        try:
inproject
# Copyright (c) 2022 spdx contributors
# 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.
from datetime import datetime
from typing import Dict, List, Optional, Union

from src.model.actor import Actor
from src.model.checksum import Checksum
from src.model.license_expression import LicenseExpression
from src.model.package import Package, ExternalPackageRef, PackageVerificationCode, PackagePurpose, \
    ExternalPackageRefCategory
from src.model.spdx_no_assertion import SpdxNoAssertion
from src.model.spdx_none import SpdxNone
from src.model.typing.constructor_type_errors import ConstructorTypeErrors
from src.parser.error import SPDXParsingError
from src.parser.json.actor_parser import ActorParser
from src.parser.json.checksum_parser import ChecksumParser
from src.parser.json.dict_parsing_functions import datetime_from_str, parse_optional_field, \
    transform_json_str_to_enum_name
from src.parser.json.license_expression_parser import LicenseExpressionParser
from src.parser.logger import Logger


class PackageParser:
    logger: Logger
    actor_parser: ActorParser
    checksum_parser: ChecksumParser
    license_expression_parser: LicenseExpressionParser

    def __init__(self):
        self.actor_parser = ActorParser()
        self.checksum_parser = ChecksumParser()
        self.license_expression_parser = LicenseExpressionParser()
        self.logger = Logger()

    def parse_packages(self, packages_dict_list: List[Dict]) -> List[Package]:
        packages_list = []
        for package_dict in packages_dict_list:
            try:
                package: Package = self.parse_package(package_dict)
                packages_list.append(package)
            except SPDXParsingError as err:
                self.logger.append_all(err.get_messages())
                continue
        if self.logger.has_messages():
            raise SPDXParsingError(self.logger.get_messages())

        return packages_list

    def parse_package(self, package_dict: Dict) -> Package:
        logger = Logger()
        name: str = package_dict.get("name")
        spdx_id: str = package_dict.get("SPDXID")
        attribution_texts: List[str] = package_dict.get("attributionTexts")
        try:
            built_date: Optional[datetime] = parse_optional_field(package_dict.get("builtDate"), datetime_from_str)
        except ValueError:
            logger.append("ValueError while parsing builtDate.")
            built_date = None
        try:
            checksums: List[Checksum] = parse_optional_field(package_dict.get("checksums"),
                                                             self.checksum_parser.parse_checksums, default=[])
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            checksums = []
        comment: Optional[str] = package_dict.get("comment")
        copyright_text: Optional[str] = package_dict.get("copyrightText")
        description: Optional[str] = package_dict.get("description")
        download_location: Union[str, SpdxNoAssertion, SpdxNone] = self.parse_download_location(
            package_dict.get("downloadLocation"))
        try:
            external_refs: List[ExternalPackageRef] = parse_optional_field(package_dict.get("externalRefs"),
                                                                           self.parse_external_refs)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            external_refs = []
        files_analyzed: Optional[bool] = parse_optional_field(package_dict.get("filesAnalyzed"), default=True)
        homepage: Optional[str] = package_dict.get("homepage")
        license_comments: Optional[str] = package_dict.get("licenseComments")
        try:
            license_concluded: Optional[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]] = parse_optional_field(
                package_dict.get("licenseConcluded"),
                self.license_expression_parser.parse_license_expression)
        except ConstructorTypeErrors as err:
            logger.append_all(err.get_messages())
            license_concluded = None
        try:
            license_declared: Optional[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]] = parse_optional_field(
                package_dict.get("licenseDeclared"),
                self.license_expression_parser.parse_license_expression)
        except ConstructorTypeErrors as err:
            logger.append_all(err.get_messages())
            license_declared = None
        try:
            license_info_from_file: Optional[
                Union[List[LicenseExpression], SpdxNoAssertion, SpdxNone]] = parse_optional_field(
                package_dict.get("licenseInfoFromFiles"),
                self.license_expression_parser.parse_license_expression)
        except ConstructorTypeErrors as err:
            logger.append_all(err.get_messages())
            license_info_from_file = None
        try:
            originator: Optional[Union[Actor, SpdxNoAssertion]] = parse_optional_field(package_dict.get("originator"),
                                                                                       self.actor_parser.parse_actor_or_no_assert)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            originator = None
        package_file_name: Optional[str] = package_dict.get("packageFileName")
        try:
            package_verification_code: Optional[PackageVerificationCode] = parse_optional_field(
                package_dict.get("packageVerificationCode"), self.parse_package_verification_code)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            package_verification_code = None

        try:
            primary_package_purpose: Optional[PackagePurpose] = parse_optional_field(
                package_dict.get("primaryPackagePurpose"), self.parse_primary_package_purpose)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            primary_package_purpose = None

        try:
            release_date: Optional[datetime] = parse_optional_field(package_dict.get("releaseDate"), datetime_from_str)
        except ValueError:
            logger.append("ValueError while parsing releaseDate.")
            release_date = None
        source_info: Optional[str] = package_dict.get("sourceInfo")
        summary: Optional[str] = package_dict.get("summary")
        try:
            supplier: Optional[Union[Actor, SpdxNoAssertion]] = parse_optional_field(package_dict.get("supplier"),
                                                                                     self.actor_parser.parse_actor_or_no_assert)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            supplier = None
        try:
            valid_until_date: Optional[datetime] = parse_optional_field(package_dict.get("validUntilDate"),
                                                                        datetime_from_str)
        except ValueError:
            logger.append("ValueError while parsing validUntilDate.")
            valid_until_date = None

        version_info: Optional[str] = package_dict.get("versionInfo")
        if logger.has_messages():
            raise SPDXParsingError([f"Error while parsing Package {name}: {logger.get_messages()}"])

        try:
            package = Package(spdx_id=spdx_id, name=name, download_location=download_location, version=version_info,
                              file_name=package_file_name, supplier=supplier, originator=originator,
                              files_analyzed=files_analyzed,
                              verification_code=package_verification_code, checksums=checksums, homepage=homepage,
                              source_info=source_info,
                              license_concluded=license_concluded, license_info_from_files=license_info_from_file,
                              license_declared=license_declared,
                              license_comment=license_comments, copyright_text=copyright_text, summary=summary,
                              description=description,
                              comment=comment, external_references=external_refs, attribution_texts=attribution_texts,
                              primary_package_purpose=primary_package_purpose,
                              release_date=release_date, built_date=built_date, valid_until_date=valid_until_date)

        except ConstructorTypeErrors as err:
            raise SPDXParsingError([f"Error while constructing Package {name}: {err.get_messages()}"])

        return package

    def parse_external_refs(self, external_ref_dicts: List[Dict]) -> List[ExternalPackageRef]:
        external_refs = []
        for external_ref_dict in external_ref_dicts:
            try:
                external_ref: ExternalPackageRef = self.parse_external_ref(external_ref_dict)
                external_refs.append(external_ref)
            except SPDXParsingError as err:
                self.logger.append_all(err.get_messages())
        return external_refs

    def parse_external_ref(self, external_ref_dict: Dict) -> ExternalPackageRef:
        logger = Logger()
        try:
            ref_category = self.parse_external_ref_category(external_ref_dict.get("referenceCategory"))
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            ref_category = None
        ref_locator = external_ref_dict.get("referenceLocator")
        ref_type = external_ref_dict.get("referenceType")
        comment = external_ref_dict.get("comment")
        if logger.has_messages():
            raise SPDXParsingError([f"Error while parsing external ref: {logger.get_messages()}"])
        try:
inproject
# Copyright (c) 2022 spdx contributors
# 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.
from datetime import datetime
from typing import Dict, List, Optional, Union

from src.model.actor import Actor
from src.model.checksum import Checksum
from src.model.license_expression import LicenseExpression
from src.model.package import Package, ExternalPackageRef, PackageVerificationCode, PackagePurpose, \
    ExternalPackageRefCategory
from src.model.spdx_no_assertion import SpdxNoAssertion
from src.model.spdx_none import SpdxNone
from src.model.typing.constructor_type_errors import ConstructorTypeErrors
from src.parser.error import SPDXParsingError
from src.parser.json.actor_parser import ActorParser
from src.parser.json.checksum_parser import ChecksumParser
from src.parser.json.dict_parsing_functions import datetime_from_str, parse_optional_field, \
    transform_json_str_to_enum_name
from src.parser.json.license_expression_parser import LicenseExpressionParser
from src.parser.logger import Logger


class PackageParser:
    logger: Logger
    actor_parser: ActorParser
    checksum_parser: ChecksumParser
    license_expression_parser: LicenseExpressionParser

    def __init__(self):
        self.actor_parser = ActorParser()
        self.checksum_parser = ChecksumParser()
        self.license_expression_parser = LicenseExpressionParser()
        self.logger = Logger()

    def parse_packages(self, packages_dict_list: List[Dict]) -> List[Package]:
        packages_list = []
        for package_dict in packages_dict_list:
            try:
                package: Package = self.parse_package(package_dict)
                packages_list.append(package)
            except SPDXParsingError as err:
                self.logger.append_all(err.get_messages())
                continue
        if self.logger.has_messages():
            raise SPDXParsingError(self.logger.get_messages())

        return packages_list

    def parse_package(self, package_dict: Dict) -> Package:
        logger = Logger()
        name: str = package_dict.get("name")
        spdx_id: str = package_dict.get("SPDXID")
        attribution_texts: List[str] = package_dict.get("attributionTexts")
        try:
            built_date: Optional[datetime] = parse_optional_field(package_dict.get("builtDate"), datetime_from_str)
        except ValueError:
            logger.append("ValueError while parsing builtDate.")
            built_date = None
        try:
            checksums: List[Checksum] = parse_optional_field(package_dict.get("checksums"),
                                                             self.checksum_parser.parse_checksums, default=[])
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            checksums = []
        comment: Optional[str] = package_dict.get("comment")
        copyright_text: Optional[str] = package_dict.get("copyrightText")
        description: Optional[str] = package_dict.get("description")
inproject
# Copyright (c) 2022 spdx contributors
# 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.
from datetime import datetime
from typing import Dict, List, Optional, Union

from src.model.actor import Actor
from src.model.checksum import Checksum
from src.model.license_expression import LicenseExpression
from src.model.package import Package, ExternalPackageRef, PackageVerificationCode, PackagePurpose, \
    ExternalPackageRefCategory
from src.model.spdx_no_assertion import SpdxNoAssertion
from src.model.spdx_none import SpdxNone
from src.model.typing.constructor_type_errors import ConstructorTypeErrors
from src.parser.error import SPDXParsingError
from src.parser.json.actor_parser import ActorParser
from src.parser.json.checksum_parser import ChecksumParser
from src.parser.json.dict_parsing_functions import datetime_from_str, parse_optional_field, \
    transform_json_str_to_enum_name
from src.parser.json.license_expression_parser import LicenseExpressionParser
from src.parser.logger import Logger


class PackageParser:
    logger: Logger
    actor_parser: ActorParser
    checksum_parser: ChecksumParser
    license_expression_parser: LicenseExpressionParser

    def __init__(self):
        self.actor_parser = ActorParser()
        self.checksum_parser = ChecksumParser()
        self.license_expression_parser = LicenseExpressionParser()
        self.logger = Logger()

    def parse_packages(self, packages_dict_list: List[Dict]) -> List[Package]:
        packages_list = []
        for package_dict in packages_dict_list:
            try:
                package: Package = self.parse_package(package_dict)
                packages_list.append(package)
            except SPDXParsingError as err:
                self.logger.append_all(err.get_messages())
                continue
        if self.logger.has_messages():
            raise SPDXParsingError(self.logger.get_messages())

        return packages_list

    def parse_package(self, package_dict: Dict) -> Package:
        logger = Logger()
        name: str = package_dict.get("name")
        spdx_id: str = package_dict.get("SPDXID")
        attribution_texts: List[str] = package_dict.get("attributionTexts")
        try:
            built_date: Optional[datetime] = parse_optional_field(package_dict.get("builtDate"), datetime_from_str)
        except ValueError:
            logger.append("ValueError while parsing builtDate.")
            built_date = None
        try:
            checksums: List[Checksum] = parse_optional_field(package_dict.get("checksums"),
                                                             self.checksum_parser.parse_checksums, default=[])
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            checksums = []
        comment: Optional[str] = package_dict.get("comment")
        copyright_text: Optional[str] = package_dict.get("copyrightText")
        description: Optional[str] = package_dict.get("description")
        download_location: Union[str, SpdxNoAssertion, SpdxNone] = self.parse_download_location(
            package_dict.get("downloadLocation"))
        try:
            external_refs: List[ExternalPackageRef] = parse_optional_field(package_dict.get("externalRefs"),
                                                                           self.parse_external_refs)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            external_refs = []
        files_analyzed: Optional[bool] = parse_optional_field(package_dict.get("filesAnalyzed"), default=True)
        homepage: Optional[str] = package_dict.get("homepage")
        license_comments: Optional[str] = package_dict.get("licenseComments")
        try:
            license_concluded: Optional[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]] = parse_optional_field(
                package_dict.get("licenseConcluded"),
                self.license_expression_parser.parse_license_expression)
        except ConstructorTypeErrors as err:
            logger.append_all(err.get_messages())
            license_concluded = None
        try:
            license_declared: Optional[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]] = parse_optional_field(
                package_dict.get("licenseDeclared"),
                self.license_expression_parser.parse_license_expression)
        except ConstructorTypeErrors as err:
            logger.append_all(err.get_messages())
            license_declared = None
        try:
            license_info_from_file: Optional[
                Union[List[LicenseExpression], SpdxNoAssertion, SpdxNone]] = parse_optional_field(
                package_dict.get("licenseInfoFromFiles"),
                self.license_expression_parser.parse_license_expression)
        except ConstructorTypeErrors as err:
            logger.append_all(err.get_messages())
            license_info_from_file = None
        try:
            originator: Optional[Union[Actor, SpdxNoAssertion]] = parse_optional_field(package_dict.get("originator"),
                                                                                       self.actor_parser.parse_actor_or_no_assert)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            originator = None
        package_file_name: Optional[str] = package_dict.get("packageFileName")
        try:
            package_verification_code: Optional[PackageVerificationCode] = parse_optional_field(
                package_dict.get("packageVerificationCode"), self.parse_package_verification_code)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            package_verification_code = None

        try:
            primary_package_purpose: Optional[PackagePurpose] = parse_optional_field(
                package_dict.get("primaryPackagePurpose"), self.parse_primary_package_purpose)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            primary_package_purpose = None

        try:
            release_date: Optional[datetime] = parse_optional_field(package_dict.get("releaseDate"), datetime_from_str)
        except ValueError:
            logger.append("ValueError while parsing releaseDate.")
            release_date = None
        source_info: Optional[str] = package_dict.get("sourceInfo")
        summary: Optional[str] = package_dict.get("summary")
        try:
            supplier: Optional[Union[Actor, SpdxNoAssertion]] = parse_optional_field(package_dict.get("supplier"),
                                                                                     self.actor_parser.parse_actor_or_no_assert)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            supplier = None
        try:
            valid_until_date: Optional[datetime] = parse_optional_field(package_dict.get("validUntilDate"),
                                                                        datetime_from_str)
        except ValueError:
            logger.append("ValueError while parsing validUntilDate.")
            valid_until_date = None

        version_info: Optional[str] = package_dict.get("versionInfo")
        if logger.has_messages():
            raise SPDXParsingError([f"Error while parsing Package {name}: {logger.get_messages()}"])

        try:
            package = Package(spdx_id=spdx_id, name=name, download_location=download_location, version=version_info,
                              file_name=package_file_name, supplier=supplier, originator=originator,
                              files_analyzed=files_analyzed,
                              verification_code=package_verification_code, checksums=checksums, homepage=homepage,
                              source_info=source_info,
                              license_concluded=license_concluded, license_info_from_files=license_info_from_file,
                              license_declared=license_declared,
                              license_comment=license_comments, copyright_text=copyright_text, summary=summary,
                              description=description,
                              comment=comment, external_references=external_refs, attribution_texts=attribution_texts,
                              primary_package_purpose=primary_package_purpose,
                              release_date=release_date, built_date=built_date, valid_until_date=valid_until_date)

        except ConstructorTypeErrors as err:
            raise SPDXParsingError([f"Error while constructing Package {name}: {err.get_messages()}"])

        return package

    def parse_external_refs(self, external_ref_dicts: List[Dict]) -> List[ExternalPackageRef]:
        external_refs = []
        for external_ref_dict in external_ref_dicts:
            try:
                external_ref: ExternalPackageRef = self.parse_external_ref(external_ref_dict)
                external_refs.append(external_ref)
            except SPDXParsingError as err:
                self.logger.append_all(err.get_messages())
        return external_refs

    def parse_external_ref(self, external_ref_dict: Dict) -> ExternalPackageRef:
        logger = Logger()
        try:
            ref_category = self.parse_external_ref_category(external_ref_dict.get("referenceCategory"))
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            ref_category = None
        ref_locator = external_ref_dict.get("referenceLocator")
        ref_type = external_ref_dict.get("referenceType")
        comment = external_ref_dict.get("comment")
        if logger.has_messages():
            raise SPDXParsingError([f"Error while parsing external ref: {logger.get_messages()}"])
        try:
            external_ref = ExternalPackageRef(category=ref_category, reference_type=ref_type, locator=ref_locator,
                                              comment=comment)
        except ConstructorTypeErrors as err:
            raise SPDXParsingError([f"Error while constructing external ref: {err.get_messages()}"])

        return external_ref

    @staticmethod
    def parse_external_ref_category(external_ref_category_str: str) -> ExternalPackageRefCategory:
        try:
inproject
# Copyright (c) 2022 spdx contributors
# 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.
from datetime import datetime
from typing import Dict, List, Optional, Union

from src.model.actor import Actor
from src.model.checksum import Checksum
from src.model.license_expression import LicenseExpression
from src.model.package import Package, ExternalPackageRef, PackageVerificationCode, PackagePurpose, \
    ExternalPackageRefCategory
from src.model.spdx_no_assertion import SpdxNoAssertion
from src.model.spdx_none import SpdxNone
from src.model.typing.constructor_type_errors import ConstructorTypeErrors
from src.parser.error import SPDXParsingError
from src.parser.json.actor_parser import ActorParser
from src.parser.json.checksum_parser import ChecksumParser
from src.parser.json.dict_parsing_functions import datetime_from_str, parse_optional_field, \
    transform_json_str_to_enum_name
from src.parser.json.license_expression_parser import LicenseExpressionParser
from src.parser.logger import Logger


class PackageParser:
    logger: Logger
    actor_parser: ActorParser
    checksum_parser: ChecksumParser
    license_expression_parser: LicenseExpressionParser

    def __init__(self):
        self.actor_parser = ActorParser()
        self.checksum_parser = ChecksumParser()
        self.license_expression_parser = LicenseExpressionParser()
        self.logger = Logger()

    def parse_packages(self, packages_dict_list: List[Dict]) -> List[Package]:
        packages_list = []
        for package_dict in packages_dict_list:
            try:
                package: Package = self.parse_package(package_dict)
                packages_list.append(package)
            except SPDXParsingError as err:
                self.logger.append_all(err.get_messages())
                continue
        if self.logger.has_messages():
            raise SPDXParsingError(self.logger.get_messages())

        return packages_list

    def parse_package(self, package_dict: Dict) -> Package:
        logger = Logger()
        name: str = package_dict.get("name")
        spdx_id: str = package_dict.get("SPDXID")
        attribution_texts: List[str] = package_dict.get("attributionTexts")
        try:
            built_date: Optional[datetime] = parse_optional_field(package_dict.get("builtDate"), datetime_from_str)
        except ValueError:
            logger.append("ValueError while parsing builtDate.")
            built_date = None
        try:
            checksums: List[Checksum] = parse_optional_field(package_dict.get("checksums"),
                                                             self.checksum_parser.parse_checksums, default=[])
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            checksums = []
        comment: Optional[str] = package_dict.get("comment")
        copyright_text: Optional[str] = package_dict.get("copyrightText")
        description: Optional[str] = package_dict.get("description")
        download_location: Union[str, SpdxNoAssertion, SpdxNone] = self.parse_download_location(
            package_dict.get("downloadLocation"))
        try:
inproject
# Copyright (c) 2022 spdx contributors
# 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.
from datetime import datetime
from typing import Dict, List, Optional, Union

from src.model.actor import Actor
from src.model.checksum import Checksum
from src.model.license_expression import LicenseExpression
from src.model.package import Package, ExternalPackageRef, PackageVerificationCode, PackagePurpose, \
    ExternalPackageRefCategory
from src.model.spdx_no_assertion import SpdxNoAssertion
from src.model.spdx_none import SpdxNone
from src.model.typing.constructor_type_errors import ConstructorTypeErrors
from src.parser.error import SPDXParsingError
from src.parser.json.actor_parser import ActorParser
from src.parser.json.checksum_parser import ChecksumParser
from src.parser.json.dict_parsing_functions import datetime_from_str, parse_optional_field, \
    transform_json_str_to_enum_name
from src.parser.json.license_expression_parser import LicenseExpressionParser
from src.parser.logger import Logger


class PackageParser:
    logger: Logger
    actor_parser: ActorParser
    checksum_parser: ChecksumParser
    license_expression_parser: LicenseExpressionParser

    def __init__(self):
        self.actor_parser = ActorParser()
        self.checksum_parser = ChecksumParser()
        self.license_expression_parser = LicenseExpressionParser()
        self.logger = Logger()

    def parse_packages(self, packages_dict_list: List[Dict]) -> List[Package]:
        packages_list = []
        for package_dict in packages_dict_list:
            try:
                package: Package = self.parse_package(package_dict)
                packages_list.append(package)
            except SPDXParsingError as err:
                self.logger.append_all(err.get_messages())
                continue
        if self.logger.has_messages():
            raise SPDXParsingError(self.logger.get_messages())

        return packages_list

    def parse_package(self, package_dict: Dict) -> Package:
        logger = Logger()
        name: str = package_dict.get("name")
        spdx_id: str = package_dict.get("SPDXID")
        attribution_texts: List[str] = package_dict.get("attributionTexts")
        try:
            built_date: Optional[datetime] = parse_optional_field(package_dict.get("builtDate"), datetime_from_str)
        except ValueError:
            logger.append("ValueError while parsing builtDate.")
            built_date = None
        try:
            checksums: List[Checksum] = parse_optional_field(package_dict.get("checksums"),
                                                             self.checksum_parser.parse_checksums, default=[])
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            checksums = []
        comment: Optional[str] = package_dict.get("comment")
        copyright_text: Optional[str] = package_dict.get("copyrightText")
        description: Optional[str] = package_dict.get("description")
        download_location: Union[str, SpdxNoAssertion, SpdxNone] = self.parse_download_location(
            package_dict.get("downloadLocation"))
        try:
            external_refs: List[ExternalPackageRef] = parse_optional_field(package_dict.get("externalRefs"),
                                                                           self.parse_external_refs)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            external_refs = []
        files_analyzed: Optional[bool] = parse_optional_field(package_dict.get("filesAnalyzed"), default=True)
        homepage: Optional[str] = package_dict.get("homepage")
        license_comments: Optional[str] = package_dict.get("licenseComments")
        try:
inproject
# Copyright (c) 2022 spdx contributors
# 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.
from datetime import datetime
from typing import Dict, List, Optional, Union

from src.model.actor import Actor
from src.model.checksum import Checksum
from src.model.license_expression import LicenseExpression
from src.model.package import Package, ExternalPackageRef, PackageVerificationCode, PackagePurpose, \
    ExternalPackageRefCategory
from src.model.spdx_no_assertion import SpdxNoAssertion
from src.model.spdx_none import SpdxNone
from src.model.typing.constructor_type_errors import ConstructorTypeErrors
from src.parser.error import SPDXParsingError
from src.parser.json.actor_parser import ActorParser
from src.parser.json.checksum_parser import ChecksumParser
from src.parser.json.dict_parsing_functions import datetime_from_str, parse_optional_field, \
    transform_json_str_to_enum_name
from src.parser.json.license_expression_parser import LicenseExpressionParser
from src.parser.logger import Logger


class PackageParser:
    logger: Logger
    actor_parser: ActorParser
    checksum_parser: ChecksumParser
    license_expression_parser: LicenseExpressionParser

    def __init__(self):
        self.actor_parser = ActorParser()
        self.checksum_parser = ChecksumParser()
        self.license_expression_parser = LicenseExpressionParser()
        self.logger = Logger()

    def parse_packages(self, packages_dict_list: List[Dict]) -> List[Package]:
        packages_list = []
        for package_dict in packages_dict_list:
            try:
                package: Package = self.parse_package(package_dict)
                packages_list.append(package)
            except SPDXParsingError as err:
                self.logger.append_all(err.get_messages())
                continue
        if self.logger.has_messages():
            raise SPDXParsingError(self.logger.get_messages())

        return packages_list

    def parse_package(self, package_dict: Dict) -> Package:
        logger = Logger()
        name: str = package_dict.get("name")
        spdx_id: str = package_dict.get("SPDXID")
        attribution_texts: List[str] = package_dict.get("attributionTexts")
        try:
            built_date: Optional[datetime] = parse_optional_field(package_dict.get("builtDate"), datetime_from_str)
        except ValueError:
            logger.append("ValueError while parsing builtDate.")
            built_date = None
        try:
            checksums: List[Checksum] = parse_optional_field(package_dict.get("checksums"),
                                                             self.checksum_parser.parse_checksums, default=[])
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            checksums = []
        comment: Optional[str] = package_dict.get("comment")
        copyright_text: Optional[str] = package_dict.get("copyrightText")
        description: Optional[str] = package_dict.get("description")
        download_location: Union[str, SpdxNoAssertion, SpdxNone] = self.parse_download_location(
            package_dict.get("downloadLocation"))
        try:
            external_refs: List[ExternalPackageRef] = parse_optional_field(package_dict.get("externalRefs"),
                                                                           self.parse_external_refs)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            external_refs = []
        files_analyzed: Optional[bool] = parse_optional_field(package_dict.get("filesAnalyzed"), default=True)
        homepage: Optional[str] = package_dict.get("homepage")
        license_comments: Optional[str] = package_dict.get("licenseComments")
        try:
            license_concluded: Optional[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]] = parse_optional_field(
                package_dict.get("licenseConcluded"),
                self.license_expression_parser.parse_license_expression)
        except ConstructorTypeErrors as err:
            logger.append_all(err.get_messages())
            license_concluded = None
        try:
            license_declared: Optional[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]] = parse_optional_field(
                package_dict.get("licenseDeclared"),
                self.license_expression_parser.parse_license_expression)
        except ConstructorTypeErrors as err:
            logger.append_all(err.get_messages())
            license_declared = None
        try:
            license_info_from_file: Optional[
                Union[List[LicenseExpression], SpdxNoAssertion, SpdxNone]] = parse_optional_field(
                package_dict.get("licenseInfoFromFiles"),
                self.license_expression_parser.parse_license_expression)
        except ConstructorTypeErrors as err:
            logger.append_all(err.get_messages())
            license_info_from_file = None
        try:
            originator: Optional[Union[Actor, SpdxNoAssertion]] = parse_optional_field(package_dict.get("originator"),
                                                                                       self.actor_parser.parse_actor_or_no_assert)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            originator = None
        package_file_name: Optional[str] = package_dict.get("packageFileName")
        try:
            package_verification_code: Optional[PackageVerificationCode] = parse_optional_field(
                package_dict.get("packageVerificationCode"), self.parse_package_verification_code)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            package_verification_code = None

        try:
            primary_package_purpose: Optional[PackagePurpose] = parse_optional_field(
                package_dict.get("primaryPackagePurpose"), self.parse_primary_package_purpose)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            primary_package_purpose = None

        try:
            release_date: Optional[datetime] = parse_optional_field(package_dict.get("releaseDate"), datetime_from_str)
        except ValueError:
            logger.append("ValueError while parsing releaseDate.")
            release_date = None
        source_info: Optional[str] = package_dict.get("sourceInfo")
        summary: Optional[str] = package_dict.get("summary")
        try:
            supplier: Optional[Union[Actor, SpdxNoAssertion]] = parse_optional_field(package_dict.get("supplier"),
                                                                                     self.actor_parser.parse_actor_or_no_assert)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            supplier = None
        try:
            valid_until_date: Optional[datetime] = parse_optional_field(package_dict.get("validUntilDate"),
                                                                        datetime_from_str)
        except ValueError:
            logger.append("ValueError while parsing validUntilDate.")
            valid_until_date = None

        version_info: Optional[str] = package_dict.get("versionInfo")
        if logger.has_messages():
            raise SPDXParsingError([f"Error while parsing Package {name}: {logger.get_messages()}"])

        try:
            package = Package(spdx_id=spdx_id, name=name, download_location=download_location, version=version_info,
                              file_name=package_file_name, supplier=supplier, originator=originator,
                              files_analyzed=files_analyzed,
                              verification_code=package_verification_code, checksums=checksums, homepage=homepage,
                              source_info=source_info,
                              license_concluded=license_concluded, license_info_from_files=license_info_from_file,
                              license_declared=license_declared,
                              license_comment=license_comments, copyright_text=copyright_text, summary=summary,
                              description=description,
                              comment=comment, external_references=external_refs, attribution_texts=attribution_texts,
                              primary_package_purpose=primary_package_purpose,
                              release_date=release_date, built_date=built_date, valid_until_date=valid_until_date)

        except ConstructorTypeErrors as err:
            raise SPDXParsingError([f"Error while constructing Package {name}: {err.get_messages()}"])

        return package

    def parse_external_refs(self, external_ref_dicts: List[Dict]) -> List[ExternalPackageRef]:
        external_refs = []
        for external_ref_dict in external_ref_dicts:
            try:
                external_ref: ExternalPackageRef = self.parse_external_ref(external_ref_dict)
                external_refs.append(external_ref)
            except SPDXParsingError as err:
                self.logger.append_all(err.get_messages())
        return external_refs

    def parse_external_ref(self, external_ref_dict: Dict) -> ExternalPackageRef:
        logger = Logger()
        try:
            ref_category = self.parse_external_ref_category(external_ref_dict.get("referenceCategory"))
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            ref_category = None
        ref_locator = external_ref_dict.get("referenceLocator")
        ref_type = external_ref_dict.get("referenceType")
        comment = external_ref_dict.get("comment")
        if logger.has_messages():
            raise SPDXParsingError([f"Error while parsing external ref: {logger.get_messages()}"])
        try:
            external_ref = ExternalPackageRef(category=ref_category, reference_type=ref_type, locator=ref_locator,
                                              comment=comment)
        except ConstructorTypeErrors as err:
            raise SPDXParsingError([f"Error while constructing external ref: {err.get_messages()}"])

        return external_ref

    @staticmethod
    def parse_external_ref_category(external_ref_category_str: str) -> ExternalPackageRefCategory:
        try:
            external_ref_category = ExternalPackageRefCategory[
                transform_json_str_to_enum_name(external_ref_category_str)]
        except KeyError:
            raise SPDXParsingError([f"Category {external_ref_category_str} not valid for externalPackageRef."])

        return external_ref_category

    @staticmethod
    def parse_package_verification_code(verification_code_dict: Dict) -> PackageVerificationCode:
        excluded_files: List[str] = verification_code_dict.get("packageVerificationCodeExcludedFiles")
        verification_code_value: str = verification_code_dict.get("packageVerificationCodeValue")
        try:
inproject
# Copyright (c) 2022 spdx contributors
# 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.
from datetime import datetime
from typing import Dict, List, Optional, Union

from src.model.actor import Actor
from src.model.checksum import Checksum
from src.model.license_expression import LicenseExpression
from src.model.package import Package, ExternalPackageRef, PackageVerificationCode, PackagePurpose, \
    ExternalPackageRefCategory
from src.model.spdx_no_assertion import SpdxNoAssertion
from src.model.spdx_none import SpdxNone
from src.model.typing.constructor_type_errors import ConstructorTypeErrors
from src.parser.error import SPDXParsingError
from src.parser.json.actor_parser import ActorParser
from src.parser.json.checksum_parser import ChecksumParser
from src.parser.json.dict_parsing_functions import datetime_from_str, parse_optional_field, \
    transform_json_str_to_enum_name
from src.parser.json.license_expression_parser import LicenseExpressionParser
from src.parser.logger import Logger


class PackageParser:
    logger: Logger
    actor_parser: ActorParser
    checksum_parser: ChecksumParser
    license_expression_parser: LicenseExpressionParser

    def __init__(self):
        self.actor_parser = ActorParser()
        self.checksum_parser = ChecksumParser()
        self.license_expression_parser = LicenseExpressionParser()
        self.logger = Logger()

    def parse_packages(self, packages_dict_list: List[Dict]) -> List[Package]:
        packages_list = []
        for package_dict in packages_dict_list:
            try:
                package: Package = self.parse_package(package_dict)
                packages_list.append(package)
            except SPDXParsingError as err:
                self.logger.append_all(err.get_messages())
                continue
        if self.logger.has_messages():
            raise SPDXParsingError(self.logger.get_messages())

        return packages_list

    def parse_package(self, package_dict: Dict) -> Package:
        logger = Logger()
        name: str = package_dict.get("name")
        spdx_id: str = package_dict.get("SPDXID")
        attribution_texts: List[str] = package_dict.get("attributionTexts")
        try:
            built_date: Optional[datetime] = parse_optional_field(package_dict.get("builtDate"), datetime_from_str)
        except ValueError:
            logger.append("ValueError while parsing builtDate.")
            built_date = None
        try:
            checksums: List[Checksum] = parse_optional_field(package_dict.get("checksums"),
                                                             self.checksum_parser.parse_checksums, default=[])
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            checksums = []
        comment: Optional[str] = package_dict.get("comment")
        copyright_text: Optional[str] = package_dict.get("copyrightText")
        description: Optional[str] = package_dict.get("description")
        download_location: Union[str, SpdxNoAssertion, SpdxNone] = self.parse_download_location(
            package_dict.get("downloadLocation"))
        try:
            external_refs: List[ExternalPackageRef] = parse_optional_field(package_dict.get("externalRefs"),
                                                                           self.parse_external_refs)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            external_refs = []
        files_analyzed: Optional[bool] = parse_optional_field(package_dict.get("filesAnalyzed"), default=True)
        homepage: Optional[str] = package_dict.get("homepage")
        license_comments: Optional[str] = package_dict.get("licenseComments")
        try:
            license_concluded: Optional[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]] = parse_optional_field(
                package_dict.get("licenseConcluded"),
                self.license_expression_parser.parse_license_expression)
        except ConstructorTypeErrors as err:
            logger.append_all(err.get_messages())
            license_concluded = None
        try:
inproject
# Copyright (c) 2022 spdx contributors
# 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.
from datetime import datetime
from typing import Dict, List, Optional, Union

from src.model.actor import Actor
from src.model.checksum import Checksum
from src.model.license_expression import LicenseExpression
from src.model.package import Package, ExternalPackageRef, PackageVerificationCode, PackagePurpose, \
    ExternalPackageRefCategory
from src.model.spdx_no_assertion import SpdxNoAssertion
from src.model.spdx_none import SpdxNone
from src.model.typing.constructor_type_errors import ConstructorTypeErrors
from src.parser.error import SPDXParsingError
from src.parser.json.actor_parser import ActorParser
from src.parser.json.checksum_parser import ChecksumParser
from src.parser.json.dict_parsing_functions import datetime_from_str, parse_optional_field, \
    transform_json_str_to_enum_name
from src.parser.json.license_expression_parser import LicenseExpressionParser
from src.parser.logger import Logger


class PackageParser:
    logger: Logger
    actor_parser: ActorParser
    checksum_parser: ChecksumParser
    license_expression_parser: LicenseExpressionParser

    def __init__(self):
        self.actor_parser = ActorParser()
        self.checksum_parser = ChecksumParser()
        self.license_expression_parser = LicenseExpressionParser()
        self.logger = Logger()

    def parse_packages(self, packages_dict_list: List[Dict]) -> List[Package]:
        packages_list = []
        for package_dict in packages_dict_list:
            try:
                package: Package = self.parse_package(package_dict)
                packages_list.append(package)
            except SPDXParsingError as err:
                self.logger.append_all(err.get_messages())
                continue
        if self.logger.has_messages():
            raise SPDXParsingError(self.logger.get_messages())

        return packages_list

    def parse_package(self, package_dict: Dict) -> Package:
        logger = Logger()
        name: str = package_dict.get("name")
        spdx_id: str = package_dict.get("SPDXID")
        attribution_texts: List[str] = package_dict.get("attributionTexts")
        try:
            built_date: Optional[datetime] = parse_optional_field(package_dict.get("builtDate"), datetime_from_str)
        except ValueError:
            logger.append("ValueError while parsing builtDate.")
            built_date = None
        try:
            checksums: List[Checksum] = parse_optional_field(package_dict.get("checksums"),
                                                             self.checksum_parser.parse_checksums, default=[])
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            checksums = []
        comment: Optional[str] = package_dict.get("comment")
        copyright_text: Optional[str] = package_dict.get("copyrightText")
        description: Optional[str] = package_dict.get("description")
        download_location: Union[str, SpdxNoAssertion, SpdxNone] = self.parse_download_location(
            package_dict.get("downloadLocation"))
        try:
            external_refs: List[ExternalPackageRef] = parse_optional_field(package_dict.get("externalRefs"),
                                                                           self.parse_external_refs)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            external_refs = []
        files_analyzed: Optional[bool] = parse_optional_field(package_dict.get("filesAnalyzed"), default=True)
        homepage: Optional[str] = package_dict.get("homepage")
        license_comments: Optional[str] = package_dict.get("licenseComments")
        try:
            license_concluded: Optional[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]] = parse_optional_field(
                package_dict.get("licenseConcluded"),
                self.license_expression_parser.parse_license_expression)
        except ConstructorTypeErrors as err:
            logger.append_all(err.get_messages())
            license_concluded = None
        try:
            license_declared: Optional[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]] = parse_optional_field(
                package_dict.get("licenseDeclared"),
                self.license_expression_parser.parse_license_expression)
        except ConstructorTypeErrors as err:
            logger.append_all(err.get_messages())
            license_declared = None
        try:
            license_info_from_file: Optional[
                Union[List[LicenseExpression], SpdxNoAssertion, SpdxNone]] = parse_optional_field(
                package_dict.get("licenseInfoFromFiles"),
                self.license_expression_parser.parse_license_expression)
        except ConstructorTypeErrors as err:
            logger.append_all(err.get_messages())
            license_info_from_file = None
        try:
            originator: Optional[Union[Actor, SpdxNoAssertion]] = parse_optional_field(package_dict.get("originator"),
                                                                                       self.actor_parser.parse_actor_or_no_assert)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            originator = None
        package_file_name: Optional[str] = package_dict.get("packageFileName")
        try:
            package_verification_code: Optional[PackageVerificationCode] = parse_optional_field(
                package_dict.get("packageVerificationCode"), self.parse_package_verification_code)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            package_verification_code = None

        try:
            primary_package_purpose: Optional[PackagePurpose] = parse_optional_field(
                package_dict.get("primaryPackagePurpose"), self.parse_primary_package_purpose)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            primary_package_purpose = None

        try:
            release_date: Optional[datetime] = parse_optional_field(package_dict.get("releaseDate"), datetime_from_str)
        except ValueError:
            logger.append("ValueError while parsing releaseDate.")
            release_date = None
        source_info: Optional[str] = package_dict.get("sourceInfo")
        summary: Optional[str] = package_dict.get("summary")
        try:
            supplier: Optional[Union[Actor, SpdxNoAssertion]] = parse_optional_field(package_dict.get("supplier"),
                                                                                     self.actor_parser.parse_actor_or_no_assert)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            supplier = None
        try:
            valid_until_date: Optional[datetime] = parse_optional_field(package_dict.get("validUntilDate"),
                                                                        datetime_from_str)
        except ValueError:
            logger.append("ValueError while parsing validUntilDate.")
            valid_until_date = None

        version_info: Optional[str] = package_dict.get("versionInfo")
        if logger.has_messages():
            raise SPDXParsingError([f"Error while parsing Package {name}: {logger.get_messages()}"])

        try:
            package = Package(spdx_id=spdx_id, name=name, download_location=download_location, version=version_info,
                              file_name=package_file_name, supplier=supplier, originator=originator,
                              files_analyzed=files_analyzed,
                              verification_code=package_verification_code, checksums=checksums, homepage=homepage,
                              source_info=source_info,
                              license_concluded=license_concluded, license_info_from_files=license_info_from_file,
                              license_declared=license_declared,
                              license_comment=license_comments, copyright_text=copyright_text, summary=summary,
                              description=description,
                              comment=comment, external_references=external_refs, attribution_texts=attribution_texts,
                              primary_package_purpose=primary_package_purpose,
                              release_date=release_date, built_date=built_date, valid_until_date=valid_until_date)

        except ConstructorTypeErrors as err:
            raise SPDXParsingError([f"Error while constructing Package {name}: {err.get_messages()}"])

        return package

    def parse_external_refs(self, external_ref_dicts: List[Dict]) -> List[ExternalPackageRef]:
        external_refs = []
        for external_ref_dict in external_ref_dicts:
            try:
                external_ref: ExternalPackageRef = self.parse_external_ref(external_ref_dict)
                external_refs.append(external_ref)
            except SPDXParsingError as err:
                self.logger.append_all(err.get_messages())
        return external_refs

    def parse_external_ref(self, external_ref_dict: Dict) -> ExternalPackageRef:
        logger = Logger()
        try:
            ref_category = self.parse_external_ref_category(external_ref_dict.get("referenceCategory"))
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            ref_category = None
        ref_locator = external_ref_dict.get("referenceLocator")
        ref_type = external_ref_dict.get("referenceType")
        comment = external_ref_dict.get("comment")
        if logger.has_messages():
            raise SPDXParsingError([f"Error while parsing external ref: {logger.get_messages()}"])
        try:
            external_ref = ExternalPackageRef(category=ref_category, reference_type=ref_type, locator=ref_locator,
                                              comment=comment)
        except ConstructorTypeErrors as err:
            raise SPDXParsingError([f"Error while constructing external ref: {err.get_messages()}"])

        return external_ref

    @staticmethod
    def parse_external_ref_category(external_ref_category_str: str) -> ExternalPackageRefCategory:
        try:
            external_ref_category = ExternalPackageRefCategory[
                transform_json_str_to_enum_name(external_ref_category_str)]
        except KeyError:
            raise SPDXParsingError([f"Category {external_ref_category_str} not valid for externalPackageRef."])

        return external_ref_category

    @staticmethod
    def parse_package_verification_code(verification_code_dict: Dict) -> PackageVerificationCode:
        excluded_files: List[str] = verification_code_dict.get("packageVerificationCodeExcludedFiles")
        verification_code_value: str = verification_code_dict.get("packageVerificationCodeValue")
        try:
            package_verification_code = PackageVerificationCode(value=verification_code_value,
                                                                excluded_files=excluded_files)
        except ConstructorTypeErrors as err:
            raise SPDXParsingError([f"Error while parsing package verification code: {err.get_messages()}"])

        return package_verification_code

    @staticmethod
    def parse_primary_package_purpose(primary_package_purpose: str) -> PackagePurpose:
        try:
inproject
# Copyright (c) 2022 spdx contributors
# 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.
from datetime import datetime
from typing import Dict, List, Optional, Union

from src.model.actor import Actor
from src.model.checksum import Checksum
from src.model.license_expression import LicenseExpression
from src.model.package import Package, ExternalPackageRef, PackageVerificationCode, PackagePurpose, \
    ExternalPackageRefCategory
from src.model.spdx_no_assertion import SpdxNoAssertion
from src.model.spdx_none import SpdxNone
from src.model.typing.constructor_type_errors import ConstructorTypeErrors
from src.parser.error import SPDXParsingError
from src.parser.json.actor_parser import ActorParser
from src.parser.json.checksum_parser import ChecksumParser
from src.parser.json.dict_parsing_functions import datetime_from_str, parse_optional_field, \
    transform_json_str_to_enum_name
from src.parser.json.license_expression_parser import LicenseExpressionParser
from src.parser.logger import Logger


class PackageParser:
    logger: Logger
    actor_parser: ActorParser
    checksum_parser: ChecksumParser
    license_expression_parser: LicenseExpressionParser

    def __init__(self):
        self.actor_parser = ActorParser()
        self.checksum_parser = ChecksumParser()
        self.license_expression_parser = LicenseExpressionParser()
        self.logger = Logger()

    def parse_packages(self, packages_dict_list: List[Dict]) -> List[Package]:
        packages_list = []
        for package_dict in packages_dict_list:
            try:
                package: Package = self.parse_package(package_dict)
                packages_list.append(package)
            except SPDXParsingError as err:
                self.logger.append_all(err.get_messages())
                continue
        if self.logger.has_messages():
            raise SPDXParsingError(self.logger.get_messages())

        return packages_list

    def parse_package(self, package_dict: Dict) -> Package:
        logger = Logger()
        name: str = package_dict.get("name")
        spdx_id: str = package_dict.get("SPDXID")
        attribution_texts: List[str] = package_dict.get("attributionTexts")
        try:
            built_date: Optional[datetime] = parse_optional_field(package_dict.get("builtDate"), datetime_from_str)
        except ValueError:
            logger.append("ValueError while parsing builtDate.")
            built_date = None
        try:
            checksums: List[Checksum] = parse_optional_field(package_dict.get("checksums"),
                                                             self.checksum_parser.parse_checksums, default=[])
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            checksums = []
        comment: Optional[str] = package_dict.get("comment")
        copyright_text: Optional[str] = package_dict.get("copyrightText")
        description: Optional[str] = package_dict.get("description")
        download_location: Union[str, SpdxNoAssertion, SpdxNone] = self.parse_download_location(
            package_dict.get("downloadLocation"))
        try:
            external_refs: List[ExternalPackageRef] = parse_optional_field(package_dict.get("externalRefs"),
                                                                           self.parse_external_refs)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            external_refs = []
        files_analyzed: Optional[bool] = parse_optional_field(package_dict.get("filesAnalyzed"), default=True)
        homepage: Optional[str] = package_dict.get("homepage")
        license_comments: Optional[str] = package_dict.get("licenseComments")
        try:
            license_concluded: Optional[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]] = parse_optional_field(
                package_dict.get("licenseConcluded"),
                self.license_expression_parser.parse_license_expression)
        except ConstructorTypeErrors as err:
            logger.append_all(err.get_messages())
            license_concluded = None
        try:
            license_declared: Optional[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]] = parse_optional_field(
                package_dict.get("licenseDeclared"),
                self.license_expression_parser.parse_license_expression)
        except ConstructorTypeErrors as err:
            logger.append_all(err.get_messages())
            license_declared = None
        try:
            license_info_from_file: Optional[
inproject
# Copyright (c) 2022 spdx contributors
# 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.
from datetime import datetime
from typing import Dict, List, Optional, Union

from src.model.actor import Actor
from src.model.checksum import Checksum
from src.model.license_expression import LicenseExpression
from src.model.package import Package, ExternalPackageRef, PackageVerificationCode, PackagePurpose, \
    ExternalPackageRefCategory
from src.model.spdx_no_assertion import SpdxNoAssertion
from src.model.spdx_none import SpdxNone
from src.model.typing.constructor_type_errors import ConstructorTypeErrors
from src.parser.error import SPDXParsingError
from src.parser.json.actor_parser import ActorParser
from src.parser.json.checksum_parser import ChecksumParser
from src.parser.json.dict_parsing_functions import datetime_from_str, parse_optional_field, \
    transform_json_str_to_enum_name
from src.parser.json.license_expression_parser import LicenseExpressionParser
from src.parser.logger import Logger


class PackageParser:
    logger: Logger
    actor_parser: ActorParser
    checksum_parser: ChecksumParser
    license_expression_parser: LicenseExpressionParser

    def __init__(self):
        self.actor_parser = ActorParser()
        self.checksum_parser = ChecksumParser()
        self.license_expression_parser = LicenseExpressionParser()
        self.logger = Logger()

    def parse_packages(self, packages_dict_list: List[Dict]) -> List[Package]:
        packages_list = []
        for package_dict in packages_dict_list:
            try:
                package: Package = self.parse_package(package_dict)
                packages_list.append(package)
            except SPDXParsingError as err:
                self.logger.append_all(err.get_messages())
                continue
        if self.logger.has_messages():
            raise SPDXParsingError(self.logger.get_messages())

        return packages_list

    def parse_package(self, package_dict: Dict) -> Package:
        logger = Logger()
        name: str = package_dict.get("name")
        spdx_id: str = package_dict.get("SPDXID")
        attribution_texts: List[str] = package_dict.get("attributionTexts")
        try:
            built_date: Optional[datetime] = parse_optional_field(package_dict.get("builtDate"), datetime_from_str)
        except ValueError:
            logger.append("ValueError while parsing builtDate.")
            built_date = None
        try:
            checksums: List[Checksum] = parse_optional_field(package_dict.get("checksums"),
                                                             self.checksum_parser.parse_checksums, default=[])
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            checksums = []
        comment: Optional[str] = package_dict.get("comment")
        copyright_text: Optional[str] = package_dict.get("copyrightText")
        description: Optional[str] = package_dict.get("description")
        download_location: Union[str, SpdxNoAssertion, SpdxNone] = self.parse_download_location(
            package_dict.get("downloadLocation"))
        try:
            external_refs: List[ExternalPackageRef] = parse_optional_field(package_dict.get("externalRefs"),
                                                                           self.parse_external_refs)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            external_refs = []
        files_analyzed: Optional[bool] = parse_optional_field(package_dict.get("filesAnalyzed"), default=True)
        homepage: Optional[str] = package_dict.get("homepage")
        license_comments: Optional[str] = package_dict.get("licenseComments")
        try:
            license_concluded: Optional[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]] = parse_optional_field(
                package_dict.get("licenseConcluded"),
                self.license_expression_parser.parse_license_expression)
        except ConstructorTypeErrors as err:
            logger.append_all(err.get_messages())
            license_concluded = None
        try:
            license_declared: Optional[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]] = parse_optional_field(
                package_dict.get("licenseDeclared"),
                self.license_expression_parser.parse_license_expression)
        except ConstructorTypeErrors as err:
            logger.append_all(err.get_messages())
            license_declared = None
        try:
            license_info_from_file: Optional[
                Union[List[LicenseExpression], SpdxNoAssertion, SpdxNone]] = parse_optional_field(
                package_dict.get("licenseInfoFromFiles"),
                self.license_expression_parser.parse_license_expression)
        except ConstructorTypeErrors as err:
            logger.append_all(err.get_messages())
            license_info_from_file = None
        try:
            originator: Optional[Union[Actor, SpdxNoAssertion]] = parse_optional_field(package_dict.get("originator"),
                                                                                       self.actor_parser.parse_actor_or_no_assert)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            originator = None
        package_file_name: Optional[str] = package_dict.get("packageFileName")
        try:
            package_verification_code: Optional[PackageVerificationCode] = parse_optional_field(
                package_dict.get("packageVerificationCode"), self.parse_package_verification_code)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            package_verification_code = None

        try:
            primary_package_purpose: Optional[PackagePurpose] = parse_optional_field(
                package_dict.get("primaryPackagePurpose"), self.parse_primary_package_purpose)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            primary_package_purpose = None

        try:
            release_date: Optional[datetime] = parse_optional_field(package_dict.get("releaseDate"), datetime_from_str)
        except ValueError:
            logger.append("ValueError while parsing releaseDate.")
            release_date = None
        source_info: Optional[str] = package_dict.get("sourceInfo")
        summary: Optional[str] = package_dict.get("summary")
        try:
            supplier: Optional[Union[Actor, SpdxNoAssertion]] = parse_optional_field(package_dict.get("supplier"),
                                                                                     self.actor_parser.parse_actor_or_no_assert)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            supplier = None
        try:
            valid_until_date: Optional[datetime] = parse_optional_field(package_dict.get("validUntilDate"),
                                                                        datetime_from_str)
        except ValueError:
            logger.append("ValueError while parsing validUntilDate.")
            valid_until_date = None

        version_info: Optional[str] = package_dict.get("versionInfo")
        if logger.has_messages():
            raise SPDXParsingError([f"Error while parsing Package {name}: {logger.get_messages()}"])

        try:
            package = Package(spdx_id=spdx_id, name=name, download_location=download_location, version=version_info,
                              file_name=package_file_name, supplier=supplier, originator=originator,
                              files_analyzed=files_analyzed,
                              verification_code=package_verification_code, checksums=checksums, homepage=homepage,
                              source_info=source_info,
                              license_concluded=license_concluded, license_info_from_files=license_info_from_file,
                              license_declared=license_declared,
                              license_comment=license_comments, copyright_text=copyright_text, summary=summary,
                              description=description,
                              comment=comment, external_references=external_refs, attribution_texts=attribution_texts,
                              primary_package_purpose=primary_package_purpose,
                              release_date=release_date, built_date=built_date, valid_until_date=valid_until_date)

        except ConstructorTypeErrors as err:
            raise SPDXParsingError([f"Error while constructing Package {name}: {err.get_messages()}"])

        return package

    def parse_external_refs(self, external_ref_dicts: List[Dict]) -> List[ExternalPackageRef]:
        external_refs = []
        for external_ref_dict in external_ref_dicts:
            try:
                external_ref: ExternalPackageRef = self.parse_external_ref(external_ref_dict)
                external_refs.append(external_ref)
            except SPDXParsingError as err:
                self.logger.append_all(err.get_messages())
        return external_refs

    def parse_external_ref(self, external_ref_dict: Dict) -> ExternalPackageRef:
        logger = Logger()
        try:
            ref_category = self.parse_external_ref_category(external_ref_dict.get("referenceCategory"))
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            ref_category = None
        ref_locator = external_ref_dict.get("referenceLocator")
        ref_type = external_ref_dict.get("referenceType")
        comment = external_ref_dict.get("comment")
        if logger.has_messages():
            raise SPDXParsingError([f"Error while parsing external ref: {logger.get_messages()}"])
        try:
            external_ref = ExternalPackageRef(category=ref_category, reference_type=ref_type, locator=ref_locator,
                                              comment=comment)
        except ConstructorTypeErrors as err:
            raise SPDXParsingError([f"Error while constructing external ref: {err.get_messages()}"])

        return external_ref

    @staticmethod
    def parse_external_ref_category(external_ref_category_str: str) -> ExternalPackageRefCategory:
        try:
            external_ref_category = ExternalPackageRefCategory[
                transform_json_str_to_enum_name(external_ref_category_str)]
        except KeyError:
            raise SPDXParsingError([f"Category {external_ref_category_str} not valid for externalPackageRef."])

        return external_ref_category

    @staticmethod
    def parse_package_verification_code(verification_code_dict: Dict) -> PackageVerificationCode:
        excluded_files: List[str] = verification_code_dict.get("packageVerificationCodeExcludedFiles")
        verification_code_value: str = verification_code_dict.get("packageVerificationCodeValue")
        try:
            package_verification_code = PackageVerificationCode(value=verification_code_value,
                                                                excluded_files=excluded_files)
        except ConstructorTypeErrors as err:
            raise SPDXParsingError([f"Error while parsing package verification code: {err.get_messages()}"])

        return package_verification_code

    @staticmethod
    def parse_primary_package_purpose(primary_package_purpose: str) -> PackagePurpose:
        try:
            return PackagePurpose[transform_json_str_to_enum_name(primary_package_purpose)]
        except KeyError:
            raise SPDXParsingError([f"Invalid primaryPackagePurpose: {primary_package_purpose}"])

    @staticmethod
    def parse_download_location(download_location: str) -> Union[str, SpdxNoAssertion, SpdxNone]:
inproject
# Copyright (c) 2022 spdx contributors
# 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.
from datetime import datetime
from typing import Dict, List, Optional, Union

from src.model.actor import Actor
from src.model.checksum import Checksum
from src.model.license_expression import LicenseExpression
from src.model.package import Package, ExternalPackageRef, PackageVerificationCode, PackagePurpose, \
    ExternalPackageRefCategory
from src.model.spdx_no_assertion import SpdxNoAssertion
from src.model.spdx_none import SpdxNone
from src.model.typing.constructor_type_errors import ConstructorTypeErrors
from src.parser.error import SPDXParsingError
from src.parser.json.actor_parser import ActorParser
from src.parser.json.checksum_parser import ChecksumParser
from src.parser.json.dict_parsing_functions import datetime_from_str, parse_optional_field, \
    transform_json_str_to_enum_name
from src.parser.json.license_expression_parser import LicenseExpressionParser
from src.parser.logger import Logger


class PackageParser:
    logger: Logger
    actor_parser: ActorParser
    checksum_parser: ChecksumParser
    license_expression_parser: LicenseExpressionParser

    def __init__(self):
        self.actor_parser = ActorParser()
        self.checksum_parser = ChecksumParser()
        self.license_expression_parser = LicenseExpressionParser()
        self.logger = Logger()

    def parse_packages(self, packages_dict_list: List[Dict]) -> List[Package]:
        packages_list = []
        for package_dict in packages_dict_list:
            try:
                package: Package = self.parse_package(package_dict)
                packages_list.append(package)
            except SPDXParsingError as err:
                self.logger.append_all(err.get_messages())
                continue
        if self.logger.has_messages():
            raise SPDXParsingError(self.logger.get_messages())

        return packages_list

    def parse_package(self, package_dict: Dict) -> Package:
        logger = Logger()
        name: str = package_dict.get("name")
        spdx_id: str = package_dict.get("SPDXID")
        attribution_texts: List[str] = package_dict.get("attributionTexts")
        try:
            built_date: Optional[datetime] = parse_optional_field(package_dict.get("builtDate"), datetime_from_str)
        except ValueError:
            logger.append("ValueError while parsing builtDate.")
            built_date = None
        try:
            checksums: List[Checksum] = parse_optional_field(package_dict.get("checksums"),
                                                             self.checksum_parser.parse_checksums, default=[])
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            checksums = []
        comment: Optional[str] = package_dict.get("comment")
        copyright_text: Optional[str] = package_dict.get("copyrightText")
        description: Optional[str] = package_dict.get("description")
        download_location: Union[str, SpdxNoAssertion, SpdxNone] = self.parse_download_location(
            package_dict.get("downloadLocation"))
        try:
            external_refs: List[ExternalPackageRef] = parse_optional_field(package_dict.get("externalRefs"),
                                                                           self.parse_external_refs)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            external_refs = []
        files_analyzed: Optional[bool] = parse_optional_field(package_dict.get("filesAnalyzed"), default=True)
        homepage: Optional[str] = package_dict.get("homepage")
        license_comments: Optional[str] = package_dict.get("licenseComments")
        try:
            license_concluded: Optional[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]] = parse_optional_field(
                package_dict.get("licenseConcluded"),
                self.license_expression_parser.parse_license_expression)
        except ConstructorTypeErrors as err:
            logger.append_all(err.get_messages())
            license_concluded = None
        try:
            license_declared: Optional[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]] = parse_optional_field(
                package_dict.get("licenseDeclared"),
                self.license_expression_parser.parse_license_expression)
        except ConstructorTypeErrors as err:
            logger.append_all(err.get_messages())
            license_declared = None
        try:
            license_info_from_file: Optional[
                Union[List[LicenseExpression], SpdxNoAssertion, SpdxNone]] = parse_optional_field(
                package_dict.get("licenseInfoFromFiles"),
                self.license_expression_parser.parse_license_expression)
        except ConstructorTypeErrors as err:
            logger.append_all(err.get_messages())
            license_info_from_file = None
        try:
            originator: Optional[Union[Actor, SpdxNoAssertion]] = parse_optional_field(package_dict.get("originator"),
                                                                                       self.actor_parser.parse_actor_or_no_assert)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            originator = None
        package_file_name: Optional[str] = package_dict.get("packageFileName")
        try:
            package_verification_code: Optional[PackageVerificationCode] = parse_optional_field(
                package_dict.get("packageVerificationCode"), self.parse_package_verification_code)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            package_verification_code = None

        try:
            primary_package_purpose: Optional[PackagePurpose] = parse_optional_field(
                package_dict.get("primaryPackagePurpose"), self.parse_primary_package_purpose)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            primary_package_purpose = None

        try:
            release_date: Optional[datetime] = parse_optional_field(package_dict.get("releaseDate"), datetime_from_str)
        except ValueError:
            logger.append("ValueError while parsing releaseDate.")
            release_date = None
        source_info: Optional[str] = package_dict.get("sourceInfo")
        summary: Optional[str] = package_dict.get("summary")
        try:
            supplier: Optional[Union[Actor, SpdxNoAssertion]] = parse_optional_field(package_dict.get("supplier"),
                                                                                     self.actor_parser.parse_actor_or_no_assert)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            supplier = None
        try:
            valid_until_date: Optional[datetime] = parse_optional_field(package_dict.get("validUntilDate"),
                                                                        datetime_from_str)
        except ValueError:
            logger.append("ValueError while parsing validUntilDate.")
            valid_until_date = None

        version_info: Optional[str] = package_dict.get("versionInfo")
        if logger.has_messages():
            raise SPDXParsingError([f"Error while parsing Package {name}: {logger.get_messages()}"])

        try:
            package = Package(spdx_id=spdx_id, name=name, download_location=download_location, version=version_info,
                              file_name=package_file_name, supplier=supplier, originator=originator,
                              files_analyzed=files_analyzed,
                              verification_code=package_verification_code, checksums=checksums, homepage=homepage,
                              source_info=source_info,
                              license_concluded=license_concluded, license_info_from_files=license_info_from_file,
                              license_declared=license_declared,
                              license_comment=license_comments, copyright_text=copyright_text, summary=summary,
                              description=description,
                              comment=comment, external_references=external_refs, attribution_texts=attribution_texts,
                              primary_package_purpose=primary_package_purpose,
                              release_date=release_date, built_date=built_date, valid_until_date=valid_until_date)

        except ConstructorTypeErrors as err:
            raise SPDXParsingError([f"Error while constructing Package {name}: {err.get_messages()}"])

        return package

    def parse_external_refs(self, external_ref_dicts: List[Dict]) -> List[ExternalPackageRef]:
        external_refs = []
        for external_ref_dict in external_ref_dicts:
            try:
                external_ref: ExternalPackageRef = self.parse_external_ref(external_ref_dict)
                external_refs.append(external_ref)
            except SPDXParsingError as err:
                self.logger.append_all(err.get_messages())
        return external_refs

    def parse_external_ref(self, external_ref_dict: Dict) -> ExternalPackageRef:
        logger = Logger()
        try:
            ref_category = self.parse_external_ref_category(external_ref_dict.get("referenceCategory"))
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            ref_category = None
        ref_locator = external_ref_dict.get("referenceLocator")
        ref_type = external_ref_dict.get("referenceType")
        comment = external_ref_dict.get("comment")
        if logger.has_messages():
            raise SPDXParsingError([f"Error while parsing external ref: {logger.get_messages()}"])
        try:
            external_ref = ExternalPackageRef(category=ref_category, reference_type=ref_type, locator=ref_locator,
                                              comment=comment)
        except ConstructorTypeErrors as err:
            raise SPDXParsingError([f"Error while constructing external ref: {err.get_messages()}"])

        return external_ref

    @staticmethod
    def parse_external_ref_category(external_ref_category_str: str) -> ExternalPackageRefCategory:
        try:
            external_ref_category = ExternalPackageRefCategory[
                transform_json_str_to_enum_name(external_ref_category_str)]
        except KeyError:
            raise SPDXParsingError([f"Category {external_ref_category_str} not valid for externalPackageRef."])

        return external_ref_category

    @staticmethod
    def parse_package_verification_code(verification_code_dict: Dict) -> PackageVerificationCode:
        excluded_files: List[str] = verification_code_dict.get("packageVerificationCodeExcludedFiles")
        verification_code_value: str = verification_code_dict.get("packageVerificationCodeValue")
        try:
            package_verification_code = PackageVerificationCode(value=verification_code_value,
                                                                excluded_files=excluded_files)
        except ConstructorTypeErrors as err:
            raise SPDXParsingError([f"Error while parsing package verification code: {err.get_messages()}"])

        return package_verification_code

    @staticmethod
    def parse_primary_package_purpose(primary_package_purpose: str) -> PackagePurpose:
        try:
            return PackagePurpose[transform_json_str_to_enum_name(primary_package_purpose)]
        except KeyError:
            raise SPDXParsingError([f"Invalid primaryPackagePurpose: {primary_package_purpose}"])

    @staticmethod
    def parse_download_location(download_location: str) -> Union[str, SpdxNoAssertion, SpdxNone]:
        if download_location == SpdxNone().__str__():
inproject
# Copyright (c) 2022 spdx contributors
# 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.
from datetime import datetime
from typing import Dict, List, Optional, Union

from src.model.actor import Actor
from src.model.checksum import Checksum
from src.model.license_expression import LicenseExpression
from src.model.package import Package, ExternalPackageRef, PackageVerificationCode, PackagePurpose, \
    ExternalPackageRefCategory
from src.model.spdx_no_assertion import SpdxNoAssertion
from src.model.spdx_none import SpdxNone
from src.model.typing.constructor_type_errors import ConstructorTypeErrors
from src.parser.error import SPDXParsingError
from src.parser.json.actor_parser import ActorParser
from src.parser.json.checksum_parser import ChecksumParser
from src.parser.json.dict_parsing_functions import datetime_from_str, parse_optional_field, \
    transform_json_str_to_enum_name
from src.parser.json.license_expression_parser import LicenseExpressionParser
from src.parser.logger import Logger


class PackageParser:
    logger: Logger
    actor_parser: ActorParser
    checksum_parser: ChecksumParser
    license_expression_parser: LicenseExpressionParser

    def __init__(self):
        self.actor_parser = ActorParser()
        self.checksum_parser = ChecksumParser()
        self.license_expression_parser = LicenseExpressionParser()
        self.logger = Logger()

    def parse_packages(self, packages_dict_list: List[Dict]) -> List[Package]:
        packages_list = []
        for package_dict in packages_dict_list:
            try:
                package: Package = self.parse_package(package_dict)
                packages_list.append(package)
            except SPDXParsingError as err:
                self.logger.append_all(err.get_messages())
                continue
        if self.logger.has_messages():
            raise SPDXParsingError(self.logger.get_messages())

        return packages_list

    def parse_package(self, package_dict: Dict) -> Package:
        logger = Logger()
        name: str = package_dict.get("name")
        spdx_id: str = package_dict.get("SPDXID")
        attribution_texts: List[str] = package_dict.get("attributionTexts")
        try:
            built_date: Optional[datetime] = parse_optional_field(package_dict.get("builtDate"), datetime_from_str)
        except ValueError:
            logger.append("ValueError while parsing builtDate.")
            built_date = None
        try:
            checksums: List[Checksum] = parse_optional_field(package_dict.get("checksums"),
                                                             self.checksum_parser.parse_checksums, default=[])
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            checksums = []
        comment: Optional[str] = package_dict.get("comment")
        copyright_text: Optional[str] = package_dict.get("copyrightText")
        description: Optional[str] = package_dict.get("description")
        download_location: Union[str, SpdxNoAssertion, SpdxNone] = self.parse_download_location(
            package_dict.get("downloadLocation"))
        try:
            external_refs: List[ExternalPackageRef] = parse_optional_field(package_dict.get("externalRefs"),
                                                                           self.parse_external_refs)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            external_refs = []
        files_analyzed: Optional[bool] = parse_optional_field(package_dict.get("filesAnalyzed"), default=True)
        homepage: Optional[str] = package_dict.get("homepage")
        license_comments: Optional[str] = package_dict.get("licenseComments")
        try:
            license_concluded: Optional[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]] = parse_optional_field(
                package_dict.get("licenseConcluded"),
                self.license_expression_parser.parse_license_expression)
        except ConstructorTypeErrors as err:
            logger.append_all(err.get_messages())
            license_concluded = None
        try:
            license_declared: Optional[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]] = parse_optional_field(
                package_dict.get("licenseDeclared"),
                self.license_expression_parser.parse_license_expression)
        except ConstructorTypeErrors as err:
            logger.append_all(err.get_messages())
            license_declared = None
        try:
            license_info_from_file: Optional[
                Union[List[LicenseExpression], SpdxNoAssertion, SpdxNone]] = parse_optional_field(
                package_dict.get("licenseInfoFromFiles"),
                self.license_expression_parser.parse_license_expression)
        except ConstructorTypeErrors as err:
            logger.append_all(err.get_messages())
            license_info_from_file = None
        try:
            originator: Optional[Union[Actor, SpdxNoAssertion]] = parse_optional_field(package_dict.get("originator"),
                                                                                       self.actor_parser.parse_actor_or_no_assert)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            originator = None
        package_file_name: Optional[str] = package_dict.get("packageFileName")
        try:
            package_verification_code: Optional[PackageVerificationCode] = parse_optional_field(
                package_dict.get("packageVerificationCode"), self.parse_package_verification_code)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            package_verification_code = None

        try:
            primary_package_purpose: Optional[PackagePurpose] = parse_optional_field(
                package_dict.get("primaryPackagePurpose"), self.parse_primary_package_purpose)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            primary_package_purpose = None

        try:
            release_date: Optional[datetime] = parse_optional_field(package_dict.get("releaseDate"), datetime_from_str)
        except ValueError:
            logger.append("ValueError while parsing releaseDate.")
            release_date = None
        source_info: Optional[str] = package_dict.get("sourceInfo")
        summary: Optional[str] = package_dict.get("summary")
        try:
            supplier: Optional[Union[Actor, SpdxNoAssertion]] = parse_optional_field(package_dict.get("supplier"),
                                                                                     self.actor_parser.parse_actor_or_no_assert)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            supplier = None
        try:
            valid_until_date: Optional[datetime] = parse_optional_field(package_dict.get("validUntilDate"),
                                                                        datetime_from_str)
        except ValueError:
            logger.append("ValueError while parsing validUntilDate.")
            valid_until_date = None

        version_info: Optional[str] = package_dict.get("versionInfo")
        if logger.has_messages():
            raise SPDXParsingError([f"Error while parsing Package {name}: {logger.get_messages()}"])

        try:
            package = Package(spdx_id=spdx_id, name=name, download_location=download_location, version=version_info,
                              file_name=package_file_name, supplier=supplier, originator=originator,
                              files_analyzed=files_analyzed,
                              verification_code=package_verification_code, checksums=checksums, homepage=homepage,
                              source_info=source_info,
                              license_concluded=license_concluded, license_info_from_files=license_info_from_file,
                              license_declared=license_declared,
                              license_comment=license_comments, copyright_text=copyright_text, summary=summary,
                              description=description,
                              comment=comment, external_references=external_refs, attribution_texts=attribution_texts,
                              primary_package_purpose=primary_package_purpose,
                              release_date=release_date, built_date=built_date, valid_until_date=valid_until_date)

        except ConstructorTypeErrors as err:
            raise SPDXParsingError([f"Error while constructing Package {name}: {err.get_messages()}"])

        return package

    def parse_external_refs(self, external_ref_dicts: List[Dict]) -> List[ExternalPackageRef]:
        external_refs = []
        for external_ref_dict in external_ref_dicts:
            try:
                external_ref: ExternalPackageRef = self.parse_external_ref(external_ref_dict)
                external_refs.append(external_ref)
            except SPDXParsingError as err:
                self.logger.append_all(err.get_messages())
        return external_refs

    def parse_external_ref(self, external_ref_dict: Dict) -> ExternalPackageRef:
        logger = Logger()
        try:
            ref_category = self.parse_external_ref_category(external_ref_dict.get("referenceCategory"))
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            ref_category = None
        ref_locator = external_ref_dict.get("referenceLocator")
        ref_type = external_ref_dict.get("referenceType")
        comment = external_ref_dict.get("comment")
        if logger.has_messages():
            raise SPDXParsingError([f"Error while parsing external ref: {logger.get_messages()}"])
        try:
            external_ref = ExternalPackageRef(category=ref_category, reference_type=ref_type, locator=ref_locator,
                                              comment=comment)
        except ConstructorTypeErrors as err:
            raise SPDXParsingError([f"Error while constructing external ref: {err.get_messages()}"])

        return external_ref

    @staticmethod
    def parse_external_ref_category(external_ref_category_str: str) -> ExternalPackageRefCategory:
        try:
            external_ref_category = ExternalPackageRefCategory[
                transform_json_str_to_enum_name(external_ref_category_str)]
        except KeyError:
            raise SPDXParsingError([f"Category {external_ref_category_str} not valid for externalPackageRef."])

        return external_ref_category

    @staticmethod
    def parse_package_verification_code(verification_code_dict: Dict) -> PackageVerificationCode:
        excluded_files: List[str] = verification_code_dict.get("packageVerificationCodeExcludedFiles")
        verification_code_value: str = verification_code_dict.get("packageVerificationCodeValue")
        try:
            package_verification_code = PackageVerificationCode(value=verification_code_value,
                                                                excluded_files=excluded_files)
        except ConstructorTypeErrors as err:
            raise SPDXParsingError([f"Error while parsing package verification code: {err.get_messages()}"])

        return package_verification_code

    @staticmethod
    def parse_primary_package_purpose(primary_package_purpose: str) -> PackagePurpose:
        try:
            return PackagePurpose[transform_json_str_to_enum_name(primary_package_purpose)]
        except KeyError:
            raise SPDXParsingError([f"Invalid primaryPackagePurpose: {primary_package_purpose}"])

    @staticmethod
    def parse_download_location(download_location: str) -> Union[str, SpdxNoAssertion, SpdxNone]:
        if download_location == SpdxNone().__str__():
            return SpdxNone()
inproject
# Copyright (c) 2022 spdx contributors
# 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.
from datetime import datetime
from typing import Dict, List, Optional, Union

from src.model.actor import Actor
from src.model.checksum import Checksum
from src.model.license_expression import LicenseExpression
from src.model.package import Package, ExternalPackageRef, PackageVerificationCode, PackagePurpose, \
    ExternalPackageRefCategory
from src.model.spdx_no_assertion import SpdxNoAssertion
from src.model.spdx_none import SpdxNone
from src.model.typing.constructor_type_errors import ConstructorTypeErrors
from src.parser.error import SPDXParsingError
from src.parser.json.actor_parser import ActorParser
from src.parser.json.checksum_parser import ChecksumParser
from src.parser.json.dict_parsing_functions import datetime_from_str, parse_optional_field, \
    transform_json_str_to_enum_name
from src.parser.json.license_expression_parser import LicenseExpressionParser
from src.parser.logger import Logger


class PackageParser:
    logger: Logger
    actor_parser: ActorParser
    checksum_parser: ChecksumParser
    license_expression_parser: LicenseExpressionParser

    def __init__(self):
        self.actor_parser = ActorParser()
        self.checksum_parser = ChecksumParser()
        self.license_expression_parser = LicenseExpressionParser()
        self.logger = Logger()

    def parse_packages(self, packages_dict_list: List[Dict]) -> List[Package]:
        packages_list = []
        for package_dict in packages_dict_list:
            try:
                package: Package = self.parse_package(package_dict)
                packages_list.append(package)
            except SPDXParsingError as err:
                self.logger.append_all(err.get_messages())
                continue
        if self.logger.has_messages():
            raise SPDXParsingError(self.logger.get_messages())

        return packages_list

    def parse_package(self, package_dict: Dict) -> Package:
        logger = Logger()
        name: str = package_dict.get("name")
        spdx_id: str = package_dict.get("SPDXID")
        attribution_texts: List[str] = package_dict.get("attributionTexts")
        try:
            built_date: Optional[datetime] = parse_optional_field(package_dict.get("builtDate"), datetime_from_str)
        except ValueError:
            logger.append("ValueError while parsing builtDate.")
            built_date = None
        try:
            checksums: List[Checksum] = parse_optional_field(package_dict.get("checksums"),
                                                             self.checksum_parser.parse_checksums, default=[])
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            checksums = []
        comment: Optional[str] = package_dict.get("comment")
        copyright_text: Optional[str] = package_dict.get("copyrightText")
        description: Optional[str] = package_dict.get("description")
        download_location: Union[str, SpdxNoAssertion, SpdxNone] = self.parse_download_location(
            package_dict.get("downloadLocation"))
        try:
            external_refs: List[ExternalPackageRef] = parse_optional_field(package_dict.get("externalRefs"),
                                                                           self.parse_external_refs)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            external_refs = []
        files_analyzed: Optional[bool] = parse_optional_field(package_dict.get("filesAnalyzed"), default=True)
        homepage: Optional[str] = package_dict.get("homepage")
        license_comments: Optional[str] = package_dict.get("licenseComments")
        try:
            license_concluded: Optional[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]] = parse_optional_field(
                package_dict.get("licenseConcluded"),
                self.license_expression_parser.parse_license_expression)
        except ConstructorTypeErrors as err:
            logger.append_all(err.get_messages())
            license_concluded = None
        try:
            license_declared: Optional[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]] = parse_optional_field(
                package_dict.get("licenseDeclared"),
                self.license_expression_parser.parse_license_expression)
        except ConstructorTypeErrors as err:
            logger.append_all(err.get_messages())
            license_declared = None
        try:
            license_info_from_file: Optional[
                Union[List[LicenseExpression], SpdxNoAssertion, SpdxNone]] = parse_optional_field(
                package_dict.get("licenseInfoFromFiles"),
                self.license_expression_parser.parse_license_expression)
        except ConstructorTypeErrors as err:
            logger.append_all(err.get_messages())
            license_info_from_file = None
        try:
inproject
# Copyright (c) 2022 spdx contributors
# 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.
from datetime import datetime
from typing import Dict, List, Optional, Union

from src.model.actor import Actor
from src.model.checksum import Checksum
from src.model.license_expression import LicenseExpression
from src.model.package import Package, ExternalPackageRef, PackageVerificationCode, PackagePurpose, \
    ExternalPackageRefCategory
from src.model.spdx_no_assertion import SpdxNoAssertion
from src.model.spdx_none import SpdxNone
from src.model.typing.constructor_type_errors import ConstructorTypeErrors
from src.parser.error import SPDXParsingError
from src.parser.json.actor_parser import ActorParser
from src.parser.json.checksum_parser import ChecksumParser
from src.parser.json.dict_parsing_functions import datetime_from_str, parse_optional_field, \
    transform_json_str_to_enum_name
from src.parser.json.license_expression_parser import LicenseExpressionParser
from src.parser.logger import Logger


class PackageParser:
    logger: Logger
    actor_parser: ActorParser
    checksum_parser: ChecksumParser
    license_expression_parser: LicenseExpressionParser

    def __init__(self):
        self.actor_parser = ActorParser()
        self.checksum_parser = ChecksumParser()
        self.license_expression_parser = LicenseExpressionParser()
        self.logger = Logger()

    def parse_packages(self, packages_dict_list: List[Dict]) -> List[Package]:
        packages_list = []
        for package_dict in packages_dict_list:
            try:
                package: Package = self.parse_package(package_dict)
                packages_list.append(package)
            except SPDXParsingError as err:
                self.logger.append_all(err.get_messages())
                continue
        if self.logger.has_messages():
            raise SPDXParsingError(self.logger.get_messages())

        return packages_list

    def parse_package(self, package_dict: Dict) -> Package:
        logger = Logger()
        name: str = package_dict.get("name")
        spdx_id: str = package_dict.get("SPDXID")
        attribution_texts: List[str] = package_dict.get("attributionTexts")
        try:
            built_date: Optional[datetime] = parse_optional_field(package_dict.get("builtDate"), datetime_from_str)
        except ValueError:
            logger.append("ValueError while parsing builtDate.")
            built_date = None
        try:
            checksums: List[Checksum] = parse_optional_field(package_dict.get("checksums"),
                                                             self.checksum_parser.parse_checksums, default=[])
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            checksums = []
        comment: Optional[str] = package_dict.get("comment")
        copyright_text: Optional[str] = package_dict.get("copyrightText")
        description: Optional[str] = package_dict.get("description")
        download_location: Union[str, SpdxNoAssertion, SpdxNone] = self.parse_download_location(
            package_dict.get("downloadLocation"))
        try:
            external_refs: List[ExternalPackageRef] = parse_optional_field(package_dict.get("externalRefs"),
                                                                           self.parse_external_refs)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            external_refs = []
        files_analyzed: Optional[bool] = parse_optional_field(package_dict.get("filesAnalyzed"), default=True)
        homepage: Optional[str] = package_dict.get("homepage")
        license_comments: Optional[str] = package_dict.get("licenseComments")
        try:
            license_concluded: Optional[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]] = parse_optional_field(
                package_dict.get("licenseConcluded"),
                self.license_expression_parser.parse_license_expression)
        except ConstructorTypeErrors as err:
            logger.append_all(err.get_messages())
            license_concluded = None
        try:
            license_declared: Optional[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]] = parse_optional_field(
                package_dict.get("licenseDeclared"),
                self.license_expression_parser.parse_license_expression)
        except ConstructorTypeErrors as err:
            logger.append_all(err.get_messages())
            license_declared = None
        try:
            license_info_from_file: Optional[
                Union[List[LicenseExpression], SpdxNoAssertion, SpdxNone]] = parse_optional_field(
                package_dict.get("licenseInfoFromFiles"),
                self.license_expression_parser.parse_license_expression)
        except ConstructorTypeErrors as err:
            logger.append_all(err.get_messages())
            license_info_from_file = None
        try:
            originator: Optional[Union[Actor, SpdxNoAssertion]] = parse_optional_field(package_dict.get("originator"),
                                                                                       self.actor_parser.parse_actor_or_no_assert)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            originator = None
        package_file_name: Optional[str] = package_dict.get("packageFileName")
        try:
            package_verification_code: Optional[PackageVerificationCode] = parse_optional_field(
                package_dict.get("packageVerificationCode"), self.parse_package_verification_code)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            package_verification_code = None

        try:
            primary_package_purpose: Optional[PackagePurpose] = parse_optional_field(
                package_dict.get("primaryPackagePurpose"), self.parse_primary_package_purpose)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            primary_package_purpose = None

        try:
            release_date: Optional[datetime] = parse_optional_field(package_dict.get("releaseDate"), datetime_from_str)
        except ValueError:
            logger.append("ValueError while parsing releaseDate.")
            release_date = None
        source_info: Optional[str] = package_dict.get("sourceInfo")
        summary: Optional[str] = package_dict.get("summary")
        try:
            supplier: Optional[Union[Actor, SpdxNoAssertion]] = parse_optional_field(package_dict.get("supplier"),
                                                                                     self.actor_parser.parse_actor_or_no_assert)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            supplier = None
        try:
            valid_until_date: Optional[datetime] = parse_optional_field(package_dict.get("validUntilDate"),
                                                                        datetime_from_str)
        except ValueError:
            logger.append("ValueError while parsing validUntilDate.")
            valid_until_date = None

        version_info: Optional[str] = package_dict.get("versionInfo")
        if logger.has_messages():
            raise SPDXParsingError([f"Error while parsing Package {name}: {logger.get_messages()}"])

        try:
            package = Package(spdx_id=spdx_id, name=name, download_location=download_location, version=version_info,
                              file_name=package_file_name, supplier=supplier, originator=originator,
                              files_analyzed=files_analyzed,
                              verification_code=package_verification_code, checksums=checksums, homepage=homepage,
                              source_info=source_info,
                              license_concluded=license_concluded, license_info_from_files=license_info_from_file,
                              license_declared=license_declared,
                              license_comment=license_comments, copyright_text=copyright_text, summary=summary,
                              description=description,
                              comment=comment, external_references=external_refs, attribution_texts=attribution_texts,
                              primary_package_purpose=primary_package_purpose,
                              release_date=release_date, built_date=built_date, valid_until_date=valid_until_date)

        except ConstructorTypeErrors as err:
            raise SPDXParsingError([f"Error while constructing Package {name}: {err.get_messages()}"])

        return package

    def parse_external_refs(self, external_ref_dicts: List[Dict]) -> List[ExternalPackageRef]:
        external_refs = []
        for external_ref_dict in external_ref_dicts:
            try:
                external_ref: ExternalPackageRef = self.parse_external_ref(external_ref_dict)
                external_refs.append(external_ref)
            except SPDXParsingError as err:
                self.logger.append_all(err.get_messages())
        return external_refs

    def parse_external_ref(self, external_ref_dict: Dict) -> ExternalPackageRef:
        logger = Logger()
        try:
            ref_category = self.parse_external_ref_category(external_ref_dict.get("referenceCategory"))
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            ref_category = None
        ref_locator = external_ref_dict.get("referenceLocator")
        ref_type = external_ref_dict.get("referenceType")
        comment = external_ref_dict.get("comment")
        if logger.has_messages():
            raise SPDXParsingError([f"Error while parsing external ref: {logger.get_messages()}"])
        try:
            external_ref = ExternalPackageRef(category=ref_category, reference_type=ref_type, locator=ref_locator,
                                              comment=comment)
        except ConstructorTypeErrors as err:
            raise SPDXParsingError([f"Error while constructing external ref: {err.get_messages()}"])

        return external_ref

    @staticmethod
    def parse_external_ref_category(external_ref_category_str: str) -> ExternalPackageRefCategory:
        try:
            external_ref_category = ExternalPackageRefCategory[
                transform_json_str_to_enum_name(external_ref_category_str)]
        except KeyError:
            raise SPDXParsingError([f"Category {external_ref_category_str} not valid for externalPackageRef."])

        return external_ref_category

    @staticmethod
    def parse_package_verification_code(verification_code_dict: Dict) -> PackageVerificationCode:
        excluded_files: List[str] = verification_code_dict.get("packageVerificationCodeExcludedFiles")
        verification_code_value: str = verification_code_dict.get("packageVerificationCodeValue")
        try:
            package_verification_code = PackageVerificationCode(value=verification_code_value,
                                                                excluded_files=excluded_files)
        except ConstructorTypeErrors as err:
            raise SPDXParsingError([f"Error while parsing package verification code: {err.get_messages()}"])

        return package_verification_code

    @staticmethod
    def parse_primary_package_purpose(primary_package_purpose: str) -> PackagePurpose:
        try:
            return PackagePurpose[transform_json_str_to_enum_name(primary_package_purpose)]
        except KeyError:
            raise SPDXParsingError([f"Invalid primaryPackagePurpose: {primary_package_purpose}"])

    @staticmethod
    def parse_download_location(download_location: str) -> Union[str, SpdxNoAssertion, SpdxNone]:
        if download_location == SpdxNone().__str__():
            return SpdxNone()
        if download_location == SpdxNoAssertion().__str__():
inproject
# Copyright (c) 2022 spdx contributors
# 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.
from datetime import datetime
from typing import Dict, List, Optional, Union

from src.model.actor import Actor
from src.model.checksum import Checksum
from src.model.license_expression import LicenseExpression
from src.model.package import Package, ExternalPackageRef, PackageVerificationCode, PackagePurpose, \
    ExternalPackageRefCategory
from src.model.spdx_no_assertion import SpdxNoAssertion
from src.model.spdx_none import SpdxNone
from src.model.typing.constructor_type_errors import ConstructorTypeErrors
from src.parser.error import SPDXParsingError
from src.parser.json.actor_parser import ActorParser
from src.parser.json.checksum_parser import ChecksumParser
from src.parser.json.dict_parsing_functions import datetime_from_str, parse_optional_field, \
    transform_json_str_to_enum_name
from src.parser.json.license_expression_parser import LicenseExpressionParser
from src.parser.logger import Logger


class PackageParser:
    logger: Logger
    actor_parser: ActorParser
    checksum_parser: ChecksumParser
    license_expression_parser: LicenseExpressionParser

    def __init__(self):
        self.actor_parser = ActorParser()
        self.checksum_parser = ChecksumParser()
        self.license_expression_parser = LicenseExpressionParser()
        self.logger = Logger()

    def parse_packages(self, packages_dict_list: List[Dict]) -> List[Package]:
        packages_list = []
        for package_dict in packages_dict_list:
            try:
                package: Package = self.parse_package(package_dict)
                packages_list.append(package)
            except SPDXParsingError as err:
                self.logger.append_all(err.get_messages())
                continue
        if self.logger.has_messages():
            raise SPDXParsingError(self.logger.get_messages())

        return packages_list

    def parse_package(self, package_dict: Dict) -> Package:
        logger = Logger()
        name: str = package_dict.get("name")
        spdx_id: str = package_dict.get("SPDXID")
        attribution_texts: List[str] = package_dict.get("attributionTexts")
        try:
            built_date: Optional[datetime] = parse_optional_field(package_dict.get("builtDate"), datetime_from_str)
        except ValueError:
            logger.append("ValueError while parsing builtDate.")
            built_date = None
        try:
            checksums: List[Checksum] = parse_optional_field(package_dict.get("checksums"),
                                                             self.checksum_parser.parse_checksums, default=[])
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            checksums = []
        comment: Optional[str] = package_dict.get("comment")
        copyright_text: Optional[str] = package_dict.get("copyrightText")
        description: Optional[str] = package_dict.get("description")
        download_location: Union[str, SpdxNoAssertion, SpdxNone] = self.parse_download_location(
            package_dict.get("downloadLocation"))
        try:
            external_refs: List[ExternalPackageRef] = parse_optional_field(package_dict.get("externalRefs"),
                                                                           self.parse_external_refs)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            external_refs = []
        files_analyzed: Optional[bool] = parse_optional_field(package_dict.get("filesAnalyzed"), default=True)
        homepage: Optional[str] = package_dict.get("homepage")
        license_comments: Optional[str] = package_dict.get("licenseComments")
        try:
            license_concluded: Optional[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]] = parse_optional_field(
                package_dict.get("licenseConcluded"),
                self.license_expression_parser.parse_license_expression)
        except ConstructorTypeErrors as err:
            logger.append_all(err.get_messages())
            license_concluded = None
        try:
            license_declared: Optional[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]] = parse_optional_field(
                package_dict.get("licenseDeclared"),
                self.license_expression_parser.parse_license_expression)
        except ConstructorTypeErrors as err:
            logger.append_all(err.get_messages())
            license_declared = None
        try:
            license_info_from_file: Optional[
                Union[List[LicenseExpression], SpdxNoAssertion, SpdxNone]] = parse_optional_field(
                package_dict.get("licenseInfoFromFiles"),
                self.license_expression_parser.parse_license_expression)
        except ConstructorTypeErrors as err:
            logger.append_all(err.get_messages())
            license_info_from_file = None
        try:
            originator: Optional[Union[Actor, SpdxNoAssertion]] = parse_optional_field(package_dict.get("originator"),
                                                                                       self.actor_parser.parse_actor_or_no_assert)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            originator = None
        package_file_name: Optional[str] = package_dict.get("packageFileName")
        try:
inproject
# Copyright (c) 2022 spdx contributors
# 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.
from datetime import datetime
from typing import Dict, List, Optional, Union

from src.model.actor import Actor
from src.model.checksum import Checksum
from src.model.license_expression import LicenseExpression
from src.model.package import Package, ExternalPackageRef, PackageVerificationCode, PackagePurpose, \
    ExternalPackageRefCategory
from src.model.spdx_no_assertion import SpdxNoAssertion
from src.model.spdx_none import SpdxNone
from src.model.typing.constructor_type_errors import ConstructorTypeErrors
from src.parser.error import SPDXParsingError
from src.parser.json.actor_parser import ActorParser
from src.parser.json.checksum_parser import ChecksumParser
from src.parser.json.dict_parsing_functions import datetime_from_str, parse_optional_field, \
    transform_json_str_to_enum_name
from src.parser.json.license_expression_parser import LicenseExpressionParser
from src.parser.logger import Logger


class PackageParser:
    logger: Logger
    actor_parser: ActorParser
    checksum_parser: ChecksumParser
    license_expression_parser: LicenseExpressionParser

    def __init__(self):
        self.actor_parser = ActorParser()
        self.checksum_parser = ChecksumParser()
        self.license_expression_parser = LicenseExpressionParser()
        self.logger = Logger()

    def parse_packages(self, packages_dict_list: List[Dict]) -> List[Package]:
        packages_list = []
        for package_dict in packages_dict_list:
            try:
                package: Package = self.parse_package(package_dict)
                packages_list.append(package)
            except SPDXParsingError as err:
                self.logger.append_all(err.get_messages())
                continue
        if self.logger.has_messages():
            raise SPDXParsingError(self.logger.get_messages())

        return packages_list

    def parse_package(self, package_dict: Dict) -> Package:
        logger = Logger()
        name: str = package_dict.get("name")
        spdx_id: str = package_dict.get("SPDXID")
        attribution_texts: List[str] = package_dict.get("attributionTexts")
        try:
            built_date: Optional[datetime] = parse_optional_field(package_dict.get("builtDate"), datetime_from_str)
        except ValueError:
            logger.append("ValueError while parsing builtDate.")
            built_date = None
        try:
            checksums: List[Checksum] = parse_optional_field(package_dict.get("checksums"),
                                                             self.checksum_parser.parse_checksums, default=[])
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            checksums = []
        comment: Optional[str] = package_dict.get("comment")
        copyright_text: Optional[str] = package_dict.get("copyrightText")
        description: Optional[str] = package_dict.get("description")
        download_location: Union[str, SpdxNoAssertion, SpdxNone] = self.parse_download_location(
            package_dict.get("downloadLocation"))
        try:
            external_refs: List[ExternalPackageRef] = parse_optional_field(package_dict.get("externalRefs"),
                                                                           self.parse_external_refs)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            external_refs = []
        files_analyzed: Optional[bool] = parse_optional_field(package_dict.get("filesAnalyzed"), default=True)
        homepage: Optional[str] = package_dict.get("homepage")
        license_comments: Optional[str] = package_dict.get("licenseComments")
        try:
            license_concluded: Optional[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]] = parse_optional_field(
                package_dict.get("licenseConcluded"),
                self.license_expression_parser.parse_license_expression)
        except ConstructorTypeErrors as err:
            logger.append_all(err.get_messages())
            license_concluded = None
        try:
            license_declared: Optional[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]] = parse_optional_field(
                package_dict.get("licenseDeclared"),
                self.license_expression_parser.parse_license_expression)
        except ConstructorTypeErrors as err:
            logger.append_all(err.get_messages())
            license_declared = None
        try:
            license_info_from_file: Optional[
                Union[List[LicenseExpression], SpdxNoAssertion, SpdxNone]] = parse_optional_field(
                package_dict.get("licenseInfoFromFiles"),
                self.license_expression_parser.parse_license_expression)
        except ConstructorTypeErrors as err:
            logger.append_all(err.get_messages())
            license_info_from_file = None
        try:
            originator: Optional[Union[Actor, SpdxNoAssertion]] = parse_optional_field(package_dict.get("originator"),
                                                                                       self.actor_parser.parse_actor_or_no_assert)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            originator = None
        package_file_name: Optional[str] = package_dict.get("packageFileName")
        try:
            package_verification_code: Optional[PackageVerificationCode] = parse_optional_field(
                package_dict.get("packageVerificationCode"), self.parse_package_verification_code)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            package_verification_code = None

        try:
inproject
# Copyright (c) 2022 spdx contributors
# 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.
from datetime import datetime
from typing import Dict, List, Optional, Union

from src.model.actor import Actor
from src.model.checksum import Checksum
from src.model.license_expression import LicenseExpression
from src.model.package import Package, ExternalPackageRef, PackageVerificationCode, PackagePurpose, \
    ExternalPackageRefCategory
from src.model.spdx_no_assertion import SpdxNoAssertion
from src.model.spdx_none import SpdxNone
from src.model.typing.constructor_type_errors import ConstructorTypeErrors
from src.parser.error import SPDXParsingError
from src.parser.json.actor_parser import ActorParser
from src.parser.json.checksum_parser import ChecksumParser
from src.parser.json.dict_parsing_functions import datetime_from_str, parse_optional_field, \
    transform_json_str_to_enum_name
from src.parser.json.license_expression_parser import LicenseExpressionParser
from src.parser.logger import Logger


class PackageParser:
    logger: Logger
    actor_parser: ActorParser
    checksum_parser: ChecksumParser
    license_expression_parser: LicenseExpressionParser

    def __init__(self):
        self.actor_parser = ActorParser()
        self.checksum_parser = ChecksumParser()
        self.license_expression_parser = LicenseExpressionParser()
        self.logger = Logger()

    def parse_packages(self, packages_dict_list: List[Dict]) -> List[Package]:
        packages_list = []
        for package_dict in packages_dict_list:
            try:
                package: Package = self.parse_package(package_dict)
                packages_list.append(package)
            except SPDXParsingError as err:
                self.logger.append_all(err.get_messages())
                continue
        if self.logger.has_messages():
            raise SPDXParsingError(self.logger.get_messages())

        return packages_list

    def parse_package(self, package_dict: Dict) -> Package:
        logger = Logger()
        name: str = package_dict.get("name")
        spdx_id: str = package_dict.get("SPDXID")
        attribution_texts: List[str] = package_dict.get("attributionTexts")
        try:
            built_date: Optional[datetime] = parse_optional_field(package_dict.get("builtDate"), datetime_from_str)
        except ValueError:
            logger.append("ValueError while parsing builtDate.")
            built_date = None
        try:
            checksums: List[Checksum] = parse_optional_field(package_dict.get("checksums"),
                                                             self.checksum_parser.parse_checksums, default=[])
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            checksums = []
        comment: Optional[str] = package_dict.get("comment")
        copyright_text: Optional[str] = package_dict.get("copyrightText")
        description: Optional[str] = package_dict.get("description")
        download_location: Union[str, SpdxNoAssertion, SpdxNone] = self.parse_download_location(
            package_dict.get("downloadLocation"))
        try:
            external_refs: List[ExternalPackageRef] = parse_optional_field(package_dict.get("externalRefs"),
                                                                           self.parse_external_refs)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            external_refs = []
        files_analyzed: Optional[bool] = parse_optional_field(package_dict.get("filesAnalyzed"), default=True)
        homepage: Optional[str] = package_dict.get("homepage")
        license_comments: Optional[str] = package_dict.get("licenseComments")
        try:
            license_concluded: Optional[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]] = parse_optional_field(
                package_dict.get("licenseConcluded"),
                self.license_expression_parser.parse_license_expression)
        except ConstructorTypeErrors as err:
            logger.append_all(err.get_messages())
            license_concluded = None
        try:
            license_declared: Optional[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]] = parse_optional_field(
                package_dict.get("licenseDeclared"),
                self.license_expression_parser.parse_license_expression)
        except ConstructorTypeErrors as err:
            logger.append_all(err.get_messages())
            license_declared = None
        try:
            license_info_from_file: Optional[
                Union[List[LicenseExpression], SpdxNoAssertion, SpdxNone]] = parse_optional_field(
                package_dict.get("licenseInfoFromFiles"),
                self.license_expression_parser.parse_license_expression)
        except ConstructorTypeErrors as err:
            logger.append_all(err.get_messages())
            license_info_from_file = None
        try:
            originator: Optional[Union[Actor, SpdxNoAssertion]] = parse_optional_field(package_dict.get("originator"),
                                                                                       self.actor_parser.parse_actor_or_no_assert)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            originator = None
        package_file_name: Optional[str] = package_dict.get("packageFileName")
        try:
            package_verification_code: Optional[PackageVerificationCode] = parse_optional_field(
                package_dict.get("packageVerificationCode"), self.parse_package_verification_code)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            package_verification_code = None

        try:
            primary_package_purpose: Optional[PackagePurpose] = parse_optional_field(
                package_dict.get("primaryPackagePurpose"), self.parse_primary_package_purpose)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            primary_package_purpose = None

        try:
common
# Copyright (c) 2022 spdx contributors
# 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.
from datetime import datetime
from typing import Dict, List, Optional, Union

from src.model.actor import Actor
from src.model.checksum import Checksum
from src.model.license_expression import LicenseExpression
from src.model.package import Package, ExternalPackageRef, PackageVerificationCode, PackagePurpose, \
    ExternalPackageRefCategory
from src.model.spdx_no_assertion import SpdxNoAssertion
from src.model.spdx_none import SpdxNone
from src.model.typing.constructor_type_errors import ConstructorTypeErrors
from src.parser.error import SPDXParsingError
from src.parser.json.actor_parser import ActorParser
from src.parser.json.checksum_parser import ChecksumParser
from src.parser.json.dict_parsing_functions import datetime_from_str, parse_optional_field, \
    transform_json_str_to_enum_name
from src.parser.json.license_expression_parser import LicenseExpressionParser
from src.parser.logger import Logger


class PackageParser:
    logger: Logger
    actor_parser: ActorParser
    checksum_parser: ChecksumParser
    license_expression_parser: LicenseExpressionParser

    def __init__(self):
        self.actor_parser = ActorParser()
        self.checksum_parser = ChecksumParser()
        self.license_expression_parser = LicenseExpressionParser()
        self.logger = Logger()

    def parse_packages(self, packages_dict_list: List[Dict]) -> List[Package]:
        packages_list = []
        for package_dict in packages_dict_list:
            try:
                package: Package = self.parse_package(package_dict)
                packages_list.append(package)
            except SPDXParsingError as err:
                self.logger.append_all(err.get_messages())
                continue
        if self.logger.has_messages():
            raise SPDXParsingError(self.logger.get_messages())

        return packages_list

    def parse_package(self, package_dict: Dict) -> Package:
        logger = Logger()
        name: str = package_dict.get("name")
        spdx_id: str = package_dict.get("SPDXID")
        attribution_texts: List[str] = package_dict.get("attributionTexts")
        try:
            built_date: Optional[datetime] = parse_optional_field(package_dict.get("builtDate"), datetime_from_str)
        except ValueError:
            logger.append("ValueError while parsing builtDate.")
            built_date = None
        try:
            checksums: List[Checksum] = parse_optional_field(package_dict.get("checksums"),
                                                             self.checksum_parser.parse_checksums, default=[])
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            checksums = []
        comment: Optional[str] = package_dict.get("comment")
        copyright_text: Optional[str] = package_dict.get("copyrightText")
        description: Optional[str] = package_dict.get("description")
        download_location: Union[str, SpdxNoAssertion, SpdxNone] = self.parse_download_location(
            package_dict.get("downloadLocation"))
        try:
            external_refs: List[ExternalPackageRef] = parse_optional_field(package_dict.get("externalRefs"),
                                                                           self.parse_external_refs)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            external_refs = []
        files_analyzed: Optional[bool] = parse_optional_field(package_dict.get("filesAnalyzed"), default=True)
        homepage: Optional[str] = package_dict.get("homepage")
        license_comments: Optional[str] = package_dict.get("licenseComments")
        try:
            license_concluded: Optional[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]] = parse_optional_field(
                package_dict.get("licenseConcluded"),
                self.license_expression_parser.parse_license_expression)
        except ConstructorTypeErrors as err:
            logger.append_all(err.get_messages())
            license_concluded = None
        try:
            license_declared: Optional[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]] = parse_optional_field(
                package_dict.get("licenseDeclared"),
                self.license_expression_parser.parse_license_expression)
        except ConstructorTypeErrors as err:
            logger.append_all(err.get_messages())
            license_declared = None
        try:
            license_info_from_file: Optional[
                Union[List[LicenseExpression], SpdxNoAssertion, SpdxNone]] = parse_optional_field(
                package_dict.get("licenseInfoFromFiles"),
                self.license_expression_parser.parse_license_expression)
        except ConstructorTypeErrors as err:
            logger.append_all(err.get_messages())
            license_info_from_file = None
        try:
            originator: Optional[Union[Actor, SpdxNoAssertion]] = parse_optional_field(package_dict.get("originator"),
                                                                                       self.actor_parser.parse_actor_or_no_assert)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            originator = None
        package_file_name: Optional[str] = package_dict.get("packageFileName")
        try:
            package_verification_code: Optional[PackageVerificationCode] = parse_optional_field(
                package_dict.get("packageVerificationCode"), self.parse_package_verification_code)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            package_verification_code = None

        try:
            primary_package_purpose: Optional[PackagePurpose] = parse_optional_field(
                package_dict.get("primaryPackagePurpose"), self.parse_primary_package_purpose)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            primary_package_purpose = None

        try:
            release_date: Optional[datetime] = parse_optional_field(package_dict.get("releaseDate"), datetime_from_str)
        except ValueError:
            logger.append("ValueError while parsing releaseDate.")
            release_date = None
common
# Copyright (c) 2022 spdx contributors
# 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.
from datetime import datetime
from typing import Dict, List, Optional, Union

from src.model.actor import Actor
from src.model.checksum import Checksum
from src.model.license_expression import LicenseExpression
from src.model.package import Package, ExternalPackageRef, PackageVerificationCode, PackagePurpose, \
    ExternalPackageRefCategory
from src.model.spdx_no_assertion import SpdxNoAssertion
from src.model.spdx_none import SpdxNone
from src.model.typing.constructor_type_errors import ConstructorTypeErrors
from src.parser.error import SPDXParsingError
from src.parser.json.actor_parser import ActorParser
from src.parser.json.checksum_parser import ChecksumParser
from src.parser.json.dict_parsing_functions import datetime_from_str, parse_optional_field, \
    transform_json_str_to_enum_name
from src.parser.json.license_expression_parser import LicenseExpressionParser
from src.parser.logger import Logger


class PackageParser:
    logger: Logger
    actor_parser: ActorParser
    checksum_parser: ChecksumParser
    license_expression_parser: LicenseExpressionParser

    def __init__(self):
        self.actor_parser = ActorParser()
        self.checksum_parser = ChecksumParser()
        self.license_expression_parser = LicenseExpressionParser()
        self.logger = Logger()

    def parse_packages(self, packages_dict_list: List[Dict]) -> List[Package]:
        packages_list = []
        for package_dict in packages_dict_list:
            try:
                package: Package = self.parse_package(package_dict)
                packages_list.append(package)
            except SPDXParsingError as err:
                self.logger.append_all(err.get_messages())
                continue
        if self.logger.has_messages():
            raise SPDXParsingError(self.logger.get_messages())

        return packages_list

    def parse_package(self, package_dict: Dict) -> Package:
        logger = Logger()
        name: str = package_dict.get("name")
        spdx_id: str = package_dict.get("SPDXID")
        attribution_texts: List[str] = package_dict.get("attributionTexts")
        try:
            built_date: Optional[datetime] = parse_optional_field(package_dict.get("builtDate"), datetime_from_str)
        except ValueError:
            logger.append("ValueError while parsing builtDate.")
            built_date = None
        try:
            checksums: List[Checksum] = parse_optional_field(package_dict.get("checksums"),
                                                             self.checksum_parser.parse_checksums, default=[])
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            checksums = []
        comment: Optional[str] = package_dict.get("comment")
        copyright_text: Optional[str] = package_dict.get("copyrightText")
        description: Optional[str] = package_dict.get("description")
        download_location: Union[str, SpdxNoAssertion, SpdxNone] = self.parse_download_location(
            package_dict.get("downloadLocation"))
        try:
            external_refs: List[ExternalPackageRef] = parse_optional_field(package_dict.get("externalRefs"),
                                                                           self.parse_external_refs)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            external_refs = []
        files_analyzed: Optional[bool] = parse_optional_field(package_dict.get("filesAnalyzed"), default=True)
        homepage: Optional[str] = package_dict.get("homepage")
        license_comments: Optional[str] = package_dict.get("licenseComments")
        try:
            license_concluded: Optional[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]] = parse_optional_field(
                package_dict.get("licenseConcluded"),
                self.license_expression_parser.parse_license_expression)
        except ConstructorTypeErrors as err:
            logger.append_all(err.get_messages())
            license_concluded = None
        try:
            license_declared: Optional[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]] = parse_optional_field(
                package_dict.get("licenseDeclared"),
                self.license_expression_parser.parse_license_expression)
        except ConstructorTypeErrors as err:
            logger.append_all(err.get_messages())
            license_declared = None
        try:
            license_info_from_file: Optional[
                Union[List[LicenseExpression], SpdxNoAssertion, SpdxNone]] = parse_optional_field(
                package_dict.get("licenseInfoFromFiles"),
                self.license_expression_parser.parse_license_expression)
        except ConstructorTypeErrors as err:
            logger.append_all(err.get_messages())
            license_info_from_file = None
        try:
            originator: Optional[Union[Actor, SpdxNoAssertion]] = parse_optional_field(package_dict.get("originator"),
                                                                                       self.actor_parser.parse_actor_or_no_assert)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            originator = None
        package_file_name: Optional[str] = package_dict.get("packageFileName")
        try:
            package_verification_code: Optional[PackageVerificationCode] = parse_optional_field(
                package_dict.get("packageVerificationCode"), self.parse_package_verification_code)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            package_verification_code = None

        try:
            primary_package_purpose: Optional[PackagePurpose] = parse_optional_field(
                package_dict.get("primaryPackagePurpose"), self.parse_primary_package_purpose)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            primary_package_purpose = None

        try:
            release_date: Optional[datetime] = parse_optional_field(package_dict.get("releaseDate"), datetime_from_str)
        except ValueError:
            logger.append("ValueError while parsing releaseDate.")
            release_date = None
        source_info: Optional[str] = package_dict.get("sourceInfo")
common
# Copyright (c) 2022 spdx contributors
# 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.
from datetime import datetime
from typing import Dict, List, Optional, Union

from src.model.actor import Actor
from src.model.checksum import Checksum
from src.model.license_expression import LicenseExpression
from src.model.package import Package, ExternalPackageRef, PackageVerificationCode, PackagePurpose, \
    ExternalPackageRefCategory
from src.model.spdx_no_assertion import SpdxNoAssertion
from src.model.spdx_none import SpdxNone
from src.model.typing.constructor_type_errors import ConstructorTypeErrors
from src.parser.error import SPDXParsingError
from src.parser.json.actor_parser import ActorParser
from src.parser.json.checksum_parser import ChecksumParser
from src.parser.json.dict_parsing_functions import datetime_from_str, parse_optional_field, \
    transform_json_str_to_enum_name
from src.parser.json.license_expression_parser import LicenseExpressionParser
from src.parser.logger import Logger


class PackageParser:
    logger: Logger
    actor_parser: ActorParser
    checksum_parser: ChecksumParser
    license_expression_parser: LicenseExpressionParser

    def __init__(self):
        self.actor_parser = ActorParser()
        self.checksum_parser = ChecksumParser()
        self.license_expression_parser = LicenseExpressionParser()
        self.logger = Logger()

    def parse_packages(self, packages_dict_list: List[Dict]) -> List[Package]:
        packages_list = []
        for package_dict in packages_dict_list:
            try:
                package: Package = self.parse_package(package_dict)
                packages_list.append(package)
            except SPDXParsingError as err:
                self.logger.append_all(err.get_messages())
                continue
        if self.logger.has_messages():
            raise SPDXParsingError(self.logger.get_messages())

        return packages_list

    def parse_package(self, package_dict: Dict) -> Package:
        logger = Logger()
        name: str = package_dict.get("name")
        spdx_id: str = package_dict.get("SPDXID")
        attribution_texts: List[str] = package_dict.get("attributionTexts")
        try:
            built_date: Optional[datetime] = parse_optional_field(package_dict.get("builtDate"), datetime_from_str)
        except ValueError:
            logger.append("ValueError while parsing builtDate.")
            built_date = None
        try:
            checksums: List[Checksum] = parse_optional_field(package_dict.get("checksums"),
                                                             self.checksum_parser.parse_checksums, default=[])
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            checksums = []
        comment: Optional[str] = package_dict.get("comment")
        copyright_text: Optional[str] = package_dict.get("copyrightText")
        description: Optional[str] = package_dict.get("description")
        download_location: Union[str, SpdxNoAssertion, SpdxNone] = self.parse_download_location(
            package_dict.get("downloadLocation"))
        try:
            external_refs: List[ExternalPackageRef] = parse_optional_field(package_dict.get("externalRefs"),
                                                                           self.parse_external_refs)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            external_refs = []
        files_analyzed: Optional[bool] = parse_optional_field(package_dict.get("filesAnalyzed"), default=True)
        homepage: Optional[str] = package_dict.get("homepage")
        license_comments: Optional[str] = package_dict.get("licenseComments")
        try:
            license_concluded: Optional[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]] = parse_optional_field(
                package_dict.get("licenseConcluded"),
                self.license_expression_parser.parse_license_expression)
        except ConstructorTypeErrors as err:
            logger.append_all(err.get_messages())
            license_concluded = None
        try:
            license_declared: Optional[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]] = parse_optional_field(
                package_dict.get("licenseDeclared"),
                self.license_expression_parser.parse_license_expression)
        except ConstructorTypeErrors as err:
            logger.append_all(err.get_messages())
            license_declared = None
        try:
            license_info_from_file: Optional[
                Union[List[LicenseExpression], SpdxNoAssertion, SpdxNone]] = parse_optional_field(
                package_dict.get("licenseInfoFromFiles"),
                self.license_expression_parser.parse_license_expression)
        except ConstructorTypeErrors as err:
            logger.append_all(err.get_messages())
            license_info_from_file = None
        try:
            originator: Optional[Union[Actor, SpdxNoAssertion]] = parse_optional_field(package_dict.get("originator"),
                                                                                       self.actor_parser.parse_actor_or_no_assert)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            originator = None
        package_file_name: Optional[str] = package_dict.get("packageFileName")
        try:
            package_verification_code: Optional[PackageVerificationCode] = parse_optional_field(
                package_dict.get("packageVerificationCode"), self.parse_package_verification_code)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            package_verification_code = None

        try:
            primary_package_purpose: Optional[PackagePurpose] = parse_optional_field(
                package_dict.get("primaryPackagePurpose"), self.parse_primary_package_purpose)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            primary_package_purpose = None

        try:
            release_date: Optional[datetime] = parse_optional_field(package_dict.get("releaseDate"), datetime_from_str)
        except ValueError:
            logger.append("ValueError while parsing releaseDate.")
            release_date = None
        source_info: Optional[str] = package_dict.get("sourceInfo")
        summary: Optional[str] = package_dict.get("summary")
        try:
            supplier: Optional[Union[Actor, SpdxNoAssertion]] = parse_optional_field(package_dict.get("supplier"),
                                                                                     self.actor_parser.parse_actor_or_no_assert)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            supplier = None
        try:
common
# Copyright (c) 2022 spdx contributors
# 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.
from datetime import datetime
from typing import Dict, List, Optional, Union

from src.model.actor import Actor
from src.model.checksum import Checksum
from src.model.license_expression import LicenseExpression
from src.model.package import Package, ExternalPackageRef, PackageVerificationCode, PackagePurpose, \
    ExternalPackageRefCategory
from src.model.spdx_no_assertion import SpdxNoAssertion
from src.model.spdx_none import SpdxNone
from src.model.typing.constructor_type_errors import ConstructorTypeErrors
from src.parser.error import SPDXParsingError
from src.parser.json.actor_parser import ActorParser
from src.parser.json.checksum_parser import ChecksumParser
from src.parser.json.dict_parsing_functions import datetime_from_str, parse_optional_field, \
    transform_json_str_to_enum_name
from src.parser.json.license_expression_parser import LicenseExpressionParser
from src.parser.logger import Logger


class PackageParser:
    logger: Logger
    actor_parser: ActorParser
    checksum_parser: ChecksumParser
    license_expression_parser: LicenseExpressionParser

    def __init__(self):
        self.actor_parser = ActorParser()
        self.checksum_parser = ChecksumParser()
        self.license_expression_parser = LicenseExpressionParser()
        self.logger = Logger()

    def parse_packages(self, packages_dict_list: List[Dict]) -> List[Package]:
        packages_list = []
        for package_dict in packages_dict_list:
            try:
                package: Package = self.parse_package(package_dict)
                packages_list.append(package)
            except SPDXParsingError as err:
                self.logger.append_all(err.get_messages())
                continue
        if self.logger.has_messages():
            raise SPDXParsingError(self.logger.get_messages())

        return packages_list

    def parse_package(self, package_dict: Dict) -> Package:
        logger = Logger()
        name: str = package_dict.get("name")
        spdx_id: str = package_dict.get("SPDXID")
        attribution_texts: List[str] = package_dict.get("attributionTexts")
        try:
            built_date: Optional[datetime] = parse_optional_field(package_dict.get("builtDate"), datetime_from_str)
        except ValueError:
            logger.append("ValueError while parsing builtDate.")
            built_date = None
        try:
            checksums: List[Checksum] = parse_optional_field(package_dict.get("checksums"),
                                                             self.checksum_parser.parse_checksums, default=[])
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            checksums = []
        comment: Optional[str] = package_dict.get("comment")
        copyright_text: Optional[str] = package_dict.get("copyrightText")
        description: Optional[str] = package_dict.get("description")
        download_location: Union[str, SpdxNoAssertion, SpdxNone] = self.parse_download_location(
            package_dict.get("downloadLocation"))
        try:
            external_refs: List[ExternalPackageRef] = parse_optional_field(package_dict.get("externalRefs"),
                                                                           self.parse_external_refs)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            external_refs = []
        files_analyzed: Optional[bool] = parse_optional_field(package_dict.get("filesAnalyzed"), default=True)
        homepage: Optional[str] = package_dict.get("homepage")
        license_comments: Optional[str] = package_dict.get("licenseComments")
        try:
            license_concluded: Optional[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]] = parse_optional_field(
                package_dict.get("licenseConcluded"),
                self.license_expression_parser.parse_license_expression)
        except ConstructorTypeErrors as err:
            logger.append_all(err.get_messages())
            license_concluded = None
        try:
            license_declared: Optional[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]] = parse_optional_field(
                package_dict.get("licenseDeclared"),
                self.license_expression_parser.parse_license_expression)
        except ConstructorTypeErrors as err:
            logger.append_all(err.get_messages())
            license_declared = None
        try:
            license_info_from_file: Optional[
                Union[List[LicenseExpression], SpdxNoAssertion, SpdxNone]] = parse_optional_field(
                package_dict.get("licenseInfoFromFiles"),
                self.license_expression_parser.parse_license_expression)
        except ConstructorTypeErrors as err:
            logger.append_all(err.get_messages())
            license_info_from_file = None
        try:
            originator: Optional[Union[Actor, SpdxNoAssertion]] = parse_optional_field(package_dict.get("originator"),
                                                                                       self.actor_parser.parse_actor_or_no_assert)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            originator = None
        package_file_name: Optional[str] = package_dict.get("packageFileName")
        try:
            package_verification_code: Optional[PackageVerificationCode] = parse_optional_field(
                package_dict.get("packageVerificationCode"), self.parse_package_verification_code)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            package_verification_code = None

        try:
            primary_package_purpose: Optional[PackagePurpose] = parse_optional_field(
                package_dict.get("primaryPackagePurpose"), self.parse_primary_package_purpose)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            primary_package_purpose = None

        try:
            release_date: Optional[datetime] = parse_optional_field(package_dict.get("releaseDate"), datetime_from_str)
        except ValueError:
            logger.append("ValueError while parsing releaseDate.")
            release_date = None
        source_info: Optional[str] = package_dict.get("sourceInfo")
        summary: Optional[str] = package_dict.get("summary")
        try:
            supplier: Optional[Union[Actor, SpdxNoAssertion]] = parse_optional_field(package_dict.get("supplier"),
                                                                                     self.actor_parser.parse_actor_or_no_assert)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            supplier = None
        try:
            valid_until_date: Optional[datetime] = parse_optional_field(package_dict.get("validUntilDate"),
                                                                        datetime_from_str)
        except ValueError:
            logger.append("ValueError while parsing validUntilDate.")
            valid_until_date = None

common
# Copyright (c) 2022 spdx contributors
# 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.
from datetime import datetime
from typing import Dict, List, Optional, Union

from src.model.actor import Actor
from src.model.checksum import Checksum
from src.model.license_expression import LicenseExpression
from src.model.package import Package, ExternalPackageRef, PackageVerificationCode, PackagePurpose, \
    ExternalPackageRefCategory
from src.model.spdx_no_assertion import SpdxNoAssertion
from src.model.spdx_none import SpdxNone
from src.model.typing.constructor_type_errors import ConstructorTypeErrors
from src.parser.error import SPDXParsingError
from src.parser.json.actor_parser import ActorParser
from src.parser.json.checksum_parser import ChecksumParser
from src.parser.json.dict_parsing_functions import datetime_from_str, parse_optional_field, \
    transform_json_str_to_enum_name
from src.parser.json.license_expression_parser import LicenseExpressionParser
from src.parser.logger import Logger


class PackageParser:
    logger: Logger
    actor_parser: ActorParser
    checksum_parser: ChecksumParser
    license_expression_parser: LicenseExpressionParser

    def __init__(self):
        self.actor_parser = ActorParser()
        self.checksum_parser = ChecksumParser()
        self.license_expression_parser = LicenseExpressionParser()
        self.logger = Logger()

    def parse_packages(self, packages_dict_list: List[Dict]) -> List[Package]:
        packages_list = []
        for package_dict in packages_dict_list:
            try:
                package: Package = self.parse_package(package_dict)
                packages_list.append(package)
            except SPDXParsingError as err:
                self.logger.append_all(err.get_messages())
                continue
        if self.logger.has_messages():
            raise SPDXParsingError(self.logger.get_messages())

        return packages_list

    def parse_package(self, package_dict: Dict) -> Package:
        logger = Logger()
common
# Copyright (c) 2022 spdx contributors
# 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.
from datetime import datetime
from typing import Dict, List, Optional, Union

from src.model.actor import Actor
from src.model.checksum import Checksum
from src.model.license_expression import LicenseExpression
from src.model.package import Package, ExternalPackageRef, PackageVerificationCode, PackagePurpose, \
    ExternalPackageRefCategory
from src.model.spdx_no_assertion import SpdxNoAssertion
from src.model.spdx_none import SpdxNone
from src.model.typing.constructor_type_errors import ConstructorTypeErrors
from src.parser.error import SPDXParsingError
from src.parser.json.actor_parser import ActorParser
from src.parser.json.checksum_parser import ChecksumParser
from src.parser.json.dict_parsing_functions import datetime_from_str, parse_optional_field, \
    transform_json_str_to_enum_name
from src.parser.json.license_expression_parser import LicenseExpressionParser
from src.parser.logger import Logger


class PackageParser:
    logger: Logger
    actor_parser: ActorParser
    checksum_parser: ChecksumParser
    license_expression_parser: LicenseExpressionParser

    def __init__(self):
        self.actor_parser = ActorParser()
        self.checksum_parser = ChecksumParser()
        self.license_expression_parser = LicenseExpressionParser()
        self.logger = Logger()

    def parse_packages(self, packages_dict_list: List[Dict]) -> List[Package]:
        packages_list = []
        for package_dict in packages_dict_list:
            try:
                package: Package = self.parse_package(package_dict)
                packages_list.append(package)
            except SPDXParsingError as err:
                self.logger.append_all(err.get_messages())
                continue
        if self.logger.has_messages():
            raise SPDXParsingError(self.logger.get_messages())

        return packages_list

    def parse_package(self, package_dict: Dict) -> Package:
        logger = Logger()
        name: str = package_dict.get("name")
common
# Copyright (c) 2022 spdx contributors
# 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.
from datetime import datetime
from typing import Dict, List, Optional, Union

from src.model.actor import Actor
from src.model.checksum import Checksum
from src.model.license_expression import LicenseExpression
from src.model.package import Package, ExternalPackageRef, PackageVerificationCode, PackagePurpose, \
    ExternalPackageRefCategory
from src.model.spdx_no_assertion import SpdxNoAssertion
from src.model.spdx_none import SpdxNone
from src.model.typing.constructor_type_errors import ConstructorTypeErrors
from src.parser.error import SPDXParsingError
from src.parser.json.actor_parser import ActorParser
from src.parser.json.checksum_parser import ChecksumParser
from src.parser.json.dict_parsing_functions import datetime_from_str, parse_optional_field, \
    transform_json_str_to_enum_name
from src.parser.json.license_expression_parser import LicenseExpressionParser
from src.parser.logger import Logger


class PackageParser:
    logger: Logger
    actor_parser: ActorParser
    checksum_parser: ChecksumParser
    license_expression_parser: LicenseExpressionParser

    def __init__(self):
        self.actor_parser = ActorParser()
        self.checksum_parser = ChecksumParser()
        self.license_expression_parser = LicenseExpressionParser()
        self.logger = Logger()

    def parse_packages(self, packages_dict_list: List[Dict]) -> List[Package]:
        packages_list = []
        for package_dict in packages_dict_list:
            try:
                package: Package = self.parse_package(package_dict)
                packages_list.append(package)
            except SPDXParsingError as err:
                self.logger.append_all(err.get_messages())
                continue
        if self.logger.has_messages():
            raise SPDXParsingError(self.logger.get_messages())

        return packages_list

    def parse_package(self, package_dict: Dict) -> Package:
        logger = Logger()
        name: str = package_dict.get("name")
        spdx_id: str = package_dict.get("SPDXID")
common
# Copyright (c) 2022 spdx contributors
# 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.
from datetime import datetime
from typing import Dict, List, Optional, Union

from src.model.actor import Actor
from src.model.checksum import Checksum
from src.model.license_expression import LicenseExpression
from src.model.package import Package, ExternalPackageRef, PackageVerificationCode, PackagePurpose, \
    ExternalPackageRefCategory
from src.model.spdx_no_assertion import SpdxNoAssertion
from src.model.spdx_none import SpdxNone
from src.model.typing.constructor_type_errors import ConstructorTypeErrors
from src.parser.error import SPDXParsingError
from src.parser.json.actor_parser import ActorParser
from src.parser.json.checksum_parser import ChecksumParser
from src.parser.json.dict_parsing_functions import datetime_from_str, parse_optional_field, \
    transform_json_str_to_enum_name
from src.parser.json.license_expression_parser import LicenseExpressionParser
from src.parser.logger import Logger


class PackageParser:
    logger: Logger
    actor_parser: ActorParser
    checksum_parser: ChecksumParser
    license_expression_parser: LicenseExpressionParser

    def __init__(self):
        self.actor_parser = ActorParser()
        self.checksum_parser = ChecksumParser()
        self.license_expression_parser = LicenseExpressionParser()
        self.logger = Logger()

    def parse_packages(self, packages_dict_list: List[Dict]) -> List[Package]:
        packages_list = []
        for package_dict in packages_dict_list:
            try:
                package: Package = self.parse_package(package_dict)
                packages_list.append(package)
            except SPDXParsingError as err:
                self.logger.append_all(err.get_messages())
                continue
        if self.logger.has_messages():
            raise SPDXParsingError(self.logger.get_messages())

        return packages_list

    def parse_package(self, package_dict: Dict) -> Package:
        logger = Logger()
        name: str = package_dict.get("name")
        spdx_id: str = package_dict.get("SPDXID")
        attribution_texts: List[str] = package_dict.get("attributionTexts")
        try:
            built_date: Optional[datetime] = parse_optional_field(package_dict.get("builtDate"), datetime_from_str)
        except ValueError:
            logger.append("ValueError while parsing builtDate.")
            built_date = None
        try:
            checksums: List[Checksum] = parse_optional_field(package_dict.get("checksums"),
                                                             self.checksum_parser.parse_checksums, default=[])
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            checksums = []
        comment: Optional[str] = package_dict.get("comment")
        copyright_text: Optional[str] = package_dict.get("copyrightText")
        description: Optional[str] = package_dict.get("description")
        download_location: Union[str, SpdxNoAssertion, SpdxNone] = self.parse_download_location(
            package_dict.get("downloadLocation"))
        try:
            external_refs: List[ExternalPackageRef] = parse_optional_field(package_dict.get("externalRefs"),
                                                                           self.parse_external_refs)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            external_refs = []
        files_analyzed: Optional[bool] = parse_optional_field(package_dict.get("filesAnalyzed"), default=True)
        homepage: Optional[str] = package_dict.get("homepage")
        license_comments: Optional[str] = package_dict.get("licenseComments")
        try:
            license_concluded: Optional[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]] = parse_optional_field(
                package_dict.get("licenseConcluded"),
                self.license_expression_parser.parse_license_expression)
        except ConstructorTypeErrors as err:
            logger.append_all(err.get_messages())
            license_concluded = None
        try:
            license_declared: Optional[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]] = parse_optional_field(
                package_dict.get("licenseDeclared"),
                self.license_expression_parser.parse_license_expression)
        except ConstructorTypeErrors as err:
            logger.append_all(err.get_messages())
            license_declared = None
        try:
            license_info_from_file: Optional[
                Union[List[LicenseExpression], SpdxNoAssertion, SpdxNone]] = parse_optional_field(
                package_dict.get("licenseInfoFromFiles"),
                self.license_expression_parser.parse_license_expression)
        except ConstructorTypeErrors as err:
            logger.append_all(err.get_messages())
            license_info_from_file = None
        try:
            originator: Optional[Union[Actor, SpdxNoAssertion]] = parse_optional_field(package_dict.get("originator"),
                                                                                       self.actor_parser.parse_actor_or_no_assert)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            originator = None
        package_file_name: Optional[str] = package_dict.get("packageFileName")
        try:
            package_verification_code: Optional[PackageVerificationCode] = parse_optional_field(
                package_dict.get("packageVerificationCode"), self.parse_package_verification_code)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            package_verification_code = None

        try:
            primary_package_purpose: Optional[PackagePurpose] = parse_optional_field(
                package_dict.get("primaryPackagePurpose"), self.parse_primary_package_purpose)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            primary_package_purpose = None

        try:
            release_date: Optional[datetime] = parse_optional_field(package_dict.get("releaseDate"), datetime_from_str)
        except ValueError:
            logger.append("ValueError while parsing releaseDate.")
            release_date = None
        source_info: Optional[str] = package_dict.get("sourceInfo")
        summary: Optional[str] = package_dict.get("summary")
        try:
            supplier: Optional[Union[Actor, SpdxNoAssertion]] = parse_optional_field(package_dict.get("supplier"),
                                                                                     self.actor_parser.parse_actor_or_no_assert)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            supplier = None
        try:
            valid_until_date: Optional[datetime] = parse_optional_field(package_dict.get("validUntilDate"),
                                                                        datetime_from_str)
        except ValueError:
            logger.append("ValueError while parsing validUntilDate.")
            valid_until_date = None

        version_info: Optional[str] = package_dict.get("versionInfo")
        if logger.has_messages():
            raise SPDXParsingError([f"Error while parsing Package {name}: {logger.get_messages()}"])

        try:
            package = Package(spdx_id=spdx_id, name=name, download_location=download_location, version=version_info,
                              file_name=package_file_name, supplier=supplier, originator=originator,
                              files_analyzed=files_analyzed,
                              verification_code=package_verification_code, checksums=checksums, homepage=homepage,
                              source_info=source_info,
                              license_concluded=license_concluded, license_info_from_files=license_info_from_file,
                              license_declared=license_declared,
                              license_comment=license_comments, copyright_text=copyright_text, summary=summary,
                              description=description,
                              comment=comment, external_references=external_refs, attribution_texts=attribution_texts,
                              primary_package_purpose=primary_package_purpose,
                              release_date=release_date, built_date=built_date, valid_until_date=valid_until_date)

        except ConstructorTypeErrors as err:
            raise SPDXParsingError([f"Error while constructing Package {name}: {err.get_messages()}"])

        return package

    def parse_external_refs(self, external_ref_dicts: List[Dict]) -> List[ExternalPackageRef]:
        external_refs = []
        for external_ref_dict in external_ref_dicts:
            try:
                external_ref: ExternalPackageRef = self.parse_external_ref(external_ref_dict)
                external_refs.append(external_ref)
            except SPDXParsingError as err:
                self.logger.append_all(err.get_messages())
        return external_refs

    def parse_external_ref(self, external_ref_dict: Dict) -> ExternalPackageRef:
        logger = Logger()
        try:
            ref_category = self.parse_external_ref_category(external_ref_dict.get("referenceCategory"))
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            ref_category = None
common
# Copyright (c) 2022 spdx contributors
# 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.
from datetime import datetime
from typing import Dict, List, Optional, Union

from src.model.actor import Actor
from src.model.checksum import Checksum
from src.model.license_expression import LicenseExpression
from src.model.package import Package, ExternalPackageRef, PackageVerificationCode, PackagePurpose, \
    ExternalPackageRefCategory
from src.model.spdx_no_assertion import SpdxNoAssertion
from src.model.spdx_none import SpdxNone
from src.model.typing.constructor_type_errors import ConstructorTypeErrors
from src.parser.error import SPDXParsingError
from src.parser.json.actor_parser import ActorParser
from src.parser.json.checksum_parser import ChecksumParser
from src.parser.json.dict_parsing_functions import datetime_from_str, parse_optional_field, \
    transform_json_str_to_enum_name
from src.parser.json.license_expression_parser import LicenseExpressionParser
from src.parser.logger import Logger


class PackageParser:
    logger: Logger
    actor_parser: ActorParser
    checksum_parser: ChecksumParser
    license_expression_parser: LicenseExpressionParser

    def __init__(self):
        self.actor_parser = ActorParser()
        self.checksum_parser = ChecksumParser()
        self.license_expression_parser = LicenseExpressionParser()
        self.logger = Logger()

    def parse_packages(self, packages_dict_list: List[Dict]) -> List[Package]:
        packages_list = []
        for package_dict in packages_dict_list:
            try:
                package: Package = self.parse_package(package_dict)
                packages_list.append(package)
            except SPDXParsingError as err:
                self.logger.append_all(err.get_messages())
                continue
        if self.logger.has_messages():
            raise SPDXParsingError(self.logger.get_messages())

        return packages_list

    def parse_package(self, package_dict: Dict) -> Package:
        logger = Logger()
        name: str = package_dict.get("name")
        spdx_id: str = package_dict.get("SPDXID")
        attribution_texts: List[str] = package_dict.get("attributionTexts")
        try:
            built_date: Optional[datetime] = parse_optional_field(package_dict.get("builtDate"), datetime_from_str)
        except ValueError:
            logger.append("ValueError while parsing builtDate.")
            built_date = None
        try:
            checksums: List[Checksum] = parse_optional_field(package_dict.get("checksums"),
                                                             self.checksum_parser.parse_checksums, default=[])
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            checksums = []
        comment: Optional[str] = package_dict.get("comment")
        copyright_text: Optional[str] = package_dict.get("copyrightText")
        description: Optional[str] = package_dict.get("description")
        download_location: Union[str, SpdxNoAssertion, SpdxNone] = self.parse_download_location(
            package_dict.get("downloadLocation"))
        try:
            external_refs: List[ExternalPackageRef] = parse_optional_field(package_dict.get("externalRefs"),
                                                                           self.parse_external_refs)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            external_refs = []
        files_analyzed: Optional[bool] = parse_optional_field(package_dict.get("filesAnalyzed"), default=True)
        homepage: Optional[str] = package_dict.get("homepage")
        license_comments: Optional[str] = package_dict.get("licenseComments")
        try:
            license_concluded: Optional[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]] = parse_optional_field(
                package_dict.get("licenseConcluded"),
                self.license_expression_parser.parse_license_expression)
        except ConstructorTypeErrors as err:
            logger.append_all(err.get_messages())
            license_concluded = None
        try:
            license_declared: Optional[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]] = parse_optional_field(
                package_dict.get("licenseDeclared"),
                self.license_expression_parser.parse_license_expression)
        except ConstructorTypeErrors as err:
            logger.append_all(err.get_messages())
            license_declared = None
        try:
            license_info_from_file: Optional[
                Union[List[LicenseExpression], SpdxNoAssertion, SpdxNone]] = parse_optional_field(
                package_dict.get("licenseInfoFromFiles"),
                self.license_expression_parser.parse_license_expression)
        except ConstructorTypeErrors as err:
            logger.append_all(err.get_messages())
            license_info_from_file = None
        try:
            originator: Optional[Union[Actor, SpdxNoAssertion]] = parse_optional_field(package_dict.get("originator"),
                                                                                       self.actor_parser.parse_actor_or_no_assert)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            originator = None
        package_file_name: Optional[str] = package_dict.get("packageFileName")
        try:
            package_verification_code: Optional[PackageVerificationCode] = parse_optional_field(
                package_dict.get("packageVerificationCode"), self.parse_package_verification_code)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            package_verification_code = None

        try:
            primary_package_purpose: Optional[PackagePurpose] = parse_optional_field(
                package_dict.get("primaryPackagePurpose"), self.parse_primary_package_purpose)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            primary_package_purpose = None

        try:
            release_date: Optional[datetime] = parse_optional_field(package_dict.get("releaseDate"), datetime_from_str)
        except ValueError:
            logger.append("ValueError while parsing releaseDate.")
            release_date = None
        source_info: Optional[str] = package_dict.get("sourceInfo")
        summary: Optional[str] = package_dict.get("summary")
        try:
            supplier: Optional[Union[Actor, SpdxNoAssertion]] = parse_optional_field(package_dict.get("supplier"),
                                                                                     self.actor_parser.parse_actor_or_no_assert)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            supplier = None
        try:
            valid_until_date: Optional[datetime] = parse_optional_field(package_dict.get("validUntilDate"),
                                                                        datetime_from_str)
        except ValueError:
            logger.append("ValueError while parsing validUntilDate.")
            valid_until_date = None

        version_info: Optional[str] = package_dict.get("versionInfo")
        if logger.has_messages():
            raise SPDXParsingError([f"Error while parsing Package {name}: {logger.get_messages()}"])

        try:
            package = Package(spdx_id=spdx_id, name=name, download_location=download_location, version=version_info,
                              file_name=package_file_name, supplier=supplier, originator=originator,
                              files_analyzed=files_analyzed,
                              verification_code=package_verification_code, checksums=checksums, homepage=homepage,
                              source_info=source_info,
                              license_concluded=license_concluded, license_info_from_files=license_info_from_file,
                              license_declared=license_declared,
                              license_comment=license_comments, copyright_text=copyright_text, summary=summary,
                              description=description,
                              comment=comment, external_references=external_refs, attribution_texts=attribution_texts,
                              primary_package_purpose=primary_package_purpose,
                              release_date=release_date, built_date=built_date, valid_until_date=valid_until_date)

        except ConstructorTypeErrors as err:
            raise SPDXParsingError([f"Error while constructing Package {name}: {err.get_messages()}"])

        return package

    def parse_external_refs(self, external_ref_dicts: List[Dict]) -> List[ExternalPackageRef]:
        external_refs = []
        for external_ref_dict in external_ref_dicts:
            try:
                external_ref: ExternalPackageRef = self.parse_external_ref(external_ref_dict)
                external_refs.append(external_ref)
            except SPDXParsingError as err:
                self.logger.append_all(err.get_messages())
        return external_refs

    def parse_external_ref(self, external_ref_dict: Dict) -> ExternalPackageRef:
        logger = Logger()
        try:
            ref_category = self.parse_external_ref_category(external_ref_dict.get("referenceCategory"))
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            ref_category = None
        ref_locator = external_ref_dict.get("referenceLocator")
common
# Copyright (c) 2022 spdx contributors
# 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.
from datetime import datetime
from typing import Dict, List, Optional, Union

from src.model.actor import Actor
from src.model.checksum import Checksum
from src.model.license_expression import LicenseExpression
from src.model.package import Package, ExternalPackageRef, PackageVerificationCode, PackagePurpose, \
    ExternalPackageRefCategory
from src.model.spdx_no_assertion import SpdxNoAssertion
from src.model.spdx_none import SpdxNone
from src.model.typing.constructor_type_errors import ConstructorTypeErrors
from src.parser.error import SPDXParsingError
from src.parser.json.actor_parser import ActorParser
from src.parser.json.checksum_parser import ChecksumParser
from src.parser.json.dict_parsing_functions import datetime_from_str, parse_optional_field, \
    transform_json_str_to_enum_name
from src.parser.json.license_expression_parser import LicenseExpressionParser
from src.parser.logger import Logger


class PackageParser:
    logger: Logger
    actor_parser: ActorParser
    checksum_parser: ChecksumParser
    license_expression_parser: LicenseExpressionParser

    def __init__(self):
        self.actor_parser = ActorParser()
        self.checksum_parser = ChecksumParser()
        self.license_expression_parser = LicenseExpressionParser()
        self.logger = Logger()

    def parse_packages(self, packages_dict_list: List[Dict]) -> List[Package]:
        packages_list = []
        for package_dict in packages_dict_list:
            try:
                package: Package = self.parse_package(package_dict)
                packages_list.append(package)
            except SPDXParsingError as err:
                self.logger.append_all(err.get_messages())
                continue
        if self.logger.has_messages():
            raise SPDXParsingError(self.logger.get_messages())

        return packages_list

    def parse_package(self, package_dict: Dict) -> Package:
        logger = Logger()
        name: str = package_dict.get("name")
        spdx_id: str = package_dict.get("SPDXID")
        attribution_texts: List[str] = package_dict.get("attributionTexts")
        try:
common
# Copyright (c) 2022 spdx contributors
# 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.
from datetime import datetime
from typing import Dict, List, Optional, Union

from src.model.actor import Actor
from src.model.checksum import Checksum
from src.model.license_expression import LicenseExpression
from src.model.package import Package, ExternalPackageRef, PackageVerificationCode, PackagePurpose, \
    ExternalPackageRefCategory
from src.model.spdx_no_assertion import SpdxNoAssertion
from src.model.spdx_none import SpdxNone
from src.model.typing.constructor_type_errors import ConstructorTypeErrors
from src.parser.error import SPDXParsingError
from src.parser.json.actor_parser import ActorParser
from src.parser.json.checksum_parser import ChecksumParser
from src.parser.json.dict_parsing_functions import datetime_from_str, parse_optional_field, \
    transform_json_str_to_enum_name
from src.parser.json.license_expression_parser import LicenseExpressionParser
from src.parser.logger import Logger


class PackageParser:
    logger: Logger
    actor_parser: ActorParser
    checksum_parser: ChecksumParser
    license_expression_parser: LicenseExpressionParser

    def __init__(self):
        self.actor_parser = ActorParser()
        self.checksum_parser = ChecksumParser()
        self.license_expression_parser = LicenseExpressionParser()
        self.logger = Logger()

    def parse_packages(self, packages_dict_list: List[Dict]) -> List[Package]:
        packages_list = []
        for package_dict in packages_dict_list:
            try:
                package: Package = self.parse_package(package_dict)
                packages_list.append(package)
            except SPDXParsingError as err:
                self.logger.append_all(err.get_messages())
                continue
        if self.logger.has_messages():
            raise SPDXParsingError(self.logger.get_messages())

        return packages_list

    def parse_package(self, package_dict: Dict) -> Package:
        logger = Logger()
        name: str = package_dict.get("name")
        spdx_id: str = package_dict.get("SPDXID")
        attribution_texts: List[str] = package_dict.get("attributionTexts")
        try:
            built_date: Optional[datetime] = parse_optional_field(package_dict.get("builtDate"), datetime_from_str)
        except ValueError:
            logger.append("ValueError while parsing builtDate.")
            built_date = None
        try:
            checksums: List[Checksum] = parse_optional_field(package_dict.get("checksums"),
                                                             self.checksum_parser.parse_checksums, default=[])
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            checksums = []
        comment: Optional[str] = package_dict.get("comment")
        copyright_text: Optional[str] = package_dict.get("copyrightText")
        description: Optional[str] = package_dict.get("description")
        download_location: Union[str, SpdxNoAssertion, SpdxNone] = self.parse_download_location(
            package_dict.get("downloadLocation"))
        try:
            external_refs: List[ExternalPackageRef] = parse_optional_field(package_dict.get("externalRefs"),
                                                                           self.parse_external_refs)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            external_refs = []
        files_analyzed: Optional[bool] = parse_optional_field(package_dict.get("filesAnalyzed"), default=True)
        homepage: Optional[str] = package_dict.get("homepage")
        license_comments: Optional[str] = package_dict.get("licenseComments")
        try:
            license_concluded: Optional[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]] = parse_optional_field(
                package_dict.get("licenseConcluded"),
                self.license_expression_parser.parse_license_expression)
        except ConstructorTypeErrors as err:
            logger.append_all(err.get_messages())
            license_concluded = None
        try:
            license_declared: Optional[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]] = parse_optional_field(
                package_dict.get("licenseDeclared"),
                self.license_expression_parser.parse_license_expression)
        except ConstructorTypeErrors as err:
            logger.append_all(err.get_messages())
            license_declared = None
        try:
            license_info_from_file: Optional[
                Union[List[LicenseExpression], SpdxNoAssertion, SpdxNone]] = parse_optional_field(
                package_dict.get("licenseInfoFromFiles"),
                self.license_expression_parser.parse_license_expression)
        except ConstructorTypeErrors as err:
            logger.append_all(err.get_messages())
            license_info_from_file = None
        try:
            originator: Optional[Union[Actor, SpdxNoAssertion]] = parse_optional_field(package_dict.get("originator"),
                                                                                       self.actor_parser.parse_actor_or_no_assert)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            originator = None
        package_file_name: Optional[str] = package_dict.get("packageFileName")
        try:
            package_verification_code: Optional[PackageVerificationCode] = parse_optional_field(
                package_dict.get("packageVerificationCode"), self.parse_package_verification_code)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            package_verification_code = None

        try:
            primary_package_purpose: Optional[PackagePurpose] = parse_optional_field(
                package_dict.get("primaryPackagePurpose"), self.parse_primary_package_purpose)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            primary_package_purpose = None

        try:
            release_date: Optional[datetime] = parse_optional_field(package_dict.get("releaseDate"), datetime_from_str)
        except ValueError:
            logger.append("ValueError while parsing releaseDate.")
            release_date = None
        source_info: Optional[str] = package_dict.get("sourceInfo")
        summary: Optional[str] = package_dict.get("summary")
        try:
            supplier: Optional[Union[Actor, SpdxNoAssertion]] = parse_optional_field(package_dict.get("supplier"),
                                                                                     self.actor_parser.parse_actor_or_no_assert)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            supplier = None
        try:
            valid_until_date: Optional[datetime] = parse_optional_field(package_dict.get("validUntilDate"),
                                                                        datetime_from_str)
        except ValueError:
            logger.append("ValueError while parsing validUntilDate.")
            valid_until_date = None

        version_info: Optional[str] = package_dict.get("versionInfo")
        if logger.has_messages():
            raise SPDXParsingError([f"Error while parsing Package {name}: {logger.get_messages()}"])

        try:
            package = Package(spdx_id=spdx_id, name=name, download_location=download_location, version=version_info,
                              file_name=package_file_name, supplier=supplier, originator=originator,
                              files_analyzed=files_analyzed,
                              verification_code=package_verification_code, checksums=checksums, homepage=homepage,
                              source_info=source_info,
                              license_concluded=license_concluded, license_info_from_files=license_info_from_file,
                              license_declared=license_declared,
                              license_comment=license_comments, copyright_text=copyright_text, summary=summary,
                              description=description,
                              comment=comment, external_references=external_refs, attribution_texts=attribution_texts,
                              primary_package_purpose=primary_package_purpose,
                              release_date=release_date, built_date=built_date, valid_until_date=valid_until_date)

        except ConstructorTypeErrors as err:
            raise SPDXParsingError([f"Error while constructing Package {name}: {err.get_messages()}"])

        return package

    def parse_external_refs(self, external_ref_dicts: List[Dict]) -> List[ExternalPackageRef]:
        external_refs = []
        for external_ref_dict in external_ref_dicts:
            try:
                external_ref: ExternalPackageRef = self.parse_external_ref(external_ref_dict)
                external_refs.append(external_ref)
            except SPDXParsingError as err:
                self.logger.append_all(err.get_messages())
        return external_refs

    def parse_external_ref(self, external_ref_dict: Dict) -> ExternalPackageRef:
        logger = Logger()
        try:
            ref_category = self.parse_external_ref_category(external_ref_dict.get("referenceCategory"))
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            ref_category = None
        ref_locator = external_ref_dict.get("referenceLocator")
        ref_type = external_ref_dict.get("referenceType")
common
# Copyright (c) 2022 spdx contributors
# 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.
from datetime import datetime
from typing import Dict, List, Optional, Union

from src.model.actor import Actor
from src.model.checksum import Checksum
from src.model.license_expression import LicenseExpression
from src.model.package import Package, ExternalPackageRef, PackageVerificationCode, PackagePurpose, \
    ExternalPackageRefCategory
from src.model.spdx_no_assertion import SpdxNoAssertion
from src.model.spdx_none import SpdxNone
from src.model.typing.constructor_type_errors import ConstructorTypeErrors
from src.parser.error import SPDXParsingError
from src.parser.json.actor_parser import ActorParser
from src.parser.json.checksum_parser import ChecksumParser
from src.parser.json.dict_parsing_functions import datetime_from_str, parse_optional_field, \
    transform_json_str_to_enum_name
from src.parser.json.license_expression_parser import LicenseExpressionParser
from src.parser.logger import Logger


class PackageParser:
    logger: Logger
    actor_parser: ActorParser
    checksum_parser: ChecksumParser
    license_expression_parser: LicenseExpressionParser

    def __init__(self):
        self.actor_parser = ActorParser()
        self.checksum_parser = ChecksumParser()
        self.license_expression_parser = LicenseExpressionParser()
        self.logger = Logger()

    def parse_packages(self, packages_dict_list: List[Dict]) -> List[Package]:
        packages_list = []
        for package_dict in packages_dict_list:
            try:
                package: Package = self.parse_package(package_dict)
                packages_list.append(package)
            except SPDXParsingError as err:
                self.logger.append_all(err.get_messages())
                continue
        if self.logger.has_messages():
            raise SPDXParsingError(self.logger.get_messages())

        return packages_list

    def parse_package(self, package_dict: Dict) -> Package:
        logger = Logger()
        name: str = package_dict.get("name")
        spdx_id: str = package_dict.get("SPDXID")
        attribution_texts: List[str] = package_dict.get("attributionTexts")
        try:
            built_date: Optional[datetime] = parse_optional_field(package_dict.get("builtDate"), datetime_from_str)
        except ValueError:
            logger.append("ValueError while parsing builtDate.")
            built_date = None
        try:
            checksums: List[Checksum] = parse_optional_field(package_dict.get("checksums"),
                                                             self.checksum_parser.parse_checksums, default=[])
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            checksums = []
common
# Copyright (c) 2022 spdx contributors
# 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.
from datetime import datetime
from typing import Dict, List, Optional, Union

from src.model.actor import Actor
from src.model.checksum import Checksum
from src.model.license_expression import LicenseExpression
from src.model.package import Package, ExternalPackageRef, PackageVerificationCode, PackagePurpose, \
    ExternalPackageRefCategory
from src.model.spdx_no_assertion import SpdxNoAssertion
from src.model.spdx_none import SpdxNone
from src.model.typing.constructor_type_errors import ConstructorTypeErrors
from src.parser.error import SPDXParsingError
from src.parser.json.actor_parser import ActorParser
from src.parser.json.checksum_parser import ChecksumParser
from src.parser.json.dict_parsing_functions import datetime_from_str, parse_optional_field, \
    transform_json_str_to_enum_name
from src.parser.json.license_expression_parser import LicenseExpressionParser
from src.parser.logger import Logger


class PackageParser:
    logger: Logger
    actor_parser: ActorParser
    checksum_parser: ChecksumParser
    license_expression_parser: LicenseExpressionParser

    def __init__(self):
        self.actor_parser = ActorParser()
        self.checksum_parser = ChecksumParser()
        self.license_expression_parser = LicenseExpressionParser()
        self.logger = Logger()

    def parse_packages(self, packages_dict_list: List[Dict]) -> List[Package]:
        packages_list = []
        for package_dict in packages_dict_list:
            try:
                package: Package = self.parse_package(package_dict)
                packages_list.append(package)
            except SPDXParsingError as err:
                self.logger.append_all(err.get_messages())
                continue
        if self.logger.has_messages():
            raise SPDXParsingError(self.logger.get_messages())

        return packages_list

    def parse_package(self, package_dict: Dict) -> Package:
        logger = Logger()
        name: str = package_dict.get("name")
        spdx_id: str = package_dict.get("SPDXID")
        attribution_texts: List[str] = package_dict.get("attributionTexts")
        try:
            built_date: Optional[datetime] = parse_optional_field(package_dict.get("builtDate"), datetime_from_str)
        except ValueError:
            logger.append("ValueError while parsing builtDate.")
            built_date = None
        try:
            checksums: List[Checksum] = parse_optional_field(package_dict.get("checksums"),
                                                             self.checksum_parser.parse_checksums, default=[])
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            checksums = []
        comment: Optional[str] = package_dict.get("comment")
common
# Copyright (c) 2022 spdx contributors
# 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.
from datetime import datetime
from typing import Dict, List, Optional, Union

from src.model.actor import Actor
from src.model.checksum import Checksum
from src.model.license_expression import LicenseExpression
from src.model.package import Package, ExternalPackageRef, PackageVerificationCode, PackagePurpose, \
    ExternalPackageRefCategory
from src.model.spdx_no_assertion import SpdxNoAssertion
from src.model.spdx_none import SpdxNone
from src.model.typing.constructor_type_errors import ConstructorTypeErrors
from src.parser.error import SPDXParsingError
from src.parser.json.actor_parser import ActorParser
from src.parser.json.checksum_parser import ChecksumParser
from src.parser.json.dict_parsing_functions import datetime_from_str, parse_optional_field, \
    transform_json_str_to_enum_name
from src.parser.json.license_expression_parser import LicenseExpressionParser
from src.parser.logger import Logger


class PackageParser:
    logger: Logger
    actor_parser: ActorParser
    checksum_parser: ChecksumParser
    license_expression_parser: LicenseExpressionParser

    def __init__(self):
        self.actor_parser = ActorParser()
        self.checksum_parser = ChecksumParser()
        self.license_expression_parser = LicenseExpressionParser()
        self.logger = Logger()

    def parse_packages(self, packages_dict_list: List[Dict]) -> List[Package]:
        packages_list = []
        for package_dict in packages_dict_list:
            try:
                package: Package = self.parse_package(package_dict)
                packages_list.append(package)
            except SPDXParsingError as err:
                self.logger.append_all(err.get_messages())
                continue
        if self.logger.has_messages():
            raise SPDXParsingError(self.logger.get_messages())

        return packages_list

    def parse_package(self, package_dict: Dict) -> Package:
        logger = Logger()
        name: str = package_dict.get("name")
        spdx_id: str = package_dict.get("SPDXID")
        attribution_texts: List[str] = package_dict.get("attributionTexts")
        try:
            built_date: Optional[datetime] = parse_optional_field(package_dict.get("builtDate"), datetime_from_str)
        except ValueError:
            logger.append("ValueError while parsing builtDate.")
            built_date = None
        try:
            checksums: List[Checksum] = parse_optional_field(package_dict.get("checksums"),
                                                             self.checksum_parser.parse_checksums, default=[])
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            checksums = []
        comment: Optional[str] = package_dict.get("comment")
        copyright_text: Optional[str] = package_dict.get("copyrightText")
common
# Copyright (c) 2022 spdx contributors
# 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.
from datetime import datetime
from typing import Dict, List, Optional, Union

from src.model.actor import Actor
from src.model.checksum import Checksum
from src.model.license_expression import LicenseExpression
from src.model.package import Package, ExternalPackageRef, PackageVerificationCode, PackagePurpose, \
    ExternalPackageRefCategory
from src.model.spdx_no_assertion import SpdxNoAssertion
from src.model.spdx_none import SpdxNone
from src.model.typing.constructor_type_errors import ConstructorTypeErrors
from src.parser.error import SPDXParsingError
from src.parser.json.actor_parser import ActorParser
from src.parser.json.checksum_parser import ChecksumParser
from src.parser.json.dict_parsing_functions import datetime_from_str, parse_optional_field, \
    transform_json_str_to_enum_name
from src.parser.json.license_expression_parser import LicenseExpressionParser
from src.parser.logger import Logger


class PackageParser:
    logger: Logger
    actor_parser: ActorParser
    checksum_parser: ChecksumParser
    license_expression_parser: LicenseExpressionParser

    def __init__(self):
        self.actor_parser = ActorParser()
        self.checksum_parser = ChecksumParser()
        self.license_expression_parser = LicenseExpressionParser()
        self.logger = Logger()

    def parse_packages(self, packages_dict_list: List[Dict]) -> List[Package]:
        packages_list = []
        for package_dict in packages_dict_list:
            try:
                package: Package = self.parse_package(package_dict)
                packages_list.append(package)
            except SPDXParsingError as err:
                self.logger.append_all(err.get_messages())
                continue
        if self.logger.has_messages():
            raise SPDXParsingError(self.logger.get_messages())

        return packages_list

    def parse_package(self, package_dict: Dict) -> Package:
        logger = Logger()
        name: str = package_dict.get("name")
        spdx_id: str = package_dict.get("SPDXID")
        attribution_texts: List[str] = package_dict.get("attributionTexts")
        try:
            built_date: Optional[datetime] = parse_optional_field(package_dict.get("builtDate"), datetime_from_str)
        except ValueError:
            logger.append("ValueError while parsing builtDate.")
            built_date = None
        try:
            checksums: List[Checksum] = parse_optional_field(package_dict.get("checksums"),
                                                             self.checksum_parser.parse_checksums, default=[])
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            checksums = []
        comment: Optional[str] = package_dict.get("comment")
        copyright_text: Optional[str] = package_dict.get("copyrightText")
        description: Optional[str] = package_dict.get("description")
        download_location: Union[str, SpdxNoAssertion, SpdxNone] = self.parse_download_location(
common
# Copyright (c) 2022 spdx contributors
# 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.
from datetime import datetime
from typing import Dict, List, Optional, Union

from src.model.actor import Actor
from src.model.checksum import Checksum
from src.model.license_expression import LicenseExpression
from src.model.package import Package, ExternalPackageRef, PackageVerificationCode, PackagePurpose, \
    ExternalPackageRefCategory
from src.model.spdx_no_assertion import SpdxNoAssertion
from src.model.spdx_none import SpdxNone
from src.model.typing.constructor_type_errors import ConstructorTypeErrors
from src.parser.error import SPDXParsingError
from src.parser.json.actor_parser import ActorParser
from src.parser.json.checksum_parser import ChecksumParser
from src.parser.json.dict_parsing_functions import datetime_from_str, parse_optional_field, \
    transform_json_str_to_enum_name
from src.parser.json.license_expression_parser import LicenseExpressionParser
from src.parser.logger import Logger


class PackageParser:
    logger: Logger
    actor_parser: ActorParser
    checksum_parser: ChecksumParser
    license_expression_parser: LicenseExpressionParser

    def __init__(self):
        self.actor_parser = ActorParser()
        self.checksum_parser = ChecksumParser()
        self.license_expression_parser = LicenseExpressionParser()
        self.logger = Logger()

    def parse_packages(self, packages_dict_list: List[Dict]) -> List[Package]:
        packages_list = []
        for package_dict in packages_dict_list:
            try:
                package: Package = self.parse_package(package_dict)
                packages_list.append(package)
            except SPDXParsingError as err:
                self.logger.append_all(err.get_messages())
                continue
        if self.logger.has_messages():
            raise SPDXParsingError(self.logger.get_messages())

        return packages_list

    def parse_package(self, package_dict: Dict) -> Package:
        logger = Logger()
        name: str = package_dict.get("name")
        spdx_id: str = package_dict.get("SPDXID")
        attribution_texts: List[str] = package_dict.get("attributionTexts")
        try:
            built_date: Optional[datetime] = parse_optional_field(package_dict.get("builtDate"), datetime_from_str)
        except ValueError:
            logger.append("ValueError while parsing builtDate.")
            built_date = None
        try:
            checksums: List[Checksum] = parse_optional_field(package_dict.get("checksums"),
                                                             self.checksum_parser.parse_checksums, default=[])
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            checksums = []
        comment: Optional[str] = package_dict.get("comment")
        copyright_text: Optional[str] = package_dict.get("copyrightText")
        description: Optional[str] = package_dict.get("description")
        download_location: Union[str, SpdxNoAssertion, SpdxNone] = self.parse_download_location(
            package_dict.get("downloadLocation"))
        try:
            external_refs: List[ExternalPackageRef] = parse_optional_field(package_dict.get("externalRefs"),
                                                                           self.parse_external_refs)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            external_refs = []
common
# Copyright (c) 2022 spdx contributors
# 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.
from datetime import datetime
from typing import Dict, List, Optional, Union

from src.model.actor import Actor
from src.model.checksum import Checksum
from src.model.license_expression import LicenseExpression
from src.model.package import Package, ExternalPackageRef, PackageVerificationCode, PackagePurpose, \
    ExternalPackageRefCategory
from src.model.spdx_no_assertion import SpdxNoAssertion
from src.model.spdx_none import SpdxNone
from src.model.typing.constructor_type_errors import ConstructorTypeErrors
from src.parser.error import SPDXParsingError
from src.parser.json.actor_parser import ActorParser
from src.parser.json.checksum_parser import ChecksumParser
from src.parser.json.dict_parsing_functions import datetime_from_str, parse_optional_field, \
    transform_json_str_to_enum_name
from src.parser.json.license_expression_parser import LicenseExpressionParser
from src.parser.logger import Logger


class PackageParser:
    logger: Logger
    actor_parser: ActorParser
    checksum_parser: ChecksumParser
    license_expression_parser: LicenseExpressionParser

    def __init__(self):
        self.actor_parser = ActorParser()
        self.checksum_parser = ChecksumParser()
        self.license_expression_parser = LicenseExpressionParser()
        self.logger = Logger()

    def parse_packages(self, packages_dict_list: List[Dict]) -> List[Package]:
        packages_list = []
        for package_dict in packages_dict_list:
            try:
                package: Package = self.parse_package(package_dict)
                packages_list.append(package)
            except SPDXParsingError as err:
                self.logger.append_all(err.get_messages())
                continue
        if self.logger.has_messages():
            raise SPDXParsingError(self.logger.get_messages())

        return packages_list

    def parse_package(self, package_dict: Dict) -> Package:
        logger = Logger()
        name: str = package_dict.get("name")
        spdx_id: str = package_dict.get("SPDXID")
        attribution_texts: List[str] = package_dict.get("attributionTexts")
        try:
            built_date: Optional[datetime] = parse_optional_field(package_dict.get("builtDate"), datetime_from_str)
        except ValueError:
            logger.append("ValueError while parsing builtDate.")
            built_date = None
        try:
            checksums: List[Checksum] = parse_optional_field(package_dict.get("checksums"),
                                                             self.checksum_parser.parse_checksums, default=[])
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            checksums = []
        comment: Optional[str] = package_dict.get("comment")
        copyright_text: Optional[str] = package_dict.get("copyrightText")
        description: Optional[str] = package_dict.get("description")
        download_location: Union[str, SpdxNoAssertion, SpdxNone] = self.parse_download_location(
            package_dict.get("downloadLocation"))
        try:
            external_refs: List[ExternalPackageRef] = parse_optional_field(package_dict.get("externalRefs"),
                                                                           self.parse_external_refs)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            external_refs = []
        files_analyzed: Optional[bool] = parse_optional_field(package_dict.get("filesAnalyzed"), default=True)
common
# Copyright (c) 2022 spdx contributors
# 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.
from datetime import datetime
from typing import Dict, List, Optional, Union

from src.model.actor import Actor
from src.model.checksum import Checksum
from src.model.license_expression import LicenseExpression
from src.model.package import Package, ExternalPackageRef, PackageVerificationCode, PackagePurpose, \
    ExternalPackageRefCategory
from src.model.spdx_no_assertion import SpdxNoAssertion
from src.model.spdx_none import SpdxNone
from src.model.typing.constructor_type_errors import ConstructorTypeErrors
from src.parser.error import SPDXParsingError
from src.parser.json.actor_parser import ActorParser
from src.parser.json.checksum_parser import ChecksumParser
from src.parser.json.dict_parsing_functions import datetime_from_str, parse_optional_field, \
    transform_json_str_to_enum_name
from src.parser.json.license_expression_parser import LicenseExpressionParser
from src.parser.logger import Logger


class PackageParser:
    logger: Logger
    actor_parser: ActorParser
    checksum_parser: ChecksumParser
    license_expression_parser: LicenseExpressionParser

    def __init__(self):
        self.actor_parser = ActorParser()
        self.checksum_parser = ChecksumParser()
        self.license_expression_parser = LicenseExpressionParser()
        self.logger = Logger()

    def parse_packages(self, packages_dict_list: List[Dict]) -> List[Package]:
        packages_list = []
        for package_dict in packages_dict_list:
            try:
                package: Package = self.parse_package(package_dict)
                packages_list.append(package)
            except SPDXParsingError as err:
                self.logger.append_all(err.get_messages())
                continue
        if self.logger.has_messages():
            raise SPDXParsingError(self.logger.get_messages())

        return packages_list

    def parse_package(self, package_dict: Dict) -> Package:
        logger = Logger()
        name: str = package_dict.get("name")
        spdx_id: str = package_dict.get("SPDXID")
        attribution_texts: List[str] = package_dict.get("attributionTexts")
        try:
            built_date: Optional[datetime] = parse_optional_field(package_dict.get("builtDate"), datetime_from_str)
        except ValueError:
            logger.append("ValueError while parsing builtDate.")
            built_date = None
        try:
            checksums: List[Checksum] = parse_optional_field(package_dict.get("checksums"),
                                                             self.checksum_parser.parse_checksums, default=[])
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            checksums = []
        comment: Optional[str] = package_dict.get("comment")
        copyright_text: Optional[str] = package_dict.get("copyrightText")
        description: Optional[str] = package_dict.get("description")
        download_location: Union[str, SpdxNoAssertion, SpdxNone] = self.parse_download_location(
            package_dict.get("downloadLocation"))
        try:
            external_refs: List[ExternalPackageRef] = parse_optional_field(package_dict.get("externalRefs"),
                                                                           self.parse_external_refs)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            external_refs = []
        files_analyzed: Optional[bool] = parse_optional_field(package_dict.get("filesAnalyzed"), default=True)
        homepage: Optional[str] = package_dict.get("homepage")
common
# Copyright (c) 2022 spdx contributors
# 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.
from datetime import datetime
from typing import Dict, List, Optional, Union

from src.model.actor import Actor
from src.model.checksum import Checksum
from src.model.license_expression import LicenseExpression
from src.model.package import Package, ExternalPackageRef, PackageVerificationCode, PackagePurpose, \
    ExternalPackageRefCategory
from src.model.spdx_no_assertion import SpdxNoAssertion
from src.model.spdx_none import SpdxNone
from src.model.typing.constructor_type_errors import ConstructorTypeErrors
from src.parser.error import SPDXParsingError
from src.parser.json.actor_parser import ActorParser
from src.parser.json.checksum_parser import ChecksumParser
from src.parser.json.dict_parsing_functions import datetime_from_str, parse_optional_field, \
    transform_json_str_to_enum_name
from src.parser.json.license_expression_parser import LicenseExpressionParser
from src.parser.logger import Logger


class PackageParser:
    logger: Logger
    actor_parser: ActorParser
    checksum_parser: ChecksumParser
    license_expression_parser: LicenseExpressionParser

    def __init__(self):
        self.actor_parser = ActorParser()
        self.checksum_parser = ChecksumParser()
        self.license_expression_parser = LicenseExpressionParser()
        self.logger = Logger()

    def parse_packages(self, packages_dict_list: List[Dict]) -> List[Package]:
        packages_list = []
        for package_dict in packages_dict_list:
            try:
                package: Package = self.parse_package(package_dict)
                packages_list.append(package)
            except SPDXParsingError as err:
                self.logger.append_all(err.get_messages())
                continue
        if self.logger.has_messages():
            raise SPDXParsingError(self.logger.get_messages())

        return packages_list

    def parse_package(self, package_dict: Dict) -> Package:
        logger = Logger()
        name: str = package_dict.get("name")
        spdx_id: str = package_dict.get("SPDXID")
        attribution_texts: List[str] = package_dict.get("attributionTexts")
        try:
            built_date: Optional[datetime] = parse_optional_field(package_dict.get("builtDate"), datetime_from_str)
        except ValueError:
            logger.append("ValueError while parsing builtDate.")
            built_date = None
        try:
            checksums: List[Checksum] = parse_optional_field(package_dict.get("checksums"),
                                                             self.checksum_parser.parse_checksums, default=[])
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            checksums = []
        comment: Optional[str] = package_dict.get("comment")
        copyright_text: Optional[str] = package_dict.get("copyrightText")
        description: Optional[str] = package_dict.get("description")
        download_location: Union[str, SpdxNoAssertion, SpdxNone] = self.parse_download_location(
            package_dict.get("downloadLocation"))
        try:
            external_refs: List[ExternalPackageRef] = parse_optional_field(package_dict.get("externalRefs"),
                                                                           self.parse_external_refs)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            external_refs = []
        files_analyzed: Optional[bool] = parse_optional_field(package_dict.get("filesAnalyzed"), default=True)
        homepage: Optional[str] = package_dict.get("homepage")
        license_comments: Optional[str] = package_dict.get("licenseComments")
        try:
            license_concluded: Optional[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]] = parse_optional_field(
                package_dict.get("licenseConcluded"),
                self.license_expression_parser.parse_license_expression)
        except ConstructorTypeErrors as err:
            logger.append_all(err.get_messages())
            license_concluded = None
        try:
            license_declared: Optional[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]] = parse_optional_field(
                package_dict.get("licenseDeclared"),
                self.license_expression_parser.parse_license_expression)
        except ConstructorTypeErrors as err:
            logger.append_all(err.get_messages())
            license_declared = None
        try:
            license_info_from_file: Optional[
                Union[List[LicenseExpression], SpdxNoAssertion, SpdxNone]] = parse_optional_field(
                package_dict.get("licenseInfoFromFiles"),
                self.license_expression_parser.parse_license_expression)
        except ConstructorTypeErrors as err:
            logger.append_all(err.get_messages())
            license_info_from_file = None
        try:
            originator: Optional[Union[Actor, SpdxNoAssertion]] = parse_optional_field(package_dict.get("originator"),
                                                                                       self.actor_parser.parse_actor_or_no_assert)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            originator = None
        package_file_name: Optional[str] = package_dict.get("packageFileName")
        try:
            package_verification_code: Optional[PackageVerificationCode] = parse_optional_field(
                package_dict.get("packageVerificationCode"), self.parse_package_verification_code)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            package_verification_code = None

        try:
            primary_package_purpose: Optional[PackagePurpose] = parse_optional_field(
                package_dict.get("primaryPackagePurpose"), self.parse_primary_package_purpose)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            primary_package_purpose = None

        try:
            release_date: Optional[datetime] = parse_optional_field(package_dict.get("releaseDate"), datetime_from_str)
        except ValueError:
            logger.append("ValueError while parsing releaseDate.")
            release_date = None
        source_info: Optional[str] = package_dict.get("sourceInfo")
        summary: Optional[str] = package_dict.get("summary")
        try:
            supplier: Optional[Union[Actor, SpdxNoAssertion]] = parse_optional_field(package_dict.get("supplier"),
                                                                                     self.actor_parser.parse_actor_or_no_assert)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            supplier = None
        try:
            valid_until_date: Optional[datetime] = parse_optional_field(package_dict.get("validUntilDate"),
                                                                        datetime_from_str)
        except ValueError:
            logger.append("ValueError while parsing validUntilDate.")
            valid_until_date = None

        version_info: Optional[str] = package_dict.get("versionInfo")
        if logger.has_messages():
            raise SPDXParsingError([f"Error while parsing Package {name}: {logger.get_messages()}"])

        try:
            package = Package(spdx_id=spdx_id, name=name, download_location=download_location, version=version_info,
                              file_name=package_file_name, supplier=supplier, originator=originator,
                              files_analyzed=files_analyzed,
                              verification_code=package_verification_code, checksums=checksums, homepage=homepage,
                              source_info=source_info,
                              license_concluded=license_concluded, license_info_from_files=license_info_from_file,
                              license_declared=license_declared,
                              license_comment=license_comments, copyright_text=copyright_text, summary=summary,
                              description=description,
                              comment=comment, external_references=external_refs, attribution_texts=attribution_texts,
                              primary_package_purpose=primary_package_purpose,
                              release_date=release_date, built_date=built_date, valid_until_date=valid_until_date)

        except ConstructorTypeErrors as err:
            raise SPDXParsingError([f"Error while constructing Package {name}: {err.get_messages()}"])

        return package

    def parse_external_refs(self, external_ref_dicts: List[Dict]) -> List[ExternalPackageRef]:
        external_refs = []
        for external_ref_dict in external_ref_dicts:
            try:
                external_ref: ExternalPackageRef = self.parse_external_ref(external_ref_dict)
                external_refs.append(external_ref)
            except SPDXParsingError as err:
                self.logger.append_all(err.get_messages())
        return external_refs

    def parse_external_ref(self, external_ref_dict: Dict) -> ExternalPackageRef:
        logger = Logger()
        try:
            ref_category = self.parse_external_ref_category(external_ref_dict.get("referenceCategory"))
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            ref_category = None
        ref_locator = external_ref_dict.get("referenceLocator")
        ref_type = external_ref_dict.get("referenceType")
        comment = external_ref_dict.get("comment")
        if logger.has_messages():
            raise SPDXParsingError([f"Error while parsing external ref: {logger.get_messages()}"])
        try:
            external_ref = ExternalPackageRef(category=ref_category, reference_type=ref_type, locator=ref_locator,
                                              comment=comment)
        except ConstructorTypeErrors as err:
            raise SPDXParsingError([f"Error while constructing external ref: {err.get_messages()}"])

        return external_ref

    @staticmethod
    def parse_external_ref_category(external_ref_category_str: str) -> ExternalPackageRefCategory:
        try:
            external_ref_category = ExternalPackageRefCategory[
                transform_json_str_to_enum_name(external_ref_category_str)]
        except KeyError:
            raise SPDXParsingError([f"Category {external_ref_category_str} not valid for externalPackageRef."])

        return external_ref_category

    @staticmethod
    def parse_package_verification_code(verification_code_dict: Dict) -> PackageVerificationCode:
common
# Copyright (c) 2022 spdx contributors
# 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.
from datetime import datetime
from typing import Dict, List, Optional, Union

from src.model.actor import Actor
from src.model.checksum import Checksum
from src.model.license_expression import LicenseExpression
from src.model.package import Package, ExternalPackageRef, PackageVerificationCode, PackagePurpose, \
    ExternalPackageRefCategory
from src.model.spdx_no_assertion import SpdxNoAssertion
from src.model.spdx_none import SpdxNone
from src.model.typing.constructor_type_errors import ConstructorTypeErrors
from src.parser.error import SPDXParsingError
from src.parser.json.actor_parser import ActorParser
from src.parser.json.checksum_parser import ChecksumParser
from src.parser.json.dict_parsing_functions import datetime_from_str, parse_optional_field, \
    transform_json_str_to_enum_name
from src.parser.json.license_expression_parser import LicenseExpressionParser
from src.parser.logger import Logger


class PackageParser:
    logger: Logger
    actor_parser: ActorParser
    checksum_parser: ChecksumParser
    license_expression_parser: LicenseExpressionParser

    def __init__(self):
        self.actor_parser = ActorParser()
        self.checksum_parser = ChecksumParser()
        self.license_expression_parser = LicenseExpressionParser()
        self.logger = Logger()

    def parse_packages(self, packages_dict_list: List[Dict]) -> List[Package]:
        packages_list = []
        for package_dict in packages_dict_list:
            try:
                package: Package = self.parse_package(package_dict)
                packages_list.append(package)
            except SPDXParsingError as err:
                self.logger.append_all(err.get_messages())
                continue
        if self.logger.has_messages():
            raise SPDXParsingError(self.logger.get_messages())

        return packages_list

    def parse_package(self, package_dict: Dict) -> Package:
        logger = Logger()
        name: str = package_dict.get("name")
        spdx_id: str = package_dict.get("SPDXID")
        attribution_texts: List[str] = package_dict.get("attributionTexts")
        try:
            built_date: Optional[datetime] = parse_optional_field(package_dict.get("builtDate"), datetime_from_str)
        except ValueError:
            logger.append("ValueError while parsing builtDate.")
            built_date = None
        try:
            checksums: List[Checksum] = parse_optional_field(package_dict.get("checksums"),
                                                             self.checksum_parser.parse_checksums, default=[])
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            checksums = []
        comment: Optional[str] = package_dict.get("comment")
        copyright_text: Optional[str] = package_dict.get("copyrightText")
        description: Optional[str] = package_dict.get("description")
        download_location: Union[str, SpdxNoAssertion, SpdxNone] = self.parse_download_location(
            package_dict.get("downloadLocation"))
        try:
            external_refs: List[ExternalPackageRef] = parse_optional_field(package_dict.get("externalRefs"),
                                                                           self.parse_external_refs)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            external_refs = []
        files_analyzed: Optional[bool] = parse_optional_field(package_dict.get("filesAnalyzed"), default=True)
        homepage: Optional[str] = package_dict.get("homepage")
        license_comments: Optional[str] = package_dict.get("licenseComments")
        try:
            license_concluded: Optional[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]] = parse_optional_field(
                package_dict.get("licenseConcluded"),
                self.license_expression_parser.parse_license_expression)
        except ConstructorTypeErrors as err:
            logger.append_all(err.get_messages())
            license_concluded = None
        try:
            license_declared: Optional[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]] = parse_optional_field(
                package_dict.get("licenseDeclared"),
                self.license_expression_parser.parse_license_expression)
        except ConstructorTypeErrors as err:
            logger.append_all(err.get_messages())
            license_declared = None
        try:
            license_info_from_file: Optional[
                Union[List[LicenseExpression], SpdxNoAssertion, SpdxNone]] = parse_optional_field(
                package_dict.get("licenseInfoFromFiles"),
                self.license_expression_parser.parse_license_expression)
        except ConstructorTypeErrors as err:
            logger.append_all(err.get_messages())
            license_info_from_file = None
        try:
            originator: Optional[Union[Actor, SpdxNoAssertion]] = parse_optional_field(package_dict.get("originator"),
                                                                                       self.actor_parser.parse_actor_or_no_assert)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            originator = None
        package_file_name: Optional[str] = package_dict.get("packageFileName")
        try:
            package_verification_code: Optional[PackageVerificationCode] = parse_optional_field(
                package_dict.get("packageVerificationCode"), self.parse_package_verification_code)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            package_verification_code = None

        try:
            primary_package_purpose: Optional[PackagePurpose] = parse_optional_field(
                package_dict.get("primaryPackagePurpose"), self.parse_primary_package_purpose)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            primary_package_purpose = None

        try:
            release_date: Optional[datetime] = parse_optional_field(package_dict.get("releaseDate"), datetime_from_str)
        except ValueError:
            logger.append("ValueError while parsing releaseDate.")
            release_date = None
        source_info: Optional[str] = package_dict.get("sourceInfo")
        summary: Optional[str] = package_dict.get("summary")
        try:
            supplier: Optional[Union[Actor, SpdxNoAssertion]] = parse_optional_field(package_dict.get("supplier"),
                                                                                     self.actor_parser.parse_actor_or_no_assert)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            supplier = None
        try:
            valid_until_date: Optional[datetime] = parse_optional_field(package_dict.get("validUntilDate"),
                                                                        datetime_from_str)
        except ValueError:
            logger.append("ValueError while parsing validUntilDate.")
            valid_until_date = None

        version_info: Optional[str] = package_dict.get("versionInfo")
        if logger.has_messages():
            raise SPDXParsingError([f"Error while parsing Package {name}: {logger.get_messages()}"])

        try:
            package = Package(spdx_id=spdx_id, name=name, download_location=download_location, version=version_info,
                              file_name=package_file_name, supplier=supplier, originator=originator,
                              files_analyzed=files_analyzed,
                              verification_code=package_verification_code, checksums=checksums, homepage=homepage,
                              source_info=source_info,
                              license_concluded=license_concluded, license_info_from_files=license_info_from_file,
                              license_declared=license_declared,
                              license_comment=license_comments, copyright_text=copyright_text, summary=summary,
                              description=description,
                              comment=comment, external_references=external_refs, attribution_texts=attribution_texts,
                              primary_package_purpose=primary_package_purpose,
                              release_date=release_date, built_date=built_date, valid_until_date=valid_until_date)

        except ConstructorTypeErrors as err:
            raise SPDXParsingError([f"Error while constructing Package {name}: {err.get_messages()}"])

        return package

    def parse_external_refs(self, external_ref_dicts: List[Dict]) -> List[ExternalPackageRef]:
        external_refs = []
        for external_ref_dict in external_ref_dicts:
            try:
                external_ref: ExternalPackageRef = self.parse_external_ref(external_ref_dict)
                external_refs.append(external_ref)
            except SPDXParsingError as err:
                self.logger.append_all(err.get_messages())
        return external_refs

    def parse_external_ref(self, external_ref_dict: Dict) -> ExternalPackageRef:
        logger = Logger()
        try:
            ref_category = self.parse_external_ref_category(external_ref_dict.get("referenceCategory"))
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            ref_category = None
        ref_locator = external_ref_dict.get("referenceLocator")
        ref_type = external_ref_dict.get("referenceType")
        comment = external_ref_dict.get("comment")
        if logger.has_messages():
            raise SPDXParsingError([f"Error while parsing external ref: {logger.get_messages()}"])
        try:
            external_ref = ExternalPackageRef(category=ref_category, reference_type=ref_type, locator=ref_locator,
                                              comment=comment)
        except ConstructorTypeErrors as err:
            raise SPDXParsingError([f"Error while constructing external ref: {err.get_messages()}"])

        return external_ref

    @staticmethod
    def parse_external_ref_category(external_ref_category_str: str) -> ExternalPackageRefCategory:
        try:
            external_ref_category = ExternalPackageRefCategory[
                transform_json_str_to_enum_name(external_ref_category_str)]
        except KeyError:
            raise SPDXParsingError([f"Category {external_ref_category_str} not valid for externalPackageRef."])

        return external_ref_category

    @staticmethod
    def parse_package_verification_code(verification_code_dict: Dict) -> PackageVerificationCode:
        excluded_files: List[str] = verification_code_dict.get("packageVerificationCodeExcludedFiles")
common
# Copyright (c) 2022 spdx contributors
# 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.
from datetime import datetime
from typing import Dict, List, Optional, Union

from src.model.actor import Actor
from src.model.checksum import Checksum
from src.model.license_expression import LicenseExpression
from src.model.package import Package, ExternalPackageRef, PackageVerificationCode, PackagePurpose, \
    ExternalPackageRefCategory
from src.model.spdx_no_assertion import SpdxNoAssertion
from src.model.spdx_none import SpdxNone
from src.model.typing.constructor_type_errors import ConstructorTypeErrors
from src.parser.error import SPDXParsingError
from src.parser.json.actor_parser import ActorParser
from src.parser.json.checksum_parser import ChecksumParser
from src.parser.json.dict_parsing_functions import datetime_from_str, parse_optional_field, \
    transform_json_str_to_enum_name
from src.parser.json.license_expression_parser import LicenseExpressionParser
from src.parser.logger import Logger


class PackageParser:
    logger: Logger
    actor_parser: ActorParser
    checksum_parser: ChecksumParser
    license_expression_parser: LicenseExpressionParser

    def __init__(self):
        self.actor_parser = ActorParser()
        self.checksum_parser = ChecksumParser()
        self.license_expression_parser = LicenseExpressionParser()
        self.logger = Logger()

    def parse_packages(self, packages_dict_list: List[Dict]) -> List[Package]:
        packages_list = []
        for package_dict in packages_dict_list:
            try:
                package: Package = self.parse_package(package_dict)
                packages_list.append(package)
            except SPDXParsingError as err:
                self.logger.append_all(err.get_messages())
                continue
        if self.logger.has_messages():
            raise SPDXParsingError(self.logger.get_messages())

        return packages_list

    def parse_package(self, package_dict: Dict) -> Package:
        logger = Logger()
        name: str = package_dict.get("name")
        spdx_id: str = package_dict.get("SPDXID")
        attribution_texts: List[str] = package_dict.get("attributionTexts")
        try:
            built_date: Optional[datetime] = parse_optional_field(package_dict.get("builtDate"), datetime_from_str)
        except ValueError:
            logger.append("ValueError while parsing builtDate.")
            built_date = None
        try:
            checksums: List[Checksum] = parse_optional_field(package_dict.get("checksums"),
                                                             self.checksum_parser.parse_checksums, default=[])
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            checksums = []
        comment: Optional[str] = package_dict.get("comment")
        copyright_text: Optional[str] = package_dict.get("copyrightText")
        description: Optional[str] = package_dict.get("description")
        download_location: Union[str, SpdxNoAssertion, SpdxNone] = self.parse_download_location(
            package_dict.get("downloadLocation"))
        try:
            external_refs: List[ExternalPackageRef] = parse_optional_field(package_dict.get("externalRefs"),
                                                                           self.parse_external_refs)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            external_refs = []
        files_analyzed: Optional[bool] = parse_optional_field(package_dict.get("filesAnalyzed"), default=True)
        homepage: Optional[str] = package_dict.get("homepage")
        license_comments: Optional[str] = package_dict.get("licenseComments")
        try:
            license_concluded: Optional[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]] = parse_optional_field(
common
# Copyright (c) 2022 spdx contributors
# 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.
from datetime import datetime
from typing import Dict, List, Optional, Union

from src.model.actor import Actor
from src.model.checksum import Checksum
from src.model.license_expression import LicenseExpression
from src.model.package import Package, ExternalPackageRef, PackageVerificationCode, PackagePurpose, \
    ExternalPackageRefCategory
from src.model.spdx_no_assertion import SpdxNoAssertion
from src.model.spdx_none import SpdxNone
from src.model.typing.constructor_type_errors import ConstructorTypeErrors
from src.parser.error import SPDXParsingError
from src.parser.json.actor_parser import ActorParser
from src.parser.json.checksum_parser import ChecksumParser
from src.parser.json.dict_parsing_functions import datetime_from_str, parse_optional_field, \
    transform_json_str_to_enum_name
from src.parser.json.license_expression_parser import LicenseExpressionParser
from src.parser.logger import Logger


class PackageParser:
    logger: Logger
    actor_parser: ActorParser
    checksum_parser: ChecksumParser
    license_expression_parser: LicenseExpressionParser

    def __init__(self):
        self.actor_parser = ActorParser()
        self.checksum_parser = ChecksumParser()
        self.license_expression_parser = LicenseExpressionParser()
        self.logger = Logger()

    def parse_packages(self, packages_dict_list: List[Dict]) -> List[Package]:
        packages_list = []
        for package_dict in packages_dict_list:
            try:
                package: Package = self.parse_package(package_dict)
                packages_list.append(package)
            except SPDXParsingError as err:
                self.logger.append_all(err.get_messages())
                continue
        if self.logger.has_messages():
            raise SPDXParsingError(self.logger.get_messages())

        return packages_list

    def parse_package(self, package_dict: Dict) -> Package:
        logger = Logger()
        name: str = package_dict.get("name")
        spdx_id: str = package_dict.get("SPDXID")
        attribution_texts: List[str] = package_dict.get("attributionTexts")
        try:
            built_date: Optional[datetime] = parse_optional_field(package_dict.get("builtDate"), datetime_from_str)
        except ValueError:
            logger.append("ValueError while parsing builtDate.")
            built_date = None
        try:
            checksums: List[Checksum] = parse_optional_field(package_dict.get("checksums"),
                                                             self.checksum_parser.parse_checksums, default=[])
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            checksums = []
        comment: Optional[str] = package_dict.get("comment")
        copyright_text: Optional[str] = package_dict.get("copyrightText")
        description: Optional[str] = package_dict.get("description")
        download_location: Union[str, SpdxNoAssertion, SpdxNone] = self.parse_download_location(
            package_dict.get("downloadLocation"))
        try:
            external_refs: List[ExternalPackageRef] = parse_optional_field(package_dict.get("externalRefs"),
                                                                           self.parse_external_refs)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            external_refs = []
        files_analyzed: Optional[bool] = parse_optional_field(package_dict.get("filesAnalyzed"), default=True)
        homepage: Optional[str] = package_dict.get("homepage")
        license_comments: Optional[str] = package_dict.get("licenseComments")
        try:
            license_concluded: Optional[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]] = parse_optional_field(
                package_dict.get("licenseConcluded"),
                self.license_expression_parser.parse_license_expression)
        except ConstructorTypeErrors as err:
            logger.append_all(err.get_messages())
            license_concluded = None
        try:
            license_declared: Optional[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]] = parse_optional_field(
common
# Copyright (c) 2022 spdx contributors
# 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.
from datetime import datetime
from typing import Dict, List, Optional, Union

from src.model.actor import Actor
from src.model.checksum import Checksum
from src.model.license_expression import LicenseExpression
from src.model.package import Package, ExternalPackageRef, PackageVerificationCode, PackagePurpose, \
    ExternalPackageRefCategory
from src.model.spdx_no_assertion import SpdxNoAssertion
from src.model.spdx_none import SpdxNone
from src.model.typing.constructor_type_errors import ConstructorTypeErrors
from src.parser.error import SPDXParsingError
from src.parser.json.actor_parser import ActorParser
from src.parser.json.checksum_parser import ChecksumParser
from src.parser.json.dict_parsing_functions import datetime_from_str, parse_optional_field, \
    transform_json_str_to_enum_name
from src.parser.json.license_expression_parser import LicenseExpressionParser
from src.parser.logger import Logger


class PackageParser:
    logger: Logger
    actor_parser: ActorParser
    checksum_parser: ChecksumParser
    license_expression_parser: LicenseExpressionParser

    def __init__(self):
        self.actor_parser = ActorParser()
        self.checksum_parser = ChecksumParser()
        self.license_expression_parser = LicenseExpressionParser()
        self.logger = Logger()

    def parse_packages(self, packages_dict_list: List[Dict]) -> List[Package]:
        packages_list = []
        for package_dict in packages_dict_list:
            try:
                package: Package = self.parse_package(package_dict)
                packages_list.append(package)
            except SPDXParsingError as err:
                self.logger.append_all(err.get_messages())
                continue
        if self.logger.has_messages():
            raise SPDXParsingError(self.logger.get_messages())

        return packages_list

    def parse_package(self, package_dict: Dict) -> Package:
        logger = Logger()
        name: str = package_dict.get("name")
        spdx_id: str = package_dict.get("SPDXID")
        attribution_texts: List[str] = package_dict.get("attributionTexts")
        try:
            built_date: Optional[datetime] = parse_optional_field(package_dict.get("builtDate"), datetime_from_str)
        except ValueError:
            logger.append("ValueError while parsing builtDate.")
            built_date = None
        try:
            checksums: List[Checksum] = parse_optional_field(package_dict.get("checksums"),
                                                             self.checksum_parser.parse_checksums, default=[])
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            checksums = []
        comment: Optional[str] = package_dict.get("comment")
        copyright_text: Optional[str] = package_dict.get("copyrightText")
        description: Optional[str] = package_dict.get("description")
        download_location: Union[str, SpdxNoAssertion, SpdxNone] = self.parse_download_location(
            package_dict.get("downloadLocation"))
        try:
            external_refs: List[ExternalPackageRef] = parse_optional_field(package_dict.get("externalRefs"),
                                                                           self.parse_external_refs)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            external_refs = []
        files_analyzed: Optional[bool] = parse_optional_field(package_dict.get("filesAnalyzed"), default=True)
        homepage: Optional[str] = package_dict.get("homepage")
        license_comments: Optional[str] = package_dict.get("licenseComments")
        try:
            license_concluded: Optional[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]] = parse_optional_field(
                package_dict.get("licenseConcluded"),
                self.license_expression_parser.parse_license_expression)
        except ConstructorTypeErrors as err:
            logger.append_all(err.get_messages())
            license_concluded = None
        try:
            license_declared: Optional[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]] = parse_optional_field(
                package_dict.get("licenseDeclared"),
                self.license_expression_parser.parse_license_expression)
        except ConstructorTypeErrors as err:
            logger.append_all(err.get_messages())
            license_declared = None
        try:
            license_info_from_file: Optional[
                Union[List[LicenseExpression], SpdxNoAssertion, SpdxNone]] = parse_optional_field(
common
# Copyright (c) 2022 spdx contributors
# 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.
from datetime import datetime
from typing import Dict, List, Optional, Union

from src.model.actor import Actor
from src.model.checksum import Checksum
from src.model.license_expression import LicenseExpression
from src.model.package import Package, ExternalPackageRef, PackageVerificationCode, PackagePurpose, \
    ExternalPackageRefCategory
from src.model.spdx_no_assertion import SpdxNoAssertion
from src.model.spdx_none import SpdxNone
from src.model.typing.constructor_type_errors import ConstructorTypeErrors
from src.parser.error import SPDXParsingError
from src.parser.json.actor_parser import ActorParser
from src.parser.json.checksum_parser import ChecksumParser
from src.parser.json.dict_parsing_functions import datetime_from_str, parse_optional_field, \
    transform_json_str_to_enum_name
from src.parser.json.license_expression_parser import LicenseExpressionParser
from src.parser.logger import Logger


class PackageParser:
    logger: Logger
    actor_parser: ActorParser
    checksum_parser: ChecksumParser
    license_expression_parser: LicenseExpressionParser

    def __init__(self):
        self.actor_parser = ActorParser()
        self.checksum_parser = ChecksumParser()
        self.license_expression_parser = LicenseExpressionParser()
        self.logger = Logger()

    def parse_packages(self, packages_dict_list: List[Dict]) -> List[Package]:
        packages_list = []
        for package_dict in packages_dict_list:
            try:
                package: Package = self.parse_package(package_dict)
                packages_list.append(package)
            except SPDXParsingError as err:
                self.logger.append_all(err.get_messages())
                continue
        if self.logger.has_messages():
            raise SPDXParsingError(self.logger.get_messages())

        return packages_list

    def parse_package(self, package_dict: Dict) -> Package:
        logger = Logger()
        name: str = package_dict.get("name")
        spdx_id: str = package_dict.get("SPDXID")
        attribution_texts: List[str] = package_dict.get("attributionTexts")
        try:
            built_date: Optional[datetime] = parse_optional_field(package_dict.get("builtDate"), datetime_from_str)
        except ValueError:
            logger.append("ValueError while parsing builtDate.")
            built_date = None
        try:
            checksums: List[Checksum] = parse_optional_field(package_dict.get("checksums"),
                                                             self.checksum_parser.parse_checksums, default=[])
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            checksums = []
        comment: Optional[str] = package_dict.get("comment")
        copyright_text: Optional[str] = package_dict.get("copyrightText")
        description: Optional[str] = package_dict.get("description")
        download_location: Union[str, SpdxNoAssertion, SpdxNone] = self.parse_download_location(
            package_dict.get("downloadLocation"))
        try:
            external_refs: List[ExternalPackageRef] = parse_optional_field(package_dict.get("externalRefs"),
                                                                           self.parse_external_refs)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            external_refs = []
        files_analyzed: Optional[bool] = parse_optional_field(package_dict.get("filesAnalyzed"), default=True)
        homepage: Optional[str] = package_dict.get("homepage")
        license_comments: Optional[str] = package_dict.get("licenseComments")
        try:
            license_concluded: Optional[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]] = parse_optional_field(
                package_dict.get("licenseConcluded"),
                self.license_expression_parser.parse_license_expression)
        except ConstructorTypeErrors as err:
            logger.append_all(err.get_messages())
            license_concluded = None
        try:
            license_declared: Optional[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]] = parse_optional_field(
                package_dict.get("licenseDeclared"),
                self.license_expression_parser.parse_license_expression)
        except ConstructorTypeErrors as err:
            logger.append_all(err.get_messages())
            license_declared = None
        try:
            license_info_from_file: Optional[
                Union[List[LicenseExpression], SpdxNoAssertion, SpdxNone]] = parse_optional_field(
                package_dict.get("licenseInfoFromFiles"),
                self.license_expression_parser.parse_license_expression)
        except ConstructorTypeErrors as err:
            logger.append_all(err.get_messages())
            license_info_from_file = None
        try:
            originator: Optional[Union[Actor, SpdxNoAssertion]] = parse_optional_field(package_dict.get("originator"),
                                                                                       self.actor_parser.parse_actor_or_no_assert)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            originator = None
common
# Copyright (c) 2022 spdx contributors
# 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.
from datetime import datetime
from typing import Dict, List, Optional, Union

from src.model.actor import Actor
from src.model.checksum import Checksum
from src.model.license_expression import LicenseExpression
from src.model.package import Package, ExternalPackageRef, PackageVerificationCode, PackagePurpose, \
    ExternalPackageRefCategory
from src.model.spdx_no_assertion import SpdxNoAssertion
non_informative
# Copyright (c) 2022 spdx contributors
# 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.
from datetime import datetime
from typing import Dict, List, Optional, Union

from src.model.actor import Actor
from src.model.checksum import Checksum
from src.model.license_expression import LicenseExpression
from src.model.package import Package, ExternalPackageRef, PackageVerificationCode, PackagePurpose, \
    ExternalPackageRefCategory
from src.model.spdx_no_assertion import SpdxNoAssertion
from src.model.spdx_none import SpdxNone
from src.model.typing.constructor_type_errors import ConstructorTypeErrors
from src.parser.error import SPDXParsingError
from src.parser.json.actor_parser import ActorParser
from src.parser.json.checksum_parser import ChecksumParser
from src.parser.json.dict_parsing_functions import datetime_from_str, parse_optional_field, \
    transform_json_str_to_enum_name
from src.parser.json.license_expression_parser import LicenseExpressionParser
from src.parser.logger import Logger


class PackageParser:
    logger: Logger
    actor_parser: ActorParser
    checksum_parser: ChecksumParser
    license_expression_parser: LicenseExpressionParser

    def __init__(self):
        self.actor_parser = ActorParser()
        self.checksum_parser = ChecksumParser()
        self.license_expression_parser = LicenseExpressionParser()
        self.logger = Logger()

    def parse_packages(self, packages_dict_list: List[Dict]) -> List[Package]:
        packages_list = []
        for package_dict in packages_dict_list:
            try:
                package: Package = self.parse_package(package_dict)
                packages_list.append(package)
            except SPDXParsingError as err:
                self.logger.append_all(err.get_messages())
                continue
        if self.logger.has_messages():
            raise SPDXParsingError(self.logger.get_messages())

        return packages_list

    def parse_package(self, package_dict: Dict) -> Package:
        logger = Logger()
        name: str = package_dict.get("name")
        spdx_id: str = package_dict.get("SPDXID")
        attribution_texts: List[str] = package_dict.get("attributionTexts")
        try:
            built_date: Optional[datetime] = parse_optional_field(package_dict.get("builtDate"), datetime_from_str)
        except ValueError:
            logger.append("ValueError while parsing builtDate.")
            built_date = None
        try:
            checksums: List[Checksum] = parse_optional_field(package_dict.get("checksums"),
                                                             self.checksum_parser.parse_checksums, default=[])
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            checksums = []
        comment: Optional[str] = package_dict.get("comment")
        copyright_text: Optional[str] = package_dict.get("copyrightText")
        description: Optional[str] = package_dict.get("description")
        download_location: Union[str, SpdxNoAssertion, SpdxNone] = self.parse_download_location(
            package_dict.get("downloadLocation"))
        try:
            external_refs: List[ExternalPackageRef] = parse_optional_field(package_dict.get("externalRefs"),
                                                                           self.parse_external_refs)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            external_refs = []
        files_analyzed: Optional[bool] = parse_optional_field(package_dict.get("filesAnalyzed"), default=True)
        homepage: Optional[str] = package_dict.get("homepage")
        license_comments: Optional[str] = package_dict.get("licenseComments")
        try:
            license_concluded: Optional[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]] = parse_optional_field(
                package_dict.get("licenseConcluded"),
                self.license_expression_parser.parse_license_expression)
        except ConstructorTypeErrors as err:
            logger.append_all(err.get_messages())
            license_concluded = None
        try:
            license_declared: Optional[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]] = parse_optional_field(
                package_dict.get("licenseDeclared"),
                self.license_expression_parser.parse_license_expression)
        except ConstructorTypeErrors as err:
            logger.append_all(err.get_messages())
            license_declared = None
        try:
            license_info_from_file: Optional[
                Union[List[LicenseExpression], SpdxNoAssertion, SpdxNone]] = parse_optional_field(
                package_dict.get("licenseInfoFromFiles"),
                self.license_expression_parser.parse_license_expression)
        except ConstructorTypeErrors as err:
            logger.append_all(err.get_messages())
            license_info_from_file = None
        try:
            originator: Optional[Union[Actor, SpdxNoAssertion]] = parse_optional_field(package_dict.get("originator"),
                                                                                       self.actor_parser.parse_actor_or_no_assert)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            originator = None
        package_file_name: Optional[str] = package_dict.get("packageFileName")
        try:
            package_verification_code: Optional[PackageVerificationCode] = parse_optional_field(
                package_dict.get("packageVerificationCode"), self.parse_package_verification_code)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            package_verification_code = None

        try:
            primary_package_purpose: Optional[PackagePurpose] = parse_optional_field(
                package_dict.get("primaryPackagePurpose"), self.parse_primary_package_purpose)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            primary_package_purpose = None

        try:
            release_date: Optional[datetime] = parse_optional_field(package_dict.get("releaseDate"), datetime_from_str)
        except ValueError:
            logger.append("ValueError while parsing releaseDate.")
            release_date = None
        source_info: Optional[str] = package_dict.get("sourceInfo")
        summary: Optional[str] = package_dict.get("summary")
        try:
            supplier: Optional[Union[Actor, SpdxNoAssertion]] = parse_optional_field(package_dict.get("supplier"),
                                                                                     self.actor_parser.parse_actor_or_no_assert)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            supplier = None
        try:
            valid_until_date: Optional[datetime] = parse_optional_field(package_dict.get("validUntilDate"),
                                                                        datetime_from_str)
        except ValueError:
            logger.append("ValueError while parsing validUntilDate.")
            valid_until_date = None

        version_info: Optional[str] = package_dict.get("versionInfo")
        if logger.has_messages():
            raise SPDXParsingError([f"Error while parsing Package {name}: {logger.get_messages()}"])

        try:
            package = Package(spdx_id=spdx_id, name=name, download_location=download_location, version=version_info,
                              file_name=package_file_name, supplier=supplier, originator=originator,
                              files_analyzed=files_analyzed,
                              verification_code=package_verification_code, checksums=checksums, homepage=homepage,
                              source_info=source_info,
                              license_concluded=license_concluded, license_info_from_files=license_info_from_file,
                              license_declared=license_declared,
                              license_comment=license_comments, copyright_text=copyright_text, summary=summary,
                              description=description,
                              comment=comment, external_references=external_refs, attribution_texts=attribution_texts,
                              primary_package_purpose=primary_package_purpose,
                              release_date=release_date, built_date=built_date, valid_until_date=valid_until_date)

        except ConstructorTypeErrors as err:
            raise SPDXParsingError([f"Error while constructing Package {name}: {err.get_messages()}"])

        return package

    def parse_external_refs(self, external_ref_dicts: List[Dict]) -> List[ExternalPackageRef]:
        external_refs = []
        for external_ref_dict in external_ref_dicts:
            try:
                external_ref: ExternalPackageRef = self.parse_external_ref(external_ref_dict)
                external_refs.append(external_ref)
            except SPDXParsingError as err:
                self.logger.append_all(err.get_messages())
        return external_refs

    def parse_external_ref(self, external_ref_dict: Dict) -> ExternalPackageRef:
        logger = Logger()
        try:
            ref_category = self.parse_external_ref_category(external_ref_dict.get("referenceCategory"))
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            ref_category = None
        ref_locator = external_ref_dict.get("referenceLocator")
        ref_type = external_ref_dict.get("referenceType")
        comment = external_ref_dict.get("comment")
        if logger.has_messages():
            raise SPDXParsingError([f"Error while parsing external ref: {logger.get_messages()}"])
        try:
            external_ref = ExternalPackageRef(category=ref_category, reference_type=ref_type, locator=ref_locator,
                                              comment=comment)
        except ConstructorTypeErrors as err:
            raise SPDXParsingError([f"Error while constructing external ref: {err.get_messages()}"])

        return external_ref

    @staticmethod
    def parse_external_ref_category(external_ref_category_str: str) -> ExternalPackageRefCategory:
        try:
            external_ref_category = ExternalPackageRefCategory[
                transform_json_str_to_enum_name(external_ref_category_str)]
        except KeyError:
            raise SPDXParsingError([f"Category {external_ref_category_str} not valid for externalPackageRef."])
non_informative
# Copyright (c) 2022 spdx contributors
# 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.
from datetime import datetime
from typing import Dict, List, Optional, Union

from src.model.actor import Actor
from src.model.checksum import Checksum
from src.model.license_expression import LicenseExpression
from src.model.package import Package, ExternalPackageRef, PackageVerificationCode, PackagePurpose, \
    ExternalPackageRefCategory
from src.model.spdx_no_assertion import SpdxNoAssertion
from src.model.spdx_none import SpdxNone
non_informative
# Copyright (c) 2022 spdx contributors
# 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.
non_informative
# Copyright (c) 2022 spdx contributors
# 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.
from datetime import datetime
from typing import Dict, List, Optional, Union

from src.model.actor import Actor
from src.model.checksum import Checksum
from src.model.license_expression import LicenseExpression
from src.model.package import Package, ExternalPackageRef, PackageVerificationCode, PackagePurpose, \
    ExternalPackageRefCategory
from src.model.spdx_no_assertion import SpdxNoAssertion
from src.model.spdx_none import SpdxNone
from src.model.typing.constructor_type_errors import ConstructorTypeErrors
from src.parser.error import SPDXParsingError
from src.parser.json.actor_parser import ActorParser
from src.parser.json.checksum_parser import ChecksumParser
from src.parser.json.dict_parsing_functions import datetime_from_str, parse_optional_field, \
    transform_json_str_to_enum_name
from src.parser.json.license_expression_parser import LicenseExpressionParser
from src.parser.logger import Logger


class PackageParser:
    logger: Logger
    actor_parser: ActorParser
    checksum_parser: ChecksumParser
    license_expression_parser: LicenseExpressionParser

    def __init__(self):
        self.actor_parser = ActorParser()
        self.checksum_parser = ChecksumParser()
        self.license_expression_parser = LicenseExpressionParser()
        self.logger = Logger()

    def parse_packages(self, packages_dict_list: List[Dict]) -> List[Package]:
        packages_list = []
        for package_dict in packages_dict_list:
            try:
                package: Package = self.parse_package(package_dict)
                packages_list.append(package)
            except SPDXParsingError as err:
                self.logger.append_all(err.get_messages())
                continue
        if self.logger.has_messages():
            raise SPDXParsingError(self.logger.get_messages())

        return packages_list

    def parse_package(self, package_dict: Dict) -> Package:
        logger = Logger()
        name: str = package_dict.get("name")
        spdx_id: str = package_dict.get("SPDXID")
        attribution_texts: List[str] = package_dict.get("attributionTexts")
        try:
            built_date: Optional[datetime] = parse_optional_field(package_dict.get("builtDate"), datetime_from_str)
        except ValueError:
            logger.append("ValueError while parsing builtDate.")
            built_date = None
        try:
            checksums: List[Checksum] = parse_optional_field(package_dict.get("checksums"),
                                                             self.checksum_parser.parse_checksums, default=[])
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            checksums = []
        comment: Optional[str] = package_dict.get("comment")
        copyright_text: Optional[str] = package_dict.get("copyrightText")
        description: Optional[str] = package_dict.get("description")
        download_location: Union[str, SpdxNoAssertion, SpdxNone] = self.parse_download_location(
            package_dict.get("downloadLocation"))
        try:
            external_refs: List[ExternalPackageRef] = parse_optional_field(package_dict.get("externalRefs"),
                                                                           self.parse_external_refs)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            external_refs = []
        files_analyzed: Optional[bool] = parse_optional_field(package_dict.get("filesAnalyzed"), default=True)
        homepage: Optional[str] = package_dict.get("homepage")
        license_comments: Optional[str] = package_dict.get("licenseComments")
        try:
            license_concluded: Optional[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]] = parse_optional_field(
                package_dict.get("licenseConcluded"),
                self.license_expression_parser.parse_license_expression)
        except ConstructorTypeErrors as err:
            logger.append_all(err.get_messages())
            license_concluded = None
        try:
            license_declared: Optional[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]] = parse_optional_field(
                package_dict.get("licenseDeclared"),
                self.license_expression_parser.parse_license_expression)
        except ConstructorTypeErrors as err:
            logger.append_all(err.get_messages())
            license_declared = None
        try:
            license_info_from_file: Optional[
                Union[List[LicenseExpression], SpdxNoAssertion, SpdxNone]] = parse_optional_field(
                package_dict.get("licenseInfoFromFiles"),
                self.license_expression_parser.parse_license_expression)
        except ConstructorTypeErrors as err:
            logger.append_all(err.get_messages())
            license_info_from_file = None
        try:
            originator: Optional[Union[Actor, SpdxNoAssertion]] = parse_optional_field(package_dict.get("originator"),
                                                                                       self.actor_parser.parse_actor_or_no_assert)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            originator = None
        package_file_name: Optional[str] = package_dict.get("packageFileName")
        try:
            package_verification_code: Optional[PackageVerificationCode] = parse_optional_field(
                package_dict.get("packageVerificationCode"), self.parse_package_verification_code)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            package_verification_code = None

        try:
            primary_package_purpose: Optional[PackagePurpose] = parse_optional_field(
                package_dict.get("primaryPackagePurpose"), self.parse_primary_package_purpose)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            primary_package_purpose = None

        try:
            release_date: Optional[datetime] = parse_optional_field(package_dict.get("releaseDate"), datetime_from_str)
        except ValueError:
            logger.append("ValueError while parsing releaseDate.")
            release_date = None
        source_info: Optional[str] = package_dict.get("sourceInfo")
        summary: Optional[str] = package_dict.get("summary")
        try:
            supplier: Optional[Union[Actor, SpdxNoAssertion]] = parse_optional_field(package_dict.get("supplier"),
                                                                                     self.actor_parser.parse_actor_or_no_assert)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            supplier = None
        try:
            valid_until_date: Optional[datetime] = parse_optional_field(package_dict.get("validUntilDate"),
                                                                        datetime_from_str)
        except ValueError:
            logger.append("ValueError while parsing validUntilDate.")
            valid_until_date = None

        version_info: Optional[str] = package_dict.get("versionInfo")
        if logger.has_messages():
            raise SPDXParsingError([f"Error while parsing Package {name}: {logger.get_messages()}"])

        try:
            package = Package(spdx_id=spdx_id, name=name, download_location=download_location, version=version_info,
                              file_name=package_file_name, supplier=supplier, originator=originator,
                              files_analyzed=files_analyzed,
                              verification_code=package_verification_code, checksums=checksums, homepage=homepage,
                              source_info=source_info,
                              license_concluded=license_concluded, license_info_from_files=license_info_from_file,
                              license_declared=license_declared,
                              license_comment=license_comments, copyright_text=copyright_text, summary=summary,
random
# Copyright (c) 2022 spdx contributors
# 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.
from datetime import datetime
from typing import Dict, List, Optional, Union

from src.model.actor import Actor
from src.model.checksum import Checksum
from src.model.license_expression import LicenseExpression
from src.model.package import Package, ExternalPackageRef, PackageVerificationCode, PackagePurpose, \
    ExternalPackageRefCategory
from src.model.spdx_no_assertion import SpdxNoAssertion
from src.model.spdx_none import SpdxNone
from src.model.typing.constructor_type_errors import ConstructorTypeErrors
from src.parser.error import SPDXParsingError
from src.parser.json.actor_parser import ActorParser
from src.parser.json.checksum_parser import ChecksumParser
from src.parser.json.dict_parsing_functions import datetime_from_str, parse_optional_field, \
    transform_json_str_to_enum_name
from src.parser.json.license_expression_parser import LicenseExpressionParser
from src.parser.logger import Logger


class PackageParser:
    logger: Logger
    actor_parser: ActorParser
    checksum_parser: ChecksumParser
    license_expression_parser: LicenseExpressionParser

    def __init__(self):
        self.actor_parser = ActorParser()
        self.checksum_parser = ChecksumParser()
        self.license_expression_parser = LicenseExpressionParser()
        self.logger = Logger()

    def parse_packages(self, packages_dict_list: List[Dict]) -> List[Package]:
        packages_list = []
        for package_dict in packages_dict_list:
            try:
                package: Package = self.parse_package(package_dict)
                packages_list.append(package)
            except SPDXParsingError as err:
                self.logger.append_all(err.get_messages())
                continue
        if self.logger.has_messages():
            raise SPDXParsingError(self.logger.get_messages())

        return packages_list

    def parse_package(self, package_dict: Dict) -> Package:
        logger = Logger()
        name: str = package_dict.get("name")
        spdx_id: str = package_dict.get("SPDXID")
        attribution_texts: List[str] = package_dict.get("attributionTexts")
        try:
            built_date: Optional[datetime] = parse_optional_field(package_dict.get("builtDate"), datetime_from_str)
        except ValueError:
            logger.append("ValueError while parsing builtDate.")
            built_date = None
        try:
            checksums: List[Checksum] = parse_optional_field(package_dict.get("checksums"),
                                                             self.checksum_parser.parse_checksums, default=[])
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            checksums = []
        comment: Optional[str] = package_dict.get("comment")
        copyright_text: Optional[str] = package_dict.get("copyrightText")
        description: Optional[str] = package_dict.get("description")
        download_location: Union[str, SpdxNoAssertion, SpdxNone] = self.parse_download_location(
            package_dict.get("downloadLocation"))
        try:
            external_refs: List[ExternalPackageRef] = parse_optional_field(package_dict.get("externalRefs"),
                                                                           self.parse_external_refs)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            external_refs = []
        files_analyzed: Optional[bool] = parse_optional_field(package_dict.get("filesAnalyzed"), default=True)
        homepage: Optional[str] = package_dict.get("homepage")
        license_comments: Optional[str] = package_dict.get("licenseComments")
        try:
            license_concluded: Optional[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]] = parse_optional_field(
                package_dict.get("licenseConcluded"),
                self.license_expression_parser.parse_license_expression)
        except ConstructorTypeErrors as err:
            logger.append_all(err.get_messages())
            license_concluded = None
        try:
            license_declared: Optional[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]] = parse_optional_field(
                package_dict.get("licenseDeclared"),
                self.license_expression_parser.parse_license_expression)
        except ConstructorTypeErrors as err:
            logger.append_all(err.get_messages())
            license_declared = None
        try:
            license_info_from_file: Optional[
                Union[List[LicenseExpression], SpdxNoAssertion, SpdxNone]] = parse_optional_field(
                package_dict.get("licenseInfoFromFiles"),
                self.license_expression_parser.parse_license_expression)
        except ConstructorTypeErrors as err:
            logger.append_all(err.get_messages())
            license_info_from_file = None
        try:
            originator: Optional[Union[Actor, SpdxNoAssertion]] = parse_optional_field(package_dict.get("originator"),
                                                                                       self.actor_parser.parse_actor_or_no_assert)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            originator = None
        package_file_name: Optional[str] = package_dict.get("packageFileName")
        try:
            package_verification_code: Optional[PackageVerificationCode] = parse_optional_field(
                package_dict.get("packageVerificationCode"), self.parse_package_verification_code)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            package_verification_code = None

        try:
            primary_package_purpose: Optional[PackagePurpose] = parse_optional_field(
                package_dict.get("primaryPackagePurpose"), self.parse_primary_package_purpose)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            primary_package_purpose = None

        try:
            release_date: Optional[datetime] = parse_optional_field(package_dict.get("releaseDate"), datetime_from_str)
        except ValueError:
            logger.append("ValueError while parsing releaseDate.")
            release_date = None
        source_info: Optional[str] = package_dict.get("sourceInfo")
        summary: Optional[str] = package_dict.get("summary")
        try:
            supplier: Optional[Union[Actor, SpdxNoAssertion]] = parse_optional_field(package_dict.get("supplier"),
                                                                                     self.actor_parser.parse_actor_or_no_assert)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            supplier = None
        try:
            valid_until_date: Optional[datetime] = parse_optional_field(package_dict.get("validUntilDate"),
                                                                        datetime_from_str)
        except ValueError:
            logger.append("ValueError while parsing validUntilDate.")
            valid_until_date = None

        version_info: Optional[str] = package_dict.get("versionInfo")
        if logger.has_messages():
            raise SPDXParsingError([f"Error while parsing Package {name}: {logger.get_messages()}"])

        try:
            package = Package(spdx_id=spdx_id, name=name, download_location=download_location, version=version_info,
                              file_name=package_file_name, supplier=supplier, originator=originator,
                              files_analyzed=files_analyzed,
                              verification_code=package_verification_code, checksums=checksums, homepage=homepage,
                              source_info=source_info,
                              license_concluded=license_concluded, license_info_from_files=license_info_from_file,
                              license_declared=license_declared,
                              license_comment=license_comments, copyright_text=copyright_text, summary=summary,
                              description=description,
                              comment=comment, external_references=external_refs, attribution_texts=attribution_texts,
                              primary_package_purpose=primary_package_purpose,
                              release_date=release_date, built_date=built_date, valid_until_date=valid_until_date)

        except ConstructorTypeErrors as err:
            raise SPDXParsingError([f"Error while constructing Package {name}: {err.get_messages()}"])

        return package

    def parse_external_refs(self, external_ref_dicts: List[Dict]) -> List[ExternalPackageRef]:
        external_refs = []
        for external_ref_dict in external_ref_dicts:
            try:
                external_ref: ExternalPackageRef = self.parse_external_ref(external_ref_dict)
                external_refs.append(external_ref)
            except SPDXParsingError as err:
                self.logger.append_all(err.get_messages())
        return external_refs

    def parse_external_ref(self, external_ref_dict: Dict) -> ExternalPackageRef:
        logger = Logger()
        try:
            ref_category = self.parse_external_ref_category(external_ref_dict.get("referenceCategory"))
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            ref_category = None
        ref_locator = external_ref_dict.get("referenceLocator")
        ref_type = external_ref_dict.get("referenceType")
        comment = external_ref_dict.get("comment")
        if logger.has_messages():
            raise SPDXParsingError([f"Error while parsing external ref: {logger.get_messages()}"])
        try:
            external_ref = ExternalPackageRef(category=ref_category, reference_type=ref_type, locator=ref_locator,
                                              comment=comment)
        except ConstructorTypeErrors as err:
            raise SPDXParsingError([f"Error while constructing external ref: {err.get_messages()}"])

        return external_ref

    @staticmethod
    def parse_external_ref_category(external_ref_category_str: str) -> ExternalPackageRefCategory:
        try:
            external_ref_category = ExternalPackageRefCategory[
                transform_json_str_to_enum_name(external_ref_category_str)]
        except KeyError:
            raise SPDXParsingError([f"Category {external_ref_category_str} not valid for externalPackageRef."])

        return external_ref_category

random
# Copyright (c) 2022 spdx contributors
# 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.
from datetime import datetime
from typing import Dict, List, Optional, Union

from src.model.actor import Actor
from src.model.checksum import Checksum
from src.model.license_expression import LicenseExpression
from src.model.package import Package, ExternalPackageRef, PackageVerificationCode, PackagePurpose, \
    ExternalPackageRefCategory
from src.model.spdx_no_assertion import SpdxNoAssertion
from src.model.spdx_none import SpdxNone
from src.model.typing.constructor_type_errors import ConstructorTypeErrors
from src.parser.error import SPDXParsingError
from src.parser.json.actor_parser import ActorParser
from src.parser.json.checksum_parser import ChecksumParser
from src.parser.json.dict_parsing_functions import datetime_from_str, parse_optional_field, \
    transform_json_str_to_enum_name
from src.parser.json.license_expression_parser import LicenseExpressionParser
from src.parser.logger import Logger


class PackageParser:
    logger: Logger
    actor_parser: ActorParser
    checksum_parser: ChecksumParser
    license_expression_parser: LicenseExpressionParser

    def __init__(self):
        self.actor_parser = ActorParser()
        self.checksum_parser = ChecksumParser()
        self.license_expression_parser = LicenseExpressionParser()
        self.logger = Logger()

    def parse_packages(self, packages_dict_list: List[Dict]) -> List[Package]:
        packages_list = []
        for package_dict in packages_dict_list:
            try:
                package: Package = self.parse_package(package_dict)
                packages_list.append(package)
            except SPDXParsingError as err:
                self.logger.append_all(err.get_messages())
                continue
        if self.logger.has_messages():
            raise SPDXParsingError(self.logger.get_messages())

        return packages_list

    def parse_package(self, package_dict: Dict) -> Package:
        logger = Logger()
        name: str = package_dict.get("name")
        spdx_id: str = package_dict.get("SPDXID")
        attribution_texts: List[str] = package_dict.get("attributionTexts")
        try:
            built_date: Optional[datetime] = parse_optional_field(package_dict.get("builtDate"), datetime_from_str)
        except ValueError:
            logger.append("ValueError while parsing builtDate.")
            built_date = None
        try:
            checksums: List[Checksum] = parse_optional_field(package_dict.get("checksums"),
                                                             self.checksum_parser.parse_checksums, default=[])
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            checksums = []
        comment: Optional[str] = package_dict.get("comment")
        copyright_text: Optional[str] = package_dict.get("copyrightText")
        description: Optional[str] = package_dict.get("description")
        download_location: Union[str, SpdxNoAssertion, SpdxNone] = self.parse_download_location(
            package_dict.get("downloadLocation"))
        try:
            external_refs: List[ExternalPackageRef] = parse_optional_field(package_dict.get("externalRefs"),
                                                                           self.parse_external_refs)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            external_refs = []
        files_analyzed: Optional[bool] = parse_optional_field(package_dict.get("filesAnalyzed"), default=True)
        homepage: Optional[str] = package_dict.get("homepage")
        license_comments: Optional[str] = package_dict.get("licenseComments")
        try:
            license_concluded: Optional[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]] = parse_optional_field(
                package_dict.get("licenseConcluded"),
                self.license_expression_parser.parse_license_expression)
        except ConstructorTypeErrors as err:
            logger.append_all(err.get_messages())
            license_concluded = None
        try:
            license_declared: Optional[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]] = parse_optional_field(
                package_dict.get("licenseDeclared"),
                self.license_expression_parser.parse_license_expression)
        except ConstructorTypeErrors as err:
            logger.append_all(err.get_messages())
            license_declared = None
        try:
            license_info_from_file: Optional[
                Union[List[LicenseExpression], SpdxNoAssertion, SpdxNone]] = parse_optional_field(
                package_dict.get("licenseInfoFromFiles"),
                self.license_expression_parser.parse_license_expression)
        except ConstructorTypeErrors as err:
            logger.append_all(err.get_messages())
            license_info_from_file = None
        try:
            originator: Optional[Union[Actor, SpdxNoAssertion]] = parse_optional_field(package_dict.get("originator"),
                                                                                       self.actor_parser.parse_actor_or_no_assert)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            originator = None
        package_file_name: Optional[str] = package_dict.get("packageFileName")
        try:
            package_verification_code: Optional[PackageVerificationCode] = parse_optional_field(
                package_dict.get("packageVerificationCode"), self.parse_package_verification_code)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            package_verification_code = None

        try:
            primary_package_purpose: Optional[PackagePurpose] = parse_optional_field(
                package_dict.get("primaryPackagePurpose"), self.parse_primary_package_purpose)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            primary_package_purpose = None

        try:
            release_date: Optional[datetime] = parse_optional_field(package_dict.get("releaseDate"), datetime_from_str)
        except ValueError:
            logger.append("ValueError while parsing releaseDate.")
            release_date = None
        source_info: Optional[str] = package_dict.get("sourceInfo")
        summary: Optional[str] = package_dict.get("summary")
        try:
            supplier: Optional[Union[Actor, SpdxNoAssertion]] = parse_optional_field(package_dict.get("supplier"),
                                                                                     self.actor_parser.parse_actor_or_no_assert)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            supplier = None
        try:
            valid_until_date: Optional[datetime] = parse_optional_field(package_dict.get("validUntilDate"),
                                                                        datetime_from_str)
        except ValueError:
            logger.append("ValueError while parsing validUntilDate.")
            valid_until_date = None

        version_info: Optional[str] = package_dict.get("versionInfo")
        if logger.has_messages():
            raise SPDXParsingError([f"Error while parsing Package {name}: {logger.get_messages()}"])

        try:
            package = Package(spdx_id=spdx_id, name=name, download_location=download_location, version=version_info,
                              file_name=package_file_name, supplier=supplier, originator=originator,
                              files_analyzed=files_analyzed,
                              verification_code=package_verification_code, checksums=checksums, homepage=homepage,
                              source_info=source_info,
                              license_concluded=license_concluded, license_info_from_files=license_info_from_file,
                              license_declared=license_declared,
random
# Copyright (c) 2022 spdx contributors
# 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.
from datetime import datetime
from typing import Dict, List, Optional, Union

from src.model.actor import Actor
from src.model.checksum import Checksum
from src.model.license_expression import LicenseExpression
from src.model.package import Package, ExternalPackageRef, PackageVerificationCode, PackagePurpose, \
    ExternalPackageRefCategory
from src.model.spdx_no_assertion import SpdxNoAssertion
from src.model.spdx_none import SpdxNone
from src.model.typing.constructor_type_errors import ConstructorTypeErrors
from src.parser.error import SPDXParsingError
from src.parser.json.actor_parser import ActorParser
from src.parser.json.checksum_parser import ChecksumParser
from src.parser.json.dict_parsing_functions import datetime_from_str, parse_optional_field, \
    transform_json_str_to_enum_name
from src.parser.json.license_expression_parser import LicenseExpressionParser
from src.parser.logger import Logger


class PackageParser:
    logger: Logger
    actor_parser: ActorParser
    checksum_parser: ChecksumParser
    license_expression_parser: LicenseExpressionParser

    def __init__(self):
        self.actor_parser = ActorParser()
        self.checksum_parser = ChecksumParser()
        self.license_expression_parser = LicenseExpressionParser()
        self.logger = Logger()

    def parse_packages(self, packages_dict_list: List[Dict]) -> List[Package]:
        packages_list = []
        for package_dict in packages_dict_list:
            try:
                package: Package = self.parse_package(package_dict)
                packages_list.append(package)
            except SPDXParsingError as err:
                self.logger.append_all(err.get_messages())
                continue
        if self.logger.has_messages():
            raise SPDXParsingError(self.logger.get_messages())

        return packages_list

    def parse_package(self, package_dict: Dict) -> Package:
        logger = Logger()
        name: str = package_dict.get("name")
        spdx_id: str = package_dict.get("SPDXID")
        attribution_texts: List[str] = package_dict.get("attributionTexts")
        try:
            built_date: Optional[datetime] = parse_optional_field(package_dict.get("builtDate"), datetime_from_str)
        except ValueError:
            logger.append("ValueError while parsing builtDate.")
            built_date = None
        try:
            checksums: List[Checksum] = parse_optional_field(package_dict.get("checksums"),
                                                             self.checksum_parser.parse_checksums, default=[])
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            checksums = []
        comment: Optional[str] = package_dict.get("comment")
        copyright_text: Optional[str] = package_dict.get("copyrightText")
        description: Optional[str] = package_dict.get("description")
        download_location: Union[str, SpdxNoAssertion, SpdxNone] = self.parse_download_location(
            package_dict.get("downloadLocation"))
        try:
            external_refs: List[ExternalPackageRef] = parse_optional_field(package_dict.get("externalRefs"),
                                                                           self.parse_external_refs)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
random
# Copyright (c) 2022 spdx contributors
# 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.
from datetime import datetime
from typing import Dict, List, Optional, Union

from src.model.actor import Actor
from src.model.checksum import Checksum
from src.model.license_expression import LicenseExpression
from src.model.package import Package, ExternalPackageRef, PackageVerificationCode, PackagePurpose, \
    ExternalPackageRefCategory
from src.model.spdx_no_assertion import SpdxNoAssertion
from src.model.spdx_none import SpdxNone
from src.model.typing.constructor_type_errors import ConstructorTypeErrors
from src.parser.error import SPDXParsingError
from src.parser.json.actor_parser import ActorParser
from src.parser.json.checksum_parser import ChecksumParser
from src.parser.json.dict_parsing_functions import datetime_from_str, parse_optional_field, \
    transform_json_str_to_enum_name
from src.parser.json.license_expression_parser import LicenseExpressionParser
from src.parser.logger import Logger


class PackageParser:
    logger: Logger
    actor_parser: ActorParser
    checksum_parser: ChecksumParser
    license_expression_parser: LicenseExpressionParser

    def __init__(self):
        self.actor_parser = ActorParser()
        self.checksum_parser = ChecksumParser()
        self.license_expression_parser = LicenseExpressionParser()
        self.logger = Logger()

    def parse_packages(self, packages_dict_list: List[Dict]) -> List[Package]:
        packages_list = []
        for package_dict in packages_dict_list:
            try:
                package: Package = self.parse_package(package_dict)
                packages_list.append(package)
            except SPDXParsingError as err:
                self.logger.append_all(err.get_messages())
                continue
        if self.logger.has_messages():
            raise SPDXParsingError(self.logger.get_messages())

        return packages_list

    def parse_package(self, package_dict: Dict) -> Package:
        logger = Logger()
        name: str = package_dict.get("name")
        spdx_id: str = package_dict.get("SPDXID")
        attribution_texts: List[str] = package_dict.get("attributionTexts")
        try:
            built_date: Optional[datetime] = parse_optional_field(package_dict.get("builtDate"), datetime_from_str)
        except ValueError:
            logger.append("ValueError while parsing builtDate.")
            built_date = None
        try:
            checksums: List[Checksum] = parse_optional_field(package_dict.get("checksums"),
                                                             self.checksum_parser.parse_checksums, default=[])
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            checksums = []
        comment: Optional[str] = package_dict.get("comment")
        copyright_text: Optional[str] = package_dict.get("copyrightText")
        description: Optional[str] = package_dict.get("description")
        download_location: Union[str, SpdxNoAssertion, SpdxNone] = self.parse_download_location(
            package_dict.get("downloadLocation"))
        try:
            external_refs: List[ExternalPackageRef] = parse_optional_field(package_dict.get("externalRefs"),
                                                                           self.parse_external_refs)
        except SPDXParsingError as err:
            logger.append_all(err.get_messages())
            external_refs = []
        files_analyzed: Optional[bool] = parse_optional_field(package_dict.get("filesAnalyzed"), default=True)
        homepage: Optional[str] = package_dict.get("homepage")
        license_comments: Optional[str] = package_dict.get("licenseComments")
        try:
            license_concluded: Optional[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]] = parse_optional_field(
                package_dict.get("licenseConcluded"),
                self.license_expression_parser.parse_license_expression)
        except ConstructorTypeErrors as err:
            logger.append_all(err.get_messages())
            license_concluded = None
        try:
            license_declared: Optional[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]] = parse_optional_field(
                package_dict.get("licenseDeclared"),
                self.license_expression_parser.parse_license_expression)
        except ConstructorTypeErrors as err:
            logger.append_all(err.get_messages())
random
            ref_category = self.parse_external_ref_category(external_ref_dict.get("referenceCategory"))                 package_dict.get("primaryPackagePurpose"), self.parse_primary_package_purpose)                 package_dict.get("packageVerificationCode"), self.parse_package_verification_code)                                                                            self.parse_external_refs)             supplier: Optional[Union[Actor, SpdxNoAssertion]] = parse_optional_field(package_dict.get("supplier"),     ExternalPackageRefCategory             package = Package(spdx_id=spdx_id, name=name, download_location=download_location, version=version_info,         except ConstructorTypeErrors as err:                 package: Package = self.parse_package(package_dict)                 external_ref: ExternalPackageRef = self.parse_external_ref(external_ref_dict)             checksums: List[Checksum] = parse_optional_field(package_dict.get("checksums"),             external_ref = ExternalPackageRef(category=ref_category, reference_type=ref_type, locator=ref_locator,         download_location: Union[str, SpdxNoAssertion, SpdxNone] = self.parse_download_location(             external_ref_category = ExternalPackageRefCategory[             external_refs: List[ExternalPackageRef] = parse_optional_field(package_dict.get("externalRefs"),             license_concluded: Optional[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]] = parse_optional_field(             package_verification_code = PackageVerificationCode(value=verification_code_value,             license_declared: Optional[Union[LicenseExpression, SpdxNoAssertion, SpdxNone]] = parse_optional_field(             return PackagePurpose[transform_json_str_to_enum_name(primary_package_purpose)]                 Union[List[LicenseExpression], SpdxNoAssertion, SpdxNone]] = parse_optional_field(         if download_location == SpdxNone().__str__():             return SpdxNone()         if download_location == SpdxNoAssertion().__str__():             originator: Optional[Union[Actor, SpdxNoAssertion]] = parse_optional_field(package_dict.get("originator"),             return SpdxNoAssertion()             package_verification_code: Optional[PackageVerificationCode] = parse_optional_field(             primary_package_purpose: Optional[PackagePurpose] = parse_optional_field(             release_date: Optional[datetime] = parse_optional_field(package_dict.get("releaseDate"), datetime_from_str)         source_info: Optional[str] = package_dict.get("sourceInfo")         summary: Optional[str] = package_dict.get("summary")             valid_until_date: Optional[datetime] = parse_optional_field(package_dict.get("validUntilDate"),         version_info: Optional[str] = package_dict.get("versionInfo")         name: str = package_dict.get("name")         spdx_id: str = package_dict.get("SPDXID")         attribution_texts: List[str] = package_dict.get("attributionTexts")         ref_locator = external_ref_dict.get("referenceLocator")         ref_type = external_ref_dict.get("referenceType")             built_date: Optional[datetime] = parse_optional_field(package_dict.get("builtDate"), datetime_from_str)         comment = external_ref_dict.get("comment")         comment: Optional[str] = package_dict.get("comment")         copyright_text: Optional[str] = package_dict.get("copyrightText")         description: Optional[str] = package_dict.get("description")             package_dict.get("downloadLocation"))         files_analyzed: Optional[bool] = parse_optional_field(package_dict.get("filesAnalyzed"), default=True)         homepage: Optional[str] = package_dict.get("homepage")         license_comments: Optional[str] = package_dict.get("licenseComments")         excluded_files: List[str] = verification_code_dict.get("packageVerificationCodeExcludedFiles")         verification_code_value: str = verification_code_dict.get("packageVerificationCodeValue")                 package_dict.get("licenseConcluded"),                 package_dict.get("licenseDeclared"),                 package_dict.get("licenseInfoFromFiles"),         package_file_name: Optional[str] = package_dict.get("packageFileName") from src.model.spdx_none import SpdxNone from src.model.typing.constructor_type_errors import ConstructorTypeErrors # See the License for the specific language governing permissions and                               description=description,     @staticmethod                               license_comment=license_comments, copyright_text=copyright_text, summary=summary,             external_refs = []             license_declared = None