diff --git a/sohstationviewer/controller/plottingData.py b/sohstationviewer/controller/plottingData.py index 098409ac0ee480ac446dd6d3ad532369214ad3d6..a561376855f756a5149031e80b15144ee2aefe3f 100755 --- a/sohstationviewer/controller/plottingData.py +++ b/sohstationviewer/controller/plottingData.py @@ -7,7 +7,6 @@ import math from obspy import UTCDateTime from sohstationviewer.conf import constants as const - maxInt = 1E100 maxFloat = 1.0E100 @@ -36,10 +35,12 @@ def getMassposValueColors(rangeOpt, chan_id, cMode, processing_log, if rangeOpt.lower() not in MassPosVoltRanges.keys(): processing_log.append( - f"{chan_id}: The current selected Mass Position color range is " - f"'{rangeOpt}' isn't allowable. The accept ranges are: " - f"{', '.join(MassPosVoltRanges.keys())}", - "error" + ( + f"{chan_id}: The current selected Mass Position color range is" + f" '{rangeOpt}' isn't allowable. The accept ranges are: " + f"{', '.join(MassPosVoltRanges.keys())}", + "error" + ) ) return massPosVoltRange = MassPosVoltRanges[rangeOpt] @@ -54,7 +55,8 @@ def getMassposValueColors(rangeOpt, chan_id, cMode, processing_log, if i == len(massPosVoltRange) - 1: if retType == 'str': valueColors.append( - "%s:+%s" % (massPosVoltRange[i], massPosColorPallet[i+1])) + "%s:+%s" % ( + massPosVoltRange[i], massPosColorPallet[i + 1])) else: valueColors.append( (massPosVoltRange[i], massPosColorPallet[i + 1])) @@ -102,7 +104,7 @@ def getTitle(key, minTime, maxTime, dateMode): :return: title for the plot - str """ diff = maxTime - minTime - hours = diff/3600 + hours = diff / 3600 return ("%s %s to %s (%s)" % (key, formatTime(minTime, dateMode, "HH:MM:SS"), @@ -193,10 +195,10 @@ def getDayTicks(): """ times = list(range(const.NO_5M_1H, const.NO_5M_DAY, const.NO_5M_1H)) - majorTimes = list(range(4*const.NO_5M_1H, + majorTimes = list(range(4 * const.NO_5M_1H, const.NO_5M_DAY, - 4*const.NO_5M_1H)) - majorTimeLabels = ["%02d" % int(t/const.NO_5M_1H) for t in majorTimes] + 4 * const.NO_5M_1H)) + majorTimeLabels = ["%02d" % int(t / const.NO_5M_1H) for t in majorTimes] return times, majorTimes, majorTimeLabels diff --git a/tests/test_controller/test_plotting_data.py b/tests/test_controller/test_plotting_data.py new file mode 100644 index 0000000000000000000000000000000000000000..c784da7178b41599b27ea019ae7febc45edfdce2 --- /dev/null +++ b/tests/test_controller/test_plotting_data.py @@ -0,0 +1,649 @@ +"""Tests for functions defined in sohstationviewer.controller.plottingData""" + +from unittest import TestCase + +from obspy import UTCDateTime + +from sohstationviewer.controller.plottingData import ( + getMassposValueColors, + formatTime, + getTitle, + getGaps, + getTimeTicks, + getDayTicks, + getUnitBitweight +) + + +class TestGetGaps(TestCase): + """Test suite for getGaps.""" + def test_mixed_gap_sizes(self): + """ + Test getGaps - the given list of gaps contain both gaps that are too + short and gaps that are long enough. + """ + gaps = [(0, 60), (60, 180), (180, 360)] + min_gap = 3 + self.assertListEqual(getGaps(gaps, min_gap), [(180, 360)]) + + def test_empty_gap_list(self): + """ + Test getGaps - the given list of gaps is empty. + """ + gaps = [] + min_gap = 3 + self.assertListEqual(getGaps(gaps, min_gap), []) + + def test_all_gaps_are_too_short(self): + """ + Test getGaps - the given list of gaps only contain gaps that are too + short. + """ + gaps = [(0, 60), (60, 180)] + min_gap = 3 + self.assertListEqual(getGaps(gaps, min_gap), []) + + def test_all_gaps_are_long_enough(self): + """ + Test getGaps - the given list of gaps only contain gaps that are long + enough. + """ + gaps = [(0, 180), (180, 360)] + min_gap = 3 + self.assertListEqual(getGaps(gaps, min_gap), [(0, 180), (180, 360)]) + + +class TestGetDayTicks(TestCase): + """Test suite for getDayTicks.""" + def test_get_day_ticks(self): + """Test getDayTicks.""" + expected = ( + [12, 24, 36, 48, 60, 72, 84, 96, 108, 120, 132, 144, 156, 168, 180, + 192, 204, 216, 228, 240, 252, 264, 276], + [48, 96, 144, 192, 240], + ['04', '08', '12', '16', '20'] + ) + self.assertTupleEqual(getDayTicks(), expected) + + +class TestGetMassposValue(TestCase): + """Test suite for getMasspossValue""" + def test_string_output(self): + """ + Test basic functionality of getMassposValueColors - the range option + and color mode are correct, and the output is a string. + """ + expected_input_output_pairs = { + ('regular', 'B'): '0.5:C|2.0:G|4.0:Y|7.0:R|7.0:+M', + ('regular', 'W'): '0.5:B|2.0:B|4.0:B|7.0:B|7.0:+B', + ('trillium', 'B'): '0.5:C|1.8:G|2.4:Y|3.5:R|3.5:+M', + ('trillium', 'W'): '0.5:B|1.8:B|2.4:B|3.5:B|3.5:+B', + } + test_names = ( + 'test_regular_B', + 'test_regular_W', + 'test_trillium_B', + 'test_trillium_W', + ) + idx = 0 + for input_val in expected_input_output_pairs: + with self.subTest(test_names[idx]): + self.assertEqual( + getMassposValueColors(input_val[0], '', input_val[1], []), + expected_input_output_pairs[input_val] + ) + idx += 1 + + def test_list_output(self): + """ + Test basic functionality of getMassposValueColors - the range option + and color mode are correct, and the output is a list. + """ + expected_input_output_pairs = { + ('regular', 'B'): + [(0.5, 'C'), (2.0, 'G'), (4.0, 'Y'), (7.0, 'R'), (7.0, 'M')], + ('regular', 'W'): + [(0.5, 'B'), (2.0, 'B'), (4.0, 'B'), (7.0, 'B'), (7.0, 'B')], + ('trillium', 'B'): + [(0.5, 'C'), (1.8, 'G'), (2.4, 'Y'), (3.5, 'R'), (3.5, 'M')], + ('trillium', 'W'): + [(0.5, 'B'), (1.8, 'B'), (2.4, 'B'), (3.5, 'B'), (3.5, 'B')], + } + test_names = ( + 'test_regular_B', + 'test_regular_W', + 'test_trillium_B', + 'test_trillium_W', + ) + for i, input_val in enumerate(expected_input_output_pairs): + with self.subTest(test_names[i]): + self.assertListEqual( + getMassposValueColors( + input_val[0], '', input_val[1], [], retType=''), + expected_input_output_pairs[input_val] + ) + + def test_range_option_not_supported(self): + """ + Test basic functionality of getMassposValueColors - the range option + is not supported. + """ + errors = [] + empty_color_option = '' + self.assertIsNone( + getMassposValueColors(empty_color_option, '', 'B', errors)) + self.assertGreater(len(errors), 0) + + errors = [] + bad_color_option = 'unsupported' + self.assertIsNone( + getMassposValueColors(bad_color_option, '', 'B', errors)) + self.assertGreater(len(errors), 0) + + def test_color_mode_not_supported(self): + """ + Test basic functionality of getMassposValueColors - the color mode is + not supported. + """ + errors = [] + empty_color_mode = '' + with self.assertRaises(KeyError): + getMassposValueColors('regular', '', empty_color_mode, errors) + + errors = [] + bad_color_mode = 'unsupported' + with self.assertRaises(KeyError): + getMassposValueColors('regular', '', bad_color_mode, errors) + + +class TestGetTimeTicks(TestCase): + """Test suite for getTimeTicks.""" + def setUp(self) -> None: + """Set up text fixtures.""" + self.label_cnt = 5 + self.date_fmt = 'YYYYMMDD' + + def test_expected_time_range(self): + """ + Test basic functionality of getTimeTicks - the given time range is + expected in the data. + """ + + with self.subTest('test_less_than_a_minute'): + earliest = UTCDateTime(1970, 1, 1, 0, 0, 0).timestamp + latest = UTCDateTime(1970, 1, 1, 0, 0, 5).timestamp + expected = ( + [1.0, 2.0, 3.0, 4.0], + [1.0, 2.0, 3.0, 4.0], + ['19700101 00:00:01', '19700101 00:00:02', + '19700101 00:00:03', '19700101 00:00:04'] + ) + self.assertTupleEqual( + getTimeTicks(earliest, latest, self.date_fmt, self.label_cnt), + expected + ) + + with self.subTest('test_at_least_a_minute'): + earliest = UTCDateTime(1970, 1, 1, 0, 0, 0).timestamp + latest = UTCDateTime(1970, 1, 1, 0, 5, 53).timestamp + expected = ( + [60.0, 120.0, 180.0, 240.0, 300.0], + [60.0, 120.0, 180.0, 240.0, 300.0], + ['19700101 00:01:00', '19700101 00:02:00', '19700101 00:03:00', + '19700101 00:04:00', '19700101 00:05:00'] + ) + self.assertTupleEqual( + getTimeTicks(earliest, latest, self.date_fmt, self.label_cnt), + expected + ) + + with self.subTest('test_at_least_an_hour'): + earliest = UTCDateTime(1970, 1, 1, 0, 0, 0).timestamp + latest = UTCDateTime(1970, 1, 1, 7, 45, 51).timestamp + expected = ( + [3600.0, 7200.0, 10800.0, 14400.0, 18000.0, 21600.0, 25200.0], + [3600.0, 10800.0, 18000.0, 25200.0], + ['19700101 01:00', '19700101 03:00', '19700101 05:00', + '19700101 07:00'] + ) + self.assertTupleEqual( + getTimeTicks(earliest, latest, self.date_fmt, self.label_cnt), + expected + ) + + with self.subTest('test_at_least_ten_days'): + # Exactly 10 days + earliest = UTCDateTime(1970, 1, 1, 0, 0, 0).timestamp + latest = UTCDateTime(1970, 1, 11, 0, 0, 0).timestamp + expected = ( + [86400.0, 172800.0, 259200.0, 345600.0, 432000.0, + 518400.0, 604800.0, 691200.0, 777600.0], + [86400.0, 259200.0, 432000.0, 604800.0, 777600.0], + ['19700102', '19700104', '19700106', '19700108', '19700110'] + ) + self.assertTupleEqual( + getTimeTicks(earliest, latest, self.date_fmt, self.label_cnt), + expected + ) + + # More than 10 days but fewer than 30 days + earliest = UTCDateTime(1970, 1, 1, 0, 0, 0).timestamp + latest = UTCDateTime(1970, 1, 14, 3, 5, 21).timestamp + expected = ( + [86400.0, 172800.0, 259200.0, 345600.0, 432000.0, + 518400.0, 604800.0, 691200.0, 777600.0, 864000.0, + 950400.0, 1036800.0, 1123200.0], + [86400.0, 345600.0, 604800.0, 864000.0, 1123200.0], + ['19700102', '19700105', '19700108', '19700111', '19700114'] + ) + self.assertTupleEqual( + getTimeTicks(earliest, latest, self.date_fmt, self.label_cnt), + expected + ) + + with self.subTest('test_at_least_thirty_days'): + # Exactly 30 days + earliest = UTCDateTime(1970, 1, 1, 0, 0, 0).timestamp + latest = UTCDateTime(1970, 1, 31, 0, 0, 0).timestamp + expected = ([864000.0, 1728000.0], + [864000.0, 1728000.0], + ['19700111', '19700121']) + self.assertTupleEqual( + getTimeTicks(earliest, latest, self.date_fmt, self.label_cnt), + expected + ) + + # More than 30 days + earliest = UTCDateTime(1970, 1, 1, 0, 0, 0).timestamp + latest = UTCDateTime(1970, 3, 21, 21, 43, 53).timestamp + expected = ( + [864000.0, 1728000.0, 2592000.0, 3456000.0, 4320000.0, + 5184000.0, 6048000.0], + [864000.0, 2592000.0, 4320000.0, 6048000.0], + ['19700111', '19700131', '19700220', '19700312'] + ) + self.assertTupleEqual( + getTimeTicks(earliest, latest, self.date_fmt, self.label_cnt), + expected + ) + + def test_boundary_time_range(self): + """ + Test basic functionality of getTimeTicks - the given time range is + exactly 1 second, 1 minute, or 1 hour. Test the behavior where these + time ranges make getTimeTicks returns a tuple that contains empty + lists. + """ + expected = ([], [], []) + with self.subTest('test_exactly_one_second'): + earliest = UTCDateTime(1970, 1, 1, 0, 0, 0).timestamp + latest = UTCDateTime(1970, 1, 1, 0, 0, 1).timestamp + self.assertTupleEqual( + getTimeTicks(earliest, latest, self.date_fmt, self.label_cnt), + expected + ) + with self.subTest('test_exactly_one_minute'): + earliest = UTCDateTime(1970, 1, 1, 0, 0, 0).timestamp + latest = UTCDateTime(1970, 1, 1, 0, 1, 0).timestamp + self.assertTupleEqual( + getTimeTicks(earliest, latest, self.date_fmt, self.label_cnt), + expected + ) + with self.subTest('test_exactly_one_hour'): + earliest = UTCDateTime(1970, 1, 1, 0, 0, 0).timestamp + latest = UTCDateTime(1970, 1, 1, 1, 0, 0).timestamp + self.assertTupleEqual( + getTimeTicks(earliest, latest, self.date_fmt, self.label_cnt), + expected + ) + + def test_earliest_time_later_than_latest_time(self): + """ + Test basic functionality of getTimeTicks - the given latest time is + earlier than the earliest time. + """ + self.assertTupleEqual( + getTimeTicks(100, 0, self.date_fmt, self.label_cnt), + ([], [], []) + ) + + def test_time_range_is_zero(self): + """ + Test basic functionality of getTimeTicks - the given time range is 0. + """ + self.assertTupleEqual( + getTimeTicks(0, 0, self.date_fmt, self.label_cnt), + ([], [], []) + ) + + def test_get_time_ticks_no_label_displayed(self): + """ + Test basic functionality of getTimeTicks - no time label is requested + to be displayed. + """ + zero_label_cnt = 0 + with self.assertRaises(ZeroDivisionError): + getTimeTicks(0, 1000, self.date_fmt, zero_label_cnt) + + +class TestFormatTimeAndGetTitle(TestCase): + """Test suite for formatTime and getTitle""" + def setUp(self) -> None: + """Set up text fixtures.""" + self.positive_epoch_time = 67567567 + self.positive_formatted_dates = { + 'YYYY-MM-DD': '1972-02-22', + 'YYYYMMDD': '19720222', + 'YYYY:DOY': '1972:053', + } + self.positive_formatted_time = '00:46:07' + + self.negative_epoch_time = -67567567 + self.negative_formatted_dates = { + 'YYYY-MM-DD': '1967-11-10', + 'YYYYMMDD': '19671110', + 'YYYY:DOY': '1967:314', + } + self.negative_formatted_time = '23:13:53' + + def test_format_time_epoch_time_date_only(self): + """ + Test basic functionality of formatTime - given time is epoch time and + uses only a date format. Tests three cases for each date format: epoch + time is positive, negative, and zero. + """ + # formatter:off + test_name_to_date_mode_map = { + 'test_year_month_day_format': 'YYYY-MM-DD', + 'test_year_month_day_format_no_dash': 'YYYYMMDD', + 'test_day_of_year_format': 'YYYY:DOY' + } + zero_epoch_formatted = { + 'test_year_month_day_format': '1970-01-01', + 'test_year_month_day_format_no_dash': '19700101', + 'test_day_of_year_format': '1970:001', + } + # formatter:on + for test_name, date_mode in test_name_to_date_mode_map.items(): + with self.subTest(test_name): + self.assertEqual( + formatTime(self.positive_epoch_time, date_mode), + self.positive_formatted_dates[date_mode]) + self.assertEqual( + formatTime(self.negative_epoch_time, date_mode), + self.negative_formatted_dates[date_mode]) + self.assertEqual( + formatTime(0, date_mode), + zero_epoch_formatted[test_name]) + + def test_format_time_epoch_time_date_and_time(self): + """ + Test basic functionality of formatTime - given time is epoch time and + both a time and a date format are used. Tests three cases for each date + format: epoch time is positive, negative, and zero. + """ + # formatter:off + test_name_to_date_mode_map = { + 'test_year_month_day_format': 'YYYY-MM-DD', + 'test_year_month_day_format_no_dash': 'YYYYMMDD', + 'test_day_of_year_format': 'YYYY:DOY', + } + zero_epoch_formatted = { + 'test_year_month_day_format': '1970-01-01 00:00:00', + 'test_year_month_day_format_no_dash': '19700101 00:00:00', + 'test_day_of_year_format': '1970:001 00:00:00', + } + # formatter:on + for test_name, date_mode in test_name_to_date_mode_map.items(): + with self.subTest(test_name): + positive_time_expected = ( + f'{self.positive_formatted_dates[date_mode]} ' + f'{self.positive_formatted_time}' + ) + negative_time_expected = ( + f'{self.negative_formatted_dates[date_mode]} ' + f'{self.negative_formatted_time}' + ) + + self.assertEqual( + formatTime(self.positive_epoch_time, date_mode, + 'HH:MM:SS'), + positive_time_expected + ) + self.assertEqual( + formatTime(self.negative_epoch_time, date_mode, + 'HH:MM:SS'), + negative_time_expected + ) + self.assertEqual(formatTime(0, date_mode, 'HH:MM:SS'), + zero_epoch_formatted[test_name]) + + def test_format_time_UTCDateTime_date_only(self): + """ + Test basic functionality of formatTime - given time is an UTCDateTime + instance and uses only a date format. + """ + test_name_to_date_mode_map = { + 'test_year_month_day_format': 'YYYY-MM-DD', + 'test_year_month_day_format_no_dash': 'YYYYMMDD', + 'test_day_of_year_format': 'YYYY:DOY', + } + utc_date_time = UTCDateTime(self.positive_epoch_time) + expected_dates = self.positive_formatted_dates + for test_name, date_mode in test_name_to_date_mode_map.items(): + with self.subTest(test_name): + self.assertEqual(formatTime(utc_date_time, date_mode), + expected_dates[date_mode]) + + def test_format_time_UTCDateTime_date_and_time(self): + """ + Test basic functionality of formatTime - given time is an UTCDateTime + instance and both a time and a date format are used. + """ + test_name_to_date_mode_map = { + 'test_year_month_day_format': 'YYYY-MM-DD', + 'test_year_month_day_format_no_dash': 'YYYYMMDD', + 'test_day_of_year_format': 'YYYY:DOY', + } + test_time = UTCDateTime(self.positive_epoch_time) + expected_dates = self.positive_formatted_dates + expected_time = self.positive_formatted_time + for test_name, date_mode in test_name_to_date_mode_map.items(): + with self.subTest('test_year_month_day_format'): + self.assertEqual( + formatTime(test_time, date_mode, 'HH:MM:SS'), + f'{expected_dates[date_mode]} {expected_time}' + ) + + def test_format_time_unsupported_date_format(self): + """ + Test basic functionality of formatTime - given date format is not + supported. + """ + test_time = self.positive_epoch_time + empty_format = '' + bad_format = 'bad_format' + + with self.subTest('test_without_time_format'): + expected = '' + self.assertEqual(formatTime(test_time, empty_format), + expected) + self.assertEqual(formatTime(test_time, bad_format), + expected) + + with self.subTest('test_with_time_format'): + expected = f' {self.positive_formatted_time}' + self.assertEqual(formatTime(test_time, empty_format, 'HH:MM:SS'), + expected) + self.assertEqual(formatTime(test_time, bad_format, 'HH:MM:SS'), + expected) + + def test_format_time_unsupported_time_format(self): + """ + Test basic functionality of formatTime - given time format is not + supported. + """ + test_time = self.positive_epoch_time + date_format = 'YYYYMMDD' + empty_format = '' + bad_format = 'bad_format' + + expected = self.positive_formatted_dates[date_format] + self.assertEqual(formatTime(test_time, date_format, empty_format), + expected) + self.assertEqual(formatTime(test_time, date_format, bad_format), + expected) + + def test_format_time_unsupported_date_and_time_format(self): + """ + Test basic functionality of formatTime - both given date and time + format are unsupported. + """ + test_time = self.positive_epoch_time + expected = '' + bad_date_formats = ['', 'bad_date_format'] + bad_time_format = ['', 'bad_time_format'] + for date_format in bad_date_formats: + for time_format in bad_time_format: + self.assertEqual( + formatTime(test_time, date_format, time_format), + expected + ) + + def test_get_title(self): + """Test basic functionality of getTitle.""" + date_mode = 'YYYYMMDD' + min_time = 0 + max_time = self.positive_epoch_time + formatted_max_time = (f'{self.positive_formatted_dates[date_mode]}' + f' {self.positive_formatted_time}') + with self.subTest('test_mseed'): + key = '3734' + expected = (f'3734 19700101 00:00:00 to ' + f'{formatted_max_time} (18768.77)') + self.assertEqual(getTitle(key, min_time, max_time, date_mode), + expected) + with self.subTest('test_rt130'): + key = ('92EB', 25) + expected = (f"('92EB', 25) 19700101 00:00:00 to " + f"{formatted_max_time} (18768.77)") + self.assertEqual(getTitle(key, min_time, max_time, date_mode), + expected) + + def test_get_title_max_time_earlier_than_min_time(self): + """ + Test basic functionality of getTitle - the given maximum time is + chronologically earlier than the given minimum time. + """ + date_mode = 'YYYYMMDD' + min_time = self.positive_epoch_time + max_time = 0 + formatted_max_time = (f'{self.positive_formatted_dates[date_mode]}' + f' {self.positive_formatted_time}') + with self.subTest('test_mseed'): + key = '3734' + expected = (f'3734 {formatted_max_time} to ' + f'19700101 00:00:00 (-18768.77)') + self.assertEqual(getTitle(key, min_time, max_time, date_mode), + expected) + with self.subTest('test_rt130'): + key = ('92EB', 25) + expected = (f"('92EB', 25) {formatted_max_time} to " + f"19700101 00:00:00 (-18768.77)") + self.assertEqual(getTitle(key, min_time, max_time, date_mode), + expected) + + +class TestGetUnitBitweight(TestCase): + """Test suite for getUnitBitweight.""" + + def setUp(self) -> None: + """Set up test fixtures.""" + self.chan_info = { + 'channel': 'Test Channel Name', + 'fixPoint': 0, + 'plotType': 'test_plot_type', + 'unit': 'test_unit' + } + # In most cases, we do not care about the value of bitweightOpt. So, we + # give it a default value unless needed. + self.default_bitweight_opt = 'low' + + def test_soh_channel_linesDots_linesSRate_linesMasspos_plot_type(self): + """ + Test basic functionality of getUnitBitweight - the given plot type is + linesDots, linesSRate, or linesMassposs. + """ + self.chan_info['plotType'] = 'linesDots' + with self.subTest('test_no_fix_point'): + self.assertEqual( + getUnitBitweight(self.chan_info, self.default_bitweight_opt), + '{}test_unit' + ) + with self.subTest('test_have_fix_point'): + self.chan_info['fixPoint'] = 1 + self.assertEqual( + getUnitBitweight(self.chan_info, self.default_bitweight_opt), + '{:.1f}test_unit' + ) + + def test_soh_channel_other_plot_type(self): + """ + Test basic functionality of getUnitBitweight - the given plot type is + not linesDots, linesSRate, or linesMassposs and the channel is not a + seismic data channel. + """ + self.assertEqual( + getUnitBitweight(self.chan_info, self.default_bitweight_opt), + '' + ) + + def test_seismic_channel_have_fix_point(self): + """ + Test basic functionality of getUnitBitweight - the given plot type is + not linesDots, linesSRate, or linesMassposs, the channel is a + seismic data channel, and there is a fix point. + """ + self.chan_info['channel'] = 'SEISMIC' + self.chan_info['fixPoint'] = 1 + self.assertEqual( + getUnitBitweight(self.chan_info, self.default_bitweight_opt), + '{:.1f}test_unit' + ) + + def test_seismic_channel_no_fix_point(self): + """ + Test basic functionality of getUnitBitweight - the given plot type is + not linesDots, linesSRate, or linesMassposs, the channel is a + seismic data channel, and there is no fix point. + """ + self.chan_info['channel'] = 'SEISMIC' + with self.subTest('test_no_bitweight_option'): + self.assertEqual(getUnitBitweight(self.chan_info, 'high'), '{}V') + with self.subTest('test_have_bitweight_option'): + self.assertEqual(getUnitBitweight(self.chan_info, ''), + '{}test_unit') + + def test_no_fix_point(self): + """ + Test basic functionality of getUnitBitweight - the given channel info + does not contain a value for fixPoint. + """ + del self.chan_info['fixPoint'] + # Asserts that an error is not raised. TestCase does not have a method + # to check that an exception was not raised so we have to use this + # workaround. For more discussion on this topic, see these + # stackoverflow questions and the answers + # https://stackoverflow.com/questions/6181555/pass-a-python-unittest-if-an-exception-isnt-raised?noredirect=1&lq=1 # noqa + # https://stackoverflow.com/questions/4319825/python-unittest-opposite-of-assertraises/4319870#4319870 # noqa:E501 + + # Some context for this code: in getUnitBitWeight, if chanDB does not + # have 'fix_point' as a key, then the value of fix_point defaults to 0. + # This is implemented by getting the value of 'fix_point' in chanDB and + # catching the resulting KeyError. So, in order to test that + # getUnitBitweight handles this case correctly, we assert that no + # exception was raised. + try: + getUnitBitweight(self.chan_info, '') + except KeyError: + self.fail()