286 lines
9.3 KiB
C++
286 lines
9.3 KiB
C++
// SPDX-License-Identifier: LGPL-2.1-or-later
|
|
|
|
#include "gtest/gtest.h"
|
|
|
|
#include <FCConfig.h>
|
|
|
|
#include <App/Application.h>
|
|
#include <App/Document.h>
|
|
#include <App/Expression.h>
|
|
#include <App/ObjectIdentifier.h>
|
|
#include <Mod/Sketcher/App/GeoEnum.h>
|
|
#include <Mod/Sketcher/App/SketchObject.h>
|
|
#include <src/App/InitApplication.h>
|
|
|
|
class SketchObjectTest: public ::testing::Test
|
|
{
|
|
protected:
|
|
static void SetUpTestSuite()
|
|
{
|
|
tests::initApplication();
|
|
}
|
|
|
|
void SetUp() override
|
|
{
|
|
_docName = App::GetApplication().getUniqueDocumentName("test");
|
|
auto _doc = App::GetApplication().newDocument(_docName.c_str(), "testUser");
|
|
// TODO: Do we add a body first, or is just adding sketch sufficient for this test?
|
|
_sketchobj =
|
|
static_cast<Sketcher::SketchObject*>(_doc->addObject("Sketcher::SketchObject"));
|
|
}
|
|
|
|
void TearDown() override
|
|
{
|
|
App::GetApplication().closeDocument(_docName.c_str());
|
|
}
|
|
|
|
Sketcher::SketchObject* getObject()
|
|
{
|
|
return _sketchobj;
|
|
}
|
|
|
|
private:
|
|
// TODO: use shared_ptr or something else here?
|
|
Sketcher::SketchObject* _sketchobj;
|
|
std::string _docName;
|
|
std::vector<const char*> allowedTypes {"Vertex",
|
|
"Edge",
|
|
"ExternalEdge",
|
|
"H_Axis",
|
|
"V_Axis",
|
|
"RootPoint"};
|
|
};
|
|
|
|
TEST_F(SketchObjectTest, createSketchObject) // NOLINT
|
|
{
|
|
// Arrange
|
|
|
|
// Act
|
|
|
|
// Assert
|
|
}
|
|
|
|
TEST_F(SketchObjectTest, testGeoIdFromShapeTypeEdge)
|
|
{
|
|
// Arrange
|
|
// TODO: Do we need to separate existing vs non-existing?
|
|
// It would need to be implemented in code as well.
|
|
Data::IndexedName name("Edge", 1);
|
|
int geoId;
|
|
Sketcher::PointPos posId;
|
|
|
|
// Act
|
|
getObject()->geoIdFromShapeType(name, geoId, posId);
|
|
|
|
// Assert
|
|
EXPECT_EQ(geoId, 0);
|
|
EXPECT_EQ(posId, Sketcher::PointPos::none);
|
|
}
|
|
|
|
TEST_F(SketchObjectTest, testGeoIdFromShapeTypeVertex)
|
|
{
|
|
// Arrange
|
|
// For operating on vertices, there is first a check if the vertex exists.
|
|
Base::Vector3d p1(0.0, 0.0, 0.0), p2(1.0, 0.0, 0.0);
|
|
std::unique_ptr<Part::Geometry> geoline(new Part::GeomLineSegment());
|
|
static_cast<Part::GeomLineSegment*>(geoline.get())->setPoints(p1, p2);
|
|
getObject()->addGeometry(geoline.get());
|
|
// TODO: Do we need to separate existing vs non-existing?
|
|
// It would need to be implemented in code as well.
|
|
Data::IndexedName name("Vertex", 1);
|
|
int geoId;
|
|
Sketcher::PointPos posId;
|
|
|
|
// Act
|
|
getObject()->geoIdFromShapeType(name, geoId, posId);
|
|
|
|
// Assert
|
|
EXPECT_EQ(geoId, 0);
|
|
EXPECT_EQ(posId, Sketcher::PointPos::start);
|
|
}
|
|
|
|
TEST_F(SketchObjectTest, testGeoIdFromShapeTypeExternalEdge)
|
|
{
|
|
// Arrange
|
|
// TODO: Do we need to separate existing vs non-existing?
|
|
// It would need to be implemented in code as well.
|
|
Data::IndexedName name("ExternalEdge", 1);
|
|
int geoId;
|
|
Sketcher::PointPos posId;
|
|
|
|
// Act
|
|
getObject()->geoIdFromShapeType(name, geoId, posId);
|
|
|
|
// Assert
|
|
EXPECT_EQ(geoId, Sketcher::GeoEnum::RefExt);
|
|
EXPECT_EQ(posId, Sketcher::PointPos::none);
|
|
}
|
|
|
|
TEST_F(SketchObjectTest, testGeoIdFromShapeTypeHAxis)
|
|
{
|
|
// Arrange
|
|
Data::IndexedName name("H_Axis");
|
|
int geoId;
|
|
Sketcher::PointPos posId;
|
|
|
|
// Act
|
|
getObject()->geoIdFromShapeType(name, geoId, posId);
|
|
|
|
// Assert
|
|
EXPECT_EQ(geoId, Sketcher::GeoEnum::HAxis);
|
|
EXPECT_EQ(posId, Sketcher::PointPos::none);
|
|
}
|
|
|
|
TEST_F(SketchObjectTest, testGeoIdFromShapeTypeVAxis)
|
|
{
|
|
// Arrange
|
|
Data::IndexedName name("V_Axis");
|
|
int geoId;
|
|
Sketcher::PointPos posId;
|
|
|
|
// Act
|
|
getObject()->geoIdFromShapeType(name, geoId, posId);
|
|
|
|
// Assert
|
|
EXPECT_EQ(geoId, Sketcher::GeoEnum::VAxis);
|
|
EXPECT_EQ(posId, Sketcher::PointPos::none);
|
|
}
|
|
|
|
TEST_F(SketchObjectTest, testGeoIdFromShapeTypeRootPoint)
|
|
{
|
|
// Arrange
|
|
Data::IndexedName name("RootPoint");
|
|
int geoId;
|
|
Sketcher::PointPos posId;
|
|
|
|
// Act
|
|
getObject()->geoIdFromShapeType(name, geoId, posId);
|
|
|
|
// Assert
|
|
EXPECT_EQ(geoId, Sketcher::GeoEnum::RtPnt);
|
|
EXPECT_EQ(posId, Sketcher::PointPos::start);
|
|
}
|
|
|
|
TEST_F(SketchObjectTest, testReverseAngleConstraintToSupplementaryExpressionNoUnits1)
|
|
{
|
|
std::string expr = Sketcher::SketchObject::reverseAngleConstraintExpression("180 - 60");
|
|
EXPECT_EQ(expr, std::string("60"));
|
|
}
|
|
|
|
TEST_F(SketchObjectTest, testReverseAngleConstraintToSupplementaryExpressionNoUnits2)
|
|
{
|
|
std::string expr = Sketcher::SketchObject::reverseAngleConstraintExpression("60");
|
|
EXPECT_EQ(expr, std::string("180 - (60)"));
|
|
}
|
|
|
|
TEST_F(SketchObjectTest, testReverseAngleConstraintToSupplementaryExpressionWithUnits1)
|
|
{
|
|
std::string expr = Sketcher::SketchObject::reverseAngleConstraintExpression("180 ° - 60 °");
|
|
EXPECT_EQ(expr, std::string("60 °"));
|
|
}
|
|
|
|
TEST_F(SketchObjectTest, testReverseAngleConstraintToSupplementaryExpressionWithUnits2)
|
|
{
|
|
std::string expr = Sketcher::SketchObject::reverseAngleConstraintExpression("60 °");
|
|
EXPECT_EQ(expr, std::string("180 ° - (60 °)"));
|
|
}
|
|
|
|
TEST_F(SketchObjectTest, testReverseAngleConstraintToSupplementaryExpressionWithUnits3)
|
|
{
|
|
std::string expr = Sketcher::SketchObject::reverseAngleConstraintExpression("60 deg");
|
|
EXPECT_EQ(expr, std::string("180 ° - (60 deg)"));
|
|
}
|
|
|
|
TEST_F(SketchObjectTest, testReverseAngleConstraintToSupplementaryExpressionWithUnits4)
|
|
{
|
|
std::string expr = Sketcher::SketchObject::reverseAngleConstraintExpression("1rad");
|
|
EXPECT_EQ(expr, std::string("180 ° - (1rad)"));
|
|
}
|
|
|
|
TEST_F(SketchObjectTest, testReverseAngleConstraintToSupplementaryExpressionApplyAndReverse1)
|
|
{
|
|
std::string expr = "180";
|
|
expr = Sketcher::SketchObject::reverseAngleConstraintExpression(expr);
|
|
expr = Sketcher::SketchObject::reverseAngleConstraintExpression(expr);
|
|
EXPECT_EQ(expr, std::string("(180)"));
|
|
}
|
|
|
|
TEST_F(SketchObjectTest, testReverseAngleConstraintToSupplementaryExpressionApplyAndReverse2)
|
|
{
|
|
std::string expr = "(30 + 15) * 2 / 3";
|
|
expr = Sketcher::SketchObject::reverseAngleConstraintExpression(expr);
|
|
expr = Sketcher::SketchObject::reverseAngleConstraintExpression(expr);
|
|
EXPECT_EQ(expr, std::string("((30 + 15) * 2 / 3)"));
|
|
}
|
|
|
|
TEST_F(SketchObjectTest, testReverseAngleConstraintToSupplementaryExpressionSimple)
|
|
{
|
|
// Arrange
|
|
auto constraint = new Sketcher::Constraint(); // Ownership will be transferred to the sketch
|
|
constraint->Type = Sketcher::ConstraintType::Angle;
|
|
auto id = getObject()->addConstraint(constraint);
|
|
|
|
App::ObjectIdentifier path(App::ObjectIdentifier::parse(getObject(), "Constraints[0]"));
|
|
std::shared_ptr<App::Expression> shared_expr(App::Expression::parse(getObject(), "0"));
|
|
getObject()->setExpression(path, shared_expr);
|
|
|
|
getObject()->setConstraintExpression(id, "180 - (60)");
|
|
|
|
// Act
|
|
getObject()->reverseAngleConstraintToSupplementary(constraint, id);
|
|
|
|
// Assert
|
|
EXPECT_EQ(std::string("60"), getObject()->getConstraintExpression(id));
|
|
}
|
|
|
|
TEST_F(SketchObjectTest, testReverseAngleConstraintToSupplementaryExpressionApplyAndReverse)
|
|
{
|
|
// Arrange
|
|
auto constraint = new Sketcher::Constraint(); // Ownership will be transferred to the sketch
|
|
constraint->Type = Sketcher::ConstraintType::Angle;
|
|
auto id = getObject()->addConstraint(constraint);
|
|
|
|
App::ObjectIdentifier path(App::ObjectIdentifier::parse(getObject(), "Constraints[0]"));
|
|
std::shared_ptr<App::Expression> shared_expr(App::Expression::parse(getObject(), "0"));
|
|
getObject()->setExpression(path, shared_expr);
|
|
|
|
getObject()->setConstraintExpression(id, "32 °");
|
|
|
|
// Act
|
|
getObject()->reverseAngleConstraintToSupplementary(constraint, id);
|
|
getObject()->reverseAngleConstraintToSupplementary(constraint, id);
|
|
|
|
// Assert
|
|
EXPECT_EQ(std::string("32 °"), getObject()->getConstraintExpression(id));
|
|
}
|
|
|
|
TEST_F(SketchObjectTest, testGetElementName)
|
|
{
|
|
// Arrange
|
|
Base::Vector3d p1(0.0, 0.0, 0.0), p2(1.0, 0.0, 0.0);
|
|
std::unique_ptr<Part::Geometry> geoline(new Part::GeomLineSegment());
|
|
static_cast<Part::GeomLineSegment*>(geoline.get())->setPoints(p1, p2);
|
|
getObject()->addGeometry(geoline.get());
|
|
getObject()->recomputeFeature(); // or ->execute()
|
|
// Act
|
|
// unless it's Export, we are really just testing the superclass App::GeoFeature::getElementName
|
|
// call.
|
|
auto forward_normal_name =
|
|
getObject()->getElementName("g39;SKT", App::GeoFeature::ElementNameType::Normal);
|
|
auto reverse_normal_name =
|
|
getObject()->getElementName("Vertex2", App::GeoFeature::ElementNameType::Normal);
|
|
auto reverse_export_name =
|
|
getObject()->getElementName("Vertex1", App::GeoFeature::ElementNameType::Export);
|
|
auto map = getObject()->Shape.getShape().getElementMap();
|
|
ASSERT_EQ(map.size(), 3);
|
|
EXPECT_STREQ(map[0].name.toString().c_str(), "g39;SKT");
|
|
EXPECT_EQ(map[0].index.toString(), "Edge1");
|
|
// Assert
|
|
EXPECT_STREQ(forward_normal_name.first.c_str(), ";g39;SKT.Edge1");
|
|
EXPECT_STREQ(forward_normal_name.second.c_str(), "Edge1");
|
|
EXPECT_STREQ(reverse_normal_name.first.c_str(), ";g39v2;SKT.Vertex2");
|
|
EXPECT_STREQ(reverse_normal_name.second.c_str(), "Vertex2");
|
|
EXPECT_STREQ(reverse_export_name.first.c_str(), ";g39v1;SKT.Vertex1");
|
|
EXPECT_STREQ(reverse_export_name.second.c_str(), "Vertex1");
|
|
}
|