Avoid memory corruption with a large number of families.
[gedcom-parse.git] / t / src / update_gom.c
1 /* Test program for the Gedcom library.
2    Copyright (C) 2001, 2002 The Genes Development Team
3    This file is part of the Gedcom parser library.
4    Contributed by Peter Verthez <Peter.Verthez@advalvas.be>, 2001.
5
6    The Gedcom parser library is free software; you can redistribute it
7    and/or modify it under the terms of the GNU Lesser General Public
8    License as published by the Free Software Foundation; either
9    version 2.1 of the License, or (at your option) any later version.
10
11    The Gedcom parser library is distributed in the hope that it will be
12    useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14    Lesser General Public License for more details.
15
16    You should have received a copy of the GNU Lesser General Public
17    License along with the Gedcom parser library; if not, write to the
18    Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19    02111-1307 USA.  */
20
21 /* $Id$ */
22 /* $Name$ */
23
24 #include "gedcom.h"
25 #include "gom.h"
26 #include "output.h"
27 #include "dump_gom.h"
28 #include "portability.h"
29 #include "string.h"
30 #include <locale.h>
31 #include <stdio.h>
32
33 void gedcom_message_handler(Gedcom_msg_type type, char *msg)
34 {
35   if (type == MESSAGE)
36     output(1, "MESSAGE: ");
37   else if (type == WARNING)
38     output(1, "WARNING: ");
39   else if (type == ERROR)
40     output(1, "ERROR: ");
41   output(1, "%s\n", msg);
42 }
43
44 void show_help ()
45 {
46   printf("gedcom-parse test program for libgedcom\n\n");
47   printf("Usage:  updategomtest [options]\n");
48   printf("Options:\n");
49   printf("  -h    Show this help text\n");
50   printf("  -q    No output to standard output\n");
51   printf("  -o <outfile>  File to generate output to (def. testgedcom.out)\n");
52 }
53
54 int test_string_functions()
55 {
56   struct header* head;
57   struct submitter* subm;
58   struct xref_value* xref;
59   char* value;
60   int conv_fails = 0;
61   const char* orig_source_id = "GEDCOM_PARSE";
62   const char* new_source_id = "TEST_UPDATE";
63   const char* new_submitter_name_utf8 = "Belgi\xC3\xAB";
64   const char* new_submitter_name_ansi = "Belgi\xEB";
65
66   head = gom_get_header();
67   if (head == NULL)
68     return 10;
69   
70   value = gom_get_string(head->source.id);
71   if (value == NULL)
72     return 11;
73   if (strcmp(value, orig_source_id))
74     return 12;
75
76   value = gom_set_string(&head->source.id, new_source_id);
77   if (value == NULL)
78     return 13;
79   if (strcmp(value, new_source_id))
80     return 14;
81
82   value = gom_get_string(head->source.id);
83   if (value == NULL)
84     return 15;
85   if (strcmp(value, new_source_id))
86     return 16;
87
88   xref = head->submitter;
89   if (xref == NULL)
90     return 17;
91   
92   subm = gom_get_submitter_by_xref(xref->string);
93   if (subm == NULL)
94     return 18;
95
96   value = gom_set_string(&subm->name, new_submitter_name_utf8);
97   if (value == NULL)
98     return 19;
99   if (strcmp(value, new_submitter_name_utf8))
100     return 20;
101
102   value = gom_get_string_for_locale(subm->name, &conv_fails);
103   if (value == NULL)
104     return 21;
105   if (!strcmp(value, new_submitter_name_utf8))
106     return 22;
107   if (conv_fails != 1)
108     return 23;
109
110   value = gom_set_string(&subm->name, new_submitter_name_ansi);
111   if (value != NULL)
112     return 24;
113   
114   value = gom_set_string_for_locale(&subm->name, new_submitter_name_ansi);
115   if (value != NULL)
116     return 25;
117
118   return 0;
119 }
120
121 char* print_date(const char* message, struct date_value* dv)
122 {
123   char* date_str;
124   output(0, "\n%s:", message);
125   show_date(dv);
126   date_str = gedcom_date_to_string(dv);
127   output(0, "String: '%s'\n", str_val(date_str));
128   return date_str;
129 }
130
131 int test_date_functions()
132 {
133   struct header* head;
134   struct date_value* dv;
135   char* date_str;
136   int normalized;
137   
138   head = gom_get_header();
139   if (head == NULL)
140     return 50;
141
142   dv = head->date;
143   if (dv != NULL)
144     return 51;
145
146   dv = gedcom_new_date_value(NULL);
147   if (dv == NULL)
148     return 52;
149
150   head->date = dv;
151   date_str = print_date("Initial date value", dv);
152   if (date_str[0])
153     return 53;
154
155   dv->date1.cal = CAL_GREGORIAN;
156   strcpy(dv->date1.year_str, "1990");
157   normalized = gedcom_normalize_date(DI_FROM_STRINGS, dv);
158   if (normalized != 0)
159     return 54;
160   date_str = print_date("Setting only year string", dv);
161   if (! date_str[0])
162     return 55;
163
164   dv->date1.year = 1989;
165   normalized = gedcom_normalize_date(DI_FROM_NUMBERS, dv);
166   if (normalized != 0)
167     return 56;
168   date_str = print_date("Setting only year number", dv);
169   if (! date_str[0])
170     return 57;
171
172   dv->date1.type = DATE_EXACT;
173   dv->date1.sdn1 = 2500000;
174   dv->date1.sdn2 = -1;
175   normalized = gedcom_normalize_date(DI_FROM_SDN, dv);
176   if (normalized != 0)
177     return 58;
178   date_str = print_date("Setting only SDN 1", dv);
179   if (! date_str[0])
180     return 59;
181
182   dv->date1.cal = CAL_HEBREW;
183   normalized = gedcom_normalize_date(DI_FROM_SDN, dv);  
184   if (normalized != 0)
185     return 60;
186   date_str = print_date("Same date in Hebrew calendar", dv);
187   if (! date_str[0])
188     return 61;
189
190   dv->date1.cal = CAL_FRENCH_REV;
191   normalized = gedcom_normalize_date(DI_FROM_SDN, dv);  
192   if (normalized == 0)
193     return 62;
194   date_str = print_date("Same date in French revolution calendar", dv);
195   if (date_str[0])
196     return 63;
197
198   dv->date1.cal = CAL_GREGORIAN;
199   dv->date1.day = 4;
200   dv->date1.month = 2;
201   dv->date1.year = 1799;
202   normalized = gedcom_normalize_date(DI_FROM_NUMBERS, dv);
203   if (normalized != 0)
204     return 64;
205   dv->date1.cal = CAL_FRENCH_REV;
206   normalized = gedcom_normalize_date(DI_FROM_SDN, dv);
207   if (normalized != 0)
208     return 65;
209   date_str = print_date("Valid French revolution date", dv);
210   if (! date_str[0])
211     return 66;
212
213   return 0;
214 }
215
216 int test_record_add_delete_functions()
217 {
218   struct family* fam1;
219   struct individual *ind1, *ind2, *ind3, *ind4;
220   struct multimedia* mm1;
221   struct note* note1;
222   struct repository* repo1;
223   struct source* sour1;
224   struct submitter* subm2;
225   struct submission* subn1;
226   struct user_rec* user1;
227   struct xref_value* xr;
228   struct xref_list* xrl;
229   int result;
230   char* value;
231   const char* new_nr_of_children = "3";
232   const char* note_text = "This is some text";
233
234   fam1 = gom_new_family("@FAM1@");
235   if (!fam1) return 101;
236   
237   value = gom_set_string(&fam1->nr_of_children, new_nr_of_children);
238   if (value == NULL)
239     return 102;
240   if (strcmp(value, new_nr_of_children))
241     return 103;
242
243   ind1 = gom_new_individual("@FAM1@");
244   if (ind1) return 104;
245
246   ind1 = gom_new_individual("@IND1@");
247   if (!ind1) return 105;
248
249   mm1 = gom_new_multimedia("@OBJ1@");
250   if (!mm1) return 106;
251
252   note1 = gom_new_note("@NOTE1@");
253   if (!note1) return 107;
254   
255   value = gom_set_string(&note1->text, note_text);
256   if (value == NULL)
257     return 108;
258   if (strcmp(value, note_text))
259     return 109;
260
261   repo1 = gom_new_repository("@REPO1@");
262   if (!repo1) return 110;
263
264   sour1 = gom_new_source("@SOUR1@");
265   if (!sour1) return 111;
266
267   subm2 = gom_new_submitter("@SUBMITTER@");
268   if (subm2) return 112;
269
270   subm2 = gom_new_submitter("@SUBM2@");
271   if (!subm2) return 113;
272
273   subn1 = gom_new_submission("@SUBMISSION@");
274   if (!subn1) return 114;
275
276   user1 = gom_new_user_rec("@USER1@", "WRTAG");
277   if (user1) return 115;
278
279   user1 = gom_new_user_rec("@USER1@", "_TAG");
280   if (!user1) return 116;
281
282   xr = gom_set_xref(&(fam1->husband), ind1->xrefstr);
283   if (!xr) return 118;
284
285   ind2 = gom_new_individual("@IND2@");
286   if (!ind2) return 119;
287
288   ind3 = gom_new_individual("@IND3@");
289   if (!ind3) return 120;
290
291   ind4 = gom_new_individual("@IND4@");
292   if (!ind4) return 121;
293
294   xrl = gom_add_xref(&(fam1->children), ind2->xrefstr);
295   if (!xrl) return 122;
296
297   xrl = gom_add_xref(&(fam1->children), ind3->xrefstr);
298   if (!xrl) return 123;
299
300   xrl = gom_add_xref(&(fam1->children), ind4->xrefstr);
301   if (!xrl) return 124;
302
303   result = gom_move_xref(MOVE_UP, &(fam1->children), ind4->xrefstr);
304   if (result != 0) return 127;
305
306   result = gom_move_xref(MOVE_UP, &(fam1->children), ind4->xrefstr);
307   if (result != 0) return 128;
308
309   result = gom_move_xref(MOVE_UP, &(fam1->children), ind4->xrefstr);
310   if (result != 0) return 129;
311
312   result = gom_move_xref(MOVE_DOWN, &(fam1->children), ind4->xrefstr);
313   if (result != 0) return 130;
314
315   result = gom_remove_xref(&(fam1->children), ind3->xrefstr);
316   if (result != 0) return 125;
317
318   result = gom_remove_xref(&(fam1->children), ind4->xrefstr);
319   if (result != 0) return 126;
320
321   output(1, "Intermediate output:\n");
322   show_data();
323
324   result = gom_delete_individual(ind1);
325   if (result == 0) return 150;
326
327   xr = gom_set_xref(&(fam1->husband), NULL);
328   if (xr) return 151;
329
330   result = gom_delete_individual(ind1);
331   if (result != 0) return 152;
332
333   result = gom_delete_family(fam1);
334   if (result != 0) return 153;
335
336   result = gom_delete_individual(ind2);
337   if (result != 0) return 154;
338
339   result = gom_delete_multimedia(mm1);
340   if (result != 0) return 155;
341
342   result = gom_delete_note(note1);
343   if (result != 0) return 156;
344
345   result = gom_delete_repository(repo1);
346   if (result != 0) return 157;
347
348   result = gom_delete_source(sour1);
349   if (result != 0) return 158;
350
351   result = gom_delete_submitter(subm2);
352   if (result != 0) return 159;
353
354   result = gom_delete_submission(subn1);
355   if (result != 0) return 160;
356
357   result = gom_delete_user_rec(user1);
358   if (result != 0) return 161;
359   
360   return 0;
361 }
362
363 int main(int argc, char* argv[])
364 {
365   int result;
366   char* outfilename = NULL;
367   
368   if (argc > 1) {
369     int i;
370     for (i=1; i<argc; i++) {
371       if (!strncmp(argv[i], "-h", 3)) {
372         show_help();
373         exit(1);
374       }
375       else if (!strncmp(argv[i], "-q", 3)) {
376         output_set_quiet(1);
377       }
378       else if (!strncmp(argv[i], "-o", 3)) {
379         i++;
380         if (i < argc) {
381           outfilename = argv[i];
382         }
383         else {
384           printf ("Missing output file name\n");
385           show_help();
386           exit(1);
387         }
388       }
389       else {
390         printf ("Unrecognized option: %s\n", argv[i]);
391         show_help();
392         exit(1);
393       }
394     }
395   }
396   
397   gedcom_init();
398   setlocale(LC_ALL, "");
399   gedcom_set_message_handler(gedcom_message_handler);
400
401   output_open(outfilename);
402   
403   result = gom_new_model();
404   if (result == 0)
405     result |= test_string_functions();
406   if (result == 0)
407     result |= test_date_functions();
408   if (result == 0)
409     result |= test_record_add_delete_functions();
410   if (result == 0) {
411     output(1, "Test succeeded\n");
412   }
413   else {
414     output(1, "Test failed: %d\n", result);
415   }
416
417   show_data();
418   output_close();
419   return result;
420 }