
"""
Tests related to barcoding applications.
"""

from unittest import SkipTest
import os.path as op

from pbcore.io import SubreadSet
from pbcommand.models import FileTypes

from pysiv2.custom.base import TestReportStatistics, TestBase


class TestBarcodeReport(TestReportStatistics):
    """
    Test contents of table in the barcode report; the expected column values
    should be defined in the ``barcode_report`` section of ``test_values.json``,
    e.g.::

        "barcode_report": {
            "barcode_ids": ["fwd1", "fwd2", "fwd3"],
            "number_of_reads": [101, 245, 147],
            "number_of_bases": [10123, 24680, 14694]
        }

    """

    REPORT_ID = "barcode"
    TEST_ID = "barcode_report"
    METRIC_IDS = []

    def _compare_table_column(self, column_name):
        expected_values = self.expected_values.get(column_name, None)
        if expected_values is None:
            raise SkipTest("No expected values defined")
        report_values = self._get_table_row("barcode_table", column_name)
        self.assertEqual(report_values, expected_values)

    def test_barcode_ids(self):
        """
        Test that the identifiers in the table column ``barcode`` are the
        expected strings.
        """
        self._compare_table_column("barcode")

    def test_number_of_barcoded_reads(self): # XXX subreads?
        """
        Test that the values in the table column ``number_of_reads`` are the
        expected values.
        """
        self._compare_table_column("number_of_reads")

    def test_number_of_barcoded_bases(self):
        """
        Test that the values in the table column ``number_of_bases`` are the
        expected values.
        """
        self._compare_table_column("number_of_bases")


class TestSubreadSetOutput(TestBase):
    """
    Various sanity checks run on the barcoded SubreadSet.
    """

    def _get_subreadset_out(self):
        for file_id, file_info in self.datastore.get_file_dict().iteritems():
            if file_info.file_type_id == FileTypes.DS_SUBREADS.file_type_id:
                return file_info.path

    def test_output_subreadset_is_barcoded(self):
        """
        Test that the BAM files in the output SubreadSet contain barcoding
        information.
        """
        with SubreadSet(self._get_subreadset_out()) as ds_out:
            self.assertTrue(ds_out.isBarcoded)

    def test_output_subreadset_has_metadata(self):
        """
        Verify that metadata from the instrument are propagated to the barcoded
        SubreadSet.
        """
        with SubreadSet(self.entrypoints.data['eid_subread']) as ds_in:
            with SubreadSet(self._get_subreadset_out()) as ds_out:
                md_in = ds_in.metadata
                md_out = ds_out.metadata
                self.assertTrue(len(md_out.collections.submetadata) > 0)
                self.assertEqual(
                    md_in.collections.submetadata[0].attrib['InstrumentName'],
                    md_out.collections.submetadata[0].attrib['InstrumentName'])

    def test_output_subreadset_has_scraps(self):
        """
        Verify that scraps BAM files are included in the barcoded SubreadSet.
        """
        with SubreadSet(self._get_subreadset_out()) as ds_out:
            for ext_res in ds_out.externalResources:
                self.assertTrue(op.isfile(ext_res.scraps))

    def test_output_subreadset_name(self):
        """
        Verify that the output SubreadSet name is identical to the input name
        plus ' (barcoded)'.
        """
        with SubreadSet(self.entrypoints.data['eid_subread']) as ds_in:
            with SubreadSet(self._get_subreadset_out()) as ds_out:
                self.assertEqual(ds_out.name, ds_in.name + " (barcoded)")
