diff --git a/Osdag b/Osdag new file mode 160000 index 000000000..32dabe46c --- /dev/null +++ b/Osdag @@ -0,0 +1 @@ +Subproject commit 32dabe46c05000dde32ff8ccb84fc82f32e94add diff --git a/tests/CleatAngleTest1.osi b/tests/CleatAngleTest1.osi new file mode 100644 index 000000000..3dc747325 --- /dev/null +++ b/tests/CleatAngleTest1.osi @@ -0,0 +1,127 @@ +Bolt.Bolt_Hole_Type: Standard +Bolt.Diameter: +- '8' +- '10' +- '12' +- '16' +- '20' +- '24' +- '30' +- '36' +- '42' +- '48' +- '56' +- '64' +- '14' +- '18' +- '22' +- '27' +- '33' +- '39' +- '45' +- '52' +- '60' +Bolt.Grade: +- '3.6' +- '4.6' +- '4.8' +- '5.6' +- '5.8' +- '6.8' +- '8.8' +- '9.8' +- '10.9' +- '12.9' +Bolt.Slip_Factor: '0.3' +Bolt.TensionType: Pretensioned +Bolt.Type: Bearing Bolt +Connectivity *: Beam-Beam +Connector.Angle_List: +- 50 x 50 x 3 +- 50 x 50 x 4 +- 50 x 50 x 5 +- 50 x 50 x 6 +- 55 x 55 x 4 +- 55 x 55 x 5 +- 55 x 55 x 6 +- 55 x 55 x 8 +- 60 x 60 x 4 +- 60 x 60 x 5 +- 60 x 60 x 6 +- 60 x 60 x 8 +- 65 x 65 x 4 +- 65 x 65 x 5 +- 65 x 65 x 6 +- 65 x 65 x 8 +- 70 x 70 x 5 +- 70 x 70 x 6 +- 70 x 70 x 8 +- 70 x 70 x 10 +- 75 x 75 x 5 +- 75 x 75 x 6 +- 75 x 75 x 8 +- 75 x 75 x 10 +- 80 x 80 x 6 +- 80 x 80 x 8 +- 80 x 80 x 10 +- 80 x 80 x 12 +- 90 x 90 x 6 +- 90 x 90 x 8 +- 90 x 90 x 10 +- 90 x 90 x 12 +- 100 x 100 x 6 +- 100 x 100 x 8 +- 100 x 100 x 10 +- 100 x 100 x 12 +- 110 x 110 x 8 +- 110 x 110 x 10 +- 110 x 110 x 12 +- 110 x 110 x 16 +- 130 x 130 x 8 +- 130 x130 x 10 +- 130 x130 x 12 +- 130 x130 x 16 +- 150 x 150 x 10 +- 150 x 150 x 12 +- 150 x 150 x 16 +- 150 x 150 x 20 +- 200 x 200 x 12 +- 200 x 200 x 16 +- 200 x 200 x 20 +- 200 x 200 x 25 +- 50 x 50 x 7 +- 50 x 50 x 8 +- 55 x 55 x 10 +- 60 x 60 x 10 +- 65 x 65 x 10 +- 70 x 70 x 7 +- 100 x 100 x 7 +- 100 x 100 x 15 +- 120 x 120 x 8 +- 120 x 120 x 10 +- 120 x 120 x 12 +- 120 x 120 x 15 +- 130 x 130 x 9 +- 150 x 150 x 15 +- 150 x 150 x 18 +- 180 x 180 x 15 +- 180 x 180 x 18 +- 180 x 180 x 20 +- 200 x 200 x 24 +Connector.Material: E 250 (Fe 410 W)A +Design.Design_Method: Limit State Design +Detailing.Corrosive_Influences: 'No' +Detailing.Edge_type: Sheared or hand flame cut +Detailing.Gap: '10' +Load.Shear: '40' +Material: E 250 (Fe 410 W)A +Member.Supported_Section.Designation: MB 200 +Member.Supported_Section.Material: E 250 (Fe 410 W)A +Member.Supporting_Section.Designation: MB 400 +Member.Supporting_Section.Material: E 250 (Fe 410 W)A +Module: Cleat Angle Connection +out_titles_status: +- 1 +- 1 +- 1 +- 1 diff --git a/tests/CleatAngleTest2.osi b/tests/CleatAngleTest2.osi new file mode 100644 index 000000000..51abc0fea --- /dev/null +++ b/tests/CleatAngleTest2.osi @@ -0,0 +1,33 @@ +Bolt.Bolt_Hole_Type: Standard +Bolt.Diameter: +- '8' +Bolt.Grade: +- '3.6' +- '4.6' +- '4.8' +- '5.6' +- '5.8' +- '6.8' +- '8.8' +- '9.8' +- '10.9' +- '12.9' +Bolt.Slip_Factor: '0.3' +Bolt.TensionType: Non pre-tensioned +Bolt.Type: Bearing Bolt +Connectivity *: Column Web-Beam Web +Connector.Angle_List: +- 60 x 60 x 4 +- 70 x 70 x 5 +Connector.Material: E 250 (Fe 410 W)A +Design.Design_Method: Limit State Design +Detailing.Corrosive_Influences: 'No' +Detailing.Edge_type: Rolled, machine-flame cut, sawn and planed +Detailing.Gap: '10' +Load.Shear: '80' +Material: E 250 (Fe 410 W)A +Member.Supported_Section.Designation: LB 200 +Member.Supported_Section.Material: E 250 (Fe 410 W)A +Member.Supporting_Section.Designation: HB 225 +Member.Supporting_Section.Material: E 250 (Fe 410 W)A +Module: Cleat Angle Connection diff --git a/tests/CleatAngleTest3.osi b/tests/CleatAngleTest3.osi new file mode 100644 index 000000000..ba160b0c5 --- /dev/null +++ b/tests/CleatAngleTest3.osi @@ -0,0 +1,102 @@ +Bolt.Bolt_Hole_Type: Standard +Bolt.Diameter: +- '8' +Bolt.Grade: +- '3.6' +- '4.6' +- '4.8' +- '5.6' +- '5.8' +- '6.8' +- '8.8' +- '9.8' +- '10.9' +- '12.9' +Bolt.Slip_Factor: '0.1' +Bolt.TensionType: Pre-tensioned +Bolt.Type: Friction Grip Bolt +Connectivity *: Column Web-Beam Web +Connector.Angle_List: +- 50 x 50 x 3 +- 50 x 50 x 4 +- 50 x 50 x 5 +- 50 x 50 x 6 +- 55 x 55 x 4 +- 55 x 55 x 5 +- 55 x 55 x 6 +- 55 x 55 x 8 +- 60 x 60 x 4 +- 60 x 60 x 5 +- 60 x 60 x 6 +- 60 x 60 x 8 +- 65 x 65 x 4 +- 65 x 65 x 5 +- 65 x 65 x 6 +- 65 x 65 x 8 +- 70 x 70 x 5 +- 70 x 70 x 6 +- 70 x 70 x 8 +- 70 x 70 x 10 +- 75 x 75 x 5 +- 75 x 75 x 6 +- 75 x 75 x 8 +- 75 x 75 x 10 +- 80 x 80 x 6 +- 80 x 80 x 8 +- 80 x 80 x 10 +- 80 x 80 x 12 +- 90 x 90 x 6 +- 90 x 90 x 8 +- 90 x 90 x 10 +- 90 x 90 x 12 +- 100 x 100 x 6 +- 100 x 100 x 8 +- 100 x 100 x 10 +- 100 x 100 x 12 +- 110 x 110 x 8 +- 110 x 110 x 10 +- 110 x 110 x 12 +- 110 x 110 x 16 +- 130 x 130 x 8 +- 130 x130 x 10 +- 130 x130 x 12 +- 130 x130 x 16 +- 150 x 150 x 10 +- 150 x 150 x 12 +- 150 x 150 x 16 +- 150 x 150 x 20 +- 200 x 200 x 12 +- 200 x 200 x 16 +- 200 x 200 x 20 +- 200 x 200 x 25 +- 50 x 50 x 7 +- 50 x 50 x 8 +- 55 x 55 x 10 +- 60 x 60 x 10 +- 65 x 65 x 10 +- 70 x 70 x 7 +- 100 x 100 x 7 +- 100 x 100 x 15 +- 120 x 120 x 8 +- 120 x 120 x 10 +- 120 x 120 x 12 +- 120 x 120 x 15 +- 130 x 130 x 9 +- 150 x 150 x 15 +- 150 x 150 x 18 +- 180 x 180 x 15 +- 180 x 180 x 18 +- 180 x 180 x 20 +- 200 x 200 x 24 +Connector.Material: E 250 (Fe 410 W)A +Design.Design_Method: Limit State Design +Detailing.Corrosive_Influences: 'No' +Detailing.Edge_type: Sheared or hand flame cut +Detailing.Gap: '10' +Load.Shear: '35' +Material: E 250 (Fe 410 W)A +Member.Supported_Section.Designation: LB 200 +Member.Supported_Section.Material: E 250 (Fe 410 W)A +Member.Supporting_Section.Designation: HB 225 +Member.Supporting_Section.Material: E 250 (Fe 410 W)A +Module: Cleat Angle Connection diff --git a/tests/CleatAngleTest4.osi b/tests/CleatAngleTest4.osi new file mode 100644 index 000000000..40a258daa --- /dev/null +++ b/tests/CleatAngleTest4.osi @@ -0,0 +1,102 @@ +Bolt.Bolt_Hole_Type: Standard +Bolt.Diameter: +- '8' +Bolt.Grade: +- '3.6' +- '4.6' +- '4.8' +- '5.6' +- '5.8' +- '6.8' +- '8.8' +- '9.8' +- '10.9' +- '12.9' +Bolt.Slip_Factor: '0.1' +Bolt.TensionType: Pre-tensioned +Bolt.Type: Bearing Bolt +Connectivity *: Column Flange-Beam Web +Connector.Angle_List: +- 50 x 50 x 3 +- 50 x 50 x 4 +- 50 x 50 x 5 +- 50 x 50 x 6 +- 55 x 55 x 4 +- 55 x 55 x 5 +- 55 x 55 x 6 +- 55 x 55 x 8 +- 60 x 60 x 4 +- 60 x 60 x 5 +- 60 x 60 x 6 +- 60 x 60 x 8 +- 65 x 65 x 4 +- 65 x 65 x 5 +- 65 x 65 x 6 +- 65 x 65 x 8 +- 70 x 70 x 5 +- 70 x 70 x 6 +- 70 x 70 x 8 +- 70 x 70 x 10 +- 75 x 75 x 5 +- 75 x 75 x 6 +- 75 x 75 x 8 +- 75 x 75 x 10 +- 80 x 80 x 6 +- 80 x 80 x 8 +- 80 x 80 x 10 +- 80 x 80 x 12 +- 90 x 90 x 6 +- 90 x 90 x 8 +- 90 x 90 x 10 +- 90 x 90 x 12 +- 100 x 100 x 6 +- 100 x 100 x 8 +- 100 x 100 x 10 +- 100 x 100 x 12 +- 110 x 110 x 8 +- 110 x 110 x 10 +- 110 x 110 x 12 +- 110 x 110 x 16 +- 130 x 130 x 8 +- 130 x130 x 10 +- 130 x130 x 12 +- 130 x130 x 16 +- 150 x 150 x 10 +- 150 x 150 x 12 +- 150 x 150 x 16 +- 150 x 150 x 20 +- 200 x 200 x 12 +- 200 x 200 x 16 +- 200 x 200 x 20 +- 200 x 200 x 25 +- 50 x 50 x 7 +- 50 x 50 x 8 +- 55 x 55 x 10 +- 60 x 60 x 10 +- 65 x 65 x 10 +- 70 x 70 x 7 +- 100 x 100 x 7 +- 100 x 100 x 15 +- 120 x 120 x 8 +- 120 x 120 x 10 +- 120 x 120 x 12 +- 120 x 120 x 15 +- 130 x 130 x 9 +- 150 x 150 x 15 +- 150 x 150 x 18 +- 180 x 180 x 15 +- 180 x 180 x 18 +- 180 x 180 x 20 +- 200 x 200 x 24 +Connector.Material: E 250 (Fe 410 W)A +Design.Design_Method: Limit State Design +Detailing.Corrosive_Influences: 'No' +Detailing.Edge_type: Sheared or hand flame cut +Detailing.Gap: '10' +Load.Shear: '35' +Material: E 250 (Fe 410 W)A +Member.Supported_Section.Designation: JB 225 +Member.Supported_Section.Material: E 250 (Fe 410 W)A +Member.Supporting_Section.Designation: HB 300 +Member.Supporting_Section.Material: E 250 (Fe 410 W)A +Module: Cleat Angle Connection diff --git a/tests/FinPlateTest1.osi b/tests/FinPlateTest1.osi new file mode 100644 index 000000000..5f7f8cf7f --- /dev/null +++ b/tests/FinPlateTest1.osi @@ -0,0 +1,73 @@ +Bolt.Bolt_Hole_Type: Standard +Bolt.Diameter: +- '8' +- '10' +- '12' +- '16' +- '20' +- '24' +- '30' +- '36' +- '42' +- '48' +- '56' +- '64' +- '14' +- '18' +- '22' +- '27' +- '33' +- '39' +- '45' +- '52' +- '60' +Bolt.Grade: +- '10.9' +Bolt.Slip_Factor: '0.3' +Bolt.TensionType: Pretensioned +Bolt.Type: Bearing Bolt +Connectivity *: Column Flange-Beam Web +Connector.Material: E 250 (Fe 410 W)A +Connector.Plate.Thickness_List: +- '8' +- '10' +- '12' +- '14' +- '16' +- '18' +- '20' +- '22' +- '25' +- '28' +- '32' +- '36' +- '40' +- '45' +- '50' +- '56' +- '63' +- '75' +- '80' +- '90' +- '100' +- '110' +- '120' +Design.Design_Method: Limit State Design +Detailing.Corrosive_Influences: 'No' +Detailing.Edge_type: Sheared or hand flame cut +Detailing.Gap: '10' +Load.Axial: '' +Load.Shear: '5' +Material: E 250 (Fe 410 W)A +Member.Supported_Section.Designation: LB 125 +Member.Supported_Section.Material: E 250 (Fe 410 W)A +Member.Supporting_Section.Designation: HB 300* +Member.Supporting_Section.Material: E 250 (Fe 410 W)A +Module: Fin Plate Connection +Weld.Fab: Shop Weld +Weld.Material_Grade_OverWrite: '410' +out_titles_status: +- 1 +- 1 +- 1 +- 1 diff --git a/tests/FinPlateTest2.osi b/tests/FinPlateTest2.osi new file mode 100644 index 000000000..ea375aae0 --- /dev/null +++ b/tests/FinPlateTest2.osi @@ -0,0 +1,82 @@ +Bolt.Bolt_Hole_Type: Standard +Bolt.Diameter: +- '8' +- '10' +- '12' +- '16' +- '20' +- '24' +- '30' +- '36' +- '42' +- '48' +- '56' +- '64' +- '14' +- '18' +- '22' +- '27' +- '33' +- '39' +- '45' +- '52' +- '60' +Bolt.Grade: +- '3.6' +- '4.6' +- '4.8' +- '5.6' +- '5.8' +- '6.8' +- '8.8' +- '9.8' +- '10.9' +- '12.9' +Bolt.Slip_Factor: '0.3' +Bolt.TensionType: Pretensioned +Bolt.Type: Friction Grip Bolt +Connectivity *: Column Web-Beam Web +Connector.Material: E 250 (Fe 410 W)A +Connector.Plate.Thickness_List: +- '8' +- '10' +- '12' +- '14' +- '16' +- '18' +- '20' +- '22' +- '25' +- '28' +- '32' +- '36' +- '40' +- '45' +- '50' +- '56' +- '63' +- '75' +- '80' +- '90' +- '100' +- '110' +- '120' +Design.Design_Method: Limit State Design +Detailing.Corrosive_Influences: 'No' +Detailing.Edge_type: Sheared or hand flame cut +Detailing.Gap: '10' +Load.Axial: '' +Load.Shear: '5' +Material: E 250 (Fe 410 W)A +Member.Supported_Section.Designation: JB 150 +Member.Supported_Section.Material: E 250 (Fe 410 W)A +Member.Supporting_Section.Designation: HB 200 +Member.Supporting_Section.Material: E 250 (Fe 410 W)A +Module: Fin Plate Connection +Weld.Fab: Shop Weld +Weld.Material_Grade_OverWrite: '410' +out_titles_status: +- 1 +- 1 +- 1 +- 1 diff --git a/tests/FinPlateTest3.osi b/tests/FinPlateTest3.osi new file mode 100644 index 000000000..ff9fcb1a4 --- /dev/null +++ b/tests/FinPlateTest3.osi @@ -0,0 +1,46 @@ +Bolt.Bolt_Hole_Type: Standard +Bolt.Diameter: +- '14' +- '16' +- '20' +Bolt.Grade: +- '3.6' +- '4.6' +- '4.8' +- '5.6' +- '5.8' +- '6.8' +- '8.8' +- '9.8' +- '10.9' +- '12.9' +Bolt.Slip_Factor: '0.3' +Bolt.TensionType: Pretensioned +Bolt.Type: Bearing Bolt +Connectivity *: Beam-Beam +Connector.Material: E 250 (Fe 410 W)A +Connector.Plate.Thickness_List: +- '10' +- '12' +- '16' +- '20' +- '25' +Design.Design_Method: Limit State Design +Detailing.Corrosive_Influences: 'No' +Detailing.Edge_type: Sheared or hand flame cut +Detailing.Gap: '10' +Load.Axial: '8' +Load.Shear: '50' +Material: E 250 (Fe 410 W)A +Member.Supported_Section.Designation: MB 200 +Member.Supported_Section.Material: E 250 (Fe 410 W)A +Member.Supporting_Section.Designation: MB 300 +Member.Supporting_Section.Material: E 250 (Fe 410 W)A +Module: Fin Plate Connection +Weld.Fab: Shop Weld +Weld.Material_Grade_OverWrite: '410' +out_titles_status: +- 1 +- 1 +- 1 +- 1 diff --git a/tests/FinPlateTest4.osi b/tests/FinPlateTest4.osi new file mode 100644 index 000000000..44bfdb184 --- /dev/null +++ b/tests/FinPlateTest4.osi @@ -0,0 +1,43 @@ +Bolt.Bolt_Hole_Type: Over-sized +Bolt.Diameter: +- '8' +- '10' +- '14' +- '16' +- '20' +- '24' +- '30' +Bolt.Grade: +- '3.6' +- '4.6' +- '4.8' +- '5.6' +- '5.8' +- '6.8' +- '8.8' +- '9.8' +- '10.9' +- '12.9' +Bolt.Slip_Factor: '0.3' +Bolt.TensionType: Non pre-tensioned +Bolt.Type: Bearing Bolt +Connectivity *: Beam-Beam +Connector.Material: E 250 (Fe 410 W)A +Connector.Plate.Thickness_List: +- '16' +- '20' +- '25' +Design.Design_Method: Limit State Design +Detailing.Corrosive_Influences: 'No' +Detailing.Edge_type: Rolled, machine-flame cut, sawn and planed +Detailing.Gap: '10' +Load.Axial: '8' +Load.Shear: '50' +Material: E 250 (Fe 410 W)A +Member.Supported_Section.Designation: MB 200 +Member.Supported_Section.Material: E 250 (Fe 410 W)A +Member.Supporting_Section.Designation: MB 300 +Member.Supporting_Section.Material: E 250 (Fe 410 W)A +Module: Fin Plate Connection +Weld.Fab: Field weld +Weld.Material_Grade_OverWrite: '410' diff --git a/tests/cleat_angle_test1.py b/tests/cleat_angle_test1.py new file mode 100644 index 000000000..788000994 --- /dev/null +++ b/tests/cleat_angle_test1.py @@ -0,0 +1,118 @@ +import yaml +import pandas as pd +import os +from osdag.design_type.connection.cleat_angle_connection import CleatAngleConnection + +def load_test_data(): + """Load test cases from Excel file""" + try: + df = pd.read_excel("ExpectedOutputs.xlsx", sheet_name="Cleat Angle Connection") + print("✅ Successfully loaded test cases") + return df + except Exception as e: + print(f"Failed to load Excel file: {e}") + exit(1) + +def setup_connection(data): + """Create and configure connection object""" + connection = CleatAngleConnection() + + try: + connection.set_input_values(data) + except Exception as e: + print(f" set_input_values failed: {e}") + raise + + try: + connection.check_available_cleat_thk() + connection.create3DModel() + except Exception as e: + print(f"Error during cleat checks or model creation: {e}") + + return connection + +def run_single_test(filename, expected): + """Run test for a single OSI file""" + print(f"\n Testing: {filename}") + print(f" Expected: {expected}") + + try: + with open(filename, 'r') as f: + data = yaml.safe_load(f) + + if not data: + print(" Empty YAML file") + return "error" + + connection = setup_connection(data) + + + if not hasattr(connection, "cleat") or not hasattr(connection, "bolt"): + print(" Missing 'cleat' or 'bolt' attribute") + return "error" + + actual = { + "designation": connection.cleat.designation, + "bolt_dia": connection.bolt.bolt_diameter_provided, + "bolt_grade": connection.bolt.bolt_PC_provided + } + + print(f" Actual: {actual}") + + for key in expected: + if key in actual and expected[key] != actual[key]: + print(f" Mismatch in {key}: expected {expected[key]}, got {actual[key]}") + return "failed" + + return "passed" + + except Exception as e: + print(f" Test failed with error: {type(e).__name__}: {e}") + return "error" + +def main(): + test_cases = load_test_data() + + expected_values = [] + for _, row in test_cases.iterrows(): + if pd.notna(row["Designation"]) and row["Designation"] not in ["Value", "Designation"]: + expected_values.append({ + "designation": row["Designation"], + "bolt_dia": row["Bolt Diameter"], + "bolt_grade": str(row["Property Class"]) + }) + + results = {"passed": 0, "failed": 0, "errors": 0, "skipped": 0} + + for i, expected in enumerate(expected_values, 1): + filename = f"CleatAngleTest{i}.osi" + + if not os.path.exists(filename): + print(f" Skipping {filename} (file not found)") + results["skipped"] += 1 + continue + + test_result = run_single_test(filename, expected) + + # Safe update + if test_result in results: + results[test_result] += 1 + else: + results["errors"] += 1 + + print("\n" + "=" * 50) + print(" TEST SUMMARY") + print("=" * 50) + print(f" Passed: {results['passed']}") + print(f" Failed: {results['failed']}") + print(f" Errors: {results['errors']}") + print(f"⏭ Skipped: {results['skipped']}") + print("=" * 50) + + if results['passed'] == len(expected_values): + print(" All tests passed!") + else: + print(" Some tests failed or errored. See above.") + +if __name__ == "__main__": + main() diff --git a/tests/python b/tests/python new file mode 100644 index 000000000..e69de29bb diff --git a/tests/test_cleat_angle.py b/tests/test_cleat_angle.py new file mode 100644 index 000000000..2da2870dd --- /dev/null +++ b/tests/test_cleat_angle.py @@ -0,0 +1,135 @@ +import sys +import os +import builtins +import yaml +import pytest + +# Add Osdag source path +sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "../src"))) + +# Inject missing constants before Osdag loads +builtins.KEY_DP_FAB_SHOP = "fab_shop" +builtins.KEY_DP_FAB_FIELD = "fab_field" + +# Import CleatAngleConnection safely +from osdag.design_type.connection.cleat_angle_connection import CleatAngleConnection + +import osdag.design_type.connection.cleat_angle_connection as cleat_mod +import logging + +# Patch missing logger +cleat_mod.logger = logging.getLogger("dummy_logger") +cleat_mod.logger.addHandler(logging.NullHandler()) + + +# Patch set_input_values to fix argument issue +def patched_set_input_values(self, design_dictionary): + CleatAngleConnection.__bases__[0].set_input_values(self, design_dictionary) + +CleatAngleConnection.set_input_values = patched_set_input_values + +# Patch connectdb after import (mock DB access) +class DummyCursor: + def execute(self, query): + if "Bolt" in query: + return [(10,), (8,), (12,)] + return [] + def fetchall(self): + return [(10,), (8,), (12,)] + +class DummyConnection: + def execute(self, q): return DummyCursor() + def cursor(self): return DummyCursor() + def commit(self): pass + def close(self): pass + +if "osdag.Common" in sys.modules: + sys.modules["osdag.Common"].connectdb = lambda name: DummyConnection() + +# Load YAML file +def load_osi_file(filepath): + with open(filepath, 'r') as f: + return yaml.safe_load(f) + +# Run design logic +def run_design(filepath): + data = load_osi_file(filepath) + obj = CleatAngleConnection() + obj.set_input_values(data) + + connector = data.get("Connector", {}) # Safe access + obj.angle_list = connector.get("Angle_List", []) + obj.cleat_list = obj.angle_list.copy() + obj.cleat_material_grade = connector.get("Material", "") + obj.check_available_cleat_thk() + + return obj + +# Test case from Excel +test_cases = [ + ( + "CleatAngleTest1.osi", + { + "designation": "50x50x3", + "height": 115, + "shear_yielding_capacity": 90.54, + "block_shear_capacity": 101.36, + "moment_capacity": 4.51, + "bolt_diameter": 10, + "property_class": "5.6" + } + ), + ( + "CleatAngleTest2.osi", + { + "designation": "60x60x4", + "height": 130, + "shear_yielding_capacity": 136.46, + "block_shear_capacity": 124.08, + "moment_capacity": 7.68, + "bolt_diameter": 8, + "property_class": "6.8" + } + ), + ( + "CleatAngleTest3.osi", + { + "designation": "65x65x8", + "height": 150, + "shear_yielding_capacity": 314.92, + "block_shear_capacity": 353.61, + "moment_capacity": 20.45, + "bolt_diameter": 8, + "property_class": "12.9" + } + ), + ( + "CleatAngleTest4.osi", + { + "designation": "50x50x3", + "height": 150, + "shear_yielding_capacity": 118.09, + "block_shear_capacity": 125.77, + "moment_capacity": 7.67, + "bolt_diameter": 8, + "property_class": "4.8" + } + ) +] + +# Pytest test function +@pytest.mark.parametrize("filename, expected", test_cases) +def test_cleat_angle_output(filename, expected): + filepath = os.path.join(os.path.dirname(__file__), filename) + assert os.path.exists(filepath), f"Missing OSI file: {filepath}" + + obj = run_design(filepath) + + assert hasattr(obj, "cleat"), f"No cleat selected for {filename}" + assert obj.cleat.designation == expected["designation"] + assert obj.cleat.height == expected["height"] + assert round(obj.shear_yielding_capacity, 2) == expected["shear_yielding_capacity"] + assert round(obj.block_shear_capacity, 2) == expected["block_shear_capacity"] + assert round(obj.moment_capacity, 2) == expected["moment_capacity"] + assert obj.bolt.bolt_diameter_provided == expected["bolt_diameter"] + assert obj.bolt.bolt_PC_provided == expected["property_class"] diff --git a/tests/test_finplate2.py b/tests/test_finplate2.py new file mode 100644 index 000000000..0bcbb3760 --- /dev/null +++ b/tests/test_finplate2.py @@ -0,0 +1,116 @@ +import pytest +import yaml +from osdag.design_type.connection.fin_plate_connection import FinPlateConnection +import pandas as pd +import glob +import os + +# Mock or import these as needed for your environment +# from src.osdag.cad import generate_cad +# from src.osdag.report import generate_report + +if not (os.path.exists('FinPlateTest1.osi') and os.path.exists('ExpectedOutputs.xlsx')): + + pytest.skip('Required OSI or Excel file missing, skipping test.', allow_module_level=True) + +def get_expected_from_excel(excel_path, osi_filename): + df = pd.read_excel(excel_path) + # Find the row matching the OSI file name + row = df[df['OSI File Name'] == osi_filename].iloc[0] + # Map Excel columns to output fields (update as needed) + expected = { + 'Plate.Thickness': row['Gusset Plate Thickness Value'], + 'Plate.Height': row['Gusset Plate Min Height Value'], + 'Plate.Length': row['Gusset Plate Length Value'], + 'Weld.Size': row['Size of Weld Value'], + 'Weld.Strength': row['Weld Strength Value'], + 'Weld.Stress': row['Weld Strength Value'], # Adjust if different + # Add more mappings as needed + } + return expected + +def extract_results_from_output(output): + # Convert output list of tuples to a dict for easy comparison + return {k: v for (k, _, _, v, *_) in output if k} + +@pytest.mark.parametrize("osi_path", sorted(glob.glob("FinPlateTest*.osi"))) + +def test_fin_plate_connection_vs_excel(osi_path): + osi_filename = os.path.basename(osi_path) + excel_path = "ExpectedOutputs.xlsx" + + osi_data = yaml.safe_load(open(osi_path)) + conn = FinPlateConnection() + conn.set_input_values(osi_data) + output = conn.output_values(flag=True) + results = extract_results_from_output(output) + expected = get_expected_from_excel(excel_path, osi_filename) + for key, exp_val in expected.items(): + assert key in results, f"Missing result for {key}" + # Use tolerance for float comparison + if isinstance(exp_val, float): + assert abs(results[key] - exp_val) < 1e-2, f"Mismatch for {key}: {results[key]} != {exp_val}" + else: + assert results[key] == exp_val, f"Mismatch for {key}: {results[key]} != {exp_val}" + +def test_fin_plate_connection(): + # 1. Load OSI file + with open('FinPlateTest1.osi', 'r') as f: + + osi_data = yaml.safe_load(f) + + # 2. Create FinPlateConnection instance + conn = FinPlateConnection() + + # 3. Set input values (mapping is handled in set_input_values) + conn.set_input_values(osi_data) + + # 4. Run design calculation (simulate pressing 'Design') + # This is typically done in set_input_values, but you may need to call additional methods if required + # conn.member_capacity() # Already called in set_input_values + + # 5. Check calculation values (replace with real expected values from Excel) + # Example: assert conn.plate.thickness == 8 + # assert conn.bolt.bolt_diameter_provided == 8 + # assert conn.plate.height == 60.0 + # assert conn.plate.length == 40.0 + # assert conn.weld.size == 5 + # assert round(conn.weld.strength, 1) == 662.8 + # assert round(conn.weld.stress, 2) == 347.85 + + # 6. Check output fields are populated + output = conn.output_values(flag=True) + assert any(o[0] == 'Bolt.Diameter' and o[3] for o in output) + assert any(o[0] == 'Bolt.Grade_Provided' and o[3] for o in output) + assert any(o[0] == 'Bolt.Shear' and o[3] for o in output) + assert any(o[0] == 'Bolt.Bearing' and o[3] for o in output) + assert any(o[0] == 'Bolt.Capacity' and o[3] for o in output) + assert any(o[0] == 'Plate.Thickness' and o[3] for o in output) + assert any(o[0] == 'Plate.Height' and o[3] for o in output) + assert any(o[0] == 'Plate.Length' and o[3] for o in output) + assert any(o[0] == 'Weld.Size' and o[3] for o in output) + assert any(o[0] == 'Weld.Strength' and o[3] for o in output) + assert any(o[0] == 'Weld.Stress' and o[3] for o in output) + + # 7. Check CAD generation (mocked or real) + try: + if hasattr(conn, 'get_3d_components'): + conn.get_3d_components() + cad_success = True + except Exception as e: + cad_success = False + assert cad_success, 'CAD generation failed (OCC dependency or other error)' + + # 8. Check report generation (mocked or real) + try: + if hasattr(conn, 'save_design'): + conn.save_design(popup_summary=False) + report_success = True + except Exception as e: + report_success = False + assert report_success, 'Report generation failed (LaTeX or other error)' + + if not os.path.exists('osi_files/TensionBoltedTest1.osi'): + pytest.skip("Missing OSI file, skipping test.") + + # ... rest of the test ... \ No newline at end of file