diff --git a/python/test/test_file_parser.py b/python/test/test_file_parser.py index fa214da27..3944ffe4c 100644 --- a/python/test/test_file_parser.py +++ b/python/test/test_file_parser.py @@ -33,18 +33,17 @@ from novatel_edie import STATUS, ENCODE_FORMAT -# ------------------------------------------------------------------------------------------------------- -# Unit Tests -# ------------------------------------------------------------------------------------------------------- - @pytest.fixture(scope="function") def fp(): return ne.FileParser() +@pytest.fixture(scope="module") +def test_gps_file(decoders_test_resources): + return decoders_test_resources / "BESTUTMBIN.GPS" + + def test_logger(): - assert ne.Logging.get("novatel_file_parser") is None - assert ne.Logging.get("novatel_parser") is None # FileParser logger level = ne.LogLevel.OFF file_parser = ne.FileParser() @@ -78,51 +77,40 @@ def test_unknown_bytes(fp): assert not fp.return_unknown_bytes -def test_parse_file_with_filter(fp, decoders_test_resources): +def test_parse_file_with_filter(fp, test_gps_file): fp.filter = ne.Filter() fp.filter.logger.set_level(ne.LogLevel.DEBUG) - - test_gps_file = decoders_test_resources / "BESTUTMBIN.GPS" + fp.encode_format = ENCODE_FORMAT.ASCII + assert fp.encode_format == ENCODE_FORMAT.ASCII with test_gps_file.open("rb") as f: assert fp.set_stream(f) - - success = 0 - expected_meta_data_length = [213, 195] - expected_milliseconds = [270605000, 172189053] - expected_message_length = [213, 195] - status = STATUS.UNKNOWN - fp.encode_format = ENCODE_FORMAT.ASCII - assert fp.encode_format == ENCODE_FORMAT.ASCII - + success = 0 while status != STATUS.STREAM_EMPTY: status, message_data, meta_data = fp.read() if status == STATUS.SUCCESS: - assert meta_data.length == expected_meta_data_length[success] - assert meta_data.milliseconds == pytest.approx(expected_milliseconds[success]) - assert len(message_data.message) == expected_message_length[success] + assert meta_data.length == [213, 195][success] + assert meta_data.milliseconds == pytest.approx([270605000, 172189053][success]) + assert len(message_data.message) == [213, 195][success] success += 1 assert success == 2 -def test_file_parser_iterator(fp, decoders_test_resources): +def test_file_parser_iterator(fp, test_gps_file): fp.filter = ne.Filter() fp.filter.logger.set_level(ne.LogLevel.DEBUG) - test_gps_file = decoders_test_resources / "BESTUTMBIN.GPS" + fp.encode_format = ENCODE_FORMAT.ASCII with test_gps_file.open("rb") as f: assert fp.set_stream(f) success = 0 - expected_meta_data_length = [213, 195] - expected_milliseconds = [270605000, 172189053] - expected_message_length = [213, 195] - fp.encode_format = ENCODE_FORMAT.ASCII for status, message_data, meta_data in fp: if status == STATUS.SUCCESS: - assert meta_data.length == expected_meta_data_length[success] - assert meta_data.milliseconds == pytest.approx(expected_milliseconds[success]) - assert len(message_data.message) == expected_message_length[success] + assert meta_data.length == [213, 195][success] + assert meta_data.milliseconds == pytest.approx([270605000, 172189053][success]) + assert len(message_data.message) == [213, 195][success] success += 1 - assert success == 2 + assert fp.flush(return_flushed_bytes=True) == b"" + assert success == 2 def test_reset(fp): diff --git a/python/test/test_parser.py b/python/test/test_parser.py new file mode 100644 index 000000000..9f858947d --- /dev/null +++ b/python/test/test_parser.py @@ -0,0 +1,95 @@ +################################################################################ +# +# COPYRIGHT NovAtel Inc, 2022. All rights reserved. +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# +################################################################################ +# DESCRIPTION +# +# \file novateltest.hpp +# \brief Unit tests for OEM Framer, HeaderDecoder, MessageDecoder, +# Encoder and Filter. +################################################################################ + +import novatel_edie as ne +import pytest +from novatel_edie import STATUS, ENCODE_FORMAT + + +@pytest.fixture(scope="function") +def parser(): + return ne.Parser() + +@pytest.fixture(scope="module") +def test_gps_file(decoders_test_resources): + return decoders_test_resources / "BESTUTMBIN.GPS" + +def test_logger(): + # Parser logger + level = ne.LogLevel.OFF + parser = ne.Parser() + logger = parser.logger + logger.set_level(level) + assert logger.name == "novatel_parser" + assert logger.level == level + # Parser logger + parser.enable_framer_decoder_logging(level, "novatel_parser.log") + + +@pytest.mark.skip(reason="Slow and redundant") +def test_parser_instantiation(json_db, json_db_path): + parser = ne.Parser() + parser.load_json_db(json_db) + ne.Parser(json_db_path) + ne.Parser(json_db) + + +def test_range_cmp(parser): + parser.decompress_range_cmp = True + assert parser.decompress_range_cmp + parser.decompress_range_cmp = False + assert not parser.decompress_range_cmp + + +def test_unknown_bytes(parser): + parser.return_unknown_bytes = True + assert parser.return_unknown_bytes + parser.return_unknown_bytes = False + assert not parser.return_unknown_bytes + + +def test_parse_file_with_filter(parser, test_gps_file): + parser.filter = ne.Filter() + parser.filter.logger.set_level(ne.LogLevel.DEBUG) + parser.encode_format = ENCODE_FORMAT.ASCII + assert parser.encode_format == ENCODE_FORMAT.ASCII + with test_gps_file.open("rb") as f: + success = 0 + while chunk := f.read(32): + parser.write(chunk) + for status, message_data, meta_data in parser: + print(status) + if status == STATUS.SUCCESS: + assert meta_data.length == [213, 195][success] + assert meta_data.milliseconds == pytest.approx([270605000, 172189053][success]) + assert len(message_data.message) == [213, 195][success] + success += 1 + assert parser.flush(return_flushed_bytes=True) == b"" + assert success == 2 diff --git a/python/test/test_rxconfig.py b/python/test/test_rxconfig.py index 26669f43b..3bad03bdd 100644 --- a/python/test/test_rxconfig.py +++ b/python/test/test_rxconfig.py @@ -15,7 +15,7 @@ import novatel_edie as ne -from novatel_edie import HEADER_FORMAT, STATUS, ENCODE_FORMAT +from novatel_edie import STATUS, ENCODE_FORMAT import pytest diff --git a/src/decoders/oem/test/oem_test.cpp b/src/decoders/oem/test/oem_test.cpp index f8e43717c..e87416dd7 100644 --- a/src/decoders/oem/test/oem_test.cpp +++ b/src/decoders/oem/test/oem_test.cpp @@ -2869,6 +2869,7 @@ TEST_F(FileParserTest, PARSE_FILE_WITH_FILTER) eStatus = pclFp->Read(stMessageData, stMetaData); } + ASSERT_EQ(pclFp->Flush(), 0); ASSERT_EQ(numSuccess, 2); } @@ -2879,6 +2880,141 @@ TEST_F(FileParserTest, RESET) ASSERT_TRUE(pclFp->Reset()); } +// ------------------------------------------------------------------------------------------------------- +// Parser Unit Tests +// ------------------------------------------------------------------------------------------------------- +class ParserTest : public ::testing::Test +{ + protected: + static std::unique_ptr<Parser> pclParser; + + static void SetUpTestSuite() + { + try + { + pclParser = std::make_unique<Parser>(std::getenv("TEST_DATABASE_PATH")); + } + catch (JsonDbReaderFailure& e) + { + std::cout << e.what() << '\n'; + } + } + + static void TearDownTestSuite() { Logger::Shutdown(); } +}; + +std::unique_ptr<Parser> ParserTest::pclParser = nullptr; + +TEST_F(ParserTest, LOGGER) +{ + spdlog::level::level_enum eLevel = spdlog::level::off; + ASSERT_NE(spdlog::get("novatel_parser"), nullptr); + std::shared_ptr<spdlog::logger> novatelParser = pclParser->GetLogger(); + pclParser->SetLoggerLevel(eLevel); + ASSERT_EQ(novatelParser->level(), eLevel); +} + +TEST_F(ParserTest, FILEPARSER_INSTANTIATION) +{ + ASSERT_NO_THROW(Parser fp1); + ASSERT_NO_THROW(Parser fp2(std::getenv("TEST_DATABASE_PATH"))); + + std::string sTEST_DATABASE_PATH = std::getenv("TEST_DATABASE_PATH"); + const std::u32string usTEST_DATABASE_PATH(sTEST_DATABASE_PATH.begin(), sTEST_DATABASE_PATH.end()); + ASSERT_NO_THROW(Parser fp3 = Parser(usTEST_DATABASE_PATH)); + + auto jsonDb = JsonDbReader::LoadFile(std::getenv("TEST_DATABASE_PATH")); + ASSERT_NO_THROW(Parser fp4(jsonDb)); +} + +TEST_F(ParserTest, LOAD_JSON_DB_STRING) +{ + auto pclMyJsonDb = JsonDbReader::LoadFile(std::getenv("TEST_DATABASE_PATH")); + ASSERT_NO_THROW(pclParser->LoadJsonDb(pclMyJsonDb)); + ASSERT_NO_THROW(pclParser->LoadJsonDb(nullptr)); +} + +TEST_F(ParserTest, LOAD_JSON_DB_U32STRING) +{ + std::wstring_convert<std::codecvt_utf8<char32_t>, char32_t> converter; + std::u32string u32str = converter.from_bytes(std::getenv("TEST_DATABASE_PATH")); + auto pclMyJsonDb = JsonDbReader::LoadFile(u32str); + ASSERT_NO_THROW(pclParser->LoadJsonDb(pclMyJsonDb)); + ASSERT_NO_THROW(pclParser->LoadJsonDb(nullptr)); +} + +TEST_F(ParserTest, LOAD_JSON_DB_CHAR_ARRAY) +{ + auto pclMyJsonDb = JsonDbReader::LoadFile(std::getenv("TEST_DATABASE_PATH")); + ASSERT_NO_THROW(pclParser->LoadJsonDb(pclMyJsonDb)); + ASSERT_NO_THROW(pclParser->LoadJsonDb(nullptr)); +} + +TEST_F(ParserTest, RANGE_CMP) +{ + pclParser->SetDecompressRangeCmp(true); + ASSERT_TRUE(pclParser->GetDecompressRangeCmp()); + pclParser->SetDecompressRangeCmp(false); + ASSERT_FALSE(pclParser->GetDecompressRangeCmp()); +} + +TEST_F(ParserTest, UNKNOWN_BYTES) +{ + pclParser->SetReturnUnknownBytes(true); + ASSERT_TRUE(pclParser->GetReturnUnknownBytes()); + pclParser->SetReturnUnknownBytes(false); + ASSERT_FALSE(pclParser->GetReturnUnknownBytes()); +} + +TEST_F(ParserTest, PARSE_FILE_WITH_FILTER) +{ + // Reset the Parser with the database because a previous test assigns it to the nullptr + pclParser = std::make_unique<Parser>(std::getenv("TEST_DATABASE_PATH")); + auto clFilter = std::make_shared<Filter>(); + clFilter->SetLoggerLevel(spdlog::level::debug); + pclParser->SetFilter(clFilter); + ASSERT_EQ(pclParser->GetFilter(), clFilter); + + std::filesystem::path test_gps_file = std::filesystem::path(std::getenv("TEST_RESOURCE_PATH")) / "BESTUTMBIN.GPS"; + std::ifstream clInputFileStream{test_gps_file.string().c_str(), std::ios::binary}; + + MetaDataStruct stMetaData; + MessageDataStruct stMessageData; + + int numSuccess = 0; + uint32_t uiExpectedMetaDataLength[2] = {213, 195}; + double dExpectedMilliseconds[2] = {270605000, 172189053}; + uint32_t uiExpectedMessageLength[2] = {213, 195}; + + pclParser->SetEncodeFormat(ENCODE_FORMAT::ASCII); + ASSERT_EQ(pclParser->GetEncodeFormat(), ENCODE_FORMAT::ASCII); + + const std::size_t chunkSize = 32; + std::vector<char> buffer(chunkSize); + while (clInputFileStream.read(buffer.data(), chunkSize) || clInputFileStream.gcount() > 0) { + std::size_t n = clInputFileStream.gcount(); + pclParser->Write(reinterpret_cast<const uint8_t*>(buffer.data()), n); + while (true) + { + STATUS eStatus = pclParser->Read(stMessageData, stMetaData); + if (eStatus == STATUS::BUFFER_EMPTY || eStatus == STATUS::INCOMPLETE || eStatus == STATUS::INCOMPLETE_MORE_DATA) + { + break; + } + if (eStatus == STATUS::SUCCESS) + { + ASSERT_EQ(stMetaData.uiLength, uiExpectedMetaDataLength[numSuccess]); + ASSERT_DOUBLE_EQ(stMetaData.dMilliseconds, dExpectedMilliseconds[numSuccess]); + ASSERT_EQ(stMessageData.uiMessageLength, uiExpectedMessageLength[numSuccess]); + numSuccess++; + } + } + } + + ASSERT_EQ(pclParser->Flush(), 0); + ASSERT_EQ(numSuccess, 2); +} + // ------------------------------------------------------------------------------------------------------- // Novatel Types Unit Tests // -------------------------------------------------------------------------------------------------------