1
// SPDX-License-Identifier: LGPL-2.1-or-later
3
#include <gtest/gtest.h>
7
#include <App/Application.h>
8
#include <App/Document.h>
9
#include <App/Expression.h>
10
#include <App/ObjectIdentifier.h>
11
#include <Mod/Sketcher/App/GeoEnum.h>
12
#include <Mod/Sketcher/App/SketchObject.h>
13
#include <src/App/InitApplication.h>
15
class SketchObjectTest: public ::testing::Test
18
static void SetUpTestSuite()
20
tests::initApplication();
25
_docName = App::GetApplication().getUniqueDocumentName("test");
26
auto _doc = App::GetApplication().newDocument(_docName.c_str(), "testUser");
27
// TODO: Do we add a body newName, or is just adding sketch sufficient for this test?
29
static_cast<Sketcher::SketchObject*>(_doc->addObject("Sketcher::SketchObject"));
32
void TearDown() override
34
App::GetApplication().closeDocument(_docName.c_str());
37
Sketcher::SketchObject* getObject()
43
// TODO: use shared_ptr or something else here?
44
Sketcher::SketchObject* _sketchobj;
46
std::vector<const char*> allowedTypes {"Vertex",
54
TEST_F(SketchObjectTest, createSketchObject) // NOLINT
63
TEST_F(SketchObjectTest, testGeoIdFromShapeTypeEdge)
66
// TODO: Do we need to separate existing vs non-existing?
67
// It would need to be implemented in code as well.
68
Data::IndexedName name("Edge", 1);
70
Sketcher::PointPos posId;
73
getObject()->geoIdFromShapeType(name, geoId, posId);
77
EXPECT_EQ(posId, Sketcher::PointPos::none);
80
TEST_F(SketchObjectTest, testGeoIdFromShapeTypeVertex)
83
// For operating on vertices, there is newName a check if the vertex exists.
84
Base::Vector3d p1(0.0, 0.0, 0.0), p2(1.0, 0.0, 0.0);
85
std::unique_ptr<Part::Geometry> geoline(new Part::GeomLineSegment());
86
static_cast<Part::GeomLineSegment*>(geoline.get())->setPoints(p1, p2);
87
getObject()->addGeometry(geoline.get());
88
// TODO: Do we need to separate existing vs non-existing?
89
// It would need to be implemented in code as well.
90
Data::IndexedName name("Vertex", 1);
92
Sketcher::PointPos posId;
95
getObject()->geoIdFromShapeType(name, geoId, posId);
99
EXPECT_EQ(posId, Sketcher::PointPos::start);
102
TEST_F(SketchObjectTest, testGeoIdFromShapeTypeExternalEdge)
105
// TODO: Do we need to separate existing vs non-existing?
106
// It would need to be implemented in code as well.
107
Data::IndexedName name("ExternalEdge", 1);
109
Sketcher::PointPos posId;
112
getObject()->geoIdFromShapeType(name, geoId, posId);
115
EXPECT_EQ(geoId, Sketcher::GeoEnum::RefExt);
116
EXPECT_EQ(posId, Sketcher::PointPos::none);
119
TEST_F(SketchObjectTest, testGeoIdFromShapeTypeHAxis)
122
Data::IndexedName name("H_Axis");
124
Sketcher::PointPos posId;
127
getObject()->geoIdFromShapeType(name, geoId, posId);
130
EXPECT_EQ(geoId, Sketcher::GeoEnum::HAxis);
131
EXPECT_EQ(posId, Sketcher::PointPos::none);
134
TEST_F(SketchObjectTest, testGeoIdFromShapeTypeVAxis)
137
Data::IndexedName name("V_Axis");
139
Sketcher::PointPos posId;
142
getObject()->geoIdFromShapeType(name, geoId, posId);
145
EXPECT_EQ(geoId, Sketcher::GeoEnum::VAxis);
146
EXPECT_EQ(posId, Sketcher::PointPos::none);
149
TEST_F(SketchObjectTest, testGeoIdFromShapeTypeRootPoint)
152
Data::IndexedName name("RootPoint");
154
Sketcher::PointPos posId;
157
getObject()->geoIdFromShapeType(name, geoId, posId);
160
EXPECT_EQ(geoId, Sketcher::GeoEnum::RtPnt);
161
EXPECT_EQ(posId, Sketcher::PointPos::start);
164
TEST_F(SketchObjectTest, testReverseAngleConstraintToSupplementaryExpressionNoUnits1)
166
std::string expr = Sketcher::SketchObject::reverseAngleConstraintExpression("180 - 60");
167
EXPECT_EQ(expr, std::string("60"));
170
TEST_F(SketchObjectTest, testReverseAngleConstraintToSupplementaryExpressionNoUnits2)
172
std::string expr = Sketcher::SketchObject::reverseAngleConstraintExpression("60");
173
EXPECT_EQ(expr, std::string("180 - (60)"));
176
TEST_F(SketchObjectTest, testReverseAngleConstraintToSupplementaryExpressionWithUnits1)
178
std::string expr = Sketcher::SketchObject::reverseAngleConstraintExpression("180 ° - 60 °");
179
EXPECT_EQ(expr, std::string("60 °"));
182
TEST_F(SketchObjectTest, testReverseAngleConstraintToSupplementaryExpressionWithUnits2)
184
std::string expr = Sketcher::SketchObject::reverseAngleConstraintExpression("60 °");
185
EXPECT_EQ(expr, std::string("180 ° - (60 °)"));
188
TEST_F(SketchObjectTest, testReverseAngleConstraintToSupplementaryExpressionWithUnits3)
190
std::string expr = Sketcher::SketchObject::reverseAngleConstraintExpression("60 deg");
191
EXPECT_EQ(expr, std::string("180 ° - (60 deg)"));
194
TEST_F(SketchObjectTest, testReverseAngleConstraintToSupplementaryExpressionWithUnits4)
196
std::string expr = Sketcher::SketchObject::reverseAngleConstraintExpression("1rad");
197
EXPECT_EQ(expr, std::string("180 ° - (1rad)"));
200
TEST_F(SketchObjectTest, testReverseAngleConstraintToSupplementaryExpressionApplyAndReverse1)
202
std::string expr = "180";
203
expr = Sketcher::SketchObject::reverseAngleConstraintExpression(expr);
204
expr = Sketcher::SketchObject::reverseAngleConstraintExpression(expr);
205
EXPECT_EQ(expr, std::string("(180)"));
208
TEST_F(SketchObjectTest, testReverseAngleConstraintToSupplementaryExpressionApplyAndReverse2)
210
std::string expr = "(30 + 15) * 2 / 3";
211
expr = Sketcher::SketchObject::reverseAngleConstraintExpression(expr);
212
expr = Sketcher::SketchObject::reverseAngleConstraintExpression(expr);
213
EXPECT_EQ(expr, std::string("((30 + 15) * 2 / 3)"));
216
TEST_F(SketchObjectTest, testReverseAngleConstraintToSupplementaryExpressionSimple)
219
auto constraint = new Sketcher::Constraint(); // Ownership will be transferred to the sketch
220
constraint->Type = Sketcher::ConstraintType::Angle;
221
auto id = getObject()->addConstraint(constraint);
223
App::ObjectIdentifier path(App::ObjectIdentifier::parse(getObject(), "Constraints[0]"));
224
std::shared_ptr<App::Expression> shared_expr(App::Expression::parse(getObject(), "0"));
225
getObject()->setExpression(path, shared_expr);
227
getObject()->setConstraintExpression(id, "180 - (60)");
230
getObject()->reverseAngleConstraintToSupplementary(constraint, id);
233
EXPECT_EQ(std::string("60"), getObject()->getConstraintExpression(id));
236
TEST_F(SketchObjectTest, testReverseAngleConstraintToSupplementaryExpressionApplyAndReverse)
239
auto constraint = new Sketcher::Constraint(); // Ownership will be transferred to the sketch
240
constraint->Type = Sketcher::ConstraintType::Angle;
241
auto id = getObject()->addConstraint(constraint);
243
App::ObjectIdentifier path(App::ObjectIdentifier::parse(getObject(), "Constraints[0]"));
244
std::shared_ptr<App::Expression> shared_expr(App::Expression::parse(getObject(), "0"));
245
getObject()->setExpression(path, shared_expr);
247
getObject()->setConstraintExpression(id, "32 °");
250
getObject()->reverseAngleConstraintToSupplementary(constraint, id);
251
getObject()->reverseAngleConstraintToSupplementary(constraint, id);
254
EXPECT_EQ(std::string("32 °"), getObject()->getConstraintExpression(id));
257
TEST_F(SketchObjectTest, testGetElementName)
260
Base::Vector3d p1(0.0, 0.0, 0.0), p2(1.0, 0.0, 0.0);
261
std::unique_ptr<Part::Geometry> geoline(new Part::GeomLineSegment());
262
static_cast<Part::GeomLineSegment*>(geoline.get())->setPoints(p1, p2);
263
auto id = getObject()->addGeometry(geoline.get());
265
getObject()->getGeometryId(id, tag); // We need to look up the tag that got assigned
266
std::ostringstream oss;
268
auto tagName = oss.str();
269
getObject()->recomputeFeature(); // or ->execute()
271
// unless it's Export, we are really just testing the superclass App::GeoFeature::getElementName
273
auto forward_normal_name =
274
getObject()->getElementName((tagName + ";SKT").c_str(),
275
App::GeoFeature::ElementNameType::Normal);
276
auto reverse_normal_name =
277
getObject()->getElementName("Vertex2", App::GeoFeature::ElementNameType::Normal);
278
auto reverse_export_name =
279
getObject()->getElementName("Vertex1", App::GeoFeature::ElementNameType::Export);
280
auto map = getObject()->Shape.getShape().getElementMap();
281
ASSERT_EQ(map.size(), 3);
282
EXPECT_STREQ(map[0].name.toString().c_str(), (tagName + ";SKT").c_str());
283
EXPECT_EQ(map[0].index.toString(), "Edge1");
284
EXPECT_STREQ(map[1].name.toString().c_str(), (tagName + "v1;SKT").c_str());
285
EXPECT_EQ(map[1].index.toString(), "Vertex1");
286
EXPECT_STREQ(map[2].name.toString().c_str(), (tagName + "v2;SKT").c_str());
287
EXPECT_EQ(map[2].index.toString(), "Vertex2");
289
EXPECT_STREQ(forward_normal_name.newName.c_str(), (";" + tagName + ";SKT.Edge1").c_str());
290
EXPECT_STREQ(forward_normal_name.oldName.c_str(), "Edge1");
291
EXPECT_STREQ(reverse_normal_name.newName.c_str(), (";" + tagName + "v2;SKT.Vertex2").c_str());
292
EXPECT_STREQ(reverse_normal_name.oldName.c_str(), "Vertex2");
293
EXPECT_STREQ(reverse_export_name.newName.c_str(), (";" + tagName + "v1;SKT.Vertex1").c_str());
294
EXPECT_STREQ(reverse_export_name.oldName.c_str(), "Vertex1");