def setUp(self):
    # create importer object
    self.importer = TVImporter()

    # create and initialize an in-memory database
    self.db = ProjectDB()
    self.db.createDB(":memory:")
    self.db.initializeDBTables()

    # insert sample data
    self.insertSampleCategoryData()
    self.insertSampleLicenseData()
    self.insertSampleConversionData()
    self.insertSampleSubprojectData()
    self.insertSampleScanData()

    # build sample file data list
    self.fd1 = createFD("/tmp/f1", "DoAnything", md5="abcdef")
    self.fd2 = createFD("/tmp/f2", "DoAnythingNoncommercial", sha256="abcdef")
    self.fd3 = createFD("/tmp/f3", "HarshEULA", sha1="abcdef")
    self.fd4 = createFD("/tmp/f4", "HarshEULA")
    self.fdList = [self.fd1, self.fd2, self.fd3, self.fd4]
    # not in fdList by default
    self.fd5 = createFD("/tmp/badLicense", "UnknownLicense")
    self.fd6 = createFD("/tmp/badLic2", "SecondUnknownLic")
    self.fdConvert = createFD("/tmp/needsConvert", "293")
    def setUp(self):
        # create and initialize an in-memory database
        self.db = ProjectDB()
        self.db.createDB(":memory:")
        self.db.initializeDBTables()

        # create reporter
        self.reporter = JSONReporter(db=self.db)
示例#3
0
    def setUp(self):
        # create and initialize an in-memory database
        self.db = ProjectDB()
        self.db.createDB(":memory:")
        self.db.initializeDBTables()

        # insert sample data
        self.insertSampleConfigData()
示例#4
0
    def setUp(self):
        # create and initialize an in-memory database
        self.db = ProjectDB()
        self.db.createDB(":memory:")
        self.db.initializeDBTables()

        # insert sample data
        self.insertSampleCategoryData()
        self.insertSampleLicenseData()
        self.insertSampleSubprojectData()
        self.insertSampleScanData()
        self.insertSampleFileData()
 def test_can_create_new_database(self):
     # don't use db from setUp(); create new in-memory DB from scratch
     dbnew = ProjectDB()
     dbnew.createDB(":memory:")
     self.assertTrue(dbnew.isOpened())
     self.assertFalse(dbnew.isInitialized())
     dbnew.closeDB()
 def test_that_closed_db_reports_as_uninitialized(self):
     # don't use db from setUp(); create new in-memory DB from scratch
     dbnew = ProjectDB()
     dbnew.createDB(":memory:")
     # and then close it
     dbnew.closeDB()
     self.assertFalse(dbnew.isInitialized())
     self.assertIsNone(dbnew.session)
     self.assertIsNone(dbnew.engine)
示例#7
0
    def setUp(self):
        # fake SLM config
        mainconfig_json = """{
      "projects": [
        { "name": "frotz", "desc": "The FROTZ Project" },
        { "name": "rezrov", "desc": "The REZROV Project" },
        { "name": "gnusto", "desc": "The GNUSTO Project" }
      ]
    }"""
        self.mainconfig = SLMConfig()
        self.mainconfig.loadConfig(mainconfig_json)

        # SLM manager for testing
        self.manager = SLMManager(config=self.mainconfig,
                                  root="/tmp/fake/whatever")

        # fake DBs for projects
        self.frotz_db = ProjectDB()
        self.frotz_db.createDB(":memory:")
        self.frotz_db.initializeDBTables()

        self.rezrov_db = ProjectDB()
        self.rezrov_db.createDB(":memory:")
        self.rezrov_db.initializeDBTables()

        self.gnusto_db = ProjectDB()
        self.gnusto_db.createDB(":memory:")
        self.gnusto_db.initializeDBTables()

        # insert sample data
        self.insertSampleSubprojectData()
        self.insertSampleScans()
    def test_cannot_open_some_random_file_as_db(self):
        # create in temporary directory on disk, so we can re-open it
        # (testfixtures will wipe out the directory at end of test)
        with TempDirectory() as td:
            fakeDBPath = os.path.join(td.path, "tmp.txt")
            with open(fakeDBPath, "w") as f:
                f.write("some random text")

            dbnew = ProjectDB()
            with self.assertRaises(ProjectDBConfigError):
                dbnew.openDB(fakeDBPath)
            self.assertFalse(dbnew.isOpened())
            self.assertFalse(dbnew.isInitialized())
 def setUp(self):
     # create and initialize an in-memory database
     self.db = ProjectDB()
     self.db.createDB(":memory:")
     self.db.initializeDBTables()
示例#10
0
class DBScanUnitTestSuite(unittest.TestCase):
    """spdxLicenseManager unit test suite for scan metadata in DB."""
    def setUp(self):
        # create and initialize an in-memory database
        self.db = ProjectDB()
        self.db.createDB(":memory:")
        self.db.initializeDBTables()

        # insert sample data
        self.insertSampleSubprojectData()
        self.insertSampleScanData()

    def tearDown(self):
        self.db.closeDB()
        self.db = None

    def insertSampleSubprojectData(self):
        subprojects = [
            Subproject(_id=1, name="sub1", desc="subproject 1"),
            Subproject(_id=2, name="subX", desc="subproject XYZ"),
            Subproject(_id=3, name="subC", desc="subproject B"),
        ]
        self.db.session.bulk_save_objects(subprojects)
        self.db.session.commit()

    def insertSampleScanData(self):
        scans = [
            Scan(_id=1,
                 subproject_id=2,
                 scan_dt=datetime.date(2017, 1, 10),
                 desc="XYZ initial scan"),
            Scan(_id=2,
                 subproject_id=1,
                 scan_dt=datetime.date(2017, 1, 3),
                 desc="1 initial scan"),
            Scan(_id=3,
                 subproject_id=2,
                 scan_dt=datetime.date(2017, 2, 10),
                 desc="XYZ 2017-02 monthly scan"),
            Scan(_id=4,
                 subproject_id=2,
                 scan_dt=datetime.date(2017, 2, 17),
                 desc="XYZ 2017-02 rescan"),
        ]
        self.db.session.bulk_save_objects(scans)
        self.db.session.commit()

    ##### Test cases below

    def test_can_retrieve_all_scans(self):
        scans = self.db.getScansAll()
        self.assertIsInstance(scans, list)
        self.assertEqual(len(scans), 4)
        # will sort by ID
        self.assertEqual(scans[0]._id, 1)
        self.assertEqual(scans[0].subproject.name, "subX")
        self.assertEqual(scans[1]._id, 2)
        self.assertEqual(scans[1].subproject.name, "sub1")
        self.assertEqual(scans[2]._id, 3)
        self.assertEqual(scans[2].subproject.name, "subX")
        self.assertEqual(scans[3]._id, 4)
        self.assertEqual(scans[3].subproject.name, "subX")

    def test_can_retrieve_scans_in_just_one_subproject(self):
        scans = self.db.getScansFiltered(subproject="subX")
        self.assertIsInstance(scans, list)
        self.assertEqual(len(scans), 3)
        # will sort by scan ID
        self.assertEqual(scans[0]._id, 1)
        self.assertEqual(scans[0].desc, "XYZ initial scan")
        self.assertEqual(scans[1]._id, 3)
        self.assertEqual(scans[1].desc, "XYZ 2017-02 monthly scan")
        self.assertEqual(scans[2]._id, 4)
        self.assertEqual(scans[2].desc, "XYZ 2017-02 rescan")

    def test_cannot_retrieve_scans_in_subproject_that_does_not_exist(self):
        with self.assertRaises(ProjectDBQueryError):
            self.db.getScansFiltered(subproject="invalid")

    def test_can_retrieve_scans_by_subproject_and_month(self):
        scans = self.db.getScansFiltered(subproject="subX",
                                         month_tuple=(2017, 2))
        self.assertIsInstance(scans, list)
        self.assertEqual(len(scans), 2)
        # will sort by scan ID
        self.assertEqual(scans[0]._id, 3)
        self.assertEqual(scans[0].desc, "XYZ 2017-02 monthly scan")
        self.assertEqual(scans[1]._id, 4)
        self.assertEqual(scans[1].desc, "XYZ 2017-02 rescan")

    def test_cannot_retrieve_scans_in_subproject_with_integer_month(self):
        with self.assertRaises(ProjectDBQueryError):
            self.db.getScansFiltered(subproject="subX", month_tuple=2)

    def test_cannot_retrieve_scans_in_subproject_with_invalid_month_tuple(
            self):
        with self.assertRaises(ProjectDBQueryError):
            self.db.getScansFiltered(subproject="subX",
                                     month_tuple=("hi", "there"))

    def test_retrieve_scan_with_unknown_month_returns_empty_list(self):
        scans = self.db.getScansFiltered(subproject="subX",
                                         month_tuple=(2017, 3))
        self.assertIsInstance(scans, list)
        self.assertEqual(scans, [])

    def test_can_retrieve_scans_by_month_without_subproject(self):
        scans = self.db.getScansFiltered(month_tuple=(2017, 1))
        self.assertIsInstance(scans, list)
        self.assertEqual(len(scans), 2)
        # will sort by scan ID
        self.assertEqual(scans[0]._id, 1)
        self.assertEqual(scans[0].desc, "XYZ initial scan")
        self.assertEqual(scans[1]._id, 2)
        self.assertEqual(scans[1].desc, "1 initial scan")

    def test_cannot_retrieve_filtered_scans_without_subproject_or_month(self):
        with self.assertRaises(ProjectDBQueryError):
            self.db.getScansFiltered()

    def test_cannot_retrieve_filtered_scans_with_positional_args(self):
        with self.assertRaises(TypeError):
            self.db.getScansFiltered("subX")
        with self.assertRaises(TypeError):
            self.db.getScansFiltered("subX", (2017, 1))
        with self.assertRaises(TypeError):
            self.db.getScansFiltered((2017, 1))

    def test_can_retrieve_one_scan_by_id(self):
        scan = self.db.getScan(_id=2)
        self.assertEqual(scan.desc, "1 initial scan")

    def test_returns_none_if_scan_not_found_by_id(self):
        scan = self.db.getScan(_id=17)
        self.assertIsNone(scan)

    def test_can_add_and_retrieve_scans(self):
        scan_id = self.db.addScan(subproject="subX",
                                  scan_dt_str="2017-03-05",
                                  desc="XYZ 2017-03 monthly scan")

        # confirm that we now have five scans
        scans = self.db.getScansAll()
        self.assertEqual(len(scans), 5)
        self.assertEqual(scan_id, 5)

        # and confirm that we can retrieve this one by id
        scan = self.db.getScan(_id=5)
        self.assertEqual(scan.desc, "XYZ 2017-03 monthly scan")
        self.assertEqual(scan.subproject.name, "subX")

    def test_can_start_adding_but_rollback_scan(self):
        scan_id = self.db.addScan(subproject="subX",
                                  scan_dt_str="2011-01-01",
                                  desc="will rollback",
                                  commit=False)
        self.db.rollback()
        # confirm that we still only have four scans
        scans = self.db.getScansAll()
        self.assertEqual(len(scans), 4)
        # and confirm that this scan ID doesn't exist in database
        scan = self.db.getScan(_id=scan_id)
        self.assertIsNone(scan)

    def test_can_start_adding_and_then_commit_scans(self):
        s1_id = self.db.addScan(subproject="subX",
                                scan_dt_str="2011-01-01",
                                desc="s1",
                                commit=False)
        s2_id = self.db.addScan(subproject="subX",
                                scan_dt_str="2012-02-02",
                                desc="s2",
                                commit=False)
        self.db.commit()
        # confirm that we now have six scans
        scans = self.db.getScansAll()
        self.assertEqual(len(scans), 6)

    def test_cannot_add_scan_without_subproject(self):
        with self.assertRaises(TypeError):
            self.db.addScan(scan_dt_str="2011-01-01", desc="oops")
        # confirm it wasn't added either
        scan = self.db.getScan(_id=5)
        self.assertIsNone(scan)

    def test_cannot_add_scan_without_scan_date_string(self):
        with self.assertRaises(TypeError):
            self.db.addScan(subproject="subX", desc="oops")
        # confirm it wasn't added either
        scan = self.db.getScan(_id=5)
        self.assertIsNone(scan)

    def test_can_add_scan_with_duplicate_desc(self):
        scan_id = self.db.addScan(subproject="sub1",
                                  scan_dt_str="2017-02-02",
                                  desc="1 initial scan")

        # confirm that we now have five scans and desc matches
        scans = self.db.getScansAll()
        self.assertEqual(len(scans), 5)
        self.assertEqual(scan_id, 5)
        scan = self.db.getScan(_id=5)
        self.assertEqual(scan.desc, "1 initial scan")

    def test_can_add_scan_with_duplicate_scan_date(self):
        scan_id = self.db.addScan(subproject="sub1",
                                  scan_dt_str="2017-01-03",
                                  desc="1 rescan")

        # confirm that we now have five scans and desc matches
        scans = self.db.getScansAll()
        self.assertEqual(len(scans), 5)
        self.assertEqual(scan_id, 5)
        scan = self.db.getScan(_id=5)
        self.assertEqual(scan.desc, "1 rescan")
示例#11
0
 def test_cannot_create_new_database_if_file_already_exists(
         self, os_exists):
     dbnew = ProjectDB()
     with self.assertRaises(ProjectDBConfigError):
         dbnew.createDB("/tmp/fake/existing.db")
示例#12
0
class DBFileUnitTestSuite(unittest.TestCase):
    """spdxLicenseManager unit test suite for scan metadata in DB."""
    def setUp(self):
        # create and initialize an in-memory database
        self.db = ProjectDB()
        self.db.createDB(":memory:")
        self.db.initializeDBTables()

        # insert sample data
        self.insertSampleCategoryData()
        self.insertSampleLicenseData()
        self.insertSampleSubprojectData()
        self.insertSampleScanData()
        self.insertSampleFileData()

    def tearDown(self):
        self.db.closeDB()
        self.db = None

    def insertSampleCategoryData(self):
        categories = [
            Category(_id=1, name="a category", order=3),
            Category(_id=2, name="cat", order=2),
            Category(_id=3, name="blah category", order=1),
        ]
        self.db.session.bulk_save_objects(categories)
        self.db.session.commit()

    def insertSampleLicenseData(self):
        licenses = [
            License(_id=1, name="DoAnything", category_id=1),
            License(_id=2, name="HarshEULA", category_id=2),
            License(_id=3, name="293PageEULA", category_id=3),
            License(_id=4, name="DoAnythingNoncommercial", category_id=1),
        ]
        self.db.session.bulk_save_objects(licenses)
        self.db.session.commit()

    def insertSampleSubprojectData(self):
        subprojects = [
            Subproject(_id=1, name="sub1", desc="subproject 1"),
            Subproject(_id=2, name="subX", desc="subproject XYZ"),
            Subproject(_id=3, name="subC", desc="subproject B"),
        ]
        self.db.session.bulk_save_objects(subprojects)
        self.db.session.commit()

    def insertSampleScanData(self):
        scans = [
            Scan(_id=1,
                 subproject_id=2,
                 scan_dt=datetime.date(2017, 1, 10),
                 desc="XYZ initial scan"),
            Scan(_id=2,
                 subproject_id=1,
                 scan_dt=datetime.date(2017, 1, 3),
                 desc="1 initial scan"),
            Scan(_id=3,
                 subproject_id=2,
                 scan_dt=datetime.date(2017, 2, 10),
                 desc="XYZ 2017-02 monthly scan"),
            Scan(_id=4,
                 subproject_id=2,
                 scan_dt=datetime.date(2017, 2, 17),
                 desc="XYZ 2017-02 rescan"),
        ]
        self.db.session.bulk_save_objects(scans)
        self.db.session.commit()

    def insertSampleFileData(self):
        files = [
            File(_id=1,
                 scan_id=1,
                 path="/fileC.c",
                 license_id=1,
                 sha1="aabbcc",
                 md5="ddeeff",
                 sha256="aaccee"),
            File(_id=2,
                 scan_id=1,
                 path="/fileA.c",
                 license_id=1,
                 sha1="112233",
                 md5="445566",
                 sha256="778899"),
            File(_id=3,
                 scan_id=1,
                 path="/fileB.c",
                 license_id=2,
                 sha1=None,
                 md5=None,
                 sha256=None),
            File(_id=4,
                 scan_id=1,
                 path="/dir/fileA.c",
                 license_id=4,
                 sha1="123456",
                 md5="789012",
                 sha256="345678"),
        ]
        self.db.session.bulk_save_objects(files)
        self.db.session.commit()

    ##### Test cases below

    def test_can_retrieve_files_in_one_scan(self):
        files = self.db.getFiles(scan_id=1)
        self.assertIsInstance(files, list)
        self.assertEqual(len(files), 4)
        # will sort by file path
        self.assertEqual(files[0]._id, 4)
        self.assertEqual(files[0].path, "/dir/fileA.c")
        self.assertEqual(files[1]._id, 2)
        self.assertEqual(files[1].path, "/fileA.c")
        self.assertEqual(files[2]._id, 3)
        self.assertEqual(files[2].path, "/fileB.c")
        self.assertEqual(files[3]._id, 1)
        self.assertEqual(files[3].path, "/fileC.c")

    def test_cannot_retrieve_files_in_scan_that_does_not_exist(self):
        with self.assertRaises(ProjectDBQueryError):
            self.db.getFiles(scan_id=17)

    def test_returns_empty_list_if_no_files_in_known_scan(self):
        files = self.db.getFiles(scan_id=4)
        self.assertEqual(files, [])

    def test_can_get_file_by_id(self):
        file = self.db.getFile(_id=3)
        self.assertEqual(file.path, "/fileB.c")
        self.assertEqual(file.license.name, "HarshEULA")

    def test_can_get_file_by_scan_and_path(self):
        file = self.db.getFile(scan_id=1, path="/fileB.c")
        self.assertEqual(file._id, 3)
        self.assertEqual(file.license.name, "HarshEULA")

    def test_cannot_get_file_by_id_with_scan_or_path(self):
        with self.assertRaises(ProjectDBQueryError):
            self.db.getFile(_id=3, scan_id=1)
        with self.assertRaises(ProjectDBQueryError):
            self.db.getFile(_id=3, path="/fileB.c")

    def test_cannot_get_file_with_no_id_or_scan_or_path(self):
        with self.assertRaises(ProjectDBQueryError):
            self.db.getFile()

    def test_cannot_get_file_with_only_one_of_scan_or_path(self):
        with self.assertRaises(ProjectDBQueryError):
            self.db.getFile(scan_id=1)
        with self.assertRaises(ProjectDBQueryError):
            self.db.getFile(path="/fileB.c")

    def test_returns_none_if_file_not_found_by_id(self):
        file = self.db.getFile(_id=17)
        self.assertIsNone(file)

    def test_returns_none_if_file_not_found_by_scan_plus_path(self):
        file = self.db.getFile(scan_id=1, path="/nope")
        self.assertIsNone(file)
        file = self.db.getFile(scan_id=6, path="/fileB.c")
        self.assertIsNone(file)

    def test_can_add_and_retrieve_files(self):
        self.db.addFile(scan_id=1,
                        path="/file17.py",
                        license_id=3,
                        sha1=None,
                        md5=None,
                        sha256=None)
        self.db.addFile(scan_id=1,
                        path="/file13.py",
                        license_id=2,
                        sha1=None,
                        md5=None,
                        sha256=None)
        file_id = self.db.addFile(scan_id=1,
                                  path="/dir5/file128.py",
                                  license_id=4,
                                  sha1="123456",
                                  md5="789012",
                                  sha256="345678")

        # confirm that we now have seven files in this scan
        files = self.db.getFiles(scan_id=1)
        self.assertEqual(len(files), 7)
        self.assertEqual(file_id, 7)

        # and confirm that we can retrieve this one by id
        file = self.db.getFile(_id=7)
        self.assertEqual(file.path, "/dir5/file128.py")
        self.assertEqual(file.license.name, "DoAnythingNoncommercial")

    def test_can_start_adding_but_rollback_file(self):
        file_id = self.db.addFile(scan_id=1,
                                  path="/will_rollback",
                                  license_id=3,
                                  sha1=None,
                                  md5=None,
                                  sha256=None,
                                  commit=False)
        self.db.rollback()
        # confirm that we still only have four files
        files = self.db.getFiles(scan_id=1)
        self.assertEqual(len(files), 4)
        # and confirm that this file ID doesn't exist in database
        file = self.db.getFile(_id=file_id)
        self.assertIsNone(file)

    def test_can_start_adding_and_then_commit_files(self):
        f1_id = self.db.addFile(scan_id=1,
                                path="/f1",
                                license_id=1,
                                sha1=None,
                                md5=None,
                                sha256=None,
                                commit=False)
        f2_id = self.db.addFile(scan_id=1,
                                path="/f2",
                                license_id=1,
                                sha1=None,
                                md5=None,
                                sha256=None,
                                commit=False)
        self.db.commit()
        # confirm that we now have six files
        files = self.db.getFiles(scan_id=1)
        self.assertEqual(len(files), 6)

    def test_can_bulk_add_and_retrieve_files(self):
        bulkfiles = [
            ("/file17.py", 3, None, None, None),
            ("/file13.py", 2, None, None, None),
            ("/dir5/file128.py", 4, "123456", "789012", "345678"),
        ]
        self.db.addBulkFiles(scan_id=1, file_tuples=bulkfiles)

        # confirm that we now have seven files in this scan
        files = self.db.getFiles(scan_id=1)
        self.assertEqual(len(files), 7)

        # and confirm that we can retrieve last one by id
        file = self.db.getFile(_id=7)
        self.assertEqual(file.path, "/dir5/file128.py")
        self.assertEqual(file.license.name, "DoAnythingNoncommercial")

    def test_can_start_bulk_adding_files_but_rollback(self):
        bulkfiles = [
            ("/file17.py", 3, None, None, None),
            ("/file13.py", 2, None, None, None),
            ("/dir5/file128.py", 4, "123456", "789012", "345678"),
        ]
        self.db.addBulkFiles(scan_id=1, file_tuples=bulkfiles, commit=False)
        self.db.rollback()
        # confirm that we still only have four files
        files = self.db.getFiles(scan_id=1)
        self.assertEqual(len(files), 4)
        # and confirm that this file ID doesn't exist in database
        file = self.db.getFile(_id=7)
        self.assertIsNone(file)

    def test_can_start_bulk_adding_and_then_commit_files(self):
        bulkfiles = [
            ("/file17.py", 3, None, None, None),
            ("/file13.py", 2, None, None, None),
            ("/dir5/file128.py", 4, "123456", "789012", "345678"),
        ]
        self.db.addBulkFiles(scan_id=1, file_tuples=bulkfiles, commit=False)
        self.db.commit()
        # confirm that we now have seven files
        files = self.db.getFiles(scan_id=1)
        self.assertEqual(len(files), 7)
示例#13
0
class DBLicenseUnitTestSuite(unittest.TestCase):
  """spdxLicenseManager unit test suite for license data in DB."""

  def setUp(self):
    # create and initialize an in-memory database
    self.db = ProjectDB()
    self.db.createDB(":memory:")
    self.db.initializeDBTables()

    # insert sample data
    self.insertSampleCategoryData()
    self.insertSampleLicenseData()

  def tearDown(self):
    self.db.closeDB()
    self.db = None

  def insertSampleCategoryData(self):
    categories = [
      Category(_id=1, name="a category", order=3),
      Category(_id=2, name="cat", order=2),
      Category(_id=3, name="blah category", order=1),
    ]
    self.db.session.bulk_save_objects(categories)
    self.db.session.commit()

  def insertSampleLicenseData(self):
    licenses = [
      License(_id=1, name="DoAnything", category_id=1),
      License(_id=2, name="HarshEULA", category_id=2),
      License(_id=3, name="293PageEULA", category_id=3),
      License(_id=4, name="DoAnythingNoncommercial", category_id=1),
    ]
    self.db.session.bulk_save_objects(licenses)
    self.db.session.commit()

  ##### Test cases below

  def test_can_retrieve_all_license_names(self):
    licenses = self.db.getLicensesAll()
    self.assertIsInstance(licenses, list)
    self.assertEqual(len(licenses), 4)
    # will sort alphabetically
    self.assertEqual(licenses[0]._id, 3)
    self.assertEqual(licenses[0].name, "293PageEULA")

  def test_can_retrieve_all_license_names_by_category(self):
    cat_lics = self.db.getLicensesAllByCategory()
    self.assertIsInstance(cat_lics, list)
    self.assertEqual(len(cat_lics), 4)
    # returns a flat list of tuples, of form [(cat name, lic name)]
    # categories should be ordered by cat order
    # and within each category, licenses should be ordered alphabetically
    self.assertEqual(cat_lics[0][0], "blah category")
    self.assertEqual(cat_lics[0][1], "293PageEULA")
    self.assertEqual(cat_lics[1][0], "cat")
    self.assertEqual(cat_lics[1][1], "HarshEULA")
    self.assertEqual(cat_lics[2][0], "a category")
    self.assertEqual(cat_lics[2][1], "DoAnything")
    self.assertEqual(cat_lics[3][0], "a category")
    self.assertEqual(cat_lics[3][1], "DoAnythingNoncommercial")

  def test_can_retrieve_licenses_in_just_one_category(self):
    licenses = self.db.getLicensesInCategory(category="a category")
    self.assertIsInstance(licenses, list)
    self.assertEqual(len(licenses), 2)
    # will sort alphabetically
    self.assertEqual(licenses[0]._id, 1)
    self.assertEqual(licenses[0].name, "DoAnything")
    self.assertEqual(licenses[1]._id, 4)
    self.assertEqual(licenses[1].name, "DoAnythingNoncommercial")

  def test_cannot_retrieve_license_in_category_that_does_not_exist(self):
    with self.assertRaises(ProjectDBQueryError):
      self.db.getLicensesInCategory(category="invalid")

  def test_can_retrieve_one_license_by_id(self):
    license = self.db.getLicense(_id=2)
    self.assertEqual(license.name, "HarshEULA")

  def test_can_retrieve_one_license_by_name(self):
    license = self.db.getLicense(name="DoAnything")
    self.assertEqual(license._id, 1)

  def test_cannot_retrieve_license_by_both_name_and_id(self):
    with self.assertRaises(ProjectDBQueryError):
      self.db.getLicense(_id=3, name="293PageEULA")

  def test_cannot_retrieve_license_without_either_name_or_id(self):
    with self.assertRaises(ProjectDBQueryError):
      self.db.getLicense()

  def test_cannot_retrieve_license_with_positional_args(self):
    with self.assertRaises(TypeError):
      self.db.getLicense("DoAnything")

  def test_returns_none_if_license_not_found_by_id(self):
    license = self.db.getLicense(_id=17)
    self.assertIsNone(license)

  def test_returns_none_if_license_not_found_by_name(self):
    license = self.db.getLicense(name="noSuchLicense")
    self.assertIsNone(license)

  def test_can_retrieve_multiple_licenses_by_name(self):
    licenses = [
      "293PageEULA",
      "DoAnything",
      "UnknownLicense",
    ]
    ldict = self.db.getMultipleLicenses(licenses)
    self.assertEqual(ldict["293PageEULA"], 3)
    self.assertEqual(ldict["DoAnything"], 1)
    self.assertIsNone(ldict["UnknownLicense"])

  def test_can_add_and_retrieve_licenses(self):
    license_id = self.db.addLicense(name="SomeOtherEULA",
      category="blah category")

    # confirm that we now have five licenses
    licenses = self.db.getLicensesAll()
    self.assertEqual(len(licenses), 5)

    # and confirm that we can retrieve this one by name
    license = self.db.getLicense(name="SomeOtherEULA")
    self.assertEqual(license._id, 5)
    self.assertEqual(license.category_id, 3)
    self.assertIsNotNone(license.category)
    self.assertEqual(license.category.name, "blah category")

    # and confirm that we can retrieve this one by id
    license = self.db.getLicense(_id=5)
    self.assertEqual(license.name, "SomeOtherEULA")
    self.assertEqual(license.category_id, 3)

  def test_can_start_adding_but_rollback_license(self):
    license_id = self.db.addLicense(name="will rollback",
      category="blah category", commit=False)
    self.db.rollback()
    # confirm that we still only have four licenses
    licenses = self.db.getLicensesAll()
    self.assertEqual(len(licenses), 4)
    # and confirm that this license ID doesn't exist in database
    license = self.db.getLicense(_id=license_id)
    self.assertIsNone(license)

  def test_can_start_adding_and_then_commit_licenses(self):
    l1_id = self.db.addLicense(name="newl1", category="cat", commit=False)
    l2_id = self.db.addLicense(name="newl2", category="cat", commit=False)
    self.db.commit()
    # confirm that we now have six licenses
    licenses = self.db.getLicensesAll()
    self.assertEqual(len(licenses), 6)

  def test_cannot_add_license_without_category(self):
    with self.assertRaises(TypeError):
      self.db.addLicense(name="oops")
    # confirm it wasn't added either
    license = self.db.getLicense(name="oops")
    self.assertIsNone(license)

  def test_cannot_add_license_without_existing_category(self):
    with self.assertRaises(ProjectDBInsertError):
      self.db.addLicense(name="oops", category="noSuchCategory")
    # confirm it wasn't added either
    license = self.db.getLicense(name="oops")
    self.assertIsNone(license)

  def test_cannot_add_license_with_duplicate_name(self):
    with self.assertRaises(ProjectDBInsertError):
      self.db.addLicense(name="DoAnything", category="cat")

  def test_can_edit_license_name(self):
    self.db.changeLicenseName(name="293PageEULA", newName="432PageEULA")
    license = self.db.getLicense(name="432PageEULA")
    self.assertEqual(license._id, 3)

  def test_cannot_edit_license_name_that_does_not_exist(self):
    with self.assertRaises(ProjectDBUpdateError):
      self.db.changeLicenseName(name="invalid", newName="this will fail")

  def test_cannot_change_license_name_to_existing_name(self):
    with self.assertRaises(ProjectDBUpdateError):
      self.db.changeLicenseName(name="293PageEULA", newName="DoAnything")

  def test_can_edit_license_category(self):
    self.db.changeLicenseCategory(name="293PageEULA", newCat="a category")
    license = self.db.getLicense(name="293PageEULA")
    self.assertEqual(license.category.name, "a category")

  def test_cannot_change_license_to_category_that_does_not_exist(self):
    with self.assertRaises(ProjectDBUpdateError):
      self.db.changeLicenseCategory(name="293PageEULA", newCat="invalid")

  def test_can_get_max_license_id(self):
    lic_id = self.db.getLicenseMaxID()
    self.assertEqual(4, lic_id)
示例#14
0
class SLMManagerTestSuite(unittest.TestCase):
    """spdxLicenseManager SLM manager unit test suite."""
    def setUp(self):
        # fake SLM config
        mainconfig_json = """{
      "projects": [
        { "name": "frotz", "desc": "The FROTZ Project" },
        { "name": "rezrov", "desc": "The REZROV Project" },
        { "name": "gnusto", "desc": "The GNUSTO Project" }
      ]
    }"""
        self.mainconfig = SLMConfig()
        self.mainconfig.loadConfig(mainconfig_json)

        # SLM manager for testing
        self.manager = SLMManager(config=self.mainconfig,
                                  root="/tmp/fake/whatever")

        # fake DBs for projects
        self.frotz_db = ProjectDB()
        self.frotz_db.createDB(":memory:")
        self.frotz_db.initializeDBTables()

        self.rezrov_db = ProjectDB()
        self.rezrov_db.createDB(":memory:")
        self.rezrov_db.initializeDBTables()

        self.gnusto_db = ProjectDB()
        self.gnusto_db.createDB(":memory:")
        self.gnusto_db.initializeDBTables()

        # insert sample data
        self.insertSampleSubprojectData()
        self.insertSampleScans()

    def tearDown(self):
        pass

    def insertSampleSubprojectData(self):
        # for frotz
        frotz_subprojects = [
            Subproject(_id=1,
                       name="f1",
                       spdx_search="f1",
                       desc="subproject f1"),
            Subproject(_id=2,
                       name="f2",
                       spdx_search="fX2",
                       desc="subproject fX2"),
            Subproject(_id=3, name="f3", spdx_search="f3", desc="f3"),
        ]
        self.frotz_db.session.bulk_save_objects(frotz_subprojects)
        self.frotz_db.session.commit()

        # for gnusto
        # note that IDs restart b/c projects keep separate databases
        gnusto_subprojects = [
            Subproject(_id=1,
                       name="g1",
                       spdx_search="g1",
                       desc="subproject g1"),
            Subproject(_id=2, name="g2", spdx_search="gAX2", desc="gAX2"),
        ]
        self.gnusto_db.session.bulk_save_objects(gnusto_subprojects)
        self.gnusto_db.session.commit()

        # none for rezrov

    def insertSampleScans(self):
        # for frotz
        frotz_scans = [
            Scan(_id=1,
                 subproject_id=2,
                 scan_dt=datetime.date(2017, 1, 10),
                 desc="fX2 initial scan"),
            Scan(_id=2,
                 subproject_id=1,
                 scan_dt=datetime.date(2017, 2, 3),
                 desc="f1 initial scan"),
            Scan(_id=3,
                 subproject_id=2,
                 scan_dt=datetime.date(2017, 2, 10),
                 desc="fX2 2017-02 monthly scan"),
            Scan(_id=4,
                 subproject_id=2,
                 scan_dt=datetime.date(2017, 2, 17),
                 desc="fX2 2017-02 rescan"),
            # none for subproject 3
        ]
        self.frotz_db.session.bulk_save_objects(frotz_scans)
        self.frotz_db.session.commit()

        # for gnusto
        # note that IDs restart b/c projects keep separate databases
        gnusto_scans = [
            # none for subproject 1
            Scan(_id=1,
                 subproject_id=2,
                 scan_dt=datetime.date(2017, 1, 10),
                 desc="gAX2 initial scan"),
            Scan(_id=2,
                 subproject_id=2,
                 scan_dt=datetime.date(2017, 2, 3),
                 desc="gAX2 2017-02 monthly scan"),
        ]
        self.gnusto_db.session.bulk_save_objects(gnusto_scans)
        self.gnusto_db.session.commit()

        # none for rezrov

    ##### Test cases below

    def test_can_get_list_of_all_projects(self):
        projects = self.manager.getProjects()
        self.assertIsInstance(projects, list)
        self.assertEqual(len(projects), 3)
        self.assertIn("frotz", projects)
        self.assertIn("gnusto", projects)
        self.assertIn("rezrov", projects)

    def test_can_get_project_directory_path(self):
        frotz_dir = self.manager.getProjectDir("frotz")
        self.assertEqual(frotz_dir, "/tmp/fake/whatever/projects/frotz")

    def test_can_get_project_database_path(self):
        frotz_db_path = self.manager.getProjectDBPath("frotz")
        self.assertEqual(frotz_db_path,
                         "/tmp/fake/whatever/projects/frotz/frotz.db")

    def test_can_get_project_reports_directory_path(self):
        frotz_reports_dir = self.manager.getProjectReportsDir("frotz")
        self.assertEqual(frotz_reports_dir,
                         "/tmp/fake/whatever/projects/frotz/reports")

    def test_can_get_subprojects_directory_path(self):
        f2_dir = self.manager.getSubprojectDir("frotz", "f2")
        self.assertEqual(f2_dir,
                         "/tmp/fake/whatever/projects/frotz/subprojects/f2")

    def test_can_get_subprojects_reports_directory_path(self):
        f2_reports_dir = self.manager.getSubprojectReportsDir("frotz", "f2")
        self.assertEqual(
            f2_reports_dir,
            "/tmp/fake/whatever/projects/frotz/subprojects/f2/reports")

    def test_can_get_subprojects_spdx_directory_path(self):
        f2_spdx_dir = self.manager.getSubprojectSPDXDir("frotz", "f2")
        self.assertEqual(
            f2_spdx_dir,
            "/tmp/fake/whatever/projects/frotz/subprojects/f2/spdx")

    def test_can_get_subproject_scan_dates_for_month_with_one_scan(self):
        dates = self.manager.getScanDates(self.frotz_db, "f1", "2017-02")
        self.assertIsInstance(dates, list)
        self.assertEqual(len(dates), 1)
        self.assertEqual(dates[0], "2017-02-03")

    def test_can_get_subproject_scan_dates_for_month_with_two_scans(self):
        dates = self.manager.getScanDates(self.frotz_db, "f2", "2017-02")
        self.assertIsInstance(dates, list)
        self.assertEqual(len(dates), 2)
        self.assertEqual(dates[0], "2017-02-10")
        self.assertEqual(dates[1], "2017-02-17")

    def test_getting_scan_dates_without_scans_returns_empty_list(self):
        dates = self.manager.getScanDates(self.frotz_db, "f3", "2017-02")
        self.assertIsInstance(dates, list)
        self.assertEqual(len(dates), 0)

    def test_getting_scan_dates_without_choosing_subproject_raises_exception(
            self):
        with self.assertRaises(SLMManagerError):
            self.manager.getScanDates(self.frotz_db, None, "2017-02")

    def test_getting_scan_dates_without_any_subprojects_raises_exception(self):
        with self.assertRaises(SLMManagerError):
            self.manager.getScanDates(self.rezrov_db, None, "2017-02")

    def test_getting_scan_dates_with_nonexistent_subproject_raises_exception(
            self):
        with self.assertRaises(SLMManagerError):
            self.manager.getScanDates(self.frotz_db, "oops", "2017-02")

    def test_can_check_if_any_scan_is_present_for_given_month(self):
        retval = self.manager.isScanForMonth(self.frotz_db, "f1", "2017-02")
        self.assertTrue(retval)
        retval = self.manager.isScanForMonth(self.frotz_db, "f2", "2017-02")
        self.assertTrue(retval)
        retval = self.manager.isScanForMonth(self.frotz_db, "f3", "2017-02")
        self.assertFalse(retval)

    def test_can_get_spdx_possible_filenames_for_scan_dt(self):
        spdx_paths = self.manager.getSPDXExpectedPaths(self.frotz_db, "frotz",
                                                       "f1", "2017-02")
        self.assertIsInstance(spdx_paths, list)
        self.assertEqual(len(spdx_paths), 1)
        self.assertEqual(
            spdx_paths[0],
            "/tmp/fake/whatever/projects/frotz/subprojects/f1/spdx/f1-2017-02-03.spdx"
        )

        spdx_paths2 = self.manager.getSPDXExpectedPaths(
            self.frotz_db, "frotz", "f2", "2017-02")
        self.assertIsInstance(spdx_paths2, list)
        self.assertEqual(len(spdx_paths2), 2)
        self.assertEqual(
            spdx_paths2[0],
            "/tmp/fake/whatever/projects/frotz/subprojects/f2/spdx/f2-2017-02-10.spdx"
        )
        self.assertEqual(
            spdx_paths2[1],
            "/tmp/fake/whatever/projects/frotz/subprojects/f2/spdx/f2-2017-02-17.spdx"
        )

    @mock.patch('slm.projectdb.os.path.isfile', return_value=True)
    def test_can_check_if_spdx_file_is_present(self, os_isfile):
        retval = self.manager.isSPDXForMonth(self.frotz_db, "frotz", "f1",
                                             "2017-02")
        self.assertTrue(retval)

    @mock.patch('slm.projectdb.os.path.isfile', return_value=False)
    def test_can_check_if_spdx_file_is_absent(self, os_isfile):
        retval = self.manager.isSPDXForMonth(self.frotz_db, "frotz", "f1",
                                             "2017-02")
        self.assertFalse(retval)

    @mock.patch('slm.projectdb.os.path.isfile', return_value=True)
    def test_can_check_if_xlsx_report_is_present(self, os_isfile):
        retval = self.manager.isXLSXForMonth("frotz", "f1", "2017-02")
        self.assertTrue(retval)

    @mock.patch('slm.projectdb.os.path.isfile', return_value=False)
    def test_can_check_if_xlsx_report_is_absent(self, os_isfile):
        retval = self.manager.isXLSXForMonth("frotz", "f1", "2017-02")
        self.assertFalse(retval)

    @mock.patch('slm.projectdb.os.path.isfile', return_value=True)
    def test_can_check_if_json_report_is_present(self, os_isfile):
        retval = self.manager.isJSONForMonth("frotz", "f1", "2017-02")
        self.assertTrue(retval)

    @mock.patch('slm.projectdb.os.path.isfile', return_value=False)
    def test_can_check_if_json_report_is_absent(self, os_isfile):
        retval = self.manager.isJSONForMonth("frotz", "f1", "2017-02")
        self.assertFalse(retval)
示例#15
0
 def test_cannot_open_in_memory_db(self):
     dbnew = ProjectDB()
     with self.assertRaises(ProjectDBConfigError):
         dbnew.openDB(":memory:")
示例#16
0
class DBConfigUnitTestSuite(unittest.TestCase):
    """spdxLicenseManager unit test suite for configuration data in DB."""
    def setUp(self):
        # create and initialize an in-memory database
        self.db = ProjectDB()
        self.db.createDB(":memory:")
        self.db.initializeDBTables()

        # insert sample data
        self.insertSampleConfigData()

    def tearDown(self):
        self.db.closeDB()
        self.db = None

    def insertSampleConfigData(self):
        configs = [
            Config(key="report-strip-licenseref", value="yes"),
        ]
        self.db.session.bulk_save_objects(configs)
        self.db.session.commit()

    ##### Test cases below

    def test_can_retrieve_config_value_from_key(self):
        value = self.db.getConfigValue(key="report-strip-licenseref")
        self.assertEqual(value, "yes")

    def test_cannot_retrieve_config_value_for_unknown_key(self):
        with self.assertRaises(ProjectDBQueryError):
            self.db.getConfigValue(key="unknown_key")

    def test_can_set_and_get_config_value_for_new_key_if_known(self):
        self.db.setConfigValue(key="analyze-extensions-list", value="json")
        value = self.db.getConfigValue(key="analyze-extensions-list")
        self.assertEqual(value, "json")

    def test_can_update_and_get_config_value_for_existing_key(self):
        self.db.setConfigValue(key="report-strip-licenseref", value="no")
        value = self.db.getConfigValue(key="report-strip-licenseref")
        self.assertEqual(value, "no")

    def test_cannot_update_config_value_for_reserved_keys(self):
        with self.assertRaises(ProjectDBUpdateError):
            self.db.setConfigValue(key="magic", value="blah")
        with self.assertRaises(ProjectDBUpdateError):
            self.db.setConfigValue(key="initialized", value="blah")

    def test_cannot_set_unknown_key(self):
        with self.assertRaises(ProjectDBInsertError):
            self.db.setConfigValue(key="new_key", value="123abc")

    def test_can_get_all_configs(self):
        configs = self.db.getConfigsAll()
        self.assertIsInstance(configs, list)
        self.assertEqual(len(configs), 3)
        self.assertEqual(configs[0].key, "initialized")
        self.assertEqual(configs[0].value, "yes")
        self.assertEqual(configs[1].key, "magic")
        self.assertEqual(configs[1].value, "spdxLicenseManager")
        self.assertEqual(configs[2].key, "report-strip-licenseref")
        self.assertEqual(configs[2].value, "yes")

    def test_can_unset_config(self):
        self.db.unsetConfigValue(key="report-strip-licenseref")
        with self.assertRaises(ProjectDBQueryError):
            self.db.getConfigValue(key="report-strip-licenseref")

    def test_cannot_unset_config_for_internal_config(self):
        with self.assertRaises(ProjectDBDeleteError):
            self.db.unsetConfigValue(key="magic")

    def test_cannot_unset_config_for_unknown_config(self):
        with self.assertRaises(ProjectDBDeleteError):
            self.db.unsetConfigValue(key="blah")

    def test_cannot_unset_config_for_valid_config_that_is_not_set(self):
        with self.assertRaises(ProjectDBDeleteError):
            self.db.unsetConfigValue(key="analyze-extensions-list")
示例#17
0
class ProjectDBUnitTestSuite(unittest.TestCase):
    """spdxLicenseManager unit test suite for DB initialization and lifecycle."""
    def setUp(self):
        # create and initialize an in-memory database
        self.db = ProjectDB()
        self.db.createDB(":memory:")
        self.db.initializeDBTables()

    def tearDown(self):
        self.db.closeDB()
        self.db = None

    def test_can_create_new_database(self):
        # don't use db from setUp(); create new in-memory DB from scratch
        dbnew = ProjectDB()
        dbnew.createDB(":memory:")
        self.assertTrue(dbnew.isOpened())
        self.assertFalse(dbnew.isInitialized())
        dbnew.closeDB()

    @mock.patch('slm.projectdb.os.path.exists', return_value=True)
    def test_cannot_create_new_database_if_file_already_exists(
            self, os_exists):
        dbnew = ProjectDB()
        with self.assertRaises(ProjectDBConfigError):
            dbnew.createDB("/tmp/fake/existing.db")

    def test_that_initialized_db_reports_as_initialized(self):
        self.assertTrue(self.db.isInitialized())

    def test_that_closed_db_reports_as_uninitialized(self):
        # don't use db from setUp(); create new in-memory DB from scratch
        dbnew = ProjectDB()
        dbnew.createDB(":memory:")
        # and then close it
        dbnew.closeDB()
        self.assertFalse(dbnew.isInitialized())
        self.assertIsNone(dbnew.session)
        self.assertIsNone(dbnew.engine)

    def test_can_open_existing_db(self):
        # create in temporary directory on disk, so we can re-open DB
        # (testfixtures will wipe out the directory at end of test)
        with TempDirectory() as td:
            dbPath = os.path.join(td.path, "tmp.db")
            dbnew = ProjectDB()
            dbnew.createDB(dbPath)
            dbnew.initializeDBTables()
            dbnew.closeDB()
            # and reopen it
            dbnew.openDB(dbPath)
            self.assertTrue(dbnew.isOpened())
            self.assertTrue(dbnew.isInitialized())
            dbnew.closeDB()

    def test_cannot_open_in_memory_db(self):
        dbnew = ProjectDB()
        with self.assertRaises(ProjectDBConfigError):
            dbnew.openDB(":memory:")

    def test_open_db_fails_if_invalid_magic_number(self):
        # create in temporary directory on disk, so we can re-open it
        # (testfixtures will wipe out the directory at end of test)
        with TempDirectory() as td:
            dbPath = os.path.join(td.path, "tmp.db")
            dbnew = ProjectDB()
            dbnew.createDB(dbPath)
            dbnew.initializeDBTables()

            # set invalid magic number
            query = dbnew.session.query(Config).filter(Config.key == "magic")
            query.update({Config.value: "invalidMagic"})
            dbnew.session.commit()
            dbnew.closeDB()

            # and reopen it
            with self.assertRaises(ProjectDBConfigError):
                dbnew.openDB(dbPath)
            self.assertFalse(dbnew.isOpened())
            self.assertFalse(dbnew.isInitialized())

    def test_cannot_open_some_random_file_as_db(self):
        # create in temporary directory on disk, so we can re-open it
        # (testfixtures will wipe out the directory at end of test)
        with TempDirectory() as td:
            fakeDBPath = os.path.join(td.path, "tmp.txt")
            with open(fakeDBPath, "w") as f:
                f.write("some random text")

            dbnew = ProjectDB()
            with self.assertRaises(ProjectDBConfigError):
                dbnew.openDB(fakeDBPath)
            self.assertFalse(dbnew.isOpened())
            self.assertFalse(dbnew.isInitialized())
class ReportJSONTestSuite(unittest.TestCase):
    """spdxLicenseManager JSON reporting unit test suite."""
    def setUp(self):
        # create and initialize an in-memory database
        self.db = ProjectDB()
        self.db.createDB(":memory:")
        self.db.initializeDBTables()

        # create reporter
        self.reporter = JSONReporter(db=self.db)

    def tearDown(self):
        pass

    ##### Test helpers to mimic results from analysis

    def _buildCategories(self, results):
        self.cat2 = Category()
        self.cat2._id = 2
        self.cat2.name = "catID2"
        self.cat2.licenses = []
        results.append(self.cat2)

        self.cat1 = Category()
        self.cat1._id = 1
        self.cat1.name = "catID1"
        self.cat1.licenses = []
        results.append(self.cat1)

        self.cat4 = Category()
        self.cat4._id = 4
        self.cat4.name = "No license found"
        self.cat4.licenses = []
        results.append(self.cat4)

    def _buildLicenses(self, results):
        # should sort alphabetically before lic1cat2 in reports
        self.lic2cat2 = License()
        self.lic2cat2._id = 2
        self.lic2cat2.name = "another lic2cat2"
        self.lic2cat2.files = []
        self.cat2.licenses.append(self.lic2cat2)

        self.lic1cat2 = License()
        self.lic1cat2._id = 1
        self.lic1cat2.name = "lic1cat2"
        self.lic1cat2.files = []
        self.cat2.licenses.append(self.lic1cat2)

        self.lic5cat1 = License()
        self.lic5cat1._id = 5
        self.lic5cat1.name = "a license"
        self.lic5cat1.files = []
        self.cat1.licenses.append(self.lic5cat1)

        # no license found option, for analysis outputs
        self.noLicFound = License()
        self.noLicFound._id = 6
        self.noLicFound.name = "No license found"
        self.noLicFound.files = []
        self.cat4.licenses.append(self.noLicFound)

    def _buildFiles(self, results):
        # should sort alphabetically by path before f1
        self.f2 = File()
        self.f2._id = 2
        self.f2.path = "/first/tmp/f2"
        self.f2.scan_id = 1
        self.f2.findings = {}
        self.lic2cat2.files.append(self.f2)

        self.f1 = File()
        self.f1._id = 1
        self.f1.path = "/tmp/f1"
        self.f1.scan_id = 1
        self.f1.findings = {}
        self.lic2cat2.files.append(self.f1)

        # should sort after f2 and f1 b/c license ID sorts after theirs
        self.f3 = File()
        self.f3._id = 3
        self.f3.path = "/earliest/tmp/f3"
        self.f3.scan_id = 1
        self.f3.findings = {}
        self.lic1cat2.files.append(self.f3)

        self.f4 = File()
        self.f4._id = 4
        self.f4.path = "/tmp/f4"
        self.f4.scan_id = 1
        self.f4.findings = {}
        self.lic1cat2.files.append(self.f4)

        self.f5 = File()
        self.f5._id = 5
        self.f5.path = "/tmp/f5"
        self.f5.scan_id = 1
        self.f5.findings = {}
        self.lic5cat1.files.append(self.f5)

        self.f6 = File()
        self.f6._id = 6
        self.f6.path = "/tmp/f6.png"
        self.f6.scan_id = 1
        self.f6.findings = {
            "extension": "yes",
        }
        self.noLicFound.files.append(self.f6)

        # add some more files for testing findings
        self.f7 = File()
        self.f7._id = 7
        self.f7.path = "/tmp/__init__.py"
        self.f7.scan_id = 1
        self.f7.findings = {
            "emptyfile": "yes",
        }
        self.noLicFound.files.append(self.f7)

        self.f8 = File()
        self.f8._id = 8
        self.f8.path = "/tmp/vendor/dep.py"
        self.f8.scan_id = 1
        self.f8.findings = {
            "thirdparty": "yes",
        }
        self.noLicFound.files.append(self.f8)

        self.f9 = File()
        self.f9._id = 9
        self.f9.path = "/tmp/code.py"
        self.f9.scan_id = 1
        self.f9.findings = {}
        self.noLicFound.files.append(self.f9)

    def _getAnalysisResults(self):
        results = []
        self._buildCategories(results)
        self._buildLicenses(results)
        self._buildFiles(results)
        return results

    ##### Test cases below

    def test_new_reporter_is_in_reset_state(self):
        self.assertIsNone(self.reporter.results)
        self.assertIsNone(self.reporter.rjs)
        self.assertFalse(self.reporter.reportSaved)
        self.assertEqual({}, self.reporter.kwConfig)

    ##### Reporter config function tests

    def test_reporter_can_take_optional_config_params(self):
        configDict = {
            "report-pretty-print": "yes",
        }
        newReporter = JSONReporter(db=self.db, config=configDict)
        self.assertEqual("yes", newReporter.kwConfig["report-pretty-print"])

    def test_can_get_reporter_final_config(self):
        self.db.setConfigValue(key="report-pretty-print", value="yes")
        summary = self.reporter._getFinalConfigValue(key="report-pretty-print")
        self.assertEqual(summary, "yes")

    def test_can_override_db_config_in_reporter_final_config(self):
        self.db.setConfigValue(key="report-pretty-print", value="yes")
        newReporter = JSONReporter(db=self.db,
                                   config={"report-pretty-print": "no"})
        summary = newReporter._getFinalConfigValue(key="report-pretty-print")
        self.assertEqual(summary, "no")

    ##### Reporter setup function tests

    def test_can_set_results_and_create_empty_string_for_json(self):
        results = self._getAnalysisResults()
        self.reporter.setResults(results)
        self.assertIsInstance(self.reporter.rjs, str)
        self.assertEqual(self.reporter.rjs, "")
        self.assertEqual(self.reporter.results, results)

    ##### Reporter custom JSON encoder tests

    def test_encoder_creates_correct_values(self):
        results = self._getAnalysisResults()
        enc = self.reporter.SLMJSONEncoder()

        # here's a file with findings
        enc_f6 = enc.default(self.f6)
        self.assertEqual(enc_f6["path"], "/tmp/f6.png")
        self.assertEqual(enc_f6["_id"], 6)
        self.assertEqual(enc_f6["findings"], {"extension": "yes"})

        # here's a file with no findings
        enc_f5 = enc.default(self.f5)
        self.assertEqual(enc_f5["path"], "/tmp/f5")
        self.assertEqual(enc_f5["_id"], 5)
        with self.assertRaises(KeyError):
            na = enc_f5["findings"]

        # here's a license
        enc_lic1 = enc.default(self.lic1cat2)
        self.assertEqual(enc_lic1["name"], "lic1cat2")
        self.assertEqual(enc_lic1["_id"], 1)
        self.assertEqual(enc_lic1["numFiles"], 2)
        self.assertEqual(enc_lic1["files"], self.lic1cat2.files)

        # here's a category
        enc_cat2 = enc.default(self.cat2)
        self.assertEqual(enc_cat2["name"], "catID2")
        self.assertEqual(enc_cat2["_id"], 2)
        self.assertEqual(enc_cat2["numFiles"], 4)
        self.assertEqual(enc_cat2["licenses"], self.cat2.licenses)

    ##### Reporter helpers

    def test_helper_can_get_number_of_files_for_license(self):
        results = self._getAnalysisResults()
        enc = self.reporter.SLMJSONEncoder()
        numFiles = enc._getNumFilesForLicense(self.lic1cat2)
        self.assertEqual(numFiles, 2)

    def test_helper_can_get_number_of_files_for_category(self):
        results = self._getAnalysisResults()
        enc = self.reporter.SLMJSONEncoder()
        numFiles = enc._getNumFilesForCategory(self.cat2)
        self.assertEqual(numFiles, 4)

    ##### Reporter generate function tests

    def test_save_report_fails_if_results_not_ready(self):
        with self.assertRaises(ReportNotReadyError):
            self.reporter.save(path="/tmp/fake/whatever.json")
        self.assertFalse(self.reporter.reportSaved)

    @mock.patch('slm.reports.json.open')
    @mock.patch('slm.reports.json.json.dump')
    def test_save_calls_functions_to_save(self, dump_mock, open_mock):
        outfile = "/tmp/newfile.json"
        results = self._getAnalysisResults()
        self.reporter.setResults(results)
        self.reporter.save(path=outfile)

        dump_mock.assert_called()
        args = dump_mock.call_args
        self.assertEqual(args[0][0], results)
        self.assertEqual(args[1], {"cls": JSONReporter.SLMJSONEncoder})
        open_mock.assert_called_with(outfile, "w")

    ##### Reporter save function tests

    @mock.patch('slm.reports.json.open')
    @mock.patch('slm.reports.json.os.path.exists', return_value=True)
    def test_save_check_raises_exception_if_file_already_exists(
            self, os_exists, open_mock):
        results = self._getAnalysisResults()
        self.reporter.setResults(results)

        with self.assertRaises(ReportFileError):
            self.reporter._saveCheck(path="/tmp/fake/existing.json")

    @mock.patch('slm.reports.json.open')
    @mock.patch('slm.reports.json.os.path.exists', return_value=True)
    @mock.patch('slm.reports.json.os.access', return_value=True)
    def test_save_check_doesnt_raise_exception_if_replace_flag_set(
            self, os_access, os_exists, open_mock):
        results = self._getAnalysisResults()
        self.reporter.setResults(results)

        try:
            self.reporter._saveCheck(path="/tmp/fake/existing.json",
                                     replace=True)
        except ReportFileError:
            self.fail(
                "ReportFileError raised even though replace flag is True")

    @mock.patch('slm.reports.json.open')
    @mock.patch('slm.reports.json.os.access', return_value=False)
    def test_save_check_fails_if_no_write_permission_for_path(
            self, os_access, open_mock):
        results = self._getAnalysisResults()
        self.reporter.setResults(results)

        with self.assertRaises(ReportFileError):
            self.reporter._saveCheck(path="/tmp/readonly/report.json")

    def test_save_check_fails_if_report_not_ready_yet(self):
        with self.assertRaises(ReportNotReadyError):
            self.reporter._saveCheck(path="whatever")

    @mock.patch('slm.reports.json.open')
    @mock.patch('slm.reports.json.JSONReporter._saveCheck')
    def test_save_calls_save_checker(self, check_mock, open_mock):
        results = self._getAnalysisResults()
        self.reporter.setResults(results)
        path = "something"
        replace = True

        self.reporter.save(path=path, replace=replace)

        check_mock.assert_called_with(path=path, replace=replace)
        open_mock.assert_called_with(path, "w")
示例#19
0
class ReportXlsxTestSuite(unittest.TestCase):
    """spdxLicenseManager Xlsx reporting unit test suite."""
    def setUp(self):
        # create and initialize an in-memory database
        self.db = ProjectDB()
        self.db.createDB(":memory:")
        self.db.initializeDBTables()

        # create reporter
        self.reporter = XlsxReporter(db=self.db)

    def tearDown(self):
        pass

    ##### Test helpers to mimic results from analysis

    def _buildCategories(self, results):
        self.cat2 = Category()
        self.cat2._id = 2
        self.cat2.name = "catID2"
        self.cat2.order = 1
        self.cat2.licensesSorted = OrderedDict()
        self.cat2.hasFiles = True
        results[2] = self.cat2

        # no files, cat3 should not appear in reports
        self.cat3 = Category()
        self.cat3._id = 3
        self.cat3.name = "catID3"
        self.cat3.order = 2
        self.cat3.licensesSorted = OrderedDict()
        self.cat3.hasFiles = False
        results[3] = self.cat3

        self.cat1 = Category()
        self.cat1._id = 1
        self.cat1.name = "catID1"
        self.cat1.order = 3
        self.cat1.licensesSorted = OrderedDict()
        self.cat1.hasFiles = True
        results[1] = self.cat1

        self.cat4 = Category()
        self.cat4._id = 4
        self.cat4.name = "No license found"
        self.cat4.order = 4
        self.cat4.licensesSorted = OrderedDict()
        self.cat4.hasFiles = True
        results[4] = self.cat4

    def _buildLicenses(self, results):
        # should sort alphabetically before lic1cat2 in reports
        self.lic2cat2 = License()
        self.lic2cat2._id = 2
        self.lic2cat2.name = "another lic2cat2"
        self.lic2cat2.category_id = 2
        self.lic2cat2.filesSorted = OrderedDict()
        self.lic2cat2.hasFiles = True
        self.cat2.licensesSorted[2] = self.lic2cat2

        self.lic1cat2 = License()
        self.lic1cat2._id = 1
        self.lic1cat2.name = "lic1cat2"
        self.lic1cat2.category_id = 2
        self.lic1cat2.filesSorted = OrderedDict()
        self.lic1cat2.hasFiles = True
        self.cat2.licensesSorted[1] = self.lic1cat2

        # no files, lic3cat2 should not appear in reports
        self.lic3cat2 = License()
        self.lic3cat2._id = 3
        self.lic3cat2.name = "nope lic3cat2"
        self.lic3cat2.category_id = 2
        self.lic3cat2.filesSorted = OrderedDict()
        self.lic3cat2.hasFiles = False
        self.cat2.licensesSorted[3] = self.lic3cat2

        # no files, lic4cat3 should not appear in reports
        self.lic4cat3 = License()
        self.lic4cat3._id = 4
        self.lic4cat3.name = "nope lic4cat3"
        self.lic4cat3.category_id = 3
        self.lic4cat3.filesSorted = OrderedDict()
        self.lic4cat3.hasFiles = False
        self.cat3.licensesSorted[4] = self.lic4cat3

        self.lic5cat1 = License()
        self.lic5cat1._id = 5
        self.lic5cat1.name = "a license"
        self.lic5cat1.category_id = 1
        self.lic5cat1.filesSorted = OrderedDict()
        self.lic5cat1.hasFiles = True
        self.cat1.licensesSorted[5] = self.lic5cat1

        # no license found option, for analysis outputs
        self.noLicFound = License()
        self.noLicFound._id = 6
        self.noLicFound.name = "No license found"
        self.noLicFound.category_id = 4
        self.noLicFound.filesSorted = OrderedDict()
        self.noLicFound.hasFiles = True
        self.cat4.licensesSorted[6] = self.noLicFound

    def _buildFiles(self, results):
        # should sort alphabetically by path before f1
        self.f2 = File()
        self.f2._id = 2
        self.f2.path = "/first/tmp/f2"
        self.f2.scan_id = 1
        self.f2.license_id = 2
        self.f2.findings = {}
        self.lic2cat2.filesSorted[2] = self.f2

        self.f1 = File()
        self.f1._id = 1
        self.f1.path = "/tmp/f1"
        self.f1.scan_id = 1
        self.f1.license_id = 2
        self.f1.findings = {}
        self.lic2cat2.filesSorted[1] = self.f1

        # should sort after f2 and f1 b/c license ID sorts after theirs
        self.f3 = File()
        self.f3._id = 3
        self.f3.path = "/earliest/tmp/f3"
        self.f3.scan_id = 1
        self.f3.license_id = 1
        self.f3.findings = {}
        self.lic1cat2.filesSorted[3] = self.f3

        self.f4 = File()
        self.f4._id = 4
        self.f4.path = "/tmp/f4"
        self.f4.scan_id = 1
        self.f4.license_id = 1
        self.f4.findings = {}
        self.lic1cat2.filesSorted[4] = self.f4

        self.f5 = File()
        self.f5._id = 5
        self.f5.path = "/tmp/f5"
        self.f5.scan_id = 1
        self.f5.license_id = 5
        self.f5.findings = {}
        self.lic5cat1.filesSorted[5] = self.f5

        self.f6 = File()
        self.f6._id = 6
        self.f6.path = "/tmp/f6.png"
        self.f6.scan_id = 1
        self.f6.license_id = 6
        self.f6.findings = {
            "extension": "yes",
        }
        self.noLicFound.filesSorted[6] = self.f6

        # add some more files for testing findings
        self.f7 = File()
        self.f7._id = 7
        self.f7.path = "/tmp/__init__.py"
        self.f7.scan_id = 1
        self.f7.license_id = 6
        self.f7.findings = {
            "emptyfile": "yes",
        }
        self.noLicFound.filesSorted[7] = self.f7

        self.f8 = File()
        self.f8._id = 8
        self.f8.path = "/tmp/vendor/dep.py"
        self.f8.scan_id = 1
        self.f8.license_id = 6
        self.f8.findings = {
            "thirdparty": "yes",
        }
        self.noLicFound.filesSorted[8] = self.f8

        self.f9 = File()
        self.f9._id = 9
        self.f9.path = "/tmp/code.py"
        self.f9.scan_id = 1
        self.f9.license_id = 6
        self.f9.findings = {}
        self.noLicFound.filesSorted[9] = self.f9

    def _getAnalysisResults(self):
        results = OrderedDict()
        self._buildCategories(results)
        self._buildLicenses(results)
        self._buildFiles(results)
        return results

    ##### Test cases below

    def test_new_reporter_is_in_reset_state(self):
        self.assertIsNone(self.reporter.results)
        self.assertIsNone(self.reporter.wb)
        self.assertFalse(self.reporter.reportGenerated)
        self.assertEqual({}, self.reporter.kwConfig)

    ##### Reporter config function tests

    def test_reporter_can_take_optional_config_params(self):
        configDict = {
            "report-include-summary": "yes",
        }
        newReporter = XlsxReporter(db=self.db, config=configDict)
        self.assertEqual("yes", newReporter.kwConfig["report-include-summary"])

    def test_can_get_reporter_final_config(self):
        self.db.setConfigValue(key="report-include-summary", value="yes")
        summary = self.reporter._getFinalConfigValue(
            key="report-include-summary")
        self.assertEqual(summary, "yes")

    def test_can_override_db_config_in_reporter_final_config(self):
        self.db.setConfigValue(key="report-include-summary", value="yes")
        newReporter = XlsxReporter(db=self.db,
                                   config={"report-include-summary": "no"})
        summary = newReporter._getFinalConfigValue(
            key="report-include-summary")
        self.assertEqual(summary, "no")

    ##### Reporter setup function tests

    def test_can_set_results_and_create_workbook(self):
        results = self._getAnalysisResults()
        self.reporter.setResults(results)
        self.assertEqual(Workbook, type(self.reporter.wb))
        self.assertEqual(results, self.reporter.results)

    ##### Reporter generate function tests

    def test_generate_report_fails_if_results_not_ready(self):
        with self.assertRaises(ReportNotReadyError):
            self.reporter.generate()
        self.assertFalse(self.reporter.reportGenerated)

        # even with workbook created, should fail if results aren't ready yet
        self.reporter.wb = Workbook()
        with self.assertRaises(ReportNotReadyError):
            self.reporter.generate()
        self.assertFalse(self.reporter.reportGenerated)

    @mock.patch('slm.reports.xlsx.XlsxReporter._generateFileListings')
    @mock.patch('slm.reports.xlsx.XlsxReporter._generateCategorySheets')
    def test_generate_calls_required_helpers(self, cs_mock, file_mock):
        results = self._getAnalysisResults()
        self.reporter.setResults(results)
        self.reporter.generate()
        cs_mock.assert_called_with(self.reporter.wb, self.reporter.results)
        file_mock.assert_called_with(self.reporter.wb,
                                     self.reporter.results,
                                     strip_licenseref=False)

    def test_generate_sets_report_generated_flag(self):
        results = self._getAnalysisResults()
        self.reporter.setResults(results)
        self.reporter.generate()
        self.assertTrue(self.reporter.reportGenerated)

    def test_can_generate_report_category_pages(self):
        wb = Workbook()
        results = self._getAnalysisResults()
        self.reporter._generateCategorySheets(wb, results)

        # workbook now has the expected category sheets
        # catID3 does not appear because it has no files
        self.assertEqual(["catID2", "catID1", "No license found"],
                         wb.sheetnames)
        # proper headers are set for each category page
        # and header fonts are as expected
        for sheet in wb:
            headerFile = sheet['A1']
            self.assertEqual("File", headerFile.value)
            self.assertEqual(16, headerFile.font.size)
            self.assertTrue(headerFile.font.bold)
            self.assertFalse(headerFile.alignment.wrap_text)
            headerLicense = sheet['B1']
            self.assertEqual("License", sheet['B1'].value)
            self.assertEqual(16, headerLicense.font.size)
            self.assertTrue(headerLicense.font.bold)
            self.assertFalse(headerLicense.alignment.wrap_text)

            # column widths are as expected
            self.assertEqual(100, sheet.column_dimensions["A"].width)
            self.assertEqual(60, sheet.column_dimensions["B"].width)

    def test_cannot_generate_files_before_category_sheets_are_generated(self):
        wb = Workbook()
        results = self._getAnalysisResults()
        with self.assertRaises(ReportNotReadyError):
            self.reporter._generateFileListings(wb, results)

    def test_can_generate_file_listings(self):
        wb = Workbook()
        results = self._getAnalysisResults()
        self.reporter._generateCategorySheets(wb, results)
        self.reporter._generateFileListings(wb, results)

        # correct files and licenses are in the correct cells
        ws1 = wb['catID2']
        self.assertEqual("/first/tmp/f2", ws1['A2'].value)
        self.assertEqual("another lic2cat2", ws1['B2'].value)
        self.assertEqual("/tmp/f1", ws1['A3'].value)
        self.assertEqual("another lic2cat2", ws1['B3'].value)
        self.assertEqual("/earliest/tmp/f3", ws1['A4'].value)
        self.assertEqual("lic1cat2", ws1['B4'].value)
        self.assertEqual("/tmp/f4", ws1['A5'].value)
        self.assertEqual("lic1cat2", ws1['B5'].value)

        ws2 = wb['catID1']
        self.assertEqual("/tmp/f5", ws2['A2'].value)
        self.assertEqual("a license", ws2['B2'].value)

        cellFile = ws2['A2']
        self.assertEqual(14, cellFile.font.size)
        self.assertFalse(cellFile.font.bold)
        self.assertTrue(cellFile.alignment.wrap_text)
        cellLicense = ws2['B2']
        self.assertEqual(14, cellLicense.font.size)
        self.assertFalse(cellLicense.font.bold)
        self.assertTrue(cellLicense.alignment.wrap_text)

    @mock.patch('slm.reports.xlsx.XlsxReporter._generateSummarySheet')
    def test_summary_not_generated_if_config_not_set(self, summary_mock):
        results = self._getAnalysisResults()
        self.reporter.setResults(results)
        self.reporter.generate()
        summary_mock.assert_not_called()

    @mock.patch('slm.reports.xlsx.XlsxReporter._generateSummarySheet')
    def test_summary_is_generated_if_config_set(self, summary_mock):
        self.db.setConfigValue(key="report-include-summary", value="yes")
        results = self._getAnalysisResults()
        self.reporter.setResults(results)
        self.reporter.generate()
        summary_mock.assert_called_with(self.reporter.wb,
                                        self.reporter.results,
                                        strip_licenseref=False)

    def test_can_generate_summary_sheet(self):
        wb = Workbook()
        results = self._getAnalysisResults()
        self.reporter._generateSummarySheet(wb, results)
        # sheet title is as expected
        self.assertEqual('License summary', wb.sheetnames[0])
        ws = wb.active
        # column widths are as expected
        self.assertEqual(3, ws.column_dimensions["A"].width)
        self.assertEqual(60, ws.column_dimensions["B"].width)
        self.assertEqual(10, ws.column_dimensions["C"].width)
        # headers are as expected
        self.assertEqual("License", ws['A1'].value)
        self.assertEqual(16, ws['A1'].font.size)
        self.assertTrue(ws['A1'].font.bold)
        self.assertFalse(ws['A1'].alignment.wrap_text)
        self.assertEqual("# of files", ws['C1'].value)
        self.assertEqual(16, ws['C1'].font.size)
        self.assertTrue(ws['C1'].font.bold)
        self.assertFalse(ws['C1'].alignment.wrap_text)
        # and rows/values and formatting are all as expected
        # cats and licenses with no files should not appear
        self.assertEqual("catID2:", ws['A3'].value)
        self.assertEqual(16, ws['A3'].font.size)
        self.assertTrue(ws['A3'].font.bold)
        self.assertFalse(ws['A3'].alignment.wrap_text)
        self.assertEqual("another lic2cat2", ws['B4'].value)
        self.assertEqual(14, ws['B4'].font.size)
        self.assertFalse(ws['B4'].font.bold)
        self.assertTrue(ws['B4'].alignment.wrap_text)
        self.assertEqual(2, ws['C4'].value)
        self.assertEqual("lic1cat2", ws['B5'].value)
        self.assertEqual(2, ws['C5'].value)
        self.assertEqual("catID1:", ws['A6'].value)
        self.assertEqual("a license", ws['B7'].value)
        self.assertEqual(1, ws['C7'].value)
        self.assertEqual("No license found:", ws['A8'].value)
        self.assertEqual("No license found", ws['B9'].value)
        self.assertEqual(4, ws['C9'].value)
        self.assertEqual("TOTAL", ws['A11'].value)
        self.assertEqual(16, ws['A11'].font.size)
        self.assertTrue(ws['A11'].font.bold)
        self.assertFalse(ws['A11'].alignment.wrap_text)
        self.assertEqual(9, ws['C11'].value)
        self.assertEqual(16, ws['C11'].font.size)
        self.assertTrue(ws['C11'].font.bold)
        self.assertFalse(ws['C11'].alignment.wrap_text)

    def test_summary_sheet_not_overwritten_by_other_sheets(self):
        self.db.setConfigValue(key="report-include-summary", value="yes")
        results = self._getAnalysisResults()
        self.reporter.setResults(results)
        self.reporter.generate()
        # workbook should have the summary sheet AND the expected category sheets
        self.assertEqual(
            ["License summary", "catID2", "catID1", "No license found"],
            self.reporter.wb.sheetnames)
        # the summary sheet has the expected summary headers
        self.assertEqual("License",
                         self.reporter.wb['License summary']['A1'].value)
        self.assertEqual("# of files",
                         self.reporter.wb['License summary']['C1'].value)
        # and the file listing sheets have the expected file listing headers
        self.assertEqual("File", self.reporter.wb['catID2']['A1'].value)
        self.assertEqual("License", self.reporter.wb['catID2']['B1'].value)

    ##### Reporter findings license renaming tests

    def test_can_modify_licenses_in_no_lic_found_cat_for_findings(self):
        self.db.setConfigValue(key="analyze-extensions", value="yes")
        self.db.setConfigValue(key="analyze-emptyfile", value="yes")
        self.db.setConfigValue(key="analyze-thirdparty", value="yes")
        results = self._getAnalysisResults()

        # hand the "No license found" category to the annotate function
        self.reporter._annotateNoLicenseFound(
            catNoLicense=self.cat4,
            nextLicID=7,
        )

        # check that it has been modified as expected, with new licenses,
        # and with the expected files within those licenses

        # this will temporarily get assigned the next available license ID
        # (only in memory, not committed to db)
        noLicExt = self.cat4.licensesSorted[7]
        self.assertEqual("No license found - excluded file extension",
                         noLicExt.name)
        self.assertEqual(4, noLicExt.category_id)
        self.assertTrue(noLicExt.hasFiles)
        self.assertEqual(noLicExt.filesSorted[6], self.f6)

        noLicEmpty = self.cat4.licensesSorted[8]
        self.assertEqual("No license found - empty file", noLicEmpty.name)
        self.assertEqual(4, noLicEmpty.category_id)
        self.assertTrue(noLicEmpty.hasFiles)
        self.assertEqual(noLicEmpty.filesSorted[7], self.f7)

        noLicThird = self.cat4.licensesSorted[9]
        self.assertEqual("No license found - third party directory",
                         noLicThird.name)
        self.assertEqual(4, noLicThird.category_id)
        self.assertTrue(noLicThird.hasFiles)
        self.assertEqual(noLicThird.filesSorted[8], self.f8)

    ##### Reporter save function tests

    @mock.patch('slm.reports.xlsx.os.path.exists', return_value=True)
    def test_save_check_raises_exception_if_file_already_exists(
            self, os_exists):
        results = self._getAnalysisResults()
        self.reporter.setResults(results)
        self.reporter.generate()

        with self.assertRaises(ReportFileError):
            self.reporter._saveCheck(path="/tmp/fake/existing.xlsx")

    @mock.patch('slm.reports.xlsx.os.path.exists', return_value=True)
    @mock.patch('slm.reports.xlsx.os.access', return_value=True)
    def test_save_check_doesnt_raise_exception_if_replace_flag_set(
            self, os_access, os_exists):
        results = self._getAnalysisResults()
        self.reporter.setResults(results)
        self.reporter.generate()

        try:
            self.reporter._saveCheck(path="/tmp/fake/existing.xlsx",
                                     replace=True)
        except ReportFileError:
            self.fail(
                "ReportFileError raised even though replace flag is True")

    @mock.patch('slm.reports.xlsx.os.access', return_value=False)
    def test_save_check_fails_if_no_write_permission_for_path(self, os_access):
        results = self._getAnalysisResults()
        self.reporter.setResults(results)
        self.reporter.generate()

        with self.assertRaises(ReportFileError):
            self.reporter._saveCheck(path="/tmp/readonly/report.xlsx")

    def test_save_check_fails_if_report_not_ready_yet(self):
        with self.assertRaises(ReportNotReadyError):
            self.reporter._saveCheck(path="whatever")

        # and even with results added, should fail if report not generated yet
        results = self._getAnalysisResults()
        self.reporter.setResults(results)
        with self.assertRaises(ReportNotReadyError):
            self.reporter._saveCheck(path="whatever")

    @mock.patch('slm.reports.xlsx.openpyxl.workbook.Workbook.save')
    @mock.patch('slm.reports.xlsx.XlsxReporter._saveCheck')
    def test_save_calls_save_checker(self, check_mock, save_mock):
        results = self._getAnalysisResults()
        self.reporter.setResults(results)
        self.reporter.generate()

        path = "something"
        replace = True
        self.reporter.save(path=path, replace=replace)
        check_mock.assert_called_with(path=path, replace=replace)
        save_mock.assert_called_with(path)

    ##### Reporter misc helper function tests

    def test_can_get_max_lic_id_from_results(self):
        results = self._getAnalysisResults()
        maxLicID = self.reporter._getResultsMaxLicenseID(results)
        self.assertEqual(6, maxLicID)

    def test_can_create_temp_license(self):
        lic = self.reporter._createTempLicense(catID=4,
                                               nextLicID=7,
                                               name="No license found - blah")
        self.assertEqual(7, lic._id)
        self.assertEqual(4, lic.category_id)
        self.assertEqual("No license found - blah", lic.name)
        self.assertTrue(lic.hasFiles)
        self.assertEqual(OrderedDict(), lic.filesSorted)

    def test_will_strip_licenseref_prefix_if_requested(self):
        licName = "LicenseRef-blah-1 AND Apache-2.0 AND LicenseRef-hi"
        finalLicName = self.reporter._getFinalLicenseName(licName, True)
        self.assertEqual(finalLicName, "blah-1 AND Apache-2.0 AND hi")

    def test_will_not_strip_licenseref_prefix_if_not_requested(self):
        licName = "LicenseRef-blah-1 AND Apache-2.0 AND LicenseRef-hi"
        finalLicName = self.reporter._getFinalLicenseName(licName, False)
        self.assertEqual(finalLicName,
                         "LicenseRef-blah-1 AND Apache-2.0 AND LicenseRef-hi")

    @mock.patch('slm.reports.xlsx.XlsxReporter._getFinalLicenseName',
                return_value="blah")
    def test_generate_file_listings_strips_licenseref_prefix_if_arg_set(
            self, final_name):
        wb = Workbook()
        results = self._getAnalysisResults()
        self.reporter._generateCategorySheets(wb, results)
        self.reporter._generateFileListings(wb, results, strip_licenseref=True)
        final_name.assert_any_call("another lic2cat2", True)

    @mock.patch('slm.reports.xlsx.XlsxReporter._getFinalLicenseName',
                return_value="blah")
    def test_generate_file_listings_does_not_strip_licenseref_prefix_if_arg_not_set(
            self, final_name):
        wb = Workbook()
        results = self._getAnalysisResults()
        self.reporter._generateCategorySheets(wb, results)
        self.reporter._generateFileListings(wb, results)
        final_name.assert_any_call("another lic2cat2", False)

    @mock.patch('slm.reports.xlsx.XlsxReporter._generateFileListings')
    def test_generate_strips_licenseref_prefix_if_config_set(self, gfl_mock):
        self.db.setConfigValue(key="report-strip-licenseref", value="yes")
        results = self._getAnalysisResults()
        self.reporter.setResults(results)
        self.reporter.generate()
        gfl_mock.assert_any_call(self.reporter.wb,
                                 self.reporter.results,
                                 strip_licenseref=True)

    @mock.patch('slm.reports.xlsx.XlsxReporter._generateFileListings')
    def test_generate_does_not_strip_licenseref_prefix_if_config_not_set(
            self, gfl_mock):
        results = self._getAnalysisResults()
        self.reporter.setResults(results)
        self.reporter.generate()
        gfl_mock.assert_any_call(self.reporter.wb,
                                 self.reporter.results,
                                 strip_licenseref=False)

    @mock.patch('slm.reports.xlsx.XlsxReporter._getFinalLicenseName',
                return_value="blah")
    def test_generate_summary_strips_licenseref_prefix_if_arg_set(
            self, final_name):
        wb = Workbook()
        results = self._getAnalysisResults()
        self.reporter._generateCategorySheets(wb, results)
        self.reporter._generateSummarySheet(wb, results, strip_licenseref=True)
        final_name.assert_any_call("another lic2cat2", True)

    @mock.patch('slm.reports.xlsx.XlsxReporter._getFinalLicenseName',
                return_value="blah")
    def test_generate_summary_does_not_strip_licenseref_prefix_if_arg_not_set(
            self, final_name):
        wb = Workbook()
        results = self._getAnalysisResults()
        self.reporter._generateCategorySheets(wb, results)
        self.reporter._generateSummarySheet(wb, results)
        final_name.assert_any_call("another lic2cat2", False)

    @mock.patch('slm.reports.xlsx.XlsxReporter._generateSummarySheet')
    def test_generate_strips_licenseref_prefix_from_summary_if_config_set(
            self, gss_mock):
        self.db.setConfigValue(key="report-include-summary", value="yes")
        self.db.setConfigValue(key="report-strip-licenseref", value="yes")
        results = self._getAnalysisResults()
        self.reporter.setResults(results)
        self.reporter.generate()
        gss_mock.assert_any_call(self.reporter.wb,
                                 self.reporter.results,
                                 strip_licenseref=True)

    @mock.patch('slm.reports.xlsx.XlsxReporter._generateSummarySheet')
    def test_generate_does_not_strip_licenseref_prefix_from_summary_if_config_not_set(
            self, gss_mock):
        self.db.setConfigValue(key="report-include-summary", value="yes")
        results = self._getAnalysisResults()
        self.reporter.setResults(results)
        self.reporter.generate()
        gss_mock.assert_any_call(self.reporter.wb,
                                 self.reporter.results,
                                 strip_licenseref=False)
class DBCategoryUnitTestSuite(unittest.TestCase):
    """spdxLicenseManager unit test suite for category data in DB."""
    def setUp(self):
        # create and initialize an in-memory database
        self.db = ProjectDB()
        self.db.createDB(":memory:")
        self.db.initializeDBTables()

        # insert sample data
        self.insertSampleCategoryData()

    def tearDown(self):
        self.db.closeDB()
        self.db = None

    def insertSampleCategoryData(self):
        categories = [
            Category(_id=1, name="a category", order=3),
            Category(_id=2, name="cat of crazy licenses", order=2),
            Category(_id=3, name="blah category", order=1),
        ]
        self.db.session.bulk_save_objects(categories)
        self.db.session.commit()

    ##### Test cases below

    def test_can_retrieve_all_category_names_and_descs(self):
        categories = self.db.getCategoriesAll()
        self.assertIsInstance(categories, list)
        self.assertEqual(len(categories), 3)
        self.assertEqual(categories[0]._id, 3)
        self.assertEqual(categories[0].name, "blah category")
        self.assertEqual(categories[0].order, 1)

    def test_all_categories_are_sorted_by_order(self):
        categories = self.db.getCategoriesAll()
        self.assertEqual(categories[0].name, "blah category")
        self.assertEqual(categories[1].name, "cat of crazy licenses")
        self.assertEqual(categories[2].name, "a category")

    def test_can_retrieve_one_category_by_id(self):
        category = self.db.getCategory(_id=2)
        self.assertEqual(category.name, "cat of crazy licenses")

    def test_can_retrieve_one_category_by_name(self):
        category = self.db.getCategory(name="a category")
        self.assertEqual(category._id, 1)

    def test_cannot_retrieve_category_by_both_name_and_id(self):
        with self.assertRaises(ProjectDBQueryError):
            self.db.getCategory(_id=3, name="blah category")

    def test_cannot_retrieve_category_without_either_name_or_id(self):
        with self.assertRaises(ProjectDBQueryError):
            self.db.getCategory()

    def test_cannot_retrieve_category_with_positional_args(self):
        with self.assertRaises(TypeError):
            self.db.getCategory("blah category")

    def test_returns_none_if_category_not_found_by_id(self):
        category = self.db.getCategory(_id=17)
        self.assertIsNone(category)

    def test_returns_none_if_category_not_found_by_name(self):
        category = self.db.getCategory(name="noSuchCategory")
        self.assertIsNone(category)

    def test_can_add_and_retrieve_categories(self):
        category_id = self.db.addCategory(name="newcat", order=4)

        # confirm that we now have four categories
        categories = self.db.getCategoriesAll()
        self.assertEqual(len(categories), 4)

        # and confirm that we can retrieve this one by name
        category = self.db.getCategory(name="newcat")
        self.assertEqual(category._id, 4)
        self.assertEqual(category.order, 4)

        # and confirm that we can retrieve this one by id
        category = self.db.getCategory(_id=4)
        self.assertEqual(category.name, "newcat")
        self.assertEqual(category.order, 4)

    def test_can_start_adding_but_rollback_category(self):
        category_id = self.db.addCategory(name="will rollback",
                                          order=99,
                                          commit=False)
        self.db.rollback()
        # confirm that we still only have three categories
        categories = self.db.getCategoriesAll()
        self.assertEqual(len(categories), 3)
        # and confirm that this category ID doesn't exist in database
        category = self.db.getCategory(_id=category_id)
        self.assertIsNone(category)

    def test_can_start_adding_and_then_commit_categories(self):
        c1_id = self.db.addCategory(name="newc1", order=98, commit=False)
        c2_id = self.db.addCategory(name="newc2", order=99, commit=False)
        self.db.commit()
        # confirm that we now have five categories
        categories = self.db.getCategoriesAll()
        self.assertEqual(len(categories), 5)

    def test_omitting_order_from_new_category_places_it_at_end(self):
        category_id = self.db.addCategory(name="newcat")
        category = self.db.getCategory(name="newcat")
        self.assertEqual(category.order, 4)

    def test_cannot_create_category_with_existing_order(self):
        with self.assertRaises(ProjectDBInsertError):
            self.db.addCategory(name="duplicate order", order=3)

    def test_can_get_highest_category_order(self):
        highestOrder = self.db.getCategoryHighestOrder()
        self.assertEqual(highestOrder, 3)

    def test_highest_order_works_even_with_no_categories(self):
        newdb = ProjectDB()
        newdb.createDB(":memory:")
        newdb.initializeDBTables()
        highestOrder = newdb.getCategoryHighestOrder()
        self.assertEqual(highestOrder, 0)

    def test_can_edit_category_name(self):
        self.db.changeCategoryName(name="a category",
                                   newName="another category")
        category = self.db.getCategory(name="another category")
        self.assertEqual(category._id, 1)

    def test_cannot_edit_category_name_that_does_not_exist(self):
        with self.assertRaises(ProjectDBUpdateError):
            self.db.changeCategoryName(name="invalid",
                                       newName="this will fail")

    def test_cannot_change_category_name_to_existing_name(self):
        with self.assertRaises(ProjectDBUpdateError):
            self.db.changeCategoryName(name="a category",
                                       newName="blah category")

    def test_can_reorder_categories_from_higher_to_lower(self):
        self.db.changeCategoryOrder(name="a category",
                                    sortBefore="blah category")
        categories = self.db.getCategoriesAll()
        self.assertEqual(categories[0].name, "a category")
        self.assertEqual(categories[1].name, "blah category")
        self.assertEqual(categories[2].name, "cat of crazy licenses")

    def test_can_reorder_categories_from_lower_to_higher(self):
        self.db.changeCategoryOrder(name="blah category",
                                    sortBefore="a category")
        categories = self.db.getCategoriesAll()
        self.assertEqual(categories[0].name, "cat of crazy licenses")
        self.assertEqual(categories[1].name, "blah category")
        self.assertEqual(categories[2].name, "a category")

    def test_cannot_reorder_category_name_before_one_that_does_not_exist(self):
        with self.assertRaises(ProjectDBUpdateError):
            self.db.changeCategoryOrder(name="a category", sortBefore="oops")

    def test_cannot_reorder_category_name_that_does_not_exist(self):
        with self.assertRaises(ProjectDBUpdateError):
            self.db.changeCategoryOrder(name="oops", sortBefore="a category")

    def test_cannot_create_category_with_order_less_than_one(self):
        with self.assertRaises(ProjectDBInsertError):
            self.db.addCategory(name="need positive order", order=0)
 def test_highest_order_works_even_with_no_categories(self):
     newdb = ProjectDB()
     newdb.createDB(":memory:")
     newdb.initializeDBTables()
     highestOrder = newdb.getCategoryHighestOrder()
     self.assertEqual(highestOrder, 0)
class DBConversionUnitTestSuite(unittest.TestCase):
  """spdxLicenseManager unit test suite for converting license names in DB."""

  def setUp(self):
    # create and initialize an in-memory database
    self.db = ProjectDB()
    self.db.createDB(":memory:")
    self.db.initializeDBTables()

    # insert sample data
    self.insertSampleCategoryData()
    self.insertSampleLicenseData()
    self.insertSampleConversionData()

  def tearDown(self):
    self.db.closeDB()
    self.db = None

  def insertSampleCategoryData(self):
    categories = [
      Category(_id=1, name="a category", order=3),
      Category(_id=2, name="cat", order=2),
      Category(_id=3, name="blah category", order=1),
    ]
    self.db.session.bulk_save_objects(categories)
    self.db.session.commit()

  def insertSampleLicenseData(self):
    licenses = [
      License(_id=1, name="DoAnything", category_id=1),
      License(_id=2, name="HarshEULA", category_id=2),
      License(_id=3, name="293PageEULA", category_id=3),
      License(_id=4, name="DoAnythingNoncommercial", category_id=1),
    ]
    self.db.session.bulk_save_objects(licenses)
    self.db.session.commit()

  def insertSampleConversionData(self):
    conversions = [
      Conversion(_id=1, old_text="293", new_license_id=3),
      Conversion(_id=2, old_text="NC", new_license_id=4),
      Conversion(_id=3, old_text="anything", new_license_id=1),
      Conversion(_id=4, old_text="Anything", new_license_id=1),
    ]
    self.db.session.bulk_save_objects(conversions)
    self.db.session.commit()

  ##### Test cases below

  def test_can_retrieve_one_conversion_by_id(self):
    conversion = self.db.getConversion(_id=2)
    self.assertEqual(conversion.old_text, "NC")
    self.assertEqual(conversion.new_license_id, 4)
    self.assertEqual(conversion.new_license._id, 4)
    self.assertEqual(conversion.new_license.name, "DoAnythingNoncommercial")

  def test_can_retrieve_one_conversion_by_name(self):
    conversion = self.db.getConversion(old_text="293")
    self.assertEqual(conversion._id, 1)

  def test_cannot_retrieve_conversion_by_both_name_and_id(self):
    with self.assertRaises(ProjectDBQueryError):
      self.db.getConversion(_id=3, old_text="anything")

  def test_cannot_retrieve_conversion_without_either_name_or_id(self):
    with self.assertRaises(ProjectDBQueryError):
      self.db.getConversion()

  def test_cannot_retrieve_conversion_with_positional_args(self):
    with self.assertRaises(TypeError):
      self.db.getConversion("NC")

  def test_returns_none_if_conversion_not_found_by_id(self):
    conversion = self.db.getConversion(_id=17)
    self.assertIsNone(conversion)

  def test_returns_none_if_conversion_not_found_by_name(self):
    conversion = self.db.getConversion(old_text="noSuchConversion")
    self.assertIsNone(conversion)

  def test_can_add_and_retrieve_conversions(self):
    conv_id = self.db.addConversion(old_text="harsh", new_license="HarshEULA")

    # confirm that we now have five conversions
    convs = self.db.getConversionsAll()
    self.assertEqual(len(convs), 5)

    # and confirm that we can retrieve this one by its text
    conv = self.db.getConversion(old_text="harsh")
    self.assertEqual(conv._id, 5)
    self.assertEqual(conv.new_license_id, 2)
    self.assertIsNotNone(conv.new_license)
    self.assertEqual(conv.new_license.name, "HarshEULA")

    # and confirm that we can retrieve this one by id
    conv = self.db.getConversion(_id=5)
    self.assertEqual(conv.old_text, "harsh")
    self.assertEqual(conv.new_license_id, 2)

  def test_can_start_adding_but_rollback_conversion(self):
    conv_id = self.db.addConversion(old_text="will rollback",
      new_license="293PageEULA", commit=False)
    self.db.rollback()
    # confirm that we still only have four conversions
    convs = self.db.getConversionsAll()
    self.assertEqual(len(convs), 4)
    # and confirm that this conversion ID doesn't exist in database
    conv = self.db.getConversion(_id=5)
    self.assertIsNone(conv)

  def test_can_start_adding_and_then_commit_conversions(self):
    c1_id = self.db.addConversion(old_text="c1", new_license="293PageEULA",
      commit=False)
    c2_id = self.db.addConversion(old_text="c2", new_license="293PageEULA",
      commit=False)
    self.db.commit()
    # confirm that we now have six conversions
    convs = self.db.getConversionsAll()
    self.assertEqual(len(convs), 6)

  def test_cannot_add_conversion_without_license(self):
    with self.assertRaises(TypeError):
      self.db.addConversion(old_text="oops")
    # confirm it wasn't added either
    conv = self.db.getConversion(old_text="oops")
    self.assertIsNone(conv)

  def test_cannot_add_conversion_without_existing_license(self):
    with self.assertRaises(ProjectDBInsertError):
      self.db.addConversion(old_text="oops", new_license="blah")
    # confirm it wasn't added either
    conv = self.db.getConversion(old_text="oops")
    self.assertIsNone(conv)

  def test_cannot_add_conversion_with_duplicate_name(self):
    with self.assertRaises(ProjectDBInsertError):
      self.db.addConversion(old_text="NC", new_license="293PageEULA")

  def test_can_edit_conversion_license(self):
    self.db.changeConversion(old_text="NC", new_license="DoAnything")
    conv = self.db.getConversion(old_text="NC")
    self.assertEqual(conv.new_license_id, 1)

  def test_cannot_edit_conversion_name_that_does_not_exist(self):
    with self.assertRaises(ProjectDBUpdateError):
      self.db.changeConversion(old_text="invalid", new_license="will fail")

  def test_can_retrieve_all_conversions(self):
    convs = self.db.getConversionsAll()
    self.assertIsInstance(convs, list)
    self.assertEqual(len(convs), 4)
    self.assertIsInstance(convs[0], Conversion)
    # will sort alphabetically
    self.assertEqual(convs[2]._id, 2)
    self.assertEqual(convs[2].old_text, "NC")
class TVImporterTestSuite(unittest.TestCase):
  """spdxLicenseManager SPDX tag-value importer unit test suite."""

  def setUp(self):
    # create importer object
    self.importer = TVImporter()

    # create and initialize an in-memory database
    self.db = ProjectDB()
    self.db.createDB(":memory:")
    self.db.initializeDBTables()

    # insert sample data
    self.insertSampleCategoryData()
    self.insertSampleLicenseData()
    self.insertSampleConversionData()
    self.insertSampleSubprojectData()
    self.insertSampleScanData()

    # build sample file data list
    self.fd1 = createFD("/tmp/f1", "DoAnything", md5="abcdef")
    self.fd2 = createFD("/tmp/f2", "DoAnythingNoncommercial", sha256="abcdef")
    self.fd3 = createFD("/tmp/f3", "HarshEULA", sha1="abcdef")
    self.fd4 = createFD("/tmp/f4", "HarshEULA")
    self.fdList = [self.fd1, self.fd2, self.fd3, self.fd4]
    # not in fdList by default
    self.fd5 = createFD("/tmp/badLicense", "UnknownLicense")
    self.fd6 = createFD("/tmp/badLic2", "SecondUnknownLic")
    self.fdConvert = createFD("/tmp/needsConvert", "293")

  def tearDown(self):
    pass

  def insertSampleCategoryData(self):
    categories = [
      Category(_id=1, name="a category", order=3),
      Category(_id=2, name="cat", order=2),
      Category(_id=3, name="blah category", order=1),
    ]
    self.db.session.bulk_save_objects(categories)
    self.db.session.commit()

  def insertSampleLicenseData(self):
    licenses = [
      License(_id=1, name="DoAnything", category_id=1),
      License(_id=2, name="HarshEULA", category_id=2),
      License(_id=3, name="293PageEULA", category_id=3),
      License(_id=4, name="DoAnythingNoncommercial", category_id=1),
    ]
    self.db.session.bulk_save_objects(licenses)
    self.db.session.commit()

  def insertSampleConversionData(self):
    conversions = [
      Conversion(_id=1, old_text="293", new_license_id=3),
      Conversion(_id=2, old_text="NC", new_license_id=4),
      Conversion(_id=3, old_text="anything", new_license_id=1),
      Conversion(_id=4, old_text="Anything", new_license_id=1),
    ]
    self.db.session.bulk_save_objects(conversions)
    self.db.session.commit()

  def insertSampleSubprojectData(self):
    subprojects = [
      Subproject(_id=1, name="sub1", desc="subproject 1"),
    ]
    self.db.session.bulk_save_objects(subprojects)
    self.db.session.commit()

  def insertSampleScanData(self):
    scans = [
      Scan(_id=1, subproject_id=1, scan_dt=datetime.date(2017, 1, 10),
        desc="new scan"),
    ]
    self.db.session.bulk_save_objects(scans)
    self.db.session.commit()
    self.scan_id = 1

  ##### Test cases below

  def test_new_importer_is_in_expected_reset_state(self):
    self.assertEqual(self.importer.scanChecked, False)
    self.assertEqual(self.importer.licensesAll, [])
    self.assertEqual(self.importer.licensesUnknown, [])
    self.assertEqual(self.importer.licensesMapping, {})
    self.assertEqual(self.importer.pathDuplicates, [])
    self.assertEqual(self.importer.importedCount, 0)

  def test_import_fails_if_scan_not_checked_first(self):
    with self.assertRaises(ProjectDBInsertError):
      self.importer.importFileDataList(fdList=self.fdList, db=self.db,
        scan_id=self.scan_id)

  def test_cannot_check_without_providing_valid_fdList(self):
    with self.assertRaises(ProjectDBInsertError):
      self.importer.checkFileDataList(db=self.db)

  def test_cannot_check_without_providing_database(self):
    with self.assertRaises(ProjectDBInsertError):
      self.importer.checkFileDataList(fdList=self.fdList)

  def test_checking_valid_fdList_returns_true(self):
    retval = self.importer.checkFileDataList(fdList=self.fdList, db=self.db)
    self.assertEqual(True, retval)

  def test_checker_returns_false_if_any_licenses_are_unknown(self):
    self.fdList.append(self.fd5)
    retval = self.importer.checkFileDataList(fdList=self.fdList, db=self.db)
    self.assertEqual(False, retval)

  def test_can_get_license_list_if_any_are_unknown(self):
    self.fdList.append(self.fd5)
    self.importer.checkFileDataList(fdList=self.fdList, db=self.db)
    unknowns = self.importer.getUnknowns()
    self.assertIn("UnknownLicense", unknowns)
    self.assertNotIn("DoAnything", unknowns)
    self.assertNotIn("HarshEULA", unknowns)

  def test_license_list_is_sorted_if_multiple_are_unknown(self):
    self.fdList.append(self.fd5)
    self.fdList.append(self.fd6)
    self.importer.checkFileDataList(fdList=self.fdList, db=self.db)
    unknowns = self.importer.getUnknowns()
    self.assertEqual("SecondUnknownLic", unknowns[0])
    self.assertEqual("UnknownLicense", unknowns[1])

  def test_checker_returns_true_if_all_paths_are_unique(self):
    retval = self.importer.checkFileDataList(fdList=self.fdList, db=self.db)
    self.assertEqual(True, retval)

  def test_checker_returns_false_if_any_paths_are_duplicates(self):
    fdup = createFD("/tmp/f2", "DoAnythingNoncommercial", sha256="abcdef")
    self.fdList.append(fdup)
    retval = self.importer.checkFileDataList(fdList=self.fdList, db=self.db)
    self.assertEqual(False, retval)

  def test_duplicates_list_is_empty_if_all_paths_are_unique(self):
    self.importer.checkFileDataList(fdList=self.fdList, db=self.db)
    dups = self.importer.getDuplicatePaths()
    self.assertEqual([], dups)

  def test_duplicates_list_has_paths_if_any_paths_are_duplicates(self):
    fdup = createFD("/tmp/f2", "DoAnythingNoncommercial", sha256="abcdef")
    self.fdList.append(fdup)
    self.importer.checkFileDataList(fdList=self.fdList, db=self.db)
    dups = self.importer.getDuplicatePaths()
    self.assertEqual(["/tmp/f2"], dups)

  def test_can_get_duplicate_paths_after_checker_if_any(self):
    fdup = createFD("/tmp/f2", "DoAnythingNoncommercial", sha256="abcdef")
    self.fdList.append(fdup)
    retval = self.importer.checkFileDataList(fdList=self.fdList, db=self.db)
    dups = self.importer.getDuplicatePaths()
    self.assertIn("/tmp/f2", dups)
    self.assertNotIn("/tmp/f1", dups)

  def test_checker_returns_true_if_all_is_good(self):
    retval = self.importer.checkFileDataList(fdList=self.fdList, db=self.db)
    self.assertEqual(True, retval)

  def test_reads_licenses_into_licensesAll(self):
    # fill in finalLicense, since we are skipping _applyConversions
    for fd in self.fdList:
      fd.finalLicense = fd.license
    self.importer._checkFileDataListForLicenses(fdList=self.fdList, db=self.db)
    self.assertIn("DoAnything", self.importer.licensesAll)

  def test_reads_only_unknown_licenses_into_licensesUnknown(self):
    self.fdList.append(self.fd5)
    # fill in finalLicense, since we are skipping _applyConversions
    for fd in self.fdList:
      fd.finalLicense = fd.license
    self.importer._checkFileDataListForLicenses(fdList=self.fdList, db=self.db)
    self.assertIn("UnknownLicense", self.importer.licensesUnknown)
    self.assertNotIn("DoAnything", self.importer.licensesUnknown)

  def test_reads_only_known_licenses_into_licensesMapping(self):
    self.fdList.append(self.fd5)
    # fill in finalLicense, since we are skipping _applyConversions
    for fd in self.fdList:
      fd.finalLicense = fd.license
    self.importer._checkFileDataListForLicenses(fdList=self.fdList, db=self.db)
    self.assertEqual(1, self.importer.licensesMapping.get("DoAnything", None))
    self.assertEqual(2, self.importer.licensesMapping.get("HarshEULA", None))
    self.assertEqual(None, self.importer.licensesMapping.get("UnknownLicense", None))

  def test_checker_returns_true_if_all_licenses_are_known(self):
    # fill in finalLicense, since we are skipping _applyConversions
    for fd in self.fdList:
      fd.finalLicense = fd.license
    retval = self.importer._checkFileDataListForLicenses(fdList=self.fdList,
      db=self.db)
    self.assertEqual(True, retval)

  def test_checker_returns_false_if_any_licenses_are_unknown(self):
    # fill in finalLicense, since we are skipping _applyConversions
    for fd in self.fdList:
      fd.finalLicense = fd.license
    self.fdList.append(self.fd5)
    retval = self.importer._checkFileDataListForLicenses(fdList=self.fdList,
      db=self.db)
    self.assertEqual(False, retval)

  def test_cannot_import_without_providing_valid_fdList(self):
    self.importer.checkFileDataList(fdList=self.fdList, db=self.db)
    with self.assertRaises(ProjectDBInsertError):
      self.importer.importFileDataList(db=self.db, scan_id=self.scan_id)

  def test_cannot_import_without_providing_database(self):
    self.importer.checkFileDataList(fdList=self.fdList, db=self.db)
    with self.assertRaises(ProjectDBInsertError):
      self.importer.importFileDataList(fdList=self.fdList,
        scan_id=self.scan_id)

  def test_cannot_import_without_providing_scan_id(self):
    self.importer.checkFileDataList(fdList=self.fdList, db=self.db)
    with self.assertRaises(ProjectDBInsertError):
      self.importer.importFileDataList(fdList=self.fdList, db=self.db)

  def test_cannot_import_with_positional_args(self):
    self.importer.checkFileDataList(fdList=self.fdList, db=self.db)
    with self.assertRaises(TypeError):
      self.importer.importFileDataList(self.fdList)
    with self.assertRaises(TypeError):
      self.importer.importFileDataList(self.fdList, self.db)
    with self.assertRaises(TypeError):
      self.importer.importFileDataList(self.fdList, self.db, self.scan_id)

  def test_checker_returns_true_if_all_paths_are_unique(self):
    retval = self.importer._checkFileDataListForDuplicatePaths(fdList=self.fdList)
    self.assertEqual(True, retval)

  def test_checker_returns_false_if_any_paths_are_duplicates(self):
    fdup = createFD("/tmp/f2", "DoAnythingNoncommercial", sha256="abcdef")
    self.fdList.append(fdup)
    retval = self.importer._checkFileDataListForDuplicatePaths(fdList=self.fdList)
    self.assertEqual(False, retval)

  def test_files_are_imported_if_all_is_good(self):
    self.importer.checkFileDataList(fdList=self.fdList, db=self.db)
    retval = self.importer.importFileDataList(fdList=self.fdList, db=self.db,
      scan_id=self.scan_id)
    self.assertEqual(True, retval)
    f1 = self.db.getFile(scan_id=self.scan_id, path="/tmp/f1")
    self.assertEqual("/tmp/f1", f1.path)
    self.assertEqual("abcdef", f1.md5)
    self.assertEqual("DoAnything", f1.license.name)
    f4 = self.db.getFile(scan_id=self.scan_id, path="/tmp/f4")
    self.assertEqual("/tmp/f4", f4.path)
    self.assertEqual(None, f4.md5)
    self.assertEqual("HarshEULA", f4.license.name)

  def test_can_get_count_of_imported_files_if_all_licenses_are_known(self):
    self.importer.checkFileDataList(fdList=self.fdList, db=self.db)
    self.importer.importFileDataList(fdList=self.fdList, db=self.db,
      scan_id=self.scan_id)
    count = self.importer.getImportedCount()
    self.assertEqual(4, count)

  def test_files_are_not_imported_if_any_licenses_are_unknown(self):
    self.fdList.append(self.fd5)
    self.importer.checkFileDataList(fdList=self.fdList, db=self.db)
    with self.assertRaises(ProjectDBInsertError):
      self.importer.importFileDataList(fdList=self.fdList, db=self.db,
        scan_id=self.scan_id)
    f1 = self.db.getFile(scan_id=self.scan_id, path="/tmp/f1")
    self.assertIsNone(f1)

  def test_checker_applies_conversions(self):
    self.fdList.append(self.fdConvert)
    retval = self.importer.checkFileDataList(fdList=self.fdList, db=self.db)
    self.assertTrue(retval)
    self.assertEqual("293PageEULA", self.fdConvert.finalLicense)

  def test_path_prefixes_are_stripped_if_config_is_yes(self):
    self.db.setConfigValue("import-strip-path-prefixes", "Yes")
    prefix = self.importer._applyPathPrefixStrip(fdList=self.fdList,
      db=self.db)
    self.assertEqual("/tmp", prefix)
    self.assertEqual("/tmp/f1", self.fd1.path)
    self.assertEqual("/f1", self.fd1.finalPath)

  def test_path_prefixes_are_not_stripped_if_config_is_no(self):
    self.db.setConfigValue("import-strip-path-prefixes", "no")
    prefix = self.importer._applyPathPrefixStrip(fdList=self.fdList,
      db=self.db)
    self.assertEqual("", prefix)
    self.assertEqual("/tmp/f1", self.fd1.path)
    self.assertEqual("/tmp/f1", self.fd1.finalPath)

  def test_path_prefixes_are_not_stripped_if_config_is_not_set(self):
    prefix = self.importer._applyPathPrefixStrip(fdList=self.fdList,
      db=self.db)
    self.assertEqual("", prefix)
    self.assertEqual("/tmp/f1", self.fd1.path)
    self.assertEqual("/tmp/f1", self.fd1.finalPath)

  def test_path_prefixes_are_not_stripped_if_mixing_abs_and_rel_paths(self):
    self.db.setConfigValue("import-strip-path-prefixes", "yes")
    self.fdDifferentPath = createFD("absolutePath", "293PageEULA")
    self.fdList.append(self.fdDifferentPath)
    prefix = self.importer._applyPathPrefixStrip(fdList=self.fdList,
      db=self.db)
    self.assertEqual("", prefix)
    self.assertEqual("/tmp/f1", self.fd1.path)
    self.assertEqual("/tmp/f1", self.fd1.finalPath)

  def test_path_prefixes_are_not_stripped_if_no_common_prefix(self):
    self.db.setConfigValue("import-strip-path-prefixes", "yes")
    fdDifferentPath1 = createFD("somewhereElse", "293PageEULA")
    fdDifferentPath2 = createFD("something", "293PageEULA")
    tmpFDList = [fdDifferentPath1, fdDifferentPath2]
    prefix = self.importer._applyPathPrefixStrip(fdList=tmpFDList,
      db=self.db)
    self.assertEqual("", prefix)
    self.assertEqual("somewhereElse", fdDifferentPath1.finalPath)
    self.assertEqual("something", fdDifferentPath2.finalPath)

  def test_file_path_prefixes_are_stripped_on_import_if_configured(self):
    self.db.setConfigValue("import-strip-path-prefixes", "yes")
    self.importer.checkFileDataList(fdList=self.fdList, db=self.db)
    retval = self.importer.importFileDataList(fdList=self.fdList, db=self.db,
      scan_id=self.scan_id)
    self.assertEqual(True, retval)
    f1 = self.db.getFile(scan_id=self.scan_id, path="/f1")
    self.assertEqual("/f1", f1.path)
    self.assertEqual("DoAnything", f1.license.name)
    f4 = self.db.getFile(scan_id=self.scan_id, path="/f4")
    self.assertEqual("/f4", f4.path)
    self.assertEqual("HarshEULA", f4.license.name)
    wrongPathFile = self.db.getFile(scan_id=self.scan_id, path="/tmp/f1")
    self.assertIsNone(wrongPathFile)
class ReportAnalysisTestSuite(unittest.TestCase):
    """spdxLicenseManager analysis for reporting unit test suite."""
    def setUp(self):
        # create and initialize an in-memory database
        self.db = ProjectDB()
        self.db.createDB(":memory:")
        self.db.initializeDBTables()

        # insert sample data
        self.insertSampleCategoryData()
        self.insertSampleLicenseData()
        self.insertSampleSubprojectData()
        self.insertSampleScanData()
        self.insertSampleFileData()

        # create analyzer
        self.analyzer = Analyzer(db=self.db)

    def tearDown(self):
        pass

    def insertSampleCategoryData(self):
        categories = [
            Category(_id=1, name="a category", order=3),
            Category(_id=2, name="cat", order=2),
            Category(_id=3, name="blah category", order=1),
            Category(_id=4, name="no lic category", order=4),
        ]
        self.db.session.bulk_save_objects(categories)
        self.db.session.commit()

    def insertSampleLicenseData(self):
        licenses = [
            License(_id=1, name="DoAnything", category_id=1),
            License(_id=2, name="HarshEULA", category_id=2),
            License(_id=3, name="293PageEULA", category_id=3),
            License(_id=4, name="DoAnythingNoncommercial", category_id=1),
            License(_id=5, name="No license found", category_id=4),
            License(_id=6, name="Also no license found", category_id=4),
            License(_id=7, name="LicWithNoFiles", category_id=4),
        ]
        self.db.session.bulk_save_objects(licenses)
        self.db.session.commit()

    def insertSampleSubprojectData(self):
        subprojects = [
            Subproject(_id=1, name="sub1", desc="subproject 1"),
        ]
        self.db.session.bulk_save_objects(subprojects)
        self.db.session.commit()

    def insertSampleScanData(self):
        scans = [
            Scan(_id=1,
                 subproject_id=1,
                 scan_dt=datetime.date(2017, 1, 10),
                 desc="new scan"),
            Scan(_id=2,
                 subproject_id=1,
                 scan_dt=datetime.date(2017, 2, 10),
                 desc="monthly scan 2"),
            Scan(_id=3,
                 subproject_id=1,
                 scan_dt=datetime.date(2017, 3, 10),
                 desc="monthly scan 3"),
        ]
        self.db.session.bulk_save_objects(scans)
        self.db.session.commit()

    def insertSampleFileData(self):
        self.f1 = File(_id=1,
                       scan_id=1,
                       license_id=1,
                       path="/tmp/f1",
                       sha1=None,
                       md5="abcdef",
                       sha256=None)
        self.f2 = File(_id=2,
                       scan_id=1,
                       license_id=4,
                       path="/tmp/f2",
                       sha1=None,
                       md5=None,
                       sha256="abcdef")
        self.f3 = File(_id=3,
                       scan_id=1,
                       license_id=2,
                       path="/tmp/f3",
                       sha1="abcdef",
                       md5=None,
                       sha256=None)
        self.f4 = File(_id=4,
                       scan_id=1,
                       license_id=2,
                       path="/tmp/f4",
                       sha1=None,
                       md5=None,
                       sha256=None)
        self.f5 = File(_id=5,
                       scan_id=1,
                       license_id=5,
                       path="/tmp/nolic/image.png",
                       sha1=None,
                       md5=None,
                       sha256=None)
        self.f6 = File(_id=6,
                       scan_id=1,
                       license_id=2,
                       path="/tmp/nolic/vendor/whatever",
                       sha1=None,
                       md5=None,
                       sha256=None)
        self.f7 = File(_id=7,
                       scan_id=1,
                       license_id=6,
                       path="/tmp/nolic/vendor/image-both.png",
                       sha1=None,
                       md5=None,
                       sha256=None)
        self.f8 = File(_id=8,
                       scan_id=1,
                       license_id=6,
                       path="/tmp/nolic/emptyfile",
                       sha1=None,
                       md5="d41d8cd98f00b204e9800998ecf8427e",
                       sha256=None)
        self.f9 = File(_id=9,
                       scan_id=1,
                       license_id=6,
                       path="/tmp/nolic/vendor/emptyfile",
                       sha1=None,
                       md5="d41d8cd98f00b204e9800998ecf8427e",
                       sha256=None)
        self.f10 = File(_id=10,
                        scan_id=1,
                        license_id=6,
                        path="/tmp/nolic/emptyfile.png",
                        sha1=None,
                        md5="d41d8cd98f00b204e9800998ecf8427e",
                        sha256=None)
        self.f11 = File(_id=11,
                        scan_id=1,
                        license_id=6,
                        path="/tmp/nolic/vendor/emptyfile.json",
                        sha1=None,
                        md5="d41d8cd98f00b204e9800998ecf8427e",
                        sha256=None)
        self.f21 = File(_id=21,
                        scan_id=2,
                        license_id=1,
                        path="/scan2/tmp/f1",
                        sha1=None,
                        md5="abcdef",
                        sha256=None)
        self.f22 = File(_id=22,
                        scan_id=2,
                        license_id=4,
                        path="/scan2/tmp/f2",
                        sha1=None,
                        md5=None,
                        sha256="abcdef")
        self.f23 = File(_id=23,
                        scan_id=2,
                        license_id=3,
                        path="/scan2/tmp/f3-lic3",
                        sha1="abcdef",
                        md5=None,
                        sha256=None)
        self.f24 = File(_id=24,
                        scan_id=2,
                        license_id=2,
                        path="/scan2/tmp/f4",
                        sha1=None,
                        md5=None,
                        sha256=None)
        self.f31 = File(_id=31,
                        scan_id=3,
                        license_id=1,
                        path="/scan3/tmp/f1",
                        sha1=None,
                        md5="abcdef",
                        sha256=None)
        self.f32 = File(_id=32,
                        scan_id=3,
                        license_id=4,
                        path="/scan3/tmp/f2",
                        sha1=None,
                        md5=None,
                        sha256="abcdef")
        self.f33 = File(_id=33,
                        scan_id=3,
                        license_id=2,
                        path="/scan3/tmp/f3",
                        sha1="abcdef",
                        md5=None,
                        sha256=None)
        self.f34 = File(_id=34,
                        scan_id=3,
                        license_id=2,
                        path="/scan3/tmp/f4",
                        sha1=None,
                        md5=None,
                        sha256=None)
        self.files = [
            self.f1,
            self.f2,
            self.f3,
            self.f4,
            self.f5,
            self.f6,
            self.f7,
            self.f8,
            self.f9,
            self.f10,
            self.f11,
            self.f21,
            self.f22,
            self.f23,
            self.f24,
            self.f31,
            self.f32,
            self.f33,
            self.f34,
        ]
        self.db.session.bulk_save_objects(self.files)
        self.db.session.commit()

    ##### Helpers for tests

    def _checkFileExtFindingIsNone(self, file_id):
        ext = self.analyzer._getFile(file_id).findings.get("extension", None)
        self.assertIsNone(ext)

    def _checkFileExtFindingIsYes(self, file_id):
        ext = self.analyzer._getFile(file_id).findings.get("extension", None)
        self.assertEqual("yes", ext)

    def _checkFileEmptyFindingIsNone(self, file_id):
        empty = self.analyzer._getFile(file_id).findings.get("emptyfile", None)
        self.assertIsNone(empty)

    def _checkFileEmptyFindingIsYes(self, file_id):
        empty = self.analyzer._getFile(file_id).findings.get("emptyfile", None)
        self.assertEqual("yes", empty)

    def _checkFileDirFindingIsNone(self, file_id):
        tp = self.analyzer._getFile(file_id).findings.get("thirdparty", None)
        self.assertIsNone(tp)

    def _checkFileDirFindingIsYes(self, file_id):
        tp = self.analyzer._getFile(file_id).findings.get("thirdparty", None)
        self.assertEqual("yes", tp)

    ##### Test cases below

    def test_analyzer_is_in_reset_state(self):
        self.assertEqual(self.db, self.analyzer.db)
        self.assertFalse(self.analyzer.isReady)
        self.assertIsNone(self.analyzer.primaryScan)
        self.assertEqual(OrderedDict(), self.analyzer.primaryScanCategories)
        self.assertEqual({}, self.analyzer.kwConfig)
        self.assertFalse(self.analyzer.analysisDone)

    def test_analyzer_retrieves_all_categories_for_report(self):
        self.analyzer._buildScanCategories()
        self.assertEqual(len(self.analyzer.primaryScanCategories), 4)

    def test_analyzer_still_not_ready_after_just_buildScanCategories(self):
        self.analyzer._buildScanCategories()
        self.assertFalse(self.analyzer.isReady)

    def test_analyzer_cannot_call_buildScanCategories_twice(self):
        self.analyzer._buildScanCategories()
        with self.assertRaises(ReportAnalysisError):
            self.analyzer._buildScanCategories()

    def test_analyzer_builds_categories_with_OD_for_licenses(self):
        self.analyzer._buildScanCategories()
        for cat in self.analyzer.primaryScanCategories.values():
            self.assertIs(type(cat.licensesSorted), OrderedDict)
        c1 = self.analyzer.primaryScanCategories[1]
        l1 = c1.licensesSorted[1]
        self.assertEqual(l1._id, 1)
        self.assertEqual(l1.name, "DoAnything")
        l4 = c1.licensesSorted[4]
        self.assertEqual(l4._id, 4)
        self.assertEqual(l4.name, "DoAnythingNoncommercial")
        # and it doesn't have licenses from a different category
        with self.assertRaises(KeyError):
            c1.licensesSorted[2]

    def test_analyzer_builds_categories_OD_in_sort_order(self):
        self.analyzer._buildScanCategories()
        (c_id1, c1) = self.analyzer.primaryScanCategories.popitem(last=False)
        self.assertEqual(3, c_id1)
        self.assertEqual("blah category", c1.name)
        (c_id2, c2) = self.analyzer.primaryScanCategories.popitem(last=False)
        self.assertEqual(2, c_id2)
        self.assertEqual("cat", c2.name)
        (c_id3, c3) = self.analyzer.primaryScanCategories.popitem(last=False)
        self.assertEqual(1, c_id3)
        self.assertEqual("a category", c3.name)

    ##### Analyzer adding files tests

    def test_analyzer_cannot_add_files_before_categories_are_built(self):
        with self.assertRaises(ReportAnalysisError):
            self.analyzer._addFiles(scan_id=1)

    def test_analyzer_cannot_add_files_from_invalid_scan_id(self):
        self.analyzer._buildScanCategories()
        with self.assertRaises(ReportAnalysisError):
            self.analyzer._addFiles(scan_id=187)

    def test_analyzer_can_add_files_to_categories_for_a_scan(self):
        self.analyzer._buildScanCategories()
        self.analyzer._addFiles(scan_id=1)

        # check category 1, with one license and NO FILES
        (c_id1, c1) = self.analyzer.primaryScanCategories.popitem(last=False)
        self.assertEqual("blah category", c1.name)
        (l_id11, l11) = c1.licensesSorted.popitem(last=False)
        self.assertEqual("293PageEULA", l11.name)
        self.assertEqual([], list(l11.filesSorted.items()))

        # check category 2, with one license and three files
        (c_id2, c2) = self.analyzer.primaryScanCategories.popitem(last=False)
        self.assertEqual("cat", c2.name)
        (l_id21, l21) = c2.licensesSorted.popitem(last=False)
        self.assertEqual("HarshEULA", l21.name)
        self.assertEqual(len(l21.filesSorted), 3)
        (f_id211, f211) = l21.filesSorted.popitem(last=False)
        self.assertEqual(f_id211, 3)
        self.assertEqual(f211.path, "/tmp/f3")
        self.assertEqual(f211.findings, {})
        (f_id212, f212) = l21.filesSorted.popitem(last=False)
        self.assertEqual(f_id212, 4)
        self.assertEqual(f212.path, "/tmp/f4")
        self.assertEqual(f212.findings, {})
        (f_id216, f216) = l21.filesSorted.popitem(last=False)
        self.assertEqual(f_id216, 6)
        self.assertEqual(f216.path, "/tmp/nolic/vendor/whatever")
        self.assertEqual(f216.findings, {})  # haven't run analysis yet

        # check category 3, with two licenses and two files
        (c_id3, c3) = self.analyzer.primaryScanCategories.popitem(last=False)
        self.assertEqual("a category", c3.name)
        (l_id31, l31) = c3.licensesSorted.popitem(last=False)
        self.assertEqual("DoAnything", l31.name)
        self.assertEqual(len(l31.filesSorted), 1)
        (f_id311, f311) = l31.filesSorted.popitem(last=False)
        self.assertEqual(f_id311, 1)
        self.assertEqual(f311.path, "/tmp/f1")
        self.assertEqual(f311.findings, {})
        (l_id32, l32) = c3.licensesSorted.popitem(last=False)
        self.assertEqual("DoAnythingNoncommercial", l32.name)
        self.assertEqual(len(l32.filesSorted), 1)
        (f_id321, f321) = l32.filesSorted.popitem(last=False)
        self.assertEqual(f_id321, 2)
        self.assertEqual(f321.path, "/tmp/f2")
        self.assertEqual(f321.findings, {})

    def test_can_add_files_from_multiple_scans(self):
        self.analyzer._buildScanCategories()
        self.analyzer._addFiles(scan_id=1)
        self.analyzer._addFiles(scan_id=3)

        # check category 1, with one license and still NO FILES
        (c_id1, c1) = self.analyzer.primaryScanCategories.popitem(last=False)
        self.assertEqual("blah category", c1.name)
        (l_id11, l11) = c1.licensesSorted.popitem(last=False)
        self.assertEqual("293PageEULA", l11.name)
        self.assertEqual([], list(l11.filesSorted.items()))

        # check category 2, with one license and now five files
        (c_id2, c2) = self.analyzer.primaryScanCategories.popitem(last=False)
        self.assertEqual("cat", c2.name)
        (l_id21, l21) = c2.licensesSorted.popitem(last=False)
        self.assertEqual("HarshEULA", l21.name)
        self.assertEqual(len(l21.filesSorted), 5)
        (f_id211, f211) = l21.filesSorted.popitem(last=False)
        self.assertEqual(f_id211, 3)
        self.assertEqual(f211.path, "/tmp/f3")
        self.assertEqual(f211.findings, {})
        (f_id212, f212) = l21.filesSorted.popitem(last=False)
        self.assertEqual(f_id212, 4)
        self.assertEqual(f212.path, "/tmp/f4")
        self.assertEqual(f212.findings, {})
        (f_id216, f216) = l21.filesSorted.popitem(last=False)
        self.assertEqual(f_id216, 6)
        self.assertEqual(f216.path, "/tmp/nolic/vendor/whatever")
        self.assertEqual(f216.findings, {})  # haven't run analysis yet
        (f3_id211, f3211) = l21.filesSorted.popitem(last=False)
        self.assertEqual(f3_id211, 33)
        self.assertEqual(f3211.path, "/scan3/tmp/f3")
        self.assertEqual(f3211.findings, {})
        (f3_id212, f3212) = l21.filesSorted.popitem(last=False)
        self.assertEqual(f3_id212, 34)
        self.assertEqual(f3212.path, "/scan3/tmp/f4")
        self.assertEqual(f3212.findings, {})

    def test_analyzer_marks_cats_and_lics_that_have_files(self):
        self.analyzer._buildScanCategories()
        self.analyzer._addFiles(scan_id=1)

        # check categories
        c1 = self.analyzer._getCategory(category_id=1)
        self.assertTrue(c1.hasFiles)
        c2 = self.analyzer._getCategory(category_id=2)
        self.assertTrue(c2.hasFiles)
        c3 = self.analyzer._getCategory(category_id=3)
        self.assertFalse(c3.hasFiles)

        # check licenses
        l2 = self.analyzer._getLicense(license_id=2)
        self.assertTrue(l2.hasFiles)
        l4 = self.analyzer._getLicense(license_id=4)
        self.assertTrue(l4.hasFiles)
        l7 = self.analyzer._getLicense(license_id=7)
        self.assertFalse(l7.hasFiles)

    ##### Analyzer config params tests

    def test_analyzer_can_take_optional_config_params(self):
        configDict = {
            "analyze-extensions": "yes",
            "analyze-extensions-list": "json;jpeg;png"
        }
        newAnalyzer = Analyzer(db=self.db, config=configDict)
        self.assertEqual("yes", newAnalyzer.kwConfig["analyze-extensions"])
        self.assertEqual("json;jpeg;png",
                         newAnalyzer.kwConfig["analyze-extensions-list"])

    def test_can_get_analyze_final_config_from_analyzer(self):
        self.db.setConfigValue(key="analyze-extensions", value="yes")
        exts = self.analyzer._getFinalConfigValue(key="analyze-extensions")
        self.assertEqual(exts, "yes")

    def test_can_override_db_config_in_analyzer_final_config(self):
        self.db.setConfigValue(key="analyze-extensions", value="yes")
        newAnalyzer = Analyzer(db=self.db, config={"analyze-extensions": "no"})
        exts = newAnalyzer._getFinalConfigValue(key="analyze-extensions")
        self.assertEqual(exts, "no")

    ##### Analyzer main analysis function tests

    def test_analyzer_cannot_analyze_before_categories_are_built(self):
        with self.assertRaises(ReportAnalysisError):
            self.analyzer._runAnalysis()

    @mock.patch('slm.reports.analysis.Analyzer._analyzeExtensions')
    def test_analyzer_runs_extensions_check_if_set(self, ext_mock):
        self.db.setConfigValue(key="analyze-extensions", value="yes")
        self.analyzer._buildScanCategories()
        self.analyzer._addFiles(scan_id=1)
        self.analyzer._runAnalysis()
        ext_mock.assert_called()

    @mock.patch('slm.reports.analysis.Analyzer._analyzeExtensions')
    def test_analyzer_does_not_run_extensions_check_if_not_set(self, ext_mock):
        self.analyzer._buildScanCategories()
        self.analyzer._addFiles(scan_id=1)
        self.analyzer._runAnalysis()
        ext_mock.assert_not_called()

    @mock.patch('slm.reports.analysis.Analyzer._analyzeExtensions')
    def test_analyzer_does_not_run_extensions_check_if_set_to_no(
            self, ext_mock):
        self.db.setConfigValue(key="analyze-extensions", value="no")
        self.analyzer._buildScanCategories()
        self.analyzer._addFiles(scan_id=1)
        self.analyzer._runAnalysis()
        ext_mock.assert_not_called()

    @mock.patch('slm.reports.analysis.Analyzer._analyzeThirdparty')
    def test_analyzer_runs_thirparty_check_if_set(self, tp_mock):
        self.db.setConfigValue(key="analyze-thirdparty", value="yes")
        self.analyzer._buildScanCategories()
        self.analyzer._addFiles(scan_id=1)
        self.analyzer._runAnalysis()
        tp_mock.assert_called()

    @mock.patch('slm.reports.analysis.Analyzer._analyzeThirdparty')
    def test_analyzer_does_not_run_thirdparty_check_if_not_set(self, tp_mock):
        self.analyzer._buildScanCategories()
        self.analyzer._addFiles(scan_id=1)
        self.analyzer._runAnalysis()
        tp_mock.assert_not_called()

    @mock.patch('slm.reports.analysis.Analyzer._analyzeEmptyFile')
    def test_analyzer_runs_emptyfile_check_if_set(self, empty_mock):
        self.db.setConfigValue(key="analyze-emptyfile", value="yes")
        self.analyzer._buildScanCategories()
        self.analyzer._addFiles(scan_id=1)
        self.analyzer._runAnalysis()
        empty_mock.assert_called()

    @mock.patch('slm.reports.analysis.Analyzer._analyzeEmptyFile')
    def test_analyzer_does_not_run_emptyfile_check_if_not_set(
            self, empty_mock):
        self.analyzer._buildScanCategories()
        self.analyzer._addFiles(scan_id=1)
        self.analyzer._runAnalysis()
        empty_mock.assert_not_called()

    @mock.patch('slm.reports.analysis.Analyzer._analyzeExcludePathPrefix')
    def test_analyzer_runs_excludePathPrefix_if_set(self, path_mock):
        self.db.setConfigValue(key="analyze-exclude-path-prefix", value="yes")
        self.analyzer._buildScanCategories()
        self.analyzer._addFiles(scan_id=1)
        self.analyzer._runAnalysis()
        path_mock.assert_called()

    @mock.patch('slm.reports.analysis.Analyzer._analyzeExcludePathPrefix')
    def test_analyzer_does_not_run_excludePathPrefix_if_not_set(
            self, path_mock):
        self.analyzer._buildScanCategories()
        self.analyzer._addFiles(scan_id=1)
        self.analyzer._runAnalysis()
        path_mock.assert_not_called()

    @mock.patch('slm.reports.analysis.Analyzer._analyzeExcludeEmptyCatsAndLics'
                )
    def test_analyzer_runs_excludeEmptyCatsAndLics_if_set(self, ecl_mock):
        self.db.setConfigValue(key="analyze-exclude-empty-cats-and-lics",
                               value="yes")
        self.analyzer._buildScanCategories()
        self.analyzer._addFiles(scan_id=1)
        self.analyzer._runAnalysis()
        ecl_mock.assert_called()

    @mock.patch('slm.reports.analysis.Analyzer._analyzeExcludeEmptyCatsAndLics'
                )
    def test_analyzer_does_not_run_excludeEmptyCatsAndLics_if_not_set(
            self, ecl_mock):
        self.analyzer._buildScanCategories()
        self.analyzer._addFiles(scan_id=1)
        self.analyzer._runAnalysis()
        ecl_mock.assert_not_called()

    ##### getter helper tests

    def test_analyzer_cannot_get_specific_cat_before_building_categories(self):
        with self.assertRaises(ReportAnalysisError):
            self.analyzer._getCategory(category_id=3)

    def test_analyzer_returns_none_if_getting_specific_cat_by_unknown_id(self):
        self.analyzer._buildScanCategories()
        self.analyzer._addFiles(scan_id=1)
        self.analyzer._runAnalysis()
        cat = self.analyzer._getCategory(category_id=77)
        self.assertIsNone(cat)

    def test_analyzer_can_get_specific_category_by_id(self):
        self.analyzer._buildScanCategories()
        self.analyzer._addFiles(scan_id=1)
        self.analyzer._runAnalysis()
        cat = self.analyzer._getCategory(category_id=3)
        self.assertEqual("blah category", cat.name)

    def test_analyzer_cannot_get_specific_lic_before_building_categories(self):
        with self.assertRaises(ReportAnalysisError):
            self.analyzer._getLicense(license_id=6)

    def test_analyzer_returns_none_if_getting_specific_lic_by_unknown_id(self):
        self.analyzer._buildScanCategories()
        self.analyzer._addFiles(scan_id=1)
        self.analyzer._runAnalysis()
        lic = self.analyzer._getLicense(license_id=77)
        self.assertIsNone(lic)

    def test_analyzer_can_get_specific_license_by_id(self):
        self.analyzer._buildScanCategories()
        self.analyzer._addFiles(scan_id=1)
        self.analyzer._runAnalysis()
        lic = self.analyzer._getLicense(license_id=6)
        self.assertEqual("Also no license found", lic.name)

    def test_analyzer_cannot_get_specific_file_before_building_categories(
            self):
        with self.assertRaises(ReportAnalysisError):
            self.analyzer._getFile(7)

    def test_analyzer_returns_none_if_getting_specific_file_by_unknown_id(
            self):
        self.analyzer._buildScanCategories()
        self.analyzer._addFiles(scan_id=1)
        self.analyzer._runAnalysis()
        f = self.analyzer._getFile(77)
        self.assertIsNone(f)

    def test_analyzer_can_get_specific_file_by_id(self):
        self.analyzer._buildScanCategories()
        self.analyzer._addFiles(scan_id=1)
        self.analyzer._runAnalysis()
        f = self.analyzer._getFile(file_id=7)
        self.assertEqual("/tmp/nolic/vendor/image-both.png", f.path)

    ##### file extension analysis tests

    def test_can_parse_file_extension_string(self):
        extString = "json;jpeg;png;gif"
        self.db.setConfigValue(key="analyze-extensions-list", value=extString)
        exts = self.analyzer._parseExtConfig()
        # extensions are sorted in alphabetical order
        self.assertEqual(["gif", "jpeg", "json", "png"], exts)

    def test_extension_string_parser_returns_empty_list_if_not_set(self):
        exts = self.analyzer._parseExtConfig()
        self.assertEqual([], exts)

    def test_ignore_whitespace_in_file_extension_string(self):
        extString = "   json ;  jpeg;   png  ;gif     "
        self.db.setConfigValue(key="analyze-extensions-list", value=extString)
        exts = self.analyzer._parseExtConfig()
        # extensions are sorted in alphabetical order
        self.assertEqual(["gif", "jpeg", "json", "png"], exts)

    def test_files_with_extension_match_get_extra_flag_and_others_dont(self):
        self.db.setConfigValue(key="analyze-extensions", value="yes")
        extString = "json;jpeg;png;gif"
        self.db.setConfigValue(key="analyze-extensions-list", value=extString)
        self.analyzer._buildScanCategories()
        self.analyzer._addFiles(scan_id=1)
        self.analyzer._runAnalysis()

        # check specific files
        self._checkFileExtFindingIsNone(1)
        self._checkFileExtFindingIsNone(2)
        self._checkFileExtFindingIsNone(3)
        self._checkFileExtFindingIsNone(4)
        self._checkFileExtFindingIsYes(5)
        self._checkFileExtFindingIsNone(6)
        self._checkFileExtFindingIsYes(7)
        self._checkFileExtFindingIsNone(8)
        self._checkFileExtFindingIsNone(9)
        self._checkFileExtFindingIsYes(10)
        self._checkFileExtFindingIsYes(11)

    ##### empty file analysis tests

    def test_empty_files_get_extra_flag_and_others_dont(self):
        self.db.setConfigValue(key="analyze-emptyfile", value="yes")
        self.analyzer._buildScanCategories()
        self.analyzer._addFiles(scan_id=1)
        self.analyzer._runAnalysis()

        # check specific files
        self._checkFileEmptyFindingIsNone(1)
        self._checkFileEmptyFindingIsNone(2)
        self._checkFileEmptyFindingIsNone(3)
        self._checkFileEmptyFindingIsNone(4)
        self._checkFileEmptyFindingIsNone(5)
        self._checkFileEmptyFindingIsNone(6)
        self._checkFileEmptyFindingIsNone(7)
        self._checkFileEmptyFindingIsYes(8)
        self._checkFileEmptyFindingIsYes(9)
        self._checkFileEmptyFindingIsYes(10)
        self._checkFileEmptyFindingIsYes(11)

    ##### third party directory analysis tests

    def test_can_parse_thirdparty_dirs_string(self):
        dirString = "vendor;thirdparty;third-party"
        self.db.setConfigValue(key="analyze-thirdparty-dirs", value=dirString)
        dirs = self.analyzer._parseDirConfig()
        # directories are sorted in alphabetical order
        self.assertEqual(["third-party", "thirdparty", "vendor"], dirs)

    def test_directories_string_parser_returns_empty_list_if_not_set(self):
        dirs = self.analyzer._parseDirConfig()
        self.assertEqual([], dirs)

    def test_ignore_whitespace_in_thirdparty_dirs_string(self):
        dirString = "   thirdparty ;  vendor  ;third-party     "
        self.db.setConfigValue(key="analyze-thirdparty-dirs", value=dirString)
        dirs = self.analyzer._parseDirConfig()
        # directories are sorted in alphabetical order
        self.assertEqual(["third-party", "thirdparty", "vendor"], dirs)

    def test_files_with_directory_match_get_extra_flag_and_others_dont(self):
        self.db.setConfigValue(key="analyze-thirdparty", value="yes")
        dirString = "vendor;thirdparty;third-party"
        self.db.setConfigValue(key="analyze-thirdparty-dirs", value=dirString)
        self.analyzer._buildScanCategories()
        self.analyzer._addFiles(scan_id=1)
        self.analyzer._runAnalysis()

        # check specific files
        self._checkFileDirFindingIsNone(1)
        self._checkFileDirFindingIsNone(2)
        self._checkFileDirFindingIsNone(3)
        self._checkFileDirFindingIsNone(4)
        self._checkFileDirFindingIsNone(5)
        self._checkFileDirFindingIsYes(6)
        self._checkFileDirFindingIsYes(7)
        self._checkFileDirFindingIsNone(8)
        self._checkFileDirFindingIsYes(9)
        self._checkFileDirFindingIsNone(10)
        self._checkFileDirFindingIsYes(11)

    ##### exclude path prefix analysis tests

    def test_analyzer_can_exclude_common_path_prefix(self):
        self.db.setConfigValue(key="analyze-exclude-path-prefix", value="yes")
        self.analyzer._buildScanCategories()
        self.analyzer._addFiles(scan_id=1)
        self.analyzer._runAnalysis()

        # check that file paths have changed
        for cat in self.analyzer.primaryScanCategories.values():
            for lic in cat.licensesSorted.values():
                for file in lic.filesSorted.values():
                    self.assertNotIn("tmp", file.path)

    ##### exclude empty categories and licenses analysis tests

    def test_analyzer_can_exclude_empty_cats_and_lics(self):
        self.db.setConfigValue(key="analyze-exclude-empty-cats-and-lics",
                               value="yes")
        self.analyzer._buildScanCategories()
        self.analyzer._addFiles(scan_id=1)
        self.analyzer._runAnalysis()

        # check that empty cats are gone
        with self.assertRaises(KeyError):
            na = self.analyzer.primaryScanCategories[3]
        # and check that empty licenses are gone
        cat4 = self.analyzer.primaryScanCategories[4]
        with self.assertRaises(KeyError):
            na = cat4.licensesSorted[7]

        # and check that cats and licenses with files are still present
        self.assertEqual(cat4.name, "no lic category")
        self.assertEqual(cat4.licensesSorted[6].name, "Also no license found")

    ##### main analysis function tests

    def test_can_analyze_and_get_results(self):
        self.db.setConfigValue(key="analyze-extensions", value="yes")
        results = self.analyzer.runAnalysis(scan_id=1)
        self.assertEqual(OrderedDict, type(results))
        self.assertEqual(4, len(results.items()))
        cat1 = results[1]
        self.assertEqual("a category", cat1.name)
        self.assertTrue(self.analyzer.analysisDone)

    def test_can_analyze_and_get_results_for_multiple_scans(self):
        self.db.setConfigValue(key="analyze-extensions", value="yes")
        results = self.analyzer.runAnalysis(scan_ids=[1, 3])
        self.assertEqual(OrderedDict, type(results))
        self.assertEqual(4, len(results.items()))
        cat1 = results[1]
        self.assertEqual("a category", cat1.name)
        self.assertTrue(self.analyzer.analysisDone)

    def test_cannot_analyze_invalid_scan_id(self):
        with self.assertRaises(ReportAnalysisError):
            self.analyzer.runAnalysis(scan_id=187)

    def test_cannot_analyze_invalid_scan_id_in_multiple_ids(self):
        with self.assertRaises(ReportAnalysisError):
            self.analyzer.runAnalysis(scan_ids=[1, 3, 187])

    def test_cannot_analyze_with_singular_and_multiple_scan_ids(self):
        with self.assertRaises(ReportAnalysisError):
            self.analyzer.runAnalysis(scan_id=1, scan_ids=[1, 3])

    ##### create list results from OrderedDict results

    def test_cannot_get_list_results_before_results_are_generated(self):
        with self.assertRaises(ReportAnalysisError):
            self.analyzer.getResultsAsList()

        self.analyzer._buildScanCategories()
        with self.assertRaises(ReportAnalysisError):
            self.analyzer.getResultsAsList()

        self.analyzer._addFiles(scan_id=1)
        with self.assertRaises(ReportAnalysisError):
            self.analyzer.getResultsAsList()

    def test_can_get_list_results_from_OrderedDict_results(self):
        self.db.setConfigValue(key="analyze-exclude-empty-cats-and-lics",
                               value="yes")
        self.analyzer.runAnalysis(scan_id=1)

        list_results = self.analyzer.getResultsAsList()

        # check top-level list of categories
        # should be sorted by order and should exclude empty categories
        self.assertIsInstance(list_results, list)
        self.assertEqual(len(list_results), 3)
        cat2 = list_results[0]
        self.assertIsInstance(cat2, Category)
        self.assertEqual(cat2.name, "cat")
        self.assertEqual(cat2._id, 2)

        # check licenses within a category
        # should be sorted alphabetically and should exclude empty licenses
        cat4 = list_results[2]
        self.assertIsInstance(cat4.licenses, list)
        self.assertEqual(len(cat4.licenses), 2)
        lic6 = cat4.licenses[0]
        self.assertIsInstance(lic6, License)
        self.assertEqual(lic6.name, "Also no license found")
        self.assertEqual(lic6._id, 6)

        # check files within a license
        self.assertIsInstance(lic6.files, list)
        self.assertEqual(len(lic6.files), 5)
        self.assertIsInstance(lic6.files[0], File)

    ##### Split string into separate scan IDs

    def test_can_split_string_with_individual_scan_ids(self):
        sstring = "1,3,10,6,2"
        scan_ids = self.analyzer.splitScanIDString(sstring)
        # scan IDs should be included regardless of whether they're actual
        # scans, and should be sorted
        self.assertEqual(scan_ids, [1, 2, 3, 6, 10])

    def test_can_split_string_with_range_of_scan_ids(self):
        sstring = "1,8,4-6,9"
        scan_ids = self.analyzer.splitScanIDString(sstring)
        self.assertEqual(scan_ids, [1, 4, 5, 6, 8, 9])

    def test_raises_error_if_invalid_text_found(self):
        with self.assertRaises(ReportAnalysisError):
            self.analyzer.splitScanIDString("oops")
        with self.assertRaises(ReportAnalysisError):
            self.analyzer.splitScanIDString("1,oops")
        with self.assertRaises(ReportAnalysisError):
            self.analyzer.splitScanIDString("oops,3")
        with self.assertRaises(ReportAnalysisError):
            self.analyzer.splitScanIDString("1,oops,3")

    def test_ids_not_duplicated_if_included_repeatedly(self):
        sstring = "1,1-4,1,4,7-8,7-8,7"
        scan_ids = self.analyzer.splitScanIDString(sstring)
        self.assertEqual(scan_ids, [1, 2, 3, 4, 7, 8])

    def test_raises_error_if_range_is_backwards(self):
        with self.assertRaises(ReportAnalysisError):
            self.analyzer.splitScanIDString("9-2")

    def test_raises_error_if_range_format_is_invalid(self):
        with self.assertRaises(ReportAnalysisError):
            self.analyzer.splitScanIDString("9-")
        with self.assertRaises(ReportAnalysisError):
            self.analyzer.splitScanIDString("9-10-15")
        with self.assertRaises(ReportAnalysisError):
            self.analyzer.splitScanIDString("-9")
        with self.assertRaises(ReportAnalysisError):
            self.analyzer.splitScanIDString("-")
        with self.assertRaises(ReportAnalysisError):
            self.analyzer.splitScanIDString("9--12")
        with self.assertRaises(ReportAnalysisError):
            self.analyzer.splitScanIDString("-9-10")

    def test_helper_returns_int_from_string(self):
        i = self.analyzer._getIntFromStringScanID("3")
        self.assertEqual(i, 3)

    def test_helper_raises_report_analysis_error_for_non_integers(self):
        with self.assertRaises(ReportAnalysisError):
            self.analyzer._getIntFromStringScanID("")
        with self.assertRaises(ReportAnalysisError):
            self.analyzer._getIntFromStringScanID("a")
        with self.assertRaises(ReportAnalysisError):
            self.analyzer._getIntFromStringScanID("3-")
        with self.assertRaises(ReportAnalysisError):
            self.analyzer._getIntFromStringScanID("3a")
        with self.assertRaises(ReportAnalysisError):
            self.analyzer._getIntFromStringScanID(",")
        with self.assertRaises(ReportAnalysisError):
            self.analyzer._getIntFromStringScanID("3:")
示例#25
0
 def test_can_open_existing_db(self):
     # create in temporary directory on disk, so we can re-open DB
     # (testfixtures will wipe out the directory at end of test)
     with TempDirectory() as td:
         dbPath = os.path.join(td.path, "tmp.db")
         dbnew = ProjectDB()
         dbnew.createDB(dbPath)
         dbnew.initializeDBTables()
         dbnew.closeDB()
         # and reopen it
         dbnew.openDB(dbPath)
         self.assertTrue(dbnew.isOpened())
         self.assertTrue(dbnew.isInitialized())
         dbnew.closeDB()
示例#26
0
class DBSubprojectUnitTestSuite(unittest.TestCase):
    """spdxLicenseManager unit test suite for subproject data in DB."""
    def setUp(self):
        # create and initialize an in-memory database
        self.db = ProjectDB()
        self.db.createDB(":memory:")
        self.db.initializeDBTables()

        # insert sample data
        self.insertSampleSubprojectData()

    def tearDown(self):
        self.db.closeDB()
        self.db = None

    def insertSampleSubprojectData(self):
        subprojects = [
            Subproject(_id=1,
                       name="sub1",
                       spdx_search="sub1",
                       desc="subproject 1"),
            Subproject(_id=2,
                       name="subX",
                       spdx_search="subX",
                       desc="subproject XYZ"),
            Subproject(_id=3,
                       name="subC",
                       spdx_search="subC",
                       desc="subproject B"),
        ]
        self.db.session.bulk_save_objects(subprojects)
        self.db.session.commit()

    ##### Test cases below

    def test_can_retrieve_all_subproject_names_and_descs(self):
        subprojects = self.db.getSubprojectsAll()
        self.assertIsInstance(subprojects, list)
        self.assertEqual(len(subprojects), 3)
        self.assertEqual(subprojects[0]._id, 1)
        self.assertEqual(subprojects[0].name, "sub1")
        self.assertEqual(subprojects[0].desc, "subproject 1")
        self.assertEqual(subprojects[0].spdx_search, "sub1")

    def test_all_subprojects_are_sorted_by_name(self):
        subprojects = self.db.getSubprojectsAll()
        self.assertEqual(subprojects[0].name, "sub1")
        self.assertEqual(subprojects[1].name, "subC")
        self.assertEqual(subprojects[2].name, "subX")

    def test_can_retrieve_one_subproject_by_id(self):
        subproject = self.db.getSubproject(_id=2)
        self.assertEqual(subproject.name, "subX")
        self.assertEqual(subproject.desc, "subproject XYZ")
        self.assertEqual(subproject.spdx_search, "subX")

    def test_can_retrieve_one_subproject_by_name(self):
        subproject = self.db.getSubproject(name="subC")
        self.assertEqual(subproject._id, 3)
        self.assertEqual(subproject.desc, "subproject B")
        self.assertEqual(subproject.spdx_search, "subC")

    def test_cannot_retrieve_subproject_by_both_name_and_id(self):
        with self.assertRaises(ProjectDBQueryError):
            self.db.getSubproject(_id=3, name="subC")

    def test_cannot_retrieve_subproject_without_either_name_or_id(self):
        with self.assertRaises(ProjectDBQueryError):
            self.db.getSubproject()

    def test_cannot_retrieve_subproject_with_positional_args(self):
        with self.assertRaises(TypeError):
            self.db.getSubproject("subC")

    def test_returns_none_if_subproject_not_found_by_id(self):
        subproject = self.db.getSubproject(_id=17)
        self.assertIsNone(subproject)

    def test_returns_none_if_subproject_not_found_by_name(self):
        subproject = self.db.getSubproject(name="noSuchSubproject")
        self.assertIsNone(subproject)

    def test_can_add_and_retrieve_subproject(self):
        subproject_id = self.db.addSubproject("newsub",
                                              "subproject new",
                                              spdx_search="newsub")

        # confirm that we now have four subprojects
        subprojects = self.db.getSubprojectsAll()
        self.assertEqual(len(subprojects), 4)

        # and confirm that we can retrieve this one by name
        subproject = self.db.getSubproject(name="newsub")
        self.assertEqual(subproject.name, "newsub")
        self.assertEqual(subproject.desc, "subproject new")
        self.assertEqual(subproject.spdx_search, "newsub")

        # and confirm that we can retrieve this one by id
        subproject = self.db.getSubproject(_id=4)
        self.assertEqual(subproject.name, "newsub")
        self.assertEqual(subproject.desc, "subproject new")
        self.assertEqual(subproject.spdx_search, "newsub")

    def test_can_add_subproject_without_providing_spdx_search_name(self):
        subproject_id = self.db.addSubproject("newsub", "subproject new")

        # confirm that we now have four subprojects
        subprojects = self.db.getSubprojectsAll()
        self.assertEqual(len(subprojects), 4)

        # and confirm that we can retrieve this one by name
        subproject = self.db.getSubproject(name="newsub")
        self.assertEqual(subproject.name, "newsub")
        self.assertEqual(subproject.desc, "subproject new")
        self.assertEqual(subproject.spdx_search, "newsub")

        # and confirm that we can retrieve this one by id
        subproject = self.db.getSubproject(_id=4)
        self.assertEqual(subproject.name, "newsub")
        self.assertEqual(subproject.desc, "subproject new")
        self.assertEqual(subproject.spdx_search, "newsub")

    def test_can_start_adding_but_rollback_subproject(self):
        subproject_id = self.db.addSubproject(name="newsub",
                                              spdx_search="newsub",
                                              desc="will rollback",
                                              commit=False)
        self.db.rollback()
        # confirm that we still only have three subprojects
        subprojects = self.db.getSubprojectsAll()
        self.assertEqual(len(subprojects), 3)
        # and confirm that this subproject ID doesn't exist in database
        subproject = self.db.getSubproject(_id=subproject_id)
        self.assertIsNone(subproject)

    def test_can_start_adding_and_then_commit_subprojects(self):
        s2_id = self.db.addSubproject(name="news2",
                                      spdx_search="news2",
                                      desc="new sp 2",
                                      commit=False)
        s1_id = self.db.addSubproject(name="news1",
                                      spdx_search="news1",
                                      desc="new sp 1",
                                      commit=False)
        self.db.commit()
        # confirm that we now have five subprojects
        subprojects = self.db.getSubprojectsAll()
        self.assertEqual(len(subprojects), 5)

    def test_can_edit_subproject_spdx_string(self):
        self.db.changeSubprojectSPDXSearch(name="subX",
                                           spdx_search="subXSpecial")
        subproject = self.db.getSubproject(name="subX")
        self.assertEqual(subproject.name, "subX")
        self.assertEqual(subproject.spdx_search, "subXSpecial")

    def test_cannot_edit_subproject_spdx_search_for_nonexistent_name(self):
        with self.assertRaises(ProjectDBUpdateError):
            self.db.changeSubprojectSPDXSearch(name="invalid",
                                               spdx_search="this will fail")

    def test_cannot_change_subproject_spdx_search_to_existing_search(self):
        with self.assertRaises(ProjectDBUpdateError):
            self.db.changeSubprojectSPDXSearch(name="sub1", spdx_search="subX")
示例#27
0
    def test_open_db_fails_if_invalid_magic_number(self):
        # create in temporary directory on disk, so we can re-open it
        # (testfixtures will wipe out the directory at end of test)
        with TempDirectory() as td:
            dbPath = os.path.join(td.path, "tmp.db")
            dbnew = ProjectDB()
            dbnew.createDB(dbPath)
            dbnew.initializeDBTables()

            # set invalid magic number
            query = dbnew.session.query(Config).filter(Config.key == "magic")
            query.update({Config.value: "invalidMagic"})
            dbnew.session.commit()
            dbnew.closeDB()

            # and reopen it
            with self.assertRaises(ProjectDBConfigError):
                dbnew.openDB(dbPath)
            self.assertFalse(dbnew.isOpened())
            self.assertFalse(dbnew.isInitialized())