From 1881a910563c103ec8f8f7e478203e370c4cd8aa Mon Sep 17 00:00:00 2001 From: Jeff Ng Date: Thu, 19 Dec 2024 14:13:38 -0800 Subject: [PATCH 1/3] Updated ODB python unit tests and hooked them up to CTest-based regression system Signed-off-by: Jeff Ng --- src/odb/test/CMakeLists.txt | 8 ++ src/odb/test/{unitTestsPython => }/helper.py | 59 +++++++---- src/odb/test/odbUnitTest.py | 14 +++ src/odb/test/regression-py.sh | 100 ------------------ .../TestBlock.py => test_block.py} | 27 +++-- .../TestBTerm.py => test_bterm.py} | 6 +- .../TestDestroy.py => test_destroy.py} | 27 ++--- .../TestGroup.py => test_group.py} | 16 +-- .../TestInst.py => test_inst.py} | 12 +-- .../TestITerm.py => test_iterm.py} | 46 ++++---- .../TestModule.py => test_module.py} | 8 +- .../TestNet.py => test_net.py} | 5 +- src/odb/test/unitTests.sh | 22 ---- src/odb/test/unitTestsPython/odbUnitTest.py | 40 ------- test/regression_test.sh | 4 +- test/shared/regression.sh | 22 +++- 16 files changed, 155 insertions(+), 261 deletions(-) rename src/odb/test/{unitTestsPython => }/helper.py (79%) create mode 100644 src/odb/test/odbUnitTest.py delete mode 100755 src/odb/test/regression-py.sh rename src/odb/test/{unitTestsPython/TestBlock.py => test_block.py} (85%) rename src/odb/test/{unitTestsPython/TestBTerm.py => test_bterm.py} (94%) rename src/odb/test/{unitTestsPython/TestDestroy.py => test_destroy.py} (86%) rename src/odb/test/{unitTestsPython/TestGroup.py => test_group.py} (82%) rename src/odb/test/{unitTestsPython/TestInst.py => test_inst.py} (84%) rename src/odb/test/{unitTestsPython/TestITerm.py => test_iterm.py} (70%) rename src/odb/test/{unitTestsPython/TestModule.py => test_module.py} (91%) rename src/odb/test/{unitTestsPython/TestNet.py => test_net.py} (97%) delete mode 100755 src/odb/test/unitTests.sh delete mode 100644 src/odb/test/unitTestsPython/odbUnitTest.py diff --git a/src/odb/test/CMakeLists.txt b/src/odb/test/CMakeLists.txt index 05d7ac46a68..cc7e0d390bd 100644 --- a/src/odb/test/CMakeLists.txt +++ b/src/odb/test/CMakeLists.txt @@ -53,6 +53,14 @@ or_integration_tests( dump_netlists dump_netlists_withfill parser_unit_test + test_block + test_bterm + test_destroy + test_group + test_inst + test_iterm + test_module + test_net ) # Skipped diff --git a/src/odb/test/unitTestsPython/helper.py b/src/odb/test/helper.py similarity index 79% rename from src/odb/test/unitTestsPython/helper.py rename to src/odb/test/helper.py index 6c63e7d392a..800619fb921 100644 --- a/src/odb/test/unitTestsPython/helper.py +++ b/src/odb/test/helper.py @@ -1,11 +1,12 @@ -import opendbpy as odb - +import odb +import openroad +from openroad import Design def createSimpleDB(): - db = odb.dbDatabase.create() - tech = odb.dbTech.create(db) + db = Design.createDetachedDb() + tech = odb.dbTech.create(db, "simple_tech") L1 = odb.dbTechLayer_create(tech, "L1", "ROUTING") - lib = odb.dbLib.create(db, "lib") + lib = odb.dbLib.create(db, "lib", tech, "/") odb.dbChip.create(db) # Creating Master and2 and or2 and2 = createMaster2X1(lib, "and2", 1000, 1000, "a", "b", "o") @@ -14,8 +15,8 @@ def createSimpleDB(): def createMultiLayerDB(): - db = odb.dbDatabase.create() - tech = odb.dbTech.create(db) + db = Design.createDetachedDb() + tech = odb.dbTech.create(db, "multi_tech") m1 = odb.dbTechLayer_create(tech, "M1", "ROUTING") m1.setWidth(2000) @@ -44,7 +45,7 @@ def createMultiLayerDB(): # +----- def create1LevelBlock(db, lib, parent): blockName = "1LevelBlock" - block = odb.dbBlock_create(parent, blockName, ",") + block = odb.dbBlock_create(parent, blockName, lib.getTech(), ",") # Creating Master and2 and instance inst and2 = lib.findMaster("and2") inst = odb.dbInst.create(block, and2, "inst") @@ -59,9 +60,12 @@ def create1LevelBlock(db, lib, parent): OUT = odb.dbBTerm.create(n3, "OUT") OUT.setIoType("OUTPUT") # connecting nets - odb.dbITerm.connect(inst, n1, inst.getMaster().findMTerm("a")) - odb.dbITerm.connect(inst, n2, inst.getMaster().findMTerm("b")) - odb.dbITerm.connect(inst, n3, inst.getMaster().findMTerm("o")) + a = inst.findITerm("a") + a.connect(n1) + b = inst.findITerm("b") + b.connect(n2) + o = inst.findITerm("o") + o.connect(n3) return block @@ -79,7 +83,7 @@ def create1LevelBlock(db, lib, parent): # +----- def create2LevelBlock(db, lib, parent): blockName = "2LevelBlock" - block = odb.dbBlock_create(parent, blockName, ",") + block = odb.dbBlock_create(parent, blockName, lib.getTech(), ",") and2 = lib.findMaster("and2") or2 = lib.findMaster("or2") @@ -107,17 +111,26 @@ def create2LevelBlock(db, lib, parent): OUT = odb.dbBTerm.create(n7, "OUT") OUT.setIoType("OUTPUT") # connecting nets - odb.dbITerm.connect(i1, n1, i1.getMaster().findMTerm("a")) - odb.dbITerm.connect(i1, n2, i1.getMaster().findMTerm("b")) - odb.dbITerm.connect(i1, n5, i1.getMaster().findMTerm("o")) - - odb.dbITerm.connect(i2, n3, i2.getMaster().findMTerm("a")) - odb.dbITerm.connect(i2, n4, i2.getMaster().findMTerm("b")) - odb.dbITerm.connect(i2, n6, i2.getMaster().findMTerm("o")) - - odb.dbITerm.connect(i3, n5, i3.getMaster().findMTerm("a")) - odb.dbITerm.connect(i3, n6, i3.getMaster().findMTerm("b")) - odb.dbITerm.connect(i3, n7, i3.getMaster().findMTerm("o")) + i1_a = i1.findITerm("a") + i1_a.connect(n1) + i1_b = i1.findITerm("b") + i1_b.connect(n2) + i1_o = i1.findITerm("o") + i1_o.connect(n5) + + i2_a = i2.findITerm("a") + i2_a.connect(n3) + i2_b = i2.findITerm("b") + i2_b.connect(n4) + i2_o = i2.findITerm("o") + i2_o.connect(n6) + + i3_a = i3.findITerm("a") + i3_a.connect(n5) + i3_b = i3.findITerm("b") + i3_b.connect(n6) + i3_o = i3.findITerm("o") + i3_o.connect(n7) P1 = odb.dbBPin_create(IN1) P2 = odb.dbBPin_create(IN2) diff --git a/src/odb/test/odbUnitTest.py b/src/odb/test/odbUnitTest.py new file mode 100644 index 00000000000..0dc50391b8a --- /dev/null +++ b/src/odb/test/odbUnitTest.py @@ -0,0 +1,14 @@ +import unittest + + +class TestCase(unittest.TestCase): + # Function to change a value and test the change effect + def changeAndTest(self, obj, SetterName, GetterName, expectedVal, *args): + getattr(obj, SetterName)(*args) + self.assertEqual(getattr(obj, GetterName)(), expectedVal) + + def check(self, obj, GetterName, expectedVal, *args): + self.assertEqual(getattr(obj, GetterName)(*args), expectedVal) + + def change(self, obj, SetterName, *args): + return getattr(obj, SetterName)(*args) diff --git a/src/odb/test/regression-py.sh b/src/odb/test/regression-py.sh deleted file mode 100755 index c8a2f93c7a8..00000000000 --- a/src/odb/test/regression-py.sh +++ /dev/null @@ -1,100 +0,0 @@ -set -e - -BASE_DIR=$(dirname $0) -export PYTHONPATH=$BASE_DIR/../../../build/src/odb/src/swig/python:$PYTHONPATH -APP=$BASE_DIR/../../../build/src/odb/src/swig/python/odbpy - -echo "Running tests .." -echo "================" - -echo "[1] Importing opendbpy package" -$APP $BASE_DIR/python/01-import_package_test.py -echo "SUCCESS!" -echo "" - -echo "[2] Reading lef files" -$APP $BASE_DIR/python/02-read_lef_test.py -echo "SUCCESS!" -echo "" - - -echo "[3] Dump via rules" -$APP $BASE_DIR/python/03-dump_via_rules_test.py -echo "SUCCESS!" -echo "" - -echo "[4] Dump vias" -$APP $BASE_DIR/python/04-dump_vias_test.py -echo "SUCCESS!" -echo "" - -echo "[5] Read DEF" -$APP $BASE_DIR/python/05-read_def_test.py -echo "SUCCESS!" -echo "" - -echo "[7] Dump nets" -$APP $BASE_DIR/python/07-dump_nets_test.py -echo "SUCCESS!" -echo "" - -echo "[8] Write LEF/DEF file" -$APP $BASE_DIR/python/08-write_lef_and_def_test.py -echo "SUCCESS!" -echo "" - -echo "[9] Database LEF access tests" -$APP $BASE_DIR/python/09-lef_data_access_test.py -echo "SUCCESS!" -echo "" - -echo "[10] Database DEF access tests (1)" -$APP $BASE_DIR/python/10-gcd_def_access_test.py -echo "SUCCESS!" -echo "" - -echo "[11] Database DEF access tests (2)" -$APP $BASE_DIR/python/11-gcd_pdn_def_access_test.py -echo "SUCCESS!" -echo "" - -echo "[12] Database edit DEF tests" -$APP $BASE_DIR/python/12-edit_def_test.py -echo "SUCCESS!" -echo "" - -echo "[13] Wire encoder test" -$APP $BASE_DIR/python/13-wire_encoder_test.py -echo "SUCCESS!" -echo "" - -echo "[14] Edit via params test" -$APP $BASE_DIR/python/14-edit_via_params_test.py -echo "SUCCESS!" -echo "" - -echo "[15] Database row create test" -$APP $BASE_DIR/python/15-row_settings_test.py -echo "SUCCESS!" -echo "" - -echo "[16] Database def octilinear read write test" -$APP $BASE_DIR/python/16-db-read-write-octilinear-def_test.py -echo "SUCCESS!" -echo "" - -echo "[17] Database read/write test" -$APP $BASE_DIR/python/17-db_read-write_test.py -echo "SUCCESS!" -echo "" - - -echo "[18] Multiple Boxes per dbBPin test" -$APP $BASE_DIR/python/18-multiple_boxes_pin_test.py -echo "SUCCESS!" -echo "" - -echo "[19] Swig Interface test" -$APP $BASE_DIR/python/19-swig_interface_test.py -echo "SUCCESS!" -echo "" diff --git a/src/odb/test/unitTestsPython/TestBlock.py b/src/odb/test/test_block.py similarity index 85% rename from src/odb/test/unitTestsPython/TestBlock.py rename to src/odb/test/test_block.py index 6cc7431eca9..509717a12e0 100644 --- a/src/odb/test/unitTestsPython/TestBlock.py +++ b/src/odb/test/test_block.py @@ -1,6 +1,7 @@ -import opendbpy as odb +import odb import helper import odbUnitTest +import unittest def placeInst(inst, x, y): @@ -22,7 +23,6 @@ def setUp(self): self.extcornerblock = self.block.createExtCornerBlock(1) odb.dbTechNonDefaultRule_create(self.block, "non_default_1") self.parentRegion = odb.dbRegion_create(self.block, "parentRegion") - self.childRegion = odb.dbRegion_create(self.parentRegion, "childRegion") def tearDown(self): self.db.destroy(self.db) @@ -60,10 +60,6 @@ def test_find(self): self.assertEqual( self.block.findRegion("parentRegion").getName(), "parentRegion" ) - self.assertEqual(self.block.findRegion("childRegion").getName(), "childRegion") - self.assertEqual( - self.block.findRegion("childRegion").getParent().getName(), "parentRegion" - ) def check_box_rect(self, min_x, min_y, max_x, max_y): box = self.block.getBBox() @@ -142,7 +138,22 @@ def test_bbox4(self): self.block_placement(4, False) self.check_box_rect(-1580, -1000, 2550, 4100) + def test_get_chip(self): + """ + Tests getChip API + + Note: can't call assertEqual directly on the getChip() result because + the two objects point to different swig-wrapped objects + """ + self.assertEqual(self.db.getChip().getBlock().getName(), self.parentBlock.getChip().getBlock().getName()) + + @unittest.skip("re-enable once memory corruption is resolved") + def test_duplicate(self): + dup_block = odb.dbBlock_duplicate(self.block, "dup_block") + self.assertEqual(dup_block.getName(), "dup_block") + self.assertEqual(len(dup_block.getInsts()), len(self.block.getInsts())) + self.assertEqual(len(dup_block.getNets()), len(self.block.getNets())) + self.assertEqual(len(dup_block.getBTerms()), len(self.block.getBTerms())) if __name__ == "__main__": - odbUnitTest.mainParallel(TestBlock) -# odbUnitTest.main() + unittest.main() diff --git a/src/odb/test/unitTestsPython/TestBTerm.py b/src/odb/test/test_bterm.py similarity index 94% rename from src/odb/test/unitTestsPython/TestBTerm.py rename to src/odb/test/test_bterm.py index c5c114afc21..ff7b910bf1e 100644 --- a/src/odb/test/unitTestsPython/TestBTerm.py +++ b/src/odb/test/test_bterm.py @@ -1,6 +1,7 @@ -import opendbpy as odb +import odb import helper import odbUnitTest +import unittest class TestBTerm(odbUnitTest.TestCase): @@ -40,5 +41,4 @@ def test_disconnect(self): if __name__ == "__main__": - odbUnitTest.mainParallel(TestBTerm) -# odbUnitTest.main() + unittest.main() diff --git a/src/odb/test/unitTestsPython/TestDestroy.py b/src/odb/test/test_destroy.py similarity index 86% rename from src/odb/test/unitTestsPython/TestDestroy.py rename to src/odb/test/test_destroy.py index 911941f5b70..0c581b50c39 100644 --- a/src/odb/test/unitTestsPython/TestDestroy.py +++ b/src/odb/test/test_destroy.py @@ -1,6 +1,7 @@ -import opendbpy as odb +import odb import helper import odbUnitTest +import unittest # destroying dbInst, dbNet, dbBTerm, dbBlock, dbBPin, dbWire, dbCapNode, # dbCcSeg, dbLib, dbSWire, dbObstruction, dbRegion @@ -151,31 +152,16 @@ def test_destroy_obstruction(self): def setup_regions(self): parentRegion = odb.dbRegion_create(self.block, "parentRegion") - childRegion = odb.dbRegion_create(parentRegion, "childRegion") - childRegion.addInst(self.i1) - return parentRegion, childRegion + return parentRegion def test_create_regions(self): - parentRegion, childRegion = self.setup_regions() - self.assertEqual(self.i1.getRegion().getName(), childRegion.getName()) - self.assertEqual(len(parentRegion.getChildren()), 1) - self.assertEqual(len(childRegion.getChildren()), 0) - self.assertEqual(parentRegion.getChildren()[0].getName(), childRegion.getName()) - self.assertEqual(len(self.block.getRegions()), 2) - self.assertEqual(self.i1.getRegion().getName(), childRegion.getName()) - self.assertEqual(childRegion.getParent().getName(), parentRegion.getName()) - self.assertIsNone(parentRegion.getParent()) - - def test_destroy_region_child(self): - parentRegion, childRegion = self.setup_regions() - childRegion.destroy(childRegion) + parentRegion = self.setup_regions() self.assertIsNone(self.i1.getRegion()) - self.assertEqual(len(parentRegion.getChildren()), 0) self.assertEqual(len(self.block.getRegions()), 1) self.assertEqual(self.block.getRegions()[0].getName(), parentRegion.getName()) def test_destroy_region_parent(self): - parentRegion, childRegion = self.setup_regions() + parentRegion = self.setup_regions() parentRegion.destroy(parentRegion) self.assertEqual(len(self.block.getRegions()), 0) @@ -189,5 +175,4 @@ def test_destroy_trackgrid(self): if __name__ == "__main__": - odbUnitTest.mainParallel(TestDestroy) -# odbUnitTest.main() + unittest.main() diff --git a/src/odb/test/unitTestsPython/TestGroup.py b/src/odb/test/test_group.py similarity index 82% rename from src/odb/test/unitTestsPython/TestGroup.py rename to src/odb/test/test_group.py index 872a6b7114c..1c683117190 100644 --- a/src/odb/test/unitTestsPython/TestGroup.py +++ b/src/odb/test/test_group.py @@ -1,6 +1,7 @@ -import opendbpy as odb +import odb import helper import odbUnitTest +import unittest ################## @@ -13,7 +14,8 @@ def setUp(self): self.db, self.lib = helper.createSimpleDB() self.block = helper.create1LevelBlock(self.db, self.lib, self.db.getChip()) self.group = odb.dbGroup_create(self.block, "group") - self.domain = odb.dbGroup_create(self.block, "domain", 0, 0, 100, 100) + self.domain = odb.dbRegion_create(self.block, "domain") + odb.dbBox_create(self.domain, 0, 0, 100, 100) self.child = odb.dbGroup_create(self.block, "child") self.master_mod = odb.dbModule_create(self.block, "master_mod") self.parent_mod = odb.dbModule_create(self.block, "parent_mod") @@ -26,10 +28,12 @@ def tearDown(self): def test_default(self): self.check(self.group, "getName", "group") - print("") self.assertEqual(self.block.findGroup("group").getName(), "group") - self.assertEqual(len(self.block.getGroups()), 3) - self.assertEqual(self.domain.getBox().xMax(), 100) + self.assertEqual(len(self.block.getGroups()), 2) + self.assertEqual(len(self.block.getRegions()), 1) + region_boundaries = self.domain.getBoundaries() + self.assertEqual(len(region_boundaries), 1) + self.assertEqual(region_boundaries[0].xMax(), 100) self.group.addModInst(self.i1) self.assertEqual(self.group.getModInsts()[0].getName(), "i1") self.assertEqual(self.i1.getGroup().getName(), "group") @@ -53,4 +57,4 @@ def test_default(self): if __name__ == "__main__": - odbUnitTest.mainParallel(TestModule) + unittest.main() diff --git a/src/odb/test/unitTestsPython/TestInst.py b/src/odb/test/test_inst.py similarity index 84% rename from src/odb/test/unitTestsPython/TestInst.py rename to src/odb/test/test_inst.py index 40acb739aee..ebd4d790927 100644 --- a/src/odb/test/unitTestsPython/TestInst.py +++ b/src/odb/test/test_inst.py @@ -1,6 +1,7 @@ -import opendbpy as odb +import odb import helper import odbUnitTest +import unittest class TestInst(odbUnitTest.TestCase): @@ -14,19 +15,19 @@ def tearDown(self): def test_swap_master(self): self.assertEqual(self.i1.getMaster().getName(), "and2") - # testing with a gate with different mterm names + # testing with a gate with different mterm names - should fail gate = helper.createMaster2X1(self.lib, "_g2", 800, 800, "_a", "_b", "_o") self.assertFalse(self.i1.swapMaster(gate)) self.assertNotEqual(self.i1.getMaster().getName(), "_g2") for iterm in self.i1.getITerms(): self.assertNotIn(iterm.getMTerm().getName(), ["_a", "_b", "_o"]) - # testing with a gate with different mterms number + # testing with a gate with different mterms number - shuld fail gate = helper.createMaster3X1(self.lib, "_g3", 800, 800, "_a", "_b", "_c", "_o") self.assertFalse(self.i1.swapMaster(gate)) self.assertNotEqual(self.i1.getMaster().getName(), "_g3") for iterm in self.i1.getITerms(): self.assertNotIn(iterm.getMTerm().getName(), ["_a", "_b", "_c", "_o"]) - # testing with a gate with same mterm names + # testing with a gate with same mterm names - should succeed gate = helper.createMaster2X1(self.lib, "g2", 800, 800, "a", "b", "o") self.assertTrue(self.i1.swapMaster(gate)) self.assertEqual(self.i1.getMaster().getName(), "g2") @@ -35,5 +36,4 @@ def test_swap_master(self): if __name__ == "__main__": - odbUnitTest.mainParallel(TestInst) -# odbUnitTest.main() + unittest.main() diff --git a/src/odb/test/unitTestsPython/TestITerm.py b/src/odb/test/test_iterm.py similarity index 70% rename from src/odb/test/unitTestsPython/TestITerm.py rename to src/odb/test/test_iterm.py index 171f680e66f..9010da7b135 100644 --- a/src/odb/test/unitTestsPython/TestITerm.py +++ b/src/odb/test/test_iterm.py @@ -1,6 +1,7 @@ -import opendbpy as odb +import odb import helper import odbUnitTest +import unittest class TestITerm(odbUnitTest.TestCase): @@ -23,14 +24,14 @@ def test_connection_from_iterm(self): n = odb.dbNet_create(self.block, "n1") self.assertEqual(n.getITermCount(), 0) self.assertEqual(n.getITerms(), []) - self.iterm_a.connect(self.iterm_a, n) + self.iterm_a.connect(n) self.iterm_a.setConnected() self.assertEqual(self.iterm_a.getNet().getName(), "n1") self.assertEqual(n.getITermCount(), 1) self.assertEqual(n.getITerms()[0].getMTerm().getName(), "a") self.assertTrue(self.iterm_a.isConnected()) # disconnect - self.iterm_a.disconnect(self.iterm_a) + self.iterm_a.disconnect() self.iterm_a.clearConnected() self.assertEqual(n.getITermCount(), 0) self.assertEqual(n.getITerms(), []) @@ -42,14 +43,14 @@ def test_connection_from_inst(self): n = odb.dbNet_create(self.block, "n1") self.assertEqual(n.getITermCount(), 0) self.assertEqual(n.getITerms(), []) - self.iterm_a.connect(self.inst, n, self.inst.getMaster().findMTerm("a")) + self.iterm_a.connect(n) self.iterm_a.setConnected() self.assertEqual(self.iterm_a.getNet().getName(), "n1") self.assertEqual(n.getITermCount(), 1) self.assertEqual(n.getITerms()[0].getMTerm().getName(), "a") self.assertTrue(self.iterm_a.isConnected()) # disconnect - self.iterm_a.disconnect(self.iterm_a) + self.iterm_a.disconnect() self.iterm_a.clearConnected() self.assertEqual(n.getITermCount(), 0) self.assertEqual(n.getITerms(), []) @@ -57,28 +58,28 @@ def test_connection_from_inst(self): self.assertFalse(self.iterm_a.isConnected()) def test_avgxy_R0(self): - x = odb.new_int(0) - y = odb.new_int(0) - self.assertFalse(self.iterm_a.getAvgXY(x, y)) # no mpin to work on + result, x, y = self.iterm_a.getAvgXY() + self.assertFalse(result) # no mpin to work on mterm_a = self.and2.findMTerm("a") mpin_a = odb.dbMPin_create(mterm_a) - self.assertFalse(self.iterm_a.getAvgXY(x, y)) # no boxes to work on + result, x, y = self.iterm_a.getAvgXY() + self.assertFalse(result) # no boxes to work on geo_box_a_1 = odb.dbBox_create( mpin_a, self.lib.getTech().getLayers()[0], 0, 0, 50, 50 ) - self.assertTrue(self.iterm_a.getAvgXY(x, y)) - self.assertEqual(odb.get_int(x), int((0 + 50) / 2)) - self.assertEqual(odb.get_int(y), int((0 + 50) / 2)) + result, x, y = self.iterm_a.getAvgXY() + self.assertTrue(result) + self.assertEqual(x, int((0 + 50) / 2)) + self.assertEqual(y, int((0 + 50) / 2)) geo_box_a_2 = odb.dbBox_create( mpin_a, self.lib.getTech().getLayers()[0], 5, 10, 100, 100 ) - self.assertTrue(self.iterm_a.getAvgXY(x, y)) - self.assertEqual(odb.get_int(x), int(((0 + 50) + (5 + 100)) / 4)) - self.assertEqual(odb.get_int(y), int(((0 + 50) + (10 + 100)) / 4)) + result, x, y = self.iterm_a.getAvgXY() + self.assertTrue(result) + self.assertEqual(x, int(((0 + 50) + (5 + 100)) / 4)) + self.assertEqual(y, int(((0 + 50) + (10 + 100)) / 4)) def test_avgxy_R90(self): - x = odb.new_int(0) - y = odb.new_int(0) mterm_a = self.and2.findMTerm("a") mpin_a = odb.dbMPin_create(mterm_a) geo_box_a_1 = odb.dbBox_create( @@ -88,11 +89,10 @@ def test_avgxy_R90(self): mpin_a, self.lib.getTech().getLayers()[0], 0, 0, 100, 100 ) self.inst.setOrient("R90") - self.assertTrue(self.iterm_a.getAvgXY(x, y)) - self.assertEqual(odb.get_int(x), int(((0 + 50) + (0 + 100)) / 4) * -1) - self.assertEqual(odb.get_int(y), int(((0 + 50) + (0 + 100)) / 4)) - + result, x, y = self.iterm_a.getAvgXY() + self.assertTrue(result) + self.assertEqual(x, int(((0 + 50) + (0 + 100)) / 4) * -1) + self.assertEqual(y, int(((0 + 50) + (0 + 100)) / 4)) if __name__ == "__main__": - odbUnitTest.mainParallel(TestITerm) -# odbUnitTest.main() + unittest.main() diff --git a/src/odb/test/unitTestsPython/TestModule.py b/src/odb/test/test_module.py similarity index 91% rename from src/odb/test/unitTestsPython/TestModule.py rename to src/odb/test/test_module.py index 6f697f1b71f..cb1c7ab3631 100644 --- a/src/odb/test/unitTestsPython/TestModule.py +++ b/src/odb/test/test_module.py @@ -1,6 +1,7 @@ -import opendbpy as odb +import odb import helper import odbUnitTest +import unittest ################## @@ -32,11 +33,12 @@ def test_default(self): self.parent_mod.addInst(self.inst1) self.assertEqual(self.parent_mod.getInsts()[0].getName(), "inst") self.assertEqual(self.inst1.getModule().getName(), "parent_mod") - self.parent_mod.removeInst(self.inst1) + odb.dbInst_destroy(self.inst1) + self.assertIsNone(self.parent_mod.findModInst("inst")) self.assertEqual(self.parent_mod.findModInst("i1").getName(), "i1") self.i1.destroy(self.i1) self.parent_mod.destroy(self.parent_mod) if __name__ == "__main__": - odbUnitTest.mainParallel(TestModule) + unittest.main() diff --git a/src/odb/test/unitTestsPython/TestNet.py b/src/odb/test/test_net.py similarity index 97% rename from src/odb/test/unitTestsPython/TestNet.py rename to src/odb/test/test_net.py index 3cd0ed747a4..fe5eaaba404 100644 --- a/src/odb/test/unitTestsPython/TestNet.py +++ b/src/odb/test/test_net.py @@ -1,6 +1,7 @@ -import opendbpy as odb +import odb import helper import odbUnitTest +import unittest # TestNet: A unit test class for class dbNet @@ -57,4 +58,4 @@ def test_cc(self): if __name__ == "__main__": - odbUnitTest.mainParallel(TestNet) + unittest.main() diff --git a/src/odb/test/unitTests.sh b/src/odb/test/unitTests.sh deleted file mode 100755 index 3335d0c0d8e..00000000000 --- a/src/odb/test/unitTests.sh +++ /dev/null @@ -1,22 +0,0 @@ -set -e - -BASE_DIR=$(dirname $0) - -export PYTHONPATH=$BASE_DIR/../build/src/swig/python:$PYTHONPATH - -echo "Running tests .." -echo "" -if [[ $1 = "parallel" ]] -then - unittest-parallel -s $BASE_DIR/unitTestsPython/ -p 'Test*.py' -q -else - files=$(find $BASE_DIR/unitTestsPython -name "Test*.py") - for file in $files - do - name=$(echo $file | awk -F"/" '{print $NF}') - echo "$name" - echo "" - python3 $BASE_DIR/unitTestsPython/$name - echo "" - done -fi \ No newline at end of file diff --git a/src/odb/test/unitTestsPython/odbUnitTest.py b/src/odb/test/unitTestsPython/odbUnitTest.py deleted file mode 100644 index 1e5ad356596..00000000000 --- a/src/odb/test/unitTestsPython/odbUnitTest.py +++ /dev/null @@ -1,40 +0,0 @@ -import unittest -import testtools - - -class TestCase(unittest.TestCase): - # Function to change a value and test the change effect - def changeAndTest(self, obj, SetterName, GetterName, expectedVal, *args): - getattr(obj, SetterName)(*args) - self.assertEqual(getattr(obj, GetterName)(), expectedVal) - - def check(self, obj, GetterName, expectedVal, *args): - self.assertEqual(getattr(obj, GetterName)(*args), expectedVal) - - def change(self, obj, SetterName, *args): - return getattr(obj, SetterName)(*args) - - -class TracingStreamResult(testtools.StreamResult): - def status(self, *args, **kwargs): - tid = kwargs["test_id"].split(".") - if kwargs["test_status"] in ["success", "fail"]: - print(tid[2], " : ", kwargs["test_status"]) - - -# print('{0[test_id]}: {0[test_status]}'.format(kwargs)) - - -def main(): - unittest.main() - - -def mainParallel(Test): - suite = unittest.TestLoader().loadTestsFromTestCase(Test) - concurrent_suite = testtools.ConcurrentStreamTestSuite( - lambda: ((case, None) for case in suite) - ) - result = TracingStreamResult() - result.startTestRun() - concurrent_suite.run(result) - result.stopTestRun() diff --git a/test/regression_test.sh b/test/regression_test.sh index 99d5ee07257..0f2eff1771d 100644 --- a/test/regression_test.sh +++ b/test/regression_test.sh @@ -14,7 +14,7 @@ fi echo "Directory: ${PWD}" echo "Command: $OPENROAD_EXE $ORD_ARGS -no_splash -no_init -exit $TEST_NAME.$TEST_EXT > $LOG_FILE" -$OPENROAD_EXE $ORD_ARGS -no_splash -no_init -exit $TEST_NAME.$TEST_EXT > $LOG_FILE +$OPENROAD_EXE $ORD_ARGS -no_splash -no_init -exit $TEST_NAME.$TEST_EXT &> $LOG_FILE echo "Exitcode: $?" @@ -24,5 +24,5 @@ if [ "$TEST_CHECK_LOG" == "True" ]; then fi if [ "$TEST_CHECK_PASSFAIL" == "True" ]; then - tail -n1 $LOG_FILE | grep -G '^pass$' + tail -n1 $LOG_FILE | grep -E '^(pass|OK)' fi diff --git a/test/shared/regression.sh b/test/shared/regression.sh index 6c1dd13bbec..ccf130a14d6 100755 --- a/test/shared/regression.sh +++ b/test/shared/regression.sh @@ -37,8 +37,26 @@ set -e -tool=$(basename $(dirname $PWD)) +# +# Uses the current directory to figure out what the tool name is. Allows us to +# call the script from src/tool/test and src/tool directories. Wish we could +# just use the path of the regression script, but we can't since $0 points to +# the location in test/shared and not src/tool/test. +# +_get_tool_name() +{ + echo $(readlink $0) + script_path=$(realpath $PWD) + tool=$(basename "${script_path%%/src/*}/src/$(echo "$script_path" | awk -F'/src/' '{print $2}' | cut -d'/' -f1)") +} -cd ../../../build +_get_tool_name + +# build directory is two directories up from test/shared where this file exists +build_dir_path=$(dirname $(dirname $(dirname $(realpath "$0"))))/build + +cd $build_dir_path ctest -L $tool ${@:1} + + From 9a009fd9d88f0425a3c60bcfea636067469fd173 Mon Sep 17 00:00:00 2001 From: Jeff Ng Date: Thu, 19 Dec 2024 14:30:06 -0800 Subject: [PATCH 2/3] lint fixes Signed-off-by: Jeff Ng --- src/odb/test/helper.py | 7 +- src/odb/test/test_block.py | 134 ------------------------------------- src/odb/test/test_iterm.py | 1 + 3 files changed, 5 insertions(+), 137 deletions(-) diff --git a/src/odb/test/helper.py b/src/odb/test/helper.py index 800619fb921..88b142c883c 100644 --- a/src/odb/test/helper.py +++ b/src/odb/test/helper.py @@ -2,6 +2,7 @@ import openroad from openroad import Design + def createSimpleDB(): db = Design.createDetachedDb() tech = odb.dbTech.create(db, "simple_tech") @@ -117,21 +118,21 @@ def create2LevelBlock(db, lib, parent): i1_b.connect(n2) i1_o = i1.findITerm("o") i1_o.connect(n5) - + # connect i2 i2_a = i2.findITerm("a") i2_a.connect(n3) i2_b = i2.findITerm("b") i2_b.connect(n4) i2_o = i2.findITerm("o") i2_o.connect(n6) - + # connect i3 i3_a = i3.findITerm("a") i3_a.connect(n5) i3_b = i3.findITerm("b") i3_b.connect(n6) i3_o = i3.findITerm("o") i3_o.connect(n7) - + # connect pins P1 = odb.dbBPin_create(IN1) P2 = odb.dbBPin_create(IN2) P3 = odb.dbBPin_create(IN3) diff --git a/src/odb/test/test_block.py b/src/odb/test/test_block.py index 509717a12e0..cb2aeb612c3 100644 --- a/src/odb/test/test_block.py +++ b/src/odb/test/test_block.py @@ -19,141 +19,7 @@ def setUp(self): self.db, self.lib = helper.createSimpleDB() self.parentBlock = odb.dbBlock_create(self.db.getChip(), "Parent") self.block = helper.create2LevelBlock(self.db, self.lib, self.parentBlock) - self.block.setCornerCount(4) - self.extcornerblock = self.block.createExtCornerBlock(1) - odb.dbTechNonDefaultRule_create(self.block, "non_default_1") - self.parentRegion = odb.dbRegion_create(self.block, "parentRegion") - def tearDown(self): - self.db.destroy(self.db) - - def test_find(self): - # bterm - self.assertEqual(self.block.findBTerm("IN1").getName(), "IN1") - self.assertIsNone(self.block.findBTerm("in1")) - # child - self.assertEqual( - self.parentBlock.findChild("2LevelBlock").getName(), "2LevelBlock" - ) - self.assertIsNone(self.parentBlock.findChild("1LevelBlock")) - # inst - self.assertEqual(self.block.findInst("i3").getName(), "i3") - self.assertIsNone(self.parentBlock.findInst("i3")) - # net - self.assertEqual(self.block.findNet("n2").getName(), "n2") - self.assertIsNone(self.block.findNet("a")) - # iterm - self.assertEqual(self.block.findITerm("i1,o").getInst().getName(), "i1") - self.assertEqual(self.block.findITerm("i1,o").getMTerm().getName(), "o") - self.assertIsNone(self.block.findITerm("i1\o")) - # extcornerblock - self.assertEqual( - self.block.findExtCornerBlock(1).getName(), "extCornerBlock__1" - ) - self.assertIsNone(self.block.findExtCornerBlock(0)) - # nondefaultrule - self.assertEqual( - self.block.findNonDefaultRule("non_default_1").getName(), "non_default_1" - ) - self.assertIsNone(self.block.findNonDefaultRule("non_default_2")) - # region - self.assertEqual( - self.block.findRegion("parentRegion").getName(), "parentRegion" - ) - - def check_box_rect(self, min_x, min_y, max_x, max_y): - box = self.block.getBBox() - self.assertEqual(box.xMin(), min_x) - self.assertEqual(box.xMax(), max_x) - self.assertEqual(box.yMin(), min_y) - self.assertEqual(box.yMax(), max_y) - - def block_placement(self, test_num, flag): - if (flag and test_num == 1) or (not flag and test_num >= 1): - if flag: - print("here") - placeInst(self.block.findInst("i1"), 0, 3000) - placeInst(self.block.findInst("i2"), -1000, 0) - placeInst(self.block.findInst("i3"), 2000, -1000) - if (flag and test_num == 2) or (not flag and test_num >= 2): - placeBPin( - self.block.findBTerm("OUT").getBPins()[0], - self.lib.getTech().findLayer("L1"), - 2500, - -1000, - 2550, - -950, - ) - if (flag and test_num == 3) or (not flag and test_num >= 3): - odb.dbObstruction_create( - self.block, self.lib.getTech().findLayer("L1"), -1500, 0, -1580, 50 - ) - if (flag and test_num == 4) or (not flag and test_num >= 4): - n_s = odb.dbNet_create(self.block, "n_s") - swire = odb.dbSWire_create(n_s, "NONE") - odb.dbSBox_create( - swire, self.lib.getTech().findLayer("L1"), 0, 4000, 100, 4100, "NONE" - ) - if (flag and test_num == 5) or (not flag and test_num >= 5): - pass - # TODO ADD WIRE - - def test_bbox0(self): - box = self.block.getBBox() - self.check_box_rect(0, 0, 0, 0) - - def test_bbox1(self): - box = self.block.getBBox() - self.block_placement(1, False) - self.check_box_rect(-1000, -1000, 2500, 4000) - - def test_bbox2(self): - box = self.block.getBBox() - self.block_placement(2, False) - self.check_box_rect(-1000, -1000, 2550, 4000) - - def test_bbox3(self): - # self.block_placement(2,False) - # box = self.block.getBBox() - # self.block_placement(3,True) - placeInst(self.block.findInst("i1"), 0, 3000) - placeInst(self.block.findInst("i2"), -1000, 0) - placeInst(self.block.findInst("i3"), 2000, -1000) - placeBPin( - self.block.findBTerm("OUT").getBPins()[0], - self.lib.getTech().findLayer("L1"), - 2500, - -1000, - 2550, - -950, - ) - box = self.block.getBBox() - odb.dbObstruction_create( - self.block, self.lib.getTech().findLayer("L1"), -1500, 0, -1580, 50 - ) - self.check_box_rect(-1580, -1000, 2550, 4000) - - def test_bbox4(self): - box = self.block.getBBox() - self.block_placement(4, False) - self.check_box_rect(-1580, -1000, 2550, 4100) - - def test_get_chip(self): - """ - Tests getChip API - - Note: can't call assertEqual directly on the getChip() result because - the two objects point to different swig-wrapped objects - """ - self.assertEqual(self.db.getChip().getBlock().getName(), self.parentBlock.getChip().getBlock().getName()) - - @unittest.skip("re-enable once memory corruption is resolved") - def test_duplicate(self): - dup_block = odb.dbBlock_duplicate(self.block, "dup_block") - self.assertEqual(dup_block.getName(), "dup_block") - self.assertEqual(len(dup_block.getInsts()), len(self.block.getInsts())) - self.assertEqual(len(dup_block.getNets()), len(self.block.getNets())) - self.assertEqual(len(dup_block.getBTerms()), len(self.block.getBTerms())) if __name__ == "__main__": unittest.main() diff --git a/src/odb/test/test_iterm.py b/src/odb/test/test_iterm.py index 9010da7b135..0ee56025ee8 100644 --- a/src/odb/test/test_iterm.py +++ b/src/odb/test/test_iterm.py @@ -94,5 +94,6 @@ def test_avgxy_R90(self): self.assertEqual(x, int(((0 + 50) + (0 + 100)) / 4) * -1) self.assertEqual(y, int(((0 + 50) + (0 + 100)) / 4)) + if __name__ == "__main__": unittest.main() From 0d00a33812375df61cdf05f27f0d82e67c9f2e3f Mon Sep 17 00:00:00 2001 From: Jeff Ng Date: Fri, 20 Dec 2024 07:56:53 -0800 Subject: [PATCH 3/3] added back missing content Signed-off-by: Jeff Ng --- src/odb/test/test_block.py | 118 +++++++++++++++++++++++++++++++++++++ 1 file changed, 118 insertions(+) diff --git a/src/odb/test/test_block.py b/src/odb/test/test_block.py index cb2aeb612c3..e792d7823e7 100644 --- a/src/odb/test/test_block.py +++ b/src/odb/test/test_block.py @@ -19,6 +19,124 @@ def setUp(self): self.db, self.lib = helper.createSimpleDB() self.parentBlock = odb.dbBlock_create(self.db.getChip(), "Parent") self.block = helper.create2LevelBlock(self.db, self.lib, self.parentBlock) + self.block.setCornerCount(4) + self.extcornerblock = self.block.createExtCornerBlock(1) + odb.dbTechNonDefaultRule_create(self.block, "non_default_1") + self.parentRegion = odb.dbRegion_create(self.block, "parentRegion") + + def tearDown(self): + self.db.destroy(self.db) + + def test_find(self): + # bterm + self.assertEqual(self.block.findBTerm("IN1").getName(), "IN1") + self.assertIsNone(self.block.findBTerm("in1")) + # child + self.assertEqual( + self.parentBlock.findChild("2LevelBlock").getName(), "2LevelBlock" + ) + self.assertIsNone(self.parentBlock.findChild("1LevelBlock")) + # inst + self.assertEqual(self.block.findInst("i3").getName(), "i3") + self.assertIsNone(self.parentBlock.findInst("i3")) + # net + self.assertEqual(self.block.findNet("n2").getName(), "n2") + self.assertIsNone(self.block.findNet("a")) + # iterm + self.assertEqual(self.block.findITerm("i1,o").getInst().getName(), "i1") + self.assertEqual(self.block.findITerm("i1,o").getMTerm().getName(), "o") + self.assertIsNone(self.block.findITerm("i1\o")) + # extcornerblock + self.assertEqual( + self.block.findExtCornerBlock(1).getName(), "extCornerBlock__1" + ) + self.assertIsNone(self.block.findExtCornerBlock(0)) + # nondefaultrule + self.assertEqual( + self.block.findNonDefaultRule("non_default_1").getName(), "non_default_1" + ) + self.assertIsNone(self.block.findNonDefaultRule("non_default_2")) + # region + self.assertEqual( + self.block.findRegion("parentRegion").getName(), "parentRegion" + ) + + def check_box_rect(self, min_x, min_y, max_x, max_y): + box = self.block.getBBox() + self.assertEqual(box.xMin(), min_x) + self.assertEqual(box.xMax(), max_x) + self.assertEqual(box.yMin(), min_y) + self.assertEqual(box.yMax(), max_y) + + def block_placement(self, test_num, flag): + if (flag and test_num == 1) or (not flag and test_num >= 1): + if flag: + print("here") + placeInst(self.block.findInst("i1"), 0, 3000) + placeInst(self.block.findInst("i2"), -1000, 0) + placeInst(self.block.findInst("i3"), 2000, -1000) + if (flag and test_num == 2) or (not flag and test_num >= 2): + placeBPin( + self.block.findBTerm("OUT").getBPins()[0], + self.lib.getTech().findLayer("L1"), + 2500, + -1000, + 2550, + -950, + ) + if (flag and test_num == 3) or (not flag and test_num >= 3): + odb.dbObstruction_create( + self.block, self.lib.getTech().findLayer("L1"), -1500, 0, -1580, 50 + ) + if (flag and test_num == 4) or (not flag and test_num >= 4): + n_s = odb.dbNet_create(self.block, "n_s") + swire = odb.dbSWire_create(n_s, "NONE") + odb.dbSBox_create( + swire, self.lib.getTech().findLayer("L1"), 0, 4000, 100, 4100, "NONE" + ) + if (flag and test_num == 5) or (not flag and test_num >= 5): + pass + # TODO ADD WIRE + + def test_bbox0(self): + box = self.block.getBBox() + self.check_box_rect(0, 0, 0, 0) + + def test_bbox1(self): + box = self.block.getBBox() + self.block_placement(1, False) + self.check_box_rect(-1000, -1000, 2500, 4000) + + def test_bbox2(self): + box = self.block.getBBox() + self.block_placement(2, False) + self.check_box_rect(-1000, -1000, 2550, 4000) + + def test_bbox3(self): + # self.block_placement(2,False) + # box = self.block.getBBox() + # self.block_placement(3,True) + placeInst(self.block.findInst("i1"), 0, 3000) + placeInst(self.block.findInst("i2"), -1000, 0) + placeInst(self.block.findInst("i3"), 2000, -1000) + placeBPin( + self.block.findBTerm("OUT").getBPins()[0], + self.lib.getTech().findLayer("L1"), + 2500, + -1000, + 2550, + -950, + ) + box = self.block.getBBox() + odb.dbObstruction_create( + self.block, self.lib.getTech().findLayer("L1"), -1500, 0, -1580, 50 + ) + self.check_box_rect(-1580, -1000, 2550, 4000) + + def test_bbox4(self): + box = self.block.getBBox() + self.block_placement(4, False) + self.check_box_rect(-1580, -1000, 2550, 4100) if __name__ == "__main__":