diff --git a/src/App/Metadata.cpp b/src/App/Metadata.cpp index df89913f08..e3f1a22dc6 100644 --- a/src/App/Metadata.cpp +++ b/src/App/Metadata.cpp @@ -24,6 +24,7 @@ #ifndef _PreComp_ # include +# include #endif #include "Metadata.h" @@ -55,6 +56,34 @@ using namespace App; namespace fs = boost::filesystem; XERCES_CPP_NAMESPACE_USE +namespace MetadataInternal { + class XMLErrorHandler : public HandlerBase { + void warning(const SAXParseException& toCatch) + { + // Don't deal with warnings at all + } + + void error(const SAXParseException& toCatch) + { + std::stringstream message; + message << "Error at file \"" << StrX(toCatch.getSystemId()) + << "\", line " << toCatch.getLineNumber() + << ", column " << toCatch.getColumnNumber() + << "\n Message: " << StrX(toCatch.getMessage()) << std::endl; + throw Base::XMLBaseException(message.str()); + } + + void fatalError(const SAXParseException& toCatch) + { + std::stringstream message; + message << "Fatal error at file \"" << StrX(toCatch.getSystemId()) + << "\", line " << toCatch.getLineNumber() + << ", column " << toCatch.getColumnNumber() + << "\n Message: " << StrX(toCatch.getMessage()) << std::endl; + throw Base::XMLBaseException(message.str()); + } + }; +} Metadata::Metadata(const fs::path& metadataFile) { @@ -65,7 +94,7 @@ Metadata::Metadata(const fs::path& metadataFile) _parser->setValidationScheme(XercesDOMParser::Val_Never); _parser->setDoNamespaces(true); - auto errHandler = std::make_unique(); + auto errHandler = std::make_unique(); _parser->setErrorHandler(errHandler.get()); _parser->parse(metadataFile.string().c_str()); diff --git a/src/App/MetadataPyImp.cpp b/src/App/MetadataPyImp.cpp index 68a9190a77..71eb86fa9c 100644 --- a/src/App/MetadataPyImp.cpp +++ b/src/App/MetadataPyImp.cpp @@ -29,6 +29,7 @@ #include "MetadataPy.cpp" using namespace Base; +XERCES_CPP_NAMESPACE_USE // Returns a string which represents the object e.g. when printed in Python std::string MetadataPy::representation(void) const @@ -70,6 +71,24 @@ int MetadataPy::PyInit(PyObject* args, PyObject* /*kwd*/) setTwinPointer(md); return 0; } + catch (const Base::XMLBaseException& e) { + PyErr_SetString(Base::BaseExceptionFreeCADError, e.what()); + return -1; + } + catch (const XMLException& toCatch) { + char* message = XMLString::transcode(toCatch.getMessage()); + std::string what = message; + XMLString::release(&message); + PyErr_SetString(Base::BaseExceptionFreeCADError, what.c_str()); + return -1; + } + catch (const DOMException& toCatch) { + char* message = XMLString::transcode(toCatch.getMessage()); + std::string what = message; + XMLString::release(&message); + PyErr_SetString(Base::BaseExceptionFreeCADError, what.c_str()); + return -1; + } catch (...) { PyErr_SetString(Base::BaseExceptionFreeCADError, "Failed to create Metadata object"); return -1; diff --git a/src/Mod/Test/CMakeLists.txt b/src/Mod/Test/CMakeLists.txt index c2f8105c47..25942dbf8a 100644 --- a/src/Mod/Test/CMakeLists.txt +++ b/src/Mod/Test/CMakeLists.txt @@ -18,6 +18,9 @@ SET(Test_SRCS SET(TestData_SRCS TestData/basic_metadata.xml + TestData/bad_root_node.xml + TestData/bad_xml.xml + TestData/bad_version.xml ) SOURCE_GROUP("" FILES ${Test_SRCS} ${TestData_SRCS}) diff --git a/src/Mod/Test/Metadata.py b/src/Mod/Test/Metadata.py index 0fef9236e8..2e3d22dd35 100644 --- a/src/Mod/Test/Metadata.py +++ b/src/Mod/Test/Metadata.py @@ -31,6 +31,40 @@ class TestMetadata(unittest.TestCase): def setUp(self): self.test_dir = os.path.join(FreeCAD.getHomePath(), "Mod", "Test", "TestData") + def test_xml_constructor(self): + try: + filename = os.path.join(self.test_dir, "basic_metadata.xml") + md = FreeCAD.Metadata(filename) + except Exception: + self.fail("Metadata construction from XML file failed") + + try: + filename = os.path.join(self.test_dir, "bad_root_node.xml") + md = FreeCAD.Metadata(filename) + except Exception as e: + FreeCAD.Console.PrintMessage(str(e) + "\n") + pass + else: + self.fail("Metadata construction from XML file with bad root node did not raise an exception") + + try: + filename = os.path.join(self.test_dir, "bad_xml.xml") + md = FreeCAD.Metadata(filename) + except Exception as e: + FreeCAD.Console.PrintMessage(str(e) + "\n") + pass + else: + self.fail("Metadata construction from invalid XML file did not raise an exception") + + try: + filename = os.path.join(self.test_dir, "bad_version.xml") + md = FreeCAD.Metadata(filename) + except Exception as e: + FreeCAD.Console.PrintMessage(str(e) + "\n") + pass + else: + self.fail("Metadata construction from XML file with bad version did not raise an exception") + def test_toplevel_tags(self): filename = os.path.join(self.test_dir, "basic_metadata.xml") md = FreeCAD.Metadata(filename) diff --git a/src/Mod/Test/TestData/bad_root_node.xml b/src/Mod/Test/TestData/bad_root_node.xml new file mode 100644 index 0000000000..b882beb291 --- /dev/null +++ b/src/Mod/Test/TestData/bad_root_node.xml @@ -0,0 +1,6 @@ + + + Bad root node + The root node is not called "package". + 1.0.0 + \ No newline at end of file diff --git a/src/Mod/Test/TestData/bad_version.xml b/src/Mod/Test/TestData/bad_version.xml new file mode 100644 index 0000000000..268e51ad1d --- /dev/null +++ b/src/Mod/Test/TestData/bad_version.xml @@ -0,0 +1,6 @@ + + + Bad format + There is no such thing as format version 2 (yet). + 1.0.0 + \ No newline at end of file diff --git a/src/Mod/Test/TestData/bad_xml.xml b/src/Mod/Test/TestData/bad_xml.xml new file mode 100644 index 0000000000..dcd8648962 --- /dev/null +++ b/src/Mod/Test/TestData/bad_xml.xml @@ -0,0 +1,5 @@ + + + Bad XML + The name tag is not closed properly. + \ No newline at end of file