"""Unit tests for download data interpretation logic.
 
Unit tests to exercise logic to interpret certain fields downloaded from the
Colorado Transparency in Contribution and Expenditure Reporting Campaign
Finance website (TRACER). This is an unofficial library.
 
These tests utalize a testing dataset in the testing_corpus subdirectory that
should be in the directory holding this script. This directory should include
one JSON file per report type, each file containing an object with a single
attribute with the same name as the report type. The value of that attribute
should be an Array of Arrays, each sub-array having two elements. The first of
that pair is a sample of data like that coming from the TRACER website and the
second is the expected dictionary after interpretation.
 
@author: A. Samuel Pottinger (samnsparky, Gleap LLC)
@organization: Gleap LLC (gleap.org)
@copyright: 2013
@license: GNU GPL v3
"""
 
import datetime
import json
import os
import unittest
 
import mox
 
import constants
import report_interpreters
 
CORPUS_FOLDER_NAME = 'testing_corpus'
TEST_INJECT_VALUES = {
    'date0': datetime.datetime(2013, 1, 1, 0, 0, 0),
    'date1': datetime.datetime(2013, 1, 17, 0, 0, 0),
    'date2': datetime.datetime(2012, 9, 28, 0, 0, 0)
}
 
 
class TestDataInterpretation(unittest.TestCase):
    """Unit tests for interpreting downloaded report data."""
 
    def load_testing_corpus(self, report_type):
        """Convienence function to load testing corpus data.
 
        @param report_type: The string identifier for the type of report that
            testing data should be loaded for.
        @type report_type: str
        @return: The loaded and de-serialized testing data.
        @rtype: dict
        """
        filename = '%s.json' % report_type
        parent_directory = os.path.dirname(os.path.realpath(__file__))
        path = os.path.join(parent_directory, CORPUS_FOLDER_NAME, filename)
        raw_data = json.load(open(path, 'rb'))[report_type]
        return self.load_dates(raw_data)
 
    def load_dates(self, raw_data):
        """Inject pre-created datetimes.
 
        Looks through loading test corpus data for the values in
        TEST_INJECT_VALUES, replacing those strings with the corresponding
        value in TEST_INJECT_VALUES.
 
        @param raw_data: The data to inject datetimes into.
        @type raw_data: dict
        """
        for (input_dict, expected_output) in raw_data:
            for field in expected_output.keys():
                value = expected_output[field]
                if value in TEST_INJECT_VALUES:
                    expected_output[field] = TEST_INJECT_VALUES[value]
        return raw_data
 
    def check_dict_equal(self, dict_1, dict_2):
        """Check if two dictionaries are equal.
 
        Convienence function for testing equality in two very large
        dictionaries, one item at a time. Asserts are executed within the body
        of this function.
 
        @param dict_1: The dictionary to test equality against.
        @type dict_1: dict
        @param dict_2: The dictionary to test equality for.
        @type dict_2: dict
        """
        self.assertEqual(dict_1.keys(), dict_2.keys())
        for key in dict_1.keys():
            self.assertEqual(dict_1[key], dict_2[key])
 
 
    def setUp(self):
        """Load testing corpus data. Called before each test."""
        self.contributions_data = self.load_testing_corpus(
            constants.REPORT_CONTRIB_DATA)
        self.expenditures_data = self.load_testing_corpus(
            constants.REPORT_EXPEND_DATA)
        self.loan_data = self.load_testing_corpus(
            constants.REPORT_LOAN_DATA)
 
    def test_interpret_contributions(self):
        """Test loading contribution reports."""
        for i in range(0, len(self.contributions_data)):
            (raw, expected_output) = self.contributions_data[i]
            output = report_interpreters.interpret_contribution_entry(raw)
            self.check_dict_equal(output, expected_output)
 
    def test_interpret_expenditures(self):
        """Test loading expenditure reports."""
        for i in range(0, len(self.expenditures_data)):
            (raw, expected_output) = self.expenditures_data[i]
            output = report_interpreters.interpret_expenditure_entry(raw)
            self.check_dict_equal(output, expected_output)
 
    def test_interpret_loans(self):
        """Test loading loan reports."""
        for i in range(0, len(self.loan_data)):
            (raw, expected_output) = self.loan_data[i]
            output = report_interpreters.interpret_loan_entry(raw)
            self.check_dict_equal(output, expected_output)
 
 
if __name__ == '__main__':
    unittest.main()