import unittest
import sys
for path in ['../', './']:
    sys.path.insert(1, path)

# python -m unittest discover
from processing.user_graph_generator import UserGraphGenerator
import networkx as nx


class TestUserGraphGenerator(unittest.TestCase):

    def setUp(self):
        self.user_graph = UserGraphGenerator()

    def test_count_edges_oneNode(self):
        count_res = {}
        self.assertEqual(count_res, self.user_graph.count_edges([1]))

    def test_count_edges_threeDistinctNodes_threeEdges(self):
        count_res = {(1, 2): 1, (1, 3): 1, (2, 3): 1}
        self.assertEqual(count_res, self.user_graph.count_edges([1, 2, 3]))

    def test_count_edges_twoNodesWithDups_notReflexive(self):
        count_res = {}
        self.assertEqual(count_res, self.user_graph.count_edges([1, 1]))

    def test_count_edges_threeNodesWithDups_countGtOne_notReflexive(self):
        count_res = {(1, 3): 2}
        self.assertEqual(count_res, self.user_graph.count_edges([1, 1, 3]))

    def test_count_edges_fourNodesWithDups_countGtOne_notReflexive(self):
        count_res = {(1, 3): 2, (1, 4): 2, (3, 4): 1}
        self.assertEqual(count_res, self.user_graph.count_edges([1, 1, 3, 4]))

    def test_count_edges_fourStringNodesWithDups_countGtOne_notReflexive(self):
        count_res = {('test', 'test2'): 2, ('test', '4'): 2, ('test2', '4'): 1}
        self.assertEqual(count_res,
                         self.user_graph.count_edges(['test', 'test', 'test2', '4']))

    def test_count_edges_fourDistinctStringNodes_fullyConnectedEdges(self):
        count_res = {
            ('1', '2'): 1, ('1', '3'): 1, ('1', '4'): 1,
            ('2', '3'): 1, ('2', '4'): 1, ('3', '4'): 1
        }
        self.assertEqual(count_res,
                         self.user_graph.count_edges(['1', '2', '3', '4']))

    def test_create_edges_with_weights_SingleEdge(self):
        counts = {('a', 'b'): 1}
        edge_result = [('a', 'b', {'weight': 1})]
        self.assertEqual(edge_result,
                         self.user_graph.create_edges_with_weights(counts))

    def test_create_edges_with_weights_SingleEdgeWeightTwo(self):
        counts = {('a', 'b'): 2}
        edge_result = [('a', 'b', {'weight': 2})]
        self.assertEqual(edge_result,
                         self.user_graph.create_edges_with_weights(counts))

    def test_create_edges_with_weights_TwoEdgesWithWeights(self):
        counts = {('a', 'b'): 2, ('b', 'c'): 1}
        edge_result = [('a', 'b', {'weight': 2}), ('b', 'c', {'weight': 1})]
        self.assertEqual(edge_result,
                         self.user_graph.create_edges_with_weights(counts))

    def test_create_graph_from_nodes_singleNode(self):
        nodes = [1]
        edges = []
        self.assertGraph(nodes, edges,
                         self.user_graph.create_graph_from_nodes(nodes))

    def test_create_graph_from_nodes_twoDistinctNodes(self):
        nodes = [1, 2]
        edges = [(1, 2, {'weight': 1})]
        self.assertGraph(nodes, edges,
                         self.user_graph.create_graph_from_nodes(nodes))

    def test_create_graph_from_nodes_threeDistinctNodes(self):
        nodes = [1, 2, 3]
        edges = [(1, 2, {'weight': 1}), (1, 3, {'weight': 1}),
                 (2, 3, {'weight': 1})]
        self.assertGraph(nodes, edges,
                         self.user_graph.create_graph_from_nodes(nodes))

    def test_create_graph_from_nodes_threeNodesWithDuplicates_TwoNodes_EdgesWithAccordingWeight(self):
        nodes = [1, 1, 3]
        edges = [(1, 3, {'weight': 2})]
        self.assertGraph(list(set(nodes)), edges,
                         self.user_graph.create_graph_from_nodes(nodes))

    # unittest custom assertions
    def assertGraph(self, nodes, edges, g: nx.Graph):
        self.assertEqual(len(nodes), g.number_of_nodes())
        self.assertEqual(len(edges), g.number_of_edges())

        for i in range(len(nodes)):
            self.assertEqual(nodes[i], list(g.nodes)[i])

        for i in range(len(edges)):
            graph_edge = list(g.edges)[i]
            first, second, weight = edges[i]

            self.assertEqual((first, second), graph_edge)
            self.assertEqual(weight, g.edges[graph_edge])


if __name__ == '__main__':
    unittest.main()
