def setUp(self):
     self.case = SequenceUploader()
     self.mock_seqdata = mock.MagicMock(spec=SequenceMetadata)
class SequenceUploaderTestCase(unittest.TestCase):
    def setUp(self):
        self.case = SequenceUploader()
        self.mock_seqdata = mock.MagicMock(spec=SequenceMetadata)

    def tearDown(self):
        del self.case


    @mock.patch('superphy.upload.sequence_upload.SequenceUploader.error_logging')
    @mock.patch('superphy.upload.sequence_upload.SequenceValidator')
    @mock.patch('superphy.upload.sequence_upload.SequenceUploader.upload')
    @mock.patch('superphy.upload.sequence_upload.SequenceUploader.load_sequence')
    @mock.patch('superphy.upload.sequence_upload.SequenceMetadata')
    @mock.patch('superphy.upload.sequence_upload.find_missing_sequences')
    def test_upload_missing_sequences(self, mock_find, mock_data, mock_load, mock_upload, mock_valid, mock_error):
        self.mock_seqdata.dict = {}

        mock_find.return_value = []
        self.case.upload_missing_sequences()

        self.assertEqual(len(mock_find.mock_calls), 1)
        mock_data.assert_not_called()
        mock_load.assert_not_called()
        mock_upload.assert_not_called()
        mock_valid.assert_not_called()
        mock_error.assert_not_called()

        mock_find.return_value = [("AAAA", "AAAA")]
        self.mock_seqdata.dict["is_from"] = "PLASMID"
        mock_data.return_value = self.mock_seqdata
        self.case.upload_missing_sequences()

        self.assertEqual(len(mock_find.mock_calls), 2)
        self.assertEqual(len(mock_data.mock_calls), 1)
        self.assertEqual(len(mock_load.mock_calls), 1)
        self.assertEqual(len(mock_upload.mock_calls), 1)
        mock_valid.assert_not_called()
        mock_error.assert_not_called()

        mock_find.return_value = [("AAAA", "AAAA")]
        self.mock_seqdata.dict["is_from"] = "CORE"
        mock_data.return_value = self.mock_seqdata
        self.case.upload_missing_sequences()

        self.assertEqual(len(mock_find.mock_calls), 3)
        self.assertEqual(len(mock_data.mock_calls), 2)
        self.assertEqual(len(mock_load.mock_calls), 2)
        self.assertEqual(len(mock_upload.mock_calls), 2)
        self.assertEqual(len(mock_valid.mock_calls), 2)
        mock_error.assert_not_called()

        mock_find.return_value = [("AAAA", "AAAA")]
        self.mock_seqdata.dict["is_from"] = "CORE"
        mock_data.return_value = self.mock_seqdata
        mock_load.side_effect = TypeError
        self.case.upload_missing_sequences()

        self.assertEqual(len(mock_find.mock_calls), 4)
        self.assertEqual(len(mock_data.mock_calls), 3)
        self.assertEqual(len(mock_load.mock_calls), 3)
        self.assertEqual(len(mock_upload.mock_calls), 2)
        self.assertEqual(len(mock_valid.mock_calls), 2)
        self.assertEqual(len(mock_error.mock_calls), 1)

    @mock.patch('superphy.upload.sequence_upload.SequenceUploader.get_seqdata')
    @mock.patch('superphy.upload.sequence_upload.check_named_individual')
    def test_load_sequence(self, mock_check, mock_get):
        mock_check.side_effect = [True, False]
        self.mock_seqdata.name = "AAAA_seq"

        with self.assertRaises(TypeError):
            self.case.load_sequence(self.mock_seqdata)
        mock_check.assert_called_once_with(mock.ANY)
        mock_get.assert_not_called()

        mock_check.reset_mock()
        mock_get.reset_mock()
        self.case.load_sequence(self.mock_seqdata)
        mock_check.assert_called_once_with(mock.ANY)
        mock_get.assert_called_once_with(mock.ANY)

    @mock.patch('superphy.upload.sequence_upload.BlazegraphUploader', autospec=True)
    @mock.patch('superphy.upload.sequence_upload.Sequence')
    def test_upload(self, mock_rdf, mock_bg):
        seq_ref = mock.MagicMock(spec=Sequence, create=True)
        sample_func = mock.Mock()
        mock_rdf.return_value = seq_ref

        self.case.upload(self.mock_seqdata, sample_func)
        self.assertEqual(self.mock_seqdata.generate_kwargs.call_count, 1)
        sample_func.assert_called_once_with(mock.ANY, mock.ANY)
        mock_rdf.assert_called_once_with(mock.ANY)
        mock_bg.assert_called_once_with()

    def test_plasmid_rdf(self):
        seq_ref = mock.MagicMock(spec=Sequence, create=True)

        self.mock_seqdata.accession = "AAAA"
        self.mock_seqdata.genome = "AAAA"
        self.case.plasmid_rdf(self.mock_seqdata, seq_ref)
        self.assertEqual(len(seq_ref.mock_calls), 2)

        seq_ref.reset_mock()
        self.mock_seqdata.accession = "AAAA"
        self.mock_seqdata.genome = "BBBB"
        self.case.plasmid_rdf(self.mock_seqdata, seq_ref)
        self.assertEqual(len(seq_ref.mock_calls), 1)

    def test_nonplasmid_rdf(self):
        seq_ref = mock.MagicMock(spec=Sequence, create=True)

        self.mock_seqdata.valid = True
        self.mock_seqdata.hits = []
        self.case.nonplasmid_rdf(self.mock_seqdata, seq_ref)
        self.assertEqual(len(seq_ref.mock_calls), 3)

        seq_ref.reset_mock()
        self.mock_seqdata.valid = False
        self.mock_seqdata.hits = []
        self.case.nonplasmid_rdf(self.mock_seqdata, seq_ref)
        self.assertEqual(len(seq_ref.mock_calls), 1)


    def test_error_logging(self):
        pass

    @mock.patch('superphy.upload.sequence_upload.SequenceUploader.from_ftp')
    @mock.patch('superphy.upload.sequence_upload.SequenceUploader.from_nuccore')
    def test_get_seqdata(self, mock_nuccore, mock_ftp):
        mock_nuccore.side_effect = [ValueError, None]
        mock_ftp.side_effect = None

        self.case.get_seqdata(self.mock_seqdata)
        mock_nuccore.assert_called_once_with(mock.ANY)
        mock_ftp.assert_called_once_with(mock.ANY)

        mock_nuccore.reset_mock()
        mock_ftp.reset_mock()
        self.case.get_seqdata(self.mock_seqdata)
        mock_nuccore.assert_called_once_with(mock.ANY)
        mock_ftp.assert_not_called()

    @mock.patch('superphy.upload.sequence_upload.SequenceUploader.read_fasta')
    @mock.patch('superphy.upload.sequence_upload.Entrez', autospec=True)
    def test_from_nuccore(self, mock_entrez, mock_read):
        mock_entrez.efetch.return_value = mock.MagicMock(spec=file)
        self.mock_seqdata.accession = None
        self.mock_seqdata.dict = {}

        self.mock_seqdata.dict["sequences"] = ['']
        with self.assertRaises(ValueError):
            self.case.from_nuccore(self.mock_seqdata)
        self.assertEqual(mock_entrez.email, "*****@*****.**")
        self.assertEqual(mock_entrez.efetch.call_count, 1)
        self.assertEqual(mock_read.call_count, 1)

        mock_entrez.reset_mock()
        mock_read.reset_mock()
        self.mock_seqdata.dict["sequences"] = ['asdf']
        self.mock_seqdata.dict["is_from"] = "PLASMID"
        self.case.from_nuccore(self.mock_seqdata)
        self.assertEqual(self.mock_seqdata.dict["is_from"], "PLASMID")

        mock_entrez.reset_mock()
        mock_read.reset_mock()
        self.mock_seqdata.dict["is_from"] = None
        self.mock_seqdata.dict["sequences"] = ['asdf']
        self.case.from_nuccore(self.mock_seqdata)
        self.assertEqual(self.mock_seqdata.dict["is_from"], "CORE")

    @mock.patch('superphy.upload.sequence_upload.SequenceUploader.read_fasta')
    @mock.patch('superphy.upload.sequence_upload.open')
    @mock.patch('superphy.upload.sequence_upload.SequenceUploader.download_file')
    def test_from_ftp(self, mock_download, mock_open, mock_read):
        mock_open.return_value = mock.MagicMock(spec=file)
        self.mock_seqdata.accession = None
        self.mock_seqdata.dict = {}

        self.case.from_ftp(self.mock_seqdata)

        mock_download.assert_called_once_with(mock.ANY, mock.ANY)
        mock_open.assert_called_once_with(mock.ANY, mock.ANY)
        mock_read.assert_called_once_with(mock.ANY, mock.ANY)
        self.assertEqual(self.mock_seqdata.dict["is_from"], "WGS")

    @mock.patch('superphy.upload.sequence_upload.SeqIO.parse')
    def test_read_fasta(self, mock_SeqIO):
        record1 = SeqRecord(seq="abcd")
        record2 = SeqRecord(seq="efghi")
        record3 = SeqRecord(seq="jklmno")
        plasmid = SeqRecord(seq="abcd", description="PLASMID")

        mock_handle = mock.MagicMock(spec=file)
        self.mock_seqdata.dict = {}

        mock_SeqIO.return_value = [record3, record1, record2]
        self.case.read_fasta(mock_handle, self.mock_seqdata)
        (args,) = self.mock_seqdata.mock_calls[0][1]
        self.assertEqual(args, ['abcd', 'efghi', 'jklmno'])

        self.mock_seqdata.reset_mock()
        mock_SeqIO.return_value = [plasmid]
        self.case.read_fasta(mock_handle, self.mock_seqdata)
        (args,) = self.mock_seqdata.mock_calls[0][1]
        self.assertEqual(args, ["abcd"])
        self.assertEqual(self.mock_seqdata.dict["is_from"], "PLASMID")

    @mock.patch('superphy.upload.sequence_upload.open')
    @mock.patch('superphy.upload.sequence_upload.FTP', autospec=True)
    def test_download_file(self, mock_FTP, mock_open):
        mock_FTP().nlst.return_value = ["wgs.JHNI.1.fsa_nt.gz", "wgs.ABCD.1.fsa_nt.gz", "wgs.IDLE.1.fsa_nt.gz"]
        mock_open.return_value = mock.MagicMock(spec=file)

        self.case.download_file("JHNI", "fsa_nt.gz")
        self.assertEqual(mock_open.call_count, 2)

        mock_open.reset_mock()
        with self.assertRaises(TypeError):
            self.case.download_file("NYAN", "fsa_nt.gz")
        mock_open.assert_not_called()