Skip to content
Snippets Groups Projects
test_lemi_metadata.py 36.5 KiB
Newer Older
# -*- coding: utf-8 -*-

"""Tests for `lemi_metadata` module."""

import logging
import openpyxl
import pickle
import unittest

from obspy import UTCDateTime
from pathlib import Path

from lemi2seed.lemi_data import LemiData, VALID_COMPONENTS
from lemi2seed.lemi_metadata import (BaseSurvey, Survey, BaseStation, Station_,
                                     Run, Electric, Magnetic, Auxiliary,
                                     LemiMetadata, log_file_path)
from lemi2seed.utils import MSG_E_CHA
OUTPUT_MSEED = Path(__file__).resolve().parent.joinpath('MSEED')
OUTPUT_XML = Path(__file__).resolve().parent.joinpath('STATIONXML')
TEST_DIR = Path(__file__).resolve().parent.joinpath('test_data')
SCR_DIR = "lemi2seed.lemi_metadata"

logging.config.fileConfig(log_file_path)
logger = logging.getLogger(SCR_DIR)


class TestBaseSurvey(unittest.TestCase):
    """Test suite for BaseSurvey data class."""

    def setUp(self):
        """Set up test fixtures"""
        lemi_data = LemiData(TEST_DIR.joinpath("EM", "TEST1"), OUTPUT_MSEED)
        lemi_data.prep_data()
        self.data_stats = lemi_data.stats

    def test_validate_time_period_start_not_utc(self):
        """Test basic functionality of validate_time_period_start."""
        data_input = self.data_stats['time_period_start']
        metadata_input = 2021.167
        bs = BaseSurvey()
        self.assertFalse(bs.validate_time_period_start(metadata_input, data_input))

    def test_validate_time_period_start_greater_than_acquisition_start(self):
        """Test basic functionality of validate_time_period_start."""
        data_input = self.data_stats['time_period_start']
        metadata_input = UTCDateTime('2020-10-01T00:00:00.000000Z')
        bs = BaseSurvey()
        self.assertFalse(bs.validate_time_period_start(metadata_input, data_input))

    def test_validate_time_period_start_valid(self):
        """Test basic functionality of validate_time_period_start."""
        data_input = self.data_stats['time_period_start']
        metadata_input = UTCDateTime('2020-09-30T00:00:00.000000Z')
        bs = BaseSurvey()
        self.assertTrue(bs.validate_time_period_start(metadata_input, data_input))

    def test_validate_time_period_end_not_utc(self):
        """Test basic functionality of validate_time_period_end."""
        data_input = self.data_stats['time_period_end']
        metadata_input = 2021.167
        bs = BaseSurvey()
        self.assertFalse(bs.validate_time_period_end(metadata_input, data_input))

    def test_validate_time_period_end_lower_than_acquisition_end(self):
        """Test basic functionality of validate_time_period_end."""
        data_input = self.data_stats['time_period_end']
        metadata_input = UTCDateTime('2020-09-30T00:00:00.000000Z')
        bs = BaseSurvey()
        self.assertFalse(bs.validate_time_period_end(metadata_input, data_input))

    def test_validate_time_period_end_valid(self):
        """Test basic functionality of validate_time_period_end."""
        data_input = self.data_stats['time_period_end']
        metadata_input = UTCDateTime('2020-10-02T00:00:00.000000Z')
        bs = BaseSurvey()
        self.assertTrue(bs.validate_time_period_end(metadata_input, data_input))


class TestSurvey(unittest.TestCase):
    """Test suite for Survey data class."""

    def test_validate_archive_network_undefined(self):
        """Test basic functionality of validate_archive_network."""
        with self.assertLogs(logger, level='ERROR') as cmd:
            Survey.validate_archive_network(None)
        msg = "The network code should be a string."
        self.assertEqual(cmd.output, [":".join(['ERROR', SCR_DIR, msg])])

    def test_validate_archive_network_erroneous_type(self):
        """Test basic functionality of validate_archive_network."""
        with self.assertLogs(logger, level='ERROR') as cmd:
            Survey.validate_archive_network(12)
        msg = "The network code should be a string."
        self.assertEqual(cmd.output, [":".join(['ERROR', SCR_DIR, msg])])

    def test_validate_archive_network_invalid(self):
        """Test basic functionality of validate_archive_network."""
        with self.assertLogs(logger, level='ERROR') as cmd:
            Survey.validate_archive_network('EMX')
        msg = "The network code should be two alphanumeric character long."
        self.assertEqual(cmd.output, [":".join(['ERROR', SCR_DIR, msg])])

    def test_validate_archive_network_valid(self):
        """Test basic functionality of validate_archive_network."""
        self.assertTrue(Survey.validate_archive_network('EM'))

    def test_validate_citation_dataset_doi_undefined(self):
        """Test basic functionality of validate_citation_dataset_doi."""
        with self.assertLogs(logger, level='ERROR') as cmd:
            Survey.validate_citation_dataset_doi(None)
        msg = "The DOI number(s) should be a string."
        self.assertEqual(cmd.output, [":".join(['ERROR', SCR_DIR, msg])])

    def test_validate_citation_dataset_doi_erroneous_type(self):
        """Test basic functionality of validate_citation_dataset_doi."""
        with self.assertLogs(logger, level='ERROR') as cmd:
            Survey.validate_citation_dataset_doi(10.7914)
        msg = "The DOI number(s) should be a string."
        self.assertEqual(cmd.output, [":".join(['ERROR', SCR_DIR, msg])])

    def test_validate_citation_dataset_doi_invalid_doi(self):
        """Test basic functionality of validate_citation_dataset_doi."""
        with self.assertLogs(logger, level='ERROR') as cmd:
            Survey.validate_citation_dataset_doi('10.7914/SN/EM')
        msg = ("Invalid DOI(s). The DOI number(s) provided by the archive "
               "should be strings formatted as follows: 'scheme: path'.")
        self.assertEqual(cmd.output, [":".join(['ERROR', SCR_DIR, msg])])

    def test_validate_citation_dataset_doi_invalid_dois(self):
        """Test basic functionality of validate_citation_dataset_doi."""
        dois = '10.7914/SN/EM, DOI:10.3421/SN/EG'
        with self.assertLogs(logger, level='ERROR') as cmd:
            Survey.validate_citation_dataset_doi(dois)
        msg = ("Invalid DOI(s). The DOI number(s) provided by the archive "
               "should be strings formatted as follows: 'scheme: path'.")
        self.assertEqual(cmd.output, [":".join(['ERROR', SCR_DIR, msg])])

    def test_validate_citation_dataset_doi_valid_doi(self):
        """Test basic functionality of validate_citation_dataset_doi."""
        doi = 'DOI:10.7914/SN/EM'
        self.assertTrue(Survey.validate_citation_dataset_doi(doi))

    def test_validate_citation_dataset_doi_valid_dois(self):
        """Test basic functionality of validate_citation_dataset_doi."""
        dois = 'DOI:10.7914/SN/EM, DOI:10.3421/SN/EG'
        self.assertTrue(Survey.validate_citation_dataset_doi(dois))

    def test_validate_project_lead_email_undefined(self):
        """Test basic functionality of validate_project_lead_email."""
        self.assertTrue(Survey.validate_project_lead_email(None))

    def test_validate_project_lead_email_erroneous_type(self):
        """Test basic functionality of validate_project_lead_email."""
        with self.assertLogs(logger, level='ERROR') as cmd:
            Survey.validate_project_lead_email(12)
        msg = "The project lead email(s) should be a string."
        self.assertEqual(cmd.output, [":".join(['ERROR', SCR_DIR, msg])])

    def test_validate_project_lead_email_invalid_email(self):
        """Test basic functionality of validate_project_lead_email."""
        email = 'mpasscal.edu'
        self.assertFalse(Survey.validate_project_lead_email(email))

    def test_validate_project_lead_email_invalid_emails(self):
        """Test basic functionality of validate_project_lead_email."""
        emails = 'mpasscal.edu, d@passcal.edu'
        self.assertFalse(Survey.validate_project_lead_email(emails))

    def test_validate_project_lead_email_valid_email(self):
        """Test basic functionality of validate_citation_dataset_doi."""
        email = 'm@passcal.edu'
        self.assertTrue(Survey.validate_project_lead_email(email))

    def test_validate_project_lead_email_valid_emails(self):
        """Test basic functionality of validate_citation_dataset_doi."""
        emails = 'm@passcal.edu, d@passcal.edu'
        self.assertTrue(Survey.validate_project_lead_email(emails))


class TestBaseStation(unittest.TestCase):
    """Test suite for BaseStation data class."""

    def setUp(self):
        """Set up test fixtures"""
        data_input = 2201.77
        min_elev, max_elev = [abs(data_input) * x for x in [0.99, 1.01]]
        param = ("Station elevation", -500, 8500, min_elev, max_elev, 'm', '')
        self.param = param

    def test_validate_geographics_undefined(self):
        """Test basic functionality of validate_geographics."""
        with self.assertLogs(logger, level='ERROR') as cmd:
            BaseStation.validate_geographics(self.param, None)
        msg = "Station elevation should be a float. "
        self.assertEqual(cmd.output, [":".join(['ERROR', SCR_DIR, msg])])

    def test_validate_geographics_erroneous_type(self):
        """Test basic functionality of validate_geographics."""
        with self.assertLogs(logger, level='ERROR') as cmd:
            BaseStation.validate_geographics(self.param, 'a')
        msg = "Station elevation should be a float. "
        self.assertEqual(cmd.output, [":".join(['ERROR', SCR_DIR, msg])])

    def test_validate_geographics_not_in_range(self):
        """Test basic functionality of validate_geographics."""
        geo, min_range, max_range, min_val, max_val, units, msg = self.param
        with self.assertLogs(logger, level='ERROR') as cmd:
            BaseStation.validate_geographics(self.param, 9000)
        msg = ("Unexpected {0}! The {0} should be between {1}{3} and {2}{3}."
               .format(geo, min_range, max_range, units))
        self.assertEqual(cmd.output, [":".join(['ERROR', SCR_DIR, msg])])

    def test_validate_geographics_do_not_match_logger_recorded_metadata(self):
        """Test basic functionality of validate_geographics."""
        geo = 'Station elevation'
        with self.assertLogs(logger, level='ERROR') as cmd:
            BaseStation.validate_geographics(self.param, 2250)
        msg = ("Unexpected {0}! Provided {0} should roughly match the {0} "
               "recorded by the on-site GPS.".format(geo))
        self.assertEqual(cmd.output, [":".join(['ERROR', SCR_DIR, msg])])


class TestStation_(unittest.TestCase):
    """Test suite for Station_ data class."""

    def test_validate_archive_id_undefined(self):
        """Test basic functionality of validate_archive_id."""
        with self.assertLogs(logger, level='ERROR') as cmd:
            Station_.validate_archive_id(None)
        msg = "The station name should be a string."
        self.assertEqual(cmd.output, [":".join(['ERROR', SCR_DIR, msg])])

    def test_validate_archive_id_erroneous_type(self):
        """Test basic functionality of validate_archive_id."""
        with self.assertLogs(logger, level='ERROR') as cmd:
            Station_.validate_archive_id(12)
        msg = "The station name should be a string."
        self.assertEqual(cmd.output, [":".join(['ERROR', SCR_DIR, msg])])

    def test_validate_archive_id_invalid(self):
        """Test basic functionality of validate_archive_id."""
        with self.assertLogs(logger, level='ERROR') as cmd:
            Station_.validate_archive_id('KELLYA')
        msg = ("The station name should be between three and five "
               "alphanumeric character long.")
        self.assertEqual(cmd.output, [":".join(['ERROR', SCR_DIR, msg])])

    def test_validate_archive_id_valid(self):
        """Test basic functionality of validate_archive_id."""
        self.assertTrue(Station_.validate_archive_id('KELLY'))

    def test_validate_submitter_email_undefined(self):
        """Test basic functionality of validate_submitter_email."""
        self.assertTrue(Station_.validate_submitter_email(None))


class TestRun(unittest.TestCase):
    """Test suite for Run data class."""

    def setUp(self):
        """Set up test fixtures"""
        self.run = Run(resource_id='mt.run.id:a')
        lemi_data = LemiData(TEST_DIR.joinpath("EM", "TEST1"), OUTPUT_MSEED)
        lemi_data.prep_data()
        self.data_stats = lemi_data.stats

    def test_validate_components_recorded_undefined(self):
        """Test basic functionality of validate_components_recorded."""
        with self.assertLogs(logger, level='ERROR') as cmd:
            self.run.validate_components_recorded(None)
        msg = ("The list of components recorded for run '{}' should be a "
               "string.".format(self.run.run_id))
        self.assertEqual(cmd.output, [":".join(['ERROR', SCR_DIR, msg])])

    def test_validate_components_recorded_erroneous_type(self):
        """Test basic functionality of validate_components_recorded."""
        with self.assertLogs(logger, level='ERROR') as cmd:
            self.run.validate_components_recorded(12)
        msg = ("The list of components recorded for run '{}' should be a "
               "string.".format(self.run.run_id))
        self.assertEqual(cmd.output, [":".join(['ERROR', SCR_DIR, msg])])

    def test_validate_components_recorded_invalid(self):
        """Test basic functionality of validate_components_recorded."""
        components = 'E1, E2, Hx, Hy, Hn'
        with self.assertLogs(logger, level='ERROR') as cmd:
            self.run.validate_components_recorded(components)
        msg = ("Some of the listed components for run '{}' are not valid. "
               "List of valid components: {}."
               .format(self.run.run_id, VALID_COMPONENTS))
        self.assertEqual(cmd.output, [":".join(['ERROR', SCR_DIR, msg])])

    def test_validate_components_recorded_valid(self):
        """Test basic functionality of validate_components_recorded."""
        components = 'E1, E2, Hx, Hy, Hz'
        self.assertTrue(self.run.validate_components_recorded(components))

    def test_validate_time_period_start_lower_than_acquisition_start(self):
        """Test basic functionality of validate_time_period_start."""
        data_input = self.data_stats['time_period_start']
        metadata_input = UTCDateTime('2020-09-30T00:00:00.000000Z')
        self.assertFalse(self.run.validate_time_period_start(metadata_input, data_input))

    def test_validate_time_period_start_valid(self):
        """Test basic functionality of validate_time_period_start."""
        data_input = self.data_stats['time_period_start']
        metadata_input = UTCDateTime('2020-10-01T00:00:00.000000Z')
        self.assertTrue(self.run.validate_time_period_start(metadata_input, data_input))

    def test_validate_time_period_end_greater_than_acquisition_end(self):
        """Test basic functionality of validate_time_period_end."""
        data_input = self.data_stats['time_period_end']
        metadata_input = UTCDateTime('2020-10-02T00:00:00.000000Z')
        self.assertFalse(self.run.validate_time_period_end(metadata_input, data_input))

    def test_validate_time_period_end_valid(self):
        """Test basic functionality of validate_time_period_end."""
        data_input = self.data_stats['time_period_end']
        metadata_input = UTCDateTime('2020-09-30T00:00:00.000000Z')
        self.assertTrue(self.run.validate_time_period_end(metadata_input, data_input))


class TestElectric(unittest.TestCase):
    """Test suite for Electric data class."""

    def setUp(self):
        """Set up test fixtures"""
        self.elec = Electric(channel_number='E1', run_id='a')
        self.metadata_invalid = {'positive_electrode_direction',
                                 'negative_electrode_direction'}
        self.param = ("contact resistance (start)", 0, 3000, 'Ω')

    def test_set_electric_component_channel_undefined_direction(self):
        """Test basic functionality of set_electric_component_channel."""
        self.elec.positive_electrode_direction = None
        self.elec.negative_electrode_direction = 'West'
        with self.assertLogs(logger, level='ERROR') as cmd:
            self.elec.set_electric_component_channel()
        msg = ("The direction of the positive and negative electrodes should "
               "be either: North, South, East or West. Please, provide "
               "electrode direction(s) for run '{0}' and channel number "
               "'{1}'! {2}".format(self.elec.run_id, self.elec.channel_number, MSG_E_CHA))
        self.assertEqual(cmd.output, [":".join(['ERROR', SCR_DIR, msg])])
        self.assertIsNone(self.elec.component)
        self.assertIsNone(self.elec.channel_name)
        self.assertSetEqual(self.elec.metadata_invalid, self.metadata_invalid)

    def test_set_electric_component_channel_invalid_direction_pair(self):
        """Test basic functionality of set_electric_component_channel."""
        self.elec.positive_electrode_direction = 'North'
        self.elec.negative_electrode_direction = 'West'
        with self.assertLogs(logger, level='WARNING') as cmd:
            self.elec.set_electric_component_channel()
        msg = ("By convention, one electrode pair is installed in a "
               "north-south direction and the other pair in a  east-west "
               "direction (check run '{0}' and channel number '{1}')!"
               .format(self.elec.run_id, self.elec.channel_number))
        self.assertEqual(cmd.output, [":".join(['WARNING', SCR_DIR, msg])])
        self.assertIsNone(self.elec.component)
        self.assertIsNone(self.elec.channel_name)
        self.assertSetEqual(self.elec.metadata_invalid, self.metadata_invalid)

    def test_set_electric_component_channel_same_direction(self):
        """Test basic functionality of set_electric_component_channel."""
        self.elec.positive_electrode_direction = 'North'
        self.elec.negative_electrode_direction = 'North'
        with self.assertLogs(logger, level='ERROR') as cmd:
            self.elec.set_electric_component_channel()
        msg = ("The direction of the positive and negative electrodes in a "
               "given pair cannot be the same (check run '{0}' and channel "
               "number '{1}')!".format(self.elec.run_id, self.elec.channel_number))
        self.assertEqual(cmd.output, [":".join(['ERROR', SCR_DIR, msg])])
        self.assertIsNone(self.elec.component)
        self.assertIsNone(self.elec.channel_name)
        self.assertSetEqual(self.elec.metadata_invalid, self.metadata_invalid)

    def test_set_electric_component_channel_valid(self):
        """Test basic functionality of set_electric_component_channel."""
        self.elec.positive_electrode_direction = 'North'
        self.elec.negative_electrode_direction = 'South'
        self.elec.metadata_invalid = self.metadata_invalid
        self.elec.set_electric_component_channel()
        self.assertEqual(self.elec.component, 'Ex')
        self.assertEqual(self.elec.channel_name, 'LQN')
        self.assertSetEqual(self.elec.metadata_invalid, set())

    def test_set_electrode_info_default(self):
        """Test basic functionality of set_electrode_info."""
        self.elec.instrument_specs = 'Borin STELTH 4 - Silver-Silver Chloride'
        self.elec.set_electrode_info()
        self.assertEqual(self.elec.instrument_manufacturer, "Borin")
        self.assertEqual(self.elec.instrument_model, "STELTH 4")
        self.assertEqual(self.elec.instrument_type, "Silver-Silver Chloride")

    def test_set_electrode_info_user_defined(self):
        """Test basic functionality of set_electrode_info."""
        self.elec.instrument_specs = 'Manufacturer: a - Model: b - Type: c'
        self.elec.set_electrode_info()
        self.assertEqual(self.elec.instrument_manufacturer, "a")
        self.assertEqual(self.elec.instrument_model, "b")
        self.assertEqual(self.elec.instrument_type, "c")

    def test_validate_e_property_undefined(self):
        """Test basic functionality of validate_e_property."""
        e_prop, min_range, max_range, units = self.param
        with self.assertLogs(logger, level='ERROR') as cmd:
            self.elec.validate_e_property(self.param, None)
        msg = ("The {0} for run '{1}' and channel number '{2}' should be a "
               "float. {3}".format(e_prop, self.elec.run_id,
                                   self.elec.channel_number, MSG_E_CHA))
        self.assertEqual(cmd.output, [":".join(['ERROR', SCR_DIR, msg])])

    def test_validate_e_property_erroneous_type(self):
        """Test basic functionality of validate_e_property."""
        e_prop, min_range, max_range, units = self.param
        with self.assertLogs(logger, level='ERROR') as cmd:
            self.elec.validate_e_property(self.param, 'a')
        msg = ("The {0} for run '{1}' and channel number '{2}' should be a "
               "float. {3}".format(e_prop, self.elec.run_id,
                                   self.elec.channel_number, MSG_E_CHA))
        self.assertEqual(cmd.output, [":".join(['ERROR', SCR_DIR, msg])])

    def test_validate_e_property_inferior_to_min_value(self):
        """Test basic functionality of validate_e_property."""
        e_prop, min_range, max_range, units = self.param
        with self.assertLogs(logger, level='ERROR') as cmd:
            self.elec.validate_e_property(self.param, -10)
        msg = ("The {0} for run '{1}' and for channel number '{2}' should be "
               "positive.".format(e_prop, self.elec.run_id, self.elec.channel_number))
        self.assertEqual(cmd.output, [":".join(['ERROR', SCR_DIR, msg])])

    def test_validate_e_property_superior_to_max_value(self):
        """Test basic functionality of validate_e_property."""
        e_prop, min_range, max_range, units = self.param
        with self.assertLogs(logger, level='WARNING') as cmd:
            self.elec.validate_e_property(self.param, 5000)
        msg = ("The {0} for run '{1}' and for channel number '{2}' should be "
               "less than {3}{4}. A {0} > {3}{4} is indicative of poor "
               "contact.".format(e_prop, self.elec.run_id,
                                 self.elec.channel_number, max_range, units))
        self.assertEqual(cmd.output, [":".join(['WARNING', SCR_DIR, msg])])

    def test_validate_e_property_valid(self):
        """Test basic functionality of validate_e_property."""
        self.assertTrue(self.elec.validate_e_property(self.param, 500))
    def test_validate_dipole_length_empty_data_inputs(self):
        """Test basic functionality of validate_dipole_length."""
        user_input = 99
        data_input = {}
        self.assertTrue(self.elec.validate_dipole_length(user_input, data_input))

    def test_validate_dipole_length_mismatch_between_user_and_data_inputs(self):
        """Test basic functionality of validate_dipole_length."""
        user_input = 99
        data_input = {'E1': 101, 'E2': 102, 'E3': 99, 'E4': 95}
        with self.assertLogs(logger, level='ERROR') as cmd:
            valid = self.elec.validate_dipole_length(user_input, data_input)
        msg = ("The dipole length for run '{0}' and channel number '{1}' does "
               "not match the dipole length value that was configured using the "
               "LEMI424 logger in the field (99 != 101)! Update value using the "
               "GUI.".format(self.elec.run_id, self.elec.channel_number))
        self.assertEqual(cmd.output, [":".join(['ERROR', SCR_DIR, msg])])
        self.assertFalse(valid)

    def test_validate_dipole_length_match_between_user_and_data_inputs(self):
        """Test basic functionality of validate_dipole_length."""
        user_input = 99
        data_input = {'E1': 99, 'E2': 102, 'E3': 99, 'E4': 95}
        self.assertTrue(self.elec.validate_dipole_length(user_input, data_input))


class TestMagnetic(unittest.TestCase):
    """Test suite for Magnetic data class."""

    def setUp(self):
        """Set up test fixtures"""
        self.mag = Magnetic()

    def test_set_magnetic_info_default(self):
        """Test basic functionality of set_magnetic_info."""
        self.mag.instrument_specs = 'LEMI-039'
        self.mag.set_magnetic_info()
        self.assertEqual(self.mag.instrument_manufacturer, "LEMI LLC.")
        self.assertEqual(self.mag.instrument_model, "LEMI-039")
        self.assertEqual(self.mag.instrument_type,
                         "3-component analog magnetometer")

    def test_set_magnetic_info_user_defined(self):
        """Test basic functionality of set_magnetic_info."""
        self.mag.instrument_specs = 'Manufacturer: a - Model: b - Type: c'
        self.mag.set_magnetic_info()
        self.assertEqual(self.mag.instrument_manufacturer, "a")
        self.assertEqual(self.mag.instrument_model, "b")
        self.assertEqual(self.mag.instrument_type, "c")


class TestAuxiliary(unittest.TestCase):
    """Test suite for Auxiliary data class."""

    def setUp(self):
        """Set up test fixtures"""
        self.aux = Auxiliary()

    def test_set_auxiliary_info(self):
        """Test basic functionality of set_auxiliary_info."""
        self.aux.set_auxiliary_info()
        self.assertEqual(self.aux.instrument_manufacturer, "LEMI LLC.")
        self.assertEqual(self.aux.instrument_model, "LEMI-424")
        self.assertEqual(self.aux.instrument_type, "long-period 32-bit")

    def test_set_data_type(self):
        """Test basic functionality of set_data_type."""
        self.aux.set_data_type()
        self.assertEqual(self.aux.data_type, "HEALTH")

    def test_set_measurement_azimuth(self):
        """Test basic functionality of set_measurement_azimuth."""
        self.aux.set_measurement_azimuth()
        self.assertEqual(self.aux.measurement_azimuth, 0.0)

    def test_set_measurement_tilt(self):
        """Test basic functionality of set_measurement_tilt."""
        self.aux.set_measurement_tilt()
        self.assertEqual(self.aux.measurement_tilt, 0.0)


class TestLemiMetadata(unittest.TestCase):
    """Test suite for LemiMetadata class."""

    def setUp(self):
        """Set up test fixtures"""
        lemi_data = LemiData(TEST_DIR.joinpath("EM", "TEST5"), OUTPUT_MSEED)
        lemi_data.prep_data()
        self.data = lemi_data
        self.path2metadata = TEST_DIR.joinpath("METADATA")
        self.path2metadata_fail_1 = TEST_DIR.joinpath("METADATA_NO_FIELD_SHEET")
        self.path2metadata_fail_2 = TEST_DIR.joinpath("METADATA_CORRUPTED")
        self.file = self.path2metadata.joinpath('LEMI_Install_Sheet.xlsx')
        self.metadata = LemiMetadata(self.path2metadata, OUTPUT_XML, self.data)
        file_ = self.path2metadata.joinpath('metadata_fields.pkl')
        with open(file_, 'rb') as fin:
            self.metadata_fields_no_reformat = pickle.load(fin)
        file_ = self.path2metadata.joinpath('metadata_fields_reformatted.pkl')
        with open(file_, 'rb') as fin:
            self.metadata_fields = pickle.load(fin)

    def test_scan_path2metadata_field_sheet_provided(self):
        """Test basic functionality of scan_path2metadata."""
        metadata = LemiMetadata(self.path2metadata, OUTPUT_XML, self.data)
        self.assertEqual(*metadata.filenames, self.file)

    def test_scan_path2metadata_no_field_sheet_provided(self):
        """Test basic functionality of scan_path2metadata."""
        with self.assertLogs(logger, level='ERROR') as cmd:
            LemiMetadata(self.path2metadata_fail_1, OUTPUT_XML, self.data)
        msg = ("No field sheet found under the following path - {}. All "
               "metadata will have to be provided using the GUI!"
               .format(self.path2metadata_fail_1))
        self.assertEqual(cmd.output, [":".join(['ERROR', SCR_DIR, msg])])

    def test_get_metadata_field_pass(self):
        """Test basic functionality of get_metadata_field."""
        workbook = openpyxl.load_workbook(self.file, data_only=True)
        sheet = workbook.active
        self.assertEqual(LemiMetadata.get_metadata_field(sheet, 'B3'), 'EM')
        workbook.close()

    def test_get_metadata_field_fail(self):
        """Test basic functionality of get_metadata_field."""
        workbook = openpyxl.load_workbook(self.file, data_only=True)
        sheet = workbook.active
        with self.assertLogs(logger, level='ERROR'):
            self.assertIsNone(LemiMetadata.get_metadata_field(sheet, 12))
        workbook.close()

    def test_identify_field_sheet_pass(self):
        """Test basic functionality of identify_field_sheet."""
        workbook = openpyxl.load_workbook(self.file, data_only=True)
        sheet = workbook.active
        sheet_type = self.metadata.identify_field_sheet(sheet, 'LEMI_Install_Sheet.xlsx')
        self.assertEqual(sheet_type, 'install_sheet')
        workbook.close()

    def test_identify_field_sheet_fail(self):
        """Test basic functionality of identify_field_sheet."""
        metadata = LemiMetadata(self.path2metadata_fail_2, OUTPUT_XML, self.data)
        file_ = self.path2metadata_fail_2.joinpath('LEMI_Install_Sheet_2.xlsx')
        workbook = openpyxl.load_workbook(file_, data_only=True)
        sheet = workbook.active
        with self.assertLogs(logger, level='WARNING') as cmd:
            metadata.identify_field_sheet(sheet, file_)
        msg = ("The following file {} does not have the proper header. The "
               "provided spread sheet templates were not used or their "
               "layout was modified. Skipping file!".format(file_))
        self.assertEqual(cmd.output, [":".join(['WARNING', SCR_DIR, msg])])
        workbook.close()

    def test_dataclass2dict(self):
        """Test basic functionality of dataclass2dict."""
        channel = self.metadata.init_channel_metadata_properties('electric', 'a')
        self.assertDictEqual(LemiMetadata.dataclass2dict(channel),
                             {'elevation': 2201.7248070562296,
                              'latitude': 34.048390237958735,
                              'longitude': -107.12844894427468,
                              'instrument_manufacturer': None,
                              'instrument_model': None,
                              'instrument_specs': None,
                              'instrument_type': None,
                              'measurement_azimuth': None,
                              'measurement_tilt': None,
                              'sample_rate': 1.0,
                              'channel_number': None,
                              'contact_resistance_end': None,
                              'contact_resistance_start': None,
                              'dc_end': None,
                              'dc_start': None,
                              'dipole_length': None,
                              'negative_electrode_direction': None,
                              'negative_electrode_serial_number': None,
                              'positive_electrode_direction': None,
                              'positive_electrode_serial_number': None})

    def test_filter_channel(self):
        """Test basic functionality of filter_channel."""
        self.assertListEqual(self.metadata.filter_channel('auxiliary', 'a'), [])

    def test_update_channelnumber(self):
        """Test basic functionality of update_channelnumber."""
        channel = self.metadata.init_channel_metadata_properties('electric', 'a')
        self.assertIsNone(channel.channel_number)
        updated_channel = LemiMetadata.update_channelnumber(channel, 'E1')
        self.assertEqual(updated_channel.channel_number, 'E1')

    def test_for_gui(self):
        """Test basic functionality of for_gui."""
        file_ = self.path2metadata.joinpath('gui_metadata_not_populated.pkl')
        with open(file_, 'rb') as fin:
            expected = pickle.load(fin)
        self.assertDictEqual(self.metadata.for_gui, expected)

    def test_reformat_run(self):
        """Test basic functionality of reformat_run."""
        run_fields = self.metadata_fields_no_reformat['Run']
        file_ = self.path2metadata.joinpath('run_fields_reformatted.pkl')
        with open(file_, 'rb') as fin:
            reformatted = pickle.load(fin)
        self.assertDictEqual(self.metadata.reformat_run(run_fields), reformatted)

    def test_reformat_electric(self):
        """Test basic functionality of reformat_electric."""
        electric_fields = self.metadata_fields_no_reformat['Electric']
        file_ = self.path2metadata.joinpath('electric_fields_reformatted.pkl')
        with open(file_, 'rb') as fin:
            reformatted = pickle.load(fin)
        self.assertDictEqual(self.metadata.reformat_electric(electric_fields), reformatted)

    def test_reformat_magnetic(self):
        """Test basic functionality of reformat_magnetic."""
        magnetic_fields = self.metadata_fields_no_reformat['Magnetic']
        file_ = self.path2metadata.joinpath('magnetic_fields_reformatted.pkl')
        with open(file_, 'rb') as fin:
            reformatted = pickle.load(fin)
        self.assertDictEqual(self.metadata.reformat_magnetic(magnetic_fields), reformatted)

    def test_reformat_metadata_dict(self):
        """Test basic functionality of reformat_metadata_dict."""
        self.assertDictEqual(self.metadata.reformat_metadata_dict(self.metadata_fields_no_reformat),
                             self.metadata_fields)

    def test_from_field_sheets_failed_to_open(self):
        """Test basic functionality of from_field_sheets"""
        self.metadata.filenames = [self.path2metadata_fail_2.joinpath('LEMI_Install_Sheet_1.xlsx')]
        with self.assertLogs(logger, level='ERROR') as cmd:
            self.metadata.from_field_sheets
        msg = ("Failed to open field sheet: {} - Skipping file - Exception: "
               "File is not a zip file".format(self.metadata.filenames[0]))
        self.assertEqual(cmd.output, [":".join(['ERROR', SCR_DIR, msg])])

    def test_from_field_sheets_duplicate_sheet_type(self):
        """Test basic functionality of from_field_sheets"""
        self.metadata.filenames = [self.file] * 2
        with self.assertLogs(logger, level='WARNING') as cmd:
            self.metadata.from_field_sheets
        msg = ("Already parsed the install sheet - You may have more than one "
               "install sheet - Skipping {}!".format(self.file))
        self.assertEqual(cmd.output, [":".join(['WARNING', SCR_DIR, msg])])

    def test_from_field_sheets_expected_workflow(self):
        """Test basic functionality of from_field_sheets"""
        self.assertDictEqual(self.metadata.from_field_sheets, self.metadata_fields)

    def test_init_run_metadata_properties(self):
        """Test basic functionality of init_run_metadata_properties."""
        time_period_starts = [UTCDateTime(2020, 9, 30, 21, 5),
                              UTCDateTime(2020, 9, 30, 21, 12),
                              UTCDateTime(2020, 9, 30, 21, 14),
                              UTCDateTime(2020, 10, 1, 0, 0)]
        time_period_ends = [UTCDateTime(2020, 9, 30, 21, 11, 1),
                            UTCDateTime(2020, 9, 30, 21, 13, 45),
                            UTCDateTime(2020, 9, 30, 21, 27, 59),
                            UTCDateTime(2020, 10, 1, 0, 5, 59)]
        self.metadata.init_run_metadata_properties()
        for ind, run in enumerate(self.metadata.run):
            self.assertEqual(run.time_period_start, time_period_starts[ind])
            self.assertEqual(run.time_period_end, time_period_ends[ind])
            self.assertEqual(run.resource_id, 'mt.run.id:' + self.metadata.run_list[ind])

    def test_init_channel_metadata_properties_electric(self):
        """Test basic functionality of init_channel_metadata_properties."""
        channel = self.metadata.init_channel_metadata_properties('electric', 'a')
        self.assertIsInstance(channel, Electric)
        self.assertEqual(channel.elevation, self.metadata.data_stats['elevation'])
        self.assertEqual(channel.latitude, self.metadata.data_stats['latitude'])
        self.assertEqual(channel.longitude, self.metadata.data_stats['longitude'])
        self.assertEqual(channel.run_id, 'a')

    def test_init_channel_metadata_properties_magnetic(self):
        """Test basic functionality of init_channel_metadata_properties."""
        channel = self.metadata.init_channel_metadata_properties('magnetic', 'a')
        self.assertIsInstance(channel, Magnetic)
        self.assertEqual(channel.elevation, self.metadata.data_stats['elevation'])
        self.assertEqual(channel.latitude, self.metadata.data_stats['latitude'])
        self.assertEqual(channel.longitude, self.metadata.data_stats['longitude'])
        self.assertEqual(channel.run_id, 'a')

    def test_init_channel_metadata_properties_auxiliary(self):
        """Test basic functionality of init_channel_metadata_properties."""
        channel = self.metadata.init_channel_metadata_properties('auxiliary', 'a')
        self.assertIsInstance(channel, Auxiliary)
        self.assertEqual(channel.elevation, self.metadata.data_stats['elevation'])
        self.assertEqual(channel.latitude, self.metadata.data_stats['latitude'])
        self.assertEqual(channel.longitude, self.metadata.data_stats['longitude'])
        self.assertEqual(channel.run_id, 'a')