1# encoding: utf-8 2# 3# Gramps - a GTK+/GNOME based genealogy program 4# 5# Copyright (C) 2000-2006 Martin Hawlisch, Donald N. Allingham 6# Copyright (C) 2008 Brian G. Matherly 7# Copyright (C) 2010 Jakim Friant 8# Copyright (C) 2011 Tim G L Lyons 9# 10# This program is free software; you can redistribute it and/or modify 11# it under the terms of the GNU General Public License as published by 12# the Free Software Foundation; either version 2 of the License, or 13# (at your option) any later version. 14# 15# This program is distributed in the hope that it will be useful, 16# but WITHOUT ANY WARRANTY; without even the implied warranty of 17# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18# GNU General Public License for more details. 19# 20# You should have received a copy of the GNU General Public License 21# along with this program; if not, write to the Free Software 22# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 23# 24 25"""Tools/Debug/Generate Testcases for Persons and Families""" 26# pylint: disable=too-many-statements,too-many-locals,too-many-branches 27# pylint: disable=wrong-import-position,too-many-public-methods,no-self-use 28# pylint: disable=too-many-arguments 29# ------------------------------------------------------------------------ 30# 31# standard python modules 32# 33# ------------------------------------------------------------------------ 34import sys 35import os 36import random 37from gramps.gen.const import GRAMPS_LOCALE as glocale 38_ = glocale.translation.gettext 39 40# ------------------------------------------------------------------------ 41# 42# GNOME libraries 43# 44# ------------------------------------------------------------------------ 45from gi.repository import Gtk 46 47# ------------------------------------------------------------------------ 48# 49# Gramps modules 50# 51# ------------------------------------------------------------------------ 52from gramps.gen.lib import ( 53 Address, Attribute, AttributeType, ChildRef, 54 ChildRefType, Citation, Date, Event, EventRef, EventRoleType, 55 EventType, Family, FamilyRelType, GrampsType, LdsOrd, Location, 56 Media, MediaRef, Name, NameOriginType, NameType, Note, 57 NoteType, Person, PersonRef, Place, PlaceType, PlaceRef, PlaceName, 58 RepoRef, Repository, RepositoryType, Source, SourceMediaType, 59 SrcAttribute, SrcAttributeType, Surname, Tag, Url, UrlType) 60from gramps.gen.lib.addressbase import AddressBase 61from gramps.gen.lib.attrbase import AttributeBase 62from gramps.gen.lib.primaryobj import BasicPrimaryObject 63from gramps.gen.lib.citationbase import CitationBase 64from gramps.gen.lib.date import Today 65from gramps.gen.lib.datebase import DateBase 66from gramps.gen.lib.ldsordbase import LdsOrdBase 67from gramps.gen.lib.locationbase import LocationBase 68from gramps.gen.lib.mediabase import MediaBase 69from gramps.gen.lib.notebase import NoteBase 70from gramps.gen.lib.placebase import PlaceBase 71from gramps.gen.lib.privacybase import PrivacyBase 72from gramps.gen.lib.tagbase import TagBase 73from gramps.gen.lib.urlbase import UrlBase 74from gramps.gen.lib import StyledText, StyledTextTag, StyledTextTagType 75from gramps.gen.db import DbTxn 76from gramps.gen.mime import get_type 77from gramps.gui.plug import tool 78from gramps.gen.utils.string import conf_strings 79from gramps.gen.utils.lds import TEMPLES 80from gramps.gen.db.dbconst import * 81from gramps.gen.const import ICON, LOGO, SPLASH 82from gramps.gui.display import display_help 83from gramps.gen.const import URL_MANUAL_PAGE 84 85# ------------------------------------------------------------------------ 86# 87# Constants 88# 89# ------------------------------------------------------------------------ 90WIKI_HELP_PAGE = '%s_-_Tools' % URL_MANUAL_PAGE 91WIKI_HELP_SEC = _('Generate_Testcases_for_Persons_and_Families') 92 93# the following allows test code to access a private copy of the random 94# number generator. The access is typically used for seeding the generator 95# to make it repeatable across runs. The private copy is unaffected by other 96# uses of the global random() functions. 97try: 98 from gramps.gen.const import myrand 99except (NameError, ImportError): 100 myrand = random.Random() 101except: 102 print("Unexpected error:", sys.exc_info()[0]) 103_random = myrand.random 104_choice = myrand.choice 105_randint = myrand.randint 106 107 108LDS_ORD_BAPT_STATUS = ( 109 LdsOrd.STATUS_NONE, 110 LdsOrd.STATUS_CHILD, LdsOrd.STATUS_CLEARED, 111 LdsOrd.STATUS_COMPLETED, LdsOrd.STATUS_INFANT, 112 LdsOrd.STATUS_PRE_1970, LdsOrd.STATUS_QUALIFIED, 113 LdsOrd.STATUS_STILLBORN, LdsOrd.STATUS_SUBMITTED, 114 LdsOrd.STATUS_UNCLEARED) 115 116LDS_ORD_CHILD_SEALING_STATUS = ( 117 LdsOrd.STATUS_NONE, 118 LdsOrd.STATUS_BIC, LdsOrd.STATUS_CLEARED, 119 LdsOrd.STATUS_COMPLETED, LdsOrd.STATUS_DNS, 120 LdsOrd.STATUS_PRE_1970, LdsOrd.STATUS_QUALIFIED, 121 LdsOrd.STATUS_STILLBORN, LdsOrd.STATUS_SUBMITTED, 122 LdsOrd.STATUS_UNCLEARED) 123 124LDS_ENDOWMENT_DATE_STATUS = ( 125 LdsOrd.STATUS_NONE, 126 LdsOrd.STATUS_CHILD, LdsOrd.STATUS_CLEARED, 127 LdsOrd.STATUS_COMPLETED, LdsOrd.STATUS_INFANT, 128 LdsOrd.STATUS_PRE_1970, LdsOrd.STATUS_QUALIFIED, 129 LdsOrd.STATUS_STILLBORN, LdsOrd.STATUS_SUBMITTED, 130 LdsOrd.STATUS_UNCLEARED) 131 132LDS_SPOUSE_SEALING_DATE_STATUS = ( 133 LdsOrd.STATUS_NONE, 134 LdsOrd.STATUS_CANCELED, LdsOrd.STATUS_CLEARED, 135 LdsOrd.STATUS_COMPLETED, LdsOrd.STATUS_DNS, 136 LdsOrd.STATUS_DNS_CAN, LdsOrd.STATUS_PRE_1970, 137 LdsOrd.STATUS_QUALIFIED, LdsOrd.STATUS_SUBMITTED, 138 LdsOrd.STATUS_UNCLEARED) 139 140LDS_INDIVIDUAL_ORD = [(LdsOrd.BAPTISM, LDS_ORD_BAPT_STATUS), 141 (LdsOrd.CONFIRMATION, LDS_ORD_BAPT_STATUS), 142 (LdsOrd.ENDOWMENT, LDS_ENDOWMENT_DATE_STATUS), 143 (LdsOrd.SEAL_TO_PARENTS, LDS_ORD_CHILD_SEALING_STATUS)] 144 145LDS_SPOUSE_SEALING = [(LdsOrd.SEAL_TO_SPOUSE, 146 LDS_SPOUSE_SEALING_DATE_STATUS)] 147 148 149# ------------------------------------------------------------------------ 150 151class TestcaseGenerator(tool.BatchTool): 152 ''' 153 This tool generates various test cases for problems that have occured. 154 The issues it generates can be corrected via the 'Check and Repair' tool. 155 ''' 156 NUMERIC = 0 157 FIRSTNAME = 1 158 FIRSTNAME_FEMALE = 2 159 FIRSTNAME_MALE = 3 160 LASTNAME = 4 161 NOTE = 5 162 SHORT = 6 163 LONG = 7 164 TAG = 8 165 STYLED_TEXT = 9 166 167# GEDCON definition: 168# 169# FAMILY_EVENT_STRUCTURE:= 170# [ 171# n [ ANUL | CENS | DIV | DIVF ] [Y|<NULL>] {1:1} 172# +1 <<EVENT_DETAIL>> {0:1} p.29 173# | 174# n [ ENGA | MARR | MARB | MARC ] [Y|<NULL>] {1:1} 175# +1 <<EVENT_DETAIL>> {0:1} p.29 176# | 177# n [ MARL | MARS ] [Y|<NULL>] {1:1} 178# +1 <<EVENT_DETAIL>> {0:1} p.29 179# | 180# n EVEN {1:1} 181# +1 <<EVENT_DETAIL>> {0:1} p.29 182# ] 183 184 FAMILY_EVENTS = set([ 185 EventType.ANNULMENT, 186 EventType.CENSUS, 187 EventType.DIVORCE, 188 EventType.DIV_FILING, 189 EventType.ENGAGEMENT, 190 EventType.MARRIAGE, 191 EventType.MARR_BANNS, 192 EventType.MARR_CONTR, 193 EventType.MARR_LIC, 194 EventType.MARR_SETTL, 195 EventType.CUSTOM]) 196 197 def __init__(self, dbstate, user, options_class, name, callback=None): 198 uistate = user.uistate 199 if uistate: 200 parent_window = uistate.window 201 else: 202 parent_window = None 203 self.progress = user.progress 204 205# ******** This ensures that a chunk of code below never executes!!!! 206 self.person = None 207 208 if dbstate.db.readonly: 209 return 210 211 tool.BatchTool.__init__(self, dbstate, user, options_class, name, 212 parent=parent_window) 213 214 if self.fail: 215 return 216 217 self.options_dict = self.options.handler.options_dict 218 self.person_count = 0 219 self.max_person_count = self.options_dict['person_count'] 220 self.persons_todo = [] 221 self.parents_todo = [] 222 self.person_dates = {} 223 self.generated_repos = [] 224 self.generated_sources = [] 225 self.generated_citations = [] 226 self.generated_media = [] 227 self.generated_places = [] 228 self.generated_events = [] 229 self.generated_families = [] 230 self.generated_notes = [] 231 self.generated_tags = [] 232 self.text_serial_number = 1 233 self.trans = None 234 235 self.parent_places = {} 236 for type_num in range(1, 8): 237 self.parent_places[type_num] = [] 238 239 # If an active persons exists the generated tree is connected to that 240 # person 241 if self.person: 242 # try to get birth and death year 243 try: 244 birth_h = self.person.get_birth_handle() 245 birth_e = self.db.get_event_from_handle(birth_h) 246 dat_o = birth_e.get_date_object() 247 birth = dat_o.get_year() 248 except AttributeError: 249 birth = None 250 try: 251 death_h = self.person.get_death_handle() 252 death_e = self.db.get_event_from_handle(death_h) 253 dat_o = death_e.get_date_object() 254 death = dat_o.get_year() 255 except AttributeError: 256 death = None 257 if not birth and not death: 258 birth = _randint(1700, 1900) 259 if birth and not death: 260 death = birth + _randint(20, 90) 261 if death and not birth: 262 birth = death - _randint(20, 90) 263 self.person_dates[self.person.get_handle()] = (birth, death) 264 265 self.persons_todo.append(self.person.get_handle()) 266 self.parents_todo.append(self.person.get_handle()) 267 268 if uistate: 269 self.init_gui(uistate) 270 else: 271 self.run_tool(cli=True) 272 273 def init_gui(self, uistate): 274 title = "%s - Gramps" % _("Generate testcases") 275 self.top = Gtk.Dialog(title, parent=uistate.window) 276 self.window = uistate.window 277 self.top.set_default_size(400, 150) 278 self.top.vbox.set_spacing(5) 279 label = Gtk.Label(label='<span size="larger" weight="bold">%s</span>' 280 % _("Generate testcases")) 281 label.set_use_markup(True) 282 self.top.vbox.pack_start(label, 0, 0, 5) 283 284 self.check_lowlevel = Gtk.CheckButton(label=_( 285 "Generate low level database " 286 "errors\nCorrection needs database reload")) 287 self.check_lowlevel.set_active(self.options_dict['lowlevel']) 288 self.top.vbox.pack_start(self.check_lowlevel, 0, 0, 5) 289 290 self.check_bugs = Gtk.CheckButton(label=_("Generate database errors")) 291 self.check_bugs.set_active(self.options_dict['bugs']) 292 self.top.vbox.pack_start(self.check_bugs, 0, 0, 5) 293 294 self.check_persons = Gtk.CheckButton(label=_("Generate dummy data")) 295 self.check_persons.set_active(self.options_dict['persons']) 296 self.check_persons.connect('clicked', self.on_dummy_data_clicked) 297 self.top.vbox.pack_start(self.check_persons, 0, 0, 5) 298 299 self.check_longnames = Gtk.CheckButton(label=_("Generate long names")) 300 self.check_longnames.set_active(self.options_dict['long_names']) 301 self.top.vbox.pack_start(self.check_longnames, 0, 0, 5) 302 303 self.check_specialchars = Gtk.CheckButton(label=_( 304 "Add special characters")) 305 self.check_specialchars.set_active(self.options_dict['specialchars']) 306 self.top.vbox.pack_start(self.check_specialchars, 0, 0, 5) 307 308 self.check_serial = Gtk.CheckButton(label=_("Add serial number")) 309 self.check_serial.set_active(self.options_dict['add_serial']) 310 self.top.vbox.pack_start(self.check_serial, 0, 0, 5) 311 312 self.check_linebreak = Gtk.CheckButton(label=_("Add line break")) 313 self.check_linebreak.set_active(self.options_dict['add_linebreak']) 314 self.top.vbox.pack_start(self.check_linebreak, 0, 0, 5) 315 316 self.label = Gtk.Label(label=_( 317 "Number of people to generate\n" 318 "(Number is approximate because families are generated)")) 319 self.label.set_halign(Gtk.Align.START) 320 self.top.vbox.pack_start(self.label, 0, 0, 5) 321 322 self.entry_count = Gtk.Entry() 323 self.entry_count.set_text(str(self.max_person_count)) 324 self.on_dummy_data_clicked(self.check_persons) 325 self.top.vbox.pack_start(self.entry_count, 0, 0, 5) 326 327 self.top.add_button(_('_Cancel'), Gtk.ResponseType.CANCEL) 328 self.top.add_button(_('_OK'), Gtk.ResponseType.OK) 329 self.top.add_button(_('_Help'), Gtk.ResponseType.HELP) 330 self.top.show_all() 331 332 while True: 333 response = self.top.run() 334 if response == Gtk.ResponseType.HELP: 335 display_help(webpage=WIKI_HELP_PAGE, 336 section=WIKI_HELP_SEC) 337 else: 338 break 339 self.options_dict['lowlevel'] = int( 340 self.check_lowlevel.get_active()) 341 self.options_dict['bugs'] = int( 342 self.check_bugs.get_active()) 343 self.options_dict['persons'] = int( 344 self.check_persons.get_active()) 345 self.options_dict['long_names'] = int( 346 self.check_longnames.get_active()) 347 self.options_dict['specialchars'] = int( 348 self.check_specialchars.get_active()) 349 self.options_dict['add_serial'] = int( 350 self.check_serial.get_active()) 351 self.options_dict['add_linebreak'] = int( 352 self.check_linebreak.get_active()) 353 self.options_dict['person_count'] = int( 354 self.entry_count.get_text()) 355 self.top.destroy() 356 357 if response == Gtk.ResponseType.OK: 358 self.run_tool(cli=False) 359 # Save options 360 self.options.handler.save_options() 361 362 def on_dummy_data_clicked(self, obj): 363 self.label.set_sensitive(obj.get_active()) 364 self.entry_count.set_sensitive(obj.get_active()) 365 366 def run_tool(self, cli=False): 367 self.cli = cli 368 if not cli: 369 while Gtk.events_pending(): 370 Gtk.main_iteration() 371 else: 372 self.window = None 373 374 self.transaction_count = 0 375 376 if self.options_dict['lowlevel']: 377 with self.progress(_('Generating testcases'), 378 _('Generating low level database errors'), 379 1) as step: 380 self.test_low_level() 381 step() 382 383 if self.options_dict['bugs'] or self.options_dict['persons']: 384 self.generate_tags() 385 386 if self.options_dict['bugs']: 387 with self.progress(_('Generating testcases'), 388 _('Generating database errors'), 389 20) as step: 390 self.generate_data_errors(step) 391 392 if self.options_dict['persons']: 393 with self.progress(_('Generating testcases'), 394 _('Generating families'), 395 self.max_person_count) \ 396 as self.progress_step: 397 self.person_count = 0 398 399 while True: 400 if not self.persons_todo: 401 pers_h = self.generate_person(0) 402 self.persons_todo.append(pers_h) 403 self.parents_todo.append(pers_h) 404 person_h = self.persons_todo.pop(0) 405 self.generate_family(person_h) 406 if _randint(0, 3) == 0: 407 self.generate_family(person_h) 408 if _randint(0, 7) == 0: 409 self.generate_family(person_h) 410 if self.person_count > self.max_person_count: 411 break 412 for child_h in self.parents_todo: 413 self.generate_parents(child_h) 414 if self.person_count > self.max_person_count: 415 break 416 417 if not cli: 418 self.top.destroy() 419 420 def generate_data_errors(self, step): 421 """This generates errors in the database to test src/plugins/tool/Check 422 The module names correspond to the checking methods in 423 src/plugins/tool/Check.CheckIntegrity """ 424 # The progress meter is normally stepped every time a person is 425 # generated by generate_person. However in this case, generate_person 426 # is called by some of the constituent functions, but we only want the 427 # meter to be stepped every time a test function has been completed. 428 self.progress_step = lambda: None 429 430 self.test_fix_encoding() 431 step() 432 self.test_fix_ctrlchars_in_notes() 433 step() 434 self.test_fix_alt_place_names() 435 step() 436 self.test_fix_duplicated_grampsid() 437 step() 438 self.test_clean_deleted_name_format() 439 step() 440 self.test_cleanup_empty_objects() 441 step() 442 self.test_chk_for_broke_family_link() 443 step() 444 self.test_check_parent_relationships() 445 step() 446 self.test_cleanup_empty_families() 447 step() 448 self.test_cleanup_duplicate_spouses() 449 step() 450 self.test_check_events() 451 step() 452 self.test_check_person_references() 453 step() 454 self.test_check_family_references() 455 step() 456 self.test_check_place_references() 457 step() 458 self.test_check_source_references() 459 step() 460 self.test_check_citation_references() 461 step() 462 self.test_check_media_references() 463 step() 464 self.test_check_repo_references() 465 step() 466 self.test_check_note_references() 467 step() 468 469 def test_low_level(self): 470 with DbTxn(_("Testcase generator step %d") % self.transaction_count, 471 self.db) as self.trans: 472 self.transaction_count += 1 473 474 obj = Note() 475 obj.set("dup 1" + self.rand_text(self.NOTE)) 476 obj.set_format(_choice((Note.FLOWED, Note.FORMATTED))) 477 obj.set_type(self.rand_type(NoteType())) 478 self.db.add_note(obj, self.trans) 479 print("object %s, handle %s, Gramps_Id %s" % (obj, obj.handle, 480 obj.gramps_id)) 481 482 handle = obj.get_handle() 483 484 src = Source() 485 src.set_title("dup 2" + self.rand_text(self.SHORT)) 486 if _randint(0, 1) == 1: 487 src.set_author(self.rand_text(self.SHORT)) 488 if _randint(0, 1) == 1: 489 src.set_publication_info(self.rand_text(self.LONG)) 490 if _randint(0, 1) == 1: 491 src.set_abbreviation(self.rand_text(self.SHORT)) 492 while _randint(0, 1) == 1: 493 sattr = SrcAttribute() 494 sattr.set_type(self.rand_text(self.SHORT)) 495 sattr.set_value(self.rand_text(self.SHORT)) 496 src.add_attribute(sattr) 497 src.set_handle(handle) 498 self.db.add_source(src, self.trans) 499 print("object %s, handle %s, Gramps_Id %s" % (src, src.handle, 500 src.gramps_id)) 501 502 def test_fix_encoding(self): 503 """ Creates a media object with character encoding errors. This tests 504 Check.fix_encoding() and also cleanup_missing_photos 505 """ 506 with DbTxn(_("Testcase generator step %d") % self.transaction_count, 507 self.db) as self.trans: 508 self.transaction_count += 1 509 510 med = Media() 511 self.fill_object(med) 512 med.set_description("leave this media object invalid description" 513 "\x9f") 514 med.set_path("/tmp/click_on_keep_reference.png\x9f") 515 med.set_mime_type("image/png\x9f") 516 self.db.add_media(med, self.trans) 517 518 med = Media() 519 self.fill_object(med) 520 med.set_description("reselect this media object invalid " 521 "description\x9f") 522 med.set_path("/tmp/click_on_select_file.png\x9f") 523 med.set_mime_type("image/png\x9f") 524 self.db.add_media(med, self.trans) 525 526 # setup media attached to Source and Citation to be removed 527 528 med = Media() 529 self.fill_object(med) 530 med.set_description('remove this media object') 531 med.set_path("/tmp/click_on_remove_object.png") 532 med.set_mime_type("image/png") 533 self.db.add_media(med, self.trans) 534 535 src = Source() 536 src.set_title('media should be removed from this source') 537 ref = MediaRef() 538 ref.set_reference_handle(med.handle) 539 src.add_media_reference(ref) 540 self.db.add_source(src, self.trans) 541 542 cit = Citation() 543 self.fill_object(cit) 544 cit.set_reference_handle(src.handle) 545 cit.set_page('media should be removed from this citation') 546 ref = MediaRef() 547 ref.set_reference_handle(med.handle) 548 cit.add_media_reference(ref) 549 self.db.add_citation(cit, self.trans) 550 551 def test_fix_ctrlchars_in_notes(self): 552 """ Creates a note with control characters. This tests 553 Check.fix_ctrlchars_in_notes() 554 """ 555 with DbTxn(_("Testcase generator step %d") % self.transaction_count, 556 self.db) as self.trans: 557 self.transaction_count += 1 558 559 obj = Note() 560 obj.set("This is a text note with a \x03 control character") 561 obj.set_format(_choice((Note.FLOWED, Note.FORMATTED))) 562 obj.set_type(self.rand_type(NoteType())) 563 self.db.add_note(obj, self.trans) 564 565 def test_fix_alt_place_names(self): 566 """ 567 Creates a place with a duplicate of primary in alt_names, 568 a blank alt_name, and a duplicate of one of the alt_names. Also 569 include two alt names that are almost duplicates, but not quite. 570 This tests Check.fix_alt_place_names() 571 """ 572 with DbTxn(_("Testcase generator step %d") % self.transaction_count, 573 self.db) as self.trans: 574 self.transaction_count += 1 575 576 plac = Place() 577 pri_name = PlaceName() 578 pri_name.set_value("Primary name") 579 alt_name1 = PlaceName() 580 alt_name1.set_value("Alt name 1") 581 alt_name2 = PlaceName() 582 alt_name2.set_value("Alt name 1") 583 alt_name2.set_language("testish") 584 alt_name3 = PlaceName() 585 alt_name3.set_value("Alt name 1") 586 alt_name3.set_date_object(Today()) 587 alt_names = [pri_name, alt_name1, alt_name1, PlaceName(), 588 alt_name2, alt_name3] 589 plac.set_name(pri_name) 590 plac.set_alternative_names(alt_names) 591 self.db.add_place(plac, self.trans) 592 593 def test_fix_duplicated_grampsid(self): 594 """ 595 Create some duplicate Gramps IDs in various object types 596 This tests Check.fix_duplicated_grampsid() 597 """ 598 with DbTxn(_("Testcase generator step %d") % self.transaction_count, 599 self.db) as self.trans: 600 self.transaction_count += 1 601 for dummy in range(0, 2): 602 cit = Citation() 603 self.fill_object(cit) 604 cit.set_gramps_id("C1001") 605 self.db.add_citation(cit, self.trans) 606 607 evt = Event() 608 self.fill_object(evt) 609 evt.set_gramps_id("E1001") 610 self.db.add_event(evt, self.trans) 611 612 person1_h = self.generate_person( 613 Person.MALE, "Smith", 614 "Dup Gramps ID test F1001") 615 person2_h = self.generate_person(Person.FEMALE, "Jones", None) 616 fam = Family() 617 fam.set_father_handle(person1_h) 618 fam.set_mother_handle(person2_h) 619 fam.set_relationship((FamilyRelType.MARRIED, '')) 620 fam.set_gramps_id("F1001") 621 fam_h = self.db.add_family(fam, self.trans) 622 person1 = self.db.get_person_from_handle(person1_h) 623 person1.add_family_handle(fam_h) 624 self.db.commit_person(person1, self.trans) 625 person2 = self.db.get_person_from_handle(person2_h) 626 person2.add_family_handle(fam_h) 627 self.db.commit_person(person2, self.trans) 628 629 med = Media() 630 self.fill_object(med) 631 med.set_gramps_id("O1001") 632 self.db.add_media(med, self.trans) 633 634 note = Note() 635 self.fill_object(note) 636 note.set_gramps_id("N1001") 637 self.db.add_note(note, self.trans) 638 639 person1_h = self.generate_person(Person.MALE, "Smith", 640 "Dup GID test GID I1001") 641 person1 = self.db.get_person_from_handle(person1_h) 642 person1.set_gramps_id("I1001") 643 self.db.commit_person(person1, self.trans) 644 645 place = Place() 646 self.fill_object(place) 647 place.set_gramps_id("P1001") 648 self.db.add_place(place, self.trans) 649 650 rep = Repository() 651 self.fill_object(rep) 652 rep.set_gramps_id("R1001") 653 self.db.add_repository(rep, self.trans) 654 655 src = Source() 656 self.fill_object(src) 657 src.set_gramps_id("S1001") 658 self.db.add_source(src, self.trans) 659 660 def test_cleanup_missing_photos(self): 661 pass 662 663 def test_clean_deleted_name_format(self): 664 pass 665 666 def test_cleanup_empty_objects(self): 667 """ Generate empty objects to test their deletion """ 668 with DbTxn(_("Testcase generator step %d") % self.transaction_count, 669 self.db) as self.trans: 670 self.transaction_count += 1 671 672 pers = Person() 673 self.db.add_person(pers, self.trans) 674 675 fam = Family() 676 self.db.add_family(fam, self.trans) 677 678 evt = Event() 679 self.db.add_event(evt, self.trans) 680 681 place = Place() 682 self.db.add_place(place, self.trans) 683 684 src = Source() 685 self.db.add_source(src, self.trans) 686 687 cit = Citation() 688 self.db.add_citation(cit, self.trans) 689 690 med = Media() 691 self.db.add_media(med, self.trans) 692 693 ref = Repository() 694 self.db.add_repository(ref, self.trans) 695 696 note = Note() 697 self.db.add_note(note, self.trans) 698 699 def test_chk_for_broke_family_link(self): 700 """ Create various family related errors """ 701 # Create a family, that links to father and mother, but father does not 702 # link back 703 with DbTxn(_("Testcase generator step %d") % self.transaction_count, 704 self.db) as self.trans: 705 self.transaction_count += 1 706 person1_h = self.generate_person( 707 Person.MALE, "Broken1", 708 "Family links to this person, but person does not link back") 709 person2_h = self.generate_person(Person.FEMALE, "Broken1", None) 710 fam = Family() 711 fam.set_father_handle(person1_h) 712 fam.set_mother_handle(person2_h) 713 fam.set_relationship((FamilyRelType.MARRIED, '')) 714 fam_h = self.db.add_family(fam, self.trans) 715 # person1 = self.db.get_person_from_handle(person1_h) 716 # person1.add_family_handle(fam_h) 717 # self.db.commit_person(person1, self.trans) 718 person2 = self.db.get_person_from_handle(person2_h) 719 person2.add_family_handle(fam_h) 720 self.db.commit_person(person2, self.trans) 721 722 # Create a family, that misses the link to the father 723 with DbTxn(_("Testcase generator step %d") % self.transaction_count, 724 self.db) as self.trans: 725 self.transaction_count += 1 726 person1_h = self.generate_person(Person.MALE, "Broken2", None) 727 person2_h = self.generate_person(Person.FEMALE, "Broken2", None) 728 fam = Family() 729 # fam.set_father_handle(person1_h) 730 fam.set_mother_handle(person2_h) 731 fam.set_relationship((FamilyRelType.MARRIED, '')) 732 fam_h = self.db.add_family(fam, self.trans) 733 person1 = self.db.get_person_from_handle(person1_h) 734 person1.add_family_handle(fam_h) 735 self.db.commit_person(person1, self.trans) 736 person2 = self.db.get_person_from_handle(person2_h) 737 person2.add_family_handle(fam_h) 738 self.db.commit_person(person2, self.trans) 739 740 # Create a family, that misses the link to the mother 741 with DbTxn(_("Testcase generator step %d") % self.transaction_count, 742 self.db) as self.trans: 743 self.transaction_count += 1 744 person1_h = self.generate_person(Person.MALE, "Broken3", None) 745 person2_h = self.generate_person(Person.FEMALE, "Broken3", None) 746 fam = Family() 747 fam.set_father_handle(person1_h) 748 # fam.set_mother_handle(person2_h) 749 fam.set_relationship((FamilyRelType.MARRIED, '')) 750 fam_h = self.db.add_family(fam, self.trans) 751 person1 = self.db.get_person_from_handle(person1_h) 752 person1.add_family_handle(fam_h) 753 self.db.commit_person(person1, self.trans) 754 person2 = self.db.get_person_from_handle(person2_h) 755 person2.add_family_handle(fam_h) 756 self.db.commit_person(person2, self.trans) 757 758 # Create a family, that links to father and mother, but mother does not 759 # link back 760 with DbTxn(_("Testcase generator step %d") % self.transaction_count, 761 self.db) as self.trans: 762 self.transaction_count += 1 763 person1_h = self.generate_person(Person.MALE, "Broken4", None) 764 person2_h = self.generate_person( 765 Person.FEMALE, "Broken4", 766 "Family links to this person, but person does not link back") 767 fam = Family() 768 fam.set_father_handle(person1_h) 769 fam.set_mother_handle(person2_h) 770 fam.set_relationship((FamilyRelType.MARRIED, '')) 771 fam_h = self.db.add_family(fam, self.trans) 772 person1 = self.db.get_person_from_handle(person1_h) 773 person1.add_family_handle(fam_h) 774 self.db.commit_person(person1, self.trans) 775 # person2 = self.db.get_person_from_handle(person2_h) 776 # person2.add_family_handle(fam_h) 777 # self.db.commit_person(person2, self.trans) 778 779 # Create two married people of same sex. 780 # This is NOT detected as an error by plugins/tool/Check.py 781 with DbTxn(_("Testcase generator step %d") % self.transaction_count, 782 self.db) as self.trans: 783 self.transaction_count += 1 784 person1_h = self.generate_person(Person.MALE, "Broken5", None) 785 person2_h = self.generate_person(Person.MALE, "Broken5", None) 786 fam = Family() 787 fam.set_father_handle(person1_h) 788 fam.set_mother_handle(person2_h) 789 fam.set_relationship((FamilyRelType.MARRIED, '')) 790 fam_h = self.db.add_family(fam, self.trans) 791 person1 = self.db.get_person_from_handle(person1_h) 792 person1.add_family_handle(fam_h) 793 self.db.commit_person(person1, self.trans) 794 person2 = self.db.get_person_from_handle(person2_h) 795 person2.add_family_handle(fam_h) 796 self.db.commit_person(person2, self.trans) 797 798 # Create a family, that contains an invalid handle to for the father 799 with DbTxn(_("Testcase generator step %d") % self.transaction_count, 800 self.db) as self.trans: 801 self.transaction_count += 1 802 # person1_h = self.generate_person(Person.MALE, "Broken6", None) 803 person2_h = self.generate_person(Person.FEMALE, "Broken6", None) 804 fam = Family() 805 fam.set_father_handle("InvalidHandle1") 806 fam.set_mother_handle(person2_h) 807 fam.set_relationship((FamilyRelType.MARRIED, '')) 808 fam_h = self.db.add_family(fam, self.trans) 809 # person1 = self.db.get_person_from_handle(person1_h) 810 # person1.add_family_handle(fam_h) 811 # self.db.commit_person(person1, self.trans) 812 person2 = self.db.get_person_from_handle(person2_h) 813 person2.add_family_handle(fam_h) 814 self.db.commit_person(person2, self.trans) 815 816 # Create a family, that contains an invalid handle to for the mother 817 with DbTxn(_("Testcase generator step %d") % self.transaction_count, 818 self.db) as self.trans: 819 self.transaction_count += 1 820 person1_h = self.generate_person(Person.MALE, "Broken7", None) 821 # person2_h = self.generate_person(Person.FEMALE, "Broken7", None) 822 fam = Family() 823 fam.set_father_handle(person1_h) 824 fam.set_mother_handle("InvalidHandle2") 825 fam.set_relationship((FamilyRelType.MARRIED, '')) 826 fam_h = self.db.add_family(fam, self.trans) 827 person1 = self.db.get_person_from_handle(person1_h) 828 person1.add_family_handle(fam_h) 829 self.db.commit_person(person1, self.trans) 830 # person2 = self.db.get_person_from_handle(person2_h) 831 # person2.add_family_handle(fam_h) 832 # self.db.commit_person(person2, self.trans) 833 834 # Creates a family where the child does not link back to the family 835 with DbTxn(_("Testcase generator step %d") % self.transaction_count, 836 self.db) as self.trans: 837 self.transaction_count += 1 838 person1_h = self.generate_person(Person.MALE, "Broken8", None) 839 person2_h = self.generate_person(Person.FEMALE, "Broken8", None) 840 child_h = self.generate_person(None, "Broken8", None) 841 fam = Family() 842 fam.set_father_handle(person1_h) 843 fam.set_mother_handle(person2_h) 844 fam.set_relationship((FamilyRelType.MARRIED, '')) 845 child_ref = ChildRef() 846 child_ref.set_reference_handle(child_h) 847 self.fill_object(child_ref) 848 fam.add_child_ref(child_ref) 849 fam_h = self.db.add_family(fam, self.trans) 850 person1 = self.db.get_person_from_handle(person1_h) 851 person1.add_family_handle(fam_h) 852 self.db.commit_person(person1, self.trans) 853 person2 = self.db.get_person_from_handle(person2_h) 854 person2.add_family_handle(fam_h) 855 self.db.commit_person(person2, self.trans) 856 # child = self.db.get_person_from_handle(child_h) 857 # person2.add_parent_family_handle(fam_h) 858 # self.db.commit_person(child, self.trans) 859 860 # Creates a family where the child is not linked, but the child links 861 # to the family 862 with DbTxn(_("Testcase generator step %d") % self.transaction_count, 863 self.db) as self.trans: 864 self.transaction_count += 1 865 person1_h = self.generate_person(Person.MALE, "Broken9", None) 866 person2_h = self.generate_person(Person.FEMALE, "Broken9", None) 867 child_h = self.generate_person(None, "Broken9", None) 868 fam = Family() 869 fam.set_father_handle(person1_h) 870 fam.set_mother_handle(person2_h) 871 fam.set_relationship((FamilyRelType.MARRIED, '')) 872 # child_ref = ChildRef() 873 # child_ref.set_reference_handle(child_h) 874 # self.fill_object(child_ref) 875 # fam.add_child_ref(child_ref) 876 fam_h = self.db.add_family(fam, self.trans) 877 person1 = self.db.get_person_from_handle(person1_h) 878 person1.add_family_handle(fam_h) 879 self.db.commit_person(person1, self.trans) 880 person2 = self.db.get_person_from_handle(person2_h) 881 person2.add_family_handle(fam_h) 882 self.db.commit_person(person2, self.trans) 883 child = self.db.get_person_from_handle(child_h) 884 child.add_parent_family_handle(fam_h) 885 self.db.commit_person(child, self.trans) 886 887 # Creates a family where the child is one of the parents 888 with DbTxn(_("Testcase generator step %d") % self.transaction_count, 889 self.db) as self.trans: 890 self.transaction_count += 1 891 person1_h = self.generate_person(Person.MALE, "Broken19", None) 892 person2_h = self.generate_person(Person.FEMALE, "Broken19", None) 893 child_h = person2_h 894 fam = Family() 895 fam.set_father_handle(person1_h) 896 fam.set_mother_handle(person2_h) 897 fam.set_relationship((FamilyRelType.MARRIED, '')) 898 child_ref = ChildRef() 899 child_ref.set_reference_handle(child_h) 900 self.fill_object(child_ref) 901 fam.add_child_ref(child_ref) 902 fam_h = self.db.add_family(fam, self.trans) 903 person1 = self.db.get_person_from_handle(person1_h) 904 person1.add_family_handle(fam_h) 905 self.db.commit_person(person1, self.trans) 906 person2 = self.db.get_person_from_handle(person2_h) 907 person2.add_family_handle(fam_h) 908 self.db.commit_person(person2, self.trans) 909 child = self.db.get_person_from_handle(child_h) 910 child.add_parent_family_handle(fam_h) 911 self.db.commit_person(child, self.trans) 912 913 # Creates a couple that refer to a family that does not exist in the 914 # database. 915 with DbTxn(_("Testcase generator step %d") % self.transaction_count, 916 self.db) as self.trans: 917 self.transaction_count += 1 918 person1_h = self.generate_person(Person.MALE, "Broken20", None) 919 person2_h = self.generate_person(Person.FEMALE, "Broken20", None) 920# fam = Family() 921# fam.set_father_handle(person1_h) 922# fam.set_mother_handle(person2_h) 923# fam.set_relationship((FamilyRelType.MARRIED, '')) 924# child_ref = ChildRef() 925# # child_ref.set_reference_handle(child_h) 926# # self.fill_object(child_ref) 927# # fam.add_child_ref(child_ref) 928# fam_h = self.db.add_family(fam, self.trans) 929 person1 = self.db.get_person_from_handle(person1_h) 930 person1.add_family_handle("InvalidHandle3") 931 self.db.commit_person(person1, self.trans) 932 person2 = self.db.get_person_from_handle(person2_h) 933 person2.add_family_handle("InvalidHandle3") 934 self.db.commit_person(person2, self.trans) 935# child = self.db.get_person_from_handle(child_h) 936# child.add_parent_family_handle(fam_h) 937# self.db.commit_person(child, self.trans) 938 939 def test_check_parent_relationships(self): 940 pass 941 942 def test_cleanup_empty_families(self): 943 pass 944 945 def test_cleanup_duplicate_spouses(self): 946 pass 947 948 def test_check_events(self): 949 """ Various event related tests """ 950 # Creates a person having a non existing birth event handle set 951 with DbTxn(_("Testcase generator step %d") % self.transaction_count, 952 self.db) as self.trans: 953 self.transaction_count += 1 954 person_h = self.generate_person(None, "Broken11", None) 955 person = self.db.get_person_from_handle(person_h) 956 event_ref = EventRef() 957 event_ref.set_reference_handle("InvalidHandle4") 958 person.set_birth_ref(event_ref) 959 self.db.commit_person(person, self.trans) 960 961 # Creates a person having a non existing death event handle set 962 with DbTxn(_("Testcase generator step %d") % self.transaction_count, 963 self.db) as self.trans: 964 self.transaction_count += 1 965 person_h = self.generate_person(None, "Broken12", None) 966 person = self.db.get_person_from_handle(person_h) 967 event_ref = EventRef() 968 event_ref.set_reference_handle("InvalidHandle5") 969 person.set_death_ref(event_ref) 970 self.db.commit_person(person, self.trans) 971 972 # Creates a person having a non existing event handle set 973 with DbTxn(_("Testcase generator step %d") % self.transaction_count, 974 self.db) as self.trans: 975 self.transaction_count += 1 976 person_h = self.generate_person(None, "Broken13", None) 977 person = self.db.get_person_from_handle(person_h) 978 event_ref = EventRef() 979 event_ref.set_reference_handle("InvalidHandle6") 980 person.add_event_ref(event_ref) 981 self.db.commit_person(person, self.trans) 982 983 # Creates a person with a birth event having an empty type 984 with DbTxn(_("Testcase generator step %d") % self.transaction_count, 985 self.db) as self.trans: 986 self.transaction_count += 1 987 person_h = self.generate_person(None, "Broken14", None) 988 event = Event() 989 # The default type _DEFAULT = BIRTH is set in eventtype 990 event.set_type('') 991 event.set_description("Test for Broken14") 992 event_h = self.db.add_event(event, self.trans) 993 event_ref = EventRef() 994 event_ref.set_reference_handle(event_h) 995 person = self.db.get_person_from_handle(person_h) 996 person.set_birth_ref(event_ref) 997 self.db.commit_person(person, self.trans) 998 999 # Creates a person with a death event having an empty type 1000 with DbTxn(_("Testcase generator step %d") % self.transaction_count, 1001 self.db) as self.trans: 1002 self.transaction_count += 1 1003 person_h = self.generate_person(None, "Broken15", None) 1004 event = Event() 1005 # The default type _DEFAULT = BIRTH is set in eventtype 1006 event.set_type('') 1007 event.set_description("Test for Broken15") 1008 event_h = self.db.add_event(event, self.trans) 1009 event_ref = EventRef() 1010 event_ref.set_reference_handle(event_h) 1011 person = self.db.get_person_from_handle(person_h) 1012 person.set_death_ref(event_ref) 1013 self.db.commit_person(person, self.trans) 1014 1015 # Creates a person with an event having an empty type 1016 # This is NOT detected as an error by plugins/tool/Check.py 1017 with DbTxn(_("Testcase generator step %d") % self.transaction_count, 1018 self.db) as self.trans: 1019 self.transaction_count += 1 1020 person_h = self.generate_person(None, "Broken16", None) 1021 event = Event() 1022 # The default type _DEFAULT = BIRTH is set in eventtype 1023 event.set_type('') 1024 event.set_description("Test for Broken16") 1025 event_h = self.db.add_event(event, self.trans) 1026 event_ref = EventRef() 1027 event_ref.set_reference_handle(event_h) 1028 person = self.db.get_person_from_handle(person_h) 1029 person.add_event_ref(event_ref) 1030 self.db.commit_person(person, self.trans) 1031 1032 def test_check_person_references(self): 1033 pass 1034 1035 def test_check_family_references(self): 1036 pass 1037 1038 def test_check_place_references(self): 1039 """ Tests various place reference errors """ 1040 # Creates a person with a birth event pointing to nonexisting place 1041 with DbTxn(_("Testcase generator step %d") % self.transaction_count, 1042 self.db) as self.trans: 1043 self.transaction_count += 1 1044 person_h = self.generate_person(None, "Broken17", None) 1045 event = Event() 1046 event.set_type(EventType.BIRTH) 1047 event.set_place_handle("InvalidHandle7") 1048 event.set_description("Test for Broken17") 1049 event_h = self.db.add_event(event, self.trans) 1050 event_ref = EventRef() 1051 event_ref.set_reference_handle(event_h) 1052 person = self.db.get_person_from_handle(person_h) 1053 person.set_birth_ref(event_ref) 1054 self.db.commit_person(person, self.trans) 1055 1056 # Creates a person with an event pointing to nonexisting place 1057 with DbTxn(_("Testcase generator step %d") % self.transaction_count, 1058 self.db) as self.trans: 1059 self.transaction_count += 1 1060 person_h = self.generate_person(None, "Broken18", None) 1061 event = Event() 1062 event.set_type(EventType.BIRTH) 1063 event.set_place_handle("InvalidHandle8") 1064 event.set_description("Test for Broken18") 1065 event_h = self.db.add_event(event, self.trans) 1066 event_ref = EventRef() 1067 event_ref.set_reference_handle(event_h) 1068 person = self.db.get_person_from_handle(person_h) 1069 person.add_event_ref(event_ref) 1070 self.db.commit_person(person, self.trans) 1071 1072 def test_check_source_references(self): 1073 """ Tests various source reference errors """ 1074 with DbTxn(_("Testcase generator step %d") % self.transaction_count, 1075 self.db) as self.trans: 1076 self.transaction_count += 1 1077 1078 cit = Citation() 1079 self.fill_object(cit) 1080 cit.set_reference_handle("unknownsourcehandle") 1081 cit.set_page('unreferenced citation with invalid source ref') 1082 self.db.add_citation(cit, self.trans) 1083 1084 cit = Citation() 1085 self.fill_object(cit) 1086 cit.set_reference_handle(None) 1087 cit.set_page('unreferenced citation with invalid source ref') 1088 self.db.add_citation(cit, self.trans) 1089 1090 cit = Citation() 1091 self.fill_object(cit) 1092 cit.set_reference_handle("unknownsourcehandle") 1093 cit.set_page('citation and references to it should be removed') 1094 c_h1 = self.db.add_citation(cit, self.trans) 1095 1096 cit = Citation() 1097 self.fill_object(cit) 1098 cit.set_reference_handle(None) 1099 cit.set_page('citation and references to it should be removed') 1100 c_h2 = self.db.add_citation(cit, self.trans) 1101 1102 self.create_all_possible_citations([c_h1, c_h2], "Broken21", 1103 'non-existent source') 1104 1105 def test_check_citation_references(self): 1106 """ Generate objects that refer to non-existant citations """ 1107 with DbTxn(_("Testcase generator step %d") % self.transaction_count, 1108 self.db) as self.trans: 1109 self.transaction_count += 1 1110 1111 c_h = "unknowncitationhandle" 1112 self.create_all_possible_citations([c_h, ''], "Broken22", 1113 'non-existent citation') 1114 1115 def create_all_possible_citations(self, c_h_list, name, message): 1116 """ Create citations attached to each of the following objects: 1117 Person 1118 Name 1119 Address 1120 Attribute 1121 PersonRef 1122 MediaRef 1123 Attribute 1124 LdsOrd 1125 1126 Family 1127 Attribute 1128 ChildRef 1129 MediaRef 1130 Attribute 1131 LdsOrd 1132 1133 Event 1134 Attribute 1135 MediaRef 1136 Attribute 1137 1138 Media 1139 Attribute 1140 1141 Place 1142 MediaRef 1143 Attribute 1144 1145 Repository (Repositories themselves do not have SourceRefs) 1146 Address 1147 """ 1148 med = Media() 1149 med.set_description(message) 1150 med.set_path(os.path.abspath(str(ICON))) 1151 med.set_mime_type(get_type(med.get_path())) 1152 med.add_citation(_choice(c_h_list)) 1153 # Media : Attribute 1154 att = Attribute() 1155 att.set_type(self.rand_type(AttributeType())) 1156 att.set_value(message) 1157 att.add_citation(_choice(c_h_list)) 1158 med.add_attribute(att) 1159 self.db.add_media(med, self.trans) 1160 1161 person1_h = self.generate_person(Person.MALE, name, None) 1162 person2_h = self.generate_person(Person.FEMALE, name, None) 1163 child_h = self.generate_person(None, name, None) 1164 fam = Family() 1165 fam.set_father_handle(person1_h) 1166 fam.set_mother_handle(person2_h) 1167 fam.set_relationship((FamilyRelType.MARRIED, '')) 1168 # Family 1169 fam.add_citation(_choice(c_h_list)) 1170 # Family : Attribute 1171 att = Attribute() 1172 att.set_type(self.rand_type(AttributeType())) 1173 att.set_value(message) 1174 att.add_citation(_choice(c_h_list)) 1175 fam.add_attribute(att) 1176 # Family : ChildRef 1177 child_ref = ChildRef() 1178 child_ref.set_reference_handle(child_h) 1179 self.fill_object(child_ref) 1180 child_ref.add_citation(_choice(c_h_list)) 1181 fam.add_child_ref(child_ref) 1182 # Family : MediaRef 1183 mref = MediaRef() 1184 mref.set_reference_handle(med.handle) 1185 mref.add_citation(_choice(c_h_list)) 1186 # Family : MediaRef : Attribute 1187 att = Attribute() 1188 att.set_type(self.rand_type(AttributeType())) 1189 att.set_value(message) 1190 att.add_citation(_choice(c_h_list)) 1191 mref.add_attribute(att) 1192 fam.add_media_reference(mref) 1193 # Family : LDSORD 1194 ldsord = LdsOrd() 1195 self.fill_object(ldsord) 1196 # TODO: adapt type and status to family/person 1197 # if isinstance(obj, Person): 1198 # if isinstance(obj, Family): 1199 # pylint: disable=protected-access 1200 ldsord.set_type(_choice([item[0] for item in LdsOrd._TYPE_MAP])) 1201 ldsord.set_status(_randint(0, len(LdsOrd._STATUS_MAP) - 1)) 1202 ldsord.add_citation(_choice(c_h_list)) 1203 fam.add_lds_ord(ldsord) 1204 # Family : EventRef 1205 evt = Event() 1206 evt.set_type(EventType.MARRIAGE) 1207 (dummy, date) = self.rand_date() 1208 evt.set_date_object(date) 1209 evt.set_description(message) 1210 event_h = self.db.add_event(evt, self.trans) 1211 eref = EventRef() 1212 eref.set_reference_handle(event_h) 1213 eref.set_role(self.rand_type(EventRoleType())) 1214 # Family : EventRef : Attribute 1215 att = Attribute() 1216 att.set_type(self.rand_type(AttributeType())) 1217 att.set_value(message) 1218 att.add_citation(_choice(c_h_list)) 1219 eref.add_attribute(att) 1220 fam.add_event_ref(eref) 1221 fam_h = self.db.add_family(fam, self.trans) 1222 person1 = self.db.get_person_from_handle(person1_h) 1223 person1.add_family_handle(fam_h) 1224 # Person 1225 person1.add_citation(_choice(c_h_list)) 1226 # Person : Name 1227 alt_name = Name(person1.get_primary_name()) 1228 alt_name.set_first_name(message) 1229 alt_name.add_citation(_choice(c_h_list)) 1230 person1.add_alternate_name(alt_name) 1231 # Person : Address 1232 add = Address() 1233 add.set_street(message) 1234 add.add_citation(_choice(c_h_list)) 1235 person1.add_address(add) 1236 # Person : Attribute 1237 att = Attribute() 1238 att.set_type(self.rand_type(AttributeType())) 1239 att.set_value(message) 1240 att.add_citation(_choice(c_h_list)) 1241 person1.add_attribute(att) 1242 # Person : PersonRef 1243 asso_h = self.generate_person() 1244 asso = PersonRef() 1245 asso.set_reference_handle(asso_h) 1246 asso.set_relation(self.rand_text(self.SHORT)) 1247 self.fill_object(asso) 1248 asso.add_citation(_choice(c_h_list)) 1249 person1.add_person_ref(asso) 1250 # Person : MediaRef 1251 mref = MediaRef() 1252 mref.set_reference_handle(med.handle) 1253 mref.add_citation(_choice(c_h_list)) 1254 # Person : MediaRef : Attribute 1255 att = Attribute() 1256 att.set_type(self.rand_type(AttributeType())) 1257 att.set_value(self.rand_text(self.SHORT)) 1258 att.add_citation(_choice(c_h_list)) 1259 mref.add_attribute(att) 1260 person1.add_media_reference(mref) 1261 # Person : LDSORD 1262 ldsord = LdsOrd() 1263 self.fill_object(ldsord) 1264 # TODO: adapt type and status to family/person 1265 # if isinstance(obj, Person): 1266 # if isinstance(obj, Family): 1267 ldsord.set_type(_choice( 1268 [item[0] for item in LdsOrd._TYPE_MAP])) 1269 ldsord.set_status(_randint(0, len(LdsOrd._STATUS_MAP) - 1)) 1270 ldsord.add_citation(_choice(c_h_list)) 1271 person1.add_lds_ord(ldsord) 1272 # Person : EventRef 1273 evt = Event() 1274 evt.set_type(EventType.ELECTED) 1275 (dummy, dat) = self.rand_date() 1276 evt.set_date_object(dat) 1277 evt.set_description(message) 1278 event_h = self.db.add_event(evt, self.trans) 1279 eref = EventRef() 1280 eref.set_reference_handle(event_h) 1281 eref.set_role(self.rand_type(EventRoleType())) 1282 # Person : EventRef : Attribute 1283 att = Attribute() 1284 att.set_type(self.rand_type(AttributeType())) 1285 att.set_value(message) 1286 att.add_citation(_choice(c_h_list)) 1287 eref.add_attribute(att) 1288 person1.add_event_ref(eref) 1289 self.db.commit_person(person1, self.trans) 1290 person2 = self.db.get_person_from_handle(person2_h) 1291 person2.add_family_handle(fam_h) 1292 self.db.commit_person(person2, self.trans) 1293 1294 evt = Event() 1295 evt.set_description(message) 1296 evt.set_type(EventType.MARRIAGE) 1297 # Event 1298 evt.add_citation(_choice(c_h_list)) 1299 # Event : Attribute 1300 att = Attribute() 1301 att.set_type(self.rand_type(AttributeType())) 1302 att.set_value(message) 1303 att.add_citation(_choice(c_h_list)) 1304 evt.add_attribute(att) 1305 # Event : MediaRef 1306 mref = MediaRef() 1307 mref.set_reference_handle(med.handle) 1308 mref.add_citation(_choice(c_h_list)) 1309 # Event : MediaRef : Attribute 1310 att = Attribute() 1311 att.set_type(self.rand_type(AttributeType())) 1312 att.set_value(self.rand_text(self.SHORT)) 1313 att.add_citation(_choice(c_h_list)) 1314 mref.add_attribute(att) 1315 evt.add_media_reference(mref) 1316 self.db.add_event(evt, self.trans) 1317 1318 place = Place() 1319 place.set_title(message) 1320 place.add_citation(_choice(c_h_list)) 1321 # Place : MediaRef 1322 mref = MediaRef() 1323 mref.set_reference_handle(med.handle) 1324 mref.add_citation(_choice(c_h_list)) 1325 # Place : MediaRef : Attribute 1326 att = Attribute() 1327 att.set_type(self.rand_type(AttributeType())) 1328 att.set_value(self.rand_text(self.SHORT)) 1329 att.add_citation(_choice(c_h_list)) 1330 mref.add_attribute(att) 1331 place.add_media_reference(mref) 1332 self.db.add_place(place, self.trans) 1333 1334 ref = Repository() 1335 ref.set_name(message) 1336 ref.set_type(RepositoryType.LIBRARY) 1337 # Repository : Address 1338 add = Address() 1339 add.set_street(message) 1340 add.add_citation(_choice(c_h_list)) 1341 ref.add_address(add) 1342 self.db.add_repository(ref, self.trans) 1343 1344 def test_check_media_references(self): 1345 pass 1346 1347 def test_check_repo_references(self): 1348 pass 1349 1350 def test_check_note_references(self): 1351 pass 1352 1353 def generate_person(self, gender=None, lastname=None, note=None, 1354 alive_in_year=None): 1355 """ This generates a person with lots of attachments """ 1356 if not self.cli: 1357 if self.person_count % 10 == 0: 1358 while Gtk.events_pending(): 1359 Gtk.main_iteration() 1360 1361 pers = Person() 1362 self.fill_object(pers) 1363 1364 # Gender 1365 if gender is None: 1366 gender = _randint(0, 1) 1367 if _randint(0, 10) == 1: # Set some persons to unknown gender 1368 pers.set_gender(Person.UNKNOWN) 1369 else: 1370 pers.set_gender(gender) 1371 1372 # Name 1373 name = Name() 1374 (firstname, lastname) = self.rand_name(lastname, gender) 1375 name.set_first_name(firstname) 1376 surname = Surname() 1377 surname.set_surname(lastname) 1378 name.add_surname(surname) 1379 self.fill_object(name) 1380 pers.set_primary_name(name) 1381 1382 # generate some slightly different alternate name 1383 firstname2 = \ 1384 firstname.replace("m", "n").replace("l", "i").replace("b", "d") 1385 if firstname2 != firstname: 1386 alt_name = Name(name) 1387 self.fill_object(alt_name) 1388 if _randint(0, 2) == 1: 1389 surname = Surname() 1390 surname.set_surname(self.rand_text(self.LASTNAME)) 1391 alt_name.add_surname(surname) 1392 elif _randint(0, 2) == 1: 1393 surname = Surname() 1394 surname.set_surname(lastname) 1395 alt_name.add_surname(surname) 1396 if _randint(0, 1) == 1: 1397 alt_name.set_first_name(firstname2) 1398 if _randint(0, 1) == 1: 1399 alt_name.set_title(self.rand_text(self.SHORT)) 1400 if _randint(0, 1) == 1: 1401 patronymic = Surname() 1402 patronymic.set_surname(self.rand_text(self.FIRSTNAME_MALE)) 1403 patronymic.set_origintype(NameOriginType.PATRONYMIC) 1404 alt_name.add_surname(patronymic) 1405 if _randint(0, 1) == 1: 1406 alt_name.get_primary_surname().set_prefix( 1407 self.rand_text(self.SHORT)) 1408 if _randint(0, 1) == 1: 1409 alt_name.set_suffix(self.rand_text(self.SHORT)) 1410 if _randint(0, 1) == 1: 1411 alt_name.set_call_name(self.rand_text(self.FIRSTNAME)) 1412 pers.add_alternate_name(alt_name) 1413 firstname2 = \ 1414 firstname.replace("a", "e").replace("o", "u").replace("r", "p") 1415 if firstname2 != firstname: 1416 alt_name = Name(name) 1417 self.fill_object(alt_name) 1418 if _randint(0, 2) == 1: 1419 surname = Surname() 1420 surname.set_surname(self.rand_text(self.LASTNAME)) 1421 alt_name.add_surname(surname) 1422 elif _randint(0, 2) == 1: 1423 surname = Surname() 1424 surname.set_surname(lastname) 1425 alt_name.add_surname(surname) 1426 if _randint(0, 1) == 1: 1427 alt_name.set_first_name(firstname2) 1428 if _randint(0, 1) == 1: 1429 alt_name.set_title(self.rand_text(self.SHORT)) 1430 if _randint(0, 1) == 1: 1431 patronymic = Surname() 1432 patronymic.set_surname(self.rand_text(self.FIRSTNAME_MALE)) 1433 patronymic.set_origintype(NameOriginType.PATRONYMIC) 1434 alt_name.add_surname(patronymic) 1435 if _randint(0, 1) == 1: 1436 alt_name.get_primary_surname().set_prefix( 1437 self.rand_text(self.SHORT)) 1438 if _randint(0, 1) == 1: 1439 alt_name.set_suffix(self.rand_text(self.SHORT)) 1440 if _randint(0, 1) == 1: 1441 alt_name.set_call_name(self.rand_text(self.FIRSTNAME)) 1442 pers.add_alternate_name(alt_name) 1443 1444 if not alive_in_year: 1445 alive_in_year = _randint(1700, 2000) 1446 1447 b_y = alive_in_year - _randint(0, 60) 1448 d_y = alive_in_year + _randint(0, 60) 1449 1450 # birth 1451 if _randint(0, 1) == 1: 1452 (dummy, eref) = self.rand_personal_event(EventType.BIRTH, b_y, b_y) 1453 pers.set_birth_ref(eref) 1454 1455 # baptism 1456 if _randint(0, 1) == 1: 1457 (dummy, eref) = self.rand_personal_event( 1458 _choice((EventType.BAPTISM, EventType.CHRISTEN)), b_y, b_y + 2) 1459 pers.add_event_ref(eref) 1460 1461 # death 1462 if _randint(0, 1) == 1: 1463 (dummy, eref) = self.rand_personal_event(EventType.DEATH, d_y, d_y) 1464 pers.set_death_ref(eref) 1465 1466 # burial 1467 if _randint(0, 1) == 1: 1468 (dummy, eref) = self.rand_personal_event( 1469 _choice((EventType.BURIAL, EventType.CREMATION)), d_y, d_y + 2) 1470 pers.add_event_ref(eref) 1471 1472 # some other events 1473 while _randint(0, 5) == 1: 1474 (dummy, eref) = self.rand_personal_event(None, b_y, d_y) 1475 pers.add_event_ref(eref) 1476 1477 # some shared events 1478 if self.generated_events: 1479 while _randint(0, 5) == 1: 1480 e_h = _choice(self.generated_events) 1481 eref = EventRef() 1482 self.fill_object(eref) 1483 eref.set_reference_handle(e_h) 1484 pers.add_event_ref(eref) 1485 1486 # PersonRef 1487 if _randint(0, 3) == 1: 1488 for dummy in range(0, _randint(1, 2)): 1489 if self.person_count > self.max_person_count: 1490 break 1491 if alive_in_year: 1492 asso_h = self.generate_person(None, None, 1493 alive_in_year=alive_in_year) 1494 else: 1495 asso_h = self.generate_person() 1496 asso = PersonRef() 1497 asso.set_reference_handle(asso_h) 1498 asso.set_relation(self.rand_text(self.SHORT)) 1499 self.fill_object(asso) 1500 pers.add_person_ref(asso) 1501 if _randint(0, 2) == 0: 1502 self.persons_todo.append(asso_h) 1503 1504 # Note 1505 if note: 1506 pass # Add later? 1507 1508 person_handle = self.db.add_person(pers, self.trans) 1509 1510 self.person_count = self.person_count + 1 1511 self.progress_step() 1512 if self.person_count % 10 == 1: 1513 print("person count", self.person_count) 1514 self.person_dates[person_handle] = (b_y, d_y) 1515 1516 return person_handle 1517 1518 def generate_family(self, person1_h): 1519 """ Make up a family """ 1520 person1 = self.db.get_person_from_handle(person1_h) 1521 if not person1: 1522 return 1523 alive_in_year = None 1524 if person1_h in self.person_dates: 1525 (born, died) = self.person_dates[person1_h] 1526 alive_in_year = min(born + _randint(10, 50), 1527 died + _randint(-10, 10)) 1528 1529 if person1.get_gender() == 1: 1530 if _randint(0, 7) == 1: 1531 person2_h = None 1532 else: 1533 if alive_in_year: 1534 person2_h = \ 1535 self.generate_person(0, alive_in_year=alive_in_year) 1536 else: 1537 person2_h = self.generate_person(0) 1538 else: 1539 person2_h = person1_h 1540 if _randint(0, 7) == 1: 1541 person1_h = None 1542 else: 1543 if alive_in_year: 1544 person1_h = \ 1545 self.generate_person(1, alive_in_year=alive_in_year) 1546 else: 1547 person1_h = self.generate_person(1) 1548 1549 if person1_h and _randint(0, 2) > 0: 1550 self.parents_todo.append(person1_h) 1551 if person2_h and _randint(0, 2) > 0: 1552 self.parents_todo.append(person2_h) 1553 1554 with DbTxn(_("Testcase generator step %d") % self.transaction_count, 1555 self.db) as self.trans: 1556 self.transaction_count += 1 1557 fam = Family() 1558 self.add_defaults(fam) 1559 if person1_h: 1560 fam.set_father_handle(person1_h) 1561 if person2_h: 1562 fam.set_mother_handle(person2_h) 1563 1564 # Avoid adding the same event more than once to the same family 1565 event_set = set() 1566 1567 # Generate at least one family event with a probability of 75% 1568 if _randint(0, 3) > 0: 1569 (dummy, eref) = self.rand_family_event(None) 1570 fam.add_event_ref(eref) 1571 event_set.add(eref.get_reference_handle()) 1572 1573 # generate some more events with a lower probability 1574 while _randint(0, 3) == 1: 1575 (dummy, eref) = self.rand_family_event(None) 1576 if eref.get_reference_handle() in event_set: 1577 continue 1578 fam.add_event_ref(eref) 1579 event_set.add(eref.get_reference_handle()) 1580 1581 # some shared events 1582 if self.generated_events: 1583 while _randint(0, 5) == 1: 1584 typeval = EventType.UNKNOWN 1585 while int(typeval) not in self.FAMILY_EVENTS: 1586 e_h = _choice(self.generated_events) 1587 typeval = self.db.get_event_from_handle(e_h).get_type() 1588 if e_h in event_set: 1589 break 1590 eref = EventRef() 1591 self.fill_object(eref) 1592 eref.set_reference_handle(e_h) 1593 fam.add_event_ref(eref) 1594 event_set.add(e_h) 1595 1596 fam_h = self.db.add_family(fam, self.trans) 1597 self.generated_families.append(fam_h) 1598 fam = self.db.commit_family(fam, self.trans) 1599 if person1_h: 1600 person1 = self.db.get_person_from_handle(person1_h) 1601 person1.add_family_handle(fam_h) 1602 self.db.commit_person(person1, self.trans) 1603 if person2_h: 1604 person2 = self.db.get_person_from_handle(person2_h) 1605 person2.add_family_handle(fam_h) 1606 self.db.commit_person(person2, self.trans) 1607 1608 lastname = person1.get_primary_name().get_surname() 1609 1610 for i in range(0, _randint(1, 10)): 1611 if self.person_count > self.max_person_count: 1612 break 1613 if alive_in_year: 1614 child_h = self.generate_person( 1615 None, lastname, 1616 alive_in_year=alive_in_year + 1617 _randint(16 + 2 * i, 30 + 2 * i)) 1618 else: 1619 child_h = self.generate_person(None, lastname) 1620 (born, died) = self.person_dates[child_h] 1621 alive_in_year = born 1622 fam = self.db.get_family_from_handle(fam_h) 1623 child_ref = ChildRef() 1624 child_ref.set_reference_handle(child_h) 1625 self.fill_object(child_ref) 1626 fam.add_child_ref(child_ref) 1627 self.db.commit_family(fam, self.trans) 1628 child = self.db.get_person_from_handle(child_h) 1629 child.add_parent_family_handle(fam_h) 1630 self.db.commit_person(child, self.trans) 1631 if _randint(0, 3) > 0: 1632 self.persons_todo.append(child_h) 1633 1634 def generate_parents(self, child_h): 1635 """ Add parents to a person, if not present already""" 1636 if not child_h: 1637 return 1638 child = self.db.get_person_from_handle(child_h) 1639 if not child: 1640 print("ERROR: Person handle %s does not exist in database" % 1641 child_h) 1642 return 1643 if child.get_parent_family_handle_list(): 1644 return 1645 1646 lastname = child.get_primary_name().get_surname() 1647 if child_h in self.person_dates: 1648 (born, dummy) = self.person_dates[child_h] 1649 person1_h = self.generate_person(1, lastname, alive_in_year=born) 1650 person2_h = self.generate_person(0, alive_in_year=born) 1651 else: 1652 person1_h = self.generate_person(1, lastname) 1653 person2_h = self.generate_person(0) 1654 1655 if _randint(0, 2) > 1: 1656 self.parents_todo.append(person1_h) 1657 if _randint(0, 2) > 1: 1658 self.parents_todo.append(person2_h) 1659 1660 with DbTxn(_("Testcase generator step %d") % self.transaction_count, 1661 self.db) as self.trans: 1662 self.transaction_count += 1 1663 fam = Family() 1664 self.add_defaults(fam) 1665 fam.set_father_handle(person1_h) 1666 fam.set_mother_handle(person2_h) 1667 child_ref = ChildRef() 1668 child_ref.set_reference_handle(child_h) 1669 self.fill_object(child_ref) 1670 fam.add_child_ref(child_ref) 1671 fam_h = self.db.add_family(fam, self.trans) 1672 self.generated_families.append(fam_h) 1673 fam = self.db.commit_family(fam, self.trans) 1674 person1 = self.db.get_person_from_handle(person1_h) 1675 person1.add_family_handle(fam_h) 1676 self.db.commit_person(person1, self.trans) 1677 person2 = self.db.get_person_from_handle(person2_h) 1678 person2.add_family_handle(fam_h) 1679 self.db.commit_person(person2, self.trans) 1680 child.add_parent_family_handle(fam_h) 1681 self.db.commit_person(child, self.trans) 1682 1683 def generate_tags(self): 1684 """ Make up some odd tags """ 1685 with DbTxn(_("Testcase generator step %d") % self.transaction_count, 1686 self.db) as self.trans: 1687 self.transaction_count += 1 1688 for dummy in range(10): 1689 tag = Tag() 1690 tag.set_name(self.rand_text(self.TAG)) 1691 tag.set_color(self.rand_color()) 1692 tag.set_priority(self.db.get_number_of_tags()) 1693 tag_handle = self.db.add_tag(tag, self.trans) 1694 self.generated_tags.append(tag_handle) 1695 1696 def add_defaults(self, obj): 1697 self.fill_object(obj) 1698 1699 def rand_name(self, lastname=None, gender=None): 1700 """ Create a name pair (first, last)""" 1701 if gender == Person.MALE: 1702 firstname = self.rand_text(self.FIRSTNAME_MALE) 1703 elif gender == Person.FEMALE: 1704 firstname = self.rand_text(self.FIRSTNAME_FEMALE) 1705 else: 1706 firstname = self.rand_text(self.FIRSTNAME) 1707 if not lastname: 1708 lastname = self.rand_text(self.LASTNAME) 1709 return (firstname, lastname) 1710 1711 def rand_date(self, start=None, end=None): 1712 """ 1713 Generates a random date object between the given years start and end 1714 """ 1715 if not start and not end: 1716 start = _randint(1700, 2000) 1717 if start and not end: 1718 end = start + _randint(0, 100) 1719 if end and not start: 1720 start = end - _randint(0, 100) 1721 year = _randint(start, end) 1722 1723 ndate = Date() 1724 if _randint(0, 10) == 1: 1725 # Some get a textual date 1726 ndate.set_as_text(_choice((self.rand_text(self.SHORT), "Unknown", 1727 "??", "Don't know", "TODO!"))) 1728 else: 1729 if _randint(0, 10) == 1: 1730 # some get an empty date 1731 pass 1732 else: 1733 # regular dates 1734 calendar = Date.CAL_GREGORIAN 1735 quality = _choice((Date.QUAL_NONE, 1736 Date.QUAL_ESTIMATED, 1737 Date.QUAL_CALCULATED)) 1738 modifier = _choice((Date.MOD_NONE, 1739 Date.MOD_BEFORE, 1740 Date.MOD_AFTER, 1741 Date.MOD_ABOUT, 1742 Date.MOD_RANGE, 1743 Date.MOD_SPAN)) 1744 day = _randint(0, 28) 1745 if day > 0: # avoid days without month 1746 month = _randint(1, 12) 1747 else: 1748 month = _randint(0, 12) 1749 1750 if modifier in (Date.MOD_RANGE, Date.MOD_SPAN): 1751 day2 = _randint(0, 28) 1752 if day2 > 0: 1753 month2 = _randint(1, 12) 1754 else: 1755 month2 = _randint(0, 12) 1756 year2 = year + _randint(1, 5) 1757 ndate.set(quality, modifier, calendar, 1758 (day, month, year, False, day2, month2, year2, 1759 False), "") 1760 else: 1761 ndate.set(quality, modifier, calendar, 1762 (day, month, year, False), "") 1763 1764 return (year, ndate) 1765 1766 def fill_object(self, obj): 1767 ''' Generic object fill routine ''' 1768 1769 if issubclass(obj.__class__, AddressBase): 1770 while _randint(0, 1) == 1: 1771 addr = Address() 1772 self.fill_object(addr) 1773 obj.add_address(addr) 1774 1775 if isinstance(obj, Attribute): 1776 obj.set_type(self.rand_type(AttributeType())) 1777 obj.set_value(self.rand_text(self.SHORT)) 1778 1779 if issubclass(obj.__class__, AttributeBase): 1780 while _randint(0, 1) == 1: 1781 att = Attribute() 1782 self.fill_object(att) 1783 obj.add_attribute(att) 1784 1785 if isinstance(obj, ChildRef): 1786 if _randint(0, 3) == 1: 1787 obj.set_mother_relation(self.rand_type(ChildRefType())) 1788 if _randint(0, 3) == 1: 1789 obj.set_father_relation(self.rand_type(ChildRefType())) 1790 1791 if issubclass(obj.__class__, DateBase): 1792 if _randint(0, 1) == 1: 1793 (dummy, dat) = self.rand_date() 1794 obj.set_date_object(dat) 1795 1796 if isinstance(obj, Event): 1797 if _randint(0, 1) == 1: 1798 obj.set_description(self.rand_text(self.LONG)) 1799 1800 if issubclass(obj.__class__, EventRef): 1801 obj.set_role(self.rand_type(EventRoleType())) 1802 1803 if isinstance(obj, Family): 1804 if _randint(0, 2) == 1: 1805 obj.set_relationship(self.rand_type(FamilyRelType())) 1806 else: 1807 obj.set_relationship(FamilyRelType(FamilyRelType.MARRIED)) 1808 1809 if isinstance(obj, LdsOrd): 1810 if _randint(0, 1) == 1: 1811 obj.set_temple(_choice(TEMPLES.name_code_data())[1]) 1812 1813 if issubclass(obj.__class__, LdsOrdBase): 1814 while _randint(0, 1) == 1: 1815 ldsord = LdsOrd() 1816 self.fill_object(ldsord) 1817 if isinstance(obj, Person): 1818 lds_type = _choice([item for item in LDS_INDIVIDUAL_ORD]) 1819 if isinstance(obj, Family): 1820 lds_type = LDS_SPOUSE_SEALING[0] 1821 if self.generated_families: 1822 ldsord.set_family_handle( 1823 _choice(self.generated_families)) 1824 ldsord.set_type(lds_type[0]) 1825 status = _choice(lds_type[1]) 1826 if status != LdsOrd.STATUS_NONE: 1827 ldsord.set_status(status) 1828 obj.add_lds_ord(ldsord) 1829 1830 if isinstance(obj, Location): 1831 if _randint(0, 1) == 1: 1832 obj.set_parish(self.rand_text(self.SHORT)) 1833 1834 if issubclass(obj.__class__, LocationBase): 1835 if _randint(0, 1) == 1: 1836 obj.set_street(self.rand_text(self.SHORT)) 1837 if _randint(0, 1) == 1: 1838 obj.set_city(self.rand_text(self.SHORT)) 1839 if _randint(0, 1) == 1: 1840 obj.set_postal_code(self.rand_text(self.SHORT)) 1841 if _randint(0, 1) == 1: 1842 obj.set_phone(self.rand_text(self.SHORT)) 1843 if _randint(0, 1) == 1: 1844 obj.set_state(self.rand_text(self.SHORT)) 1845 if _randint(0, 1) == 1: 1846 obj.set_country(self.rand_text(self.SHORT)) 1847 if _randint(0, 1) == 1: 1848 obj.set_county(self.rand_text(self.SHORT)) 1849 1850 if issubclass(obj.__class__, MediaBase): 1851 # FIXME: frequency changed to prevent recursion 1852 while _randint(0, 10) == 1: 1853 obj.add_media_reference(self.fill_object(MediaRef())) 1854 1855 if isinstance(obj, Media): 1856 if _randint(0, 3) == 1: 1857 obj.set_description(str(self.rand_text(self.LONG))) 1858 path = os.path.abspath(_choice((ICON, LOGO, SPLASH))) 1859 obj.set_path(str(path)) 1860 mime = get_type(path) 1861 obj.set_mime_type(mime) 1862 else: 1863 obj.set_description(str(self.rand_text(self.SHORT))) 1864 obj.set_path(os.path.abspath(str(ICON))) 1865 obj.set_mime_type("image/png") 1866 1867 if isinstance(obj, MediaRef): 1868 if not self.generated_media or _randint(0, 10) == 1: 1869 med = Media() 1870 self.fill_object(med) 1871 self.db.add_media(med, self.trans) 1872 self.generated_media.append(med.get_handle()) 1873 obj.set_reference_handle(_choice(self.generated_media)) 1874 if _randint(0, 1) == 1: 1875 obj.set_rectangle((_randint(0, 200), _randint(0, 200), 1876 _randint(0, 200), _randint(0, 200))) 1877 1878 if isinstance(obj, Name): 1879 obj.set_type(self.rand_type(NameType())) 1880 if _randint(0, 1) == 1: 1881 obj.set_title(self.rand_text(self.SHORT)) 1882 if _randint(0, 1) == 1: 1883 patronymic = Surname() 1884 patronymic.set_surname(self.rand_text(self.FIRSTNAME_MALE)) 1885 patronymic.set_origintype(NameOriginType.PATRONYMIC) 1886 obj.add_surname(patronymic) 1887 if _randint(0, 1) == 1: 1888 obj.get_primary_surname().set_prefix( 1889 self.rand_text(self.SHORT)) 1890 if _randint(0, 1) == 1: 1891 obj.set_suffix(self.rand_text(self.SHORT)) 1892 if _randint(0, 1) == 1: 1893 obj.set_call_name(self.rand_text(self.FIRSTNAME)) 1894 if _randint(0, 1) == 1: 1895 obj.set_group_as(obj.get_surname()[:1]) 1896 # obj.set_display_as() 1897 # obj.set_sort_as() 1898 1899 if isinstance(obj, Note): 1900 n_type = self.rand_type(NoteType()) 1901 if n_type == NoteType.HTML_CODE: 1902 obj.set(self.rand_text(self.NOTE)) 1903 else: 1904 obj.set_styledtext(self.rand_text(self.STYLED_TEXT)) 1905 obj.set_format(_choice((Note.FLOWED, Note.FORMATTED))) 1906 obj.set_type(n_type) 1907 1908 if issubclass(obj.__class__, NoteBase): 1909 while _randint(0, 1) == 1: 1910 if not self.generated_notes or _randint(0, 10) == 1: 1911 note = Note() 1912 self.fill_object(note) 1913 self.db.add_note(note, self.trans) 1914 self.generated_notes.append(note.get_handle()) 1915 n_h = _choice(self.generated_notes) 1916 obj.add_note(n_h) 1917 1918 if isinstance(obj, Place): 1919 obj.set_title(self.rand_text(self.LONG)) 1920 obj.set_name(PlaceName(value=self.rand_text(self.SHORT))) 1921 obj.set_code(self.rand_text(self.SHORT)) 1922 if _randint(0, 1) == 1: 1923 if _randint(0, 4) == 1: 1924 obj.set_longitude(self.rand_text(self.SHORT)) 1925 else: 1926 obj.set_longitude(str(_random() * 360.0 - 180.0)) 1927 if _randint(0, 1) == 1: 1928 if _randint(0, 4) == 1: 1929 obj.set_latitude(self.rand_text(self.SHORT)) 1930 else: 1931 obj.set_latitude(str(_random() * 180.0 - 90.0)) 1932 while _randint(0, 1) == 1: 1933 obj.add_alternate_locations(self.fill_object(Location())) 1934 1935 if issubclass(obj.__class__, PlaceBase): 1936 if _randint(0, 1) == 1: 1937 obj.set_place_handle(self.rand_place()) 1938 1939 if issubclass(obj.__class__, BasicPrimaryObject): 1940 if _randint(0, 1) == 1: 1941 obj.set_gramps_id(self.rand_text(self.SHORT)) 1942 1943 if issubclass(obj.__class__, PrivacyBase): 1944 obj.set_privacy(_randint(0, 5) == 1) 1945 1946 if isinstance(obj, RepoRef): 1947 if not self.generated_repos or _randint(0, 10) == 1: 1948 rep = Repository() 1949 self.fill_object(rep) 1950 self.db.add_repository(rep, self.trans) 1951 self.generated_repos.append(rep.get_handle()) 1952 obj.set_reference_handle(_choice(self.generated_repos)) 1953 if _randint(0, 1) == 1: 1954 obj.set_call_number(self.rand_text(self.SHORT)) 1955 obj.set_media_type(self.rand_type(SourceMediaType())) 1956 1957 if isinstance(obj, Repository): 1958 obj.set_type(self.rand_type(RepositoryType())) 1959 obj.set_name(self.rand_text(self.SHORT)) 1960 1961 if isinstance(obj, Source): 1962 obj.set_title(self.rand_text(self.SHORT)) 1963 if _randint(0, 1) == 1: 1964 obj.set_author(self.rand_text(self.SHORT)) 1965 if _randint(0, 1) == 1: 1966 obj.set_publication_info(self.rand_text(self.LONG)) 1967 if _randint(0, 1) == 1: 1968 obj.set_abbreviation(self.rand_text(self.SHORT)) 1969 while _randint(0, 1) == 1: 1970 sattr = SrcAttribute() 1971 sattr.set_type(self.rand_text(self.SHORT)) 1972 sattr.set_value(self.rand_text(self.SHORT)) 1973 obj.add_attribute(sattr) 1974 while _randint(0, 1) == 1: 1975 rep_ref = RepoRef() 1976 self.fill_object(rep_ref) 1977 obj.add_repo_reference(rep_ref) 1978 1979 if issubclass(obj.__class__, CitationBase): 1980 while _randint(0, 1) == 1: 1981 if not self.generated_citations or _randint(1, 10) == 1: 1982 cit = Citation() 1983 self.fill_object(cit) 1984 self.db.add_citation(cit, self.trans) 1985 self.generated_citations.append(cit.get_handle()) 1986 s_h = _choice(self.generated_citations) 1987 obj.add_citation(s_h) 1988 1989 if isinstance(obj, Citation): 1990 if not self.generated_sources or _randint(0, 10) == 1: 1991 src = Source() 1992 self.fill_object(src) 1993 self.db.add_source(src, self.trans) 1994 self.generated_sources.append(src.get_handle()) 1995 obj.set_reference_handle(_choice(self.generated_sources)) 1996 if _randint(0, 1) == 1: 1997 obj.set_page(self.rand_text(self.NUMERIC)) 1998 # if _randint(0, 1) == 1: 1999 # obj.set_text( self.rand_text(self.SHORT)) 2000 # if _randint(0, 1) == 1: 2001 # (year, dat) = self.rand_date( ) 2002 # obj.set_date_object( dat) 2003 # sort to provide deterministic output in unit tests 2004 obj.set_confidence_level(_choice(sorted(conf_strings.keys()))) 2005 2006 if issubclass(obj.__class__, TagBase): 2007 if _randint(0, 1) == 1: 2008 obj.set_tag_list(self.rand_tags()) 2009 2010 if issubclass(obj.__class__, UrlBase): 2011 while _randint(0, 1) == 1: 2012 url = Url() 2013 self.fill_object(url) 2014 obj.add_url(url) 2015 2016 if isinstance(obj, Url): 2017 obj.set_path("http://www.gramps-project.org/?test=%s" % 2018 self.rand_text(self.SHORT)) 2019 obj.set_description(self.rand_text(self.SHORT)) 2020 obj.set_type(self.rand_type(UrlType())) 2021 2022 return obj 2023 2024 def rand_personal_event(self, e_type=None, start=None, end=None): 2025 """ Random personal event """ 2026 if e_type: 2027 typeval = EventType(e_type) 2028 else: 2029 typeval = self.rand_type(EventType()) 2030 return self._rand_event(typeval, start, end) 2031 2032 def rand_family_event(self, e_type=None, start=None, end=None): 2033 """ Random family event """ 2034 if e_type: 2035 EventType(e_type) 2036 else: 2037 typeval = EventType.UNKNOWN 2038 while int(typeval) not in self.FAMILY_EVENTS: 2039 typeval = self.rand_type(EventType()) 2040 return self._rand_event(typeval, start, end) 2041 2042 def _rand_event(self, e_type, start, end): 2043 """ Random general event """ 2044 evt = Event() 2045 self.fill_object(evt) 2046 evt.set_type(e_type) 2047 (year, dat) = self.rand_date(start, end) 2048 evt.set_date_object(dat) 2049 event_h = self.db.add_event(evt, self.trans) 2050 self.generated_events.append(event_h) 2051 event_ref = EventRef() 2052 self.fill_object(event_ref) 2053 event_ref.set_reference_handle(event_h) 2054 return (year, event_ref) 2055 2056 def rand_type(self, gtype): 2057 if issubclass(gtype.__class__, GrampsType): 2058 gmap = gtype.get_map() 2059 # sort to provide deterministic output in unit tests 2060 key = _choice(sorted(gmap.keys())) 2061 if key == gtype.get_custom(): 2062 value = self.rand_text(self.SHORT) 2063 else: 2064 value = '' 2065 gtype.set((key, value)) 2066 return gtype 2067 2068 def rand_place(self): 2069 if not self.generated_places or _randint(0, 10) == 1: 2070 self.generate_place() 2071 return _choice(self.generated_places) 2072 2073 def generate_place(self): 2074 parent_handle = None 2075 for type_num in range(1, 8): 2076 if type_num > 1 and _randint(1, 3) == 1: 2077 # skip some levels in the place hierarchy 2078 continue 2079 place = Place() 2080 place.set_type(PlaceType(type_num)) 2081 if parent_handle is not None: 2082 self.add_parent_place(place, parent_handle) 2083 if type_num > 1 and _randint(1, 3) == 1: 2084 # add additional parent place 2085 parent_handle = self.find_parent_place(type_num - 1) 2086 if parent_handle is not None: 2087 self.add_parent_place(place, parent_handle) 2088 self.fill_object(place) 2089 self.db.add_place(place, self.trans) 2090 parent_handle = place.get_handle() 2091 self.generated_places.append(place.get_handle()) 2092 self.parent_places[type_num].append(place.get_handle()) 2093 2094 def find_parent_place(self, type_num): 2095 if len(self.parent_places[type_num]) > 0: 2096 return _choice(self.parent_places[type_num]) 2097 else: 2098 return None 2099 2100 def add_parent_place(self, place, handle): 2101 place_ref = PlaceRef() 2102 place_ref.ref = handle 2103 dummy, random_date = self.rand_date() 2104 place_ref.set_date_object(random_date) 2105 place.add_placeref(place_ref) 2106 2107 def rand_text(self, t_type=None): 2108 """ make random text strings according to desired type """ 2109 # for lastnamesnames 2110 syllables1 = ["sa", "li", "na", "ma", "no", "re", "mi", 2111 "cha", "ki", "du", "ba", "ku", "el"] 2112 # for firstnames 2113 syllables2 = ["as", "il", "an", "am", "on", "er", "im", 2114 "ach", "ik", "ud", "ab", "ul", "le"] 2115 # others 2116 syllables3 = ["ka", "po", "lo", "chi", "she", "di", "fa", 2117 "go", "ja", "ne", "pe"] 2118 2119 syllables = syllables1 + syllables2 + syllables3 2120 minwords = 5 2121 maxwords = 8 2122 minsyllables = 2 2123 maxsyllables = 5 2124 2125 # result = "" if t_type != self.STYLED_TEXT else StyledText("") 2126 if t_type == self.STYLED_TEXT: 2127 result = StyledText("") 2128 else: 2129 result = "" 2130 2131 if self.options_dict['specialchars']: 2132 result = result + "ä<ö&ü%ß'\"" 2133 2134 if self.options_dict['add_serial'] and t_type != self.TAG: 2135 result = result + "#+#%06d#-#" % self.text_serial_number 2136 self.text_serial_number = self.text_serial_number + 1 2137 2138 if not t_type: 2139 t_type = self.SHORT 2140 2141 if t_type == self.SHORT or t_type == self.TAG: 2142 minwords = 1 2143 maxwords = 3 2144 minsyllables = 2 2145 maxsyllables = 4 2146 2147 if t_type == self.LONG: 2148 minwords = 5 2149 maxwords = 8 2150 minsyllables = 2 2151 maxsyllables = 5 2152 2153 if t_type == self.FIRSTNAME: 2154 t_type = _choice((self.FIRSTNAME_MALE, self.FIRSTNAME_FEMALE)) 2155 2156 if t_type == self.FIRSTNAME_MALE or t_type == self.FIRSTNAME_FEMALE: 2157 syllables = syllables2 2158 minwords = 1 2159 maxwords = 5 2160 minsyllables = 2 2161 maxsyllables = 5 2162 if not self.options_dict['long_names']: 2163 maxwords = 2 2164 maxsyllables = 3 2165 2166 if t_type == self.LASTNAME: 2167 syllables = syllables1 2168 minwords = 1 2169 maxwords = 1 2170 minsyllables = 2 2171 maxsyllables = 5 2172 if not self.options_dict['long_names']: 2173 maxsyllables = 3 2174 2175 if t_type == self.NOTE or t_type == self.STYLED_TEXT: 2176 result = result + "Generated by TestcaseGenerator." 2177 minwords = 20 2178 maxwords = 100 2179 2180 if t_type == self.NUMERIC: 2181 if _randint(0, 1) == 1: 2182 return "%d %s" % (_randint(1, 100), result) 2183 if _randint(0, 1) == 1: 2184 return "%d, %d %s" % (_randint(1, 100), _randint(100, 1000), 2185 result) 2186 med = _randint(100, 1000) 2187 return "%d - %d %s" % (med, med + _randint(1, 5), result) 2188 2189 for dummy in range(0, _randint(minwords, maxwords)): 2190 if result: 2191 result = result + " " 2192 word = "" 2193 for j in range(0, _randint(minsyllables, maxsyllables)): 2194 word = word + _choice(syllables) 2195 if t_type == self.FIRSTNAME_MALE: 2196 word = word + _choice(("a", "e", "i", "o", "u")) 2197 if _randint(0, 3) == 1: 2198 word = word.title() 2199 if t_type == self.NOTE: 2200 if _randint(0, 10) == 1: 2201 word = "<b>%s</b>" % word 2202 elif _randint(0, 10) == 1: 2203 word = "<i>%s</i>" % word 2204 elif _randint(0, 10) == 1: 2205 word = "<i>%s</i>" % word 2206 if _randint(0, 20) == 1: 2207 word = word + "." 2208 elif _randint(0, 30) == 1: 2209 word = word + ".\n" 2210 if t_type == self.STYLED_TEXT: 2211 tags = [] 2212 if _randint(0, 10) == 1: 2213 tags += [StyledTextTag(StyledTextTagType.BOLD, True, 2214 [(0, len(word))])] 2215 elif _randint(0, 10) == 1: 2216 tags += [StyledTextTag(StyledTextTagType.ITALIC, True, 2217 [(0, len(word))])] 2218 elif _randint(0, 10) == 1: 2219 tags += [StyledTextTag(StyledTextTagType.UNDERLINE, True, 2220 [(0, len(word))])] 2221 sword = StyledText(word, tags) 2222 if _randint(0, 20) == 1: 2223 sword = sword + "." 2224 elif _randint(0, 30) == 1: 2225 sword = sword + ".\n" 2226 result = StyledText("").join((result, sword)) 2227 else: 2228 result += word 2229 2230 if t_type == self.LASTNAME: 2231 case = _randint(0, 2) 2232 if case == 0: 2233 result = result.title() 2234 elif case == 1: 2235 result = result.upper() 2236 2237 if self.options_dict['add_linebreak'] and \ 2238 t_type != self.TAG: 2239 result = result + "\nNEWLINE" 2240 2241 return result 2242 2243 def rand_color(self): 2244 return '#%012X' % _randint(0, 281474976710655) 2245 2246 def rand_tags(self): 2247 maxtags = 5 2248 taglist = [] 2249 for dummy in range(0, _randint(1, maxtags)): 2250 tag = _choice(self.generated_tags) 2251 if tag not in taglist: 2252 taglist.append(tag) 2253 return taglist 2254 2255 2256# ----------------------------------------------------------------------- 2257# 2258# The options class for the tool 2259# 2260# ----------------------------------------------------------------------- 2261class TestcaseGeneratorOptions(tool.ToolOptions): 2262 """ 2263 Defines options and provides handling interface. 2264 """ 2265 2266 def __init__(self, name, person_id=None): 2267 tool.ToolOptions.__init__(self, name, person_id) 2268 2269 # Options specific for this report 2270 self.options_dict = { 2271 'lowlevel': 0, 2272 'bugs': 0, 2273 'persons': 1, 2274 'person_count': 2000, 2275 'long_names': 0, 2276 'specialchars': 0, 2277 'add_serial': 0, 2278 'add_linebreak': 0, 2279 } 2280 self.options_help = { 2281 'lowlevel': ("=0/1", 2282 "Whether to create low level database errors.", 2283 ["Skip test", 2284 "Create low level database errors"], 2285 True), 2286 'bugs': ("=0/1", 2287 "Whether to create invalid database references.", 2288 ["Skip test", 2289 "Create invalid Database references"], 2290 True), 2291 'persons': ("=0/1", 2292 "Whether to create a bunch of dummy persons", 2293 ["Dont create persons", "Create dummy persons"], 2294 True), 2295 'person_count': ("=int", 2296 "Number of dummy persons to generate", 2297 "Number of persons"), 2298 'long_names': ("=0/1", 2299 "Whether to create short or long names", 2300 ["Short names", "Long names"], 2301 True), 2302 'specialchars': ("=0/1", 2303 "Whether to ass some special characters to every" 2304 " text field", 2305 ["No special characters", 2306 "Add special characters"], 2307 True), 2308 'add_serial': ("=0/1", 2309 "Whether to add a serial number to every text " 2310 "field", 2311 ["No serial", "Add serial number"], 2312 True), 2313 'add_linebreak': ("=0/1", 2314 "Whether to add a line break to every text " 2315 "field", 2316 ["No linebreak", "Add line break"], 2317 True), 2318 } 2319