Skip to content
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

Add Path Validation and Environment Loading to TreeNode Class #6064

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 71 additions & 3 deletions avocado/core/tree.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -132,9 +131,17 @@
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
"""
self.name = path.rsplit("/")[-1]
if not path:
raise ValueError("Path must be non-empty")

Check warning on line 137 in avocado/core/tree.py

View check run for this annotation

Codecov / codecov/patch

avocado/core/tree.py#L137

Added line #L137 was not covered by tests
if path != "/" and (path.endswith('/') or '//' in path):
raise ValueError(

Check warning on line 139 in avocado/core/tree.py

View check run for this annotation

Codecov / codecov/patch

avocado/core/tree.py#L139

Added line #L139 was not covered by tests
"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:
Expand Down Expand Up @@ -542,3 +549,64 @@
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}")

Check warning on line 565 in avocado/core/tree.py

View check run for this annotation

Codecov / codecov/patch

avocado/core/tree.py#L559-L565

Added lines #L559 - L565 were not covered by tests

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)

Check warning on line 571 in avocado/core/tree.py

View check run for this annotation

Codecov / codecov/patch

avocado/core/tree.py#L568-L571

Added lines #L568 - L571 were not covered by tests

def test_environment_loading(self):
environment = [

Check warning on line 574 in avocado/core/tree.py

View check run for this annotation

Codecov / codecov/patch

avocado/core/tree.py#L574

Added line #L574 was not covered by tests
("/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")

Check warning on line 582 in avocado/core/tree.py

View check run for this annotation

Codecov / codecov/patch

avocado/core/tree.py#L578-L582

Added lines #L578 - L582 were not covered by tests

def test_invalid_environment_items(self):
invalid_environment = [

Check warning on line 585 in avocado/core/tree.py

View check run for this annotation

Codecov / codecov/patch

avocado/core/tree.py#L585

Added line #L585 was not covered by tests
("/root", "key1", "value1"),
("/root/node", "key2")
]
with self.assertRaises(ValueError):
TreeNodeEnvOnly("/root", environment=invalid_environment)

Check warning on line 590 in avocado/core/tree.py

View check run for this annotation

Codecov / codecov/patch

avocado/core/tree.py#L589-L590

Added lines #L589 - L590 were not covered by tests

def test_root_path(self):
node = TreeNodeEnvOnly("/")
self.assertEqual(node.name, "/")
self.assertEqual(node.path, "/")

Check warning on line 595 in avocado/core/tree.py

View check run for this annotation

Codecov / codecov/patch

avocado/core/tree.py#L593-L595

Added lines #L593 - L595 were not covered by tests

def test_path_ending_with_slash(self):
with self.assertRaises(ValueError):
TreeNodeEnvOnly("/root/")

Check warning on line 599 in avocado/core/tree.py

View check run for this annotation

Codecov / codecov/patch

avocado/core/tree.py#L598-L599

Added lines #L598 - L599 were not covered by tests

def test_fingerprint(self):
environment = [

Check warning on line 602 in avocado/core/tree.py

View check run for this annotation

Codecov / codecov/patch

avocado/core/tree.py#L602

Added line #L602 was not covered by tests
("/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)

Check warning on line 608 in avocado/core/tree.py

View check run for this annotation

Codecov / codecov/patch

avocado/core/tree.py#L606-L608

Added lines #L606 - L608 were not covered by tests


if __name__ == "__main__":
unittest.main()

Check warning on line 612 in avocado/core/tree.py

View check run for this annotation

Codecov / codecov/patch

avocado/core/tree.py#L612

Added line #L612 was not covered by tests
38 changes: 38 additions & 0 deletions selftests/unit/tree.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Loading