From 0f4c28ce21680f45af30dc8fdda6fcdd28e9af40 Mon Sep 17 00:00:00 2001 From: sschulz92 Date: Tue, 19 Aug 2025 16:06:58 +0200 Subject: [PATCH 01/12] Fix path comparison Signed-off-by: sschulz92 --- build.py | 10 ++++++---- gauge-proto | 2 +- getgauge/registry.py | 10 ++++++---- getgauge/util.py | 4 ++-- python.json | 2 +- 5 files changed, 16 insertions(+), 12 deletions(-) diff --git a/build.py b/build.py index befca3a..a6a144e 100644 --- a/build.py +++ b/build.py @@ -98,8 +98,10 @@ def copy(src, dest): usage = """ Usage: python build.py --[option] +Example: python build.py --test --install Options: + --dist : creates the distributable. --test : runs unit tests. --install : installs python plugin and generates the pip package """ @@ -123,15 +125,15 @@ def main(): if len(sys.argv) < 2: print(usage) else: - if sys.argv[1] == '--dist': + if '--dist' in sys.argv: create_zip() generate_package() - else: + if '--test' in sys.argv: exit_code = run_tests() if exit_code != 0: sys.exit(exit_code) - elif sys.argv[1] == '--install': - install() + if '--install' in sys.argv: + install() if __name__ == '__main__': diff --git a/gauge-proto b/gauge-proto index f21c744..d0bab18 160000 --- a/gauge-proto +++ b/gauge-proto @@ -1 +1 @@ -Subproject commit f21c74490be469f83c8e20c7c7fdb8654a23bbb1 +Subproject commit d0bab18956731c7db453bdf8b9a3277c0fc42077 diff --git a/getgauge/registry.py b/getgauge/registry.py index 037e60a..4bcd4c7 100644 --- a/getgauge/registry.py +++ b/getgauge/registry.py @@ -172,7 +172,7 @@ def get_step_positions(self, file_name): positions = [] for step, infos in self.__steps_map.items(): positions = positions + [{'stepValue': step, 'span': i.span} - for i in infos if i.file_name == file_name] + for i in infos if str(i.file_name).lower() == str(file_name).lower()] return positions def _get_all_hooks(self, file_name): @@ -180,18 +180,20 @@ def _get_all_hooks(self, file_name): for hook in self.hooks: all_hooks = all_hooks + \ [h for h in getattr(self, "__{}".format(hook)) - if h.file_name == file_name] + if str(h.file_name).lower() == str(file_name).lower()] return all_hooks def get_all_methods_in(self, file_name): methods = [] for _, infos in self.__steps_map.items(): - methods = methods + [i for i in infos if i.file_name == file_name] + # Using relative paths may lead to different spelling of the C drive (lower or capital C) + methods = methods + [i for i in infos if str(i.file_name).lower() == str(file_name).lower()] return methods + self._get_all_hooks(file_name) def is_file_cached(self, file_name): for _, infos in self.__steps_map.items(): - if any(i.file_name == file_name for i in infos): + # Using relative paths may lead to different spelling of the C drive (lower or capital C) + if any(str(i.file_name).lower() == str(file_name).lower() for i in infos): return True return False diff --git a/getgauge/util.py b/getgauge/util.py index d1051d3..e47e2b4 100644 --- a/getgauge/util.py +++ b/getgauge/util.py @@ -16,8 +16,8 @@ def get_step_impl_dirs(): full_path_dir_names = [] for name in step_impl_dir_names: name = name.replace("/", os.path.sep).replace("\\", os.path.sep) - imple_dir = name if os.path.isabs(name) else os.path.join(get_project_root(), name) - full_path_dir_names.append(imple_dir) + impl_dir = name if os.path.isabs(name) else os.path.join(get_project_root(), name) + full_path_dir_names.append(impl_dir) return full_path_dir_names diff --git a/python.json b/python.json index 3835611..839bb92 100644 --- a/python.json +++ b/python.json @@ -1,6 +1,6 @@ { "id": "python", - "version": "0.4.11", + "version": "0.4.12", "description": "Python support for gauge", "run": { "windows": [ From a59794ac49bce956b65ac1b7423d545c3831c530 Mon Sep 17 00:00:00 2001 From: sschulz92 Date: Wed, 20 Aug 2025 15:59:45 +0200 Subject: [PATCH 02/12] Handle case-senstive dir/file paths by using pathlib.Path Signed-off-by: sschulz92 --- build.py | 5 +++-- getgauge/impl_loader.py | 21 ++++++++++----------- getgauge/registry.py | 26 ++++++++++++++++++-------- getgauge/util.py | 6 +++--- tests/test_processor.py | 6 +++--- 5 files changed, 37 insertions(+), 27 deletions(-) diff --git a/build.py b/build.py index a6a144e..780bc73 100644 --- a/build.py +++ b/build.py @@ -115,8 +115,9 @@ def run_tests() -> int: for i, file_name_path in enumerate(all_python_test_files): command = ["coverage", "run", file_name_path] exit_code = call(command) if exit_code == 0 else exit_code - # Keep coverage files - os.rename(".coverage", f".coverage.{i}") + if Path(".coverage").is_file(): + # Keep coverage files + os.rename(".coverage", f".coverage.{i}") call(["coverage", "combine"]) return exit_code diff --git a/getgauge/impl_loader.py b/getgauge/impl_loader.py index d3614a8..802b083 100644 --- a/getgauge/impl_loader.py +++ b/getgauge/impl_loader.py @@ -1,3 +1,4 @@ +import glob import importlib import inspect import json @@ -58,12 +59,8 @@ def copy_skel_files(): def _import_impl(base_dir, step_impl_dir): - for f in os.listdir(step_impl_dir): - file_path = os.path.join(step_impl_dir, f) - if f.endswith('.py'): - _import_file(base_dir, file_path) - elif path.isdir(file_path): - _import_impl(base_dir, file_path) + for python_file in glob.glob(f"{step_impl_dir}/**/*.py", recursive=True): + _import_file(base_dir, python_file) @contextmanager def use_temporary_sys_path(): @@ -88,15 +85,17 @@ def _import_file(base_dir, file_path): classes = inspect.getmembers(m, lambda member: inspect.isclass(member) and member.__module__ == module_name) if len(classes) > 0: for c in classes: - file = inspect.getfile(c[1]) - # Create instance of step implementation class. - if _has_methods_with_gauge_decoratores(c[1]): - update_step_registry_with_class(c[1](), file_path) # c[1]() will create a new instance of the class + class_obj = c[1] + if _has_methods_with_gauge_decoratores(class_obj): + update_step_registry_with_class( + instance=class_obj(), # class_obj() will create a new instance of the class + file_path=file_path + ) except: logger.fatal('Exception occurred while loading step implementations from file: {}.\n{}'.format(rel_path, traceback.format_exc())) -# Inject instance in each class method (hook/step) def update_step_registry_with_class(instance, file_path): + """ Inject instance in each class method (hook/step) """ # Resolve the absolute path from relative path # Note: relative path syntax ".." can appear in between the file_path too like "/../../Other_Project/src/step_impl/file.py" file_path = os.path.abspath(file_path) if ".." in str(file_path) else file_path diff --git a/getgauge/registry.py b/getgauge/registry.py index 4bcd4c7..0f40975 100644 --- a/getgauge/registry.py +++ b/getgauge/registry.py @@ -2,6 +2,7 @@ import os import re import sys +from pathlib import Path from subprocess import call from uuid import uuid1 @@ -172,35 +173,33 @@ def get_step_positions(self, file_name): positions = [] for step, infos in self.__steps_map.items(): positions = positions + [{'stepValue': step, 'span': i.span} - for i in infos if str(i.file_name).lower() == str(file_name).lower()] + for i in infos if paths_equal(i.file_name, file_name)] return positions def _get_all_hooks(self, file_name): all_hooks = [] for hook in self.hooks: all_hooks = all_hooks + \ - [h for h in getattr(self, "__{}".format(hook)) - if str(h.file_name).lower() == str(file_name).lower()] + [h for h in getattr(self, "__{}".format(hook)) + if paths_equal(h.file_name, file_name)] return all_hooks def get_all_methods_in(self, file_name): methods = [] for _, infos in self.__steps_map.items(): - # Using relative paths may lead to different spelling of the C drive (lower or capital C) - methods = methods + [i for i in infos if str(i.file_name).lower() == str(file_name).lower()] + methods = methods + [i for i in infos if paths_equal(i.file_name, file_name)] return methods + self._get_all_hooks(file_name) def is_file_cached(self, file_name): for _, infos in self.__steps_map.items(): - # Using relative paths may lead to different spelling of the C drive (lower or capital C) - if any(str(i.file_name).lower() == str(file_name).lower() for i in infos): + if any(Path(i.file_name).resolve() == Path(file_name).resolve() for i in infos): return True return False def remove_steps(self, file_name): new_map = {} for step, infos in self.__steps_map.items(): - filtered_info = [i for i in infos if i.file_name != file_name] + filtered_info = [i for i in infos if not paths_equal(i.file_name, file_name)] if len(filtered_info) > 0: new_map[step] = filtered_info self.__steps_map = new_map @@ -211,6 +210,17 @@ def clear(self): setattr(self, '__{}'.format(hook), []) +def paths_equal(p1: str | Path, p2: str | Path) -> bool: + """ + Compare two paths in a cross-platform safe way. + On Windows: case-insensitive, slash-insensitive. + On Linux/macOS: case-sensitive. + """ + p1 = Path(p1).resolve() + p2 = Path(p2).resolve() + return os.path.normcase(str(p1)) == os.path.normcase(str(p2)) + + def _filter_hooks(tags, hooks): filtered_hooks = [] for hook in hooks: diff --git a/getgauge/util.py b/getgauge/util.py index e47e2b4..f6f056b 100644 --- a/getgauge/util.py +++ b/getgauge/util.py @@ -14,9 +14,9 @@ def get_project_root(): def get_step_impl_dirs(): step_impl_dir_names = map(str.strip, os.getenv(STEP_IMPL_DIR_ENV).split(',')) if os.getenv(STEP_IMPL_DIR_ENV) else ['step_impl'] full_path_dir_names = [] - for name in step_impl_dir_names: - name = name.replace("/", os.path.sep).replace("\\", os.path.sep) - impl_dir = name if os.path.isabs(name) else os.path.join(get_project_root(), name) + for dir_name in step_impl_dir_names: + dir_name = dir_name.replace("/", os.path.sep).replace("\\", os.path.sep) + impl_dir = dir_name if os.path.isabs(dir_name) else os.path.join(get_project_root(), dir_name) full_path_dir_names.append(impl_dir) return full_path_dir_names diff --git a/tests/test_processor.py b/tests/test_processor.py index 45afc0d..4179733 100644 --- a/tests/test_processor.py +++ b/tests/test_processor.py @@ -354,7 +354,7 @@ def test_Processor_failing_ending_execution_request(self): registry.add_after_suite(failing_impl) request = ExecutionEndingRequest() response = processor.process_execution_ending_request(request) - print(response) + self.assertIsInstance(response, ExecutionStatusResponse) self.assertTrue(response.executionResult.failed) self.assertEqual(ProtoExecutionResult.ASSERTION, @@ -528,8 +528,8 @@ def foo(): processor.process_cache_file_request(request) - self.assertEqual(registry.is_implemented('foo1'), False) - self.assertEqual(registry.is_implemented('foo {}'), True) + self.assertFalse(registry.is_implemented('foo1')) + self.assertTrue(registry.is_implemented('foo {}')) def test_Processor_cache_file_with_changed_status(self): request = CacheFileRequest() From 7d0814de323a92e2131f1e4c6a18d1ae2504704d Mon Sep 17 00:00:00 2001 From: sschulz92 Date: Thu, 21 Aug 2025 15:05:40 +0200 Subject: [PATCH 03/12] Keep support of Python 3.9 Signed-off-by: sschulz92 --- getgauge/registry.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/getgauge/registry.py b/getgauge/registry.py index 0f40975..84d133e 100644 --- a/getgauge/registry.py +++ b/getgauge/registry.py @@ -4,6 +4,7 @@ import sys from pathlib import Path from subprocess import call +from typing import Union from uuid import uuid1 from getgauge import logger @@ -210,7 +211,7 @@ def clear(self): setattr(self, '__{}'.format(hook), []) -def paths_equal(p1: str | Path, p2: str | Path) -> bool: +def paths_equal(p1: Union[str, Path], p2: Union[str, Path]) -> bool: """ Compare two paths in a cross-platform safe way. On Windows: case-insensitive, slash-insensitive. From 77dbc6ba089dd92df9597369b328695426c6dbd8 Mon Sep 17 00:00:00 2001 From: sschulz92 Date: Fri, 22 Aug 2025 08:33:48 +0200 Subject: [PATCH 04/12] Add unit test, normalize path while adding a step too Signed-off-by: sschulz92 --- getgauge/registry.py | 5 +++-- tests/test_registry.py | 51 ++++++++++++++++++++++++++++++++---------- 2 files changed, 42 insertions(+), 14 deletions(-) diff --git a/getgauge/registry.py b/getgauge/registry.py index 84d133e..7efce2d 100644 --- a/getgauge/registry.py +++ b/getgauge/registry.py @@ -130,8 +130,9 @@ def add(self, func=None, tags=None, file_name=""): def add_step(self, step_text, func, file_name, span=None, has_alias=False, aliases=None): if not isinstance(step_text, list): parsed_step_text = _get_step_value(step_text) + normalized_file_path = os.path.normcase(str(Path(file_name))) info = StepInfo(step_text, parsed_step_text, func, - file_name, span, has_alias, aliases) + normalized_file_path, span, has_alias, aliases) self.__steps_map.setdefault(parsed_step_text, []).append(info) return for text in step_text: @@ -193,7 +194,7 @@ def get_all_methods_in(self, file_name): def is_file_cached(self, file_name): for _, infos in self.__steps_map.items(): - if any(Path(i.file_name).resolve() == Path(file_name).resolve() for i in infos): + if any(paths_equal(i.file_name, file_name) for i in infos): return True return False diff --git a/tests/test_registry.py b/tests/test_registry.py index 9bf4c88..bd4d583 100644 --- a/tests/test_registry.py +++ b/tests/test_registry.py @@ -160,9 +160,12 @@ def test_Registry_before_spec_with_tags(self): registry.add_before_spec(info['func'], info['tags']) self.assertEqual([info1['func']], [i.impl for i in registry.before_spec([])]) - self.assertEqual([x['func'] for x in infos], [i.impl for i in registry.before_spec(['A', 'b'])]) - self.assertEqual([info1['func'], info3['func']], [i.impl for i in registry.before_spec(['A', 'b', 'c'])]) - self.assertEqual([info1['func'], info3['func']], [i.impl for i in registry.before_spec(['A'])]) + self.assertEqual([x['func'] for x in infos], [ + i.impl for i in registry.before_spec(['A', 'b'])]) + self.assertEqual([info1['func'], info3['func']], [ + i.impl for i in registry.before_spec(['A', 'b', 'c'])]) + self.assertEqual([info1['func'], info3['func']], [ + i.impl for i in registry.before_spec(['A'])]) self.assertEqual([info1['func']], [i.impl for i in registry.before_spec(['A', 'c'])]) def test_Registry_after_spec_with_tags(self): @@ -176,9 +179,12 @@ def test_Registry_after_spec_with_tags(self): registry.add_after_spec(info['func'], info['tags']) self.assertEqual([info1['func']], [i.impl for i in registry.after_spec([])]) - self.assertEqual([x['func'] for x in infos], [i.impl for i in registry.after_spec(['A', 'b'])]) - self.assertEqual([info1['func'], info3['func']], [i.impl for i in registry.after_spec(['A', 'b', 'c'])]) - self.assertEqual([info1['func'], info3['func']], [i.impl for i in registry.after_spec(['A'])]) + self.assertEqual([x['func'] for x in infos], [ + i.impl for i in registry.after_spec(['A', 'b'])]) + self.assertEqual([info1['func'], info3['func']], [ + i.impl for i in registry.after_spec(['A', 'b', 'c'])]) + self.assertEqual([info1['func'], info3['func']], [ + i.impl for i in registry.after_spec(['A'])]) self.assertEqual([info1['func']], [i.impl for i in registry.after_spec(['A', 'c'])]) def test_Registry_before_scenario(self): @@ -269,9 +275,12 @@ def test_Registry_before_step_with_tags(self): registry.add_before_step(info['func'], info['tags']) self.assertEqual([info1['func']], [i.impl for i in registry.before_step([])]) - self.assertEqual([x['func'] for x in infos], [i.impl for i in registry.before_step(['A', 'b'])]) - self.assertEqual([info1['func'], info3['func']], [i.impl for i in registry.before_step(['A', 'b', 'c'])]) - self.assertEqual([info1['func'], info3['func']], [i.impl for i in registry.before_step(['A'])]) + self.assertEqual([x['func'] for x in infos], [ + i.impl for i in registry.before_step(['A', 'b'])]) + self.assertEqual([info1['func'], info3['func']], [ + i.impl for i in registry.before_step(['A', 'b', 'c'])]) + self.assertEqual([info1['func'], info3['func']], [ + i.impl for i in registry.before_step(['A'])]) self.assertEqual([info1['func']], [i.impl for i in registry.before_step(['A', 'c'])]) def test_Registry_after_step_with_tags(self): @@ -286,9 +295,12 @@ def test_Registry_after_step_with_tags(self): registry.add_after_step(info['func'], info['tags']) self.assertEqual([info1['func']], [i.impl for i in registry.after_step([])]) - self.assertEqual([x['func'] for x in infos], [i.impl for i in registry.after_step(['A', 'b'])]) - self.assertEqual([info1['func'], info3['func']], [i.impl for i in registry.after_step(['A', 'b', 'c'])]) - self.assertEqual([info1['func'], info3['func']], [i.impl for i in registry.after_step(['A'])]) + self.assertEqual([x['func'] for x in infos], [ + i.impl for i in registry.after_step(['A', 'b'])]) + self.assertEqual([info1['func'], info3['func']], [ + i.impl for i in registry.after_step(['A', 'b', 'c'])]) + self.assertEqual([info1['func'], info3['func']], [ + i.impl for i in registry.after_step(['A'])]) self.assertEqual([info1['func']], [i.impl for i in registry.after_step(['A', 'c'])]) def test_Registry__step_positions_of_a_given_file(self): @@ -361,6 +373,21 @@ def test_Registry_get_all_methods_in_should_give_all_the_methods_define_in_that_ self.assertEqual(3, len(registry.get_all_methods_in("foo.py"))) self.assertEqual(2, len(registry.get_all_methods_in("bar.py"))) + def test_Registry_get_all_methods_in_should_handle_paths_case_sensitive(self): + lower_c_drive = 'c:/random/path/foo.py' + upper_c_drive = 'C:/random/path/foo.py' + + step_infos = [ + {'text': 'Foo', 'func': 'func1', 'file_name': lower_c_drive}, + {'text': 'Foo <>', 'func': 'func2', 'file_name': upper_c_drive} + ] + for info in step_infos: + registry.add_step(info['text'], info['func'], info['file_name']) + + """ Note: we should find both steps regardless the different spelling as the path is in fact equal! """ + self.assertEqual(2, len(registry.get_all_methods_in(lower_c_drive))) + self.assertEqual(2, len(registry.get_all_methods_in(upper_c_drive))) + def tearDown(self): global registry registry = Registry() From f2bc30e44bf1f75e63dda09fe1050c92990372ba Mon Sep 17 00:00:00 2001 From: sschulz92 Date: Fri, 22 Aug 2025 08:35:53 +0200 Subject: [PATCH 05/12] Revert unwanted formatting Signed-off-by: sschulz92 --- tests/test_registry.py | 36 ++++++++++++------------------------ 1 file changed, 12 insertions(+), 24 deletions(-) diff --git a/tests/test_registry.py b/tests/test_registry.py index bd4d583..bb1ef41 100644 --- a/tests/test_registry.py +++ b/tests/test_registry.py @@ -160,12 +160,9 @@ def test_Registry_before_spec_with_tags(self): registry.add_before_spec(info['func'], info['tags']) self.assertEqual([info1['func']], [i.impl for i in registry.before_spec([])]) - self.assertEqual([x['func'] for x in infos], [ - i.impl for i in registry.before_spec(['A', 'b'])]) - self.assertEqual([info1['func'], info3['func']], [ - i.impl for i in registry.before_spec(['A', 'b', 'c'])]) - self.assertEqual([info1['func'], info3['func']], [ - i.impl for i in registry.before_spec(['A'])]) + self.assertEqual([x['func'] for x in infos], [i.impl for i in registry.before_spec(['A', 'b'])]) + self.assertEqual([info1['func'], info3['func']], [i.impl for i in registry.before_spec(['A', 'b', 'c'])]) + self.assertEqual([info1['func'], info3['func']], [i.impl for i in registry.before_spec(['A'])]) self.assertEqual([info1['func']], [i.impl for i in registry.before_spec(['A', 'c'])]) def test_Registry_after_spec_with_tags(self): @@ -179,12 +176,9 @@ def test_Registry_after_spec_with_tags(self): registry.add_after_spec(info['func'], info['tags']) self.assertEqual([info1['func']], [i.impl for i in registry.after_spec([])]) - self.assertEqual([x['func'] for x in infos], [ - i.impl for i in registry.after_spec(['A', 'b'])]) - self.assertEqual([info1['func'], info3['func']], [ - i.impl for i in registry.after_spec(['A', 'b', 'c'])]) - self.assertEqual([info1['func'], info3['func']], [ - i.impl for i in registry.after_spec(['A'])]) + self.assertEqual([x['func'] for x in infos], [i.impl for i in registry.after_spec(['A', 'b'])]) + self.assertEqual([info1['func'], info3['func']], [i.impl for i in registry.after_spec(['A', 'b', 'c'])]) + self.assertEqual([info1['func'], info3['func']], [i.impl for i in registry.after_spec(['A'])]) self.assertEqual([info1['func']], [i.impl for i in registry.after_spec(['A', 'c'])]) def test_Registry_before_scenario(self): @@ -275,12 +269,9 @@ def test_Registry_before_step_with_tags(self): registry.add_before_step(info['func'], info['tags']) self.assertEqual([info1['func']], [i.impl for i in registry.before_step([])]) - self.assertEqual([x['func'] for x in infos], [ - i.impl for i in registry.before_step(['A', 'b'])]) - self.assertEqual([info1['func'], info3['func']], [ - i.impl for i in registry.before_step(['A', 'b', 'c'])]) - self.assertEqual([info1['func'], info3['func']], [ - i.impl for i in registry.before_step(['A'])]) + self.assertEqual([x['func'] for x in infos], [i.impl for i in registry.before_step(['A', 'b'])]) + self.assertEqual([info1['func'], info3['func']], [i.impl for i in registry.before_step(['A', 'b', 'c'])]) + self.assertEqual([info1['func'], info3['func']], [i.impl for i in registry.before_step(['A'])]) self.assertEqual([info1['func']], [i.impl for i in registry.before_step(['A', 'c'])]) def test_Registry_after_step_with_tags(self): @@ -295,12 +286,9 @@ def test_Registry_after_step_with_tags(self): registry.add_after_step(info['func'], info['tags']) self.assertEqual([info1['func']], [i.impl for i in registry.after_step([])]) - self.assertEqual([x['func'] for x in infos], [ - i.impl for i in registry.after_step(['A', 'b'])]) - self.assertEqual([info1['func'], info3['func']], [ - i.impl for i in registry.after_step(['A', 'b', 'c'])]) - self.assertEqual([info1['func'], info3['func']], [ - i.impl for i in registry.after_step(['A'])]) + self.assertEqual([x['func'] for x in infos], [i.impl for i in registry.after_step(['A', 'b'])]) + self.assertEqual([info1['func'], info3['func']], [i.impl for i in registry.after_step(['A', 'b', 'c'])]) + self.assertEqual([info1['func'], info3['func']], [i.impl for i in registry.after_step(['A'])]) self.assertEqual([info1['func']], [i.impl for i in registry.after_step(['A', 'c'])]) def test_Registry__step_positions_of_a_given_file(self): From 9deb27ab8256bdd7499daf1832dbf49c29bb2843 Mon Sep 17 00:00:00 2001 From: sschulz92 Date: Fri, 22 Aug 2025 08:52:25 +0200 Subject: [PATCH 06/12] Add test to verify case-sensitive paths, skip the other one if OS is not Windows Signed-off-by: sschulz92 --- getgauge/registry.py | 9 ++++--- tests/test_registry.py | 54 ++++++++++++++++++++++++++++++++---------- 2 files changed, 48 insertions(+), 15 deletions(-) diff --git a/getgauge/registry.py b/getgauge/registry.py index 7efce2d..e2308e0 100644 --- a/getgauge/registry.py +++ b/getgauge/registry.py @@ -130,9 +130,8 @@ def add(self, func=None, tags=None, file_name=""): def add_step(self, step_text, func, file_name, span=None, has_alias=False, aliases=None): if not isinstance(step_text, list): parsed_step_text = _get_step_value(step_text) - normalized_file_path = os.path.normcase(str(Path(file_name))) info = StepInfo(step_text, parsed_step_text, func, - normalized_file_path, span, has_alias, aliases) + file_name, span, has_alias, aliases) self.__steps_map.setdefault(parsed_step_text, []).append(info) return for text in step_text: @@ -220,7 +219,11 @@ def paths_equal(p1: Union[str, Path], p2: Union[str, Path]) -> bool: """ p1 = Path(p1).resolve() p2 = Path(p2).resolve() - return os.path.normcase(str(p1)) == os.path.normcase(str(p2)) + if sys.platform.startswith("win"): + # As Windows is case-insensitive, we can use 'normcase' to compare paths! + return os.path.normcase(str(p1)) == os.path.normcase(str(p2)) + # Mac (and others) allows to use case-sensitive files/folders! + return p1 == p2 def _filter_hooks(tags, hooks): diff --git a/tests/test_registry.py b/tests/test_registry.py index bb1ef41..7b848ac 100644 --- a/tests/test_registry.py +++ b/tests/test_registry.py @@ -1,4 +1,5 @@ import re +import sys import unittest from getgauge.registry import Registry @@ -160,9 +161,12 @@ def test_Registry_before_spec_with_tags(self): registry.add_before_spec(info['func'], info['tags']) self.assertEqual([info1['func']], [i.impl for i in registry.before_spec([])]) - self.assertEqual([x['func'] for x in infos], [i.impl for i in registry.before_spec(['A', 'b'])]) - self.assertEqual([info1['func'], info3['func']], [i.impl for i in registry.before_spec(['A', 'b', 'c'])]) - self.assertEqual([info1['func'], info3['func']], [i.impl for i in registry.before_spec(['A'])]) + self.assertEqual([x['func'] for x in infos], [ + i.impl for i in registry.before_spec(['A', 'b'])]) + self.assertEqual([info1['func'], info3['func']], [ + i.impl for i in registry.before_spec(['A', 'b', 'c'])]) + self.assertEqual([info1['func'], info3['func']], [ + i.impl for i in registry.before_spec(['A'])]) self.assertEqual([info1['func']], [i.impl for i in registry.before_spec(['A', 'c'])]) def test_Registry_after_spec_with_tags(self): @@ -176,9 +180,12 @@ def test_Registry_after_spec_with_tags(self): registry.add_after_spec(info['func'], info['tags']) self.assertEqual([info1['func']], [i.impl for i in registry.after_spec([])]) - self.assertEqual([x['func'] for x in infos], [i.impl for i in registry.after_spec(['A', 'b'])]) - self.assertEqual([info1['func'], info3['func']], [i.impl for i in registry.after_spec(['A', 'b', 'c'])]) - self.assertEqual([info1['func'], info3['func']], [i.impl for i in registry.after_spec(['A'])]) + self.assertEqual([x['func'] for x in infos], [ + i.impl for i in registry.after_spec(['A', 'b'])]) + self.assertEqual([info1['func'], info3['func']], [ + i.impl for i in registry.after_spec(['A', 'b', 'c'])]) + self.assertEqual([info1['func'], info3['func']], [ + i.impl for i in registry.after_spec(['A'])]) self.assertEqual([info1['func']], [i.impl for i in registry.after_spec(['A', 'c'])]) def test_Registry_before_scenario(self): @@ -269,9 +276,12 @@ def test_Registry_before_step_with_tags(self): registry.add_before_step(info['func'], info['tags']) self.assertEqual([info1['func']], [i.impl for i in registry.before_step([])]) - self.assertEqual([x['func'] for x in infos], [i.impl for i in registry.before_step(['A', 'b'])]) - self.assertEqual([info1['func'], info3['func']], [i.impl for i in registry.before_step(['A', 'b', 'c'])]) - self.assertEqual([info1['func'], info3['func']], [i.impl for i in registry.before_step(['A'])]) + self.assertEqual([x['func'] for x in infos], [ + i.impl for i in registry.before_step(['A', 'b'])]) + self.assertEqual([info1['func'], info3['func']], [ + i.impl for i in registry.before_step(['A', 'b', 'c'])]) + self.assertEqual([info1['func'], info3['func']], [ + i.impl for i in registry.before_step(['A'])]) self.assertEqual([info1['func']], [i.impl for i in registry.before_step(['A', 'c'])]) def test_Registry_after_step_with_tags(self): @@ -286,9 +296,12 @@ def test_Registry_after_step_with_tags(self): registry.add_after_step(info['func'], info['tags']) self.assertEqual([info1['func']], [i.impl for i in registry.after_step([])]) - self.assertEqual([x['func'] for x in infos], [i.impl for i in registry.after_step(['A', 'b'])]) - self.assertEqual([info1['func'], info3['func']], [i.impl for i in registry.after_step(['A', 'b', 'c'])]) - self.assertEqual([info1['func'], info3['func']], [i.impl for i in registry.after_step(['A'])]) + self.assertEqual([x['func'] for x in infos], [ + i.impl for i in registry.after_step(['A', 'b'])]) + self.assertEqual([info1['func'], info3['func']], [ + i.impl for i in registry.after_step(['A', 'b', 'c'])]) + self.assertEqual([info1['func'], info3['func']], [ + i.impl for i in registry.after_step(['A'])]) self.assertEqual([info1['func']], [i.impl for i in registry.after_step(['A', 'c'])]) def test_Registry__step_positions_of_a_given_file(self): @@ -361,6 +374,7 @@ def test_Registry_get_all_methods_in_should_give_all_the_methods_define_in_that_ self.assertEqual(3, len(registry.get_all_methods_in("foo.py"))) self.assertEqual(2, len(registry.get_all_methods_in("bar.py"))) + @unittest.skipIf(sys.platform == "darwin", "Fails on macOS due to case sensitivity") def test_Registry_get_all_methods_in_should_handle_paths_case_sensitive(self): lower_c_drive = 'c:/random/path/foo.py' upper_c_drive = 'C:/random/path/foo.py' @@ -376,6 +390,22 @@ def test_Registry_get_all_methods_in_should_handle_paths_case_sensitive(self): self.assertEqual(2, len(registry.get_all_methods_in(lower_c_drive))) self.assertEqual(2, len(registry.get_all_methods_in(upper_c_drive))) + @unittest.skipIf(sys.platform.startswith("win"), "Fails on macOS due to case sensitivity") + def test_Registry_get_all_methods_in_should_handle_paths_case_sensitive_on_mac(self): + path1 = '/random/path/foo.py' + path2 = '/random/PATH/foo.py' + + step_infos = [ + {'text': 'Foo', 'func': 'func1', 'file_name': path1}, + {'text': 'Foo <>', 'func': 'func2', 'file_name': path2} + ] + for info in step_infos: + registry.add_step(info['text'], info['func'], info['file_name']) + + """ Note: since the paths are in fact different, they should be treated as different paths! """ + self.assertEqual(1, len(registry.get_all_methods_in(path1))) + self.assertEqual(1, len(registry.get_all_methods_in(path2))) + def tearDown(self): global registry registry = Registry() From e70c255484b113d720be9f567f2ff87417ee5a64 Mon Sep 17 00:00:00 2001 From: sschulz92 Date: Fri, 22 Aug 2025 08:54:46 +0200 Subject: [PATCH 07/12] Run test if OS is Windows only Signed-off-by: sschulz92 --- tests/test_registry.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_registry.py b/tests/test_registry.py index 7b848ac..1735ba7 100644 --- a/tests/test_registry.py +++ b/tests/test_registry.py @@ -374,7 +374,7 @@ def test_Registry_get_all_methods_in_should_give_all_the_methods_define_in_that_ self.assertEqual(3, len(registry.get_all_methods_in("foo.py"))) self.assertEqual(2, len(registry.get_all_methods_in("bar.py"))) - @unittest.skipIf(sys.platform == "darwin", "Fails on macOS due to case sensitivity") + @unittest.skipIf(not sys.platform.startswith("win"), "Test is designed to cover Windows like paths") def test_Registry_get_all_methods_in_should_handle_paths_case_sensitive(self): lower_c_drive = 'c:/random/path/foo.py' upper_c_drive = 'C:/random/path/foo.py' @@ -390,7 +390,7 @@ def test_Registry_get_all_methods_in_should_handle_paths_case_sensitive(self): self.assertEqual(2, len(registry.get_all_methods_in(lower_c_drive))) self.assertEqual(2, len(registry.get_all_methods_in(upper_c_drive))) - @unittest.skipIf(sys.platform.startswith("win"), "Fails on macOS due to case sensitivity") + @unittest.skipIf(sys.platform.startswith("win"), "Fails on Windows due to case sensitivity") def test_Registry_get_all_methods_in_should_handle_paths_case_sensitive_on_mac(self): path1 = '/random/path/foo.py' path2 = '/random/PATH/foo.py' From 9a063f7a2c968711ee0f8d51a30765395c4ac34e Mon Sep 17 00:00:00 2001 From: sschulz92 Date: Wed, 27 Aug 2025 14:12:36 +0200 Subject: [PATCH 08/12] Temporary changes Signed-off-by: sschulz92 --- getgauge/impl_loader.py | 65 +++++++++++++++++++++++---------------- getgauge/registry.py | 19 ++++-------- tests/test_impl_loader.py | 64 ++++++++++++++++++++++++++++---------- 3 files changed, 91 insertions(+), 57 deletions(-) diff --git a/getgauge/impl_loader.py b/getgauge/impl_loader.py index 802b083..2f2b10d 100644 --- a/getgauge/impl_loader.py +++ b/getgauge/impl_loader.py @@ -8,7 +8,10 @@ import sys import traceback from contextlib import contextmanager +from importlib import util as importlib_util from os import path +from pathlib import Path +from typing import Optional from getgauge import logger from getgauge.registry import registry @@ -19,28 +22,33 @@ env_dir = os.path.join(project_root, 'env', 'default') requirements_file = os.path.join(project_root, 'requirements.txt') sys.path.append(project_root) -temporary_sys_path = [] + PLUGIN_JSON = 'python.json' VERSION = 'version' PYTHON_PROPERTIES = 'python.properties' SKEL = 'skel' -def load_impls(step_impl_dirs=impl_dirs): +def load_impls(step_impl_dirs=impl_dirs, project_root=project_root): + """ project_root can be overwritten in tests! """ os.chdir(project_root) + logger.debug('Project root: {}'.format(project_root)) for impl_dir in step_impl_dirs: - if not os.path.isdir(impl_dir): - logger.error('Cannot import step implementations. Error: {} does not exist.'.format(step_impl_dirs)) + resolved_impl_dir = Path(impl_dir).resolve() + if not resolved_impl_dir.is_dir(): + logger.error('Cannot import step implementations. Error: {} does not exist.'.format(impl_dir)) logger.error('Make sure `STEP_IMPL_DIR` env var is set to a valid directory path.') return - base_dir = project_root if impl_dir.startswith(project_root) else os.path.dirname(impl_dir) - # Handle multi-level relative imports - for _ in range(impl_dir.count('..')): - base_dir = os.path.dirname(base_dir).replace("/", os.path.sep).replace("\\", os.path.sep) - # Add temporary sys path for relative imports that is not already added - if '..' in impl_dir and base_dir not in temporary_sys_path: - temporary_sys_path.append(base_dir) - _import_impl(base_dir, impl_dir) + + base_dir = project_root if str(resolved_impl_dir).startswith(project_root) else os.path.dirname(resolved_impl_dir) + + # Add temporary sys path for imports outside the project root + temporary_sys_path = None + if base_dir != project_root: + logger.debug('Found different base directory compared to the project root: {}'.format(base_dir, f"{resolved_impl_dir}")) + temporary_sys_path = base_dir + + _import_impl(base_dir, resolved_impl_dir, temporary_sys_path) def copy_skel_files(): @@ -58,29 +66,35 @@ def copy_skel_files(): logger.fatal('Exception occurred while copying skel files.\n{}.'.format(traceback.format_exc())) -def _import_impl(base_dir, step_impl_dir): - for python_file in glob.glob(f"{step_impl_dir}/**/*.py", recursive=True): - _import_file(base_dir, python_file) +def _import_impl(base_dir: str, absolute_step_impl_dir: str, temporary_sys_path: Optional[str]): + for python_file in glob.glob(f"{absolute_step_impl_dir}/**/*.py", recursive=True): + if python_file.endswith("__init__.py"): + continue + relative_path = os.path.normpath(python_file.replace(base_dir + os.path.sep, '')) + module_name = os.path.splitext(relative_path.replace(os.path.sep, '.'))[0] + _import_file(module_name, python_file, temporary_sys_path) @contextmanager -def use_temporary_sys_path(): +def use_temporary_sys_path(temporary_sys_path: str): original_sys_path = sys.path[:] - sys.path.extend(temporary_sys_path) + sys.path.append(temporary_sys_path) try: yield finally: sys.path = original_sys_path -def _import_file(base_dir, file_path): - rel_path = os.path.normpath(file_path.replace(base_dir + os.path.sep, '')) +def _import_file(module_name: str, file_path: str, temporary_sys_path: Optional[str]): try: - module_name = os.path.splitext(rel_path.replace(os.path.sep, '.'))[0] + logger.debug('Import module {} with path {}'.format(module_name, file_path)) + # Use temporary sys path for relative imports - if '..' in file_path: - with use_temporary_sys_path(): + if temporary_sys_path is not None: + logger.debug('Import module {} using temporary sys path {}'.format(module_name, temporary_sys_path)) + with use_temporary_sys_path(temporary_sys_path): m = importlib.import_module(module_name) else: m = importlib.import_module(module_name) + # Get all classes in the imported module classes = inspect.getmembers(m, lambda member: inspect.isclass(member) and member.__module__ == module_name) if len(classes) > 0: @@ -92,13 +106,10 @@ def _import_file(base_dir, file_path): file_path=file_path ) except: - logger.fatal('Exception occurred while loading step implementations from file: {}.\n{}'.format(rel_path, traceback.format_exc())) + logger.fatal('Exception occurred while loading step implementations from file: {}.\n{}'.format(file_path, traceback.format_exc())) -def update_step_registry_with_class(instance, file_path): +def update_step_registry_with_class(instance, file_path: str): """ Inject instance in each class method (hook/step) """ - # Resolve the absolute path from relative path - # Note: relative path syntax ".." can appear in between the file_path too like "/../../Other_Project/src/step_impl/file.py" - file_path = os.path.abspath(file_path) if ".." in str(file_path) else file_path method_list = registry.get_all_methods_in(file_path) for info in method_list: class_methods = [x[0] for x in inspect.getmembers(instance, inspect.ismethod)] diff --git a/getgauge/registry.py b/getgauge/registry.py index e2308e0..b2d15f8 100644 --- a/getgauge/registry.py +++ b/getgauge/registry.py @@ -113,6 +113,9 @@ def __init__(self): for hook in Registry.hooks: self.__def_hook(hook) + def get_steps_map(self): + return self.__steps_map + def __def_hook(self, hook): def get(self, tags=None): return _filter_hooks(tags, getattr(self, '__{}'.format(hook))) @@ -185,7 +188,7 @@ def _get_all_hooks(self, file_name): if paths_equal(h.file_name, file_name)] return all_hooks - def get_all_methods_in(self, file_name): + def get_all_methods_in(self, file_name: str): methods = [] for _, infos in self.__steps_map.items(): methods = methods + [i for i in infos if paths_equal(i.file_name, file_name)] @@ -212,18 +215,8 @@ def clear(self): def paths_equal(p1: Union[str, Path], p2: Union[str, Path]) -> bool: - """ - Compare two paths in a cross-platform safe way. - On Windows: case-insensitive, slash-insensitive. - On Linux/macOS: case-sensitive. - """ - p1 = Path(p1).resolve() - p2 = Path(p2).resolve() - if sys.platform.startswith("win"): - # As Windows is case-insensitive, we can use 'normcase' to compare paths! - return os.path.normcase(str(p1)) == os.path.normcase(str(p2)) - # Mac (and others) allows to use case-sensitive files/folders! - return p1 == p2 + """ Normalize paths in order to compare them. """ + return os.path.normcase(str(p1)) == os.path.normcase(str(p2)) def _filter_hooks(tags, hooks): diff --git a/tests/test_impl_loader.py b/tests/test_impl_loader.py index d14afc8..6e94339 100644 --- a/tests/test_impl_loader.py +++ b/tests/test_impl_loader.py @@ -1,30 +1,60 @@ import os import unittest +from pathlib import Path -from getgauge.impl_loader import update_step_registry_with_class -from test_relative_import.relative_import_class import Sample +from getgauge.impl_loader import load_impls +from getgauge.registry import registry class ImplLoaderTest(unittest.TestCase): - def setUp(self): - self.curr_dir = os.getcwd() - self.relative_file_path = os.path.join('..', 'test_relative_import', 'relative_import_class.py') - self.relative_file_path_one_level_above = os.path.join('tests', '..', 'test_relative_import', 'relative_import_class.py') def test_update_step_registry_with_class(self): - os.chdir('tests') - method_list = update_step_registry_with_class(Sample(), self.relative_file_path) - os.chdir(self.curr_dir) - self.assertEqual(["Greet from inside the class", - "Greet from outside the class"], - [method.step_text for method in method_list]) + + tests_directory = str(Path(__file__).resolve().parent) + relative_file_path = os.path.join('..', 'test_relative_import') + + load_impls( + step_impl_dirs=[relative_file_path], + project_root=tests_directory + ) + + loaded_steps = registry.get_steps_map() + + self.assertEqual(2, len(loaded_steps)) + + step_infos_of_class_instance = loaded_steps["Greet {} from inside the class"] + + self.assertEqual(1, len(step_infos_of_class_instance)) + self.assertIsNotNone(step_infos_of_class_instance[0].instance) + + self.assertEqual( + ["Greet from inside the class", "Greet from outside the class"], + registry.steps() + ) def test_update_step_registry_with_class_one_level_above(self): - os.chdir(self.curr_dir) - method_list = update_step_registry_with_class(Sample(), self.relative_file_path_one_level_above) - self.assertEqual(["Greet from inside the class", - "Greet from outside the class"], - [method.step_text for method in method_list]) + + repo_root_directory = str(Path(__file__).resolve().parent.parent) + relative_file_path_one_level_above = os.path.join('tests', '..', 'test_relative_import') + + load_impls( + step_impl_dirs=[relative_file_path_one_level_above], + project_root=repo_root_directory + ) + + loaded_steps = registry.get_steps_map() + + self.assertEqual(2, len(loaded_steps)) + + step_infos_of_class_instance = loaded_steps["Greet {} from inside the class"] + + self.assertEqual(1, len(step_infos_of_class_instance)) + self.assertIsNotNone(step_infos_of_class_instance[0].instance) + + self.assertEqual( + ["Greet from inside the class", "Greet from outside the class"], + registry.steps() + ) if __name__ == '__main__': From 8b8d983d751f7abcf199f4f3e35534add5e46940 Mon Sep 17 00:00:00 2001 From: sschulz92 Date: Fri, 29 Aug 2025 08:22:42 +0200 Subject: [PATCH 09/12] Resolve impl_loader issue if step_impl is the first part of the module to import Signed-off-by: sschulz92 --- getgauge/impl_loader.py | 18 ++++++++---------- tests/test_impl_loader.py | 15 ++++++++++----- .../test_relative_import}/__init__.py | 0 .../relative_import_class.py | 0 4 files changed, 18 insertions(+), 15 deletions(-) rename {test_relative_import => tests/test_relative_import}/__init__.py (100%) rename {test_relative_import => tests/test_relative_import}/relative_import_class.py (100%) diff --git a/getgauge/impl_loader.py b/getgauge/impl_loader.py index 2f2b10d..6557a42 100644 --- a/getgauge/impl_loader.py +++ b/getgauge/impl_loader.py @@ -8,7 +8,6 @@ import sys import traceback from contextlib import contextmanager -from importlib import util as importlib_util from os import path from pathlib import Path from typing import Optional @@ -31,21 +30,22 @@ def load_impls(step_impl_dirs=impl_dirs, project_root=project_root): """ project_root can be overwritten in tests! """ + os.chdir(project_root) - logger.debug('Project root: {}'.format(project_root)) + for impl_dir in step_impl_dirs: + resolved_impl_dir = Path(impl_dir).resolve() if not resolved_impl_dir.is_dir(): logger.error('Cannot import step implementations. Error: {} does not exist.'.format(impl_dir)) logger.error('Make sure `STEP_IMPL_DIR` env var is set to a valid directory path.') return - base_dir = project_root if str(resolved_impl_dir).startswith(project_root) else os.path.dirname(resolved_impl_dir) + base_dir = os.path.commonpath([project_root, f"{resolved_impl_dir}"]) + logger.debug("Base directory '{}' of '{}'".format(base_dir, resolved_impl_dir)) - # Add temporary sys path for imports outside the project root temporary_sys_path = None - if base_dir != project_root: - logger.debug('Found different base directory compared to the project root: {}'.format(base_dir, f"{resolved_impl_dir}")) + if project_root != base_dir: temporary_sys_path = base_dir _import_impl(base_dir, resolved_impl_dir, temporary_sys_path) @@ -68,10 +68,8 @@ def copy_skel_files(): def _import_impl(base_dir: str, absolute_step_impl_dir: str, temporary_sys_path: Optional[str]): for python_file in glob.glob(f"{absolute_step_impl_dir}/**/*.py", recursive=True): - if python_file.endswith("__init__.py"): - continue - relative_path = os.path.normpath(python_file.replace(base_dir + os.path.sep, '')) - module_name = os.path.splitext(relative_path.replace(os.path.sep, '.'))[0] + relative_path = Path(python_file).relative_to(base_dir) + module_name = ".".join(relative_path.parts).replace(".py", "") _import_file(module_name, python_file, temporary_sys_path) @contextmanager diff --git a/tests/test_impl_loader.py b/tests/test_impl_loader.py index 6e94339..bad56b8 100644 --- a/tests/test_impl_loader.py +++ b/tests/test_impl_loader.py @@ -5,17 +5,19 @@ from getgauge.impl_loader import load_impls from getgauge.registry import registry +DIRECTORY_NAME = "test_relative_import" + class ImplLoaderTest(unittest.TestCase): def test_update_step_registry_with_class(self): - tests_directory = str(Path(__file__).resolve().parent) - relative_file_path = os.path.join('..', 'test_relative_import') + test_relative_import_directory = str(Path(__file__).resolve().parent / DIRECTORY_NAME) + relative_file_path = os.path.join('..', DIRECTORY_NAME) load_impls( step_impl_dirs=[relative_file_path], - project_root=tests_directory + project_root=test_relative_import_directory ) loaded_steps = registry.get_steps_map() @@ -35,7 +37,7 @@ def test_update_step_registry_with_class(self): def test_update_step_registry_with_class_one_level_above(self): repo_root_directory = str(Path(__file__).resolve().parent.parent) - relative_file_path_one_level_above = os.path.join('tests', '..', 'test_relative_import') + relative_file_path_one_level_above = os.path.join('tests', '..', 'tests', DIRECTORY_NAME) load_impls( step_impl_dirs=[relative_file_path_one_level_above], @@ -44,7 +46,7 @@ def test_update_step_registry_with_class_one_level_above(self): loaded_steps = registry.get_steps_map() - self.assertEqual(2, len(loaded_steps)) + self.assertEqual(2, len(loaded_steps), f"Steps found: {loaded_steps}") step_infos_of_class_instance = loaded_steps["Greet {} from inside the class"] @@ -56,6 +58,9 @@ def test_update_step_registry_with_class_one_level_above(self): registry.steps() ) + def tearDown(self): + registry.clear() + if __name__ == '__main__': unittest.main() diff --git a/test_relative_import/__init__.py b/tests/test_relative_import/__init__.py similarity index 100% rename from test_relative_import/__init__.py rename to tests/test_relative_import/__init__.py diff --git a/test_relative_import/relative_import_class.py b/tests/test_relative_import/relative_import_class.py similarity index 100% rename from test_relative_import/relative_import_class.py rename to tests/test_relative_import/relative_import_class.py From e9744a37cb62cb553d88f26ecac37d0ee123f3bc Mon Sep 17 00:00:00 2001 From: sschulz92 Date: Fri, 29 Aug 2025 09:33:05 +0200 Subject: [PATCH 10/12] Upgrade Java version to support newer gradle Signed-off-by: sschulz92 --- .github/workflows/tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index a3b34e4..9607c36 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -62,7 +62,7 @@ jobs: uses: actions/setup-java@v4 with: distribution: 'temurin' - java-version: '11' + java-version: '17' - uses: getgauge/setup-gauge@master with: From 323192d895e22784d87f5da002884e4dc03e9a8d Mon Sep 17 00:00:00 2001 From: sschulz92 Date: Fri, 29 Aug 2025 09:40:45 +0200 Subject: [PATCH 11/12] Actually fix merge-conflict ... Signed-off-by: sschulz92 --- .github/workflows/tests.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 691795f..a0a1f59 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -62,11 +62,7 @@ jobs: uses: actions/setup-java@v4 with: distribution: 'temurin' -<<<<<<< HEAD - java-version: '17' -======= java-version: '21' ->>>>>>> github/master - uses: getgauge/setup-gauge@master with: From 62414f99242e49ff38d5a232226479d7ff399cae Mon Sep 17 00:00:00 2001 From: sschulz92 Date: Tue, 2 Sep 2025 10:48:30 +0200 Subject: [PATCH 12/12] Revert formatting changes Signed-off-by: sschulz92 --- getgauge/util.py | 8 ++++---- tests/test_registry.py | 36 ++++++++++++------------------------ 2 files changed, 16 insertions(+), 28 deletions(-) diff --git a/getgauge/util.py b/getgauge/util.py index f6f056b..d1051d3 100644 --- a/getgauge/util.py +++ b/getgauge/util.py @@ -14,10 +14,10 @@ def get_project_root(): def get_step_impl_dirs(): step_impl_dir_names = map(str.strip, os.getenv(STEP_IMPL_DIR_ENV).split(',')) if os.getenv(STEP_IMPL_DIR_ENV) else ['step_impl'] full_path_dir_names = [] - for dir_name in step_impl_dir_names: - dir_name = dir_name.replace("/", os.path.sep).replace("\\", os.path.sep) - impl_dir = dir_name if os.path.isabs(dir_name) else os.path.join(get_project_root(), dir_name) - full_path_dir_names.append(impl_dir) + for name in step_impl_dir_names: + name = name.replace("/", os.path.sep).replace("\\", os.path.sep) + imple_dir = name if os.path.isabs(name) else os.path.join(get_project_root(), name) + full_path_dir_names.append(imple_dir) return full_path_dir_names diff --git a/tests/test_registry.py b/tests/test_registry.py index 1735ba7..c904275 100644 --- a/tests/test_registry.py +++ b/tests/test_registry.py @@ -161,12 +161,9 @@ def test_Registry_before_spec_with_tags(self): registry.add_before_spec(info['func'], info['tags']) self.assertEqual([info1['func']], [i.impl for i in registry.before_spec([])]) - self.assertEqual([x['func'] for x in infos], [ - i.impl for i in registry.before_spec(['A', 'b'])]) - self.assertEqual([info1['func'], info3['func']], [ - i.impl for i in registry.before_spec(['A', 'b', 'c'])]) - self.assertEqual([info1['func'], info3['func']], [ - i.impl for i in registry.before_spec(['A'])]) + self.assertEqual([x['func'] for x in infos], [i.impl for i in registry.before_spec(['A', 'b'])]) + self.assertEqual([info1['func'], info3['func']], [i.impl for i in registry.before_spec(['A', 'b', 'c'])]) + self.assertEqual([info1['func'], info3['func']], [i.impl for i in registry.before_spec(['A'])]) self.assertEqual([info1['func']], [i.impl for i in registry.before_spec(['A', 'c'])]) def test_Registry_after_spec_with_tags(self): @@ -180,12 +177,9 @@ def test_Registry_after_spec_with_tags(self): registry.add_after_spec(info['func'], info['tags']) self.assertEqual([info1['func']], [i.impl for i in registry.after_spec([])]) - self.assertEqual([x['func'] for x in infos], [ - i.impl for i in registry.after_spec(['A', 'b'])]) - self.assertEqual([info1['func'], info3['func']], [ - i.impl for i in registry.after_spec(['A', 'b', 'c'])]) - self.assertEqual([info1['func'], info3['func']], [ - i.impl for i in registry.after_spec(['A'])]) + self.assertEqual([x['func'] for x in infos], [i.impl for i in registry.after_spec(['A', 'b'])]) + self.assertEqual([info1['func'], info3['func']], [i.impl for i in registry.after_spec(['A', 'b', 'c'])]) + self.assertEqual([info1['func'], info3['func']], [i.impl for i in registry.after_spec(['A'])]) self.assertEqual([info1['func']], [i.impl for i in registry.after_spec(['A', 'c'])]) def test_Registry_before_scenario(self): @@ -276,12 +270,9 @@ def test_Registry_before_step_with_tags(self): registry.add_before_step(info['func'], info['tags']) self.assertEqual([info1['func']], [i.impl for i in registry.before_step([])]) - self.assertEqual([x['func'] for x in infos], [ - i.impl for i in registry.before_step(['A', 'b'])]) - self.assertEqual([info1['func'], info3['func']], [ - i.impl for i in registry.before_step(['A', 'b', 'c'])]) - self.assertEqual([info1['func'], info3['func']], [ - i.impl for i in registry.before_step(['A'])]) + self.assertEqual([x['func'] for x in infos], [i.impl for i in registry.before_step(['A', 'b'])]) + self.assertEqual([info1['func'], info3['func']], [i.impl for i in registry.before_step(['A', 'b', 'c'])]) + self.assertEqual([info1['func'], info3['func']], [i.impl for i in registry.before_step(['A'])]) self.assertEqual([info1['func']], [i.impl for i in registry.before_step(['A', 'c'])]) def test_Registry_after_step_with_tags(self): @@ -296,12 +287,9 @@ def test_Registry_after_step_with_tags(self): registry.add_after_step(info['func'], info['tags']) self.assertEqual([info1['func']], [i.impl for i in registry.after_step([])]) - self.assertEqual([x['func'] for x in infos], [ - i.impl for i in registry.after_step(['A', 'b'])]) - self.assertEqual([info1['func'], info3['func']], [ - i.impl for i in registry.after_step(['A', 'b', 'c'])]) - self.assertEqual([info1['func'], info3['func']], [ - i.impl for i in registry.after_step(['A'])]) + self.assertEqual([x['func'] for x in infos], [i.impl for i in registry.after_step(['A', 'b'])]) + self.assertEqual([info1['func'], info3['func']], [i.impl for i in registry.after_step(['A', 'b', 'c'])]) + self.assertEqual([info1['func'], info3['func']], [i.impl for i in registry.after_step(['A'])]) self.assertEqual([info1['func']], [i.impl for i in registry.after_step(['A', 'c'])]) def test_Registry__step_positions_of_a_given_file(self):