Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 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
1 change: 1 addition & 0 deletions doc/changelog.d/2260.test.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Adding test coverage for nurbs, design, and geometry commands
17 changes: 17 additions & 0 deletions tests/_incompatible_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ backends:
- tests/integration/test_spaceclaim_tutorial_examples.py::test_combine_example
- tests/integration/test_spaceclaim_tutorial_examples.py::test_pull_example
- tests/integration/test_spaceclaim_tutorial_examples.py::test_intersect_example
- tests/integration/test_design.py::test_legacy_export_download
- tests/integration/test_design.py::test_updating_design_from_tracker
- tests/integration/test_design.py::test_failure_for_export
# Opening large files through streaming is only available from 25.2 onwards
- tests/integration/test_design.py::test_modeler_open_files
# Named selections elements are only consistent from 25.2 onwards
Expand All @@ -83,6 +86,8 @@ backends:
- tests/integration/test_design_import.py::test_design_import_solid_edge2025
- tests/integration/test_design_import.py::test_design_import_nx2412
- tests/integration/test_design_import.py::test_design_import_inventor2026
- tests/integration/test_design.py::test_legacy_export_download
- tests/integration/test_design.py::test_failure_for_export
# Bug fix included from 25.2 onwards
- tests/integration/test_issues.py::test_issue_1192_temp_body_on_empty_intersect
- tests/integration/test_issues.py::test_issue_2251_double_import_crash
Expand Down Expand Up @@ -169,6 +174,9 @@ backends:
- tests/integration/test_spaceclaim_tutorial_examples.py::test_combine_example
- tests/integration/test_spaceclaim_tutorial_examples.py::test_pull_example
- tests/integration/test_spaceclaim_tutorial_examples.py::test_intersect_example
- tests/integration/test_design.py::test_legacy_export_download
- tests/integration/test_design.py::test_updating_design_from_tracker
- tests/integration/test_design.py::test_failure_for_export
# Opening large files through streaming is only available from 25.2 onwards
- tests/integration/test_design.py::test_modeler_open_files
# Named selections elements are only consistent from 25.2 onwards
Expand Down Expand Up @@ -203,6 +211,8 @@ backends:
- tests/integration/test_design_import.py::test_design_import_solid_edge2025
- tests/integration/test_design_import.py::test_design_import_nx2412
- tests/integration/test_design_import.py::test_design_import_inventor2026
- tests/integration/test_design.py::test_legacy_export_download
- tests/integration/test_design.py::test_failure_for_export
# Insert file naming convention changed in 26.1
- tests/integration/test_design_import.py::test_design_insert
# Bug fix included from 25.2 onwards
Expand Down Expand Up @@ -230,6 +240,9 @@ backends:
- tests/integration/test_spaceclaim_tutorial_examples.py::test_combine_example
- tests/integration/test_spaceclaim_tutorial_examples.py::test_pull_example
- tests/integration/test_spaceclaim_tutorial_examples.py::test_intersect_example
- tests/integration/test_design.py::test_legacy_export_download
- tests/integration/test_design.py::test_updating_design_from_tracker
- tests/integration/test_design.py::test_failure_for_export
# Opening large files through streaming is only available from 25.2 onwards
- tests/integration/test_design.py::test_modeler_open_files
# Named selections elements are only consistent from 25.2 onwards
Expand Down Expand Up @@ -264,6 +277,8 @@ backends:
- tests/integration/test_design_import.py::test_design_import_jt
- tests/integration/test_design_import.py::test_design_import_solid_edge2025
- tests/integration/test_design_import.py::test_design_import_nx2412
- tests/integration/test_design.py::test_legacy_export_download
- tests/integration/test_design.py::test_failure_for_export
# Insert file naming convention changed in 26.1
- tests/integration/test_design_import.py::test_design_insert
# Importing named selections from design was not available prior to 26.1
Expand Down Expand Up @@ -313,6 +328,8 @@ backends:
- tests/integration/test_design_export.py::test_import_export_open_file_design[PARASOLID_TEXT-x_t-rci_std.x_t-2-1]
- tests/integration/test_design_export.py::test_import_export_open_file_design[SCDOCX-scdocx-reactorWNS.scdocx-1-3]
- tests/integration/test_design_import.py::test_design_insert_id_bug
- tests/integration/test_design.py::test_legacy_export_download
- tests/integration/test_design.py::test_failure_for_export
# Insert file naming convention changed in 26.1
- tests/integration/test_design_import.py::test_design_insert
# Importing named selections from design was not available prior to 26.1
Expand Down
Binary file added tests/integration/files/boxes_w_mat.scdocx
Binary file not shown.
113 changes: 113 additions & 0 deletions tests/integration/test_design.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
from ansys.geometry.core.connection import BackendType
import ansys.geometry.core.connection.defaults as pygeom_defaults
from ansys.geometry.core.designer import (
Component,
CurveType,
DesignFileFormat,
MidSurfaceOffsetType,
Expand Down Expand Up @@ -3880,3 +3881,115 @@ def test_write_body_facets_on_save(

missing = expected_files - namelist
assert not missing


def test_updating_design_from_tracker(modeler: Modeler):
# Adding coverage for handling the tracker response when updating the design
design = modeler.open_file(
Path(FILES_DIR, "boxes_w_mat.scdocx")
) # ,read_existing_design=True))
# Creating the tracker response that modifies, deletes and creates bodies
tracker_response = {
"modified_bodies": [
{"id": "body1", "name": "ModifiedBody1", "is_surface": True},
{"id": "7", "name": "Fake_Mat", "is_surface": False},
{"id": "10", "name": "Steel", "is_surface": False},
],
"deleted_bodies": [
{"id": "11:1", "name": "DeletedBody2"},
{"id": "7:515/7:518", "name": "DeletedBody2"},
{"id": "test", "name": "SubComponentBody"},
],
"created_bodies": [
{
"id": "body100",
"name": "ExistingBody",
"is_surface": False,
"parent_id": "Component1",
},
],
}
# Adding needed bodies and components that are modified
design.bodies.append(
MasterBody("body100", "ExistingBody", design._grpc_client, is_surface=False)
)
design.components[2].components.append(
Component("SubComponent", design.components[2], design._grpc_client, preexisting_id="sub1")
)
design.components[2].components[0].components.append(
Component(
"SubComponent2",
design.components[2].components[0],
design._grpc_client,
preexisting_id="sub2",
)
)
design.components[2].components[0].bodies.append(
MasterBody("test", "SubComponentBody", design._grpc_client, is_surface=True)
)
# Changing the ids of the bodies to match those in the tracker response
design.components[1].bodies[0]._id = "7"
design.bodies[0]._id = "10"
result = design._update_from_tracker(tracker_response)
assert result is None
# Then we create particular body_into statements to hit lines not hit when calling
# the _update_from_tracker method
body_info = {
"id": "body1",
"name": "UpdatedSubComponentBody",
"is_surface": False,
"parent_id": "sub1",
}
design._find_and_update_body(body_info, design.components[2])
top_component = Component("TopComponent", design, design._grpc_client, preexisting_id="top1")
design.components.append(top_component)
body_info = {
"id": "body1",
"name": "NewBody",
"is_surface": True,
"parent_id": "top1",
}
result = design._find_and_add_body(body_info, design.components)


def test_legacy_export_download(
modeler: Modeler, tmp_path_factory: pytest.TempPathFactory, use_grpc_client_old_backend: Modeler
):
# Test is meant to add test coverage for using an old backend to export and download
# Creating the directory and file to export
working_directory = tmp_path_factory.mktemp("test_import_export_reimport")
original_file = Path(FILES_DIR, "reactorWNS.scdocx")
reexported_file = Path(working_directory, "reexported.scdocx")
design = modeler.create_design("Assembly")
design.insert_file(original_file)
# The following lines export the file to scdocx and parasolid
design.download(reexported_file, format=DesignFileFormat.SCDOCX)
reexported_file = Path(working_directory, "reexported.x_t")
design.download(reexported_file, format=DesignFileFormat.PARASOLID_TEXT)
# This is testing out exporting out to a non-supported format
reexported_file = Path(working_directory, "reexported.stride")
with pytest.raises(
TypeError, match="memoryview: a bytes-like object is required, not 'NoneType'"
):
design.download(reexported_file, format=DesignFileFormat.STRIDE)


def test_failure_for_export(modeler: Modeler, tmp_path_factory: pytest.TempPathFactory):
# # Creating the directory and file to export
working_directory = tmp_path_factory.mktemp("test_import_export_reimport")
original_file = Path(FILES_DIR, "reactorWNS.scdocx")
reexported_file = Path(working_directory, "reexported.scdocx")
design = modeler.create_design("Assembly")
design.insert_file(original_file)
# Giving the download an incorrect file extension in the file path for the chosen format
reexported_file = Path(working_directory, "reexported.x_t")
with pytest.raises(
GeometryExitedError,
match="Geometry service connection terminated: The method or operation is not implemented.",
):
design.download(file_location=reexported_file, format=DesignFileFormat.STEP)
# Exporting to the invalid type to get an error
with pytest.raises(
TypeError, match="memoryview: a bytes-like object is required, not 'NoneType'"
):
design.download(file_location=reexported_file, format=DesignFileFormat.INVALID)
88 changes: 88 additions & 0 deletions tests/integration/test_geometry_commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
DraftSide,
ExtrudeType,
FillPatternType,
GeometryCommands,
OffsetMode,
)
from ansys.geometry.core.math import Plane, Point2D, Point3D, UnitVector3D
Expand Down Expand Up @@ -1407,6 +1408,93 @@ def test_thicken_surface_body(modeler: Modeler):
)


def test_failures_to_extrude(modeler: Modeler):
"""Add test that covers code for failing to extrude in different ways."""
# First need to create surface to extrude from
sketch = Sketch()
p1 = Point2D([0, 0])
p2 = Point2D([10, 0])
p3 = Point2D([10, 5])
p4 = Point2D([0, 5])
sketch.segment(p1, p2)
sketch.segment(p2, p3)
sketch.segment(p3, p4)
sketch.segment(p4, p1)
design = modeler.create_design("SimpleFaceDesign")
surface = design.create_surface("SimpleFace", sketch)
grpc_client = modeler.client
geometry_commands = GeometryCommands(grpc_client, _internal_use=True)

# Failing to extrude single face
geometry_commands.extrude_faces(
faces=surface.faces[0],
distance=10,
direction=UnitVector3D([1, 0, 0]),
extrude_type=ExtrudeType.ADD,
pull_symmetric=False,
)
# Then adding a check to ensure no new faces were made
assert len(design.bodies[0].faces) == 1
# For the rest of the failures, we need a 2nd surface so here is creating the circle
circle_sketch = Sketch()
circle_sketch.circle(Point2D([20, 20]), 5.0)
circle_surface = design.create_surface("CircleSurface", circle_sketch)
# The square surface needs to be rotate to make some of the extrustion not valid
surface.rotate(Point3D([0, 0, 0]), UnitVector3D([0, 1, 0]), np.pi / 2)
# Failing to extrude edge
geometry_commands.extrude_edges(
edges=circle_surface.edges[0],
distance=10,
from_face=surface.faces[0],
)
assert len(design.bodies[0].faces) == 1
assert len(design.bodies[1].faces) == 1
# Failing to extrude edge up to
geometry_commands.extrude_edges_up_to(
circle_surface.edges[0],
surface.faces[0],
Point3D([0, 0, 0]),
UnitVector3D([1, 0, 0]),
)
assert len(design.bodies[0].faces) == 1
assert len(design.bodies[1].faces) == 1
# Failing to revolve face
geometry_commands.revolve_faces(
selection=circle_surface.faces[0],
axis=Line([0, 0, 1], [0, 0, 1]),
angle=-np.pi * 3 / 2,
)
assert len(design.bodies[0].faces) == 1
assert len(design.bodies[1].faces) == 1
# Failing to revolve face up to
modeler.geometry_commands.revolve_faces_up_to(
circle_surface.faces[0],
surface.faces[0],
Line([0.5, 0.5, 0], [0, 0, 1]),
UnitVector3D([1, 0, 0]),
ExtrudeType.FORCE_ADD,
)
assert len(design.bodies[0].faces) == 1
assert len(design.bodies[1].faces) == 1
# Failing to revolve face by helix
modeler.geometry_commands.revolve_faces_by_helix(
circle_surface.faces[0],
Line([0.5, 0.5, 0], [0, 0, 1]),
UnitVector3D([1, 0, 0]),
5,
1,
np.pi / 4,
True,
True,
)
assert len(design.bodies[0].faces) == 1
# Only in 252 does the revolve not fail. This is reproducible in 252 SpaceClaim and latest
if modeler._grpc_client.backend_version == "25.2.0":
assert len(design.bodies[1].faces) == 4
else:
assert len(design.bodies[1].faces) == 1


def test_offset_faces(modeler: Modeler):
"""Test offsetting faces."""
design = modeler.create_design("offset_faces")
Expand Down
49 changes: 49 additions & 0 deletions tests/test_primitives.py
Original file line number Diff line number Diff line change
Expand Up @@ -1803,3 +1803,52 @@ def test_nurbs_surface_simple_evaluation():
assert isinstance(evaluation.vv_derivative, Vector3D)
assert isinstance(evaluation.normal, UnitVector3D)
assert isinstance(evaluation.surface, NURBSSurface)


def test_nurbs_surface_not_implemented():
"""Code coverage for methods not implemented for NURBS surfaces"""
# Creating the NURBS surface and parameters
matrix = Matrix44([[1, 0, 0, 5], [0, 1, 0, 3], [0, 0, 0.8, 2], [0, 0, 0, 1]])
param = ParamUV(0.5, 0.5)
point = Point3D([1.0, 1.0, 1.0])
degree_u = 2
degree_v = 2
knots_u = [0, 0, 0, 1, 1, 1]
knots_v = [0, 0, 0, 1, 1, 1]
control_points = [
Point3D([0, 0, 0]),
Point3D([0, 1, 1]),
Point3D([0, 2, 0]),
Point3D([1, 0, 1]),
Point3D([1, 1, 2]),
Point3D([1, 2, 1]),
Point3D([2, 0, 0]),
Point3D([2, 1, 1]),
Point3D([2, 2, 0]),
]
nurbs_surface = NURBSSurface.from_control_points(
degree_u=degree_u,
degree_v=degree_v,
knots_u=knots_u,
knots_v=knots_v,
control_points=control_points,
)
# Code for the not implemented methods under NURBSSurface
with pytest.raises(NotImplementedError):
nurbs_surface.transformed_copy(matrix)
with pytest.raises(NotImplementedError):
nurbs_surface.contains_param(param)
with pytest.raises(NotImplementedError):
nurbs_surface.contains_point(point)
with pytest.raises(NotImplementedError):
nurbs_surface.project_point(point)
# Code for the not implemented methods under NURBSSurfaceEvaluation
evaluation = NURBSSurfaceEvaluation(nurbs_surface, param)
with pytest.raises(NotImplementedError):
evaluation.min_curvature()
with pytest.raises(NotImplementedError):
evaluation.min_curvature_direction()
with pytest.raises(NotImplementedError):
evaluation.max_curvature()
with pytest.raises(NotImplementedError):
evaluation.max_curvature_direction()
Loading