7212: convert invalid dates to text on import

unit tests
This commit is contained in:
Vassilii Khachaturov 2013-11-17 20:09:13 +02:00
parent b770de1a10
commit 86dc84470e

View File

@ -0,0 +1,195 @@
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2011 Michiel D. Nauta
# Copyright (C) 2013 Vassilii Khachaturov
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
"""
Test XML import.
"""
from __future__ import print_function, unicode_literals
import unittest
import time
import os
import subprocess
import libxml2
import libxslt
from gramps.plugins.lib.libgrampsxml import GRAMPS_XML_VERSION
from gramps.gen.const import ROOT_DIR, USER_PLUGINS
from gramps.version import VERSION
HAS_EXPORTRAW = os.path.isdir(os.path.join(USER_PLUGINS, 'ExportRaw'))
class CopiedDoc(object):
"""Context manager that creates a deep copy of an libxml-xml document."""
def __init__(self, xmldoc):
self.xmldoc = xmldoc
self.copy = libxml2.readDoc(str(self.xmldoc), '', None,
libxml2.XML_PARSE_NONET)
def __enter__(self):
return self.copy
def __exit__(self, exc_type, exc_val, exc_tb):
self.copy.freeDoc()
return False
class XpathContext(object):
"""Context manager that creates a libxml2 xpath context that allows
evaluation of xpath expressions."""
def __init__(self, xmldoc):
self.xmldoc = xmldoc
self.ctxt = self.xmldoc.xpathNewContext()
self.ctxt.xpathRegisterNs('g', 'http://gramps-project.org/xml/%s/' %
GRAMPS_XML_VERSION)
def __enter__(self):
return self.ctxt
def __exit__(self, exc_type, exc_val, exc_tb):
self.ctxt.xpathFreeContext()
return False
@unittest.skipUnless(HAS_EXPORTRAW,
'These tests need the 3rd-party plugin "ExportRaw".')
class BaseImportTest(unittest.TestCase):
def base_setup(self):
"""Set up code needed by all tests."""
date = time.localtime(time.time())
libxml2.keepBlanksDefault(0)
styledoc = libxml2.parseFile(os.path.join(ROOT_DIR,
"../data/gramps_canonicalize.xsl"))
self.style = libxslt.parseStylesheetDoc(styledoc)
self.basedoc = None
self.base_str = """<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE database PUBLIC "-//GRAMPS//DTD GRAMPS XML %s//EN"
"http://gramps-project.org/xml/%s/grampsxml.dtd">
<database xmlns="http://gramps-project.org/xml/%s/">
<header>
<created date="%04d-%02d-%02d" version="%s"/>
<researcher>\n </researcher>
</header>
""" % (GRAMPS_XML_VERSION, GRAMPS_XML_VERSION, GRAMPS_XML_VERSION,
date[0], date[1], date[2], VERSION)
def tearDown(self):
self.style.freeStylesheet()
self.basedoc.freeDoc()
def canonicalize(self, doctxt):
"""
Return a canonicalized string representation
:param doctxt: the text to bring in canonical form.
:type doctxt: either a string or an Xml document.
:returns: The text but in canonical form.
:rtype: string
"""
result = ''
if isinstance(doctxt, basestring):
doc = libxml2.readDoc(doctxt, '', None, libxml2.XML_PARSE_NONET)
elif isinstance(doctxt, libxml2.xmlDoc):
doc = doctxt
else:
raise TypeError
param = {}
canonical_doc = self.style.applyStylesheet(doc, param)
result = self.style.saveResultToString(canonical_doc)
canonical_doc.freeDoc()
if isinstance(doctxt, basestring):
doc.freeDoc()
return result
def do_test(self, input_doc, expect_doc,
test_error_str='', debug=False):
"""Do the import and "assert" the result."""
process = subprocess.Popen('python Gramps.py -d .Date -d .ImportXML '
'--config=preferences.eprefix:DEFAULT '
'-i - -f gramps '
'-e - -f gramps',
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE, shell=True)
result_str, err_str = process.communicate(str(input_doc))
if err_str:
if test_error_str:
self.assertIn(test_error_str, err_str)
return
else:
if "Traceback (most recent call last):" in err_str:
raise Exception(err_str)
if debug:
print('err_str:', err_str)
print('input :', self.canonicalize(input_doc))
print('result:', self.canonicalize(result_str))
print('expect:', self.canonicalize(expect_doc))
self.assertEqual(self.canonicalize(result_str),
self.canonicalize(expect_doc))
class DateTest(BaseImportTest):
def setUp(self):
self.base_setup()
self.events_str = """
<events>
<event handle="_e0000" id="E0000">
<type>Birth</type>
{datexml}
<description>Event 0</description>
</event>
</events>
</database>"""
self.datexml_src = self.datexml_trg = None
def tearDown(self):
self.basedoc = libxml2.readDoc(
self.base_str + self.events_str.format(datexml=self.datexml_src),
'', None, libxml2.XML_PARSE_NONET)
expect = libxml2.readDoc(
self.base_str + self.events_str.format(datexml=self.datexml_trg),
'', None, libxml2.XML_PARSE_NONET)
try:
self.do_test(self.basedoc, expect)
except:
raise
finally:
expect.freeDoc()
def test_correct_dateval_passed_verbatim(self):
self.datexml_trg = self.datexml_src = \
'<dateval val="1787-05-20"/>'
def test_correct_daterange_passed_verbatim(self):
self.datexml_trg = self.datexml_src = \
'<daterange start="1746" stop="1755"/>'
def test_dateval_long_Feb_converted_to_datestr(self):
self.datexml_src = '<dateval val="1787-02-30"/>'
self.datexml_trg = '<datestr val="&lt;dateval val=&quot;1787-02-30&quot;/&gt;"/>'
def test_datespan_long_Feb_converted_to_datestr(self):
self.datexml_src = '<datespan start="1746-02-30" stop="2000"/>'
self.datexml_trg = '<datestr val="&lt;datespan start=&quot;1746-02-30&quot; stop=&quot;2000&quot;/&gt;"/>'
if __name__ == "__main__":
import sys
if not HAS_EXPORTRAW:
print('This program needs the third party "ExportRaw" plugin.', file=sys.stderr)
sys.exit(1)
unittest.main()