Addon Manager: refactor process_string_to_datetime (#18492)

* Addon Manager: Refactor utilities tests to remove filesystem use

* Addon Manager: Move process_date_string_to_python_datetime to utilities

Also add unit tests and modify the exception type

* Addon Manager: Add tests for other date separators

* Addon Manager: Refactor to reduce duplication

* Addon Manager: add explanation of why the function exists

* Addon Manager: use exception chaining

* Addon Manager: Remove unused test files
This commit is contained in:
Chris Hennes
2024-12-23 12:01:02 -05:00
committed by GitHub
parent e7bc0dbc24
commit 8a95d0e6e8
6 changed files with 115 additions and 130 deletions

View File

@@ -21,8 +21,9 @@
# * *
# ***************************************************************************
from datetime import datetime
import unittest
from unittest.mock import MagicMock, patch
from unittest.mock import MagicMock, patch, mock_open
import os
import sys
import subprocess
@@ -37,10 +38,11 @@ sys.path.append("../..")
from AddonManagerTest.app.mocks import MockAddon as Addon
from addonmanager_utilities import (
recognized_git_location,
get_readme_url,
get_assigned_string_literal,
get_macro_version_from_file,
get_readme_url,
process_date_string_to_python_datetime,
recognized_git_location,
run_interruptable_subprocess,
)
@@ -49,9 +51,6 @@ class TestUtilities(unittest.TestCase):
MODULE = "test_utilities" # file name without extension
def setUp(self):
pass
@classmethod
def tearDownClass(cls):
try:
@@ -132,21 +131,22 @@ class TestUtilities(unittest.TestCase):
result = get_assigned_string_literal(line)
self.assertIsNone(result)
def test_get_macro_version_from_file(self):
if FreeCAD:
test_dir = os.path.join(
FreeCAD.getHomePath(), "Mod", "AddonManager", "AddonManagerTest", "data"
)
good_file = os.path.join(test_dir, "good_macro_metadata.FCStd")
version = get_macro_version_from_file(good_file)
def test_get_macro_version_from_file_good_metadata(self):
good_metadata = """__Version__ = "1.2.3" """
with patch("builtins.open", new_callable=mock_open, read_data=good_metadata):
version = get_macro_version_from_file("mocked_file.FCStd")
self.assertEqual(version, "1.2.3")
bad_file = os.path.join(test_dir, "bad_macro_metadata.FCStd")
version = get_macro_version_from_file(bad_file)
def test_get_macro_version_from_file_missing_quotes(self):
bad_metadata = """__Version__ = 1.2.3 """ # No quotes
with patch("builtins.open", new_callable=mock_open, read_data=bad_metadata):
version = get_macro_version_from_file("mocked_file.FCStd")
self.assertEqual(version, "", "Bad version did not yield empty string")
empty_file = os.path.join(test_dir, "missing_macro_metadata.FCStd")
version = get_macro_version_from_file(empty_file)
def test_get_macro_version_from_file_no_version(self):
good_metadata = ""
with patch("builtins.open", new_callable=mock_open, read_data=good_metadata):
version = get_macro_version_from_file("mocked_file.FCStd")
self.assertEqual(version, "", "Missing version did not yield empty string")
@patch("subprocess.Popen")
@@ -222,6 +222,66 @@ class TestUtilities(unittest.TestCase):
with patch("time.time", fake_time):
run_interruptable_subprocess(["arg0", "arg1"], 0.1)
def test_process_date_string_to_python_datetime_non_numeric(self):
with self.assertRaises(ValueError):
process_date_string_to_python_datetime("TwentyTwentyFour-January-ThirtyFirst")
def test_process_date_string_to_python_datetime_year_first(self):
result = process_date_string_to_python_datetime("2024-01-31")
expected_result = datetime(2024, 1, 31, 0, 0)
self.assertEqual(result, expected_result)
def test_process_date_string_to_python_datetime_day_first(self):
result = process_date_string_to_python_datetime("31-01-2024")
expected_result = datetime(2024, 1, 31, 0, 0)
self.assertEqual(result, expected_result)
def test_process_date_string_to_python_datetime_month_first(self):
result = process_date_string_to_python_datetime("01-31-2024")
expected_result = datetime(2024, 1, 31, 0, 0)
self.assertEqual(result, expected_result)
def test_process_date_string_to_python_datetime_ambiguous(self):
"""In the ambiguous case, the code should assume that the date is in the DD-MM-YYYY format."""
result = process_date_string_to_python_datetime("01-12-2024")
expected_result = datetime(2024, 12, 1, 0, 0)
self.assertEqual(result, expected_result)
def test_process_date_string_to_python_datetime_invalid_date(self):
with self.assertRaises(ValueError):
process_date_string_to_python_datetime("13-31-2024")
def test_process_date_string_to_python_datetime_too_many_components(self):
with self.assertRaises(ValueError):
process_date_string_to_python_datetime("01-01-31-2024")
def test_process_date_string_to_python_datetime_too_few_components(self):
"""Month-Year-only dates are not supported"""
with self.assertRaises(ValueError):
process_date_string_to_python_datetime("01-2024")
def test_process_date_string_to_python_datetime_unrecognizable(self):
"""Two-digit years are not supported"""
with self.assertRaises(ValueError):
process_date_string_to_python_datetime("01-02-24")
def test_process_date_string_to_python_datetime_valid_separators(self):
"""Four individual separators are supported, plus any combination of multiple of those separators"""
valid_separators = [" ", ".", "/", "-", " - ", " / ", "--"]
for separator in valid_separators:
with self.subTest(separator=separator):
result = process_date_string_to_python_datetime(f"2024{separator}01{separator}31")
expected_result = datetime(2024, 1, 31, 0, 0)
self.assertEqual(result, expected_result)
def test_process_date_string_to_python_datetime_invalid_separators(self):
"""Only the four separators [ ./-] are supported: ensure others fail"""
invalid_separators = ["a", "\\", "|", "'", ";", "*", " \\ "]
for separator in invalid_separators:
with self.subTest(separator=separator):
with self.assertRaises(ValueError):
process_date_string_to_python_datetime(f"2024{separator}01{separator}31")
if __name__ == "__main__":
unittest.main()

View File

@@ -1,37 +0,0 @@
# -*- coding: utf-8 -*-
# ***************************************************************************
# * Copyright (c) 2022 FreeCAD Project Association *
# * *
# * This file is part of the FreeCAD CAx development system. *
# * *
# * This library is free software; you can redistribute it and/or *
# * modify it under the terms of the GNU Lesser General Public *
# * License as published by the Free Software Foundation; either *
# * version 2.1 of the License, or (at your option) any later version. *
# * *
# * This library is distributed in the hope that it will be useful, *
# * but WITHOUT ANY WARRANTY; without even the implied warranty of *
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
# * Lesser General Public License for more details. *
# * *
# * You should have received a copy of the GNU Lesser General Public *
# * License along with this library; if not, write to the Free Software *
# * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
# * 02110-1301 USA *
# * *
# ***************************************************************************
__Title__ = "Test Macro' # Mismatched quotes
__Author__ = Chris Hennes # Not in quotes
__Version__ = 1.2.3 # Not in quotes and not a number
__Date__ = "2022-2-25 # Missing quote
__Comment__ = """For use with the FreeCAD unit test suite""" # Triple-quotes not allowed
__Web__ = "https://freecad.org"
__Wiki__ = ""
__Icon__ = ""
__Help__ = ""
__Status__ = ""
__Requires__ = ""
__Communication__ = ""
__Files__ = ""

View File

@@ -1,37 +0,0 @@
# -*- coding: utf-8 -*-
# ***************************************************************************
# * Copyright (c) 2022 FreeCAD Project Association *
# * *
# * This file is part of the FreeCAD CAx development system. *
# * *
# * This library is free software; you can redistribute it and/or *
# * modify it under the terms of the GNU Lesser General Public *
# * License as published by the Free Software Foundation; either *
# * version 2.1 of the License, or (at your option) any later version. *
# * *
# * This library is distributed in the hope that it will be useful, *
# * but WITHOUT ANY WARRANTY; without even the implied warranty of *
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
# * Lesser General Public License for more details. *
# * *
# * You should have received a copy of the GNU Lesser General Public *
# * License along with this library; if not, write to the Free Software *
# * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
# * 02110-1301 USA *
# * *
# ***************************************************************************
__Title__ = "Test Macro"
__Author__ = "Chris Hennes"
__Version__ = "1.2.3"
__Date__ = "2022-2-25"
__Comment__ = "For use with the FreeCAD unit test suite"
__Web__ = "https://freecad.org"
__Wiki__ = ""
__Icon__ = ""
__Help__ = ""
__Status__ = ""
__Requires__ = ""
__Communication__ = ""
__Files__ = ""