Files
gramps/gramps/plugins/test/exports_test.py
2022-03-07 18:55:45 +00:00

275 lines
9.6 KiB
Python

#! /usr/bin/env python3
"""
Gramps - a GTK+/GNOME based genealogy program
Copyright (c) 2016 Gramps Development Team
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
"""
import unittest
import os
import difflib
from unittest.mock import patch
from time import localtime, strptime
import tempfile
from gramps.test.test_util import Gramps
from gramps.gen.const import DATA_DIR
from gramps.gen.datehandler import set_format
from gramps.gen.user import User
from gramps.gen.utils.config import config
TREE_NAME = "Test_exporttest"
TEST_DIR = os.path.abspath(os.path.join(DATA_DIR, "tests"))
def mock_localtime(*args):
"""
Mock up a dummy to replace the varying 'time string results'
"""
return strptime("25 Dec 1999", "%d %b %Y")
def call(*args):
""" Call Gramps to perform the action with out and err captured """
#print("call:", args)
gramps = Gramps(user=User())
out, err = gramps.run(*args)
#print("out:", out, "err:", err)
return out, err
def do_it(srcfile, tstfile, dfilter=None):
""" based on tstfile, prepare an result export and compare with
expected.
"""
tst_file = os.path.join(TEST_DIR, srcfile)
expect_file = os.path.join(TEST_DIR, tstfile)
with tempfile.TemporaryDirectory() as tmpdirname:
result_file = os.path.join(tmpdirname, tstfile)
err = call("-C", TREE_NAME, "-q",
"--import", tst_file,
"--export", result_file)[1]
if "Cleaning up." not in err:
return "Export failed, no 'Cleaning up.'"
msg = compare(expect_file, result_file, dfilter)
if not msg:
# we will leave the result_file in place if there was an error.
try:
os.remove(result_file)
except OSError:
pass
return
else:
return msg
def compare(expect_file, result_file, dfilter=None):
""" This uses the diff library to compare two files
"""
with open(expect_file, encoding='utf-8_sig', errors='surrogateescape')\
as exp_f, \
open(result_file, encoding='utf-8_sig', errors='surrogateescape')\
as res_f:
diff = difflib.unified_diff(exp_f.readlines(),
res_f.readlines(),
n=2, lineterm='\n')
msg = ""
fail = False
for line in diff:
if line == "--- \n" or line == "+++ \n":
continue
msg += line
if dfilter:
fail += dfilter(line)
else:
fail = True
return msg if fail else ""
def gedfilt(line):
""" A filter for Gedcom files.
This implements a filter that allows some differences to be ignored.
The differences are not functional, but are related to changes in Gramps
version, file date/time and filename.
"""
def get_prev_token(back):
if back > gedfilt.indx:
return None
return gedfilt.prev[gedfilt.indx - back][0]
#pylint: disable=unsubscriptable-object
if line.startswith('@@'):
gedfilt.prev = [None] * 8
gedfilt.indx = 0
return False
retval = True
diftyp = line[0]
line = line[1:].partition(' ')
level = int(line[0])
token, toss, line = line[2].partition(' ')
if diftyp == ' ':
# save the line for later if needed to figure out the data element
gedfilt.prev[gedfilt.indx] = token, level, line
gedfilt.indx = (gedfilt.indx + 1) % 8
retval = False
elif diftyp == '-':
# save the line for later if needed to figure out the data element
gedfilt.prev[gedfilt.indx] = token, level, line
gedfilt.indx = (gedfilt.indx + 1) % 8
if token == "VERS" and get_prev_token(2) == "SOUR":
# we must have a header with Gramps version
retval = False
elif token == "DATE" and get_prev_token(2) == "NAME":
# we must have a header with file date
retval = False
elif token == "TIME" and get_prev_token(2) == "DATE":
# probably have a header with file time
retval = False
elif token == "FILE" and line.endswith('.ged\n'):
# probably have a header with file name
retval = False
elif token == "FILE" and "tests" in line:
# probably have a media with file name
retval = False
elif token == "COPR" and "Copyright (c) " in line:
# probably have a copyright line with year
retval = False
else: # this is an addition
if token == "VERS" and get_prev_token(1) == "VERS":
# we must have a header with Gramps version
retval = False
elif token == "DATE" and (get_prev_token(2) == "NAME" or
get_prev_token(3) == "NAME"):
# we must have a header with file date
retval = False
elif token == "TIME" and (get_prev_token(2) == "DATE" or
get_prev_token(3) == "DATE"):
# probably have a header with file time
retval = False
elif token == "FILE" and line.endswith('.ged\n'):
# probably have a header with file name
retval = False
elif token == "FILE" and "tests" in line:
# probably have a media with file name
retval = False
elif token == "COPR" and "Copyright (c) " in line:
# probably have a copyright line with year
retval = False
return retval
def vcffilt(line):
""" A filter for VCard files.
This implements a filter that allows some differences to be ignored.
The differences are not functional, but are related to changes in Gramps
version.
"""
diftyp = line[0]
if diftyp == '@':
retval = False
elif diftyp == ' ':
retval = False
elif 'PRODID:' in line: # Gramps version is on these lines
retval = False
else:
retval = True
return retval
class ExportControl(unittest.TestCase):
""" These tests compare various exported files with expected files,
based on the matching '.gramps' test file as a source.
As more types of exports are tested, we will need to provide some
filters for the differences; some types of exports have Gramps versions,
export dates, file names etc. that don't count as differences.
"""
def setUp(self):
config.set('behavior.date-before-range', 50)
config.set('behavior.date-after-range', 50)
config.set('behavior.date-about-range', 10)
self.tearDown() # removes it if it existed
# out, err = self.call("-C", TREE_NAME,
# "--import", example)
def tearDown(self):
call("-y", "-q", "--remove", TREE_NAME)
def test_csv(self):
""" Run a csv export test """
set_format(0) # Use ISO date for test
config.set('database.backend', 'sqlite')
src_file = 'exp_sample_csv.gramps'
tst_file = 'exp_sample_csv.csv'
msg = do_it(src_file, tst_file)
if msg:
self.fail(tst_file + ': ' + msg)
def test_ged(self):
""" Run a Gedcom export test """
config.set('preferences.place-auto', True)
config.set('database.backend', 'sqlite')
src_file = 'exp_sample.gramps'
tst_file = 'exp_sample_ged.ged'
msg = do_it(src_file, tst_file, gedfilt)
if msg:
self.fail(tst_file + ': ' + msg)
def test_vcard(self):
""" Run a vcard export test """
config.set('preferences.place-auto', True)
config.set('database.backend', 'sqlite')
src_file = 'exp_sample.gramps'
tst_file = 'exp_sample.vcf'
msg = do_it(src_file, tst_file, vcffilt)
if msg:
self.fail(tst_file + ': ' + msg)
@patch('gramps.plugins.export.exportvcalendar.time.localtime', mock_localtime)
def test_vcs(self):
""" Run a Vcalandar export test """
config.set('preferences.place-auto', True)
config.set('database.backend', 'sqlite')
src_file = 'exp_sample.gramps'
tst_file = 'exp_sample.vcs'
msg = do_it(src_file, tst_file)
if msg:
self.fail(tst_file + ': ' + msg)
def test_gw(self):
""" Run a Geneweb export test """
config.set('preferences.place-auto', True)
config.set('database.backend', 'sqlite')
src_file = 'exp_sample.gramps'
tst_file = 'exp_sample.gw'
msg = do_it(src_file, tst_file)
if msg:
self.fail(tst_file + ': ' + msg)
def test_wft(self):
""" Run a Web Family Tree export test """
set_format(0) # Use ISO date for test
config.set('preferences.place-auto', True)
config.set('database.backend', 'sqlite')
src_file = 'exp_sample.gramps'
tst_file = 'exp_sample.wft'
msg = do_it(src_file, tst_file)
if msg:
self.fail(tst_file + ': ' + msg)
if __name__ == "__main__":
unittest.main()