diff --git a/.coveragerc b/.coveragerc new file mode 100644 index 000000000..ff6415d7a --- /dev/null +++ b/.coveragerc @@ -0,0 +1,7 @@ +[report] +exclude_lines = + # Have to re-enable the standard pragma + pragma: no cover + + # Don't complain if tests don't hit defensive assertion code: + raise NotImplementedError diff --git a/tests/xmlparse.py b/tests/xmlparse.py index ab30cb51e..311d01de4 100644 --- a/tests/xmlparse.py +++ b/tests/xmlparse.py @@ -1448,13 +1448,43 @@ class XMLParseTest(unittest.TestCase): except ValueError: pass - def testXMLRootValidate(self): + def testXMLCoverage(self): try: + # Ensure we validate root element virtinst.DeviceDisk(self.conn, parsexml="") raise AssertionError("Expected parse failure") except RuntimeError as e: self.assertTrue("'foo'" in str(e)) + try: + # Ensure we validate root element + virtinst.DeviceDisk(self.conn, parsexml=-1) + raise AssertionError("Expected parse failure") + except Exception as e: + self.assertTrue("xmlParseDoc" in str(e)) + + try: + from virtinst import xmlutil + xmlutil.raise_programming_error(True, "for coverage") + raise AssertionError("We shouldn't get here") + except RuntimeError: + pass + + try: + virtinst.DeviceDisk.validate_generic_name("objtype", None) + raise AssertionError("We shouldn't get here") + except ValueError: + pass + try: + virtinst.DeviceDisk.validate_generic_name("objtype", "foo bar") + raise AssertionError("We shouldn't get here") + except ValueError: + pass + + # Test property __repr__ for code coverage + assert str(virtinst.DeviceDisk.address) + assert str(virtinst.DeviceDisk.driver_cache) + def testReplaceChildParse(self): buildfile = "tests/xmlparse-xml/replace-child-build.xml" parsefile = "tests/xmlparse-xml/replace-child-parse.xml" diff --git a/virtinst/xmlapi.py b/virtinst/xmlapi.py index 3522e09fe..0d2fce6fd 100644 --- a/virtinst/xmlapi.py +++ b/virtinst/xmlapi.py @@ -224,8 +224,7 @@ class _XMLBase(object): xpathobj = _XPath(fullxpath) parentxpath = "." parentnode = self._find(parentxpath) - if parentnode is None: - raise RuntimeError("programming error: " + xmlutil.raise_programming_error(not parentnode, "Did not find XML root node for xpath=%s" % fullxpath) for xpathseg in xpathobj.segments[1:]: @@ -287,15 +286,15 @@ class _Libxml2API(_XMLBase): self._ctx.xpathRegisterNs(key, val) def __del__(self): + if not hasattr(self, "_doc"): + # Incase we error when parsing the doc + return self._doc.freeDoc() self._doc = None self._ctx.xpathFreeContext() self._ctx = None def _sanitize_xml(self, xml): - # Strip starting line - if xml.startswith(" 1: - raise RuntimeError("Conflict property converter options.") + self._is_yesno, self._is_onoff]]) + xmlutil.raise_programming_error(conflicts > 1, + "Conflict property converter options.") self._is_tracked = False if _trackprops: @@ -405,8 +406,6 @@ class _XMLState(object): self._parent_xpath = xpath or "" def _join_xpath(self, x1, x2): - if x1.endswith("/"): - x1 = x1[:-1] if x2.startswith("."): x2 = x2[1:] return x1 + x2 @@ -478,11 +477,7 @@ class XMLBuilder(object): self.conn = conn if self._XML_SANITIZE: - if hasattr(parsexml, 'decode'): - parsexml = parsexml.decode("ascii", "ignore").encode("ascii") - else: - parsexml = parsexml.encode("ascii", "ignore").decode("ascii") - + parsexml = parsexml.encode("ascii", "ignore").decode("ascii") parsexml = "".join([c for c in parsexml if c in string.printable]) self._propstore = collections.OrderedDict() @@ -502,15 +497,16 @@ class XMLBuilder(object): xmlprops = self._all_xml_props() childprops = self._all_child_props() for key in self._XML_PROP_ORDER: - if key not in xmlprops and key not in childprops: - raise RuntimeError("programming error: key '%s' must be " - "xml prop or child prop" % key) + xmlutil.raise_programming_error( + key not in xmlprops and key not in childprops, + "key '%s' must be xml prop or child prop" % key) childclasses = [] for childprop in childprops.values(): - if childprop.child_class in childclasses: - raise RuntimeError("programming error: can't register " - "duplicate child_classs=%s" % childprop.child_class) + xmlutil.raise_programming_error( + childprop.child_class in childclasses, + "can't register duplicate child_class=%s" % + childprop.child_class) childclasses.append(childprop.child_class) setattr(self.__class__, cachekey, True) @@ -636,14 +632,16 @@ class XMLBuilder(object): def _find_child_prop(self, child_class): xmlprops = self._all_child_props() + ret = None for xmlprop in list(xmlprops.values()): if xmlprop.is_single: continue if child_class is xmlprop.child_class: - return xmlprop - raise RuntimeError("programming error: " - "Didn't find child property for child_class=%s" % - child_class) + ret = xmlprop + break + xmlutil.raise_programming_error(not ret, + "Didn't find child property for child_class=%s" % child_class) + return ret def _set_xpaths(self, parent_xpath, relative_object_xpath=-1): """ diff --git a/virtinst/xmlutil.py b/virtinst/xmlutil.py index eb5ed3b93..3fbbb69d2 100644 --- a/virtinst/xmlutil.py +++ b/virtinst/xmlutil.py @@ -57,3 +57,11 @@ def set_prop_path(obj, prop_path, value): parent = getattr(parent, piece) return setattr(parent, pieces[-1], value) + + +def raise_programming_error(cond, msg): + """ + Small helper to raise a consistent error message for coding issues + """ + if cond: + raise RuntimeError("programming error: %s" % msg)