aboutsummaryrefslogtreecommitdiff
path: root/gn2/tests
diff options
context:
space:
mode:
authorArun Isaac2023-12-29 18:55:37 +0000
committerArun Isaac2023-12-29 19:01:46 +0000
commit204a308be0f741726b9a620d88fbc22b22124c81 (patch)
treeb3cf66906674020b530c844c2bb4982c8a0e2d39 /gn2/tests
parent83062c75442160427b50420161bfcae2c5c34c84 (diff)
downloadgenenetwork2-204a308be0f741726b9a620d88fbc22b22124c81.tar.gz
Namespace all modules under gn2.
We move all modules under a gn2 directory. This is important for "correct" packaging and deployment as a Guix service.
Diffstat (limited to 'gn2/tests')
-rw-r--r--gn2/tests/__init__.py0
-rw-r--r--gn2/tests/integration/__init__.py0
-rw-r--r--gn2/tests/integration/wqflask/__init__.py0
-rw-r--r--gn2/tests/unit/__init__.py0
-rw-r--r--gn2/tests/unit/base/__init__.py0
-rw-r--r--gn2/tests/unit/base/test_data_set.py238
-rw-r--r--gn2/tests/unit/base/test_general_object.py40
-rw-r--r--gn2/tests/unit/base/test_mrna_assay_tissue_data.py81
-rw-r--r--gn2/tests/unit/base/test_species.py80
-rw-r--r--gn2/tests/unit/base/test_trait.py262
-rw-r--r--gn2/tests/unit/base/test_webqtl_case_data.py40
-rw-r--r--gn2/tests/unit/utility/__init__.py0
-rw-r--r--gn2/tests/unit/utility/test_authentication_tools.py192
-rw-r--r--gn2/tests/unit/utility/test_chunks.py20
-rw-r--r--gn2/tests/unit/utility/test_corestats.py55
-rw-r--r--gn2/tests/unit/utility/test_corr_result_helpers.py32
-rw-r--r--gn2/tests/unit/utility/test_formatting.py33
-rw-r--r--gn2/tests/unit/utility/test_hmac.py51
-rw-r--r--gn2/tests/unit/utility/test_type_checking.py54
-rw-r--r--gn2/tests/unit/wqflask/__init__.py0
-rw-r--r--gn2/tests/unit/wqflask/api/__init__.py0
-rw-r--r--gn2/tests/unit/wqflask/api/test_correlation.py175
-rw-r--r--gn2/tests/unit/wqflask/api/test_gen_menu.py423
-rw-r--r--gn2/tests/unit/wqflask/api/test_mapping.py113
-rw-r--r--gn2/tests/unit/wqflask/api/test_markdown_routes.py54
-rw-r--r--gn2/tests/unit/wqflask/correlation/__init__.py0
-rw-r--r--gn2/tests/unit/wqflask/correlation/test_correlation_functions.py21
-rw-r--r--gn2/tests/unit/wqflask/correlation/test_correlation_gn3.py14
-rw-r--r--gn2/tests/unit/wqflask/correlation/test_show_corr_results.py42
-rw-r--r--gn2/tests/unit/wqflask/marker_regression/__init__.py0
-rw-r--r--gn2/tests/unit/wqflask/marker_regression/genotype/bimbam/file_geno.txt0
-rw-r--r--gn2/tests/unit/wqflask/marker_regression/genotype/bimbam/file_snps.txt0
-rw-r--r--gn2/tests/unit/wqflask/marker_regression/test_display_mapping_results.py159
-rw-r--r--gn2/tests/unit/wqflask/marker_regression/test_gemma_mapping.py188
-rw-r--r--gn2/tests/unit/wqflask/marker_regression/test_plink_mapping.py86
-rw-r--r--gn2/tests/unit/wqflask/marker_regression/test_qtlreaper_mapping.py24
-rw-r--r--gn2/tests/unit/wqflask/marker_regression/test_rqtl_mapping.py43
-rw-r--r--gn2/tests/unit/wqflask/marker_regression/test_run_mapping.py288
-rw-r--r--gn2/tests/unit/wqflask/show_trait/__init__.py0
-rw-r--r--gn2/tests/unit/wqflask/show_trait/test_export_trait_data.py151
-rw-r--r--gn2/tests/unit/wqflask/show_trait/test_get_max_digits.py15
-rw-r--r--gn2/tests/unit/wqflask/snp_browser/__init__.py0
-rw-r--r--gn2/tests/unit/wqflask/snp_browser/test_snp_browser.py206
-rw-r--r--gn2/tests/unit/wqflask/test_collect.py75
-rw-r--r--gn2/tests/unit/wqflask/test_pbkdf2.py61
-rw-r--r--gn2/tests/unit/wqflask/test_resource_manager.py94
-rw-r--r--gn2/tests/unit/wqflask/test_server_side.py34
-rw-r--r--gn2/tests/unit/wqflask/test_user_login.py21
-rw-r--r--gn2/tests/unit/wqflask/test_user_session.py15
-rw-r--r--gn2/tests/unit/wqflask/wgcna/__init__.py0
-rw-r--r--gn2/tests/unit/wqflask/wgcna/test_wgcna.py50
-rw-r--r--gn2/tests/wqflask/show_trait/testSampleList.py17
-rw-r--r--gn2/tests/wqflask/show_trait/test_show_trait.py255
53 files changed, 3802 insertions, 0 deletions
diff --git a/gn2/tests/__init__.py b/gn2/tests/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/gn2/tests/__init__.py
diff --git a/gn2/tests/integration/__init__.py b/gn2/tests/integration/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/gn2/tests/integration/__init__.py
diff --git a/gn2/tests/integration/wqflask/__init__.py b/gn2/tests/integration/wqflask/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/gn2/tests/integration/wqflask/__init__.py
diff --git a/gn2/tests/unit/__init__.py b/gn2/tests/unit/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/gn2/tests/unit/__init__.py
diff --git a/gn2/tests/unit/base/__init__.py b/gn2/tests/unit/base/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/gn2/tests/unit/base/__init__.py
diff --git a/gn2/tests/unit/base/test_data_set.py b/gn2/tests/unit/base/test_data_set.py
new file mode 100644
index 00000000..7341314c
--- /dev/null
+++ b/gn2/tests/unit/base/test_data_set.py
@@ -0,0 +1,238 @@
+"""Tests for wqflask/base/data_set.py"""
+
+import unittest
+from unittest import mock
+from dataclasses import dataclass
+from gn3.monads import MonadicDict
+
+from gn2.wqflask import app
+from gn2.base.data_set import DatasetType
+from gn2.base.data_set.dataset import DataSet
+
+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"
+ ]
+ ]
+ }
+ }
+}
+"""
+
+class MockPhenotypeDataset(DataSet):
+ def setup(self):
+ self.type = "Publish"
+ self.query_for_group = ""
+ self.group = ""
+
+
+ def check_confidentiality(self):
+ pass
+
+ def retrieve_other_names(self):
+ pass
+
+@dataclass
+class MockGroup:
+ name = "Group"
+
+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()
+
+ def test_data_set_type(self):
+ """Test that DatasetType returns correctly if the Redis Instance is not empty
+ and the name variable exists in the dictionary
+
+ """
+ with app.app_context():
+ redis_mock = mock.Mock()
+ cursor_mock = mock.Mock()
+ redis_mock.get.return_value = self.test_dataset
+ self.assertEqual(DatasetType(redis_mock)
+ ("All Phenotypes", redis_mock, cursor_mock), "Publish")
+ redis_mock.get.assert_called_once_with("dataset_structure")
+
+ @mock.patch('base.data_set.datasettype.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()
+ cursor_mock = mock.Mock()
+ redis_mock.get.return_value = None
+ data_set = DatasetType(redis_mock)
+ self.assertEqual(data_set("BXDGeno", redis_mock, cursor_mock),
+ "Geno")
+ self.assertEqual(data_set("BXDPublish", redis_mock, cursor_mock),
+ "Publish")
+ self.assertEqual(data_set("HLC_0311", redis_mock, cursor_mock),
+ "ProbeSet")
+
+ redis_mock.set.assert_called_once_with(
+ "dataset_structure",
+ ('{"HLC_0311": "ProbeSet", '
+ '"HLCPublish": "Publish", '
+ '"BXDGeno": "Geno", '
+ '"HC_M2_0606_P": "ProbeSet", '
+ '"BXDPublish": "Publish"}'))
+
+
+class TestDatasetAccessionId(unittest.TestCase):
+ """Tests for the DataSetType class"""
+
+ @mock.patch("base.data_set.dataset.query_sql")
+ @mock.patch("base.data_set.dataset.DatasetGroup")
+ def test_get_accession_id(self, mock_dataset_group, mock_query_sql):
+ def mock_fn():
+ yield MonadicDict({"accession_id": 7})
+ mock_dataset_group.return_value = MockGroup()
+ mock_query_sql.return_value = mock_fn()
+ sample_dataset = MockPhenotypeDataset(
+ name="BXD-LongevityPublish",
+ get_samplelist=False,
+ group_name="BXD",
+ redis_conn=mock.Mock()
+ )
+ sample_dataset\
+ .accession_id\
+ .bind(lambda x: self.assertEqual(7, x))
+
+ @mock.patch("base.data_set.dataset.query_sql")
+ @mock.patch("base.data_set.dataset.DatasetGroup")
+ def test_get_accession_id_empty_return(self, mock_dataset_group,
+ mock_query_sql):
+ mock_dataset_group.return_value = MockGroup()
+ mock_query_sql.return_value = None
+ sample_dataset = MockPhenotypeDataset(
+ name="BXD-LongevityPublish",
+ get_samplelist=False,
+ group_name="BXD",
+ redis_conn=mock.Mock()
+ )
+ sample_dataset\
+ .accession_id\
+ .bind(lambda x: self.assertNone(x))
diff --git a/gn2/tests/unit/base/test_general_object.py b/gn2/tests/unit/base/test_general_object.py
new file mode 100644
index 00000000..1301f18b
--- /dev/null
+++ b/gn2/tests/unit/base/test_general_object.py
@@ -0,0 +1,40 @@
+import unittest
+
+from gn2.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/gn2/tests/unit/base/test_mrna_assay_tissue_data.py b/gn2/tests/unit/base/test_mrna_assay_tissue_data.py
new file mode 100644
index 00000000..5bc28ffa
--- /dev/null
+++ b/gn2/tests/unit/base/test_mrna_assay_tissue_data.py
@@ -0,0 +1,81 @@
+import pytest
+from gn2.base.mrna_assay_tissue_data import MrnaAssayTissueData
+
+
+@pytest.mark.parametrize(
+ ('gene_symbols', 'expected_query', 'sql_fetch_all_results'),
+ (
+ (None,
+ (("SELECT t.Symbol, t.GeneId, t.DataId, "
+ "t.Chr, t.Mb, t.description, "
+ "t.Probe_Target_Description "
+ "FROM (SELECT Symbol, "
+ "max(Mean) AS maxmean "
+ "FROM TissueProbeSetXRef WHERE "
+ "TissueProbeSetFreezeId=1 AND "
+ "Symbol != '' AND Symbol IS NOT "
+ "Null GROUP BY Symbol) "
+ "AS x INNER JOIN TissueProbeSetXRef "
+ "AS t ON t.Symbol = x.Symbol "
+ "AND t.Mean = x.maxmean"),),
+ (("symbol", "gene_id",
+ "data_id", "chr", "mb",
+ "description",
+ "probe_target_description"),)),
+ (["k1", "k2", "k3"],
+ ("SELECT t.Symbol, t.GeneId, t.DataId, "
+ "t.Chr, t.Mb, t.description, "
+ "t.Probe_Target_Description FROM (SELECT Symbol, "
+ "max(Mean) AS maxmean "
+ "FROM TissueProbeSetXRef WHERE "
+ "TissueProbeSetFreezeId=1 AND "
+ "Symbol IN (%s, %s, %s) "
+ "GROUP BY Symbol) AS x INNER JOIN "
+ "TissueProbeSetXRef AS "
+ "t ON t.Symbol = x.Symbol "
+ "AND t.Mean = x.maxmean",
+ ("k1", "k2", "k3")),
+ (("k1", "203",
+ "112", "xy", "20.11",
+ "Sample Description",
+ "Sample Probe Target Description"),)),
+ ),
+)
+def test_mrna_assay_tissue_data_initialisation(mocker, gene_symbols,
+ expected_query,
+ sql_fetch_all_results):
+ mock_conn = mocker.MagicMock()
+ with mock_conn.cursor() as cursor:
+ cursor.fetchall.return_value = sql_fetch_all_results
+ MrnaAssayTissueData(conn=mock_conn, gene_symbols=gene_symbols)
+ cursor.execute.assert_called_with(*expected_query)
+
+
+def test_get_trait_symbol_and_tissue_values(mocker):
+ """Test for getting trait symbol and tissue_values"""
+ mock_conn = mocker.MagicMock()
+ with mock_conn.cursor() as cursor:
+ cursor.fetchall.side_effect = [
+ (("k1", "203",
+ "112", "xy", "20.11",
+ "Sample Description",
+ "Sample Probe Target Description"),),
+ (("k1", "v1"),
+ ("k2", "v2"),
+ ("k3", "v3")),
+ ]
+ _m = MrnaAssayTissueData(conn=mock_conn,
+ gene_symbols=["k1", "k2", "k3"])
+ assert _m.get_symbol_values_pairs() == {
+ "k1": ["v1"],
+ "k2": ["v2"],
+ "k3": ["v3"],
+ }
+ cursor.execute.assert_called_with(
+ "SELECT TissueProbeSetXRef.Symbol, "
+ "TissueProbeSetData.value FROM "
+ "TissueProbeSetXRef, TissueProbeSetData "
+ "WHERE TissueProbeSetData.Id IN (%s) "
+ "AND TissueProbeSetXRef.DataId = "
+ "TissueProbeSetData.Id",
+ ('112',))
diff --git a/gn2/tests/unit/base/test_species.py b/gn2/tests/unit/base/test_species.py
new file mode 100644
index 00000000..239e8b3f
--- /dev/null
+++ b/gn2/tests/unit/base/test_species.py
@@ -0,0 +1,80 @@
+"""Tests wqflask/base/species.py"""
+import pytest
+from gn2.base.species import TheSpecies
+from gn2.base.species import IndChromosome
+from gn2.base.species import Chromosomes
+from collections import OrderedDict
+from dataclasses import dataclass
+
+
+@dataclass
+class MockChromosome:
+ OrderId: int
+ Name: str
+ Length: int
+
+
+@dataclass
+class MockGroup:
+ name: str
+
+
+@dataclass
+class MockDataset:
+ group: MockGroup
+
+
+@pytest.mark.parametrize(
+ ("species_name", "dataset", "expected_name", "chromosome_param"),
+ (("BXD", None, "BXD", 1),
+ (None, "Random Dataset", None, 1)))
+def test_species(mocker, species_name, dataset,
+ expected_name, chromosome_param):
+ _c = mocker.patch("base.species.Chromosomes",
+ return_value=chromosome_param)
+ test_species = TheSpecies(dataset=dataset,
+ species_name=species_name)
+ _c.assert_called_with(species=species_name,
+ dataset=dataset)
+ assert test_species.name == expected_name
+ assert test_species.chromosomes == chromosome_param
+
+
+@pytest.mark.parametrize(
+ ("name", "length", "mb_length"),
+ (("Test A", 10000000, 10),
+ ("Test B", 100, 0.0001)))
+def test_create_ind_chromosome(name, length, mb_length):
+ _ind = IndChromosome(name=name, length=length)
+ assert _ind.name == name
+ assert _ind.length == length
+ assert _ind.mb_length == mb_length
+
+
+@pytest.mark.parametrize(
+ ("species", "dataset", "expected_call"),
+ (("bxd", MockDataset(MockGroup("Random")),
+ ("SELECT Chr_Length.Name, Chr_Length.OrderId, Length "
+ "FROM Chr_Length, Species WHERE "
+ "Chr_Length.SpeciesId = Species.SpeciesId AND "
+ "Species.Name = %s "
+ "ORDER BY OrderId", ("Bxd",))),
+ (None, MockDataset(MockGroup("Random")),
+ ("SELECT Chr_Length.Name, Chr_Length.OrderId, "
+ "Length FROM Chr_Length, InbredSet WHERE "
+ "Chr_Length.SpeciesId = InbredSet.SpeciesId AND "
+ "InbredSet.Name = "
+ "%s ORDER BY OrderId", ("Random",)))))
+def test_create_chromosomes(mocker, species, dataset, expected_call):
+ mock_conn = mocker.MagicMock()
+ with mock_conn.cursor() as cursor:
+ cursor.fetchall.return_value = (("1", 2, 10,),
+ ("2", 3, 11,),
+ ("4", 5, 15,),)
+ _c = Chromosomes(dataset=dataset, species=species)
+ assert _c.chromosomes(cursor) == OrderedDict([
+ ("1", IndChromosome("1", 10)),
+ ("2", IndChromosome("2", 11)),
+ ("4", IndChromosome("4", 15)),
+ ])
+ cursor.execute.assert_called_with(*expected_call)
diff --git a/gn2/tests/unit/base/test_trait.py b/gn2/tests/unit/base/test_trait.py
new file mode 100644
index 00000000..417956ae
--- /dev/null
+++ b/gn2/tests/unit/base/test_trait.py
@@ -0,0 +1,262 @@
+# -*- coding: utf-8 -*-
+"""Tests wqflask/base/trait.py"""
+import unittest
+from unittest import mock
+
+from gn2.base.trait import GeneralTrait
+from gn2.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'"""
+ @mock.patch('base.trait.database_connection')
+ def test_retrieve_trait_info_with_empty_dataset(self, mock_db):
+ """Test that an exception is raised when dataset is empty"""
+ conn = mock.MagicMock()
+ mock_db.return_value.__enter__.return_value = conn
+ with self.assertRaises(ValueError):
+ retrieve_trait_info(trait=mock.MagicMock(),
+ dataset={})
+
+ @mock.patch('base.trait.requests.get')
+ @mock.patch('base.trait.g', mock.Mock())
+ @mock.patch('base.trait.database_connection')
+ def test_retrieve_trait_info_with_empty_trait_info(self,
+ mock_db,
+ requests_mock):
+ """Empty trait info"""
+ conn = mock.MagicMock()
+ cursor = mock.MagicMock()
+ cursor.fetchone.return_value = {}
+ conn.cursor.return_value.__enter__.return_value = cursor
+ mock_db.return_value.__enter__.return_value = conn
+ 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())
+ @mock.patch('base.trait.database_connection')
+ def test_retrieve_trait_info_with_non_empty_trait_info(self,
+ mock_db,
+ requests_mock):
+ """Test that attributes are set"""
+ mock_dataset = mock.MagicMock()
+ conn = mock.MagicMock()
+ cursor = mock.MagicMock()
+ cursor.fetchone.return_value = [1, 2, 3, 4]
+ conn.cursor.return_value.__enter__.return_value = cursor
+ mock_db.return_value.__enter__.return_value = conn
+ 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())
+ @mock.patch('base.trait.database_connection')
+ def test_retrieve_trait_info_utf8_parsing(self,
+ mock_db,
+ requests_mock):
+ """Test that utf-8 strings are parsed correctly"""
+ utf_8_string = "test_string"
+ conn = mock.MagicMock()
+ mock_db.return_value.__enter__.return_value = conn
+ 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 かいと")
+
+
+ @unittest.skip("Too complicated")
+ @mock.patch('base.trait.requests.get')
+ @mock.patch('base.trait.database_connection')
+ @mock.patch('base.trait.get_resource_id')
+ def test_retrieve_trait_info_with_non_empty_lrs(self,
+ resource_id_mock,
+ mock_db,
+ requests_mock):
+ """Test retrieve trait info when lrs has a value"""
+ resource_id_mock.return_value = 1
+ conn = mock.MagicMock()
+ mock_db.return_value.__enter__.return_value = conn
+ with conn.cursor() as cursor:
+ cursor.fetchone.side_effect = [
+ # trait_info = g.db.execute(query).fetchone()
+ [1, 2, 3, 4],
+ # trait_qtl = g.db.execute(query).fetchone()
+ [1, 2.37, 3, 4, 5],
+ # trait_info = g.db.execute(query).fetchone()
+ [2.7333, 2.1204]
+ ]
+ 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")
+
+ @unittest.skip("Too complicated")
+ @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")
+
+ @unittest.skip("Too complicated")
+ @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/gn2/tests/unit/base/test_webqtl_case_data.py b/gn2/tests/unit/base/test_webqtl_case_data.py
new file mode 100644
index 00000000..250b8358
--- /dev/null
+++ b/gn2/tests/unit/base/test_webqtl_case_data.py
@@ -0,0 +1,40 @@
+"""Tests for wqflask/base/webqtlCaseData.py"""
+import unittest
+
+from gn2.wqflask import app # Required because of utility.tools in webqtlCaseData.py
+from gn2.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),
+ "<webqtlCaseData> 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/gn2/tests/unit/utility/__init__.py b/gn2/tests/unit/utility/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/gn2/tests/unit/utility/__init__.py
diff --git a/gn2/tests/unit/utility/test_authentication_tools.py b/gn2/tests/unit/utility/test_authentication_tools.py
new file mode 100644
index 00000000..3b16ca94
--- /dev/null
+++ b/gn2/tests/unit/utility/test_authentication_tools.py
@@ -0,0 +1,192 @@
+"""Tests for authentication tools"""
+import unittest
+from unittest import mock
+
+from gn2.utility.authentication_tools import check_resource_availability
+from gn2.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 b"Jane"
+
+user_id = b"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', TestUserSession())
+ @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, user_id), 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 non-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, user_id),
+ ['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 = [b"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, user_id),
+ "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", user_id),
+ "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, user_id),
+ "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/gn2/tests/unit/utility/test_chunks.py b/gn2/tests/unit/utility/test_chunks.py
new file mode 100644
index 00000000..1b5a9413
--- /dev/null
+++ b/gn2/tests/unit/utility/test_chunks.py
@@ -0,0 +1,20 @@
+"""Test chunking"""
+
+import unittest
+
+from gn2.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/gn2/tests/unit/utility/test_corestats.py b/gn2/tests/unit/utility/test_corestats.py
new file mode 100644
index 00000000..c0eaf566
--- /dev/null
+++ b/gn2/tests/unit/utility/test_corestats.py
@@ -0,0 +1,55 @@
+"""Test Core Stats"""
+
+import unittest
+
+from gn2.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/gn2/tests/unit/utility/test_corr_result_helpers.py b/gn2/tests/unit/utility/test_corr_result_helpers.py
new file mode 100644
index 00000000..59260ba6
--- /dev/null
+++ b/gn2/tests/unit/utility/test_corr_result_helpers.py
@@ -0,0 +1,32 @@
+""" Test correlation helper methods """
+
+import unittest
+from gn2.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/gn2/tests/unit/utility/test_formatting.py b/gn2/tests/unit/utility/test_formatting.py
new file mode 100644
index 00000000..aad9735d
--- /dev/null
+++ b/gn2/tests/unit/utility/test_formatting.py
@@ -0,0 +1,33 @@
+import unittest
+from gn2.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/gn2/tests/unit/utility/test_hmac.py b/gn2/tests/unit/utility/test_hmac.py
new file mode 100644
index 00000000..2b428588
--- /dev/null
+++ b/gn2/tests/unit/utility/test_hmac.py
@@ -0,0 +1,51 @@
+"""Test hmac utility functions"""
+
+import unittest
+from unittest import mock
+
+from gn2.utility.hmac import data_hmac
+from gn2.utility.hmac import url_for_hmac
+from gn2.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/gn2/tests/unit/utility/test_type_checking.py b/gn2/tests/unit/utility/test_type_checking.py
new file mode 100644
index 00000000..e7b8e953
--- /dev/null
+++ b/gn2/tests/unit/utility/test_type_checking.py
@@ -0,0 +1,54 @@
+import unittest
+from gn2.utility.type_checking import is_float
+from gn2.utility.type_checking import is_int
+from gn2.utility.type_checking import is_str
+from gn2.utility.type_checking import get_float
+from gn2.utility.type_checking import get_int
+from gn2.utility.type_checking import get_string
+
+
+class TestTypeChecking(unittest.TestCase):
+ def test_is_float(self):
+ floats = [2, 1.2, '3.1']
+ not_floats = ["String", None, [], ()]
+ for flt in floats:
+ results = is_float(flt)
+ self.assertTrue(results)
+ for nflt in not_floats:
+ results = is_float(nflt)
+ self.assertFalse(results)
+
+ def test_is_int(self):
+ int_values = [1, 1.1]
+ not_int_values = ["string", None, [], "1.1"]
+ for int_val in int_values:
+ results = is_int(int_val)
+ self.assertTrue(results)
+ for not_int in not_int_values:
+ results = is_int(not_int)
+ self.assertFalse(results)
+
+ def test_is_str(self):
+ string_values = [1, False, [], {}, "string_value"]
+ falsey_values = [None]
+ for string_val in string_values:
+ results = is_str(string_val)
+ self.assertTrue(results)
+ for non_string in falsey_values:
+ results = is_str(non_string)
+ self.assertFalse(results)
+
+ def test_get_float(self):
+ vars_object = {"min_value": "12"}
+ results = get_float(vars_object, "min_value")
+ self.assertEqual(results, 12.0)
+
+ def test_get_int(self):
+ vars_object = {"lx_value": "1"}
+ results = get_int(vars_object, "lx_value")
+ self.assertEqual(results, 1)
+
+ def test_get_string(self):
+ string_object = {"mx_value": 1}
+ results = get_string(string_object, "mx_value")
+ self.assertEqual(results, "1") \ No newline at end of file
diff --git a/gn2/tests/unit/wqflask/__init__.py b/gn2/tests/unit/wqflask/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/gn2/tests/unit/wqflask/__init__.py
diff --git a/gn2/tests/unit/wqflask/api/__init__.py b/gn2/tests/unit/wqflask/api/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/gn2/tests/unit/wqflask/api/__init__.py
diff --git a/gn2/tests/unit/wqflask/api/test_correlation.py b/gn2/tests/unit/wqflask/api/test_correlation.py
new file mode 100644
index 00000000..8835375d
--- /dev/null
+++ b/gn2/tests/unit/wqflask/api/test_correlation.py
@@ -0,0 +1,175 @@
+import unittest
+from unittest import mock
+from gn2.wqflask import app
+from collections import OrderedDict
+from gn2.wqflask.api.correlation import init_corr_params
+from gn2.wqflask.api.correlation import convert_to_mouse_gene_id
+from gn2.wqflask.api.correlation import do_literature_correlation_for_all_traits
+from gn2.wqflask.api.correlation import get_sample_r_and_p_values
+from gn2.wqflask.api.correlation import calculate_results
+
+
+class AttributeSetter:
+ def __init__(self, obj):
+ for k, v in obj.items():
+ setattr(self, k, v)
+
+
+class MockDataset(AttributeSetter):
+ def get_trait_data(self):
+ return None
+
+ def retrieve_genes(self, id=None):
+ return {"TT-1": "GH-1", "TT-2": "GH-2", "TT-3": "GH-3"}
+
+
+class TestCorrelations(unittest.TestCase):
+ def setUp(self):
+ self.app_context = app.app_context()
+ self.app_context.push()
+
+ def tearDown(self):
+ self.app_context.pop()
+
+ def test_init_corr_params(self):
+ start_vars = {"return_count": "3", "type": "T1", "method": "spearman"}
+
+ corr_params_results = init_corr_params(start_vars=start_vars)
+ expected_results = {"return_count": 3, "type": "T1", "method": "spearman"}
+
+ self.assertEqual(corr_params_results, expected_results)
+
+ @mock.patch("wqflask.api.correlation.database_connection")
+ def test_convert_to_mouse_gene_id(self, mock_db):
+ conn = mock.MagicMock()
+ mock_db.return_value.__enter__.return_value = conn
+ with conn.cursor() as cursor:
+ cursor.fetchone.side_effect = [("MG-1",), ("MG-2",)]
+
+ self.assertEqual(
+ convert_to_mouse_gene_id(species="Other", gene_id=""), None
+ )
+ self.assertEqual(
+ convert_to_mouse_gene_id(species="mouse", gene_id="MG-4"), "MG-4"
+ )
+ self.assertEqual(
+ convert_to_mouse_gene_id(species="rat", gene_id="R1"), "MG-1"
+ )
+ self.assertEqual(
+ convert_to_mouse_gene_id(species="human", gene_id="H1"), "MG-2"
+ )
+
+ @mock.patch("wqflask.api.correlation.database_connection")
+ @mock.patch("wqflask.api.correlation.convert_to_mouse_gene_id")
+ def test_do_literature_correlation_for_all_traits(
+ self, mock_convert_to_mouse_geneid, mock_db
+ ):
+ mock_convert_to_mouse_geneid.side_effect = ["MG-1", "MG-2;", "MG-3", "MG-4"]
+
+ trait_geneid_dict = {"TT-1": "GH-1", "TT-2": "GH-2", "TT-3": "GH-3"}
+ conn = mock.MagicMock()
+ mock_db.return_value.__enter__.return_value = conn
+ with conn.cursor() as cursor:
+ cursor.fetchone.side_effect = [("V1",), ("V2",), ("V3",)]
+ this_trait = AttributeSetter({"geneid": "GH-1"})
+ target_dataset = AttributeSetter(
+ {"group": AttributeSetter({"species": "rat"})}
+ )
+ results = do_literature_correlation_for_all_traits(
+ this_trait=this_trait,
+ target_dataset=target_dataset,
+ trait_geneid_dict=trait_geneid_dict,
+ corr_params={},
+ )
+ expected_results = {
+ "TT-1": ["GH-1", 0],
+ "TT-2": ["GH-2", "V1"],
+ "TT-3": ["GH-3", "V2"],
+ }
+ self.assertEqual(results, expected_results)
+
+ @mock.patch("wqflask.api.correlation.corr_result_helpers.normalize_values")
+ def test_get_sample_r_and_p_values(self, mock_normalize):
+
+ group = AttributeSetter(
+ {"samplelist": ["S1", "S2", "S3", "S4", "S5", "S6", "S7"]}
+ )
+ target_dataset = AttributeSetter({"group": group})
+
+ target_vals = [3.4, 6.2, 4.1, 3.4, 1.2, 5.6]
+ trait_data = {
+ "S1": AttributeSetter({"value": 2.3}),
+ "S2": AttributeSetter({"value": 1.1}),
+ "S3": AttributeSetter({"value": 6.3}),
+ "S4": AttributeSetter({"value": 3.6}),
+ "S5": AttributeSetter({"value": 4.1}),
+ "S6": AttributeSetter({"value": 5.0}),
+ }
+ this_trait = AttributeSetter({"data": trait_data})
+ mock_normalize.return_value = (
+ [2.3, 1.1, 6.3, 3.6, 4.1, 5.0],
+ [3.4, 6.2, 4.1, 3.4, 1.2, 5.6],
+ 6,
+ )
+ mock_normalize.side_effect = [
+ ([2.3, 1.1, 6.3, 3.6, 4.1, 5.0], [3.4, 6.2, 4.1, 3.4, 1.2, 5.6], 6),
+ ([2.3, 1.1, 6.3, 3.6, 4.1, 5.0], [3.4, 6.2, 4.1, 3.4, 1.2, 5.6], 6),
+ ([2.3, 1.1, 1.4], [3.4, 6.2, 4.1], 3),
+ ]
+
+ results_pearsonr = get_sample_r_and_p_values(
+ this_trait=this_trait,
+ this_dataset={},
+ target_vals=target_vals,
+ target_dataset=target_dataset,
+ type="pearson",
+ )
+ results_spearmanr = get_sample_r_and_p_values(
+ this_trait=this_trait,
+ this_dataset={},
+ target_vals=target_vals,
+ target_dataset=target_dataset,
+ type="spearman",
+ )
+ results_num_overlap = get_sample_r_and_p_values(
+ this_trait=this_trait,
+ this_dataset={},
+ target_vals=target_vals,
+ target_dataset=target_dataset,
+ type="pearson",
+ )
+ expected_pearsonr = [-0.21618688834430866, 0.680771605997119, 6]
+ expected_spearmanr = [-0.11595420713048969, 0.826848213385815, 6]
+ for i, val in enumerate(expected_pearsonr):
+ self.assertAlmostEqual(val, results_pearsonr[i], 4)
+ for i, val in enumerate(expected_spearmanr):
+ self.assertAlmostEqual(val, results_spearmanr[i], 4)
+ self.assertEqual(results_num_overlap, None)
+
+ @mock.patch("wqflask.api.correlation.do_literature_correlation_for_all_traits")
+ def test_calculate_results(self, literature_correlation):
+
+ literature_correlation.return_value = {
+ "TT-1": ["GH-1", 0],
+ "TT-2": ["GH-2", 3],
+ "TT-3": ["GH-3", 1],
+ }
+
+ this_dataset = MockDataset({"group": AttributeSetter({"species": "rat"})})
+ target_dataset = MockDataset({"group": AttributeSetter({"species": "rat"})})
+ this_trait = AttributeSetter({"geneid": "GH-1"})
+ corr_params = {"type": "literature"}
+ sorted_results = calculate_results(
+ this_trait=this_trait,
+ this_dataset=this_dataset,
+ target_dataset=target_dataset,
+ corr_params=corr_params,
+ )
+ expected_results = {
+ "TT-2": ["GH-2", 3],
+ "TT-3": ["GH-3", 1],
+ "TT-1": ["GH-1", 0],
+ }
+
+ self.assertTrue(isinstance(sorted_results, OrderedDict))
+ self.assertEqual(dict(sorted_results), expected_results)
diff --git a/gn2/tests/unit/wqflask/api/test_gen_menu.py b/gn2/tests/unit/wqflask/api/test_gen_menu.py
new file mode 100644
index 00000000..a6081e99
--- /dev/null
+++ b/gn2/tests/unit/wqflask/api/test_gen_menu.py
@@ -0,0 +1,423 @@
+"""Test cases for wqflask.api.gen_menu"""
+import unittest
+from unittest import mock
+
+from gn2.wqflask.api.gen_menu import gen_dropdown_json
+from gn2.wqflask.api.gen_menu import get_groups
+from gn2.wqflask.api.gen_menu import get_types
+from gn2.wqflask.api.gen_menu import get_datasets
+from gn2.wqflask.api.gen_menu import phenotypes_exist
+from gn2.wqflask.api.gen_menu import genotypes_exist
+from gn2.wqflask.api.gen_menu import build_datasets
+from gn2.wqflask.api.gen_menu import build_types
+
+
+class TestGenMenu(unittest.TestCase):
+ """Tests for the gen_menu module"""
+
+ def setUp(self):
+ 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 test_get_groups(self):
+ """Test that species groups are grouped correctly"""
+ db_mock = mock.MagicMock()
+ with db_mock.cursor() as cursor:
+ cursor.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"]],
+ db_mock),
+ self.test_group)
+
+ for name in ["mouse", "human"]:
+ cursor.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)
+ )
+
+ def test_phenotypes_exist_called_with_correct_query(self):
+ """Test that phenotypes_exist is called with the correct query"""
+ db_mock = mock.MagicMock()
+ with db_mock.cursor() as cursor:
+ cursor.fetchone.return_value = None
+ phenotypes_exist("test", db_mock)
+ cursor.execute.assert_called_with(
+ "SELECT Name FROM PublishFreeze "
+ "WHERE PublishFreeze.Name = 'testPublish'"
+ )
+
+ def test_phenotypes_exist_with_falsy_values(self):
+ """Test that phenotype check returns correctly when given
+ a None value"""
+ db_mock = mock.MagicMock()
+ with db_mock.cursor() as cursor:
+ for x in [None, False, (), [], ""]:
+ cursor.fetchone.return_value = x
+ self.assertFalse(phenotypes_exist("test", db_mock))
+
+ def test_phenotypes_exist_with_truthy_value(self):
+ """Test that phenotype check returns correctly when given Truthy"""
+ db_mock = mock.MagicMock()
+ with db_mock.cursor() as conn:
+ with conn.cursor() as cursor:
+ for x in ["x", ("result"), ["result"], [1]]:
+ cursor.fetchone.return_value = (x)
+ self.assertTrue(phenotypes_exist("test", db_mock))
+
+ def test_genotypes_exist_called_with_correct_query(self):
+ """Test that genotypes_exist is called with the correct query"""
+ db_mock = mock.MagicMock()
+ with db_mock.cursor() as cursor:
+ cursor.fetchone.return_value = None
+ genotypes_exist("test", db_mock)
+ cursor.execute.assert_called_with(
+ "SELECT Name FROM GenoFreeze WHERE "
+ "GenoFreeze.Name = 'testGeno'"
+ )
+
+ def test_genotypes_exist_with_falsy_values(self):
+ """Test that genotype check returns correctly when given a None value
+
+ """
+ db_mock = mock.MagicMock()
+ with db_mock.cursor() as cursor:
+ for x in [None, False, (), [], ""]:
+ cursor.fetchone.return_value = x
+ self.assertFalse(genotypes_exist("test", db_mock))
+
+ def test_genotypes_exist_with_truthy_value(self):
+ """Test that genotype check returns correctly when given Truthy """
+ db_mock = mock.MagicMock()
+ with db_mock.cursor() as cursor:
+ for x in ["x", ("result"), ["result"], [1]]:
+ cursor.fetchone.return_value = (x)
+ self.assertTrue(phenotypes_exist("test", db_mock))
+
+ def test_build_datasets_with_type_phenotypes(self):
+ """Test that correct dataset is returned for a phenotype type"""
+ db_mock = mock.MagicMock()
+ with db_mock.cursor() as cursor:
+ cursor.fetchall.return_value = (
+ (602, "BXDPublish", "BXD Published Phenotypes"),
+ )
+ self.assertEqual(build_datasets("Mouse", "BXD",
+ "Phenotypes", db_mock),
+ [['602', "BXDPublish",
+ "BXD Published Phenotypes"]])
+ cursor.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", db_mock),
+ [['602', "BXDPublish",
+ "Mouse Phenome Database"]])
+
+ cursor.fetchall.return_value = ()
+ cursor.fetchone.return_value = (
+ "BXDPublish", "Mouse Phenome Database"
+ )
+ self.assertEqual(build_datasets("Mouse", "MDP",
+ "Phenotypes", db_mock),
+ [["None", "BXDPublish",
+ "Mouse Phenome Database"]])
+
+ def test_build_datasets_with_type_phenotypes_and_no_results(self):
+ """Test that correct dataset is returned for a phenotype type with no
+ results
+
+ """
+ db_mock = mock.MagicMock()
+ with db_mock.cursor() as cursor:
+ cursor.fetchall.return_value = None
+ cursor.fetchone.return_value = (121,
+ "text value")
+ self.assertEqual(build_datasets("Mouse", "BXD",
+ "Phenotypes", db_mock),
+ [["None", "121",
+ "text value"]])
+ cursor.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"
+ )
+
+ def test_build_datasets_with_type_genotypes(self):
+ """Test that correct dataset is returned for a phenotype type"""
+ db_mock = mock.MagicMock()
+ with db_mock.cursor() as cursor:
+ cursor.fetchone.return_value = (
+ 635, "HLCPublish", "HLC Published Genotypes"
+ )
+ self.assertEqual(build_datasets("Mouse", "HLC",
+ "Genotypes", db_mock),
+ [["635", "HLCGeno", "HLC Genotypes"]])
+ cursor.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"
+ )
+ cursor.fetchone.return_value = ()
+ self.assertEqual(build_datasets("Mouse", "HLC",
+ "Genotypes", db_mock),
+ [["None", "HLCGeno", "HLC Genotypes"]])
+
+ def test_build_datasets_with_type_mrna(self):
+ """Test that correct dataset is returned for a mRNA
+ expression/ Probeset"""
+ db_mock = mock.MagicMock()
+ with db_mock.cursor() as cursor:
+ cursor.fetchall.return_value = (
+ (112, "HC_M2_0606_P",
+ "Hippocampus Consortium M430v2 (Jun06) PDNN"), )
+ self.assertEqual(build_datasets("Mouse",
+ "HLC", "mRNA", db_mock),
+ [["112", 'HC_M2_0606_P',
+ "Hippocampus Consortium M430v2 (Jun06) PDNN"
+ ]])
+ cursor.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 AND "
+ "ProbeSetFreeze.public > 0 "
+ "ORDER BY -ProbeSetFreeze.OrderList DESC, "
+ "ProbeSetFreeze.CreateTime DESC")
+
+ @mock.patch('wqflask.api.gen_menu.build_datasets')
+ def test_build_types(self, datasets_mock):
+ """Test that correct tissue metadata is returned"""
+ db_mock = mock.MagicMock()
+ datasets_mock.return_value = [
+ ["112", 'HC_M2_0606_P',
+ "Hippocampus Consortium M430v2 (Jun06) PDNN"]
+ ]
+ with db_mock.cursor() as cursor:
+ cursor.fetchall.return_value = (
+ ('Mouse Tissue'), ('Human Tissue'), ('Rat Tissue')
+ )
+ self.assertEqual(build_types('mouse', 'random group', db_mock),
+ [['M', 'M', 'Molecular Traits'],
+ ['H', 'H', 'Molecular Traits'],
+ ['R', 'R', 'Molecular Traits']])
+ cursor.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,
+ mock.MagicMock()),
+ 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, mock.MagicMock()),
+ {'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, mock.MagicMock()),
+ 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, mock.MagicMock()),
+ 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, mock.MagicMock()),
+ 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_all_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(mock.MagicMock()), expected_result)
diff --git a/gn2/tests/unit/wqflask/api/test_mapping.py b/gn2/tests/unit/wqflask/api/test_mapping.py
new file mode 100644
index 00000000..1553cbf6
--- /dev/null
+++ b/gn2/tests/unit/wqflask/api/test_mapping.py
@@ -0,0 +1,113 @@
+import unittest
+from unittest import mock
+from gn2.wqflask.api.mapping import initialize_parameters
+from gn2.wqflask.api.mapping import do_mapping_for_api
+
+
+class AttributeSetter:
+ def __init__(self, obj):
+ for key, value in obj.items():
+ setattr(self, key, value)
+
+
+class MockGroup(AttributeSetter):
+ def get_marker(self):
+ self.markers = []
+
+
+class TestMapping(unittest.TestCase):
+
+ def test_initialize_parameters(self):
+ expected_results = {
+ "format": "json",
+ "limit_to": False,
+ "mapping_method": "gemma",
+ "maf": 0.01,
+ "use_loco": True,
+ "num_perm": 0,
+ "perm_check": False,
+ "transform": False,
+ "genofile": False
+ }
+
+ results = initialize_parameters(
+ start_vars={}, dataset={}, this_trait={})
+ self.assertEqual(results, expected_results)
+
+ start_vars = {
+ "format": "F1",
+ "limit_to": "1",
+ "mapping_method": "rqtl",
+ "control_marker": True,
+ "pair_scan": "true",
+ "interval_mapping": "true",
+ "use_loco": "true",
+ "num_perm": "14",
+ "transform": "qnorm",
+ "genofile": "BXD.8.geno"
+ }
+
+ results_2 = initialize_parameters(
+ start_vars=start_vars, dataset={}, this_trait={})
+ expected_results = {
+ "format": "F1",
+ "limit_to": 1,
+ "mapping_method": "gemma",
+ "maf": 0.01,
+ "use_loco": True,
+ "num_perm": 14,
+ "perm_check": "ON",
+ "transform": "qnorm",
+ "genofile": "BXD.8.geno"
+ }
+
+ self.assertEqual(results_2, expected_results)
+
+ @mock.patch("wqflask.api.mapping.rqtl_mapping.run_rqtl")
+ @mock.patch("wqflask.api.mapping.gemma_mapping.run_gemma")
+ @mock.patch("wqflask.api.mapping.initialize_parameters")
+ @mock.patch("wqflask.api.mapping.retrieve_sample_data")
+ @mock.patch("wqflask.api.mapping.create_trait")
+ @mock.patch("wqflask.api.mapping.data_set.create_dataset")
+ def test_do_mapping_for_api(self, mock_create_dataset, mock_trait, mock_retrieve_sample, mock_param, run_gemma, run_rqtl_geno):
+ start_vars = {
+ "db": "Temp",
+ "trait_id": "dewf3232rff2",
+ "format": "F1",
+ "mapping_method": "gemma",
+ "use_loco": True
+
+ }
+ sampleList = ["S1", "S2", "S3", "S4"]
+ samplelist = ["S1", "S2", "S4"]
+ dataset = AttributeSetter({"group": samplelist})
+ this_trait = AttributeSetter({})
+ trait_data = AttributeSetter({
+ "data": {
+ "item1": AttributeSetter({"name": "S1", "value": "S1_value"}),
+ "item2": AttributeSetter({"name": "S2", "value": "S2_value"}),
+ "item3": AttributeSetter({"name": "S3", "value": "S3_value"}),
+
+ }
+ })
+ trait = AttributeSetter({
+ "data": trait_data
+ })
+
+ dataset.return_value = dataset
+ mock_trait.return_value = this_trait
+
+ mock_retrieve_sample.return_value = trait
+ mock_param.return_value = {
+ "format": "F1",
+ "limit_to": False,
+ "mapping_method": "gemma",
+ "maf": 0.01,
+ "use_loco": "True",
+ "num_perm": 14,
+ "perm_check": "ON"
+ }
+
+ run_gemma.return_value = ["results"]
+ results = do_mapping_for_api(start_vars=start_vars)
+ self.assertEqual(results, ("results", None))
diff --git a/gn2/tests/unit/wqflask/api/test_markdown_routes.py b/gn2/tests/unit/wqflask/api/test_markdown_routes.py
new file mode 100644
index 00000000..f0f93bc1
--- /dev/null
+++ b/gn2/tests/unit/wqflask/api/test_markdown_routes.py
@@ -0,0 +1,54 @@
+"""Test functions for wqflask/api/markdown.py"""
+
+import unittest
+from unittest import mock
+
+from dataclasses import dataclass
+from gn2.wqflask.api.markdown import render_markdown
+
+
+@dataclass
+class MockRequests404:
+ status_code: int = 404
+
+
+@dataclass
+class MockRequests200:
+ status_code: int = 200
+ content: str = b"""
+# Glossary
+This is some content
+
+## Sub-heading
+This is another sub-heading"""
+
+
+class TestMarkdownRoutesFunctions(unittest.TestCase):
+ """Test cases for functions in markdown"""
+
+ @mock.patch('wqflask.api.markdown.requests.get')
+ def test_render_markdown_when_fetching_locally(self, requests_mock):
+ requests_mock.return_value = MockRequests404()
+ markdown_content = render_markdown("general/glossary/glossary.md")
+ requests_mock.assert_called_with(
+ "https://raw.githubusercontent.com"
+ "/genenetwork/gn-docs/"
+ "master/general/"
+ "glossary/glossary.md")
+ self.assertRegex(markdown_content,
+ "Content for general/glossary/glossary.md not available.")
+
+ @mock.patch('wqflask.api.markdown.requests.get')
+ def test_render_markdown_when_fetching_remotely(self, requests_mock):
+ requests_mock.return_value = MockRequests200()
+ markdown_content = render_markdown("general/glossary/glossary.md")
+ requests_mock.assert_called_with(
+ "https://raw.githubusercontent.com"
+ "/genenetwork/gn-docs/"
+ "master/general/"
+ "glossary/glossary.md")
+ self.assertEqual("""<h1>Glossary</h1>
+<p>This is some content</p>
+<h2>Sub-heading</h2>
+<p>This is another sub-heading</p>""",
+ markdown_content)
diff --git a/gn2/tests/unit/wqflask/correlation/__init__.py b/gn2/tests/unit/wqflask/correlation/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/gn2/tests/unit/wqflask/correlation/__init__.py
diff --git a/gn2/tests/unit/wqflask/correlation/test_correlation_functions.py b/gn2/tests/unit/wqflask/correlation/test_correlation_functions.py
new file mode 100644
index 00000000..c0f57141
--- /dev/null
+++ b/gn2/tests/unit/wqflask/correlation/test_correlation_functions.py
@@ -0,0 +1,21 @@
+"""module contains tests for correlation functions"""
+
+import unittest
+from unittest import mock
+
+from gn2.wqflask.correlation.correlation_functions import get_trait_symbol_and_tissue_values
+from gn2.wqflask.correlation.correlation_functions import cal_zero_order_corr_for_tiss
+
+
+def test_tissue_corr_computation(mocker):
+ """Test for cal_zero_order_corr_for_tiss"""
+ primary_values = [9.288, 9.313, 8.988, 9.660, 8.21]
+ target_values = [9.586, 8.498, 9.362, 8.820, 8.786]
+ _m = mocker.patch(("wqflask.correlation.correlation_functions."
+ "compute_corr_coeff_p_value"),
+ return_value=(0.51, 0.7))
+ results = cal_zero_order_corr_for_tiss(primary_values, target_values)
+ _m.assert_called_once_with(
+ primary_values=primary_values, target_values=target_values,
+ corr_method="pearson")
+ assert len(results) == 3
diff --git a/gn2/tests/unit/wqflask/correlation/test_correlation_gn3.py b/gn2/tests/unit/wqflask/correlation/test_correlation_gn3.py
new file mode 100644
index 00000000..432dbc95
--- /dev/null
+++ b/gn2/tests/unit/wqflask/correlation/test_correlation_gn3.py
@@ -0,0 +1,14 @@
+"""this module contains tests for code used in integrating to gn3 api"""
+from unittest import TestCase
+from gn2.base.data_set import create_dataset
+
+class TestCorrelation(TestCase):
+
+ def test_create_dataset(self):
+ """test for creating datasets"""
+
+ pass
+ def test_fetch_dataset_info(self):
+ """test for fetching dataset info data"""
+
+ pass
diff --git a/gn2/tests/unit/wqflask/correlation/test_show_corr_results.py b/gn2/tests/unit/wqflask/correlation/test_show_corr_results.py
new file mode 100644
index 00000000..b1459dd9
--- /dev/null
+++ b/gn2/tests/unit/wqflask/correlation/test_show_corr_results.py
@@ -0,0 +1,42 @@
+import unittest
+from unittest import mock
+from gn2.wqflask.correlation.show_corr_results import get_header_fields
+
+
+class AttributeSetter:
+ def __init__(self, trait_obj):
+ for key, value in trait_obj.items():
+ setattr(self, key, value)
+
+
+class TestShowCorrResults(unittest.TestCase):
+ def test_get_header_fields(self):
+ expected = [
+ ['Index',
+ 'Record',
+ 'Symbol',
+ 'Description',
+ 'Location',
+ 'Mean',
+ 'Sample rho',
+ 'N',
+ 'Sample p(rho)',
+ 'Lit rho',
+ 'Tissue rho',
+ 'Tissue p(rho)',
+ 'Max LRS',
+ 'Max LRS Location',
+ 'Additive Effect'],
+
+ ['Index',
+ 'ID',
+ 'Location',
+ 'Sample r',
+ 'N',
+ 'Sample p(r)']
+
+ ]
+ result1 = get_header_fields("ProbeSet", "spearman")
+ result2 = get_header_fields("Other", "Other")
+ self.assertEqual(result1, expected[0])
+ self.assertEqual(result2, expected[1])
diff --git a/gn2/tests/unit/wqflask/marker_regression/__init__.py b/gn2/tests/unit/wqflask/marker_regression/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/gn2/tests/unit/wqflask/marker_regression/__init__.py
diff --git a/gn2/tests/unit/wqflask/marker_regression/genotype/bimbam/file_geno.txt b/gn2/tests/unit/wqflask/marker_regression/genotype/bimbam/file_geno.txt
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/gn2/tests/unit/wqflask/marker_regression/genotype/bimbam/file_geno.txt
diff --git a/gn2/tests/unit/wqflask/marker_regression/genotype/bimbam/file_snps.txt b/gn2/tests/unit/wqflask/marker_regression/genotype/bimbam/file_snps.txt
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/gn2/tests/unit/wqflask/marker_regression/genotype/bimbam/file_snps.txt
diff --git a/gn2/tests/unit/wqflask/marker_regression/test_display_mapping_results.py b/gn2/tests/unit/wqflask/marker_regression/test_display_mapping_results.py
new file mode 100644
index 00000000..580d79cf
--- /dev/null
+++ b/gn2/tests/unit/wqflask/marker_regression/test_display_mapping_results.py
@@ -0,0 +1,159 @@
+import unittest
+
+import htmlgen as HT
+from gn2.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")),
+ ("""<img alt="random" border="0" height="13" """
+ """src="test.png" usemap="#webqtlmap" """
+ """width="10"/>""")
+ )
+
+ 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", ""),
+ ("""<form action="/testing/" enctype="multipart/form-data" """
+ """method="POST" """
+ """name="formName"><input name="Default_Name" """
+ """type="hidden"/></form>"""))
+ 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", ""), (
+ """<form action="/testing/" enctype="multipart/form-data" """
+ """method="POST" name="formName">"""
+ """<input name="Default_Name" type="hidden"/>"""
+ """<input name="FormID" type="hidden" value="showDatabase"/>"""
+ """<input name="ProbeSetID" type="hidden" value="_"/>"""
+ """<input name="database" type="hidden" value="TestGeno"/>"""
+ """<input name="CellID" type="hidden" value="_"/>"""
+ """<input name="RISet" type="hidden" value="Test"/>"""
+ """<input name="incparentsf1" type="hidden" value="ON"/>"""
+ """<img alt="random" border="0" height="13" src="test.png" """
+ """usemap="#webqtlmap" width="10"/>"""
+ """</form>"""))
+
+ 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),
+ """<p id="smallSize"></p>"""
+ )
+ test_p_element.append(HtmlGenWrapper.create_br_tag())
+ test_p_element.append(par_text)
+ self.assertEqual(
+ str(test_p_element),
+ """<p id="smallSize"><br/>{}</p>""".format(par_text)
+ )
+
+ def test_create_br_tag(self):
+ """Test HT.BR() method"""
+ self.assertEqual(str(HtmlGenWrapper.create_br_tag()),
+ "<br/>")
+
+ 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", ""),
+ ("""<input class="trait trait_" name="name" """
+ """type="hidden" value="key"/>"""))
+
+ def test_create_map_tag(self):
+ """Test HT.Map method"""
+ self.assertEqual(str(HtmlGenWrapper.create_map_tag(
+ name="WebqTLImageMap")).replace("\n", ""),
+ """<map name="WebqTLImageMap"></map>""")
+ 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", ""),
+ ("""<map name="test">"""
+ """<area coords="1 2 3" """
+ """href="#area1" shape="rect"/>"""
+ """<area coords="1 2 3" href="#area2" shape="rect"/>"""
+ """</map>"""))
+
+ 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", ""),
+ ("""<area coords="1 2" href="http://test.com" """
+ """shape="rect" title="Some Title"/>"""))
+
+ 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", ""),
+ """<a href="www.test.com" target="_blank">test</a>""")
diff --git a/gn2/tests/unit/wqflask/marker_regression/test_gemma_mapping.py b/gn2/tests/unit/wqflask/marker_regression/test_gemma_mapping.py
new file mode 100644
index 00000000..26f0c50a
--- /dev/null
+++ b/gn2/tests/unit/wqflask/marker_regression/test_gemma_mapping.py
@@ -0,0 +1,188 @@
+# test for wqflask/marker_regression/gemma_mapping.py
+import os
+import unittest
+import random
+from unittest import mock
+from gn2.wqflask.marker_regression.gemma_mapping import run_gemma
+from gn2.wqflask.marker_regression.gemma_mapping import gen_pheno_txt_file
+from gn2.wqflask.marker_regression.gemma_mapping import gen_covariates_file
+from gn2.wqflask.marker_regression.gemma_mapping import parse_loco_output
+
+
+class AttributeSetter:
+ def __init__(self, obj):
+ for key, val in obj.items():
+ setattr(self, key, val)
+
+
+class MockGroup(AttributeSetter):
+ def get_samplelist(self, redis_conn):
+ return None
+
+
+class TestGemmaMapping(unittest.TestCase):
+
+ @mock.patch("wqflask.marker_regression.gemma_mapping.parse_loco_output")
+ def test_run_gemma_firstrun_set_false(self, mock_parse_loco):
+ """add tests for gemma function where first run is set to false"""
+ dataset = AttributeSetter(
+ {"group": AttributeSetter({"genofile": "genofile.geno"})})
+
+ output_file = "file1"
+ mock_parse_loco.return_value = []
+ this_trait = AttributeSetter({"name": "t1"})
+
+ result = run_gemma(this_trait=this_trait, this_dataset=dataset, samples=[], vals=[
+ ], covariates="", use_loco=True, first_run=False, output_files=output_file)
+
+ expected_results = ([], "file1")
+ self.assertEqual(expected_results, result)
+
+ @mock.patch("wqflask.marker_regression.gemma_mapping.webqtlConfig.GENERATED_IMAGE_DIR", "/home/user/img")
+ @mock.patch("wqflask.marker_regression.gemma_mapping.GEMMAOPTS", "-debug")
+ @mock.patch("wqflask.marker_regression.gemma_mapping.GEMMA_WRAPPER_COMMAND", "ghc")
+ @mock.patch("wqflask.marker_regression.gemma_mapping.TEMPDIR",
+ os.path.join(os.path.dirname(__file__), "user/data"))
+ @mock.patch("wqflask.marker_regression.gemma_mapping.parse_loco_output")
+ @mock.patch("wqflask.marker_regression.gemma_mapping.flat_files")
+ @mock.patch("wqflask.marker_regression.gemma_mapping.gen_covariates_file")
+ @mock.patch("wqflask.marker_regression.run_mapping.random.choice")
+ @mock.patch("wqflask.marker_regression.gemma_mapping.os")
+ @mock.patch("wqflask.marker_regression.gemma_mapping.gen_pheno_txt_file")
+ def test_run_gemma_firstrun_set_true(self, mock_gen_pheno_txt, mock_os, mock_choice, mock_gen_covar, mock_flat_files, mock_parse_loco):
+ """add tests for run_gemma where first run is set to true"""
+ this_chromosomes = {}
+ for i in range(1, 5):
+ this_chromosomes[f'CH{i}'] = (AttributeSetter({"name": f"CH{i}"}))
+ chromosomes = AttributeSetter({"chromosomes": lambda cursor: this_chromosomes})
+
+ dataset_group = MockGroup(
+ {"name": "GP1", "genofile": "file_geno"})
+ dataset = AttributeSetter({"group": dataset_group, "name": "dataset1_name",
+ "species": AttributeSetter({"chromosomes": chromosomes})})
+ trait = AttributeSetter({"name": "trait1"})
+ samples = []
+ mock_gen_pheno_txt.return_value = None
+ mock_os.path.isfile.return_value = True
+ mock_gen_covar.return_value = None
+ mock_choice.return_value = "R"
+ mock_flat_files.return_value = os.path.join(
+ os.path.dirname(__file__), "genotype/bimbam")
+ mock_parse_loco.return_value = []
+ results = run_gemma(this_trait=trait, this_dataset=dataset, samples=[
+ ], vals=[], covariates="", use_loco=True)
+ mock_gen_pheno_txt.assert_called_once()
+ mock_parse_loco.assert_called_once_with(
+ dataset, "GP1_GWA_RRRRRR", True)
+ mock_os.path.isfile.assert_called_once_with(
+ ('/home/user/imgfile_output.assoc.txt'))
+ self.assertEqual(results, ([], "GP1_GWA_RRRRRR"))
+
+ @mock.patch("wqflask.marker_regression.gemma_mapping.TEMPDIR", "/home/user/data")
+ def test_gen_pheno_txt_file(self):
+ """add tests for generating pheno txt file"""
+ with mock.patch("builtins.open", mock.mock_open())as mock_open:
+ gen_pheno_txt_file(
+ this_dataset=AttributeSetter({"name": "A"}),
+ genofile_name="", vals=[
+ "x", "w", "q", "we", "R"])
+ mock_open.assert_called_once_with(
+ '/home/user/data/gn2/PHENO_KiAEKlCvM6iGTM9Kh_TAlQ.txt', 'w')
+ filehandler = mock_open()
+ values = ["x", "w", "q", "we", "R"]
+ write_calls = [mock.call('NA\n'), mock.call('w\n'), mock.call(
+ 'q\n'), mock.call('we\n'), mock.call('R\n')]
+
+ filehandler.write.assert_has_calls(write_calls)
+
+ @mock.patch("wqflask.marker_regression.gemma_mapping.flat_files")
+ @mock.patch("wqflask.marker_regression.gemma_mapping.create_trait")
+ @mock.patch("wqflask.marker_regression.gemma_mapping.create_dataset")
+ def test_gen_covariates_file(self, create_dataset, create_trait, flat_files):
+ """add tests for generating covariates files"""
+ covariates = "X1:X2,Y1:Y2,M1:M3,V1:V2"
+ samplelist = ["X1", "X2", "X3", "X4"]
+ create_dataset_side_effect = []
+ create_trait_side_effect = []
+
+ for i in range(4):
+ create_dataset_side_effect.append(
+ AttributeSetter({"name": f'name_{i}'}))
+ create_trait_side_effect.append(
+ AttributeSetter({"data": [f'data_{i}']}))
+
+ create_dataset.side_effect = create_trait_side_effect
+ create_trait.side_effect = create_trait_side_effect
+
+ group = MockGroup({"name": "group_X", "samplelist": samplelist})
+ this_dataset = AttributeSetter({"group": group, "name": "dataset1_name"})
+ flat_files.return_value = "Home/Genenetwork"
+
+ with mock.patch("builtins.open", mock.mock_open())as mock_open:
+ gen_covariates_file(this_dataset=this_dataset, covariates=covariates,
+ samples=["x1", "x2", "X3"])
+
+ create_dataset.assert_has_calls(
+ [mock.call('X2'), mock.call('Y2'), mock.call('M3'), mock.call('V2')])
+ mock_calls = []
+ trait_names = ["X1", "Y1", "M1", "V1"]
+
+ for i, trait in enumerate(create_trait_side_effect):
+ mock_calls.append(
+ mock.call(dataset=trait, name=trait_names[i], cellid=None))
+
+ create_trait.assert_has_calls(mock_calls)
+
+ flat_files.assert_called_once_with('mapping')
+ mock_open.assert_called_once_with(
+ 'Home/Genenetwork/COVAR_npKxIOnq3azWdgYixtd9IQ.txt', 'w')
+ filehandler = mock_open()
+ filehandler.write.assert_has_calls([mock.call(
+ '-9\t'), mock.call('-9\t'), mock.call('-9\t'), mock.call('-9\t'), mock.call('\n')])
+
+ @mock.patch("wqflask.marker_regression.gemma_mapping.TEMPDIR", "/home/tmp")
+ @mock.patch("wqflask.marker_regression.gemma_mapping.os")
+ @mock.patch("wqflask.marker_regression.gemma_mapping.json")
+ def test_parse_loco_outputfile_found(self, mock_json, mock_os):
+ """add tests for parse loco output file found"""
+ mock_json.load.return_value = {
+ "files": [["file_name", "user", "~/file1"],
+ ["file_name", "user", "~/file2"]]
+ }
+ return_file = """X/Y\tM1\t28.457155\tQ\tE\tA\tMMB\t23.3\tW\t0.9\t0.85\t
+chr4\tM2\t12\tQ\tE\tMMB\tR\t24\tW\t0.87\t0.5
+Y\tM4\t12\tQ\tE\tMMB\tR\t11.6\tW\t0.21\t0.7
+X\tM5\t12\tQ\tE\tMMB\tR\t21.1\tW\t0.65\t0.6"""
+
+ return_file_2 = """chr\tother\t21322\tQ\tE\tA\tP\tMMB\tCDE\t0.5\t0.4"""
+ mock_os.path.isfile.return_value = True
+ file_to_write = """{"files":["file_1","file_2"]}"""
+ with mock.patch("builtins.open") as mock_open:
+
+ handles = (mock.mock_open(read_data="gwas").return_value, mock.mock_open(
+ read_data=return_file).return_value, mock.mock_open(read_data=return_file_2).return_value)
+ mock_open.side_effect = handles
+ results = parse_loco_output(
+ this_dataset={}, gwa_output_filename=".xw/")
+ expected_results = [
+ {'name': 'M1', 'chr': 'X/Y', 'Mb': 2.8457155e-05, 'p_value': 0.85,
+ 'additive': -11.65, 'lod_score': 0.07058107428570727},
+ {'name': 'M2', 'chr': 4, 'Mb': 1.2e-05, 'p_value': 0.5,
+ 'additive': -12.0, 'lod_score': 0.3010299956639812},
+ {'name': 'M4', 'chr': 'Y', 'Mb': 1.2e-05, 'p_value': 0.7,
+ 'additive': -5.8, 'lod_score': 0.1549019599857432},
+ {'name': 'M5', 'chr': 'X', 'Mb': 1.2e-05, 'p_value': 0.6, 'additive': -10.55, 'lod_score': 0.22184874961635637}]
+ self.assertEqual(expected_results, results)
+
+ @mock.patch("wqflask.marker_regression.gemma_mapping.TEMPDIR", "/home/tmp")
+ @mock.patch("wqflask.marker_regression.gemma_mapping.os")
+ def test_parse_loco_outputfile_not_found(self, mock_os):
+ """add tests for parse loco output where output file not found"""
+
+ mock_os.path.isfile.return_value = False
+ file_to_write = """{"files":["file_1","file_2"]}"""
+
+ with mock.patch("builtins.open", mock.mock_open(read_data=file_to_write)) as mock_open:
+ results = parse_loco_output(
+ this_dataset={}, gwa_output_filename=".xw/")
+ self.assertEqual(results, [])
diff --git a/gn2/tests/unit/wqflask/marker_regression/test_plink_mapping.py b/gn2/tests/unit/wqflask/marker_regression/test_plink_mapping.py
new file mode 100644
index 00000000..4c13b907
--- /dev/null
+++ b/gn2/tests/unit/wqflask/marker_regression/test_plink_mapping.py
@@ -0,0 +1,86 @@
+# test for wqflask/marker_regression/plink_mapping.py
+import unittest
+from unittest import mock
+from gn2.wqflask.marker_regression.plink_mapping import build_line_list
+from gn2.wqflask.marker_regression.plink_mapping import get_samples_from_ped_file
+from gn2.wqflask.marker_regression.plink_mapping import flat_files
+from gn2.wqflask.marker_regression.plink_mapping import gen_pheno_txt_file_plink
+from gn2.wqflask.marker_regression.plink_mapping import parse_plink_output
+
+
+class AttributeSetter:
+ def __init__(self, obj):
+ for key, val in obj.items():
+ setattr(self, key, val)
+
+
+class TestPlinkMapping(unittest.TestCase):
+
+ def test_build_line_list(self):
+ """test for building line list"""
+ line_1 = "this is line one test"
+ irregular_line = " this is an, irregular line "
+ exp_line1 = ["this", "is", "line", "one", "test"]
+
+ results = build_line_list(irregular_line)
+ self.assertEqual(exp_line1, build_line_list(line_1))
+ self.assertEqual([], build_line_list())
+ self.assertEqual(["this", "is", "an,", "irregular", "line"], results)
+
+ @mock.patch("wqflask.marker_regression.plink_mapping.flat_files")
+ def test_get_samples_from_ped_file(self, mock_flat_files):
+ """test for getting samples from ped file"""
+ dataset = AttributeSetter({"group": AttributeSetter({"name": "n_1"})})
+ file_sample = """Expected_1\tline test
+Expected_2\there
+ Expected_3\tthree"""
+ mock_flat_files.return_value = "/home/user/"
+ with mock.patch("builtins.open", mock.mock_open(read_data=file_sample)) as mock_open:
+ results = get_samples_from_ped_file(dataset)
+ mock_flat_files.assert_called_once_with("mapping")
+ mock_open.assert_called_once_with("/home/user/n_1.ped", "r")
+ self.assertEqual(
+ ["Expected_1", "Expected_2", "Expected_3"], results)
+
+ @mock.patch("wqflask.marker_regression.plink_mapping.TMPDIR", "/home/user/data/")
+ @mock.patch("wqflask.marker_regression.plink_mapping.get_samples_from_ped_file")
+ def test_gen_pheno_txt_file_plink(self, mock_samples):
+ """test for getting gen_pheno txt file"""
+ mock_samples.return_value = ["Expected_1", "Expected_2", "Expected_3"]
+
+ trait = AttributeSetter({"name": "TX"})
+ dataset = AttributeSetter({"group": AttributeSetter({"name": "n_1"})})
+ vals = ["value=K1", "value=K2", "value=K3"]
+ with mock.patch("builtins.open", mock.mock_open()) as mock_open:
+ results = gen_pheno_txt_file_plink(this_trait=trait, dataset=dataset,
+ vals=vals, pheno_filename="ph_file")
+ mock_open.assert_called_once_with(
+ "/home/user/data/ph_file.txt", "wb")
+ filehandler = mock_open()
+ calls_expected = [mock.call('FID\tIID\tTX\n'),
+ mock.call('Expected_1\tExpected_1\tK1\nExpected_2\tExpected_2\tK2\nExpected_3\tExpected_3\tK3\n')]
+
+ filehandler.write.assert_has_calls(calls_expected)
+
+ filehandler.close.assert_called_once()
+
+ @mock.patch("wqflask.marker_regression.plink_mapping.TMPDIR", "/home/user/data/")
+ @mock.patch("wqflask.marker_regression.plink_mapping.build_line_list")
+ def test_parse_plink_output(self, mock_line_list):
+ """test for parsing plink output"""
+ chromosomes = [0, 34, 110, 89, 123, 23, 2]
+ species = AttributeSetter(
+ {"name": "S1", "chromosomes": AttributeSetter({"chromosomes": chromosomes})})
+
+ fake_file = """0 AACCAT T98.6 0.89\n2 AATA B45 0.3\n121 ACG B56.4 NA"""
+
+ mock_line_list.side_effect = [["0", "AACCAT", "T98.6", "0.89"], [
+ "2", "AATA", "B45", "0.3"], ["121", "ACG", "B56.4", "NA"]]
+ with mock.patch("builtins.open", mock.mock_open(read_data=fake_file)) as mock_open:
+ parse_results = parse_plink_output(
+ output_filename="P1_file", species=species)
+ mock_open.assert_called_once_with(
+ "/home/user/data/P1_file.qassoc", "rb")
+ expected = (2, {'AACCAT': 0.89, 'AATA': 0.3})
+
+ self.assertEqual(parse_results, expected)
diff --git a/gn2/tests/unit/wqflask/marker_regression/test_qtlreaper_mapping.py b/gn2/tests/unit/wqflask/marker_regression/test_qtlreaper_mapping.py
new file mode 100644
index 00000000..2268f4cb
--- /dev/null
+++ b/gn2/tests/unit/wqflask/marker_regression/test_qtlreaper_mapping.py
@@ -0,0 +1,24 @@
+import unittest
+from unittest import mock
+from gn2.wqflask.marker_regression.qtlreaper_mapping import gen_pheno_txt_file
+
+# issues some methods in genofile object are not defined
+# modify samples should equal to vals
+
+
+class TestQtlReaperMapping(unittest.TestCase):
+ @mock.patch("wqflask.marker_regression.qtlreaper_mapping.TEMPDIR", "/home/user/data")
+ def test_gen_pheno_txt_file(self):
+ vals = ["V1", "x", "V4", "V3", "x"]
+ samples = ["S1", "S2", "S3", "S4", "S5"]
+ trait_filename = "trait_file"
+ with mock.patch("builtins.open", mock.mock_open())as mock_open:
+ gen_pheno_txt_file(samples=samples, vals=vals,
+ trait_filename=trait_filename)
+ mock_open.assert_called_once_with(
+ "/home/user/data/gn2/trait_file.txt", "w")
+ filehandler = mock_open()
+ write_calls = [mock.call('Trait\t'), mock.call(
+ 'S1\tS3\tS4\n'), mock.call('T1\t'), mock.call('V1\tV4\tV3')]
+
+ filehandler.write.assert_has_calls(write_calls)
diff --git a/gn2/tests/unit/wqflask/marker_regression/test_rqtl_mapping.py b/gn2/tests/unit/wqflask/marker_regression/test_rqtl_mapping.py
new file mode 100644
index 00000000..5cfce28c
--- /dev/null
+++ b/gn2/tests/unit/wqflask/marker_regression/test_rqtl_mapping.py
@@ -0,0 +1,43 @@
+import unittest
+from unittest import mock
+from dataclasses import dataclass
+
+from gn2.wqflask.marker_regression.rqtl_mapping import run_rqtl
+
+@dataclass
+class MockGroup:
+ name: str
+ genofile: str
+
+@dataclass
+class MockDataset:
+ group: MockGroup
+
+class TestRqtlMapping(unittest.TestCase):
+ """Tests for functions in rqtl_mapping.py"""
+ @mock.patch("wqflask.marker_regression.rqtl_mapping.requests.post")
+ @mock.patch("wqflask.marker_regression.rqtl_mapping.locate")
+ @mock.patch("wqflask.marker_regression.rqtl_mapping.write_phenotype_file")
+ def test_run_rqtl_with_perm(self, mock_write_pheno_file, mock_locate, mock_post):
+ """Test for run_rqtl with permutations > 0"""
+ dataset_group = MockGroup("GP1", "file_geno")
+ dataset = MockDataset(dataset_group)
+
+ mock_write_pheno_file.return_value = "pheno_filename"
+ mock_locate.return_value = "geno_filename"
+ mock_post.return_value = mock.Mock(ok=True)
+ mock_post.return_value.json.return_value = {"perm_results": [],
+ "suggestive": 3,
+ "significant": 4,
+ "results" : []}
+
+ results = run_rqtl(trait_name="the_trait", vals=[], samples=[],
+ dataset=dataset, pair_scan=False, mapping_scale="cM", model="normal", method="hk",
+ num_perm=5, perm_strata_list=[], do_control="false", control_marker="",
+ manhattan_plot=True, cofactors="")
+
+ mock_write_pheno_file.assert_called_once()
+ mock_locate.assert_called_once()
+ mock_post.assert_called_once()
+
+ self.assertEqual(results, ([], 3, 4, []))
diff --git a/gn2/tests/unit/wqflask/marker_regression/test_run_mapping.py b/gn2/tests/unit/wqflask/marker_regression/test_run_mapping.py
new file mode 100644
index 00000000..dd67ce49
--- /dev/null
+++ b/gn2/tests/unit/wqflask/marker_regression/test_run_mapping.py
@@ -0,0 +1,288 @@
+import unittest
+import datetime
+from unittest import mock
+
+from gn2.wqflask.marker_regression.run_mapping import get_genofile_samplelist
+from gn2.wqflask.marker_regression.run_mapping import geno_db_exists
+from gn2.wqflask.marker_regression.run_mapping import write_input_for_browser
+from gn2.wqflask.marker_regression.run_mapping import export_mapping_results
+from gn2.wqflask.marker_regression.run_mapping import trim_markers_for_figure
+from gn2.wqflask.marker_regression.run_mapping import get_perm_strata
+from gn2.wqflask.marker_regression.run_mapping import get_chr_lengths
+
+
+class AttributeSetter:
+ def __init__(self, obj):
+ for k, v in obj.items():
+ setattr(self, k, v)
+
+
+class MockGroup(AttributeSetter):
+
+ def get_genofiles(self):
+ return [{"location": "~/genofiles/g1_file", "sample_list": ["S1", "S2", "S3", "S4"]}]
+
+
+class TestRunMapping(unittest.TestCase):
+ def setUp(self):
+
+ self.group = MockGroup(
+ {"genofile": "~/genofiles/g1_file", "name": "GP1_", "species": "Human"})
+ chromosomes = {
+ "3": AttributeSetter({
+ "name": "C1",
+ "length": "0.04"
+ }),
+ "4": AttributeSetter({
+ "name": "C2",
+ "length": "0.03"
+ }),
+ "5": AttributeSetter({
+ "name": "C4",
+ "length": "0.01"
+ })
+ }
+ self.dataset = AttributeSetter(
+ {"fullname": "dataset_1", "group": self.group, "type": "ProbeSet"})
+
+ self.chromosomes = AttributeSetter({"chromosomes": lambda cur: chromosomes})
+ self.trait = AttributeSetter(
+ {"symbol": "IGFI", "chr": "X1", "mb": 123313, "display_name": "Test Name"})
+
+ def tearDown(self):
+ self.dataset = AttributeSetter(
+ {"group": {"location": "~/genofiles/g1_file"}})
+
+ def test_get_genofile_samplelist(self):
+
+ results_1 = get_genofile_samplelist(self.dataset)
+ self.assertEqual(results_1, ["S1", "S2", "S3", "S4"])
+ self.group.genofile = "~/genofiles/g2_file"
+ result_2 = get_genofile_samplelist(self.dataset)
+ self.assertEqual(result_2, [])
+
+ @mock.patch("wqflask.marker_regression.run_mapping.data_set")
+ def test_if_geno_db_exists(self, mock_data_set):
+ mock_data_set.create_dataset.side_effect = [
+ AttributeSetter({}), Exception()]
+ results_no_error = geno_db_exists(self.dataset)
+ results_with_error = geno_db_exists(self.dataset)
+
+ self.assertEqual(mock_data_set.create_dataset.call_count, 2)
+ self.assertEqual(results_with_error, "False")
+ self.assertEqual(results_no_error, "True")
+
+ def test_trim_markers_for_figure(self):
+
+ markers = [{
+ "name": "MK1",
+ "chr": "C1",
+ "cM": "1",
+ "Mb": "12000",
+ "genotypes": [],
+ "dominance":"TT",
+ "additive":"VA",
+ "lod_score":0.5
+ },
+ {
+ "name": "MK2",
+ "chr": "C2",
+ "cM": "15",
+ "Mb": "10000",
+ "genotypes": [],
+ "lod_score":0.7
+ },
+ {
+ "name": "MK1",
+ "chr": "C3",
+ "cM": "45",
+ "Mb": "1",
+ "genotypes": [],
+ "dominance":"Tt",
+ "additive":"VE",
+ "lod_score":1
+ }]
+
+ marker_2 = [{
+ "name": "MK1",
+ "chr": "C1",
+ "cM": "1",
+ "Mb": "12000",
+ "genotypes": [],
+ "dominance":"TT",
+ "additive":"VA",
+ "p_wald":4.6
+ }]
+ results = trim_markers_for_figure(markers)
+ result_2 = trim_markers_for_figure(marker_2)
+ expected = [
+ {
+ "name": "MK1",
+ "chr": "C1",
+ "cM": "1",
+ "Mb": "12000",
+ "genotypes": [],
+ "dominance":"TT",
+ "additive":"VA",
+ "lod_score":0.5
+ },
+ {
+ "name": "MK1",
+ "chr": "C3",
+ "cM": "45",
+ "Mb": "1",
+ "genotypes": [],
+ "dominance":"Tt",
+ "additive":"VE",
+ "lod_score":1
+ }
+
+ ]
+ self.assertEqual(results, expected)
+ self.assertEqual(result_2, marker_2)
+
+ def test_export_mapping_results(self):
+ """test for exporting mapping results"""
+ datetime_mock = mock.Mock(wraps=datetime.datetime)
+ datetime_mock.now.return_value = datetime.datetime(
+ 2019, 9, 1, 10, 12, 12)
+
+ markers = [{
+ "name": "MK1",
+ "chr": "C1",
+ "cM": "1",
+ "Mb": "12000",
+ "genotypes": [],
+ "dominance":"TT",
+ "additive":"VA",
+ "lod_score":3
+ },
+ {
+ "name": "MK2",
+ "chr": "C2",
+ "cM": "15",
+ "Mb": "10000",
+ "genotypes": [],
+ "lod_score":7
+ },
+ {
+ "name": "MK1",
+ "chr": "C3",
+ "cM": "45",
+ "Mb": "1",
+ "genotypes": [],
+ "dominance":"Tt",
+ "additive":"VE",
+ "lod_score":7
+ }]
+
+ with mock.patch("builtins.open", mock.mock_open()) as mock_open:
+
+ with mock.patch("wqflask.marker_regression.run_mapping.datetime.datetime", new=datetime_mock):
+ export_mapping_results(dataset=self.dataset, trait=self.trait, markers=markers,
+ results_path="~/results", mapping_method="gemma", mapping_scale="physic",
+ score_type="-logP", transform="qnorm",
+ covariates="Dataset1:Trait1,Dataset2:Trait2",
+ n_samples="100", vals_hash="")
+
+ write_calls = [
+ mock.call('Time/Date: 09/01/19 / 10:12:12\n'),
+ mock.call('Population: Human GP1_\n'), mock.call(
+ 'Data Set: dataset_1\n'),
+ mock.call('Trait: Test Name\n'),
+ mock.call('Trait Hash: \n'),
+ mock.call('N Samples: 100\n'),
+ mock.call('Mapping Tool: gemma\n'),
+ mock.call('Transform - Quantile Normalized\n'),
+ mock.call('Gene Symbol: IGFI\n'), mock.call(
+ 'Location: X1 @ 123313 Mb\n'),
+ mock.call('Cofactors (dataset - trait):\n'),
+ mock.call('Trait1 - Dataset1\n'),
+ mock.call('Trait2 - Dataset2\n'),
+ mock.call('\n'), mock.call('Name,Chr,'),
+ mock.call('Mb,-logP'),
+ mock.call(',Additive'), mock.call(',Dominance'),
+ mock.call('\n'), mock.call('MK1,C1,'),
+ mock.call('12000,'), mock.call('3'),
+ mock.call(',VA'), mock.call(',TT'),
+ mock.call('\n'), mock.call('MK2,C2,'),
+ mock.call('10000,'), mock.call('7'),
+ mock.call('\n'), mock.call('MK1,C3,'),
+ mock.call('1,'), mock.call('7'),
+ mock.call(',VE'), mock.call(',Tt')
+ ]
+ mock_open.assert_called_once_with("~/results", "w+")
+ filehandler = mock_open()
+ filehandler.write.assert_has_calls(write_calls)
+
+ @mock.patch("wqflask.marker_regression.run_mapping.random.choice")
+ def test_write_input_for_browser(self, mock_choice):
+ """test for writing input for browser"""
+ mock_choice.side_effect = ["F", "i", "l", "e", "s", "x"]
+ with mock.patch("builtins.open", mock.mock_open()) as mock_open:
+ expected = ['GP1__Filesx_GWAS', 'GP1__Filesx_ANNOT']
+
+ results = write_input_for_browser(
+ this_dataset=self.dataset, gwas_results={}, annotations={})
+ self.assertEqual(results, expected)
+
+ def test_get_perm_strata(self):
+ categorical_vars = ["C1", "C2", "W1"]
+ used_samples = ["S1", "S2"]
+ sample_list = AttributeSetter({"sample_attribute_values": {
+ "S1": {
+ "c1": "c1_value",
+ "c2": "c2_value",
+ "w1": "w1_value"
+ },
+ "S2": {
+ "w1": "w2_value",
+ "w2": "w2_value"
+ },
+ "S3": {
+
+ "c1": "c1_value",
+ "c2": "c2_value"
+ },
+ }})
+ results = get_perm_strata(this_trait={}, sample_list=sample_list,
+ categorical_vars=categorical_vars, used_samples=used_samples)
+ self.assertEqual(results, [1, 1])
+
+ def test_get_chr_length(self):
+ """test for getting chromosome length"""
+ cursor = mock.MagicMock()
+ chromosomes = AttributeSetter({"chromosomes": self.chromosomes})
+ dataset = AttributeSetter({"species": chromosomes})
+ results = get_chr_lengths(
+ mapping_scale="physic", mapping_method="reaper", dataset=dataset, qtl_results=[])
+ chr_lengths = []
+ for key, chromo in self.chromosomes.chromosomes(cursor).items():
+ chr_lengths.append({"chr": chromo.name, "size": chromo.length})
+
+ self.assertEqual(chr_lengths, results)
+
+ qtl_results = [{
+ "chr": "16",
+ "cM": "0.2"
+ },
+ {
+ "chr": "12",
+ "cM": "0.5"
+ },
+ {
+ "chr": "18",
+ "cM": "0.1"
+ },
+ {
+ "chr": "22",
+ "cM": "0.4"
+ },
+ ]
+
+ result_with_other_mapping_scale = get_chr_lengths(
+ mapping_scale="other", mapping_method="reaper", dataset=dataset, qtl_results=qtl_results)
+ expected_value = [{'chr': '1', 'size': '0'}, {
+ 'chr': '16', 'size': '500000.0'}, {'chr': '18', 'size': '400000.0'}]
+
+ self.assertEqual(result_with_other_mapping_scale, expected_value)
diff --git a/gn2/tests/unit/wqflask/show_trait/__init__.py b/gn2/tests/unit/wqflask/show_trait/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/gn2/tests/unit/wqflask/show_trait/__init__.py
diff --git a/gn2/tests/unit/wqflask/show_trait/test_export_trait_data.py b/gn2/tests/unit/wqflask/show_trait/test_export_trait_data.py
new file mode 100644
index 00000000..a933d0bf
--- /dev/null
+++ b/gn2/tests/unit/wqflask/show_trait/test_export_trait_data.py
@@ -0,0 +1,151 @@
+import datetime
+import unittest
+from unittest import mock
+from gn2.wqflask.show_trait.export_trait_data import dict_to_sorted_list
+from gn2.wqflask.show_trait.export_trait_data import cmp_samples
+from gn2.wqflask.show_trait.export_trait_data import export_sample_table
+from gn2.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 for exporting traits and metadata"""
+
+ @mock.patch("wqflask.show_trait.export_trait_data.datetime")
+ @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(self, data_mock, trait_mock, date_mock):
+ """test for exporting metadata with dataset.type=Publish"""
+ mock_dataset = AttributesSetter({"type": "Publish",
+ "name": "HC_M2_0606_P",
+ "dataset_name": "HC_M2_0606_P"})
+
+ mock_dataset.group = AttributesSetter({"name": "C"})
+ data_mock.create_dataset.return_value = mock_dataset
+
+ trait_data = {
+ "symbol": "Nr3c1",
+ "description_display": "nuclear receptor subfamily 3,group C, member 1 (glucocorticoid receptor); distal 3' UTR",
+ "title": "Trait_1 title",
+
+ "authors": "XL_1",
+ "journal": ""
+
+ }
+
+ date_mock.datetime.now.return_value = datetime.datetime(
+ 2022, 8, 8, 19, 2, 31, 628813)
+ trait_mock.return_value = AttributesSetter(trait_data)
+
+ results = get_export_metadata({
+ "trait_id": "1460303_at",
+ "trait_display_name": "1460303_at",
+ "dataset": "HC_M2_0606_P",
+ "group": "BXD",
+ })
+
+ expected = [["Phenotype ID:", "1460303_at"],
+ ["Phenotype URL: ", "http://genenetwork.org/show_trait?trait_id=1460303_at&dataset=HC_M2_0606_P"],
+ ["Group: ", "C"],
+ ["Phenotype: ",
+ 'nuclear receptor subfamily 3","group C"," member 1 (glucocorticoid receptor); distal 3\' UTR'],
+ ["Authors: ", "XL_1"],
+ ["Title: ", "Trait_1 title"],
+ ["Journal: ", "N/A"],
+ ["Dataset Link: ", "http://gn1.genenetwork.org/webqtl/main.py?FormID=sharinginfo&InfoPageName=HC_M2_0606_P"],
+ ["Export Date: ", "August 08, 2022"],
+ ["Export Time: ", "19:02 GMT"]]
+
+ self.assertEqual(results, expected)
+
+ 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/gn2/tests/unit/wqflask/show_trait/test_get_max_digits.py b/gn2/tests/unit/wqflask/show_trait/test_get_max_digits.py
new file mode 100644
index 00000000..45484f17
--- /dev/null
+++ b/gn2/tests/unit/wqflask/show_trait/test_get_max_digits.py
@@ -0,0 +1,15 @@
+import pytest
+import unittest
+
+from gn2.wqflask.show_trait.show_trait import get_max_digits
+
+@unittest.skip("Too complicated")
+@pytest.mark.parametrize(
+ "trait_vals,expected",
+ (((
+ (0, 1345, 92, 734),
+ (234253, 33, 153, 5352),
+ (3542, 24, 135)),
+ [3, 5, 3]),))
+def test_get_max_digits(trait_vals, expected):
+ assert get_max_digits(trait_vals) == expected
diff --git a/gn2/tests/unit/wqflask/snp_browser/__init__.py b/gn2/tests/unit/wqflask/snp_browser/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/gn2/tests/unit/wqflask/snp_browser/__init__.py
diff --git a/gn2/tests/unit/wqflask/snp_browser/test_snp_browser.py b/gn2/tests/unit/wqflask/snp_browser/test_snp_browser.py
new file mode 100644
index 00000000..c33f46ef
--- /dev/null
+++ b/gn2/tests/unit/wqflask/snp_browser/test_snp_browser.py
@@ -0,0 +1,206 @@
+import unittest
+from unittest import mock
+from gn2.wqflask import app
+from gn2.wqflask.snp_browser.snp_browser import get_gene_id
+from gn2.wqflask.snp_browser.snp_browser import get_gene_id_name_dict
+from gn2.wqflask.snp_browser.snp_browser import check_if_in_gene
+from gn2.wqflask.snp_browser.snp_browser import get_browser_sample_lists
+from gn2.wqflask.snp_browser.snp_browser import get_header_list
+
+
+class TestSnpBrowser(unittest.TestCase):
+ def setUp(self):
+ self.app_context = app.app_context()
+ self.app_context.push()
+
+ def tearDown(self):
+ self.app_context.pop()
+
+ def test_get_header_list(self):
+ empty_columns = {
+ "snp_source": "false",
+ "conservation_score": "true",
+ "gene_name": "false",
+ "transcript": "false",
+ "exon": "false",
+ "domain_2": "true",
+ "function": "false",
+ "function_details": "true",
+ }
+ strains = {"mouse": ["S1", "S2", "S3", "S4", "S5"], "rat": []}
+ expected_results = (
+ [
+ [
+ "Index",
+ "SNP ID",
+ "Chr",
+ "Mb",
+ "Alleles",
+ "ConScore",
+ "Domain 1",
+ "Domain 2",
+ "Details",
+ ],
+ ["S1", "S2", "S3", "S4", "S5"],
+ ],
+ 5,
+ [
+ "index",
+ "snp_name",
+ "chr",
+ "mb_formatted",
+ "alleles",
+ "conservation_score",
+ "domain_1",
+ "domain_2",
+ "function_details",
+ "S1",
+ "S2",
+ "S3",
+ "S4",
+ "S5",
+ ],
+ )
+
+ results_with_snp = get_header_list(
+ variant_type="SNP",
+ strains=strains,
+ species="Mouse",
+ empty_columns=empty_columns,
+ )
+ results_with_indel = get_header_list(
+ variant_type="InDel", strains=strains, species="rat", empty_columns=[]
+ )
+ expected_results_with_indel = (
+ [
+ "Index",
+ "ID",
+ "Type",
+ "InDel Chr",
+ "Mb Start",
+ "Mb End",
+ "Strand",
+ "Size",
+ "Sequence",
+ "Source",
+ ],
+ 0,
+ [
+ "index",
+ "indel_name",
+ "indel_type",
+ "indel_chr",
+ "indel_mb_s",
+ "indel_mb_e",
+ "indel_strand",
+ "indel_size",
+ "indel_sequence",
+ "source_name",
+ ],
+ )
+
+ self.assertEqual(expected_results, results_with_snp)
+ self.assertEqual(expected_results_with_indel, results_with_indel)
+
+ @mock.patch("wqflask.snp_browser.snp_browser.database_connection")
+ def test_get_gene_id(self, mock_db):
+ db_query_value = (
+ "SELECT geneId FROM GeneList WHERE " "SpeciesId = %s AND geneSymbol = %s"
+ )
+ conn = mock.MagicMock()
+ mock_db.return_value.__enter__.return_value = conn
+ with conn.cursor() as cursor:
+ cursor.fetchone.return_value = (
+ ("517d729f-aa13-4413" "-a885-40a3f7ff768a"),
+ )
+
+ results = get_gene_id(
+ species_id="c9c0f59e-1259-4cba-91e6-831ef1a99c83", gene_name="INSR"
+ )
+ cursor.execute.assert_called_once_with(
+ db_query_value, ("c9c0f59e-1259-4cba-91e6-831ef1a99c83", "INSR")
+ )
+ self.assertEqual(results, "517d729f-aa13-4413-a885-40a3f7ff768a")
+
+ @mock.patch("wqflask.snp_browser.snp_browser.database_connection")
+ def test_gene_id_name_dict(self, mock_db):
+ no_gene_names = []
+ conn = mock.MagicMock()
+ mock_db.return_value.__enter__.return_value = conn
+ with conn.cursor() as cursor:
+ cursor.fetchall.side_effect = [
+ [],
+ [
+ ("fsdf43-fseferger-f22", "GH1"),
+ ("1sdf43-fsewferger-f22", "GH2"),
+ ("fwdj43-fstferger-f22", "GH3"),
+ ],
+ ]
+ self.assertEqual(
+ "",
+ get_gene_id_name_dict(
+ species_id="fregb343bui43g4", gene_name_list=no_gene_names
+ ),
+ )
+ gene_name_list = ["GH1", "GH2", "GH3"]
+ no_results = get_gene_id_name_dict(
+ species_id="ret3-32rf32", gene_name_list=gene_name_list
+ )
+ results_found = get_gene_id_name_dict(
+ species_id="ret3-32rf32", gene_name_list=gene_name_list
+ )
+ expected_found = {
+ "GH1": "fsdf43-fseferger-f22",
+ "GH2": "1sdf43-fsewferger-f22",
+ "GH3": "fwdj43-fstferger-f22",
+ }
+ db_query_value = (
+ "SELECT geneId, geneSymbol FROM GeneList WHERE "
+ "SpeciesId = %s AND geneSymbol in (%s, %s, %s)"
+ )
+ cursor.execute.assert_called_with(
+ db_query_value, ("ret3-32rf32", "GH1", "GH2", "GH3")
+ )
+ self.assertEqual(results_found, expected_found)
+ self.assertEqual(no_results, {})
+
+ @mock.patch("wqflask.snp_browser.snp_browser.database_connection")
+ def test_check_if_in_gene(self, mock_db):
+ conn = mock.MagicMock()
+ mock_db.return_value.__enter__.return_value = conn
+ with conn.cursor() as cursor:
+ cursor.fetchone.side_effect = [("fsdf-232sdf-sdf", "GHA"), ""]
+ results_found = check_if_in_gene(
+ species_id="517d729f-aa13-4413-a885-40a3f7ff768a", chr_="CH1", mb=12.09
+ )
+ self.assertEqual(results_found, ["fsdf-232sdf-sdf", "GHA"])
+ db_query_value = (
+ "SELECT geneId, geneSymbol FROM GeneList "
+ "WHERE SpeciesId = %s AND chromosome = %s "
+ "AND (txStart < %s AND txEnd > %s)"
+ )
+ gene_not_found = check_if_in_gene(
+ species_id="517d729f-aa13-4413-a885-40a3f7ff768a", chr_="CH1", mb=12.09
+ )
+ cursor.execute.assert_has_calls(
+ [
+ mock.call(
+ db_query_value,
+ ("517d729f-aa13-4413-a885-40a3f7ff768a", "CH1", 12.09, 12.09),
+ ),
+ mock.call(
+ db_query_value,
+ ("517d729f-aa13-4413-a885-40a3f7ff768a", "CH1", 12.09, 12.09),
+ ),
+ ]
+ )
+ self.assertEqual(gene_not_found, "")
+
+ @mock.patch("wqflask.snp_browser.snp_browser.database_connection")
+ def test_get_browser_sample_lists(self, mock_db):
+ conn = mock.MagicMock()
+ mock_db.return_value.__enter__.return_value = conn
+ with conn.cursor() as cursor:
+ cursor.execute.return_value.fetchall.return_value = []
+ results = get_browser_sample_lists(species_id="12")
+ self.assertEqual(results, {"mouse": [], "rat": []})
diff --git a/gn2/tests/unit/wqflask/test_collect.py b/gn2/tests/unit/wqflask/test_collect.py
new file mode 100644
index 00000000..41d6bf74
--- /dev/null
+++ b/gn2/tests/unit/wqflask/test_collect.py
@@ -0,0 +1,75 @@
+"""Test cases for some methods in collect.py"""
+
+import unittest
+from unittest import mock
+
+from flask import Flask
+from gn2.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(sorted(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')),
+ sorted(['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(sorted(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')),
+ sorted(['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/gn2/tests/unit/wqflask/test_pbkdf2.py b/gn2/tests/unit/wqflask/test_pbkdf2.py
new file mode 100644
index 00000000..ed4eff4f
--- /dev/null
+++ b/gn2/tests/unit/wqflask/test_pbkdf2.py
@@ -0,0 +1,61 @@
+"""Test cases pbkdf2"""
+
+import unittest
+from gn2.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', b'salt', 1, 20,
+ '0c60c80f961f0e71f3a9b524af6012062fe037a6'),
+ ('password', b'salt', 2, 20,
+ 'ea6c014dc72d6f8ccd1ed92ace1d41f0d8de8957'),
+ ('password', b'salt', 4096, 20,
+ '4b007901b765489abead49d926f721d065a429c1'),
+ ('passwordPASSWORDpassword',
+ b'saltSALTsaltSALTsaltSALTsaltSALTsalt',
+ 4096, 25,
+ '3d2eec4fe41c849b80c8d83662c0e44a8b291a964cf2f07038'),
+ ('pass\x00word', b'sa\x00lt', 4096, 16,
+ '56fa6aa75548099dcc37d7f03425e0c3'),
+ ('password', b'ATHENA.MIT.EDUraeburn', 1, 16,
+ 'cdedb5281bb2f801565a1122b2563515'),
+ ('password', b'ATHENA.MIT.EDUraeburn', 1, 32,
+ ('cdedb5281bb2f80'
+ '1565a1122b256351'
+ '50ad1f7a04bb9f3a33'
+ '3ecc0e2e1f70837')),
+ ('password', b'ATHENA.MIT.EDUraeburn', 2, 16,
+ '01dbee7f4a9e243e988b62c73cda935d'),
+ ('password', b'ATHENA.MIT.EDUraeburn', 2, 32,
+ ('01dbee7f4a9e243e9'
+ '88b62c73cda935da05'
+ '378b93244ec8f48a99'
+ 'e61ad799d86')),
+ ('password', b'ATHENA.MIT.EDUraeburn', 1200, 32,
+ ('5c08eb61fdf71e'
+ '4e4ec3cf6ba1f55'
+ '12ba7e52ddbc5e51'
+ '42f708a31e2e62b1e13')),
+ ('X' * 64, b'pass phrase equals block size', 1200, 32,
+ ('139c30c0966bc32ba'
+ '55fdbf212530ac9c5'
+ 'ec59f1a452f5cc9ad'
+ '940fea0598ed1')),
+ ('X' * 65, b'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/gn2/tests/unit/wqflask/test_resource_manager.py b/gn2/tests/unit/wqflask/test_resource_manager.py
new file mode 100644
index 00000000..f4335425
--- /dev/null
+++ b/gn2/tests/unit/wqflask/test_resource_manager.py
@@ -0,0 +1,94 @@
+"""Test cases for wqflask/resource_manager.py"""
+import json
+import unittest
+
+from unittest import mock
+from gn3.authentication import get_user_membership
+from gn3.authentication import get_highest_user_access_role
+from gn3.authentication import DataRole
+from gn3.authentication import AdminRole
+
+
+class TestGetUserMembership(unittest.TestCase):
+ """Test cases for `get_user_membership`"""
+
+ def setUp(self):
+ conn = mock.MagicMock()
+ conn.hgetall.return_value = {
+ '7fa95d07-0e2d-4bc5-b47c-448fdc1260b2': (
+ '{"name": "editors", '
+ '"admins": ["8ad942fe-490d-453e-bd37-56f252e41604", "rand"], '
+ '"members": ["8ad942fe-490d-453e-bd37-56f252e41603", '
+ '"rand"], '
+ '"changed_timestamp": "Oct 06 2021 06:39PM", '
+ '"created_timestamp": "Oct 06 2021 06:39PM"}')}
+ self.conn = conn
+
+ def test_user_is_group_member_only(self):
+ """Test that a user is only a group member"""
+ self.assertEqual(
+ get_user_membership(
+ conn=self.conn,
+ user_id="8ad942fe-490d-453e-bd37-56f252e41603",
+ group_id="7fa95d07-0e2d-4bc5-b47c-448fdc1260b2"),
+ {"member": True,
+ "admin": False})
+
+ def test_user_is_group_admin_only(self):
+ """Test that a user is a group admin only"""
+ self.assertEqual(
+ get_user_membership(
+ conn=self.conn,
+ user_id="8ad942fe-490d-453e-bd37-56f252e41604",
+ group_id="7fa95d07-0e2d-4bc5-b47c-448fdc1260b2"),
+ {"member": False,
+ "admin": True})
+
+ def test_user_is_both_group_member_and_admin(self):
+ """Test that a user is both an admin and member of a group"""
+ self.assertEqual(
+ get_user_membership(
+ conn=self.conn,
+ user_id="rand",
+ group_id="7fa95d07-0e2d-4bc5-b47c-448fdc1260b2"),
+ {"member": True,
+ "admin": True})
+
+
+class TestCheckUserAccessRole(unittest.TestCase):
+ """Test cases for `get_highest_user_access_role`"""
+
+ @mock.patch("wqflask.resource_manager.requests.get")
+ def test_edit_access(self, requests_mock):
+ """Test that the right access roles are set"""
+ response = mock.PropertyMock(return_value=json.dumps(
+ {
+ 'data': ['no-access', 'view', 'edit', ],
+ 'metadata': ['no-access', 'view', 'edit', ],
+ 'admin': ['not-admin', 'edit-access', ],
+ }
+ ))
+ type(requests_mock.return_value).content = response
+ self.assertEqual(get_highest_user_access_role(
+ resource_id="0196d92e1665091f202f",
+ user_id="8ad942fe-490d-453e-bd37"),
+ {"data": DataRole.EDIT,
+ "metadata": DataRole.EDIT,
+ "admin": AdminRole.EDIT_ACCESS})
+
+ @mock.patch("wqflask.resource_manager.requests.get")
+ def test_no_access(self, requests_mock):
+ response = mock.PropertyMock(return_value=json.dumps(
+ {
+ 'data': ['no-access', ],
+ 'metadata': ['no-access', ],
+ 'admin': ['not-admin', ],
+ }
+ ))
+ type(requests_mock.return_value).content = response
+ self.assertEqual(get_highest_user_access_role(
+ resource_id="0196d92e1665091f202f",
+ user_id=""),
+ {"data": DataRole.NO_ACCESS,
+ "metadata": DataRole.NO_ACCESS,
+ "admin": AdminRole.NOT_ADMIN})
diff --git a/gn2/tests/unit/wqflask/test_server_side.py b/gn2/tests/unit/wqflask/test_server_side.py
new file mode 100644
index 00000000..b3e90eb9
--- /dev/null
+++ b/gn2/tests/unit/wqflask/test_server_side.py
@@ -0,0 +1,34 @@
+import unittest
+
+from gn2.wqflask.server_side import ServerSideTable
+
+
+class TestServerSideTableTests(unittest.TestCase):
+ """
+ Test the ServerSideTable class
+
+ test table:
+ first, second, third
+ 'd', 4, 'zz'
+ 'b', 2, 'aa'
+ 'c', 1, 'ss'
+ """
+
+ def test_get_page(self):
+ rows_count = 3
+ table_rows = [
+ {'first': 'd', 'second': 4, 'third': 'zz'},
+ {'first': 'b', 'second': 2, 'third': 'aa'},
+ {'first': 'c', 'second': 1, 'third': 'ss'},
+ ]
+ headers = ['first', 'second', 'third']
+ request_args = {'sEcho': '1', 'iSortCol_0': '1', 'iSortingCols': '1',
+ 'sSortDir_0': 'asc', 'iDisplayStart': '0', 'iDisplayLength': '3'}
+
+ test_page = ServerSideTable(
+ rows_count, table_rows, headers, request_args).get_page()
+ self.assertEqual(test_page['sEcho'], '1')
+ self.assertEqual(test_page['iTotalRecords'], 'nan')
+ self.assertEqual(test_page['iTotalDisplayRecords'], '3')
+ self.assertEqual(test_page['data'], [{'first': 'b', 'second': 2, 'third': 'aa'}, {
+ 'first': 'c', 'second': 1, 'third': 'ss'}, {'first': 'd', 'second': 4, 'third': 'zz'}])
diff --git a/gn2/tests/unit/wqflask/test_user_login.py b/gn2/tests/unit/wqflask/test_user_login.py
new file mode 100644
index 00000000..84e25d45
--- /dev/null
+++ b/gn2/tests/unit/wqflask/test_user_login.py
@@ -0,0 +1,21 @@
+"""Test cases for some methods in login.py"""
+
+import unittest
+from gn2.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/gn2/tests/unit/wqflask/test_user_session.py b/gn2/tests/unit/wqflask/test_user_session.py
new file mode 100644
index 00000000..944e5b6a
--- /dev/null
+++ b/gn2/tests/unit/wqflask/test_user_session.py
@@ -0,0 +1,15 @@
+"""Test cases for some methods in user_session.py"""
+
+import unittest
+from gn2.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")))
diff --git a/gn2/tests/unit/wqflask/wgcna/__init__.py b/gn2/tests/unit/wqflask/wgcna/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/gn2/tests/unit/wqflask/wgcna/__init__.py
diff --git a/gn2/tests/unit/wqflask/wgcna/test_wgcna.py b/gn2/tests/unit/wqflask/wgcna/test_wgcna.py
new file mode 100644
index 00000000..2ed5e08f
--- /dev/null
+++ b/gn2/tests/unit/wqflask/wgcna/test_wgcna.py
@@ -0,0 +1,50 @@
+
+"""module contains for processing gn3 wgcna data"""
+from unittest import TestCase
+
+from gn2.wqflask.wgcna.gn3_wgcna import process_wgcna_data
+
+
+class DataProcessingTests(TestCase):
+ """class contains data processing tests"""
+
+ def test_data_processing(self):
+ """test for parsing data for datatable"""
+ output = {
+ "input": {
+ "sample_names": ["BXD1", "BXD2", "BXD3", "BXD4", "BXD5", "BXD6"],
+
+ },
+ "output": {
+ "ModEigens": {
+ "MEturquoise": [
+ 0.0646677768085351,
+ 0.137200224277058,
+ 0.63451113720732,
+ -0.544002665501479,
+ -0.489487590361863,
+ 0.197111117570427
+ ],
+ "MEgrey": [
+ 0.213,
+ 0.214,
+ 0.3141,
+ -0.545,
+ -0.423,
+ 0.156,
+ ]
+ }}}
+
+ row_data = [['BXD1', 0.065, 0.213],
+ ['BXD2', 0.137, 0.214],
+ ['BXD3', 0.635, 0.314],
+ ['BXD4', -0.544, -0.545],
+ ['BXD5', -0.489, -0.423],
+ ['BXD6', 0.197, 0.156]]
+
+ expected_results = {
+ "col_names": ["sample_names", "MEturquoise", "MEgrey"],
+ "mod_dataset": row_data
+ }
+
+ self.assertEqual(process_wgcna_data(output), expected_results)
diff --git a/gn2/tests/wqflask/show_trait/testSampleList.py b/gn2/tests/wqflask/show_trait/testSampleList.py
new file mode 100644
index 00000000..1c5478bb
--- /dev/null
+++ b/gn2/tests/wqflask/show_trait/testSampleList.py
@@ -0,0 +1,17 @@
+import unittest
+import re
+from unittest import mock
+from gn2.wqflask.show_trait.SampleList import natural_sort
+
+
+class TestSampleList(unittest.TestCase):
+ def test_natural_sort(self):
+ "Sort the list into natural alphanumeric order."
+
+ characters_list = ["z", "f", "q", "s", "t", "a", "g"]
+ names_list = ["temp1", "publish", "Sample", "Dataset"]
+ sorted_list_a = natural_sort(characters_list)
+ sorted_list_b = natural_sort(names_list)
+ self.assertEqual(sorted_list_a, ["a", "f", "g", "q", "s", "t", "z"])
+ self.assertEqual(
+ sorted_list_b, ["Dataset", "Sample", "publish", "temp1"])
diff --git a/gn2/tests/wqflask/show_trait/test_show_trait.py b/gn2/tests/wqflask/show_trait/test_show_trait.py
new file mode 100644
index 00000000..97618d31
--- /dev/null
+++ b/gn2/tests/wqflask/show_trait/test_show_trait.py
@@ -0,0 +1,255 @@
+"""test for wqflask/show_trait/test_show_trait.py"""
+import unittest
+import pytest
+from unittest import mock
+from gn2.wqflask.show_trait.show_trait import check_if_attr_exists
+from gn2.wqflask.show_trait.show_trait import get_ncbi_summary
+from gn2.wqflask.show_trait.show_trait import has_num_cases
+from gn2.wqflask.show_trait.show_trait import get_table_widths
+from gn2.wqflask.show_trait.show_trait import get_categorical_variables
+from gn2.wqflask.show_trait.show_trait import get_trait_units
+from gn2.wqflask.show_trait.show_trait import get_nearest_marker
+from gn2.wqflask.show_trait.show_trait import get_genotype_scales
+from gn2.wqflask.show_trait.show_trait import get_scales_from_genofile
+
+
+class TraitObject:
+ def __init__(self, obj):
+ self.distinct_values = []
+ self.id = ""
+ for key, value in obj.items():
+ setattr(self, key, value)
+ self.id += str(value)
+
+
+@pytest.mark.parametrize(
+ ('trait', 'id_type', 'expected'),
+ (
+ (TraitObject({"id_type": "id"}), "id_type", True),
+ (TraitObject({"sample_name": ['samp1']}), "id_type", False),
+ (TraitObject({"sample": ""}), "sample", False),
+ (TraitObject({"group": None}), "group", False),
+ (TraitObject({}), "any", False)
+ ),
+)
+def test_check_if_attr_exists(trait, id_type, expected):
+ """"test check_if_attr_exists"""
+ assert check_if_attr_exists(trait, id_type) == expected
+
+
+def test_get_ncbi_summary_request(mocker):
+ trait = TraitObject({"geneid": "id"})
+ mocker.patch("wqflask.show_trait.show_trait.check_if_attr_exists",
+ return_value=True)
+ mock_get = mocker.patch(
+ "wqflask.show_trait.show_trait.requests.get",
+ return_value=TraitObject({"content": """{
+ "result":{
+ "id":{
+ "summary":"this is a summary of the geneid"
+ }
+ }
+ }
+ """}))
+ assert get_ncbi_summary(trait) == "this is a summary of the geneid"
+ mock_get.assert_called_once_with(
+ "http://eutils.ncbi.nlm.nih.gov/entrez/"
+ "eutils/esummary.fcgi?db=gene&id="
+ f"{trait.geneid}&retmode=json"
+ )
+ mock_get.side_effect = Exception("an error occurred")
+ assert get_ncbi_summary(trait) == None
+
+
+class TestTraits(unittest.TestCase):
+ def test_hash_num_cases_is_probeset(self):
+ """test for hash num_cases with dataset.type set to Probeset"""
+ create_dataset = TraitObject({"type": "ProbeSet"})
+ create_trait = TraitObject({"dataset": create_dataset})
+ self.assertFalse(has_num_cases(create_trait))
+
+ def test_hash_num_cases_no_probeset(self):
+ """test for hash num cases with dataset.type not Probeset"""
+ create_dataset = TraitObject({"type": "Temp"})
+ construct_data = {
+ "nm1": TraitObject({"num_cases": False}),
+ "nm2": TraitObject({"num_cases": True}),
+ "nm3": TraitObject({"num_cases": False})
+ }
+ construct_data2 = {
+ "nm1": TraitObject({"num_cases": False}),
+ "nm2": TraitObject({"num_cases": False}),
+ "nm3": TraitObject({"num_cases": False})
+ }
+ create_trait = TraitObject(
+ {"dataset": create_dataset, "data": construct_data})
+ create_trait2 = TraitObject(
+ {"dataset": create_dataset, "data": construct_data2})
+
+ results = has_num_cases(create_trait)
+ self.assertTrue(has_num_cases(create_trait))
+ self.assertFalse(has_num_cases(create_trait2))
+
+ def test_get_table_widths(self):
+ """test for getting table widths"""
+ sample_groups = [TraitObject({'se_exists': True, "attributes": ["attr1", "attr2", "attr3"]}
+ ), TraitObject(
+ {"se_exists": False, "attributes": ["at1", "at2"]
+ })]
+
+ results_with_numcase = get_table_widths(sample_groups, True)
+ result_no_numcase = get_table_widths(sample_groups, False)
+
+ results_one_sample = get_table_widths(
+ [TraitObject({"se_exists": True, "attributes": []})], True)
+ expected_with_numcase = (450, 645)
+ expected_no_numcase = (450, 644)
+ expected_one_sample = (250, 381)
+ self.assertEqual(results_with_numcase, expected_with_numcase)
+ self.assertEqual(result_no_numcase, expected_no_numcase)
+ self.assertEqual(results_one_sample,
+ expected_one_sample)
+
+ def test_get_categorical_variables_no_sample_attributes(self):
+ """test for getting categorical variable names with no samples"""
+ trait = TraitObject({})
+ sample_list = TraitObject({"se_exists": True, "attributes": []})
+ self.assertEqual(get_categorical_variables(trait, sample_list), [])
+
+ def test_get_categorical_variables_with_sample_attributes(self):
+ """test for getting categorical variable names with no samples"""
+ this_trait = TraitObject({"data": {
+ "Gene1": TraitObject({"extra_attributes": {"ex1": "ex1value"}}),
+ "Gene2": TraitObject({"extra_attributes": {"ex2": "ex2value"}}),
+ "Gene3": TraitObject({"extra_attributes": {"ex3": "ex3value"}})
+ }})
+ sample_list = TraitObject({"attributes": {
+ "sample_attribute_1": TraitObject({"name": "ex1"}),
+ "sample_attribute_2": TraitObject({"name": "ex2"}),
+ "sample_attribute_3": TraitObject({"name": "ex3"}),
+ "sample_attribute_4": TraitObject({"name": "not_in_extra_attributes"})
+ }})
+ results = get_categorical_variables(this_trait, sample_list)
+ self.assertEqual(
+ ["ex1", "ex2", "ex3", "not_in_extra_attributes"], results)
+
+ def test_get_trait_units(self):
+ """test for getting trait units"""
+ trait = TraitObject(
+ {"description_fmt": "[this is a description] another test [N/A]"})
+ trait_no_unit_type = TraitObject({"description_fmt": ""})
+ results = get_trait_units(trait)
+ results_no_unit = get_trait_units(trait_no_unit_type)
+ self.assertEqual(results, "this is a descriptionN/A")
+ self.assertEqual(results_no_unit, "value")
+
+ @mock.patch("wqflask.show_trait.show_trait.database_connection")
+ def test_get_nearest_marker(self, mock_db):
+ """test for getting nearest marker with non-empty db"""
+ conn = mock.MagicMock()
+ mock_db.return_value.__enter__.return_value = conn
+ with conn.cursor() as cursor:
+ cursor.fetchall.return_value = [
+ ["Geno1", "Geno2"], ["Geno3"]]
+
+ trait = TraitObject({
+ "locus_chr": "test_chr",
+ "locus_mb": "test_mb"
+ })
+ group_name = TraitObject({"name": "group_name"})
+ this_db = TraitObject({"group": group_name})
+ results_with_item_db = get_nearest_marker(trait, this_db)
+ cursor.execute.assert_called_with(
+ "SELECT Geno.Name FROM Geno, GenoXRef, "
+ "GenoFreeze WHERE Geno.Chr = %s "
+ "AND GenoXRef.GenoId = Geno.Id AND "
+ "GenoFreeze.Id = GenoXRef.GenoFreezeId "
+ "AND GenoFreeze.Name = %s "
+ "ORDER BY ABS( Geno.Mb - %s) LIMIT 1",
+ ('test_chr', 'group_nameGeno', 'test_mb'))
+
+ self.assertEqual(results_with_item_db, "Geno1")
+
+ @mock.patch("wqflask.show_trait.show_trait.database_connection")
+ def test_get_nearest_marker_empty_db(self, mock_db):
+ """test for getting nearest marker with empty db"""
+ conn = mock.MagicMock()
+ mock_db.return_value.__enter__.return_value = conn
+ with conn.cursor() as cursor:
+ cursor.fetchall.return_value = []
+ trait = TraitObject({
+ "locus_chr": "test_chr",
+ "locus_mb": "test_mb"
+ })
+ group_name = TraitObject({"name": "group_name"})
+ this_db = TraitObject({"group": group_name})
+ results_empty_db = get_nearest_marker(trait, this_db)
+ cursor.execute.assert_called_once()
+ self.assertEqual(results_empty_db, "")
+
+ @mock.patch("wqflask.show_trait.show_trait.get_scales_from_genofile")
+ def test_get_genotype_scales_with_genofile_is_list(self, mock_get_scales):
+ """test for getting genotype scales with genofile as list """
+ # where genofile is instance of list
+ genofiles_list = [{"filename": "file1", "location": "~/data/files/f1"},
+ {"filename": "file2", "location": "~/data/files/f2"},
+ {"filename": "file3", "location": "~/data/files/f3"}]
+
+ mock_get_scales.side_effect = [[["morgan", "cM"]],
+ [["morgan", "cM"]],
+ [["physic", "Mb"]]]
+
+ results = get_genotype_scales(genofiles_list)
+ expected_results = {
+ "~/data/files/f1": [["morgan", "cM"]],
+ "~/data/files/f2": [["morgan", "cM"]],
+ "~/data/files/f3": [["physic", "Mb"]]
+ }
+
+ multiple_calls = [mock.call('~/data/files/f1'), mock.call('~/data/files/f2'),
+ mock.call('~/data/files/f3')]
+ mock_get_scales.assert_has_calls(multiple_calls)
+ self.assertEqual(results, expected_results)
+
+ @mock.patch("wqflask.show_trait.show_trait.get_scales_from_genofile")
+ def test_genotype_scales_with_genofile_other(self, mock_get_scales):
+ """test for getting genotype scales with genofile as a string"""
+ file_location = "~/another_file_location"
+ mock_get_scales.return_value = [["physic", "Mb"]]
+ expected_results = {f"{file_location}": [["physic", "Mb"]]}
+ self.assertEqual(get_genotype_scales(file_location), expected_results)
+ mock_get_scales.assert_called_once_with(file_location)
+
+ @mock.patch("wqflask.show_trait.show_trait.locate_ignore_error")
+ def test_get_scales_from_genofile_found(self, mock_ignore_location):
+ """"add test for get scales from genofile where file is found"""
+ mock_ignore_location.return_value = True
+ geno_file = """
+ #sample line with no @scales:other\n
+ #sample line @scales and :separated by semicolon\n
+ This attempts to check whether\n
+ """
+
+ geno_file_string = "@line start with @ and has @scale:morgan"
+
+ file_location = "~/data/file.geno"
+
+ mock_open_geno_file = mock.mock_open(read_data=geno_file)
+ with mock.patch("builtins.open", mock_open_geno_file):
+ results = get_scales_from_genofile(file_location)
+ self.assertEqual(results, [["morgan", "cM"]])
+
+ mock_open_string = mock.mock_open(read_data=geno_file_string)
+
+ with mock.patch("builtins.open", mock_open_string):
+ result2 = get_scales_from_genofile(file_location)
+ self.assertEqual([['morgan', 'cM']], result2)
+
+ @mock.patch("wqflask.show_trait.show_trait.locate_ignore_error")
+ def test_get_scales_from_genofile_not_found(self, mock_location_ignore):
+ mock_location_ignore.return_value = False
+
+ expected_results = [["physic", "Mb"]]
+ results = get_scales_from_genofile("~/data/file")
+ mock_location_ignore.assert_called_once_with("~/data/file", "genotype")
+ self.assertEqual(results, expected_results)