Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -315,6 +330,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 @@ -3911,6 +3912,118 @@ def test_write_body_facets_on_save(
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)


def test_combine_merge(modeler: Modeler):
design = modeler.create_design("combine_merge")
box1 = design.extrude_sketch("box1", Sketch().box(Point2D([0, 0]), 1, 1), 1)
Expand Down
94 changes: 94 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,99 @@ 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
results = geometry_commands.extrude_faces(
faces=surface.faces[0],
distance=10,
direction=UnitVector3D([1, 0, 0]),
extrude_type=ExtrudeType.ADD,
pull_symmetric=False,
)
assert results == []
# 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
results = geometry_commands.extrude_edges(
edges=circle_surface.edges[0],
distance=10,
from_face=surface.faces[0],
)
assert results == []
assert len(design.bodies[0].faces) == 1
assert len(design.bodies[1].faces) == 1
# Failing to extrude edge up to
results = geometry_commands.extrude_edges_up_to(
circle_surface.edges[0],
surface.faces[0],
Point3D([0, 0, 0]),
UnitVector3D([1, 0, 0]),
)
assert results == []
assert len(design.bodies[0].faces) == 1
assert len(design.bodies[1].faces) == 1
# Failing to revolve face
results = geometry_commands.revolve_faces(
selection=circle_surface.faces[0],
axis=Line([0, 0, 1], [0, 0, 1]),
angle=-np.pi * 3 / 2,
)
assert results == []
assert len(design.bodies[0].faces) == 1
assert len(design.bodies[1].faces) == 1
# Failing to revolve face up to
results = 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 results == []
assert len(design.bodies[0].faces) == 1
assert len(design.bodies[1].faces) == 1
# Failing to revolve face by helix
# Commenting out test due to it causing a segfault inside the container
# 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