From 238f56baaeecf840a19a339611ec725fe2bab937 Mon Sep 17 00:00:00 2001 From: qisijia Date: Mon, 4 Nov 2024 19:25:37 +0800 Subject: [PATCH 1/2] Add Path Validation and Environment Loading to TreeNode Class This pull request introduces path validation and environment loading functionality to the TreeNode class. The changes ensure that the path provided during initialization is valid and that environment variables can be correctly loaded into the node's environment. Signed-off-by: qisijia --- avocado/core/tree.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/avocado/core/tree.py b/avocado/core/tree.py index 387b6a5439..f6a46e7e72 100644 --- a/avocado/core/tree.py +++ b/avocado/core/tree.py @@ -134,6 +134,8 @@ def __init__(self, path, environment=None): :param path: Path of this node (must not end with '/') :param environment: List of pair/key/value items """ + if not path or path.endswith('/'): + raise ValueError("Path must be non-empty and not end with '/'") self.name = path.rsplit("/")[-1] self.path = path self.environment = TreeEnvironment() From 273de37b39e2cbc7ccbefabcaccdb33219e03610 Mon Sep 17 00:00:00 2001 From: qisijia Date: Thu, 7 Nov 2024 16:51:05 +0800 Subject: [PATCH 2/2] Add Path Validation and Environment Loading to TreeNode Class This pull request addresses issues related to invalid paths and the root path name in the `TreeNodeEnvOnly` class. Specifically, it ensures that `ValueError` is raised for all invalid paths and fixes the issue where the root path name was incorrectly set to an empty string, and relevant test cases have been added in selftests/unit/tree.py and tested successfully. Signed-off-by: qisijia --- avocado/core/tree.py | 76 +++++++++++++++++++++++++++++++++++++++--- selftests/unit/tree.py | 38 +++++++++++++++++++++ 2 files changed, 109 insertions(+), 5 deletions(-) diff --git a/avocado/core/tree.py b/avocado/core/tree.py index f6a46e7e72..f8f4cb17e8 100644 --- a/avocado/core/tree.py +++ b/avocado/core/tree.py @@ -32,7 +32,6 @@ original base tree code and re-license under GPLv2+, given that GPLv3 and GPLv2 (used in some avocado files) are incompatible. """ - import collections import copy import itertools @@ -132,11 +131,17 @@ class TreeNodeEnvOnly: def __init__(self, path, environment=None): """ :param path: Path of this node (must not end with '/') - :param environment: List of pair/key/value items + :param environment: List of triple/path/key/value items """ - if not path or path.endswith('/'): - raise ValueError("Path must be non-empty and not end with '/'") - self.name = path.rsplit("/")[-1] + if not path: + raise ValueError("Path must be non-empty") + if path != "/" and (path.endswith('/') or '//' in path): + raise ValueError( + "Path must not end with '/' unless it is the root path '/', and must not contain consecutive slashes.") + if path == "/": + self.name = path + else: + self.name = path.rsplit("/", 1)[-1] self.path = path self.environment = TreeEnvironment() if environment: @@ -544,3 +549,64 @@ def process_node(node): return "\n".join(out).encode( "utf-8" if use_utf8 else "ascii", errors="xmlcharrefreplace" ) + + +import unittest + + +class TestTreeNodeEnvOnly(unittest.TestCase): + def test_valid_paths(self): + valid_paths = ["/", "/root", "/root/node"] + for path in valid_paths: + try: + node = TreeNodeEnvOnly(path) + self.assertEqual(node.path, path) + except ValueError as e: + self.fail(f"Unexpected error for path '{path}': {e}") + + def test_invalid_paths(self): + invalid_paths = ["", "/root/", "/root//node"] + for path in invalid_paths: + with self.assertRaises(ValueError, msg=f"Path '{path}' should raise ValueError"): + TreeNodeEnvOnly(path) + + def test_environment_loading(self): + environment = [ + ("/root", "key1", "value1"), + ("/root/node", "key2", "value2") + ] + node = TreeNodeEnvOnly("/root", environment=environment) + self.assertEqual(node.environment["key1"], "value1") + self.assertEqual(node.environment.origin["key1"].path, "/root") + self.assertEqual(node.environment["key2"], "value2") + self.assertEqual(node.environment.origin["key2"].path, "/root/node") + + def test_invalid_environment_items(self): + invalid_environment = [ + ("/root", "key1", "value1"), + ("/root/node", "key2") + ] + with self.assertRaises(ValueError): + TreeNodeEnvOnly("/root", environment=invalid_environment) + + def test_root_path(self): + node = TreeNodeEnvOnly("/") + self.assertEqual(node.name, "/") + self.assertEqual(node.path, "/") + + def test_path_ending_with_slash(self): + with self.assertRaises(ValueError): + TreeNodeEnvOnly("/root/") + + def test_fingerprint(self): + environment = [ + ("/root", "key1", "value1"), + ("/root/node", "key2", "value2") + ] + node = TreeNodeEnvOnly("/root", environment=environment) + expected_fingerprint = "/root{key1: value1, key2: value2},{key1: /root, key2: /root/node},FilterSet([]),FilterSet([])" + self.assertEqual(node.fingerprint(), expected_fingerprint) + + +if __name__ == "__main__": + unittest.main() diff --git a/selftests/unit/tree.py b/selftests/unit/tree.py index 42b99d4ea8..48dd9b6f38 100644 --- a/selftests/unit/tree.py +++ b/selftests/unit/tree.py @@ -71,3 +71,41 @@ def test_is_leaf(self): self.assertTrue(tree.TreeNode().is_leaf) self.assertTrue(tree.TreeNode(value={"foo": "bar"}).is_leaf) self.assertFalse(tree.TreeNode(children=[tree.TreeNode()]).is_leaf) + + def test_valid_paths(self): + valid_paths = ["/", "/root", "/root/node"] + for path in valid_paths: + try: + node = tree.TreeNodeEnvOnly(path) + self.assertEqual(node.path, path) + except ValueError as e: + self.fail(f"Unexpected error for path '{path}': {e}") + + def test_environment_loading(self): + environment = [ + ("/root", "key1", "value1"), + ("/root/node", "key2", "value2") + ] + node = tree.TreeNodeEnvOnly("/root", environment=environment) + self.assertEqual(node.environment["key1"], "value1") + self.assertEqual(node.environment.origin["key1"].path, "/root") + self.assertEqual(node.environment["key2"], "value2") + self.assertEqual(node.environment.origin["key2"].path, "/root/node") + + def test_invalid_environment_items(self): + invalid_environment = [ + ("/root", "key1", "value1"), + ("/root/node", "key2") + ] + with self.assertRaises(ValueError): + tree.TreeNodeEnvOnly("/root", environment=invalid_environment) + + def test_fingerprint_path(self): + environment = [ + ("/root", "key1", "value1"), + ("/root/node", "key2", "value2") + ] + node = tree.TreeNodeEnvOnly("/root", environment=environment) + expected_fingerprint = "/root{key1: value1, key2: value2}," \ + "{key1: /root, key2: /root/node},FilterSet([]),FilterSet([])" + self.assertEqual(node.fingerprint(), expected_fingerprint)