From a7c76eea9a6150cfe13e8e62ca480bbb21f2a30c Mon Sep 17 00:00:00 2001 From: Shreshth-Malik Date: Fri, 7 Feb 2025 00:39:06 -0500 Subject: [PATCH 1/5] Added tests for v.build module --- vector/v.build/testsuite/test_v_build.py | 70 ++++++++++++++++++++++ vector/v.build/testsuite/vbuild_output.txt | 1 + 2 files changed, 71 insertions(+) create mode 100644 vector/v.build/testsuite/test_v_build.py create mode 100644 vector/v.build/testsuite/vbuild_output.txt diff --git a/vector/v.build/testsuite/test_v_build.py b/vector/v.build/testsuite/test_v_build.py new file mode 100644 index 00000000000..2499e8c9ea3 --- /dev/null +++ b/vector/v.build/testsuite/test_v_build.py @@ -0,0 +1,70 @@ +import os +import ast +import grass.script as gs +from grass.gunittest.case import TestCase +from grass.gunittest.main import test + + +class TestVBuild(TestCase): + """Test v.build output against expected output stored in vbuild_output.txt""" + + @classmethod + def setUpClass(cls): + """Set up a temporary region and create vector map with test features.""" + + cls.use_temp_region() + gs.run_command("v.edit", map="test_3x3_map", tool="create", overwrite=True) + gs.run_command("g.region", n=3, s=0, e=3, w=0, res=1) + input_data = "VERTI:\nP 1\n1 1\nL 2\n0.5 0.5\n2.5 2.5" + + with open("input_data.txt", "w") as file: + file.write(input_data) + + # Import features into the vector map using the input file. + gs.run_command( + "v.edit", + map="test_3x3_map", + tool="add", + type="point,line", + input="input_data.txt", + ) + + # Run v.build (with multiple dump options) and store its output in a class variable. + cls.build_module = gs.parse_command( + "v.build", map="test_3x3_map", option="build,dump,sdump,cdump,fdump" + ) + + # Read the expected output from the external file. + with open("vbuild_output.txt") as f: + expected_str = f.read() + cls.expected_output = ast.literal_eval(expected_str) + + @classmethod + def tearDownClass(cls): + """Remove created vector map and temporary files, then delete the temp region.""" + gs.run_command("g.remove", type="vector", flags="f", name="test_3x3_map") + if os.path.exists("input_data.txt"): + os.remove("input_data.txt") + cls.del_temp_region() + + def test_vbuild_output(self): + """Compare the v.build output (build_module) to the expected output.""" + + # Compare the dictionaries + if self.build_module == self.expected_output: + print("Outputs match!") + else: + print("Outputs differ!") + for key1, key2 in zip( + self.build_module.keys(), self.expected_output.keys() + ): + val1 = self.build_module.get(key1) + val2 = self.expected_output.get(key1) + if key1 != key2: + print(f"Calculated: {key1}\nExpected: {key2}\n") + if val1 != val2: + print(f"Calculated: {val1}\nExpected: {val2}\n") + + +if __name__ == "__main__": + test() diff --git a/vector/v.build/testsuite/vbuild_output.txt b/vector/v.build/testsuite/vbuild_output.txt new file mode 100644 index 00000000000..698f05d3ccd --- /dev/null +++ b/vector/v.build/testsuite/vbuild_output.txt @@ -0,0 +1 @@ +{'---------- TOPOLOGY DUMP ----------': None, 'Map: test_3x3_map@PERMANENT': None, 'Topology format: native': None, '-----------------------------------': None, 'N,S,E,W,T,B: 2.500000, 0.500000, 2.500000, 0.500000, 0.000000, 0.000000': None, 'Nodes (2 nodes, alive + dead):': None, 'node': '2, n_lines = 1, xyz = 2.500000, 2.500000, 0.000000', 'line': '2, type = 2, offset = 35, n1 = 1, n2 = 2', 'Lines (2 lines, alive + dead):': None, 'Areas (0 areas, alive + dead):': None, 'Islands (0 islands, alive + dead):': None, '---------- SPATIAL INDEX DUMP ----------': None, 'Nodes': None, 'Node level': '0 count=0', 'Branch 0 id': '1 1.000000 1.000000 0.000000 1.000000 1.000000 0.000000', 'Branch 1 id': '2 0.500000 0.500000 0.000000 2.500000 2.500000 0.000000', 'Lines': None, 'Areas': None, 'Isles': None, '---------- CATEGORY INDEX DUMP: Number of layers: 1 --------------------------------------': None, 'Layer 0 number of unique cats: 1 number of cats: 2 number of types: 2': None, '------------------------------------------------------------------------------------------': None, 'type | count': None, '1 | 1': None, '2 | 1': None, 'category | type | line/area': None, '0 | 1 | 1': None, '0 | 2 | 2': None} \ No newline at end of file From 35926d381b34e25a39517e93af626d51452adabc Mon Sep 17 00:00:00 2001 From: Shreshth-Malik Date: Sat, 8 Feb 2025 02:21:17 -0500 Subject: [PATCH 2/5] Added fixes and suggestions --- vector/v.build/testsuite/test_v_build.py | 65 +++++++++------------- vector/v.build/testsuite/vbuild_output.txt | 1 - 2 files changed, 25 insertions(+), 41 deletions(-) delete mode 100644 vector/v.build/testsuite/vbuild_output.txt diff --git a/vector/v.build/testsuite/test_v_build.py b/vector/v.build/testsuite/test_v_build.py index 2499e8c9ea3..6b1a1162aa4 100644 --- a/vector/v.build/testsuite/test_v_build.py +++ b/vector/v.build/testsuite/test_v_build.py @@ -1,4 +1,3 @@ -import os import ast import grass.script as gs from grass.gunittest.case import TestCase @@ -6,64 +5,50 @@ class TestVBuild(TestCase): - """Test v.build output against expected output stored in vbuild_output.txt""" + """Test v.build output against expected output stored in vbuild_output""" @classmethod def setUpClass(cls): """Set up a temporary region and create vector map with test features.""" - cls.use_temp_region() - gs.run_command("v.edit", map="test_3x3_map", tool="create", overwrite=True) - gs.run_command("g.region", n=3, s=0, e=3, w=0, res=1) - input_data = "VERTI:\nP 1\n1 1\nL 2\n0.5 0.5\n2.5 2.5" - - with open("input_data.txt", "w") as file: - file.write(input_data) - - # Import features into the vector map using the input file. - gs.run_command( - "v.edit", - map="test_3x3_map", - tool="add", - type="point,line", - input="input_data.txt", + input_data = "P 1\n1 1\nL 2\n0.5 0.5\n2.5 2.5" + gs.write_command( + "v.in.ascii", + input="-", + format="standard", + stdin=input_data, + output="test_3x3_map", + flags="n", + overwrite=True, ) - # Run v.build (with multiple dump options) and store its output in a class variable. cls.build_module = gs.parse_command( "v.build", map="test_3x3_map", option="build,dump,sdump,cdump,fdump" ) - - # Read the expected output from the external file. - with open("vbuild_output.txt") as f: - expected_str = f.read() - cls.expected_output = ast.literal_eval(expected_str) + # Read the expected output. + vbuild_output = """{'---------- TOPOLOGY DUMP ----------': None, 'Map: test_3x3_map@PERMANENT': None, 'Topology format: native': None, '-----------------------------------': None, 'N,S,E,W,T,B: 2.500000, 0.500000, 2.500000, 0.500000, 0.000000, 0.000000': None, 'Nodes (2 nodes, alive + dead):': None, 'node': '2, n_lines = 1, xyz = 2.500000, 2.500000, 0.000000', 'line': '2, type = 2, offset = 35, n1 = 1, n2 = 2', 'Lines (2 lines, alive + dead):': None, 'Areas (0 areas, alive + dead):': None, 'Islands (0 islands, alive + dead):': None, '---------- SPATIAL INDEX DUMP ----------': None, 'Nodes': None, 'Node level': '0 count=0', 'Branch 0 id': '1 1.000000 1.000000 0.000000 1.000000 1.000000 0.000000', 'Branch 1 id': '2 0.500000 0.500000 0.000000 2.500000 2.500000 0.000000', 'Lines': None, 'Areas': None, 'Isles': None, '---------- CATEGORY INDEX DUMP: Number of layers: 1 --------------------------------------': None, 'Layer 0 number of unique cats: 1 number of cats: 2 number of types: 2': None, '------------------------------------------------------------------------------------------': None, 'type | count': None, '1 | 1': None, '2 | 1': None, 'category | type | line/area': None, '0 | 1 | 1': None, '0 | 2 | 2': None}""" + cls.expected_output = ast.literal_eval(vbuild_output) @classmethod def tearDownClass(cls): """Remove created vector map and temporary files, then delete the temp region.""" gs.run_command("g.remove", type="vector", flags="f", name="test_3x3_map") - if os.path.exists("input_data.txt"): - os.remove("input_data.txt") cls.del_temp_region() def test_vbuild_output(self): """Compare the v.build output (build_module) to the expected output.""" - - # Compare the dictionaries - if self.build_module == self.expected_output: - print("Outputs match!") - else: - print("Outputs differ!") - for key1, key2 in zip( - self.build_module.keys(), self.expected_output.keys() - ): - val1 = self.build_module.get(key1) - val2 = self.expected_output.get(key1) - if key1 != key2: - print(f"Calculated: {key1}\nExpected: {key2}\n") - if val1 != val2: - print(f"Calculated: {val1}\nExpected: {val2}\n") + self.assertEqual( + set(self.build_module.keys()), + set(self.expected_output.keys()), + "The sets of keys differ between calculated and expected output.", + ) + # Then, iterate over the keys and assert that each value matches. + for key in self.build_module: + self.assertEqual( + self.build_module.get(key), + self.expected_output.get(key), + msg=f"Mismatch for '{key}': Calculated {self.build_module.get(key)} vs Expected {self.expected_output.get(key)}", + ) if __name__ == "__main__": diff --git a/vector/v.build/testsuite/vbuild_output.txt b/vector/v.build/testsuite/vbuild_output.txt deleted file mode 100644 index 698f05d3ccd..00000000000 --- a/vector/v.build/testsuite/vbuild_output.txt +++ /dev/null @@ -1 +0,0 @@ -{'---------- TOPOLOGY DUMP ----------': None, 'Map: test_3x3_map@PERMANENT': None, 'Topology format: native': None, '-----------------------------------': None, 'N,S,E,W,T,B: 2.500000, 0.500000, 2.500000, 0.500000, 0.000000, 0.000000': None, 'Nodes (2 nodes, alive + dead):': None, 'node': '2, n_lines = 1, xyz = 2.500000, 2.500000, 0.000000', 'line': '2, type = 2, offset = 35, n1 = 1, n2 = 2', 'Lines (2 lines, alive + dead):': None, 'Areas (0 areas, alive + dead):': None, 'Islands (0 islands, alive + dead):': None, '---------- SPATIAL INDEX DUMP ----------': None, 'Nodes': None, 'Node level': '0 count=0', 'Branch 0 id': '1 1.000000 1.000000 0.000000 1.000000 1.000000 0.000000', 'Branch 1 id': '2 0.500000 0.500000 0.000000 2.500000 2.500000 0.000000', 'Lines': None, 'Areas': None, 'Isles': None, '---------- CATEGORY INDEX DUMP: Number of layers: 1 --------------------------------------': None, 'Layer 0 number of unique cats: 1 number of cats: 2 number of types: 2': None, '------------------------------------------------------------------------------------------': None, 'type | count': None, '1 | 1': None, '2 | 1': None, 'category | type | line/area': None, '0 | 1 | 1': None, '0 | 2 | 2': None} \ No newline at end of file From 7361d0b7f03087bf417e5b78f74bb68b309c174c Mon Sep 17 00:00:00 2001 From: Shreshth-Malik Date: Sun, 9 Feb 2025 23:02:19 -0500 Subject: [PATCH 3/5] Patch for failing test due to temp map name --- vector/v.build/testsuite/test_v_build.py | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/vector/v.build/testsuite/test_v_build.py b/vector/v.build/testsuite/test_v_build.py index 6b1a1162aa4..9837da5a680 100644 --- a/vector/v.build/testsuite/test_v_build.py +++ b/vector/v.build/testsuite/test_v_build.py @@ -26,7 +26,7 @@ def setUpClass(cls): "v.build", map="test_3x3_map", option="build,dump,sdump,cdump,fdump" ) # Read the expected output. - vbuild_output = """{'---------- TOPOLOGY DUMP ----------': None, 'Map: test_3x3_map@PERMANENT': None, 'Topology format: native': None, '-----------------------------------': None, 'N,S,E,W,T,B: 2.500000, 0.500000, 2.500000, 0.500000, 0.000000, 0.000000': None, 'Nodes (2 nodes, alive + dead):': None, 'node': '2, n_lines = 1, xyz = 2.500000, 2.500000, 0.000000', 'line': '2, type = 2, offset = 35, n1 = 1, n2 = 2', 'Lines (2 lines, alive + dead):': None, 'Areas (0 areas, alive + dead):': None, 'Islands (0 islands, alive + dead):': None, '---------- SPATIAL INDEX DUMP ----------': None, 'Nodes': None, 'Node level': '0 count=0', 'Branch 0 id': '1 1.000000 1.000000 0.000000 1.000000 1.000000 0.000000', 'Branch 1 id': '2 0.500000 0.500000 0.000000 2.500000 2.500000 0.000000', 'Lines': None, 'Areas': None, 'Isles': None, '---------- CATEGORY INDEX DUMP: Number of layers: 1 --------------------------------------': None, 'Layer 0 number of unique cats: 1 number of cats: 2 number of types: 2': None, '------------------------------------------------------------------------------------------': None, 'type | count': None, '1 | 1': None, '2 | 1': None, 'category | type | line/area': None, '0 | 1 | 1': None, '0 | 2 | 2': None}""" + vbuild_output = """{'Topology format: native': None, '-----------------------------------': None, 'N,S,E,W,T,B: 2.500000, 0.500000, 2.500000, 0.500000, 0.000000, 0.000000': None, 'Nodes (2 nodes, alive + dead):': None, 'node': '2, n_lines = 1, xyz = 2.500000, 2.500000, 0.000000', 'line': '2, type = 2, offset = 35, n1 = 1, n2 = 2', 'Lines (2 lines, alive + dead):': None, 'Areas (0 areas, alive + dead):': None, 'Islands (0 islands, alive + dead):': None, '---------- SPATIAL INDEX DUMP ----------': None, 'Nodes': None, 'Node level': '0 count=0', 'Branch 0 id': '1 1.000000 1.000000 0.000000 1.000000 1.000000 0.000000', 'Branch 1 id': '2 0.500000 0.500000 0.000000 2.500000 2.500000 0.000000', 'Lines': None, 'Areas': None, 'Isles': None, '---------- CATEGORY INDEX DUMP: Number of layers: 1 --------------------------------------': None, 'Layer 0 number of unique cats: 1 number of cats: 2 number of types: 2': None, '------------------------------------------------------------------------------------------': None, 'type | count': None, '1 | 1': None, '2 | 1': None, 'category | type | line/area': None, '0 | 1 | 1': None, '0 | 2 | 2': None}""" cls.expected_output = ast.literal_eval(vbuild_output) @classmethod @@ -37,18 +37,10 @@ def tearDownClass(cls): def test_vbuild_output(self): """Compare the v.build output (build_module) to the expected output.""" - self.assertEqual( - set(self.build_module.keys()), + assert_result = self.assertEqual( + set(list(self.build_module.keys())[2:]), # Skipping the header set(self.expected_output.keys()), - "The sets of keys differ between calculated and expected output.", ) - # Then, iterate over the keys and assert that each value matches. - for key in self.build_module: - self.assertEqual( - self.build_module.get(key), - self.expected_output.get(key), - msg=f"Mismatch for '{key}': Calculated {self.build_module.get(key)} vs Expected {self.expected_output.get(key)}", - ) if __name__ == "__main__": From a2413bf0ac5d707dd1aeca2321d703b3081f3790 Mon Sep 17 00:00:00 2001 From: Shreshth-Malik Date: Thu, 13 Feb 2025 20:14:15 -0500 Subject: [PATCH 4/5] Fixed output parsing --- vector/v.build/testsuite/test_v_build.py | 61 ++++++++++++++++++++---- 1 file changed, 51 insertions(+), 10 deletions(-) diff --git a/vector/v.build/testsuite/test_v_build.py b/vector/v.build/testsuite/test_v_build.py index 9837da5a680..c56551f9070 100644 --- a/vector/v.build/testsuite/test_v_build.py +++ b/vector/v.build/testsuite/test_v_build.py @@ -1,4 +1,3 @@ -import ast import grass.script as gs from grass.gunittest.case import TestCase from grass.gunittest.main import test @@ -21,13 +20,58 @@ def setUpClass(cls): flags="n", overwrite=True, ) + # Run v.build (with multiple dump options) and store its output in a class variable. - cls.build_module = gs.parse_command( - "v.build", map="test_3x3_map", option="build,dump,sdump,cdump,fdump" - ) + cls.build_module = gs.read_command( + "v.build", + map="test_3x3_map", + option="build,dump,sdump,cdump,fdump", + quiet=True, + ).strip() + # Read the expected output. - vbuild_output = """{'Topology format: native': None, '-----------------------------------': None, 'N,S,E,W,T,B: 2.500000, 0.500000, 2.500000, 0.500000, 0.000000, 0.000000': None, 'Nodes (2 nodes, alive + dead):': None, 'node': '2, n_lines = 1, xyz = 2.500000, 2.500000, 0.000000', 'line': '2, type = 2, offset = 35, n1 = 1, n2 = 2', 'Lines (2 lines, alive + dead):': None, 'Areas (0 areas, alive + dead):': None, 'Islands (0 islands, alive + dead):': None, '---------- SPATIAL INDEX DUMP ----------': None, 'Nodes': None, 'Node level': '0 count=0', 'Branch 0 id': '1 1.000000 1.000000 0.000000 1.000000 1.000000 0.000000', 'Branch 1 id': '2 0.500000 0.500000 0.000000 2.500000 2.500000 0.000000', 'Lines': None, 'Areas': None, 'Isles': None, '---------- CATEGORY INDEX DUMP: Number of layers: 1 --------------------------------------': None, 'Layer 0 number of unique cats: 1 number of cats: 2 number of types: 2': None, '------------------------------------------------------------------------------------------': None, 'type | count': None, '1 | 1': None, '2 | 1': None, 'category | type | line/area': None, '0 | 1 | 1': None, '0 | 2 | 2': None}""" - cls.expected_output = ast.literal_eval(vbuild_output) + cls.vbuild_output = """---------- TOPOLOGY DUMP ---------- +Map: test_3x3_map@PERMANENT +Topology format: native +----------------------------------- +N,S,E,W,T,B: 2.500000, 0.500000, 2.500000, 0.500000, 0.000000, 0.000000 +----------------------------------- +Nodes (2 nodes, alive + dead): +node = 1, n_lines = 1, xyz = 0.500000, 0.500000, 0.000000 + line = 2, type = 2, angle = 0.785398 (45.0000) +node = 2, n_lines = 1, xyz = 2.500000, 2.500000, 0.000000 + line = -2, type = 2, angle = -2.356194 (225.0000) +----------------------------------- +Lines (2 lines, alive + dead): +line = 1, type = 1, offset = 18 +line = 2, type = 2, offset = 35, n1 = 1, n2 = 2 +----------------------------------- +Areas (0 areas, alive + dead): +----------------------------------- +Islands (0 islands, alive + dead): +---------- SPATIAL INDEX DUMP ---------- +Nodes +Node level=0 count=2 + Branch 0 id = 1 0.500000 0.500000 0.000000 0.500000 0.500000 0.000000 + Branch 1 id = 2 2.500000 2.500000 0.000000 2.500000 2.500000 0.000000 +Lines +Node level=0 count=2 + Branch 0 id = 1 1.000000 1.000000 0.000000 1.000000 1.000000 0.000000 + Branch 1 id = 2 0.500000 0.500000 0.000000 2.500000 2.500000 0.000000 +Areas +Node level=0 count=0 +Isles +Node level=0 count=0 +---------- CATEGORY INDEX DUMP: Number of layers: 1 -------------------------------------- +Layer 0 number of unique cats: 1 number of cats: 2 number of types: 2 +------------------------------------------------------------------------------------------ + type | count + 1 | 1 + 2 | 1 + category | type | line/area + 0 | 1 | 1 + 0 | 2 | 2 +------------------------------------------------------------------------------------------""" @classmethod def tearDownClass(cls): @@ -37,10 +81,7 @@ def tearDownClass(cls): def test_vbuild_output(self): """Compare the v.build output (build_module) to the expected output.""" - assert_result = self.assertEqual( - set(list(self.build_module.keys())[2:]), # Skipping the header - set(self.expected_output.keys()), - ) + self.assertMultiLineEqual(self.build_module, self.vbuild_output) if __name__ == "__main__": From 5546b2dcb7fbd243998e12523bb7cf91efb1795e Mon Sep 17 00:00:00 2001 From: Shreshth-Malik Date: Thu, 13 Feb 2025 20:57:18 -0500 Subject: [PATCH 5/5] Fixed build fails due to temp meta data --- vector/v.build/testsuite/test_v_build.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/vector/v.build/testsuite/test_v_build.py b/vector/v.build/testsuite/test_v_build.py index c56551f9070..453e36b2b99 100644 --- a/vector/v.build/testsuite/test_v_build.py +++ b/vector/v.build/testsuite/test_v_build.py @@ -30,10 +30,7 @@ def setUpClass(cls): ).strip() # Read the expected output. - cls.vbuild_output = """---------- TOPOLOGY DUMP ---------- -Map: test_3x3_map@PERMANENT -Topology format: native ------------------------------------ + cls.vbuild_output = """ N,S,E,W,T,B: 2.500000, 0.500000, 2.500000, 0.500000, 0.000000, 0.000000 ----------------------------------- Nodes (2 nodes, alive + dead): @@ -81,7 +78,7 @@ def tearDownClass(cls): def test_vbuild_output(self): """Compare the v.build output (build_module) to the expected output.""" - self.assertMultiLineEqual(self.build_module, self.vbuild_output) + self.assertMultiLineEqual(self.build_module[135:], self.vbuild_output) if __name__ == "__main__":