From b47029998ecb7f9c2f1dd7ca32f6f062945f1229 Mon Sep 17 00:00:00 2001 From: wmayer Date: Tue, 29 Mar 2022 14:54:03 +0200 Subject: [PATCH] Base: fix handling of path separators in parameter group names --- src/Base/Parameter.cpp | 31 ++++++------- src/Base/ParameterPy.cpp | 38 +++++++++++----- src/Mod/Test/BaseTests.py | 91 ++++++++++++++++++++++----------------- 3 files changed, 96 insertions(+), 64 deletions(-) diff --git a/src/Base/Parameter.cpp b/src/Base/Parameter.cpp index c5e9eb9221..f2158a8ba8 100644 --- a/src/Base/Parameter.cpp +++ b/src/Base/Parameter.cpp @@ -312,33 +312,34 @@ void ParameterGrp::insert(const char* FileName) Base::Reference ParameterGrp::GetGroup(const char* Name) { std::string cName = Name; + if (cName.empty()) + throw Base::ValueError("Empty group name"); + + // Remove all leading slashes + std::string::size_type beg = cName.find_first_not_of('/'); + if (beg > 0) { + cName.erase(0, beg); + } + + // Remove all trailing slashes + std::string::size_type end = cName.find_last_not_of('/'); + if (end+1 < cName.size()) { + cName.erase(end+1); + } std::string::size_type pos = cName.find('/'); // is there a path separator ? if (pos == std::string::npos) { - return _GetGroup(Name); - } - else if (pos == cName.size()) { - // ending slash! cut it away - cName.erase(pos); return _GetGroup(cName.c_str()); } - else if (pos == 0) { - // a leading slash is not handled (root unknown) - //throw FCException("ParameterGrp::GetGroup() leading slash not allowed"); - // remove leading slash - cName.erase(0,1); - // subsequent call - return GetGroup(cName.c_str()); - } else { // path, split the first path std::string cTemp; // getting the first part - cTemp.assign(cName,0,pos); + cTemp.assign(cName, 0, pos); // removing the first part from the original - cName.erase(0,pos+1); + cName.erase(0, pos+1); //subsequent call return _GetGroup(cTemp.c_str())->GetGroup(cName.c_str()); } diff --git a/src/Base/ParameterPy.cpp b/src/Base/ParameterPy.cpp index e69b11d103..2664ce5cb5 100644 --- a/src/Base/ParameterPy.cpp +++ b/src/Base/ParameterPy.cpp @@ -98,6 +98,7 @@ public: Py::Object repr(); Py::Object getGroup(const Py::Tuple&); + Py::Object getGroupName(const Py::Tuple&); Py::Object getGroups(const Py::Tuple&); Py::Object remGroup(const Py::Tuple&); Py::Object hasGroup(const Py::Tuple&); @@ -159,6 +160,7 @@ void ParameterGrpPy::init_type() behaviors().readyType(); add_varargs_method("GetGroup",&ParameterGrpPy::getGroup,"GetGroup(str)"); + add_varargs_method("GetGroupName",&ParameterGrpPy::getGroupName,"GetGroupName()"); add_varargs_method("GetGroups",&ParameterGrpPy::getGroups,"GetGroups()"); add_varargs_method("RemGroup",&ParameterGrpPy::remGroup,"RemGroup(str)"); add_varargs_method("HasGroup",&ParameterGrpPy::hasGroup,"HasGroup(str)"); @@ -260,17 +262,33 @@ Py::Object ParameterGrpPy::getGroup(const Py::Tuple& args) if (!PyArg_ParseTuple(args.ptr(), "s", &pstr)) throw Py::Exception(); + try { + // get the Handle of the wanted group + Base::Reference handle = _cParamGrp->GetGroup(pstr); + if (handle.isValid()) { + // create a python wrapper class + ParameterGrpPy *pcParamGrp = new ParameterGrpPy(handle); + // increment the ref count + return Py::asObject(pcParamGrp); + } + else { + throw Py::RuntimeError("GetGroup failed"); + } + } + catch (const Base::Exception& e) { + e.setPyException(); + throw Py::Exception(); + } +} + +Py::Object ParameterGrpPy::getGroupName(const Py::Tuple& args) +{ + if (!PyArg_ParseTuple(args.ptr(), "")) + throw Py::Exception(); + // get the Handle of the wanted group - Base::Reference handle = _cParamGrp->GetGroup(pstr); - if (handle.isValid()) { - // create a python wrapper class - ParameterGrpPy *pcParamGrp = new ParameterGrpPy(handle); - // increment the ref count - return Py::asObject(pcParamGrp); - } - else { - throw Py::RuntimeError("GetGroup failed"); - } + std::string name = _cParamGrp->GetGroupName(); + return Py::String(name); } Py::Object ParameterGrpPy::getGroups(const Py::Tuple& args) diff --git a/src/Mod/Test/BaseTests.py b/src/Mod/Test/BaseTests.py index c7c0a0b460..b9f0a49d0a 100644 --- a/src/Mod/Test/BaseTests.py +++ b/src/Mod/Test/BaseTests.py @@ -115,6 +115,15 @@ class ParameterTestCase(unittest.TestCase): self.assertTrue(self.TestPar.HasGroup("44"),"A referenced group must not be deleted") Temp = 0 + def testGroupNames(self): + with self.assertRaises(ValueError): + # no empty groups allowed + self.TestPar.GetGroup("") + grp1 = self.TestPar.GetGroup("////Sub1/////Sub2/////") + grp2 = self.TestPar.GetGroup("Sub1/Sub2") + self.assertEqual(grp1.GetGroupName(), "Sub2") + self.assertEqual(grp2.GetGroupName(), "Sub2") + # check on special conditions def testInt(self): #FreeCAD.Console.PrintLog("Base::ParameterTestCase::testInt\n") @@ -156,6 +165,49 @@ class ParameterTestCase(unittest.TestCase): self.TestPar.RemString("44") self.assertEqual(self.TestPar.GetString("44","hallo"), "hallo","Deletion error at String") + def testNesting(self): + # Parameter testing + #FreeCAD.Console.PrintLog("Base::ParameterTestCase::testNesting\n") + for i in range(50): + self.TestPar.SetFloat(str(i),4711.4711) + self.TestPar.SetInt(str(i),4711) + self.TestPar.SetBool(str(i),1) + Temp = self.TestPar.GetGroup(str(i)) + for l in range(50): + Temp.SetFloat(str(l),4711.4711) + Temp.SetInt(str(l),4711) + Temp.SetBool(str(l),1) + Temp = 0 + + def testExportImport(self): + # Parameter testing + #FreeCAD.Console.PrintLog("Base::ParameterTestCase::testNesting\n") + self.TestPar.SetFloat("ExTest",4711.4711) + self.TestPar.SetInt("ExTest",4711) + self.TestPar.SetString("ExTest","4711") + self.TestPar.SetBool("ExTest",1) + Temp = self.TestPar.GetGroup("ExTest") + Temp.SetFloat("ExTest",4711.4711) + Temp.SetInt("ExTest",4711) + Temp.SetString("ExTest","4711") + Temp.SetBool("ExTest",1) + TempPath = tempfile.gettempdir() + os.sep + "ExportTest.FCExport" + + self.TestPar.Export(TempPath) + Temp = self.TestPar.GetGroup("ImportTest") + Temp.Import(TempPath) + self.assertEqual(Temp.GetFloat("ExTest"), 4711.4711,"ExportImport error") + Temp = 0 + + def tearDown(self): + #remove all + TestPar = FreeCAD.ParamGet("System parameter:Test") + TestPar.Clear() + +class AlgebraTestCase(unittest.TestCase): + def setUp(self): + pass + def testAngle(self): v1 = FreeCAD.Vector(0,0,0.000001) v2 = FreeCAD.Vector(0,0.000001,0) @@ -313,45 +365,6 @@ class ParameterTestCase(unittest.TestCase): self.assertFalse(b.intersected(FreeCAD.BoundBox(4,4,4,6,6,6)).isValid(),"Bbox should not intersect with Bbox outside") self.assertEqual(b.intersected(FreeCAD.BoundBox(-2,-2,-2,2,2,2)).Center, b.Center,"Bbox is not a full subset") - def testNesting(self): - # Parameter testing - #FreeCAD.Console.PrintLog("Base::ParameterTestCase::testNesting\n") - for i in range(50): - self.TestPar.SetFloat(str(i),4711.4711) - self.TestPar.SetInt(str(i),4711) - self.TestPar.SetBool(str(i),1) - Temp = self.TestPar.GetGroup(str(i)) - for l in range(50): - Temp.SetFloat(str(l),4711.4711) - Temp.SetInt(str(l),4711) - Temp.SetBool(str(l),1) - Temp = 0 - - def testExportImport(self): - # Parameter testing - #FreeCAD.Console.PrintLog("Base::ParameterTestCase::testNesting\n") - self.TestPar.SetFloat("ExTest",4711.4711) - self.TestPar.SetInt("ExTest",4711) - self.TestPar.SetString("ExTest","4711") - self.TestPar.SetBool("ExTest",1) - Temp = self.TestPar.GetGroup("ExTest") - Temp.SetFloat("ExTest",4711.4711) - Temp.SetInt("ExTest",4711) - Temp.SetString("ExTest","4711") - Temp.SetBool("ExTest",1) - TempPath = tempfile.gettempdir() + os.sep + "ExportTest.FCExport" - - self.TestPar.Export(TempPath) - Temp = self.TestPar.GetGroup("ImportTest") - Temp.Import(TempPath) - self.assertEqual(Temp.GetFloat("ExTest"), 4711.4711,"ExportImport error") - Temp = 0 - - def tearDown(self): - #remove all - TestPar = FreeCAD.ParamGet("System parameter:Test") - TestPar.Clear() - class MatrixTestCase(unittest.TestCase): def setUp(self): self.mat = FreeCAD.Matrix()