about summary refs log tree commit diff
path: root/tests/unit/computations
diff options
context:
space:
mode:
Diffstat (limited to 'tests/unit/computations')
-rw-r--r--tests/unit/computations/test_correlation.py48
-rw-r--r--tests/unit/computations/test_heatmap.py143
-rw-r--r--tests/unit/computations/test_slink.py311
3 files changed, 492 insertions, 10 deletions
diff --git a/tests/unit/computations/test_correlation.py b/tests/unit/computations/test_correlation.py
index b1bc6ef..fc52ec1 100644
--- a/tests/unit/computations/test_correlation.py
+++ b/tests/unit/computations/test_correlation.py
@@ -1,5 +1,4 @@
 """Module contains the tests for correlation"""
-import unittest
 from unittest import TestCase
 from unittest import mock
 
@@ -16,9 +15,10 @@ from gn3.computations.correlations import fetch_lit_correlation_data
 from gn3.computations.correlations import query_formatter
 from gn3.computations.correlations import map_to_mouse_gene_id
 from gn3.computations.correlations import compute_all_lit_correlation
-from gn3.computations.correlations import compute_all_tissue_correlation
+from gn3.computations.correlations import compute_tissue_correlation
 from gn3.computations.correlations import map_shared_keys_to_values
 from gn3.computations.correlations import process_trait_symbol_dict
+from gn3.computations.correlations2 import compute_correlation
 
 
 class QueryableMixin:
@@ -172,7 +172,6 @@ class TestCorrelation(TestCase):
         self.assertEqual(results, (filtered_this_samplelist,
                                    filtered_target_samplelist))
 
-    @unittest.skip("Test needs to be refactored ")
     @mock.patch("gn3.computations.correlations.compute_sample_r_correlation")
     @mock.patch("gn3.computations.correlations.filter_shared_sample_keys")
     def test_compute_all_sample(self, filter_shared_samples, sample_r_corr):
@@ -180,7 +179,7 @@ class TestCorrelation(TestCase):
 
         filter_shared_samples.return_value = (["1.23", "6.565", "6.456"], [
             "6.266", "6.565", "6.456"])
-        sample_r_corr.return_value = ([-1.0, 0.9, 6])
+        sample_r_corr.return_value = (["1419792_at", -1.0, 0.9, 6])
 
         this_trait_data = {
             "trait_id": "1455376_at",
@@ -203,13 +202,14 @@ class TestCorrelation(TestCase):
             }
         ]
 
-        sample_all_results = [{"1419792_at": {"corr_coeffient": -1.0,
+        sample_all_results = [{"1419792_at": {"corr_coefficient": -1.0,
                                               "p_value": 0.9,
                                               "num_overlap": 6}}]
 
         self.assertEqual(compute_all_sample_correlation(
             this_trait=this_trait_data, target_dataset=traits_dataset), sample_all_results)
         sample_r_corr.assert_called_once_with(
+            trait_name='1419792_at',
             corr_method="pearson", trait_vals=['1.23', '6.565', '6.456'],
             target_samples_vals=['6.266', '6.565', '6.456'])
         filter_shared_samples.assert_called_once_with(
@@ -406,17 +406,17 @@ class TestCorrelation(TestCase):
         target_tissue_data = {"trait_symbol_dict": target_trait_symbol,
                               "symbol_tissue_vals_dict": target_symbol_tissue_vals}
 
-        mock_tissue_corr.side_effect = [{"tissue_corr": -0.5, "tissue_p_val": 0.9,
-                                         "tissue_number": 3},
-                                        {"tissue_corr": 1.11, "tissue_p_val": 0.2,
-                                         "tissue_number": 3}]
+        mock_tissue_corr.side_effect = [{"1418702_a_at": {"tissue_corr": -0.5, "tissue_p_val": 0.9,
+                                                          "tissue_number": 3}},
+                                        {"1412_at": {"tissue_corr": 1.11, "tissue_p_val": 0.2,
+                                                     "tissue_number": 3}}]
 
         expected_results = [{"1412_at":
                              {"tissue_corr": 1.11, "tissue_p_val": 0.2, "tissue_number": 3}},
                             {"1418702_a_at":
                              {"tissue_corr": -0.5, "tissue_p_val": 0.9, "tissue_number": 3}}]
 
-        results = compute_all_tissue_correlation(
+        results = compute_tissue_correlation(
             primary_tissue_dict=primary_tissue_dict,
             target_tissues_data=target_tissue_data,
             corr_method="pearson")
@@ -464,3 +464,31 @@ class TestCorrelation(TestCase):
             trait_symbol_dict, tissue_values_dict)
 
         self.assertEqual(results, [expected_results])
+
+    def test_compute_correlation(self):
+        """Test that the new correlation function works the same as the original
+        from genenetwork1."""
+        for dbdata, userdata, expected in [
+                [[None, None, None, None, None, None, None, None, None, None],
+                 [None, None, None, None, None, None, None, None, None, None],
+                 (0.0, 0)],
+                [[None, None, None, None, None, None, None, None, None, 0],
+                 [None, None, None, None, None, None, None, None, None, None],
+                 (0.0, 0)],
+                [[None, None, None, None, None, None, None, None, None, 0],
+                 [None, None, None, None, None, None, None, None, None, 0],
+                 (0.0, 1)],
+                [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+                 (0, 10)],
+                [[9.87, 9.87, 9.87, 9.87, 9.87, 9.87, 9.87, 9.87, 9.87, 9.87],
+                 [9.87, 9.87, 9.87, 9.87, 9.87, 9.87, 9.87, 9.87, 9.87, 9.87],
+                 (0.9999999999999998, 10)],
+                [[9.3, 2.2, 5.4, 7.2, 6.4, 7.6, 3.8, 1.8, 8.4, 0.2],
+                 [0.6, 3.97, 5.82, 8.21, 1.65, 4.55, 6.72, 9.5, 7.33, 2.34],
+                 (-0.12720361919462056, 10)],
+                [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
+                 [None, None, None, None, 2, None, None, 3, None, None],
+                 (0.0, 2)]]:
+            with self.subTest(dbdata=dbdata, userdata=userdata):
+                self.assertEqual(compute_correlation(
+                    dbdata, userdata), expected)
diff --git a/tests/unit/computations/test_heatmap.py b/tests/unit/computations/test_heatmap.py
new file mode 100644
index 0000000..650cb45
--- /dev/null
+++ b/tests/unit/computations/test_heatmap.py
@@ -0,0 +1,143 @@
+"""Module contains tests for gn3.computations.heatmap"""
+from unittest import TestCase
+from gn3.computations.heatmap import cluster_traits, export_trait_data
+
+strainlist = ["B6cC3-1", "BXD1", "BXD12", "BXD16", "BXD19", "BXD2"]
+trait_data = {
+    "mysqlid": 36688172,
+    "data": {
+        "B6cC3-1": {"strain_name": "B6cC3-1", "value": 7.51879, "variance": None, "ndata": None},
+        "BXD1": {"strain_name": "BXD1", "value": 7.77141, "variance": None, "ndata": None},
+        "BXD12": {"strain_name": "BXD12", "value": 8.39265, "variance": None, "ndata": None},
+        "BXD16": {"strain_name": "BXD16", "value": 8.17443, "variance": None, "ndata": None},
+        "BXD19": {"strain_name": "BXD19", "value": 8.30401, "variance": None, "ndata": None},
+        "BXD2": {"strain_name": "BXD2", "value": 7.80944, "variance": None, "ndata": None},
+        "BXD21": {"strain_name": "BXD21", "value": 8.93809, "variance": None, "ndata": None},
+        "BXD24": {"strain_name": "BXD24", "value": 7.99415, "variance": None, "ndata": None},
+        "BXD27": {"strain_name": "BXD27", "value": 8.12177, "variance": None, "ndata": None},
+        "BXD28": {"strain_name": "BXD28", "value": 7.67688, "variance": None, "ndata": None},
+        "BXD32": {"strain_name": "BXD32", "value": 7.79062, "variance": None, "ndata": None},
+        "BXD39": {"strain_name": "BXD39", "value": 8.27641, "variance": None, "ndata": None},
+        "BXD40": {"strain_name": "BXD40", "value": 8.18012, "variance": None, "ndata": None},
+        "BXD42": {"strain_name": "BXD42", "value": 7.82433, "variance": None, "ndata": None},
+        "BXD6": {"strain_name": "BXD6", "value": 8.09718, "variance": None, "ndata": None},
+        "BXH14": {"strain_name": "BXH14", "value": 7.97475, "variance": None, "ndata": None},
+        "BXH19": {"strain_name": "BXH19", "value": 7.67223, "variance": None, "ndata": None},
+        "BXH2": {"strain_name": "BXH2", "value": 7.93622, "variance": None, "ndata": None},
+        "BXH22": {"strain_name": "BXH22", "value": 7.43692, "variance": None, "ndata": None},
+        "BXH4": {"strain_name": "BXH4", "value": 7.96336, "variance": None, "ndata": None},
+        "BXH6": {"strain_name": "BXH6", "value": 7.75132, "variance": None, "ndata": None},
+        "BXH7": {"strain_name": "BXH7", "value": 8.12927, "variance": None, "ndata": None},
+        "BXH8": {"strain_name": "BXH8", "value": 6.77338, "variance": None, "ndata": None},
+        "BXH9": {"strain_name": "BXH9", "value": 8.03836, "variance": None, "ndata": None},
+        "C3H/HeJ": {"strain_name": "C3H/HeJ", "value": 7.42795, "variance": None, "ndata": None},
+        "C57BL/6J": {"strain_name": "C57BL/6J", "value": 7.50606, "variance": None, "ndata": None},
+        "DBA/2J": {"strain_name": "DBA/2J", "value": 7.72588, "variance": None, "ndata": None}}}
+
+class TestHeatmap(TestCase):
+    """Class for testing heatmap computation functions"""
+
+    def test_export_trait_data_dtype(self):
+        """
+        Test `export_trait_data` with different values for the `dtype` keyword
+        argument
+        """
+        for dtype, expected in [
+                ["val", (7.51879, 7.77141, 8.39265, 8.17443, 8.30401, 7.80944)],
+                ["var", (None, None, None, None, None, None)],
+                ["N", (None, None, None, None, None, None)],
+                ["all", (7.51879, 7.77141, 8.39265, 8.17443, 8.30401, 7.80944)]]:
+            with self.subTest(dtype=dtype):
+                self.assertEqual(
+                    export_trait_data(trait_data, strainlist, dtype=dtype),
+                    expected)
+
+    def test_export_trait_data_dtype_all_flags(self):
+        """
+        Test `export_trait_data` with different values for the `dtype` keyword
+        argument and the different flags set up
+        """
+        for dtype, vflag, nflag, expected in [
+                ["val", False, False,
+                 (7.51879, 7.77141, 8.39265, 8.17443, 8.30401, 7.80944)],
+                ["val", False, True,
+                 (7.51879, 7.77141, 8.39265, 8.17443, 8.30401, 7.80944)],
+                ["val", True, False,
+                 (7.51879, 7.77141, 8.39265, 8.17443, 8.30401, 7.80944)],
+                ["val", True, True,
+                 (7.51879, 7.77141, 8.39265, 8.17443, 8.30401, 7.80944)],
+                ["var", False, False, (None, None, None, None, None, None)],
+                ["var", False, True, (None, None, None, None, None, None)],
+                ["var", True, False, (None, None, None, None, None, None)],
+                ["var", True, True, (None, None, None, None, None, None)],
+                ["N", False, False, (None, None, None, None, None, None)],
+                ["N", False, True, (None, None, None, None, None, None)],
+                ["N", True, False, (None, None, None, None, None, None)],
+                ["N", True, True, (None, None, None, None, None, None)],
+                ["all", False, False,
+                 (7.51879, 7.77141, 8.39265, 8.17443, 8.30401, 7.80944)],
+                ["all", False, True,
+                 (7.51879, None, 7.77141, None, 8.39265, None, 8.17443, None,
+                  8.30401, None, 7.80944, None)],
+                ["all", True, False,
+                 (7.51879, None, 7.77141, None, 8.39265, None, 8.17443, None,
+                  8.30401, None, 7.80944, None)],
+                ["all", True, True,
+                 (7.51879, None, None, 7.77141, None, None, 8.39265, None, None,
+                  8.17443, None, None, 8.30401, None, None, 7.80944, None, None)]
+        ]:
+            with self.subTest(dtype=dtype, vflag=vflag, nflag=nflag):
+                self.assertEqual(
+                    export_trait_data(
+                        trait_data, strainlist, dtype=dtype, var_exists=vflag,
+                        n_exists=nflag),
+                    expected)
+
+    def test_cluster_traits(self):
+        """
+        Test that the clustering is working as expected.
+        """
+        traits_data_list = [
+            (7.51879, 7.77141, 8.39265, 8.17443, 8.30401, 7.80944),
+            (6.1427, 6.50588, 7.73705, 6.68328, 7.49293, 7.27398),
+            (8.4211, 8.30581, 9.24076, 8.51173, 9.18455, 8.36077),
+            (10.0904, 10.6509, 9.36716, 9.91202, 8.57444, 10.5731),
+            (10.188, 9.76652, 9.54813, 9.05074, 9.52319, 9.10505),
+            (6.74676, 7.01029, 7.54169, 6.48574, 7.01427, 7.26815),
+            (6.39359, 6.85321, 5.78337, 7.11141, 6.22101, 6.16544),
+            (6.84118, 7.08432, 7.59844, 7.08229, 7.26774, 7.24991),
+            (9.45215, 10.6943, 8.64719, 10.1592, 7.75044, 8.78615),
+            (7.04737, 6.87185, 7.58586, 6.92456, 6.84243, 7.36913)]
+        self.assertEqual(
+            cluster_traits(traits_data_list),
+            ((0.0, 0.20337048635536847, 0.16381088984330505, 1.7388553629398245,
+              1.5025235756329178, 0.6952839500255574, 1.271661230252733,
+              0.2100487290977544, 1.4699690641062024, 0.7934461515867415),
+             (0.20337048635536847, 0.0, 0.2198321044997198, 1.5753041735592204,
+              1.4815755944537086, 0.26087293140686374, 1.6939790104301427,
+              0.06024619831474998, 1.7430082449189215, 0.4497104244247795),
+             (0.16381088984330505, 0.2198321044997198, 0.0, 1.9073926868549234,
+              1.0396738891139845, 0.5278328671176757, 1.6275069061182947,
+              0.2636503792482082, 1.739617877037615, 0.7127042590637039),
+             (1.7388553629398245, 1.5753041735592204, 1.9073926868549234, 0.0,
+              0.9936846292920328, 1.1169999189889366, 0.6007483980555253,
+              1.430209221053372, 0.25879514152086425, 0.9313185954797953),
+             (1.5025235756329178, 1.4815755944537086, 1.0396738891139845,
+              0.9936846292920328, 0.0, 1.027827186339337, 1.1441743109173244,
+              1.4122477962364253, 0.8968250491499363, 1.1683723389247052),
+             (0.6952839500255574, 0.26087293140686374, 0.5278328671176757,
+              1.1169999189889366, 1.027827186339337, 0.0, 1.8420471110023269,
+              0.19179284676938602, 1.4875072385631605, 0.23451785425383564),
+             (1.271661230252733, 1.6939790104301427, 1.6275069061182947,
+              0.6007483980555253, 1.1441743109173244, 1.8420471110023269, 0.0,
+              1.6540234785929928, 0.2140799896286565, 1.7413442197913358),
+             (0.2100487290977544, 0.06024619831474998, 0.2636503792482082,
+              1.430209221053372, 1.4122477962364253, 0.19179284676938602,
+              1.6540234785929928, 0.0, 1.5225640692832796, 0.33370067057028485),
+             (1.4699690641062024, 1.7430082449189215, 1.739617877037615,
+              0.25879514152086425, 0.8968250491499363, 1.4875072385631605,
+              0.2140799896286565, 1.5225640692832796, 0.0, 1.3256191648260216),
+             (0.7934461515867415, 0.4497104244247795, 0.7127042590637039,
+              0.9313185954797953, 1.1683723389247052, 0.23451785425383564,
+              1.7413442197913358, 0.33370067057028485, 1.3256191648260216,
+              0.0)))
diff --git a/tests/unit/computations/test_slink.py b/tests/unit/computations/test_slink.py
new file mode 100644
index 0000000..995393b
--- /dev/null
+++ b/tests/unit/computations/test_slink.py
@@ -0,0 +1,311 @@
+"""Module contains tests for slink"""
+from unittest import TestCase
+
+from gn3.computations.slink import slink
+from gn3.computations.slink import nearest
+from gn3.computations.slink import LengthError
+from gn3.computations.slink import MirrorError
+
+class TestSlink(TestCase):
+    """Class for testing slink functions"""
+
+    def test_nearest_expects_list_of_lists(self):
+        """Test that function only accepts a list of lists."""
+        # This might be better handled with type-hints and mypy
+        for item in [9, "some string", 5.432,
+                     [1, 2, 3], ["test", 7.4]]:
+            with self.subTest(item=item):
+                with self.assertRaises(ValueError, msg="Expected list or tuple"):
+                    nearest(item, 1, 1)
+
+    def test_nearest_does_not_allow_empty_lists(self):
+        """Test that function does not accept an empty list, or any of the child
+        lists to be empty."""
+        for lst in [[],
+                    [[], []],
+                    [[], [], []],
+                    [[0, 1, 2], [], [1, 2, 0]]]:
+            with self.subTest(lst=lst):
+                with self.assertRaises(ValueError):
+                    nearest(lst, 1, 1)
+
+    def test_nearest_expects_children_are_same_length_as_parent(self):
+        """Test that children lists are same length as parent list."""
+        for lst in [[[0, 1]],
+                    [[0, 1, 2], [3, 4, 5]],
+                    [[0, 1, 2, 3], [4, 5, 6], [7, 8, 9, 0]],
+                    [[0, 1, 2, 3, 4], [5, 6, 7, 8, 9], [1, 2, 3, 4, 5], [2, 3],
+                     [3, 4, 5, 6, 7]]]:
+            with self.subTest(lst=lst):
+                with self.assertRaises(LengthError):
+                    nearest(lst, 1, 1)
+
+    def test_nearest_expects_member_is_zero_distance_from_itself(self):
+        """Test that distance of a member from itself is zero"""
+        for lst in [[[1]],
+                    [[1, 2], [3, 4]],
+                    [1, 0, 0], [0, 0, 5], [0, 3, 4],
+                    [0, 0, 0, 0], [0, 0, 3, 3], [0, 1, 2, 3], [0, 3, 2, 0]]:
+            with self.subTest(lst=lst):
+                with self.assertRaises(ValueError):
+                    nearest(lst, 1, 1)
+
+    def test_nearest_expects_distance_atob_is_equal_to_distance_btoa(self):
+        """Test that the distance from member A to member B is the same as that
+        from member B to member A."""
+        for lst in [[[0, 1], [2, 0]],
+                    [[0, 1, 2], [1, 0, 3], [9, 7, 0]],
+                    [[0, 1, 2, 3], [7, 0, 2, 3], [2, 3, 0, 1], [8, 9, 5, 0]]]:
+            with self.subTest(lst=lst):
+                with self.assertRaises(MirrorError):
+                    nearest(lst, 1, 1)
+
+    def test_nearest_expects_zero_or_positive_distances(self):
+        """Test that all distances are either zero, or greater than zero."""
+        # Based on:
+        # https://github.com/genenetwork/genenetwork1/blob/master/web/webqtl/heatmap/slink.py#L87-L89
+        for lst in [[[0, -1, 2, 3], [-1, 0, 3, 4], [2, 3, 0, 5], [3, 4, 5, 0]],
+                    [[0, 1, -2, 3], [1, 0, 3, 4], [-2, 3, 0, 5], [3, 4, 5, 0]],
+                    [[0, 1, 2, 3], [1, 0, -3, 4], [2, -3, 0, 5], [3, 4, 5, 0]],
+                    [[0, 1, 2, -3], [1, 0, 3, 4], [2, 3, 0, 5], [-3, 4, 5, 0]],
+                    [[0, 1, 2, 3], [1, 0, 3, -4], [2, 3, 0, 5], [3, -4, 5, 0]],
+                    [[0, 1, 2, 3], [1, 0, 3, 4], [2, 3, 0, -5], [3, 4, -5, 0]]]:
+            with self.subTest(lst=lst):
+                with self.assertRaises(ValueError, msg="Distances should be positive."):
+                    nearest(lst, 1, 1)
+
+    def test_nearest_returns_shortest_distance_given_coordinates_to_both_group_members(self):
+        """Test that the shortest distance is returned."""
+        # This test is named wrong - at least I think it is, from the expected results
+        # This tests distance when both `i`, and `j` are integers
+        # We still need to add tests for when (either one/both) (is/are) not (an) integer(s)
+        # https://github.com/genenetwork/genenetwork1/blob/master/web/webqtl/heatmap/slink.py#L39-L40
+        for lst, i, j, expected in [
+                [[[0, 9, 3, 6, 11], [9, 0, 7, 5, 10], [3, 7, 0, 9, 2],
+                  [6, 5, 9, 0, 8], [11, 10, 2, 8, 0]],
+                 0, 0, 0],
+                [[[0, 9, 3, 6, 11], [9, 0, 7, 5, 10], [3, 7, 0, 9, 2],
+                  [6, 5, 9, 0, 8], [11, 10, 2, 8, 0]],
+                 0, 1, 9],
+                [[[0, 9, 3, 6, 11], [9, 0, 7, 5, 10], [3, 7, 0, 9, 2],
+                  [6, 5, 9, 0, 8], [11, 10, 2, 8, 0]],
+                 0, 2, 3],
+                [[[0, 9, 3, 6, 11], [9, 0, 7, 5, 10], [3, 7, 0, 9, 2],
+                  [6, 5, 9, 0, 8], [11, 10, 2, 8, 0]],
+                 0, 3, 6],
+                [[[0, 9, 3, 6, 11], [9, 0, 7, 5, 10], [3, 7, 0, 9, 2],
+                  [6, 5, 9, 0, 8], [11, 10, 2, 8, 0]],
+                 0, 4, 11],
+                [[[0, 9, 3, 6, 11], [9, 0, 7, 5, 10], [3, 7, 0, 9, 2],
+                  [6, 5, 9, 0, 8], [11, 10, 2, 8, 0]],
+                 1, 0, 9],
+                [[[0, 9, 3, 6, 11], [9, 0, 7, 5, 10], [3, 7, 0, 9, 2],
+                  [6, 5, 9, 0, 8], [11, 10, 2, 8, 0]],
+                 1, 1, 0],
+                [[[0, 9, 3, 6, 11], [9, 0, 7, 5, 10], [3, 7, 0, 9, 2],
+                  [6, 5, 9, 0, 8], [11, 10, 2, 8, 0]],
+                 1, 2, 7],
+                [[[0, 9, 3, 6, 11], [9, 0, 7, 5, 10], [3, 7, 0, 9, 2],
+                  [6, 5, 9, 0, 8], [11, 10, 2, 8, 0]],
+                 1, 3, 5],
+                [[[0, 9, 3, 6, 11], [9, 0, 7, 5, 10], [3, 7, 0, 9, 2],
+                  [6, 5, 9, 0, 8], [11, 10, 2, 8, 0]],
+                 1, 4, 10],
+                [[[0, 9, 3, 6, 11], [9, 0, 7, 5, 10], [3, 7, 0, 9, 2],
+                  [6, 5, 9, 0, 8], [11, 10, 2, 8, 0]],
+                 2, 0, 3],
+                [[[0, 9, 3, 6, 11], [9, 0, 7, 5, 10], [3, 7, 0, 9, 2],
+                  [6, 5, 9, 0, 8], [11, 10, 2, 8, 0]],
+                 2, 1, 7],
+                [[[0, 9, 3, 6, 11], [9, 0, 7, 5, 10], [3, 7, 0, 9, 2],
+                  [6, 5, 9, 0, 8], [11, 10, 2, 8, 0]],
+                 2, 2, 0],
+                [[[0, 9, 3, 6, 11], [9, 0, 7, 5, 10], [3, 7, 0, 9, 2],
+                  [6, 5, 9, 0, 8], [11, 10, 2, 8, 0]],
+                 2, 3, 9],
+                [[[0, 9, 3, 6, 11], [9, 0, 7, 5, 10], [3, 7, 0, 9, 2],
+                  [6, 5, 9, 0, 8], [11, 10, 2, 8, 0]],
+                 2, 4, 2],
+                [[[0, 9, 3, 6, 11], [9, 0, 7, 5, 10], [3, 7, 0, 9, 2],
+                  [6, 5, 9, 0, 8], [11, 10, 2, 8, 0]],
+                 3, 0, 6],
+                [[[0, 9, 3, 6, 11], [9, 0, 7, 5, 10], [3, 7, 0, 9, 2],
+                  [6, 5, 9, 0, 8], [11, 10, 2, 8, 0]],
+                 3, 1, 5],
+                [[[0, 9, 3, 6, 11], [9, 0, 7, 5, 10], [3, 7, 0, 9, 2],
+                  [6, 5, 9, 0, 8], [11, 10, 2, 8, 0]],
+                 3, 2, 9],
+                [[[0, 9, 3, 6, 11], [9, 0, 7, 5, 10], [3, 7, 0, 9, 2],
+                  [6, 5, 9, 0, 8], [11, 10, 2, 8, 0]],
+                 3, 3, 0],
+                [[[0, 9, 3, 6, 11], [9, 0, 7, 5, 10], [3, 7, 0, 9, 2],
+                  [6, 5, 9, 0, 8], [11, 10, 2, 8, 0]],
+                 3, 4, 8],
+                [[[0, 9, 3, 6, 11], [9, 0, 7, 5, 10], [3, 7, 0, 9, 2],
+                  [6, 5, 9, 0, 8], [11, 10, 2, 8, 0]],
+                 4, 0, 11],
+                [[[0, 9, 3, 6, 11], [9, 0, 7, 5, 10], [3, 7, 0, 9, 2],
+                  [6, 5, 9, 0, 8], [11, 10, 2, 8, 0]],
+                 4, 1, 10],
+                [[[0, 9, 3, 6, 11], [9, 0, 7, 5, 10], [3, 7, 0, 9, 2],
+                  [6, 5, 9, 0, 8], [11, 10, 2, 8, 0]],
+                 4, 2, 2],
+                [[[0, 9, 3, 6, 11], [9, 0, 7, 5, 10], [3, 7, 0, 9, 2],
+                  [6, 5, 9, 0, 8], [11, 10, 2, 8, 0]],
+                 4, 3, 8],
+                [[[0, 9, 3, 6, 11], [9, 0, 7, 5, 10], [3, 7, 0, 9, 2],
+                  [6, 5, 9, 0, 8], [11, 10, 2, 8, 0]],
+                 4, 4, 0],
+                [[[0, 9, 5.5, 6, 11], [9, 0, 7, 5, 10], [5.5, 7, 0, 9, 2],
+                  [6, 5, 9, 0, 3], [11, 10, 2, 3, 0]],
+                 0, 0, 0],
+                [[[0, 9, 5.5, 6, 11], [9, 0, 7, 5, 10], [5.5, 7, 0, 9, 2],
+                  [6, 5, 9, 0, 3], [11, 10, 2, 3, 0]],
+                 0, 1, 9],
+                [[[0, 9, 5.5, 6, 11], [9, 0, 7, 5, 10], [5.5, 7, 0, 9, 2],
+                  [6, 5, 9, 0, 3], [11, 10, 2, 3, 0]],
+                 0, 2, 5.5],
+                [[[0, 9, 5.5, 6, 11], [9, 0, 7, 5, 10], [5.5, 7, 0, 9, 2],
+                  [6, 5, 9, 0, 3], [11, 10, 2, 3, 0]],
+                 0, 3, 6],
+                [[[0, 9, 5.5, 6, 11], [9, 0, 7, 5, 10], [5.5, 7, 0, 9, 2],
+                  [6, 5, 9, 0, 3], [11, 10, 2, 3, 0]],
+                 0, 4, 11],
+                [[[0, 9, 5.5, 6, 11], [9, 0, 7, 5, 10], [5.5, 7, 0, 9, 2],
+                  [6, 5, 9, 0, 3], [11, 10, 2, 3, 0]],
+                 1, 0, 9],
+                [[[0, 9, 5.5, 6, 11], [9, 0, 7, 5, 10], [5.5, 7, 0, 9, 2],
+                  [6, 5, 9, 0, 3], [11, 10, 2, 3, 0]],
+                 1, 1, 0],
+                [[[0, 9, 5.5, 6, 11], [9, 0, 7, 5, 10], [5.5, 7, 0, 9, 2],
+                  [6, 5, 9, 0, 3], [11, 10, 2, 3, 0]],
+                 1, 2, 7],
+                [[[0, 9, 5.5, 6, 11], [9, 0, 7, 5, 10], [5.5, 7, 0, 9, 2],
+                  [6, 5, 9, 0, 3], [11, 10, 2, 3, 0]],
+                 1, 3, 5],
+                [[[0, 9, 5.5, 6, 11], [9, 0, 7, 5, 10], [5.5, 7, 0, 9, 2],
+                  [6, 5, 9, 0, 3], [11, 10, 2, 3, 0]],
+                 1, 4, 10],
+                [[[0, 9, 5.5, 6, 11], [9, 0, 7, 5, 10], [5.5, 7, 0, 9, 2],
+                  [6, 5, 9, 0, 3], [11, 10, 2, 3, 0]],
+                 2, 0, 5.5],
+                [[[0, 9, 5.5, 6, 11], [9, 0, 7, 5, 10], [5.5, 7, 0, 9, 2],
+                  [6, 5, 9, 0, 3], [11, 10, 2, 3, 0]],
+                 2, 1, 7],
+                [[[0, 9, 5.5, 6, 11], [9, 0, 7, 5, 10], [5.5, 7, 0, 9, 2],
+                  [6, 5, 9, 0, 3], [11, 10, 2, 3, 0]],
+                 2, 2, 0],
+                [[[0, 9, 5.5, 6, 11], [9, 0, 7, 5, 10], [5.5, 7, 0, 9, 2],
+                  [6, 5, 9, 0, 3], [11, 10, 2, 3, 0]],
+                 2, 3, 9],
+                [[[0, 9, 5.5, 6, 11], [9, 0, 7, 5, 10], [5.5, 7, 0, 9, 2],
+                  [6, 5, 9, 0, 3], [11, 10, 2, 3, 0]],
+                 2, 4, 2],
+                [[[0, 9, 5.5, 6, 11], [9, 0, 7, 5, 10], [5.5, 7, 0, 9, 2],
+                  [6, 5, 9, 0, 3], [11, 10, 2, 3, 0]],
+                 3, 0, 6],
+                [[[0, 9, 5.5, 6, 11], [9, 0, 7, 5, 10], [5.5, 7, 0, 9, 2],
+                  [6, 5, 9, 0, 3], [11, 10, 2, 3, 0]],
+                 3, 1, 5],
+                [[[0, 9, 5.5, 6, 11], [9, 0, 7, 5, 10], [5.5, 7, 0, 9, 2],
+                  [6, 5, 9, 0, 3], [11, 10, 2, 3, 0]],
+                 3, 2, 9],
+                [[[0, 9, 5.5, 6, 11], [9, 0, 7, 5, 10], [5.5, 7, 0, 9, 2],
+                  [6, 5, 9, 0, 3], [11, 10, 2, 3, 0]],
+                 3, 3, 0],
+                [[[0, 9, 5.5, 6, 11], [9, 0, 7, 5, 10], [5.5, 7, 0, 9, 2],
+                  [6, 5, 9, 0, 3], [11, 10, 2, 3, 0]],
+                 3, 4, 3],
+                [[[0, 9, 5.5, 6, 11], [9, 0, 7, 5, 10], [5.5, 7, 0, 9, 2],
+                  [6, 5, 9, 0, 3], [11, 10, 2, 3, 0]],
+                 4, 0, 11],
+                [[[0, 9, 5.5, 6, 11], [9, 0, 7, 5, 10], [5.5, 7, 0, 9, 2],
+                  [6, 5, 9, 0, 3], [11, 10, 2, 3, 0]],
+                 4, 1, 10],
+                [[[0, 9, 5.5, 6, 11], [9, 0, 7, 5, 10], [5.5, 7, 0, 9, 2],
+                  [6, 5, 9, 0, 3], [11, 10, 2, 3, 0]],
+                 4, 2, 2],
+                [[[0, 9, 5.5, 6, 11], [9, 0, 7, 5, 10], [5.5, 7, 0, 9, 2],
+                  [6, 5, 9, 0, 3], [11, 10, 2, 3, 0]],
+                 4, 3, 3],
+                [[[0, 9, 5.5, 6, 11], [9, 0, 7, 5, 10], [5.5, 7, 0, 9, 2],
+                  [6, 5, 9, 0, 3], [11, 10, 2, 3, 0]],
+                 4, 4, 0]]:
+            with self.subTest(lst=lst):
+                self.assertEqual(nearest(lst, i, j), expected)
+
+    def test_nearest_gives_shortest_distance_between_list_of_members_and_member(self):
+        """Test that the shortest distance is returned."""
+        for members_distances, members_list, member_coordinate, expected_distance in [
+                [[[0, 9, 3], [9, 0, 7], [3, 7, 0]], (0, 2, 3), 1, 7],
+                [[[0, 9, 3, 6, 11], [9, 0, 7, 5, 10], [3, 7, 0, 9, 2],
+                  [6, 5, 9, 0, 8], [11, 10, 2, 8, 0]], [0, 1, 2, 3, 4], 3, 0],
+                [[[0, 9, 3, 6, 11], [9, 0, 7, 5, 10], [3, 7, 0, 9, 2],
+                  [6, 5, 9, 0, 8], [11, 10, 2, 8, 0]], [0, 1, 2, 4], 3, 5],
+                [[[0, 9, 3, 6, 11], [9, 0, 7, 5, 10], [3, 7, 0, 9, 2],
+                  [6, 5, 9, 0, 8], [11, 10, 2, 8, 0]], [0, 2, 4], 3, 6],
+                [[[0, 9, 3, 6, 11], [9, 0, 7, 5, 10], [3, 7, 0, 9, 2],
+                  [6, 5, 9, 0, 8], [11, 10, 2, 8, 0]], [2, 4], 3, 9]]:
+            with self.subTest(
+                    members_distances=members_distances,
+                    members_list=members_list,
+                    member_coordinate=member_coordinate,
+                    expected_distance=expected_distance):
+                self.assertEqual(
+                    nearest(
+                        members_distances, members_list, member_coordinate),
+                    expected_distance)
+                self.assertEqual(
+                    nearest(
+                        members_distances, member_coordinate, members_list),
+                    expected_distance)
+
+    def test_nearest_returns_shortest_distance_given_two_lists_of_members(self):
+        """Test that the shortest distance is returned."""
+        for members_distances, members_list, member_list2, expected_distance in [
+                [[[0, 9, 3, 6, 11], [9, 0, 7, 5, 10], [3, 7, 0, 9, 2],
+                  [6, 5, 9, 0, 8], [11, 10, 2, 8, 0]],
+                 [0, 1, 2, 3, 4], [0, 1, 2, 3, 4], 0],
+                [[[0, 9, 3, 6, 11], [9, 0, 7, 5, 10], [3, 7, 0, 9, 2],
+                  [6, 5, 9, 0, 8], [11, 10, 2, 8, 0]],
+                 [0, 1], [3, 4], 6],
+                [[[0, 9, 3, 6, 11], [9, 0, 7, 5, 10], [3, 7, 0, 9, 2],
+                  [6, 5, 9, 0, 8], [11, 10, 2, 8, 0]],
+                 [0, 1], [2, 3, 4], 3],
+                [[[0, 9, 3, 6, 11], [9, 0, 7, 5, 10], [3, 7, 0, 9, 2],
+                  [6, 5, 9, 0, 8], [11, 10, 2, 8, 0]],
+                 [0, 2], [3, 4], 6]]:
+            with self.subTest(
+                    members_distances=members_distances,
+                    members_list=members_list,
+                    member_list2=member_list2,
+                    expected_distance=expected_distance):
+                self.assertEqual(
+                    nearest(
+                        members_distances, members_list, member_list2),
+                    expected_distance)
+                self.assertEqual(
+                    nearest(
+                        members_distances, member_list2, members_list),
+                    expected_distance)
+
+    def test_slink_wrong_data_returns_empty_list(self):
+        """Test that empty list is returned for wrong data."""
+        for data in [1, "test", [], 2.945, nearest, [0]]:
+            with self.subTest(data=data):
+                self.assertEqual(slink(data), [])
+
+    def test_slink_with_data(self):
+        """Test slink with example data, and expected results for each data
+        sample."""
+        for data, expected in [
+                [[[0, 9], [9, 0]], [0, 1, 9]],
+                [[[0, 9, 3], [9, 0, 7], [3, 7, 0]], [(0, 2, 3), 1, 7]],
+                [[[0, 9, 3, 6], [9, 0, 7, 5], [3, 7, 0, 9], [6, 5, 9, 0]],
+                 [(0, 2, 3), (1, 3, 5), 6]],
+                [[[0, 9, 3, 6, 11], [9, 0, 7, 5, 10], [3, 7, 0, 9, 2],
+                  [6, 5, 9, 0, 8],
+                  [11, 10, 2, 8, 0]],
+                 [(0, (2, 4, 2), 3), (1, 3, 5), 6]]]:
+            with self.subTest(data=data):
+                self.assertEqual(slink(data), expected)