From f4a3652ee5b8087f551553df9498d5f00e169a86 Mon Sep 17 00:00:00 2001 From: BonfaceKilz Date: Tue, 3 Nov 2020 18:13:57 +0300 Subject: Separate unittests from integration tests --- wqflask/tests/unit/__init__.py | 0 wqflask/tests/unit/base/__init__.py | 0 wqflask/tests/unit/base/data.py | 110 ++++++ wqflask/tests/unit/base/test_data_set.py | 181 +++++++++ wqflask/tests/unit/base/test_general_object.py | 40 ++ wqflask/tests/unit/base/test_trait.py | 241 ++++++++++++ wqflask/tests/unit/base/test_webqtl_case_data.py | 39 ++ wqflask/tests/unit/utility/__init__.py | 0 .../unit/utility/test_authentication_tools.py | 189 ++++++++++ wqflask/tests/unit/utility/test_chunks.py | 19 + wqflask/tests/unit/utility/test_corestats.py | 55 +++ .../tests/unit/utility/test_corr_result_helpers.py | 32 ++ wqflask/tests/unit/utility/test_formatting.py | 33 ++ wqflask/tests/unit/utility/test_hmac.py | 52 +++ wqflask/tests/unit/wqflask/__init__.py | 0 wqflask/tests/unit/wqflask/api/__init__.py | 0 wqflask/tests/unit/wqflask/api/test_gen_menu.py | 413 +++++++++++++++++++++ .../unit/wqflask/marker_regression/__init__.py | 0 .../test_display_mapping_results.py | 156 ++++++++ wqflask/tests/unit/wqflask/show_trait/__init__.py | 0 .../wqflask/show_trait/test_export_trait_data.py | 212 +++++++++++ wqflask/tests/unit/wqflask/test_collect.py | 73 ++++ wqflask/tests/unit/wqflask/test_pbkdf2.py | 61 +++ wqflask/tests/unit/wqflask/test_user_login.py | 21 ++ wqflask/tests/unit/wqflask/test_user_session.py | 15 + 25 files changed, 1942 insertions(+) create mode 100644 wqflask/tests/unit/__init__.py create mode 100644 wqflask/tests/unit/base/__init__.py create mode 100644 wqflask/tests/unit/base/data.py create mode 100644 wqflask/tests/unit/base/test_data_set.py create mode 100644 wqflask/tests/unit/base/test_general_object.py create mode 100644 wqflask/tests/unit/base/test_trait.py create mode 100644 wqflask/tests/unit/base/test_webqtl_case_data.py create mode 100644 wqflask/tests/unit/utility/__init__.py create mode 100644 wqflask/tests/unit/utility/test_authentication_tools.py create mode 100644 wqflask/tests/unit/utility/test_chunks.py create mode 100644 wqflask/tests/unit/utility/test_corestats.py create mode 100644 wqflask/tests/unit/utility/test_corr_result_helpers.py create mode 100644 wqflask/tests/unit/utility/test_formatting.py create mode 100644 wqflask/tests/unit/utility/test_hmac.py create mode 100644 wqflask/tests/unit/wqflask/__init__.py create mode 100644 wqflask/tests/unit/wqflask/api/__init__.py create mode 100644 wqflask/tests/unit/wqflask/api/test_gen_menu.py create mode 100644 wqflask/tests/unit/wqflask/marker_regression/__init__.py create mode 100644 wqflask/tests/unit/wqflask/marker_regression/test_display_mapping_results.py create mode 100644 wqflask/tests/unit/wqflask/show_trait/__init__.py create mode 100644 wqflask/tests/unit/wqflask/show_trait/test_export_trait_data.py create mode 100644 wqflask/tests/unit/wqflask/test_collect.py create mode 100644 wqflask/tests/unit/wqflask/test_pbkdf2.py create mode 100644 wqflask/tests/unit/wqflask/test_user_login.py create mode 100644 wqflask/tests/unit/wqflask/test_user_session.py (limited to 'wqflask/tests/unit') diff --git a/wqflask/tests/unit/__init__.py b/wqflask/tests/unit/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/wqflask/tests/unit/base/__init__.py b/wqflask/tests/unit/base/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/wqflask/tests/unit/base/data.py b/wqflask/tests/unit/base/data.py new file mode 100644 index 00000000..06a5a989 --- /dev/null +++ b/wqflask/tests/unit/base/data.py @@ -0,0 +1,110 @@ +gen_menu_json = """ +{ + "datasets": { + "human": { + "HLC": { + "Liver mRNA": [ + [ + "320", + "HLC_0311", + "GSE9588 Human Liver Normal (Mar11) Both Sexes" + ] + ], + "Phenotypes": [ + [ + "635", + "HLCPublish", + "HLC Published Phenotypes" + ] + ] + } + }, + "mouse": { + "BXD": { + "Genotypes": [ + [ + "600", + "BXDGeno", + "BXD Genotypes" + ] + ], + "Hippocampus mRNA": [ + [ + "112", + "HC_M2_0606_P", + "Hippocampus Consortium M430v2 (Jun06) PDNN" + ] + ], + "Phenotypes": [ + [ + "602", + "BXDPublish", + "BXD Published Phenotypes" + ] + ] + } + } + }, + "groups": { + "human": [ + [ + "HLC", + "Liver: Normal Gene Expression with Genotypes (Merck)", + "Family:None" + ] + ], + "mouse": [ + [ + "BXD", + "BXD", + "Family:None" + ] + ] + }, + "species": [ + [ + "human", + "Human" + ], + [ + "mouse", + "Mouse" + ] + ], + "types": { + "human": { + "HLC": [ + [ + "Phenotypes", + "Traits and Cofactors", + "Phenotypes" + ], + [ + "Liver mRNA", + "Liver mRNA", + "Molecular Trait Datasets" + ] + ] + }, + "mouse": { + "BXD": [ + [ + "Phenotypes", + "Traits and Cofactors", + "Phenotypes" + ], + [ + "Genotypes", + "DNA Markers and SNPs", + "Genotypes" + ], + [ + "Hippocampus mRNA", + "Hippocampus mRNA", + "Molecular Trait Datasets" + ] + ] + } + } +} +""" diff --git a/wqflask/tests/unit/base/test_data_set.py b/wqflask/tests/unit/base/test_data_set.py new file mode 100644 index 00000000..96563a16 --- /dev/null +++ b/wqflask/tests/unit/base/test_data_set.py @@ -0,0 +1,181 @@ +"""Tests for wqflask/base/data_set.py""" + +import unittest +from unittest import mock + +from wqflask import app +from .data import gen_menu_json +from base.data_set import DatasetType + + +class TestDataSetTypes(unittest.TestCase): + """Tests for the DataSetType class""" + + def setUp(self): + self.test_dataset = """ + { + "AD-cases-controls-MyersGeno": "Geno", + "AD-cases-controls-MyersPublish": "Publish", + "AKXDGeno": "Geno", + "AXBXAGeno": "Geno", + "AXBXAPublish": "Publish", + "Aging-Brain-UCIPublish": "Publish", + "All Phenotypes": "Publish", + "B139_K_1206_M": "ProbeSet", + "B139_K_1206_R": "ProbeSet" + } + """ + self.app_context = app.app_context() + self.app_context.push() + + def tearDown(self): + self.app_context.pop() + + @mock.patch('base.data_set.g') + def test_data_set_type(self, db_mock): + """Test that DatasetType returns correctly if the Redis Instance is not empty + and the name variable exists in the dictionary + + """ + with app.app_context(): + db_mock.get = mock.Mock() + redis_mock = mock.Mock() + redis_mock.get.return_value = self.test_dataset + self.assertEqual(DatasetType(redis_mock) + ("All Phenotypes"), "Publish") + redis_mock.get.assert_called_once_with("dataset_structure") + + @mock.patch('base.data_set.requests.get') + def test_data_set_type_with_empty_redis(self, request_mock): + """Test that DatasetType returns correctly if the Redis Instance is empty and + the name variable exists in the dictionary + + """ + with app.app_context(): + request_mock.return_value.content = gen_menu_json + redis_mock = mock.Mock() + redis_mock.get.return_value = None + data_set = DatasetType(redis_mock) + self.assertEqual(data_set("BXDGeno"), "Geno") + self.assertEqual(data_set("BXDPublish"), "Publish") + self.assertEqual(data_set("HLC_0311"), "ProbeSet") + + redis_mock.set.assert_called_once_with( + "dataset_structure", + ('{"HLC_0311": "ProbeSet", ' + '"HLCPublish": "Publish", ' + '"BXDGeno": "Geno", ' + '"HC_M2_0606_P": "ProbeSet", ' + '"BXDPublish": "Publish"}')) + + @mock.patch('base.data_set.g') + def test_set_dataset_key_mrna(self, db_mock): + with app.app_context(): + db_mock.db.execute.return_value.fetchone.return_value = [1, 2, 3] + redis_mock = mock.Mock() + redis_mock.get.return_value = self.test_dataset + data_set = DatasetType(redis_mock) + data_set.set_dataset_key("mrna_expr", "Test") + self.assertEqual(data_set("Test"), "ProbeSet") + redis_mock.set.assert_called_once_with( + "dataset_structure", + ('{"AD-cases-controls-MyersGeno": "Geno", ' + '"AD-cases-controls-MyersPublish": "Publish", ' + '"AKXDGeno": "Geno", ' + '"AXBXAGeno": "Geno", ' + '"AXBXAPublish": "Publish", ' + '"Aging-Brain-UCIPublish": "Publish", ' + '"All Phenotypes": "Publish", ' + '"B139_K_1206_M": "ProbeSet", ' + '"B139_K_1206_R": "ProbeSet", ' + '"Test": "ProbeSet"}')) + + db_mock.db.execute.assert_called_with( + ("SELECT ProbeSetFreeze.Id FROM ProbeSetFreeze " + + "WHERE ProbeSetFreeze.Name = \"Test\" ") + ) + + @mock.patch('base.data_set.g') + def test_set_dataset_key_pheno(self, db_mock): + with app.app_context(): + db_mock.db.execute.return_value.fetchone.return_value = [1, 2, 3] + redis_mock = mock.Mock() + redis_mock.get.return_value = self.test_dataset + data_set = DatasetType(redis_mock) + data_set.set_dataset_key("pheno", "Test") + self.assertEqual(data_set("Test"), "Publish") + redis_mock.set.assert_called_once_with( + "dataset_structure", + ('{"AD-cases-controls-MyersGeno": "Geno", ' + '"AD-cases-controls-MyersPublish": "Publish", ' + '"AKXDGeno": "Geno", ' + '"AXBXAGeno": "Geno", ' + '"AXBXAPublish": "Publish", ' + '"Aging-Brain-UCIPublish": "Publish", ' + '"All Phenotypes": "Publish", ' + '"B139_K_1206_M": "ProbeSet", ' + '"B139_K_1206_R": "ProbeSet", ' + '"Test": "Publish"}')) + db_mock.db.execute.assert_called_with( + ("SELECT InfoFiles.GN_AccesionId " + "FROM InfoFiles, PublishFreeze, InbredSet " + "WHERE InbredSet.Name = 'Test' AND " + "PublishFreeze.InbredSetId = InbredSet.Id AND " + "InfoFiles.InfoPageName = PublishFreeze.Name") + ) + + @mock.patch('base.data_set.g') + def test_set_dataset_other_pheno(self, db_mock): + with app.app_context(): + db_mock.db.execute.return_value.fetchone.return_value = [1, 2, 3] + redis_mock = mock.Mock() + redis_mock.get.return_value = self.test_dataset + data_set = DatasetType(redis_mock) + data_set.set_dataset_key("other_pheno", "Test") + self.assertEqual(data_set("Test"), "Publish") + + redis_mock.set.assert_called_once_with( + "dataset_structure", + ('{"AD-cases-controls-MyersGeno": "Geno", ' + '"AD-cases-controls-MyersPublish": "Publish", ' + '"AKXDGeno": "Geno", ' + '"AXBXAGeno": "Geno", ' + '"AXBXAPublish": "Publish", ' + '"Aging-Brain-UCIPublish": "Publish", ' + '"All Phenotypes": "Publish", ' + '"B139_K_1206_M": "ProbeSet", ' + '"B139_K_1206_R": "ProbeSet", ' + '"Test": "Publish"}')) + + db_mock.db.execute.assert_called_with( + ("SELECT PublishFreeze.Name " + + "FROM PublishFreeze, InbredSet " + + "WHERE InbredSet.Name = 'Test' AND " + "PublishFreeze.InbredSetId = InbredSet.Id") + ) + + @mock.patch('base.data_set.g') + def test_set_dataset_geno(self, db_mock): + with app.app_context(): + db_mock.db.execute.return_value.fetchone.return_value = [1, 2, 3] + redis_mock = mock.Mock() + redis_mock.get.return_value = self.test_dataset + data_set = DatasetType(redis_mock) + data_set.set_dataset_key("geno", "Test") + self.assertEqual(data_set("Test"), "Geno") + redis_mock.set.assert_called_once_with( + "dataset_structure", + ('{"AD-cases-controls-MyersGeno": "Geno", ' + '"AD-cases-controls-MyersPublish": "Publish", ' + '"AKXDGeno": "Geno", ' + '"AXBXAGeno": "Geno", ' + '"AXBXAPublish": "Publish", ' + '"Aging-Brain-UCIPublish": "Publish", ' + '"All Phenotypes": "Publish", ' + '"B139_K_1206_M": "ProbeSet", ' + '"B139_K_1206_R": "ProbeSet", ' + '"Test": "Geno"}')) + + db_mock.db.execute.assert_called_with( + ("SELECT GenoFreeze.Id FROM " + "GenoFreeze WHERE GenoFreeze.Name = \"Test\" ")) diff --git a/wqflask/tests/unit/base/test_general_object.py b/wqflask/tests/unit/base/test_general_object.py new file mode 100644 index 00000000..00fd3c72 --- /dev/null +++ b/wqflask/tests/unit/base/test_general_object.py @@ -0,0 +1,40 @@ +import unittest + +from base.GeneralObject import GeneralObject + + +class TestGeneralObjectTests(unittest.TestCase): + """ + Test the GeneralObject base class + """ + + def test_object_contents(self): + """Test whether base contents are stored properly""" + test_obj = GeneralObject("a", "b", "c") + self.assertEqual("abc", ''.join(test_obj.contents)) + self.assertEqual(len(test_obj), 0) + + def test_object_dict(self): + """Test whether the base class is printed properly""" + test_obj = GeneralObject("a", name="test", value=1) + self.assertEqual(str(test_obj), "name = test\nvalue = 1\n") + self.assertEqual( + repr(test_obj), "contents = ['a']\nname = test\nvalue = 1\n") + self.assertEqual(len(test_obj), 2) + self.assertEqual(test_obj["value"], 1) + test_obj["test"] = 1 + self.assertEqual(test_obj["test"], 1) + + def test_get_attribute(self): + "Test that getattr works" + test_obj = GeneralObject("a", name="test", value=1) + self.assertEqual(getattr(test_obj, "value", None), 1) + self.assertEqual(getattr(test_obj, "non-existent", None), None) + + def test_object_comparisons(self): + "Test that 2 objects of the same length are equal" + test_obj1 = GeneralObject("a", name="test", value=1) + test_obj2 = GeneralObject("b", name="test2", value=2) + test_obj3 = GeneralObject("a", name="test", x=1, y=2) + self.assertTrue(test_obj1 == test_obj2) + self.assertFalse(test_obj1 == test_obj3) diff --git a/wqflask/tests/unit/base/test_trait.py b/wqflask/tests/unit/base/test_trait.py new file mode 100644 index 00000000..826ccefd --- /dev/null +++ b/wqflask/tests/unit/base/test_trait.py @@ -0,0 +1,241 @@ +# -*- coding: utf-8 -*- +"""Tests wqflask/base/trait.py""" +import unittest +from unittest import mock + +from wqflask import app +from base.trait import GeneralTrait +from base.trait import retrieve_trait_info + + +class TestResponse: + """Mock Test Response after a request""" + @property + def content(self): + """Mock the content from Requests.get(params).content""" + return "[1, 2, 3, 4]" + + +class TestNilResponse: + """Mock Test Response after a request""" + @property + def content(self): + """Mock the content from Requests.get(params).content""" + return "{}" + + +class MockTrait(GeneralTrait): + @property + def wikidata_alias_fmt(self): + return "Mock alias" + + +class TestRetrieveTraitInfo(unittest.TestCase): + """Tests for 'retrieve_trait_info'""" + + def setUp(self): + self.app_context = app.app_context() + self.app_context.push() + + def tearDown(self): + self.app_context.pop() + + def test_retrieve_trait_info_with_empty_dataset(self): + """Test that an exception is raised when dataset is empty""" + with self.assertRaises(AssertionError): + retrieve_trait_info(trait=mock.MagicMock(), + dataset={}) + + @mock.patch('base.trait.requests.get') + @mock.patch('base.trait.g', mock.Mock()) + def test_retrieve_trait_info_with_empty_trait_info(self, + requests_mock): + """Empty trait info""" + requests_mock.return_value = TestNilResponse() + with self.assertRaises(KeyError): + retrieve_trait_info(trait=mock.MagicMock(), + dataset=mock.MagicMock()) + + @mock.patch('base.trait.requests.get') + @mock.patch('base.trait.g', mock.Mock()) + def test_retrieve_trait_info_with_non_empty_trait_info(self, + requests_mock): + """Test that attributes are set""" + mock_dataset = mock.MagicMock() + requests_mock.return_value = TestResponse() + type(mock_dataset).display_fields = mock.PropertyMock( + return_value=["a", "b", "c", "d"]) + test_trait = retrieve_trait_info(trait=MockTrait(dataset=mock_dataset), + dataset=mock_dataset) + self.assertEqual(test_trait.a, 1) + self.assertEqual(test_trait.b, 2) + self.assertEqual(test_trait.c, 3) + self.assertEqual(test_trait.d, 4) + + @mock.patch('base.trait.requests.get') + @mock.patch('base.trait.g', mock.Mock()) + def test_retrieve_trait_info_utf8_parsing(self, + requests_mock): + """Test that utf-8 strings are parsed correctly""" + utf_8_string = "test_string" + mock_dataset = mock.MagicMock() + requests_mock.return_value = TestResponse() + type(mock_dataset).display_fields = mock.PropertyMock( + return_value=["a", "b", "c", "d"]) + type(mock_dataset).type = 'Publish' + + mock_trait = MockTrait( + dataset=mock_dataset, + pre_publication_description=utf_8_string + ) + trait_attrs = { + "group_code": "test_code", + "pre_publication_description": "test_pre_pub", + "pre_publication_abbreviation": "ファイルを画面毎に見て行くには、次のコマンドを使います。", + "post_publication_description": None, + "pubmed_id": None, + 'year': "2020", + "authors": "Jane Doe かいと", + } + for key, val in list(trait_attrs.items()): + setattr(mock_trait, key, val) + test_trait = retrieve_trait_info(trait=mock_trait, + dataset=mock_dataset) + self.assertEqual(test_trait.abbreviation, + "ファイルを画面毎に見て行くには、次のコマンドを使います。") + self.assertEqual(test_trait.authors, + "Jane Doe かいと") + + @mock.patch('base.trait.requests.get') + @mock.patch('base.trait.g') + @mock.patch('base.trait.get_resource_id') + def test_retrieve_trait_info_with_non_empty_lrs(self, + resource_id_mock, + g_mock, + requests_mock): + """Test retrieve trait info when lrs has a value""" + resource_id_mock.return_value = 1 + g_mock.db.execute.return_value.fetchone = mock.Mock() + g_mock.db.execute.return_value.fetchone.side_effect = [ + [1, 2, 3, 4], # trait_info = g.db.execute(query).fetchone() + [1, 2.37, 3, 4, 5], # trait_qtl = g.db.execute(query).fetchone() + [2.7333, 2.1204] # trait_info = g.db.execute(query).fetchone() + ] + requests_mock.return_value = None + + mock_dataset = mock.MagicMock() + type(mock_dataset).display_fields = mock.PropertyMock( + return_value=["a", "b", "c", "d"]) + type(mock_dataset).type = "ProbeSet" + type(mock_dataset).name = "RandomName" + + mock_trait = MockTrait( + dataset=mock_dataset, + pre_publication_description="test_string" + ) + trait_attrs = { + "description": "some description", + "probe_target_description": "some description", + "cellid": False, + "chr": 2.733, + "mb": 2.1204 + } + + for key, val in list(trait_attrs.items()): + setattr(mock_trait, key, val) + test_trait = retrieve_trait_info(trait=mock_trait, + dataset=mock_dataset, + get_qtl_info=True) + self.assertEqual(test_trait.LRS_score_repr, + "2.4") + + @mock.patch('base.trait.requests.get') + @mock.patch('base.trait.g') + @mock.patch('base.trait.get_resource_id') + def test_retrieve_trait_info_with_empty_lrs_field(self, + resource_id_mock, + g_mock, + requests_mock): + """Test retrieve trait info with empty lrs field""" + resource_id_mock.return_value = 1 + g_mock.db.execute.return_value.fetchone = mock.Mock() + g_mock.db.execute.return_value.fetchone.side_effect = [ + [1, 2, 3, 4], # trait_info = g.db.execute(query).fetchone() + [1, None, 3, 4, 5], # trait_qtl = g.db.execute(query).fetchone() + [2, 3] # trait_info = g.db.execute(query).fetchone() + ] + requests_mock.return_value = None + + mock_dataset = mock.MagicMock() + type(mock_dataset).display_fields = mock.PropertyMock( + return_value=["a", "b", "c", "d"]) + type(mock_dataset).type = "ProbeSet" + type(mock_dataset).name = "RandomName" + + mock_trait = MockTrait( + dataset=mock_dataset, + pre_publication_description="test_string" + ) + trait_attrs = { + "description": "some description", + "probe_target_description": "some description", + "cellid": False, + "chr": 2.733, + "mb": 2.1204 + } + + for key, val in list(trait_attrs.items()): + setattr(mock_trait, key, val) + test_trait = retrieve_trait_info(trait=mock_trait, + dataset=mock_dataset, + get_qtl_info=True) + self.assertEqual(test_trait.LRS_score_repr, + "N/A") + self.assertEqual(test_trait.LRS_location_repr, + "Chr2: 3.000000") + + @mock.patch('base.trait.requests.get') + @mock.patch('base.trait.g') + @mock.patch('base.trait.get_resource_id') + def test_retrieve_trait_info_with_empty_chr_field(self, + resource_id_mock, + g_mock, + requests_mock): + """Test retrieve trait info with empty chr field""" + resource_id_mock.return_value = 1 + g_mock.db.execute.return_value.fetchone = mock.Mock() + g_mock.db.execute.return_value.fetchone.side_effect = [ + [1, 2, 3, 4], # trait_info = g.db.execute(query).fetchone() + [1, 2, 3, 4, 5], # trait_qtl = g.db.execute(query).fetchone() + [None, 3] # trait_info = g.db.execute(query).fetchone() + ] + + requests_mock.return_value = None + + mock_dataset = mock.MagicMock() + type(mock_dataset).display_fields = mock.PropertyMock( + return_value=["a", "b", "c", "d"]) + type(mock_dataset).type = "ProbeSet" + type(mock_dataset).name = "RandomName" + + mock_trait = MockTrait( + dataset=mock_dataset, + pre_publication_description="test_string" + ) + trait_attrs = { + "description": "some description", + "probe_target_description": "some description", + "cellid": False, + "chr": 2.733, + "mb": 2.1204 + } + + for key, val in list(trait_attrs.items()): + setattr(mock_trait, key, val) + test_trait = retrieve_trait_info(trait=mock_trait, + dataset=mock_dataset, + get_qtl_info=True) + self.assertEqual(test_trait.LRS_score_repr, + "N/A") + self.assertEqual(test_trait.LRS_location_repr, + "N/A") diff --git a/wqflask/tests/unit/base/test_webqtl_case_data.py b/wqflask/tests/unit/base/test_webqtl_case_data.py new file mode 100644 index 00000000..8e8ba482 --- /dev/null +++ b/wqflask/tests/unit/base/test_webqtl_case_data.py @@ -0,0 +1,39 @@ +"""Tests for wqflask/base/webqtlCaseData.py""" +import unittest + +from wqflask import app # Required because of utility.tools in webqtlCaseData.py +from base.webqtlCaseData import webqtlCaseData + +class TestWebqtlCaseData(unittest.TestCase): + """Tests for WebqtlCaseData class""" + + def setUp(self): + self.w = webqtlCaseData(name="Test", + value=0, + variance=0.0, + num_cases=10, + name2="Test2") + + def test_webqtl_case_data_repr(self): + self.assertEqual( + repr(self.w), + " value=0.000 variance=0.000 ndata=10 name=Test name2=Test2" + ) + + def test_class_outlier(self): + self.assertEqual(self.w.class_outlier, "") + + def test_display_value(self): + self.assertEqual(self.w.display_value, "0.000") + self.w.value = None + self.assertEqual(self.w.display_value, "x") + + def test_display_variance(self): + self.assertEqual(self.w.display_variance, "0.000") + self.w.variance = None + self.assertEqual(self.w.display_variance, "x") + + def test_display_num_cases(self): + self.assertEqual(self.w.display_num_cases, "10") + self.w.num_cases = None + self.assertEqual(self.w.display_num_cases, "x") diff --git a/wqflask/tests/unit/utility/__init__.py b/wqflask/tests/unit/utility/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/wqflask/tests/unit/utility/test_authentication_tools.py b/wqflask/tests/unit/utility/test_authentication_tools.py new file mode 100644 index 00000000..5c391be5 --- /dev/null +++ b/wqflask/tests/unit/utility/test_authentication_tools.py @@ -0,0 +1,189 @@ +"""Tests for authentication tools""" +import unittest +from unittest import mock + +from utility.authentication_tools import check_resource_availability +from utility.authentication_tools import add_new_resource + + +class TestResponse: + """Mock Test Response after a request""" + @property + def content(self): + """Mock the content from Requests.get(params).content""" + return '["foo"]' + + +class TestUser: + """Mock user""" + @property + def user_id(self): + """Mockes user id. Used in Flask.g.user_session.user_id""" + return "Jane" + + +class TestUserSession: + """Mock user session""" + @property + def user_session(self): + """Mock user session. Mocks Flask.g.user_session object""" + return TestUser() + + +def mock_add_resource(resource_ob, update=False): + return resource_ob + + +class TestCheckResourceAvailability(unittest.TestCase): + """Test methods related to checking the resource availability""" + @mock.patch('utility.authentication_tools.add_new_resource') + @mock.patch('utility.authentication_tools.Redis') + @mock.patch('utility.authentication_tools.g', mock.Mock()) + @mock.patch('utility.authentication_tools.get_resource_id') + def test_check_resource_availability_default_mask( + self, + resource_id_mock, + redis_mock, + add_new_resource_mock): + """Test the resource availability with default mask""" + resource_id_mock.return_value = 1 + redis_mock.smembers.return_value = [] + test_dataset = mock.MagicMock() + type(test_dataset).type = mock.PropertyMock(return_value="Test") + add_new_resource_mock.return_value = {"default_mask": 2} + self.assertEqual(check_resource_availability(test_dataset), 2) + + @mock.patch('utility.authentication_tools.requests.get') + @mock.patch('utility.authentication_tools.add_new_resource') + @mock.patch('utility.authentication_tools.Redis') + @mock.patch('utility.authentication_tools.g', TestUserSession()) + @mock.patch('utility.authentication_tools.get_resource_id') + def test_check_resource_availability_non_default_mask( + self, + resource_id_mock, + redis_mock, + add_new_resource_mock, + requests_mock): + """Test the resource availability with default mask""" + resource_id_mock.return_value = 1 + redis_mock.smembers.return_value = [] + add_new_resource_mock.return_value = {"default_mask": 2} + requests_mock.return_value = TestResponse() + test_dataset = mock.MagicMock() + type(test_dataset).type = mock.PropertyMock(return_value="Test") + self.assertEqual(check_resource_availability(test_dataset), + ['foo']) + + @mock.patch('utility.authentication_tools.webqtlConfig.SUPER_PRIVILEGES', + "SUPERUSER") + @mock.patch('utility.authentication_tools.requests.get') + @mock.patch('utility.authentication_tools.add_new_resource') + @mock.patch('utility.authentication_tools.Redis') + @mock.patch('utility.authentication_tools.g', TestUserSession()) + @mock.patch('utility.authentication_tools.get_resource_id') + def test_check_resource_availability_of_super_user( + self, + resource_id_mock, + redis_mock, + add_new_resource_mock, + requests_mock): + """Test the resource availability if the user is the super user""" + resource_id_mock.return_value = 1 + redis_mock.smembers.return_value = ["Jane"] + add_new_resource_mock.return_value = {"default_mask": 2} + requests_mock.return_value = TestResponse() + test_dataset = mock.MagicMock() + type(test_dataset).type = mock.PropertyMock(return_value="Test") + self.assertEqual(check_resource_availability(test_dataset), + "SUPERUSER") + + @mock.patch('utility.authentication_tools.webqtlConfig.DEFAULT_PRIVILEGES', + "John Doe") + def test_check_resource_availability_string_dataset(self): + """Test the resource availability if the dataset is a string""" + self.assertEqual(check_resource_availability("Test"), + "John Doe") + + @mock.patch('utility.authentication_tools.webqtlConfig.DEFAULT_PRIVILEGES', + "John Doe") + def test_check_resource_availability_temp(self): + """Test the resource availability if the dataset is a string""" + test_dataset = mock.MagicMock() + type(test_dataset).type = mock.PropertyMock(return_value="Temp") + self.assertEqual(check_resource_availability(test_dataset), + "John Doe") + + +class TestAddNewResource(unittest.TestCase): + """Test cases for add_new_resource method""" + @mock.patch('utility.authentication_tools.webqtlConfig.DEFAULT_PRIVILEGES', + "John Doe") + @mock.patch('utility.authentication_tools.add_resource', mock_add_resource) + @mock.patch('utility.authentication_tools.get_group_code') + def test_add_new_resource_if_publish_datatype(self, group_code_mock): + """Test add_new_resource if dataset type is 'publish'""" + group_code_mock.return_value = "Test" + test_dataset = mock.MagicMock() + type(test_dataset).type = mock.PropertyMock(return_value="Publish") + type(test_dataset).id = mock.PropertyMock(return_value=10) + expected_value = { + "owner_id": "none", + "default_mask": "John Doe", + "group_masks": {}, + "name": "Test_None", + "data": { + "dataset": 10, + "trait": None + }, + "type": "dataset-publish" + } + self.assertEqual(add_new_resource(test_dataset), + expected_value) + + @mock.patch('utility.authentication_tools.webqtlConfig.DEFAULT_PRIVILEGES', + "John Doe") + @mock.patch('utility.authentication_tools.add_resource', mock_add_resource) + @mock.patch('utility.authentication_tools.get_group_code') + def test_add_new_resource_if_geno_datatype(self, group_code_mock): + """Test add_new_resource if dataset type is 'geno'""" + group_code_mock.return_value = "Test" + test_dataset = mock.MagicMock() + type(test_dataset).name = mock.PropertyMock(return_value="Geno") + type(test_dataset).type = mock.PropertyMock(return_value="Geno") + type(test_dataset).id = mock.PropertyMock(return_value=20) + expected_value = { + "owner_id": "none", + "default_mask": "John Doe", + "group_masks": {}, + "name": "Geno", + "data": { + "dataset": 20, + }, + "type": "dataset-geno" + } + self.assertEqual(add_new_resource(test_dataset), + expected_value) + + @mock.patch('utility.authentication_tools.webqtlConfig.DEFAULT_PRIVILEGES', + "John Doe") + @mock.patch('utility.authentication_tools.add_resource', mock_add_resource) + @mock.patch('utility.authentication_tools.get_group_code') + def test_add_new_resource_if_other_datatype(self, group_code_mock): + """Test add_new_resource if dataset type is not 'geno' or 'publish'""" + group_code_mock.return_value = "Test" + test_dataset = mock.MagicMock() + type(test_dataset).name = mock.PropertyMock(return_value="Geno") + type(test_dataset).type = mock.PropertyMock(return_value="other") + type(test_dataset).id = mock.PropertyMock(return_value=20) + expected_value = { + "owner_id": "none", + "default_mask": "John Doe", + "group_masks": {}, + "name": "Geno", + "data": { + "dataset": 20, + }, + "type": "dataset-probeset" + } + self.assertEqual(add_new_resource(test_dataset), + expected_value) diff --git a/wqflask/tests/unit/utility/test_chunks.py b/wqflask/tests/unit/utility/test_chunks.py new file mode 100644 index 00000000..8d90a1ec --- /dev/null +++ b/wqflask/tests/unit/utility/test_chunks.py @@ -0,0 +1,19 @@ +"""Test chunking""" + +import unittest + +from utility.chunks import divide_into_chunks + + +class TestChunks(unittest.TestCase): + "Test Utility method for chunking" + def test_divide_into_chunks(self): + "Check that a list is chunked correctly" + self.assertEqual(divide_into_chunks([1, 2, 7, 3, 22, 8, 5, 22, 333], 3), + [[1, 2, 7], [3, 22, 8], [5, 22, 333]]) + self.assertEqual(divide_into_chunks([1, 2, 7, 3, 22, 8, 5, 22, 333], 4), + [[1, 2, 7], [3, 22, 8], [5, 22, 333]]) + self.assertEqual(divide_into_chunks([1, 2, 7, 3, 22, 8, 5, 22, 333], 5), + [[1, 2], [7, 3], [22, 8], [5, 22], [333]]) + self.assertEqual(divide_into_chunks([], 5), + [[]]) diff --git a/wqflask/tests/unit/utility/test_corestats.py b/wqflask/tests/unit/utility/test_corestats.py new file mode 100644 index 00000000..cf91a248 --- /dev/null +++ b/wqflask/tests/unit/utility/test_corestats.py @@ -0,0 +1,55 @@ +"""Test Core Stats""" + +import unittest + +from utility.corestats import Stats + + +class TestChunks(unittest.TestCase): + "Test Utility method for chunking" + + def setUp(self): + self.stat_test = Stats((x for x in range(1, 11))) + + def test_stats_sum(self): + """ Test sequence sum """ + self.assertEqual(self.stat_test.sum(), 55) + self.stat_test = Stats([]) + self.assertEqual(self.stat_test.sum(), None) + + def test_stats_count(self): + """ Test sequence count """ + self.assertEqual(self.stat_test.count(), 10) + self.stat_test = Stats([]) + self.assertEqual(self.stat_test.count(), 0) + + def test_stats_min(self): + """ Test min value in sequence""" + self.assertEqual(self.stat_test.min(), 1) + self.stat_test = Stats([]) + self.assertEqual(self.stat_test.min(), None) + + def test_stats_max(self): + """ Test max value in sequence """ + self.assertEqual(self.stat_test.max(), 10) + self.stat_test = Stats([]) + self.assertEqual(self.stat_test.max(), None) + + def test_stats_avg(self): + """ Test avg of sequence """ + self.assertEqual(self.stat_test.avg(), 5.5) + self.stat_test = Stats([]) + self.assertEqual(self.stat_test.avg(), None) + + def test_stats_stdev(self): + """ Test standard deviation of sequence """ + self.assertEqual(self.stat_test.stdev(), 3.0276503540974917) + self.stat_test = Stats([]) + self.assertEqual(self.stat_test.stdev(), None) + + def test_stats_percentile(self): + """ Test percentile of sequence """ + self.assertEqual(self.stat_test.percentile(20), 3.0) + self.assertEqual(self.stat_test.percentile(101), None) + self.stat_test = Stats([]) + self.assertEqual(self.stat_test.percentile(20), None) diff --git a/wqflask/tests/unit/utility/test_corr_result_helpers.py b/wqflask/tests/unit/utility/test_corr_result_helpers.py new file mode 100644 index 00000000..e196fbdf --- /dev/null +++ b/wqflask/tests/unit/utility/test_corr_result_helpers.py @@ -0,0 +1,32 @@ +""" Test correlation helper methods """ + +import unittest +from utility.corr_result_helpers import normalize_values, common_keys, normalize_values_with_samples + + +class TestCorrelationHelpers(unittest.TestCase): + """Test methods for normalising lists""" + + def test_normalize_values(self): + """Test that a list is normalised correctly""" + self.assertEqual( + normalize_values([2.3, None, None, 3.2, 4.1, 5], [ + 3.4, 7.2, 1.3, None, 6.2, 4.1]), + ([2.3, 4.1, 5], [3.4, 6.2, 4.1], 3) + ) + + def test_common_keys(self): + """Test that common keys are returned as a list""" + a = dict(BXD1=9.113, BXD2=9.825, BXD14=8.985, BXD15=9.300) + b = dict(BXD1=9.723, BXD3=9.825, BXD14=9.124, BXD16=9.300) + self.assertEqual(sorted(common_keys(a, b)), ['BXD1', 'BXD14']) + + def test_normalize_values_with_samples(self): + """Test that a sample(dict) is normalised correctly""" + self.assertEqual( + normalize_values_with_samples( + dict(BXD1=9.113, BXD2=9.825, BXD14=8.985, + BXD15=9.300, BXD20=9.300), + dict(BXD1=9.723, BXD3=9.825, BXD14=9.124, BXD16=9.300)), + (({'BXD1': 9.113, 'BXD14': 8.985}, {'BXD1': 9.723, 'BXD14': 9.124}, 2)) + ) diff --git a/wqflask/tests/unit/utility/test_formatting.py b/wqflask/tests/unit/utility/test_formatting.py new file mode 100644 index 00000000..9d3033d1 --- /dev/null +++ b/wqflask/tests/unit/utility/test_formatting.py @@ -0,0 +1,33 @@ +import unittest +from utility.formatting import numify, commify + + +class TestFormatting(unittest.TestCase): + """Test formatting numbers by numifying or commifying""" + + def test_numify(self): + "Test that a number is correctly converted to a English readable string" + self.assertEqual(numify(1, 'item', 'items'), + 'one item') + self.assertEqual(numify(2, 'book'), 'two') + self.assertEqual(numify(2, 'book', 'books'), 'two books') + self.assertEqual(numify(0, 'book', 'books'), 'zero books') + self.assertEqual(numify(0), 'zero') + self.assertEqual(numify(5), 'five') + self.assertEqual(numify(14, 'book', 'books'), '14 books') + self.assertEqual(numify(999, 'book', 'books'), '999 books') + self.assertEqual(numify(1000000, 'book', 'books'), '1,000,000 books') + self.assertEqual(numify(1956), '1956') + + def test_commify(self): + "Test that commas are added correctly" + self.assertEqual(commify(1), '1') + self.assertEqual(commify(123), '123') + self.assertEqual(commify(1234), '1234') + self.assertEqual(commify(12345), '12,345') + self.assertEqual(commify(1234567890), '1,234,567,890') + self.assertEqual(commify(123.0), '123.0') + self.assertEqual(commify(1234.5), '1234.5') + self.assertEqual(commify(1234.56789), '1234.56789') + self.assertEqual(commify(123456.789), '123,456.789') + self.assertEqual(commify(None), None) diff --git a/wqflask/tests/unit/utility/test_hmac.py b/wqflask/tests/unit/utility/test_hmac.py new file mode 100644 index 00000000..4e3652f8 --- /dev/null +++ b/wqflask/tests/unit/utility/test_hmac.py @@ -0,0 +1,52 @@ +# -*- coding: utf-8 -*- +"""Test hmac utility functions""" + +import unittest +from unittest import mock + +from utility.hmac import data_hmac +from utility.hmac import url_for_hmac +from utility.hmac import hmac_creation + + +class TestHmacUtil(unittest.TestCase): + """Test Utility method for hmac creation""" + + @mock.patch("utility.hmac.app.config", {'SECRET_HMAC_CODE': "secret"}) + def test_hmac_creation(self): + """Test hmac creation with a utf-8 string""" + self.assertEqual(hmac_creation("ファイ"), "7410466338cfe109e946") + + @mock.patch("utility.hmac.app.config", + {'SECRET_HMAC_CODE': ('\x08\xdf\xfa\x93N\x80' + '\xd9\\H@\\\x9f`\x98d^' + '\xb4a;\xc6OM\x946a\xbc' + '\xfc\x80:*\xebc')}) + def test_hmac_creation_with_cookie(self): + """Test hmac creation with a cookie""" + cookie = "3f4c1dbf-5b56-4260-87d6-f35445bda37e:af4fcf5eace9e7c864ce" + uuid_, _, signature = cookie.partition(":") + self.assertEqual( + hmac_creation(uuid_), + "af4fcf5eace9e7c864ce") + + @mock.patch("utility.hmac.app.config", {'SECRET_HMAC_CODE': "secret"}) + def test_data_hmac(self): + """Test data_hmac fn with a utf-8 string""" + self.assertEqual(data_hmac("ファイ"), "ファイ:7410466338cfe109e946") + + @mock.patch("utility.hmac.app.config", {'SECRET_HMAC_CODE': "secret"}) + @mock.patch("utility.hmac.url_for") + def test_url_for_hmac_with_plain_url(self, mock_url): + """Test url_for_hmac without params""" + mock_url.return_value = "https://mock_url.com/ファイ/" + self.assertEqual(url_for_hmac("ファイ"), + "https://mock_url.com/ファイ/?hm=05bc39e659b1948f41e7") + + @mock.patch("utility.hmac.app.config", {'SECRET_HMAC_CODE': "secret"}) + @mock.patch("utility.hmac.url_for") + def test_url_for_hmac_with_param_in_url(self, mock_url): + """Test url_for_hmac with params""" + mock_url.return_value = "https://mock_url.com/?ファイ=1" + self.assertEqual(url_for_hmac("ファイ"), + "https://mock_url.com/?ファイ=1&hm=4709c1708270644aed79") diff --git a/wqflask/tests/unit/wqflask/__init__.py b/wqflask/tests/unit/wqflask/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/wqflask/tests/unit/wqflask/api/__init__.py b/wqflask/tests/unit/wqflask/api/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/wqflask/tests/unit/wqflask/api/test_gen_menu.py b/wqflask/tests/unit/wqflask/api/test_gen_menu.py new file mode 100644 index 00000000..84898bd1 --- /dev/null +++ b/wqflask/tests/unit/wqflask/api/test_gen_menu.py @@ -0,0 +1,413 @@ +"""Test cases for wqflask.api.gen_menu""" +import unittest +from unittest import mock + +from wqflask import app +from wqflask.api.gen_menu import gen_dropdown_json +from wqflask.api.gen_menu import get_species +from wqflask.api.gen_menu import get_groups +from wqflask.api.gen_menu import get_types +from wqflask.api.gen_menu import get_datasets +from wqflask.api.gen_menu import phenotypes_exist +from wqflask.api.gen_menu import genotypes_exist +from wqflask.api.gen_menu import build_datasets +from wqflask.api.gen_menu import build_types + + +class TestGenMenu(unittest.TestCase): + """Tests for the gen_menu module""" + + def setUp(self): + self.app_context = app.app_context() + self.app_context.push() + self.test_group = { + 'mouse': [ + ['H_T1', + 'H_T', + 'Family:DescriptionA' + ], + ['H_T2', "H_T'", 'Family:None'] + ], + 'human': [ + ['BXD', 'BXD', 'Family:None'], + ['HLC', 'Liver: Normal Gene Expression with Genotypes (Merck)', + 'Family:Test'] + ] + } + + self.test_type = { + 'mouse': { + 'H_T2': [('Phenotypes', + 'Traits and Cofactors', + 'Phenotypes'), + ('Genotypes', + 'DNA Markers and SNPs', + 'Genotypes'), + ['M', 'M', 'Molecular Trait Datasets']], + 'H_T1': [('Phenotypes', + 'Traits and Cofactors', + 'Phenotypes'), + ('Genotypes', + 'DNA Markers and SNPs', + 'Genotypes'), + ['M', 'M', 'Molecular Trait Datasets']] + }, + 'human': { + 'HLC': [('Phenotypes', + 'Traits and Cofactors', + 'Phenotypes'), + ('Genotypes', + 'DNA Markers and SNPs', + 'Genotypes'), + ['M', 'M', 'Molecular Trait Datasets']], + 'BXD': [('Phenotypes', + 'Traits and Cofactors', + 'Phenotypes'), + ('Genotypes', + 'DNA Markers and SNPs', + 'Genotypes'), + ['M', 'M', 'Molecular Trait Datasets']] + } + } + + def tearDown(self): + self.app_context.pop() + + @mock.patch('wqflask.api.gen_menu.g') + def test_get_species(self, db_mock): + """Test that assertion is raised when dataset and dataset_name + are defined""" + db_mock.db.execute.return_value.fetchall.return_value = ( + ('human', 'Human'), + ('mouse', 'Mouse')) + self.assertEqual(get_species(), + [['human', 'Human'], ['mouse', 'Mouse']]) + db_mock.db.execute.assert_called_once_with( + "SELECT Name, MenuName FROM Species ORDER BY OrderId" + ) + + @mock.patch('wqflask.api.gen_menu.g') + def test_get_groups(self, db_mock): + """Test that species groups are grouped correctly""" + db_mock.db.execute.return_value.fetchall.side_effect = [ + # Mouse + (('BXD', 'BXD', None), + ('HLC', 'Liver: Normal Gene Expression with Genotypes (Merck)', + 'Test')), + # Human + (('H_T1', "H_T", "DescriptionA"), + ('H_T2', "H_T'", None)) + ] + + self.assertEqual(get_groups([["human", "Human"], ["mouse", "Mouse"]]), + self.test_group) + + for name in ["mouse", "human"]: + db_mock.db.execute.assert_any_call( + ("SELECT InbredSet.Name, InbredSet.FullName, " + + "IFNULL(InbredSet.Family, 'None') " + + "FROM InbredSet, Species WHERE Species.Name " + + "= '{}' AND InbredSet.SpeciesId = Species.Id GROUP by " + + "InbredSet.Name ORDER BY IFNULL(InbredSet.FamilyOrder, " + + "InbredSet.FullName) ASC, IFNULL(InbredSet.Family, " + + "InbredSet.FullName) ASC, InbredSet.FullName ASC, " + + "InbredSet.MenuOrderId ASC").format(name) + ) + + @mock.patch('wqflask.api.gen_menu.g') + def test_phenotypes_exist_called_with_correct_query(self, db_mock): + """Test that phenotypes_exist is called with the correct query""" + db_mock.db.execute.return_value.fetchone.return_value = None + phenotypes_exist("test") + db_mock.db.execute.assert_called_with( + "SELECT Name FROM PublishFreeze " + "WHERE PublishFreeze.Name = 'testPublish'" + ) + + @mock.patch('wqflask.api.gen_menu.g') + def test_phenotypes_exist_with_falsy_values(self, db_mock): + """Test that phenotype check returns correctly when given + a None value""" + for x in [None, False, (), [], ""]: + db_mock.db.execute.return_value.fetchone.return_value = x + self.assertFalse(phenotypes_exist("test")) + + @mock.patch('wqflask.api.gen_menu.g') + def test_phenotypes_exist_with_truthy_value(self, db_mock): + """Test that phenotype check returns correctly when given Truthy """ + for x in ["x", ("result"), ["result"], [1]]: + db_mock.db.execute.return_value.fetchone.return_value = (x) + self.assertTrue(phenotypes_exist("test")) + + @mock.patch('wqflask.api.gen_menu.g') + def test_genotypes_exist_called_with_correct_query(self, db_mock): + """Test that genotypes_exist is called with the correct query""" + db_mock.db.execute.return_value.fetchone.return_value = None + genotypes_exist("test") + db_mock.db.execute.assert_called_with( + "SELECT Name FROM GenoFreeze WHERE GenoFreeze.Name = 'testGeno'" + ) + + @mock.patch('wqflask.api.gen_menu.g') + def test_genotypes_exist_with_falsy_values(self, db_mock): + """Test that genotype check returns correctly when given + a None value""" + for x in [None, False, (), [], ""]: + db_mock.db.execute.return_value.fetchone.return_value = x + self.assertFalse(genotypes_exist("test")) + + @mock.patch('wqflask.api.gen_menu.g') + def test_genotypes_exist_with_truthy_value(self, db_mock): + """Test that genotype check returns correctly when given Truthy """ + for x in ["x", ("result"), ["result"], [1]]: + db_mock.db.execute.return_value.fetchone.return_value = (x) + self.assertTrue(phenotypes_exist("test")) + + @mock.patch('wqflask.api.gen_menu.g') + def test_build_datasets_with_type_phenotypes(self, db_mock): + """Test that correct dataset is returned for a phenotype type""" + db_mock.db.execute.return_value.fetchall.return_value = ( + (602, "BXDPublish", "BXD Published Phenotypes"), + ) + self.assertEqual(build_datasets("Mouse", "BXD", "Phenotypes"), + [['602', "BXDPublish", "BXD Published Phenotypes"]]) + db_mock.db.execute.assert_called_with( + "SELECT InfoFiles.GN_AccesionId, PublishFreeze.Name, " + + "PublishFreeze.FullName FROM InfoFiles, PublishFreeze, " + + "InbredSet WHERE InbredSet.Name = 'BXD' AND " + + "PublishFreeze.InbredSetId = InbredSet.Id AND " + + "InfoFiles.InfoPageName = PublishFreeze.Name " + + "ORDER BY PublishFreeze.CreateTime ASC" + ) + self.assertEqual(build_datasets("Mouse", "MDP", "Phenotypes"), + [['602', "BXDPublish", "Mouse Phenome Database"]]) + + db_mock.db.execute.return_value.fetchall.return_value = () + db_mock.db.execute.return_value.fetchone.return_value = ( + "BXDPublish", "Mouse Phenome Database" + ) + self.assertEqual(build_datasets("Mouse", "MDP", "Phenotypes"), + [["None", "BXDPublish", "Mouse Phenome Database"]]) + + @mock.patch('wqflask.api.gen_menu.g') + def test_build_datasets_with_type_phenotypes_and_no_results(self, db_mock): + """Test that correct dataset is returned for a phenotype type with no + results + + """ + db_mock.db.execute.return_value.fetchall.return_value = None + db_mock.db.execute.return_value.fetchone.return_value = (121, + "text value") + self.assertEqual(build_datasets("Mouse", "BXD", "Phenotypes"), + [["None", "121", "text value"]]) + db_mock.db.execute.assert_called_with( + "SELECT PublishFreeze.Name, PublishFreeze.FullName " + "FROM PublishFreeze, InbredSet " + "WHERE InbredSet.Name = 'BXD' AND " + "PublishFreeze.InbredSetId = InbredSet.Id " + "ORDER BY PublishFreeze.CreateTime ASC" + ) + + @mock.patch('wqflask.api.gen_menu.g') + def test_build_datasets_with_type_genotypes(self, db_mock): + """Test that correct dataset is returned for a phenotype type""" + db_mock.db.execute.return_value.fetchone.return_value = ( + 635, "HLCPublish", "HLC Published Genotypes" + ) + + self.assertEqual(build_datasets("Mouse", "HLC", "Genotypes"), + [["635", "HLCGeno", "HLC Genotypes"]]) + db_mock.db.execute.assert_called_with( + "SELECT InfoFiles.GN_AccesionId FROM InfoFiles, " + "GenoFreeze, InbredSet WHERE InbredSet.Name = 'HLC' AND " + "GenoFreeze.InbredSetId = InbredSet.Id AND " + "InfoFiles.InfoPageName = GenoFreeze.ShortName " + + "ORDER BY GenoFreeze.CreateTime DESC" + ) + db_mock.db.execute.return_value.fetchone.return_value = () + self.assertEqual(build_datasets("Mouse", "HLC", "Genotypes"), + [["None", "HLCGeno", "HLC Genotypes"]]) + + @mock.patch('wqflask.api.gen_menu.g') + def test_build_datasets_with_type_mrna(self, db_mock): + """Test that correct dataset is returned for a mRNA + expression/ Probeset""" + db_mock.db.execute.return_value.fetchall.return_value = ( + (112, "HC_M2_0606_P", + "Hippocampus Consortium M430v2 (Jun06) PDNN"), ) + self.assertEqual(build_datasets("Mouse", "HLC", "mRNA"), [[ + "112", 'HC_M2_0606_P', "Hippocampus Consortium M430v2 (Jun06) PDNN" + ]]) + db_mock.db.execute.assert_called_once_with( + "SELECT ProbeSetFreeze.Id, ProbeSetFreeze.Name, " + + "ProbeSetFreeze.FullName FROM ProbeSetFreeze, " + + "ProbeFreeze, InbredSet, Tissue, Species WHERE " + + "Species.Name = 'Mouse' AND Species.Id = " + + "InbredSet.SpeciesId AND InbredSet.Name = 'HLC' AND " + + "ProbeSetFreeze.ProbeFreezeId = ProbeFreeze.Id and " + + "Tissue.Name = 'mRNA' AND ProbeFreeze.TissueId = " + + "Tissue.Id and ProbeFreeze.InbredSetId = InbredSet.Id " + + "ORDER BY ProbeSetFreeze.CreateTime DESC") + + @mock.patch('wqflask.api.gen_menu.build_datasets') + @mock.patch('wqflask.api.gen_menu.g') + def test_build_types(self, db_mock, datasets_mock): + """Test that correct tissue metadata is returned""" + datasets_mock.return_value = [ + ["112", 'HC_M2_0606_P', + "Hippocampus Consortium M430v2 (Jun06) PDNN"] + ] + db_mock.db.execute.return_value.fetchall.return_value = ( + ('Mouse Tissue'), ('Human Tissue'), ('Rat Tissue') + ) + self.assertEqual(build_types('mouse', 'random group'), + [['M', 'M', 'Molecular Traits'], + ['H', 'H', 'Molecular Traits'], + ['R', 'R', 'Molecular Traits']]) + db_mock.db.execute.assert_called_once_with( + "SELECT DISTINCT Tissue.Name " + + "FROM ProbeFreeze, ProbeSetFreeze, InbredSet, " + + "Tissue, Species WHERE Species.Name = 'mouse' " + + "AND Species.Id = InbredSet.SpeciesId AND " + + "InbredSet.Name = 'random group' AND " + + "ProbeFreeze.TissueId = Tissue.Id AND " + + "ProbeFreeze.InbredSetId = InbredSet.Id AND " + + "ProbeSetFreeze.ProbeFreezeId = ProbeFreeze.Id " + + "ORDER BY Tissue.Name" + ) + + @mock.patch('wqflask.api.gen_menu.build_types') + @mock.patch('wqflask.api.gen_menu.genotypes_exist') + @mock.patch('wqflask.api.gen_menu.phenotypes_exist') + def test_get_types_with_existing_genotype_and_phenotypes( + self, + phenotypes_exist_mock, + genotypes_exist_mock, + build_types_mock): + """Test that build types are constructed correctly if phenotypes and genotypes + exist + + """ + phenotypes_exist_mock.return_value = True + genotypes_exist_mock.return_value = True + + expected_result = self.test_type + + build_types_mock.return_value = [ + ['M', 'M', 'Molecular Trait Datasets'] + ] + self.assertEqual(get_types(self.test_group), expected_result) + + @mock.patch('wqflask.api.gen_menu.build_types') + @mock.patch('wqflask.api.gen_menu.genotypes_exist') + @mock.patch('wqflask.api.gen_menu.phenotypes_exist') + def test_get_types_with_buildtype_and_non_existent_genotype_and_phenotypes( + self, + phenotypes_exist_mock, + genotypes_exist_mock, + build_types_mock): + """Test that build types are constructed correctly if phenotypes_exist and + genotypes_exist are false but build_type is falsy + + """ + phenotypes_exist_mock.return_value = False + genotypes_exist_mock.return_value = False + + build_types_mock.return_value = [] + self.assertEqual(get_types(self.test_group), { + 'mouse': {}, + 'human': {} + }) + + @mock.patch('wqflask.api.gen_menu.build_types') + @mock.patch('wqflask.api.gen_menu.genotypes_exist') + @mock.patch('wqflask.api.gen_menu.phenotypes_exist') + def test_get_types_with_non_existent_genotype_phenotypes_and_buildtype( + self, + phenotypes_exist_mock, + genotypes_exist_mock, + build_types_mock): + """Test that build types are constructed correctly if phenotypes_exist, + genotypes_exist and build_types are truthy + + """ + phenotypes_exist_mock.return_value = False + genotypes_exist_mock.return_value = False + + build_types_mock.return_value = [ + ['M', 'M', 'Molecular Trait Datasets'] + ] + expected_result = { + 'mouse': { + 'H_T2': [['M', 'M', 'Molecular Trait Datasets']], + 'H_T1': [['M', 'M', 'Molecular Trait Datasets']]}, + 'human': { + 'HLC': [['M', 'M', 'Molecular Trait Datasets']], + 'BXD': [['M', 'M', 'Molecular Trait Datasets']]}} + self.assertEqual(get_types(self.test_group), + expected_result) + + @mock.patch('wqflask.api.gen_menu.build_datasets') + def test_get_datasets_with_existent_datasets(self, + build_datasets_mock): + """Test correct dataset is returned with existent build_datasets""" + build_datasets_mock.return_value = "Test" + expected_result = { + 'mouse': { + 'H_T2': {'Genotypes': 'Test', + 'M': 'Test', + 'Phenotypes': 'Test'}, + 'H_T1': {'Genotypes': 'Test', + 'M': 'Test', + 'Phenotypes': 'Test'}}, + 'human': {'HLC': {'Genotypes': 'Test', + 'M': 'Test', + 'Phenotypes': 'Test'}, + 'BXD': {'Genotypes': 'Test', + 'M': 'Test', + 'Phenotypes': 'Test'}}} + self.assertEqual(get_datasets(self.test_type), + expected_result) + + @mock.patch('wqflask.api.gen_menu.build_datasets') + def test_get_datasets_with_non_existent_datasets(self, + build_datasets_mock): + """Test correct dataset is returned with non-existent build_datasets""" + build_datasets_mock.return_value = None + expected_result = { + 'mouse': { + 'H_T2': {}, + 'H_T1': {}}, + 'human': {'HLC': {}, + 'BXD': {}}} + self.assertEqual(get_datasets(self.test_type), + expected_result) + + @mock.patch('wqflask.api.gen_menu.get_datasets') + @mock.patch('wqflask.api.gen_menu.get_types') + @mock.patch('wqflask.api.gen_menu.get_groups') + @mock.patch('wqflask.api.gen_menu.get_species') + def test_gen_dropdown_json(self, + species_mock, + groups_mock, + types_mock, + datasets_mock): + "Test that the correct dictionary is constructed properly" + species_mock.return_value = ("speciesA speciesB speciesC speciesD" + .split(" ")) + datasets_mock.return_value = ("datasetA datasetB datasetC datasetD" + .split(" ")) + groups_mock.return_value = ("groupA groupB groupC groupD" + .split(" ")) + types_mock.return_value = ("typeA typeB typeC typeD" + .split(" ")) + datasets_mock.return_value = ("datasetA datasetB datasetC datasetD" + .split(" ")) + + expected_result = { + 'datasets': ['datasetA', 'datasetB', 'datasetC', 'datasetD'], + 'types': ['typeA', 'typeB', 'typeC', 'typeD'], + 'groups': ['groupA', 'groupB', 'groupC', 'groupD'], + 'species': ['speciesA', 'speciesB', 'speciesC', 'speciesD']} + + self.assertEqual(gen_dropdown_json(), expected_result) diff --git a/wqflask/tests/unit/wqflask/marker_regression/__init__.py b/wqflask/tests/unit/wqflask/marker_regression/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/wqflask/tests/unit/wqflask/marker_regression/test_display_mapping_results.py b/wqflask/tests/unit/wqflask/marker_regression/test_display_mapping_results.py new file mode 100644 index 00000000..8ae0f09f --- /dev/null +++ b/wqflask/tests/unit/wqflask/marker_regression/test_display_mapping_results.py @@ -0,0 +1,156 @@ +import unittest + +import htmlgen as HT +from wqflask.marker_regression.display_mapping_results import ( + DisplayMappingResults, + HtmlGenWrapper +) + + +class TestDisplayMappingResults(unittest.TestCase): + """Basic Methods to test Mapping Results""" + def test_pil_colors(self): + """Test that colors use PILLOW color format""" + self.assertEqual(DisplayMappingResults.CLICKABLE_WEBQTL_REGION_COLOR, + (245, 211, 211)) + + +class TestHtmlGenWrapper(unittest.TestCase): + """Test Wrapper around HTMLGen""" + def test_create_image(self): + """Test HT.Image method""" + self.assertEqual( + str(HtmlGenWrapper.create_image_tag(src="test.png", + alt="random", + border="0", + width="10", + height="13", + usemap="#webqtlmap")), + ("""random""") + ) + + def test_create_form(self): + """Test HT.Form method""" + test_form = HtmlGenWrapper.create_form_tag( + cgi="/testing/", + enctype='multipart/form-data', + name="formName", + submit=HtmlGenWrapper.create_input_tag(type_='hidden', name='Default_Name') + ) + test_image = HtmlGenWrapper.create_image_tag( + src="test.png", + alt="random", + border="0", + width="10", + height="13", + usemap="#webqtlmap" + ) + self.assertEqual( + str(test_form).replace("\n", ""), + ("""
""")) + hddn = { + 'FormID': 'showDatabase', + 'ProbeSetID': '_', + 'database': "TestGeno", + 'CellID': '_', + 'RISet': "Test", + 'incparentsf1': 'ON' + } + for key in hddn.keys(): + test_form.append( + HtmlGenWrapper.create_input_tag( + name=key, + value=hddn[key], + type_='hidden')) + test_form.append(test_image) + + self.assertEqual(str(test_form).replace("\n", ""), ( + """
""" + """""" + """""" + """""" + """""" + """""" + """""" + """""" + """random""" + """
""")) + + def test_create_paragraph(self): + """Test HT.Paragraph method""" + test_p_element = HtmlGenWrapper.create_p_tag(id="smallSize") + par_text = ( + "Mapping using genotype data as " + "a trait will result in infinity LRS at one locus. " + "In order to display the result properly, all LRSs " + "higher than 100 are capped at 100." + ) + self.assertEqual( + str(test_p_element), + """

""" + ) + test_p_element.append(HtmlGenWrapper.create_br_tag()) + test_p_element.append(par_text) + self.assertEqual( + str(test_p_element), + """


{}

""".format(par_text) + ) + + def test_create_br_tag(self): + """Test HT.BR() method""" + self.assertEqual(str(HtmlGenWrapper.create_br_tag()), + "
") + + def test_create_input_tag(self): + """Test HT.Input method""" + self.assertEqual( + str(HtmlGenWrapper.create_input_tag( + type_="hidden", + name="name", + value="key", + Class="trait trait_")).replace("\n", ""), + ("""""")) + + def test_create_map_tag(self): + """Test HT.Map method""" + self.assertEqual(str(HtmlGenWrapper.create_map_tag( + name="WebqTLImageMap")).replace("\n", ""), + """""") + gifmap = HtmlGenWrapper.create_map_tag(name="test") + gifmap.append(HtmlGenWrapper.create_area_tag(shape="rect", + coords='1 2 3', href='#area1')) + gifmap.append(HtmlGenWrapper.create_area_tag(shape="rect", + coords='1 2 3', href='#area2')) + self.assertEqual( + str(gifmap).replace("\n", ""), + ("""""" + """""" + """""" + """""")) + + def test_create_area_tag(self): + """Test HT.Area method""" + self.assertEqual( + str(HtmlGenWrapper.create_area_tag( + shape="rect", + coords="1 2", + href="http://test.com", + title="Some Title")).replace("\n", ""), + ("""""")) + + def test_create_link_tag(self): + """Test HT.HREF method""" + self.assertEqual( + str(HtmlGenWrapper.create_link_tag( + "www.test.com", "test", target="_blank")).replace("\n", ""), + """test""") diff --git a/wqflask/tests/unit/wqflask/show_trait/__init__.py b/wqflask/tests/unit/wqflask/show_trait/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/wqflask/tests/unit/wqflask/show_trait/test_export_trait_data.py b/wqflask/tests/unit/wqflask/show_trait/test_export_trait_data.py new file mode 100644 index 00000000..41761944 --- /dev/null +++ b/wqflask/tests/unit/wqflask/show_trait/test_export_trait_data.py @@ -0,0 +1,212 @@ +import unittest +from unittest import mock +from wqflask.show_trait.export_trait_data import dict_to_sorted_list +from wqflask.show_trait.export_trait_data import cmp_samples +from wqflask.show_trait.export_trait_data import export_sample_table +from wqflask.show_trait.export_trait_data import get_export_metadata + + +class AttributesSetter: + def __init__(self, obj): + for key, value in obj.items(): + setattr(self, key, value) + + +class TestExportTraits(unittest.TestCase): + """Test methods related to converting dict to sortedlist""" + @mock.patch("wqflask.show_trait.export_trait_data.create_trait") + @mock.patch("wqflask.show_trait.export_trait_data.data_set") + def test_get_export_metadata_no_publish(self, mock_dataset, mock_trait): + """test for exporting metadata with no publish""" + mock_dataset_attributes = AttributesSetter( + {"type": "no_publish", "dataset_name": "Temp", "name": "Temp"}) + + mock_nested_attributes = AttributesSetter({"name": "name"}) + mock_dataset_attributes.group = mock_nested_attributes + mock_dataset.create_dataset.return_value = mock_dataset_attributes + mock_trait.return_value = AttributesSetter({"symbol": "", "description_display": "Description", + "title": "research1", "journal": "", "authors": ""}) + + results = get_export_metadata("random_id", "Temp") + expected = [["Record ID: random_id"], + ["Trait URL: http://genenetwork.org/show_trait?trait_id=random_id&dataset=Temp"], + ["Dataset: Temp"], + ["Group: name"], []] + + mock_dataset.create_dataset.assert_called_with("Temp") + mock_trait.assert_called_with( + dataset=mock_dataset_attributes, name="random_id", cellid=None, get_qtl_info=False) + self.assertEqual(results, expected) + + @mock.patch("wqflask.show_trait.export_trait_data.create_trait") + @mock.patch("wqflask.show_trait.export_trait_data.data_set") + def test_get_export_metadata_with_publish(self, data_mock, trait_mock): + """test for exporting metadata with dataset.type=Publish""" + mock_dataset_attributes = AttributesSetter({"type": "Publish", "dataset_name": "Temp", + "name": "Temp", "description_display": "Description goes here"}) + + mock_nested_attributes = AttributesSetter({"name": "name"}) + mock_dataset_attributes.group = mock_nested_attributes + data_mock.create_dataset.return_value = mock_dataset_attributes + trait_instance = AttributesSetter({"symbol": "", "description_display": "Description", + "title": "research1", "journal": "", "authors": ""}) + trait_mock.return_value = trait_instance + + results = get_export_metadata( + "29ae0615-0d77-4814-97c7-c9e91f6bfd7b", "Temp") + + expected = [['Phenotype ID: 29ae0615-0d77-4814-97c7-c9e91f6bfd7b'], + ['Phenotype URL: http://genenetwork.org/show_trait?trait_id=29ae0615-0d77-4814-97c7-c9e91f6bfd7b&dataset=Temp'], [ + 'Group: name'], ['Phenotype: Description'], + ['Authors: N/A'], ['Title: research1'], + ['Journal: N/A'], ['Dataset Link: http://gn1.genenetwork.org/webqtl/main.py?FormID=sharinginfo&InfoPageName=Temp'], []] + + self.assertEqual(results, expected) + + @mock.patch("wqflask.show_trait.export_trait_data.dict_to_sorted_list") + @mock.patch("wqflask.show_trait.export_trait_data.get_export_metadata") + def test_export_sample_table(self, exp_metadata, dict_list): + """test for exporting sample table""" + targs_obj = { + "export_data": """{ + "primary_samples": [ + { + "other": "germanotta", + "name": "Sauroniops", + "se":{ + "name":"S2" + }, + "num_cases":{ + "k1":"value" + + } + } + ], + "other_samples": [ + { + "se": 1, + "num_cases": 4, + "value": 6, + "name": 3 + } + ] + }""", + "trait_display_name": "Hair_color", + "trait_id": "23177fdc-312e-4084-ad0c-f3eae785fff5", + "dataset": { + } + } + exp_metadata.return_value = [ + ["Phenotype ID:0a2be192-57f5-400b-bbbd-0cf50135995f"], ['Group:gp1'], + ["Phenotype:p1"], [ + "Authors:N/A"], + ["Title:research1"], + ["Journal:N/A"], + ["Dataset Link: http://gn1.genenetwork.org/webqtl/main.py?FormID=sharinginfo&InfoPageName=name1"], []] + expected = ('Hair_color', + [['Phenotype ID:0a2be192-57f5-400b-bbbd-0cf50135995f'], + ['Group:gp1'], + ['Phenotype:p1'], + ['Authors:N/A'], + ['Title:research1'], + ['Journal:N/A'], + ['Dataset Link: ' + 'http://gn1.genenetwork.org/webqtl/main.py?FormID=sharinginfo&InfoPageName=name1'], + [], + ['Name', 'Value', 'SE', 'N'], + ['Sauroniops', 'germanotta'], + [3, 6, 1, 4]]) + + dict_list.side_effect = [['Sauroniops', 'germanotta'], [3, 6, 1, 4]] + + self.assertEqual(export_sample_table(targs_obj), expected) + exp_metadata.assert_called_with( + "23177fdc-312e-4084-ad0c-f3eae785fff5", {}) + self.assertEqual(dict_list.call_count, 2) + + def test_dict_to_sortedlist(self): + """test for conversion of dict to sorted list""" + sample1 = { + "other": "exp1", + "name": "exp2" + } + sample2 = { + "se": 1, + "num_cases": 4, + "value": 6, + "name": 3 + + } + rever = { + "name": 3, + "value": 6, + "num_cases": 4, + "se": 1 + } + oneItem = { + "item1": "one" + } + + self.assertEqual(["exp2", "exp1"], dict_to_sorted_list(sample1)) + self.assertEqual([3, 6, 1, 4], dict_to_sorted_list(sample2)) + self.assertEqual([3, 6, 1, 4], dict_to_sorted_list(rever)) + self.assertEqual(["one"], dict_to_sorted_list(oneItem)) + """test that the func returns the values not the keys""" + self.assertFalse(["other", "name"] == dict_to_sorted_list(sample1)) + + def test_cmp_samples(self): + """test for comparing samples function""" + sampleA = [ + [ + ("value", "other"), + ("name", "test_name") + ] + ] + sampleB = [ + [ + ("value", "other"), + ("unknown", "test_name") + ] + ] + sampleC = [ + [("other", "value"), + ("name", "value") + ], + [ + ("name", "value"), + ("value", "name") + ], + [ + ("other", "value"), + ("name", "value" + )], + [ + ("name", "name1"), + ("se", "valuex") + ], + [( + "value", "name1"), + ("se", "valuex") + ], + [( + "other", "name1"), + ("se", "valuex" + ) + ], + [( + "name", "name_val"), + ("num_cases", "num_val") + ], + [( + "other_a", "val_a"), + ("other_b", "val" + ) + ] + ] + results = [cmp_samples(val[0], val[1]) for val in sampleA] + resultB = [cmp_samples(val[0], val[1]) for val in sampleB] + resultC = [cmp_samples(val[0], val[1]) for val in sampleC] + + self.assertEqual(1, *results) + self.assertEqual(-1, *resultB) + self.assertEqual([1, -1, 1, -1, -1, 1, -1, -1], resultC) diff --git a/wqflask/tests/unit/wqflask/test_collect.py b/wqflask/tests/unit/wqflask/test_collect.py new file mode 100644 index 00000000..9a36132d --- /dev/null +++ b/wqflask/tests/unit/wqflask/test_collect.py @@ -0,0 +1,73 @@ +"""Test cases for some methods in collect.py""" + +import unittest +from unittest import mock + +from flask import Flask +from wqflask.collect import process_traits + +app = Flask(__name__) + + +class MockSession: + """Helper class for mocking wqflask.collect.g.user_session.logged_in""" + def __init__(self, is_logged_in=False): + self.is_logged_in = is_logged_in + + @property + def logged_in(self): + return self.is_logged_in + + +class MockFlaskG: + """Helper class for mocking wqflask.collect.g.user_session""" + def __init__(self, is_logged_in=False): + self.is_logged_in = is_logged_in + + @property + def user_session(self): + if self.is_logged_in: + return MockSession(is_logged_in=True) + return MockSession() + + +class TestCollect(unittest.TestCase): + + def setUp(self): + self.app_context = app.app_context() + self.app_context.push() + + def tearDown(self): + self.app_context.pop() + + @mock.patch("wqflask.collect.g", MockFlaskG()) + def test_process_traits_with_bytestring(self): + """ + Test that the correct traits are returned when the user is logged + out and bytes are used. + """ + self.assertEqual(process_traits( + b'1452452_at:HC_M2_0606_P:163d04f7db7c9e110de6,' + b'1452447_at:HC_M2_0606_P:eeece8fceb67072debea,' + b'1451401_a_at:HC_M2_0606_P:a043d23b3b3906d8318e,' + b'1429252_at:HC_M2_0606_P:6fa378b349bc9180e8f5'), + set(['1429252_at:HC_M2_0606_P', + '1451401_a_at:HC_M2_0606_P', + '1452447_at:HC_M2_0606_P', + '1452452_at:HC_M2_0606_P'])) + + @mock.patch("wqflask.collect.g", MockFlaskG()) + def test_process_traits_with_normal_string(self): + """ + Test that the correct traits are returned when the user is logged + out and a normal string is used. + """ + self.assertEqual(process_traits( + '1452452_at:HC_M2_0606_P:163d04f7db7c9e110de6,' + '1452447_at:HC_M2_0606_P:eeece8fceb67072debea,' + '1451401_a_at:HC_M2_0606_P:a043d23b3b3906d8318e,' + '1429252_at:HC_M2_0606_P:6fa378b349bc9180e8f5'), + set(['1429252_at:HC_M2_0606_P', + '1451401_a_at:HC_M2_0606_P', + '1452447_at:HC_M2_0606_P', + '1452452_at:HC_M2_0606_P'])) diff --git a/wqflask/tests/unit/wqflask/test_pbkdf2.py b/wqflask/tests/unit/wqflask/test_pbkdf2.py new file mode 100644 index 00000000..a33fbd4f --- /dev/null +++ b/wqflask/tests/unit/wqflask/test_pbkdf2.py @@ -0,0 +1,61 @@ +"""Test cases pbkdf2""" + +import unittest +from wqflask.pbkdf2 import pbkdf2_hex + + +class TestPbkdf2(unittest.TestCase): + def test_pbkdf2_hex(self): + """ + Test pbkdf2_hex function + """ + + for password, salt, iterations, keylen, expected_value in [ + ('password', 'salt', 1, 20, + '0c60c80f961f0e71f3a9b524af6012062fe037a6'), + ('password', 'salt', 2, 20, + 'ea6c014dc72d6f8ccd1ed92ace1d41f0d8de8957'), + ('password', 'salt', 4096, 20, + '4b007901b765489abead49d926f721d065a429c1'), + ('passwordPASSWORDpassword', + 'saltSALTsaltSALTsaltSALTsaltSALTsalt', + 4096, 25, + '3d2eec4fe41c849b80c8d83662c0e44a8b291a964cf2f07038'), + ('pass\x00word', 'sa\x00lt', 4096, 16, + '56fa6aa75548099dcc37d7f03425e0c3'), + ('password', 'ATHENA.MIT.EDUraeburn', 1, 16, + 'cdedb5281bb2f801565a1122b2563515'), + ('password', 'ATHENA.MIT.EDUraeburn', 1, 32, + ('cdedb5281bb2f80' + '1565a1122b256351' + '50ad1f7a04bb9f3a33' + '3ecc0e2e1f70837')), + ('password', 'ATHENA.MIT.EDUraeburn', 2, 16, + '01dbee7f4a9e243e988b62c73cda935d'), + ('password', 'ATHENA.MIT.EDUraeburn', 2, 32, + ('01dbee7f4a9e243e9' + '88b62c73cda935da05' + '378b93244ec8f48a99' + 'e61ad799d86')), + ('password', 'ATHENA.MIT.EDUraeburn', 1200, 32, + ('5c08eb61fdf71e' + '4e4ec3cf6ba1f55' + '12ba7e52ddbc5e51' + '42f708a31e2e62b1e13')), + ('X' * 64, 'pass phrase equals block size', 1200, 32, + ('139c30c0966bc32ba' + '55fdbf212530ac9c5' + 'ec59f1a452f5cc9ad' + '940fea0598ed1')), + ('X' * 65, 'pass phrase exceeds block size', 1200, 32, + ('9ccad6d468770cd' + '51b10e6a68721be6' + '11a8b4d282601db3' + 'b36be9246915ec82a')) + ]: + self.assertEqual( + pbkdf2_hex(data=password, + salt=salt, + iterations=iterations, + keylen=keylen), + expected_value) diff --git a/wqflask/tests/unit/wqflask/test_user_login.py b/wqflask/tests/unit/wqflask/test_user_login.py new file mode 100644 index 00000000..61cd9ab9 --- /dev/null +++ b/wqflask/tests/unit/wqflask/test_user_login.py @@ -0,0 +1,21 @@ +"""Test cases for some methods in login.py""" + +import unittest +from wqflask.user_login import encode_password + + +class TestUserLogin(unittest.TestCase): + def test_encode_password(self): + """ + Test encode password + """ + pass_gen_fields = { + "salt": "salt", + "hashfunc": "sha1", + "iterations": 4096, + "keylength": 20, + } + self.assertEqual( + encode_password(pass_gen_fields, + "password").get("password"), + '4b007901b765489abead49d926f721d065a429c1') diff --git a/wqflask/tests/unit/wqflask/test_user_session.py b/wqflask/tests/unit/wqflask/test_user_session.py new file mode 100644 index 00000000..ebb0334a --- /dev/null +++ b/wqflask/tests/unit/wqflask/test_user_session.py @@ -0,0 +1,15 @@ +"""Test cases for some methods in user_session.py""" + +import unittest +from wqflask.user_session import verify_cookie + + +class TestUserSession(unittest.TestCase): + def test_verify_cookie(self): + """ + Test cookie verification + """ + self.assertEqual( + "3f4c1dbf-5b56-4260-87d6-f35445bda37e", + verify_cookie(("3f4c1dbf-5b56-4260-87d6-" + "f35445bda37e:af4fcf5eace9e7c864ce"))) -- cgit v1.2.3 From 390dcc3c46495a8e316df36ceb57dae2089456da Mon Sep 17 00:00:00 2001 From: BonfaceKilz Date: Tue, 3 Nov 2020 19:14:24 +0300 Subject: Remove encoding header for file In python3 the default encoding is utf-8 so this is redundant. --- wqflask/tests/unit/utility/test_hmac.py | 1 - wqflask/wqflask/views.py | 4 +--- 2 files changed, 1 insertion(+), 4 deletions(-) (limited to 'wqflask/tests/unit') diff --git a/wqflask/tests/unit/utility/test_hmac.py b/wqflask/tests/unit/utility/test_hmac.py index 4e3652f8..13d6261d 100644 --- a/wqflask/tests/unit/utility/test_hmac.py +++ b/wqflask/tests/unit/utility/test_hmac.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """Test hmac utility functions""" import unittest diff --git a/wqflask/wqflask/views.py b/wqflask/wqflask/views.py index 08673f79..b7c4d142 100644 --- a/wqflask/wqflask/views.py +++ b/wqflask/wqflask/views.py @@ -1,6 +1,4 @@ -# -*- coding: utf-8 -*- -# -# Main routing table for GN2 +"""Main routing table for GN2""" import traceback # for error page import os # for error gifs -- cgit v1.2.3 From bb46ab063cc86525946563c809a896532d87147a Mon Sep 17 00:00:00 2001 From: BonfaceKilz Date: Tue, 3 Nov 2020 22:45:44 +0300 Subject: Add basic tests for rendering_markdown * wqflask/tests/unit/wqflask/test_markdown_routes.py: New tests. --- wqflask/tests/unit/wqflask/test_markdown_routes.py | 43 ++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 wqflask/tests/unit/wqflask/test_markdown_routes.py (limited to 'wqflask/tests/unit') diff --git a/wqflask/tests/unit/wqflask/test_markdown_routes.py b/wqflask/tests/unit/wqflask/test_markdown_routes.py new file mode 100644 index 00000000..8b6f7490 --- /dev/null +++ b/wqflask/tests/unit/wqflask/test_markdown_routes.py @@ -0,0 +1,43 @@ +"""Test functions in markdown utils""" + +import unittest +from unittest import mock + +from wqflask.markdown_routes import render_markdown + + +class MockRequests404: + @property + def status_code(): + return 404 + +class MockRequests200: + @property + def status_code(): + return 200 + + @property + def content(): + return """ + # Glossary + + This is some content + + ## Sub-heading + This is another sub-heading + """ + +class TestMarkdownRoutesFunctions(unittest.TestCase): + """Test cases for functions in markdown_routes""" + + @mock.patch('wqflask.markdown_routes.requests.get') + def test_render_markdown(self, requests_mock): + requests_mock.return_value = MockRequests404 + markdown_content = render_markdown("glossary.md") + requests_mock.assert_called_with( + "https://raw.githubusercontent.com" + "/genenetwork/genenetwork2/" + "wqflask/wqflask/static/" + "glossary.md") + self.assertEqual("

Content

\n", + markdown_content) -- cgit v1.2.3 From 5f6756f05baeeb6be34a079726d0df749a0557ec Mon Sep 17 00:00:00 2001 From: BonfaceKilz Date: Tue, 3 Nov 2020 23:04:53 +0300 Subject: Fix false-positive tests * wqflask/tests/unit/wqflask/test_markdown_routes.py: (MockRequests404): Pass self in all properties. (MockRequests200): Ditto. (test_render_markdown): Rename to test_render_markdown_when_fetching_locally. (test_render_markdown_when_fetching_remotely): New test. --- wqflask/tests/unit/wqflask/test_markdown_routes.py | 37 +++++++++++++++------- 1 file changed, 26 insertions(+), 11 deletions(-) (limited to 'wqflask/tests/unit') diff --git a/wqflask/tests/unit/wqflask/test_markdown_routes.py b/wqflask/tests/unit/wqflask/test_markdown_routes.py index 8b6f7490..3de14276 100644 --- a/wqflask/tests/unit/wqflask/test_markdown_routes.py +++ b/wqflask/tests/unit/wqflask/test_markdown_routes.py @@ -8,31 +8,30 @@ from wqflask.markdown_routes import render_markdown class MockRequests404: @property - def status_code(): + def status_code(self): return 404 class MockRequests200: @property - def status_code(): + def status_code(self): return 200 @property - def content(): - return """ - # Glossary + def content(self): + return b""" +# Glossary +This is some content - This is some content - - ## Sub-heading - This is another sub-heading +## Sub-heading +This is another sub-heading """ class TestMarkdownRoutesFunctions(unittest.TestCase): """Test cases for functions in markdown_routes""" @mock.patch('wqflask.markdown_routes.requests.get') - def test_render_markdown(self, requests_mock): - requests_mock.return_value = MockRequests404 + def test_render_markdown_when_fetching_locally(self, requests_mock): + requests_mock.return_value = MockRequests404() markdown_content = render_markdown("glossary.md") requests_mock.assert_called_with( "https://raw.githubusercontent.com" @@ -41,3 +40,19 @@ class TestMarkdownRoutesFunctions(unittest.TestCase): "glossary.md") self.assertEqual("

Content

\n", markdown_content) + + @mock.patch('wqflask.markdown_routes.requests.get') + def test_render_markdown_when_fetching_remotely(self, requests_mock): + requests_mock.return_value = MockRequests200() + markdown_content = render_markdown("glossary.md") + requests_mock.assert_called_with( + "https://raw.githubusercontent.com" + "/genenetwork/genenetwork2/" + "wqflask/wqflask/static/" + "glossary.md") + self.assertEqual("""

Glossary

+

This is some content

+

Sub-heading

+

This is another sub-heading

+""", + markdown_content) -- cgit v1.2.3 From fa852e4a293735215e10bff9198c812fb85912ce Mon Sep 17 00:00:00 2001 From: BonfaceKilz Date: Wed, 4 Nov 2020 18:04:48 +0300 Subject: Update test_markdown_routes * wqflask/tests/unit/wqflask/test_markdown_routes.py (test_render_markdown_when_fetching_locally): Fix failing test. --- wqflask/tests/unit/wqflask/test_markdown_routes.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'wqflask/tests/unit') diff --git a/wqflask/tests/unit/wqflask/test_markdown_routes.py b/wqflask/tests/unit/wqflask/test_markdown_routes.py index 3de14276..3adf63e5 100644 --- a/wqflask/tests/unit/wqflask/test_markdown_routes.py +++ b/wqflask/tests/unit/wqflask/test_markdown_routes.py @@ -38,8 +38,8 @@ class TestMarkdownRoutesFunctions(unittest.TestCase): "/genenetwork/genenetwork2/" "wqflask/wqflask/static/" "glossary.md") - self.assertEqual("

Content

\n", - markdown_content) + self.assertRegexpMatches(markdown_content, + "Glossary of Terms and Features") @mock.patch('wqflask.markdown_routes.requests.get') def test_render_markdown_when_fetching_remotely(self, requests_mock): -- cgit v1.2.3