示例#1
0
    def test_happy_path(self):
        """
        Test the happy path of operations where the parser takes the input
        and spits out a valid data particle given the stream.
        """
        self.stream_handle = StringIO(CtdpfParserUnitTestCase.TEST_DATA)
        self.parser = CtdpfParser(
            self.config, self.position, self.stream_handle, self.pos_callback,
            self.pub_callback)  # last one is the link to the data source

        result = self.parser.get_records(1)
        self.assert_result(result, 137, self.base_timestamp, self.particle_a)
        result = self.parser.get_records(1)
        self.assert_result(result, 174, self.base_timestamp + 1,
                           self.particle_b)
        result = self.parser.get_records(1)
        self.assert_result(result, 211, self.base_timestamp + 2,
                           self.particle_c)
        result = self.parser.get_records(1)
        self.assert_result(result, 248, self.base_timestamp + 3,
                           self.particle_d)

        # no data left, dont move the position
        result = self.parser.get_records(1)
        self.assertEqual(result, [])
        self.assertEqual(self.parser._state[StateKey.POSITION], 248)
        self.assertEqual(self.position_callback_value[StateKey.POSITION], 248)
        self.assertEqual(self.position_callback_value[StateKey.TIMESTAMP],
                         self.base_timestamp + 3)
        self.assert_(isinstance(self.publish_callback_value, list))
        self.assertEqual(self.publish_callback_value[0], self.particle_d)
示例#2
0
 def test_mid_state_start(self):
     new_state = {StateKey.POSITION:211, StateKey.TIMESTAMP:self.base_timestamp+2}
     self.stream_handle = StringIO(CtdpfParserUnitTestCase.TEST_DATA)
     self.parser = CtdpfParser(self.config, new_state, self.stream_handle,
                               self.pos_callback, self.pub_callback) # last one is the link to the data source
     result = self.parser.get_records(1)
     self.assert_result(result, 248, self.base_timestamp+3, self.particle_d)
示例#3
0
    def test_bad_data(self):
        """ There's a bad sample in the data! Ack! Skip it! """
        self.stream_handle = StringIO(CtdpfParserUnitTestCase.BAD_TEST_DATA)
        self.parser = CtdpfParser(self.config, self.position, self.stream_handle,
                                  self.pos_callback, self.pub_callback) # last one is the link to the data source

        result = self.parser.get_records(1)
        self.assert_result(result, 137, self.base_timestamp, self.particle_a)
示例#4
0
    def test_no_timestamp(self):
        """ There's no timestamp in the data! Ack! """
        self.stream_handle = StringIO(CtdpfParserUnitTestCase.NO_TIME_TEST_DATA)
        self.parser = CtdpfParser(self.config, self.position, self.stream_handle,
                                  self.pos_callback, self.pub_callback) # last one is the link to the data source

        with self.assertRaises(SampleException):
            self.parser.get_records(1)
示例#5
0
    def test_mid_timestamp(self):
        self.stream_handle = StringIO(CtdpfParserUnitTestCase.MID_TIMESTAMP_DATA)
        self.parser = CtdpfParser(self.config, self.position, self.stream_handle,
                                  self.pos_callback, self.pub_callback) # last one is the link to the data source

        result = self.parser.get_records(1)
        self.assert_result(result, 137, self.base_timestamp, self.particle_a)

        result = self.parser.get_records(1)
        self.assert_result(result, 193, self.base_timestamp+60, self.particle_e)
示例#6
0
    def test_long_stream(self):
        self.stream_handle = StringIO(CtdpfParserUnitTestCase.LONG_DATA)
        self.parser = CtdpfParser(self.config, self.position, self.stream_handle,
                                  self.pos_callback, self.pub_callback) # last one is the link to the data source

        result = self.parser.get_records(44)
        self.assertEqual(result[-1], self.particle_z)
        self.assertEqual(self.parser._state[StateKey.POSITION], 1728)
        self.assertEqual(self.position_callback_value[StateKey.POSITION], 1728)
        self.assertEqual(self.position_callback_value[StateKey.TIMESTAMP],
                         self.base_timestamp+43)
        self.assertEqual(self.publish_callback_value[-1], self.particle_z)
示例#7
0
    def test_set_state(self):
        new_state = {StateKey.POSITION:174, StateKey.TIMESTAMP:self.base_timestamp+1}
        self.stream_handle = StringIO(CtdpfParserUnitTestCase.TEST_DATA)
        self.parser = CtdpfParser(self.config, self.position, self.stream_handle,
                                  self.pos_callback, self.pub_callback) # last one is the link to the data source
        result = self.parser.get_records(1)
        self.assert_result(result, 137, self.base_timestamp, self.particle_a)

        self.parser.set_state(new_state)
        result = self.parser.get_records(1)
        self.assert_result(result, 212, self.base_timestamp+2, self.particle_c)
        result = self.parser.get_records(1)
        self.assert_result(result, 249, self.base_timestamp+3, self.particle_d)
示例#8
0
    def test_get_many(self):
        self.stream_handle = StringIO(CtdpfParserUnitTestCase.TEST_DATA)
        self.parser = CtdpfParser(self.config, self.position, self.stream_handle,
                                  self.pos_callback, self.pub_callback) # last one is the link to the data source

        result = self.parser.get_records(2)
        self.assertEqual(result, [self.particle_a, self.particle_b])
        self.assertEqual(self.parser._state[StateKey.POSITION], 174)
        self.assertEqual(self.position_callback_value[StateKey.POSITION], 174)
        self.assertEqual(self.position_callback_value[StateKey.TIMESTAMP],
                         self.base_timestamp+1)
        self.assertEqual(self.publish_callback_value[0], self.particle_a)
        self.assertEqual(self.publish_callback_value[1], self.particle_b)
    def test_happy_path(self):
        """
        Test the happy path of operations where the parser takes the input
        and spits out a valid data particle given the stream.
        """
        self.stream_handle = StringIO(CtdpfParserUnitTestCase.TEST_DATA)
        self.parser = CtdpfParser(
            self.config, self.position, self.stream_handle, self.pos_callback, self.pub_callback
        )  # last one is the link to the data source

        result = self.parser.get_records(1)
        self.assert_result(result, 137, self.base_timestamp, self.particle_a)
        result = self.parser.get_records(1)
        self.assert_result(result, 174, self.base_timestamp + 1, self.particle_b)
        result = self.parser.get_records(1)
        self.assert_result(result, 211, self.base_timestamp + 2, self.particle_c)
        result = self.parser.get_records(1)
        self.assert_result(result, 248, self.base_timestamp + 3, self.particle_d)

        # no data left, dont move the position
        result = self.parser.get_records(1)
        self.assertEqual(result, [])
        self.assertEqual(self.parser._state[StateKey.POSITION], 248)
        self.assertEqual(self.position_callback_value[StateKey.POSITION], 248)
        self.assertEqual(self.position_callback_value[StateKey.TIMESTAMP], self.base_timestamp + 3)
        self.assert_(isinstance(self.publish_callback_value, list))
        self.assertEqual(self.publish_callback_value[0], self.particle_d)
示例#10
0
 def test_mid_state_start(self):
     new_state = {StateKey.POSITION:211, StateKey.TIMESTAMP:self.base_timestamp+2}
     self.stream_handle = StringIO(CtdpfParserUnitTestCase.TEST_DATA)
     self.parser = CtdpfParser(self.config, new_state, self.stream_handle,
                               self.pos_callback, self.pub_callback) # last one is the link to the data source
     result = self.parser.get_records(1)
     self.assert_result(result, 248, self.base_timestamp+3, self.particle_d)
示例#11
0
    def test_no_timestamp(self):
        """ There's no timestamp in the data! Ack! """
        self.stream_handle = StringIO(CtdpfParserUnitTestCase.NO_TIME_TEST_DATA)
        self.parser = CtdpfParser(self.config, self.position, self.stream_handle,
                                  self.pos_callback, self.pub_callback) # last one is the link to the data source

        with self.assertRaises(SampleException):
            self.parser.get_records(1)
示例#12
0
    def test_bad_data(self):
        """ There's a bad sample in the data! Ack! Skip it! """
        self.stream_handle = StringIO(CtdpfParserUnitTestCase.BAD_TEST_DATA)
        self.parser = CtdpfParser(self.config, self.position, self.stream_handle,
                                  self.pos_callback, self.pub_callback) # last one is the link to the data source

        result = self.parser.get_records(1)
        self.assert_result(result, 137, self.base_timestamp, self.particle_a)
示例#13
0
    def test_mid_timestamp(self):
        self.stream_handle = StringIO(CtdpfParserUnitTestCase.MID_TIMESTAMP_DATA)
        self.parser = CtdpfParser(self.config, self.position, self.stream_handle,
                                  self.pos_callback, self.pub_callback) # last one is the link to the data source

        result = self.parser.get_records(1)
        self.assert_result(result, 137, self.base_timestamp, self.particle_a)

        result = self.parser.get_records(1)
        self.assert_result(result, 194, self.base_timestamp+60, self.particle_e)
示例#14
0
    def _build_parser(self, parser_state, infile):
        config = self._parser_config
        config.update({
            'particle_module': 'mi.dataset.parser.ctdpf',
            'particle_class': 'CtdpfParserDataParticle'
        })
        log.debug("MYCONFIG: %s", config)
        self._parser = CtdpfParser(config, parser_state, infile,
                                   self._save_parser_state,
                                   self._data_callback)

        return self._parser
示例#15
0
    def test_long_stream(self):
        self.stream_handle = StringIO(CtdpfParserUnitTestCase.LONG_DATA)
        self.parser = CtdpfParser(
            self.config, self.position, self.stream_handle, self.pos_callback, self.pub_callback
        )  # last one is the link to the data source

        result = self.parser.get_records(44)
        self.assertEqual(result[-1], self.particle_z)
        self.assertEqual(self.parser._state[StateKey.POSITION], 1728)
        self.assertEqual(self.position_callback_value[StateKey.POSITION], 1728)
        self.assertEqual(self.position_callback_value[StateKey.TIMESTAMP], self.base_timestamp + 43)
        self.assertEqual(self.publish_callback_value[-1], self.particle_z)
示例#16
0
    def test_get_many(self):
        self.stream_handle = StringIO(CtdpfParserUnitTestCase.TEST_DATA)
        self.parser = CtdpfParser(
            self.config, self.position, self.stream_handle, self.pos_callback, self.pub_callback
        )  # last one is the link to the data source

        result = self.parser.get_records(2)
        self.assertEqual(result, [self.particle_a, self.particle_b])
        self.assertEqual(self.parser._state[StateKey.POSITION], 174)
        self.assertEqual(self.position_callback_value[StateKey.POSITION], 174)
        self.assertEqual(self.position_callback_value[StateKey.TIMESTAMP], self.base_timestamp + 1)
        self.assertEqual(self.publish_callback_value[0], self.particle_a)
        self.assertEqual(self.publish_callback_value[1], self.particle_b)
示例#17
0
    def test_set_state(self):
        new_state = {StateKey.POSITION:174, StateKey.TIMESTAMP:self.base_timestamp+1}
        self.stream_handle = StringIO(CtdpfParserUnitTestCase.TEST_DATA)
        self.parser = CtdpfParser(self.config, self.position, self.stream_handle,
                                  self.pos_callback, self.pub_callback) # last one is the link to the data source
        result = self.parser.get_records(1)
        self.assert_result(result, 137, self.base_timestamp, self.particle_a)

        self.parser.set_state(new_state)
        result = self.parser.get_records(1)
        self.assert_result(result, 212, self.base_timestamp+2, self.particle_c)
        result = self.parser.get_records(1)
        self.assert_result(result, 249, self.base_timestamp+3, self.particle_d)
示例#18
0
class CtdpfParserUnitTestCase(ParserUnitTestCase):
    """
    CTDPF Parser unit test suite
    """

    TEST_DATA = """
* Sea-Bird SBE52 MP Data File *

*** Starting profile number 42 ***
10/01/2011 03:16:01
GPS1:
GPS2:
 42.2095, 13.4344,  143.63,   2830.2
 42.2102, 13.4346,  143.63,   2831.1
 42.2105, 13.4352,  143.63,   2830.6
 42.2110, 13.4350,  143.62,   2831.5
"""

    MID_TIMESTAMP_DATA = """
* Sea-Bird SBE52 MP Data File *

*** Starting profile number 42 ***
10/01/2011 03:16:01
GPS1:
GPS2:
 42.2095, 13.4344,  143.63,   2830.2
10/01/2011 03:17:01
 42.2102, 13.4346,  143.63,   2831.1
"""

    LONG_DATA = """
* Sea-Bird SBE52 MP Data File *

*** Starting profile number 42 ***
10/01/2011 03:16:01
GPS1:
GPS2:
 01.2095, 13.4344,  143.63,   2830.2
 02.2102, 13.4346,  143.63,   2831.1
 03.2105, 13.4352,  143.63,   2830.6
 04.2110, 13.4350,  143.62,   2831.5
 05.2095, 13.4344,  143.63,   2830.2
 06.2102, 13.4346,  143.63,   2831.1
 07.2105, 13.4352,  143.63,   2830.6
 08.2110, 13.4350,  143.62,   2831.5
 09.2095, 13.4344,  143.63,   2830.2
 10.2102, 13.4346,  143.63,   2831.1
 11.2105, 13.4352,  143.63,   2830.6
 12.2110, 13.4350,  143.62,   2831.5
 13.2095, 13.4344,  143.63,   2830.2
 14.2102, 13.4346,  143.63,   2831.1
 15.2105, 13.4352,  143.63,   2830.6
 16.2110, 13.4350,  143.62,   2831.5
 17.2095, 13.4344,  143.63,   2830.2
 18.2102, 13.4346,  143.63,   2831.1
 19.2105, 13.4352,  143.63,   2830.6
 20.2110, 13.4350,  143.62,   2831.5
 21.2095, 13.4344,  143.63,   2830.2
 22.2102, 13.4346,  143.63,   2831.1
 23.2105, 13.4352,  143.63,   2830.6
 24.2110, 13.4350,  143.62,   2831.5
 25.2095, 13.4344,  143.63,   2830.2
 26.2102, 13.4346,  143.63,   2831.1
 27.2105, 13.4352,  143.63,   2830.6
 28.2110, 13.4350,  143.62,   2831.5
 29.2095, 13.4344,  143.63,   2830.2
 30.2102, 13.4346,  143.63,   2831.1
 31.2105, 13.4352,  143.63,   2830.6
 32.2110, 13.4350,  143.62,   2831.5
 33.2095, 13.4344,  143.63,   2830.2
 34.2102, 13.4346,  143.63,   2831.1
 35.2105, 13.4352,  143.63,   2830.6
 36.2110, 13.4350,  143.62,   2831.5
 37.2095, 13.4344,  143.63,   2830.2
 38.2102, 13.4346,  143.63,   2831.1
 39.2105, 13.4352,  143.63,   2830.6
 40.2110, 13.4350,  143.62,   2831.5
 41.2095, 13.4344,  143.63,   2830.2
 42.2102, 13.4346,  143.63,   2831.1
 43.2105, 13.4352,  143.63,   2830.6
 11.1111, 22.2222,  333.33,   4444.4
"""
    BAD_TEST_DATA = """
* Sea-Bird SBE52 MP Data File *

*** Starting profile number 42 ***
10/01/2011 03:16:01
GPS1:
GPS2:
 42.2095, 13.4344,  143.63,   2830.2
 42.2102, 13.4346  143.63,   2831.1
 42.2105, 13.42,  143.63,   2830.6
 42.2110, 13.4350,  143.62,   2831.5
"""

    NO_TIME_TEST_DATA = """
* Sea-Bird SBE52 MP Data File *

*** Starting profile number 42 ***
GPS1:
GPS2:
 42.2095, 13.4344,  143.63,   2830.2
 42.2102, 13.4346,  143.63,   2831.1
 42.2105, 13.4252,  143.63,   2830.6
 42.2110, 13.4350,  143.62,   2831.5
"""

    def pos_callback(self, pos):
        """ Call back method to watch what comes in via the position callback """
        self.position_callback_value = pos

    def pub_callback(self, pub):
        """ Call back method to watch what comes in via the publish callback """
        self.publish_callback_value = pub

    def setUp(self):
        ParserUnitTestCase.setUp(self)
        self.config = {
            DataSetDriverConfigKeys.PARTICLE_MODULE: "mi.dataset.parser.ctdpf",
            DataSetDriverConfigKeys.PARTICLE_CLASS: "CtdpfParserDataParticle",
        }

        # not a DataSourceLocation...its just the parser
        self.position = {StateKey.POSITION: 0, StateKey.TIMESTAMP: 0.0}

        # Gonna need the test cases to make some of these
        # self.stream_handle = StringIO(TEST_DATA)
        # self.parser = CtdpfParser(config, self.position, self.stream_handle) # last one is the link to the data source
        self.base_timestamp = 3526427761.0
        self.particle_a = CtdpfParserDataParticle(
            " 42.2095, 13.4344,  143.63,   2830.2", internal_timestamp=self.base_timestamp
        )
        self.particle_b = CtdpfParserDataParticle(
            " 42.2102, 13.4346,  143.63,   2831.1", internal_timestamp=self.base_timestamp + 1
        )
        self.particle_c = CtdpfParserDataParticle(
            " 42.2105, 13.4352,  143.63,   2830.6", internal_timestamp=self.base_timestamp + 2
        )
        self.particle_d = CtdpfParserDataParticle(
            " 42.2110, 13.4350,  143.62,   2831.5", internal_timestamp=self.base_timestamp + 3
        )
        self.particle_e = CtdpfParserDataParticle(
            " 42.2102, 13.4346,  143.63,   2831.1", internal_timestamp=self.base_timestamp + 60
        )
        self.particle_z = CtdpfParserDataParticle(
            " 11.1111, 22.2222,  333.33,   4444.4", internal_timestamp=self.base_timestamp + 43
        )

        self.position_callback_value = None
        self.publish_callback_value = None

    def assert_result(self, result, position, timestamp, particle):
        self.assertEqual(result, [particle])
        self.assertEqual(self.parser._state[StateKey.POSITION], position)
        self.assertEqual(self.position_callback_value[StateKey.POSITION], position)
        self.assertEqual(self.position_callback_value[StateKey.TIMESTAMP], timestamp)
        self.assert_(isinstance(self.publish_callback_value, list))
        self.assertEqual(self.publish_callback_value[0], particle)

    def test_happy_path(self):
        """
        Test the happy path of operations where the parser takes the input
        and spits out a valid data particle given the stream.
        """
        self.stream_handle = StringIO(CtdpfParserUnitTestCase.TEST_DATA)
        self.parser = CtdpfParser(
            self.config, self.position, self.stream_handle, self.pos_callback, self.pub_callback
        )  # last one is the link to the data source

        result = self.parser.get_records(1)
        self.assert_result(result, 137, self.base_timestamp, self.particle_a)
        result = self.parser.get_records(1)
        self.assert_result(result, 174, self.base_timestamp + 1, self.particle_b)
        result = self.parser.get_records(1)
        self.assert_result(result, 211, self.base_timestamp + 2, self.particle_c)
        result = self.parser.get_records(1)
        self.assert_result(result, 248, self.base_timestamp + 3, self.particle_d)

        # no data left, dont move the position
        result = self.parser.get_records(1)
        self.assertEqual(result, [])
        self.assertEqual(self.parser._state[StateKey.POSITION], 248)
        self.assertEqual(self.position_callback_value[StateKey.POSITION], 248)
        self.assertEqual(self.position_callback_value[StateKey.TIMESTAMP], self.base_timestamp + 3)
        self.assert_(isinstance(self.publish_callback_value, list))
        self.assertEqual(self.publish_callback_value[0], self.particle_d)

    def test_get_many(self):
        self.stream_handle = StringIO(CtdpfParserUnitTestCase.TEST_DATA)
        self.parser = CtdpfParser(
            self.config, self.position, self.stream_handle, self.pos_callback, self.pub_callback
        )  # last one is the link to the data source

        result = self.parser.get_records(2)
        self.assertEqual(result, [self.particle_a, self.particle_b])
        self.assertEqual(self.parser._state[StateKey.POSITION], 174)
        self.assertEqual(self.position_callback_value[StateKey.POSITION], 174)
        self.assertEqual(self.position_callback_value[StateKey.TIMESTAMP], self.base_timestamp + 1)
        self.assertEqual(self.publish_callback_value[0], self.particle_a)
        self.assertEqual(self.publish_callback_value[1], self.particle_b)

    def test_bad_data(self):
        """ There's a bad sample in the data! Ack! Skip it! """
        self.stream_handle = StringIO(CtdpfParserUnitTestCase.BAD_TEST_DATA)
        self.parser = CtdpfParser(
            self.config, self.position, self.stream_handle, self.pos_callback, self.pub_callback
        )  # last one is the link to the data source

        result = self.parser.get_records(1)
        self.assert_result(result, 137, self.base_timestamp, self.particle_a)

    def test_no_timestamp(self):
        """ There's no timestamp in the data! Ack! """
        self.stream_handle = StringIO(CtdpfParserUnitTestCase.NO_TIME_TEST_DATA)
        self.parser = CtdpfParser(
            self.config, self.position, self.stream_handle, self.pos_callback, self.pub_callback
        )  # last one is the link to the data source

        with self.assertRaises(SampleException):
            self.parser.get_records(1)

    def test_long_stream(self):
        self.stream_handle = StringIO(CtdpfParserUnitTestCase.LONG_DATA)
        self.parser = CtdpfParser(
            self.config, self.position, self.stream_handle, self.pos_callback, self.pub_callback
        )  # last one is the link to the data source

        result = self.parser.get_records(44)
        self.assertEqual(result[-1], self.particle_z)
        self.assertEqual(self.parser._state[StateKey.POSITION], 1728)
        self.assertEqual(self.position_callback_value[StateKey.POSITION], 1728)
        self.assertEqual(self.position_callback_value[StateKey.TIMESTAMP], self.base_timestamp + 43)
        self.assertEqual(self.publish_callback_value[-1], self.particle_z)

    def test_mid_state_start(self):
        new_state = {StateKey.POSITION: 211, StateKey.TIMESTAMP: self.base_timestamp + 2}
        self.stream_handle = StringIO(CtdpfParserUnitTestCase.TEST_DATA)
        self.parser = CtdpfParser(
            self.config, new_state, self.stream_handle, self.pos_callback, self.pub_callback
        )  # last one is the link to the data source
        result = self.parser.get_records(1)
        self.assert_result(result, 248, self.base_timestamp + 3, self.particle_d)

    def test_set_state(self):
        new_state = {StateKey.POSITION: 174, StateKey.TIMESTAMP: self.base_timestamp + 1}
        self.stream_handle = StringIO(CtdpfParserUnitTestCase.TEST_DATA)
        self.parser = CtdpfParser(
            self.config, self.position, self.stream_handle, self.pos_callback, self.pub_callback
        )  # last one is the link to the data source
        result = self.parser.get_records(1)
        self.assert_result(result, 137, self.base_timestamp, self.particle_a)

        self.parser.set_state(new_state)
        result = self.parser.get_records(1)
        self.assert_result(result, 212, self.base_timestamp + 2, self.particle_c)
        result = self.parser.get_records(1)
        self.assert_result(result, 249, self.base_timestamp + 3, self.particle_d)

    def test_mid_timestamp(self):
        self.stream_handle = StringIO(CtdpfParserUnitTestCase.MID_TIMESTAMP_DATA)
        self.parser = CtdpfParser(
            self.config, self.position, self.stream_handle, self.pos_callback, self.pub_callback
        )  # last one is the link to the data source

        result = self.parser.get_records(1)
        self.assert_result(result, 137, self.base_timestamp, self.particle_a)

        result = self.parser.get_records(1)
        self.assert_result(result, 194, self.base_timestamp + 60, self.particle_e)
示例#19
0
class CtdpfParserUnitTestCase(ParserUnitTestCase):
    """
    CTDPF Parser unit test suite
    """
    TEST_DATA = """
* Sea-Bird SBE52 MP Data File *

*** Starting profile number 42 ***
10/01/2011 03:16:01
GPS1:
GPS2:
 42.2095, 13.4344,  143.63,   2830.2
 42.2102, 13.4346,  143.63,   2831.1
 42.2105, 13.4352,  143.63,   2830.6
 42.2110, 13.4350,  143.62,   2831.5
"""

    MID_TIMESTAMP_DATA = """
* Sea-Bird SBE52 MP Data File *

*** Starting profile number 42 ***
10/01/2011 03:16:01
GPS1:
GPS2:
 42.2095, 13.4344,  143.63,   2830.2
10/01/2011 03:17:01
 42.2102, 13.4346,  143.63,   2831.1
"""

    LONG_DATA = """
* Sea-Bird SBE52 MP Data File *

*** Starting profile number 42 ***
10/01/2011 03:16:01
GPS1:
GPS2:
 01.2095, 13.4344,  143.63,   2830.2
 02.2102, 13.4346,  143.63,   2831.1
 03.2105, 13.4352,  143.63,   2830.6
 04.2110, 13.4350,  143.62,   2831.5
 05.2095, 13.4344,  143.63,   2830.2
 06.2102, 13.4346,  143.63,   2831.1
 07.2105, 13.4352,  143.63,   2830.6
 08.2110, 13.4350,  143.62,   2831.5
 09.2095, 13.4344,  143.63,   2830.2
 10.2102, 13.4346,  143.63,   2831.1
 11.2105, 13.4352,  143.63,   2830.6
 12.2110, 13.4350,  143.62,   2831.5
 13.2095, 13.4344,  143.63,   2830.2
 14.2102, 13.4346,  143.63,   2831.1
 15.2105, 13.4352,  143.63,   2830.6
 16.2110, 13.4350,  143.62,   2831.5
 17.2095, 13.4344,  143.63,   2830.2
 18.2102, 13.4346,  143.63,   2831.1
 19.2105, 13.4352,  143.63,   2830.6
 20.2110, 13.4350,  143.62,   2831.5
 21.2095, 13.4344,  143.63,   2830.2
 22.2102, 13.4346,  143.63,   2831.1
 23.2105, 13.4352,  143.63,   2830.6
 24.2110, 13.4350,  143.62,   2831.5
 25.2095, 13.4344,  143.63,   2830.2
 26.2102, 13.4346,  143.63,   2831.1
 27.2105, 13.4352,  143.63,   2830.6
 28.2110, 13.4350,  143.62,   2831.5
 29.2095, 13.4344,  143.63,   2830.2
 30.2102, 13.4346,  143.63,   2831.1
 31.2105, 13.4352,  143.63,   2830.6
 32.2110, 13.4350,  143.62,   2831.5
 33.2095, 13.4344,  143.63,   2830.2
 34.2102, 13.4346,  143.63,   2831.1
 35.2105, 13.4352,  143.63,   2830.6
 36.2110, 13.4350,  143.62,   2831.5
 37.2095, 13.4344,  143.63,   2830.2
 38.2102, 13.4346,  143.63,   2831.1
 39.2105, 13.4352,  143.63,   2830.6
 40.2110, 13.4350,  143.62,   2831.5
 41.2095, 13.4344,  143.63,   2830.2
 42.2102, 13.4346,  143.63,   2831.1
 43.2105, 13.4352,  143.63,   2830.6
 11.1111, 22.2222,  333.33,   4444.4
"""
    BAD_TEST_DATA = """
* Sea-Bird SBE52 MP Data File *

*** Starting profile number 42 ***
10/01/2011 03:16:01
GPS1:
GPS2:
 42.2095, 13.4344,  143.63,   2830.2
 42.2102, 13.4346  143.63,   2831.1
 42.2105, 13.42,  143.63,   2830.6
 42.2110, 13.4350,  143.62,   2831.5
"""

    NO_TIME_TEST_DATA = """
* Sea-Bird SBE52 MP Data File *

*** Starting profile number 42 ***
GPS1:
GPS2:
 42.2095, 13.4344,  143.63,   2830.2
 42.2102, 13.4346,  143.63,   2831.1
 42.2105, 13.4252,  143.63,   2830.6
 42.2110, 13.4350,  143.62,   2831.5
"""

    def pos_callback(self, pos, file_ingested):
        """ Call back method to watch what comes in via the position callback """
        self.position_callback_value = pos
        self.file_ingested = file_ingested

    def pub_callback(self, pub):
        """ Call back method to watch what comes in via the publish callback """
        self.publish_callback_value = pub

    def setUp(self):
        ParserUnitTestCase.setUp(self)
        self.config = {
            DataSetDriverConfigKeys.PARTICLE_MODULE: 'mi.dataset.parser.ctdpf',
            DataSetDriverConfigKeys.PARTICLE_CLASS: 'CtdpfParserDataParticle'
        }

        # not a DataSourceLocation...its just the parser
        self.position = {StateKey.POSITION: 0, StateKey.TIMESTAMP: 0.0}

        # Gonna need the test cases to make some of these
        # self.stream_handle = StringIO(TEST_DATA)
        # self.parser = CtdpfParser(config, self.position, self.stream_handle) # last one is the link to the data source
        self.base_timestamp = 3526427761.0
        self.particle_a = CtdpfParserDataParticle(
            " 42.2095, 13.4344,  143.63,   2830.2",
            internal_timestamp=self.base_timestamp)
        self.particle_b = CtdpfParserDataParticle(
            " 42.2102, 13.4346,  143.63,   2831.1",
            internal_timestamp=self.base_timestamp + 1)
        self.particle_c = CtdpfParserDataParticle(
            " 42.2105, 13.4352,  143.63,   2830.6",
            internal_timestamp=self.base_timestamp + 2)
        self.particle_d = CtdpfParserDataParticle(
            " 42.2110, 13.4350,  143.62,   2831.5",
            internal_timestamp=self.base_timestamp + 3)
        self.particle_e = CtdpfParserDataParticle(
            " 42.2102, 13.4346,  143.63,   2831.1",
            internal_timestamp=self.base_timestamp + 60)
        self.particle_z = CtdpfParserDataParticle(
            " 11.1111, 22.2222,  333.33,   4444.4",
            internal_timestamp=self.base_timestamp + 43)

        self.position_callback_value = None
        self.publish_callback_value = None

    def assert_result(self, result, position, timestamp, particle):
        self.assertEqual(result, [particle])
        self.assertEqual(self.parser._state[StateKey.POSITION], position)
        self.assertEqual(self.position_callback_value[StateKey.POSITION],
                         position)
        self.assertEqual(self.position_callback_value[StateKey.TIMESTAMP],
                         timestamp)
        self.assert_(isinstance(self.publish_callback_value, list))
        self.assertEqual(self.publish_callback_value[0], particle)

    def test_happy_path(self):
        """
        Test the happy path of operations where the parser takes the input
        and spits out a valid data particle given the stream.
        """
        self.stream_handle = StringIO(CtdpfParserUnitTestCase.TEST_DATA)
        self.parser = CtdpfParser(
            self.config, self.position, self.stream_handle, self.pos_callback,
            self.pub_callback)  # last one is the link to the data source

        result = self.parser.get_records(1)
        self.assert_result(result, 137, self.base_timestamp, self.particle_a)
        result = self.parser.get_records(1)
        self.assert_result(result, 174, self.base_timestamp + 1,
                           self.particle_b)
        result = self.parser.get_records(1)
        self.assert_result(result, 211, self.base_timestamp + 2,
                           self.particle_c)
        result = self.parser.get_records(1)
        self.assert_result(result, 248, self.base_timestamp + 3,
                           self.particle_d)

        # no data left, dont move the position
        result = self.parser.get_records(1)
        self.assertEqual(result, [])
        self.assertEqual(self.parser._state[StateKey.POSITION], 248)
        self.assertEqual(self.position_callback_value[StateKey.POSITION], 248)
        self.assertEqual(self.position_callback_value[StateKey.TIMESTAMP],
                         self.base_timestamp + 3)
        self.assert_(isinstance(self.publish_callback_value, list))
        self.assertEqual(self.publish_callback_value[0], self.particle_d)

    def test_get_many(self):
        self.stream_handle = StringIO(CtdpfParserUnitTestCase.TEST_DATA)
        self.parser = CtdpfParser(
            self.config, self.position, self.stream_handle, self.pos_callback,
            self.pub_callback)  # last one is the link to the data source

        result = self.parser.get_records(2)
        self.assertEqual(result, [self.particle_a, self.particle_b])
        self.assertEqual(self.parser._state[StateKey.POSITION], 174)
        self.assertEqual(self.position_callback_value[StateKey.POSITION], 174)
        self.assertEqual(self.position_callback_value[StateKey.TIMESTAMP],
                         self.base_timestamp + 1)
        self.assertEqual(self.publish_callback_value[0], self.particle_a)
        self.assertEqual(self.publish_callback_value[1], self.particle_b)

    def test_bad_data(self):
        """ There's a bad sample in the data! Ack! Skip it! """
        self.stream_handle = StringIO(CtdpfParserUnitTestCase.BAD_TEST_DATA)
        self.parser = CtdpfParser(
            self.config, self.position, self.stream_handle, self.pos_callback,
            self.pub_callback)  # last one is the link to the data source

        result = self.parser.get_records(1)
        self.assert_result(result, 137, self.base_timestamp, self.particle_a)

    def test_no_timestamp(self):
        """ There's no timestamp in the data! Ack! """
        self.stream_handle = StringIO(
            CtdpfParserUnitTestCase.NO_TIME_TEST_DATA)
        self.parser = CtdpfParser(
            self.config, self.position, self.stream_handle, self.pos_callback,
            self.pub_callback)  # last one is the link to the data source

        with self.assertRaises(SampleException):
            self.parser.get_records(1)

    def test_long_stream(self):
        self.stream_handle = StringIO(CtdpfParserUnitTestCase.LONG_DATA)
        self.parser = CtdpfParser(
            self.config, self.position, self.stream_handle, self.pos_callback,
            self.pub_callback)  # last one is the link to the data source

        result = self.parser.get_records(44)
        self.assertEqual(result[-1], self.particle_z)
        self.assertEqual(self.parser._state[StateKey.POSITION], 1728)
        self.assertEqual(self.position_callback_value[StateKey.POSITION], 1728)
        self.assertEqual(self.position_callback_value[StateKey.TIMESTAMP],
                         self.base_timestamp + 43)
        self.assertEqual(self.publish_callback_value[-1], self.particle_z)

    def test_mid_state_start(self):
        new_state = {
            StateKey.POSITION: 211,
            StateKey.TIMESTAMP: self.base_timestamp + 2
        }
        self.stream_handle = StringIO(CtdpfParserUnitTestCase.TEST_DATA)
        self.parser = CtdpfParser(
            self.config, new_state, self.stream_handle, self.pos_callback,
            self.pub_callback)  # last one is the link to the data source
        result = self.parser.get_records(1)
        self.assert_result(result, 248, self.base_timestamp + 3,
                           self.particle_d)

    def test_set_state(self):
        new_state = {
            StateKey.POSITION: 174,
            StateKey.TIMESTAMP: self.base_timestamp + 1
        }
        self.stream_handle = StringIO(CtdpfParserUnitTestCase.TEST_DATA)
        self.parser = CtdpfParser(
            self.config, self.position, self.stream_handle, self.pos_callback,
            self.pub_callback)  # last one is the link to the data source
        result = self.parser.get_records(1)
        self.assert_result(result, 137, self.base_timestamp, self.particle_a)

        self.parser.set_state(new_state)
        result = self.parser.get_records(1)
        self.assert_result(result, 212, self.base_timestamp + 2,
                           self.particle_c)
        result = self.parser.get_records(1)
        self.assert_result(result, 249, self.base_timestamp + 3,
                           self.particle_d)

    def test_mid_timestamp(self):
        self.stream_handle = StringIO(
            CtdpfParserUnitTestCase.MID_TIMESTAMP_DATA)
        self.parser = CtdpfParser(
            self.config, self.position, self.stream_handle, self.pos_callback,
            self.pub_callback)  # last one is the link to the data source

        result = self.parser.get_records(1)
        self.assert_result(result, 137, self.base_timestamp, self.particle_a)

        result = self.parser.get_records(1)
        self.assert_result(result, 193, self.base_timestamp + 60,
                           self.particle_e)