-
Notifications
You must be signed in to change notification settings - Fork 24
Increase ARC's code coverage statistics. #835
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
ff060aa
e2b66d5
6f85444
f143a4e
6019886
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,91 @@ | ||
| #!/usr/bin/env python3 | ||
| # encoding: utf-8 | ||
|
|
||
| """ | ||
| This module contains unit tests for ARC's factories | ||
| """ | ||
|
|
||
| import os | ||
| import shutil | ||
| import unittest | ||
| from unittest.mock import patch | ||
|
|
||
| from arc.common import ARC_TESTING_PATH | ||
| from arc.exceptions import JobError | ||
| from arc.job.factory import job_factory, register_job_adapter | ||
| from arc.job.adapters.xtb_adapter import xTBAdapter | ||
| from arc.parser.factory import ess_factory, register_ess_adapter | ||
| from arc.parser.adapters.xtb import XTBParser | ||
| from arc.species import ARCSpecies | ||
|
|
||
|
|
||
| class TestFactories(unittest.TestCase): | ||
| """ | ||
| Contains unit tests for job and parser factories. | ||
| """ | ||
|
|
||
| @classmethod | ||
| def setUpClass(cls): | ||
| """ | ||
| A method that is run before all unit tests in this class. | ||
| """ | ||
| cls.project_dir = os.path.join(ARC_TESTING_PATH, 'factory_tests_delete') | ||
| os.makedirs(cls.project_dir, exist_ok=True) | ||
|
|
||
| def test_job_factory_unregistered(self): | ||
| """Test that job_factory raises ValueError for unregistered adapters""" | ||
| with self.assertRaises(ValueError): | ||
| job_factory('non_existent', 'project', self.project_dir) | ||
|
|
||
| def test_job_factory_missing_species_and_reactions(self): | ||
| """Test that job_factory raises JobError if both species and reactions are missing""" | ||
| with self.assertRaises(JobError): | ||
| job_factory('xtb', 'project', self.project_dir) | ||
|
|
||
| def test_job_factory_invalid_species(self): | ||
| """Test that job_factory raises JobError for invalid species type""" | ||
| with self.assertRaises(JobError): | ||
| job_factory('xtb', 'project', self.project_dir, species=['not_a_species']) | ||
|
|
||
| def test_register_job_adapter_invalid_class(self): | ||
| """Test that register_job_adapter raises TypeError for invalid class""" | ||
| with self.assertRaises(TypeError): | ||
| register_job_adapter('gaussian', object) | ||
|
|
||
| def test_ess_factory_unregistered(self): | ||
| """Test that ess_factory raises ValueError for unregistered adapters""" | ||
| with self.assertRaises(ValueError): | ||
| ess_factory('path', 'non_existent') | ||
|
|
||
| def test_ess_factory_invalid_type(self): | ||
| """Test that ess_factory raises TypeError for non-string adapter name""" | ||
| with self.assertRaises(TypeError): | ||
| ess_factory('path', 123) | ||
|
|
||
| def test_register_ess_adapter_invalid_class(self): | ||
| """Test that register_ess_adapter raises TypeError for invalid class""" | ||
| with self.assertRaises(TypeError): | ||
| register_ess_adapter('gaussian', object) | ||
|
|
||
| def test_job_factory_success(self): | ||
| """Test successful instantiation via job_factory""" | ||
| spc = ARCSpecies(label='H', smiles='[H]') | ||
| job = job_factory('xtb', 'project', self.project_dir, species=[spc], job_type='opt') | ||
| self.assertIsInstance(job, xTBAdapter) | ||
|
|
||
| def test_ess_factory_success(self): | ||
| """Test successful instantiation via ess_factory""" | ||
| with patch('arc.parser.adapter.ESSAdapter.check_logfile_exists'): | ||
| ess = ess_factory('path', 'xtb') | ||
| self.assertIsInstance(ess, XTBParser) | ||
|
|
||
| @classmethod | ||
| def tearDownClass(cls): | ||
| """ | ||
| A function that is run ONCE after all unit tests in this class. | ||
| """ | ||
| shutil.rmtree(cls.project_dir, ignore_errors=True) | ||
|
|
||
|
|
||
| if __name__ == '__main__': | ||
| unittest.main(testRunner=unittest.TextTestRunner(verbosity=2)) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,91 @@ | ||
| #!/usr/bin/env python3 | ||
| # encoding: utf-8 | ||
|
|
||
| """ | ||
| This module contains unit tests for the arc.species.xyz_to_smiles module | ||
| """ | ||
|
|
||
| import unittest | ||
| from arc.species.xyz_to_smiles import xyz_to_smiles | ||
|
|
||
| class TestXYZToSMILES(unittest.TestCase): | ||
| """ | ||
| Contains unit tests for the xyz_to_smiles function | ||
| """ | ||
|
|
||
| def test_water(self): | ||
| """Test water perception""" | ||
| xyz = {'symbols': ('O', 'H', 'H'), | ||
| 'coords': ((0.0000, 0.0000, 0.1173), | ||
| (0.0000, 0.7572, -0.4692), | ||
| (0.0000, -0.7572, -0.4692))} | ||
| smiles = xyz_to_smiles(xyz) | ||
| self.assertIn('O', smiles) | ||
|
|
||
| def test_methane(self): | ||
| """Test methane perception""" | ||
| xyz = {'symbols': ('C', 'H', 'H', 'H', 'H'), | ||
| 'coords': ((0.0000, 0.0000, 0.0000), | ||
| (0.6291, 0.6291, 0.6291), | ||
| (-0.6291, -0.6291, 0.6291), | ||
| (0.6291, -0.6291, -0.6291), | ||
| (-0.6291, 0.6291, -0.6291))} | ||
| smiles = xyz_to_smiles(xyz) | ||
| self.assertIn('C', smiles) | ||
|
|
||
| def test_ethylene(self): | ||
| """Test ethylene perception""" | ||
| xyz = {'symbols': ('C', 'C', 'H', 'H', 'H', 'H'), | ||
| 'coords': ((0.0000, 0.0000, 0.6650), | ||
| (0.0000, 0.0000, -0.6650), | ||
| (0.0000, 0.9229, 1.2327), | ||
| (0.0000, -0.9229, 1.2327), | ||
| (0.0000, 0.9229, -1.2327), | ||
| (0.0000, -0.9229, -1.2327))} | ||
| smiles = xyz_to_smiles(xyz) | ||
| self.assertIn('C=C', smiles) | ||
|
|
||
| def test_charged_species(self): | ||
| """Test OH- perception""" | ||
| xyz = {'symbols': ('O', 'H'), | ||
| 'coords': ((0.0000, 0.0000, 0.0000), | ||
| (0.0000, 0.0000, 0.9600))} | ||
| smiles = xyz_to_smiles(xyz, charge=-1) | ||
| self.assertIn('[OH-]', smiles) | ||
|
|
||
| def test_huckel(self): | ||
| """Test with use_huckel=False""" | ||
| xyz = {'symbols': ('O', 'H', 'H'), | ||
| 'coords': ((0.0000, 0.0000, 0.1173), | ||
| (0.0000, 0.7572, -0.4692), | ||
| (0.0000, -0.7572, -0.4692))} | ||
| smiles = xyz_to_smiles(xyz, use_huckel=False) | ||
| self.assertIn('O', smiles) | ||
|
|
||
| def test_acetylene(self): | ||
| """Test acetylene perception (triple bond)""" | ||
| xyz = {'symbols': ('C', 'C', 'H', 'H'), | ||
| 'coords': ((0.0000, 0.0000, 0.6000), | ||
| (0.0000, 0.0000, -0.6000), | ||
| (0.0000, 0.0000, 1.6600), | ||
| (0.0000, 0.0000, -1.6600))} | ||
| smiles = xyz_to_smiles(xyz) | ||
| self.assertIn('C#C', smiles) | ||
|
|
||
| def test_chiral_center(self): | ||
| """Test chirality perception""" | ||
| # (S)-1-fluoro-1-chloroethane | ||
| xyz = {'symbols': ('C', 'C', 'F', 'Cl', 'H', 'H', 'H', 'H'), | ||
| 'coords': ((0.0000, 0.0000, 0.0000), | ||
| (1.5000, 0.0000, 0.0000), | ||
| (-0.5000, 1.2000, 0.0000), | ||
| (-0.5000, -0.6000, 1.4000), | ||
| (-0.4000, -0.6000, -0.8000), | ||
| (1.9000, 0.5000, 0.8000), | ||
| (1.9000, 0.5000, -0.8000), | ||
| (1.9000, -1.0000, 0.0000))} | ||
| smiles = xyz_to_smiles(xyz, embed_chiral=True) | ||
| self.assertTrue(any('@' in s for s in smiles)) | ||
|
|
||
| if __name__ == '__main__': | ||
| unittest.main(testRunner=unittest.TextTestRunner(verbosity=2)) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,64 @@ | ||
| #!/usr/bin/env python3 | ||
| # encoding: utf-8 | ||
|
|
||
| """ | ||
| This module contains unit tests for ARC's arc.utils.delete module | ||
| """ | ||
|
|
||
| import unittest | ||
| from unittest.mock import patch, MagicMock | ||
| from arc.utils.delete import parse_command_line_arguments, main | ||
| from arc.exceptions import InputError | ||
|
|
||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. please add another line break before the class |
||
|
|
||
| class TestDelete(unittest.TestCase): | ||
| """ | ||
| Contains unit tests for the delete utility. | ||
| Mocks are used to isolate the main deletion logic from the actual system environment, | ||
| preventing unintended file deletion or execution of command-line parsing during tests. | ||
| - mock_parse: Simulates command-line arguments (sys.argv) parsing. | ||
| - mock_local: Simulates the deletion of local ARC jobs. | ||
| - mock_remote: Simulates the deletion of remote ARC jobs via SSH. | ||
| - mock_isfile: Simulates the presence or absence of the initiated_jobs.csv database file. | ||
| """ | ||
|
|
||
| def test_parse_command_line_arguments(self): | ||
| """Test parsing command line arguments""" | ||
| # Test project flag | ||
| args = parse_command_line_arguments(['-p', 'test_project']) | ||
| self.assertEqual(args.project, 'test_project') | ||
|
|
||
| # Test job flag | ||
| args = parse_command_line_arguments(['-j', 'a1234']) | ||
| self.assertEqual(args.job, '1234') | ||
|
|
||
| args = parse_command_line_arguments(['--job', '5678']) | ||
| self.assertEqual(args.job, '5678') | ||
|
|
||
| # Test all flag | ||
| args = parse_command_line_arguments(['-a']) | ||
| self.assertTrue(args.all) | ||
|
|
||
| @patch('arc.utils.delete.delete_all_arc_jobs') | ||
| @patch('arc.utils.delete.delete_all_local_arc_jobs') | ||
| @patch('arc.utils.delete.parse_command_line_arguments') | ||
| def test_main_no_args(self, mock_parse, mock_local, mock_remote): | ||
| """Test main raises InputError if no arguments are provided""" | ||
| mock_parse.return_value = MagicMock(all=False, project='', job='', server='') | ||
| with self.assertRaises(InputError): | ||
| main() | ||
|
|
||
| @patch('arc.utils.delete.delete_all_arc_jobs') | ||
| @patch('arc.utils.delete.delete_all_local_arc_jobs') | ||
| @patch('arc.utils.delete.parse_command_line_arguments') | ||
| @patch('arc.utils.delete.os.path.isfile') | ||
| def test_main_all(self, mock_isfile, mock_parse, mock_local, mock_remote): | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you explain the role of
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Mocks are used to isolate the main deletion logic from the actual system environment,
Also added as a docs string to the test |
||
| """Test main with the --all flag""" | ||
| mock_parse.return_value = MagicMock(all=True, project='', job='', server=['local']) | ||
| mock_isfile.return_value = False | ||
| main() | ||
| mock_local.assert_called_with(jobs=None) | ||
|
|
||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. please add another line break |
||
|
|
||
| if __name__ == '__main__': | ||
| unittest.main(testRunner=unittest.TextTestRunner(verbosity=2)) | ||
Check notice
Code scanning / CodeQL
Unused import Note
Copilot Autofix
AI 9 days ago
To fix an unused import, the standard approach is to remove the import statement for the unused symbol, leaving all other imports and functionality unchanged. This eliminates the unnecessary dependency and silences the static analysis warning without affecting runtime behavior.
In this specific case, in
arc/statmech/arkane_test.py, the linefrom unittest.mock import patchis not used anywhere in the shown code. The best fix is to delete that import line entirely. No additional code, methods, or definitions are needed because we are only removing an unused symbol, not adding new behavior. Concretely, remove line 11 that importspatch, keeping all other imports and code as-is.