xref: /webtrees/tests/app/TreeTest.php (revision 953f11988d09a6cba4eb7cf9a517539ee72ed23c)
1<?php
2
3/**
4 * webtrees: online genealogy
5 * Copyright (C) 2019 webtrees development team
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18declare(strict_types=1);
19
20namespace Fisharebest\Webtrees;
21
22use Fisharebest\Webtrees\Functions\FunctionsImport;
23use Fisharebest\Webtrees\Services\TreeService;
24use Fisharebest\Webtrees\Services\UserService;
25use InvalidArgumentException;
26
27use function stream_get_contents;
28
29/**
30 * Test harness for the class Tree
31 */
32class TreeTest extends TestCase
33{
34    protected static $uses_database = true;
35
36    /**
37     * @covers \Fisharebest\Webtrees\Tree::__construct
38     * @covers \Fisharebest\Webtrees\Tree::create
39     * @covers \Fisharebest\Webtrees\Tree::id
40     * @covers \Fisharebest\Webtrees\Tree::name
41     * @covers \Fisharebest\Webtrees\Tree::title
42     * @return void
43     */
44    public function testConstructor(): void
45    {
46        $tree = Tree::create('tree-name', 'Tree title');
47
48        $this->assertSame('tree-name', $tree->name());
49        $this->assertSame('Tree title', $tree->title());
50    }
51
52    /**
53     * @covers \Fisharebest\Webtrees\Tree::getPreference
54     * @covers \Fisharebest\Webtrees\Tree::setPreference
55     * @return void
56     */
57    public function testTreePreferences(): void
58    {
59        $tree = Tree::create('tree-name', 'Tree title');
60
61        $pref = $tree->getPreference('foo', 'default');
62        $this->assertSame('default', $pref);
63
64        $tree->setPreference('foo', 'bar');
65        $pref = $tree->getPreference('foo', 'default');
66        $this->assertSame('bar', $pref);
67    }
68
69    /**
70     * @covers \Fisharebest\Webtrees\Tree::getUserPreference
71     * @covers \Fisharebest\Webtrees\Tree::setUserPreference
72     * @return void
73     */
74    public function testUserTreePreferences(): void
75    {
76        $user_service = new UserService();
77        $tree         = Tree::create('tree-name', 'Tree title');
78        $user         = $user_service->create('user', 'User', 'user@example.com', 'secret');
79
80        $pref = $tree->getUserPreference($user, 'foo', 'default');
81        $this->assertSame('default', $pref);
82
83        $tree->setUserPreference($user, 'foo', 'bar');
84        $pref = $tree->getUserPreference($user, 'foo', 'default');
85        $this->assertSame('bar', $pref);
86    }
87
88    /**
89     * @covers \Fisharebest\Webtrees\Tree::getNewXref
90     * @return void
91     */
92    public function testGetNewXref(): void
93    {
94        $tree_service = new TreeService();
95        $tree         = $tree_service->create('tree-name', 'Tree title');
96
97        // New trees have an individual X1.
98        $this->assertSame('X2', $tree->getNewXref());
99        $this->assertSame('X3', $tree->getNewXref());
100        $this->assertSame('X4', $tree->getNewXref());
101        $this->assertSame('X5', $tree->getNewXref());
102    }
103
104    /**
105     * @covers \Fisharebest\Webtrees\Tree::createIndividual
106     * @return void
107     */
108    public function testCreateInvalidIndividual(): void
109    {
110        $this->expectException(InvalidArgumentException::class);
111
112        $user_service = new UserService();
113        $tree         = Tree::create('tree-name', 'Tree title');
114        $user         = $user_service->create('user', 'User', 'user@example.com', 'secret');
115        $user->setPreference('canadmin', '1');
116        Auth::login($user);
117
118        $tree->createIndividual("0 @@ FOO\n1 SEX U");
119    }
120
121    /**
122     * @covers \Fisharebest\Webtrees\Tree::createIndividual
123     * @return void
124     */
125    public function testCreateIndividual(): void
126    {
127        $user_service = new UserService();
128        $tree         = Tree::create('tree-name', 'Tree title');
129        $user         = $user_service->create('user', 'User', 'user@example.com', 'secret');
130        $user->setPreference('canadmin', '1');
131        Auth::login($user);
132
133        $record = $tree->createIndividual("0 @@ INDI\n1 SEX F\n1 NAME Foo /Bar/");
134        $this->assertTrue($record->isPendingAddition());
135
136        $user->setPreference('auto_accept', '1');
137        $record = $tree->createIndividual("0 @@ INDI\n1 SEX F\n1 NAME Foo /Bar/");
138        $this->assertFalse($record->isPendingAddition());
139    }
140
141    /**
142     * @covers \Fisharebest\Webtrees\Tree::createFamily
143     * @return void
144     */
145    public function testCreateInvalidFamily(): void
146    {
147        $this->expectException(InvalidArgumentException::class);
148
149        $user_service = new UserService();
150        $tree         = Tree::create('tree-name', 'Tree title');
151        $user         = $user_service->create('user', 'User', 'user@example.com', 'secret');
152        $user->setPreference('canadmin', '1');
153        Auth::login($user);
154
155        $tree->createFamily("0 @@ FOO\n1 MARR Y");
156    }
157
158    /**
159     * @covers \Fisharebest\Webtrees\Tree::createFamily
160     * @return void
161     */
162    public function testCreateFamily(): void
163    {
164        $user_service = new UserService();
165        $tree         = Tree::create('tree-name', 'Tree title');
166        $user         = $user_service->create('user', 'User', 'user@example.com', 'secret');
167        $user->setPreference('canadmin', '1');
168        Auth::login($user);
169
170        $record = $tree->createFamily("0 @@ FAM\n1 MARR Y");
171        $this->assertTrue($record->isPendingAddition());
172
173        $user->setPreference('auto_accept', '1');
174        $record = $tree->createFamily("0 @@ FAM\n1 MARR Y");
175        $this->assertFalse($record->isPendingAddition());
176    }
177
178    /**
179     * @covers \Fisharebest\Webtrees\Tree::createMediaObject
180     * @return void
181     */
182    public function testCreateInvalidMediaObject(): void
183    {
184        $this->expectException(InvalidArgumentException::class);
185
186        $user_service = new UserService();
187        $tree         = Tree::create('tree-name', 'Tree title');
188        $user         = $user_service->create('user', 'User', 'user@example.com', 'secret');
189        $user->setPreference('canadmin', '1');
190        Auth::login($user);
191
192        $tree->createMediaObject("0 @@ FOO\n1 MARR Y");
193    }
194
195    /**
196     * @covers \Fisharebest\Webtrees\Tree::createMediaObject
197     * @return void
198     */
199    public function testCreateMediaObject(): void
200    {
201        $user_service = new UserService();
202        $tree         = Tree::create('tree-name', 'Tree title');
203        $user         = $user_service->create('user', 'User', 'user@example.com', 'secret');
204        $user->setPreference('canadmin', '1');
205        Auth::login($user);
206
207        $record = $tree->createMediaObject("0 @@ OBJE\n1 FILE foo.jpeg");
208        $this->assertTrue($record->isPendingAddition());
209
210        $user->setPreference('auto_accept', '1');
211        $record = $tree->createMediaObject("0 @@ OBJE\n1 FILE foo.jpeg");
212        $this->assertFalse($record->isPendingAddition());
213    }
214
215    /**
216     * @covers \Fisharebest\Webtrees\Tree::createRecord
217     * @return void
218     */
219    public function testCreateInvalidRecord(): void
220    {
221        $this->expectException(InvalidArgumentException::class);
222
223        $user_service = new UserService();
224        $tree         = Tree::create('tree-name', 'Tree title');
225        $user         = $user_service->create('user', 'User', 'user@example.com', 'secret');
226        $user->setPreference('canadmin', '1');
227        Auth::login($user);
228
229        $tree->createRecord("0 @@FOO\n1 NOTE noted");
230    }
231
232    /**
233     * @covers \Fisharebest\Webtrees\Tree::createRecord
234     * @return void
235     */
236    public function testCreateRecord(): void
237    {
238        $user_service = new UserService();
239        $tree         = Tree::create('tree-name', 'Tree title');
240        $user         = $user_service->create('user', 'User', 'user@example.com', 'secret');
241        $user->setPreference('canadmin', '1');
242        Auth::login($user);
243
244        $record = $tree->createRecord("0 @@ FOO\n1 NOTE noted");
245        $this->assertTrue($record->isPendingAddition());
246
247        $user->setPreference('auto_accept', '1');
248        $record = $tree->createRecord("0 @@ FOO\n1 NOTE noted");
249        $this->assertFalse($record->isPendingAddition());
250    }
251
252    /**
253     * @covers \Fisharebest\Webtrees\Tree::significantIndividual
254     * @return void
255     */
256    public function testSignificantIndividual(): void
257    {
258        $user_service = new UserService();
259        $tree         = Tree::create('tree-name', 'Tree title');
260        $user         = $user_service->create('user', 'User', 'user@example.com', 'secret');
261        $user->setPreference('auto_accept', '1');
262        Auth::login($user);
263
264        // Delete the tree's default individual.
265        FunctionsImport::updateRecord('0 @X1@ INDI', $tree, true);
266
267        // No individuals in tree?  Dummy individual
268        $this->assertSame('I', $tree->significantIndividual($user)->xref());
269
270        $record1 = $tree->createIndividual("0 @@ INDI\n1 SEX F\n1 NAME Foo /Bar/");
271        $record2 = $tree->createIndividual("0 @@ INDI\n1 SEX F\n1 NAME Foo /Bar/");
272        $record3 = $tree->createIndividual("0 @@ INDI\n1 SEX F\n1 NAME Foo /Bar/");
273        $record4 = $tree->createIndividual("0 @@ INDI\n1 SEX F\n1 NAME Foo /Bar/");
274
275        // Individuals exist?  First one (lowest XREF).
276        $this->assertSame($record1->xref(), $tree->significantIndividual($user)->xref());
277
278        // Preference for tree?
279        $tree->setPreference('PEDIGREE_ROOT_ID', $record2->xref());
280        $this->assertSame($record2->xref(), $tree->significantIndividual($user)->xref());
281
282        // User preference
283        $tree->setUserPreference($user, 'gedcomid', $record3->xref());
284        $this->assertSame($record3->xref(), $tree->significantIndividual($user)->xref());
285
286        // User record
287        $tree->setUserPreference($user, 'rootid', $record4->xref());
288        $this->assertSame($record4->xref(), $tree->significantIndividual($user)->xref());
289    }
290
291    /**
292     * @covers \Fisharebest\Webtrees\Tree::importGedcomFile
293     * @covers \Fisharebest\Webtrees\Tree::deleteGenealogyData
294     * @return void
295     */
296    public function testImportAndDeleteGedcomFile(): void
297    {
298        $tree_service = new TreeService();
299        $tree = $this->importTree('demo.ged');
300        $this->assertNotNull($tree_service->findByName('demo.ged'));
301        Site::setPreference('DEFAULT_GEDCOM', $tree->name());
302
303        $tree_service->delete($tree);
304
305        $this->assertNull($tree_service->findByName('demo.ged'));
306        $this->assertSame('', Site::getPreference('DEFAULT_GEDCOM'));
307    }
308
309    /**
310     * @covers \Fisharebest\Webtrees\Tree::hasPendingEdit
311     * @return void
312     */
313    public function testHasPendingEdits(): void
314    {
315        $user_service = new UserService();
316        $tree         = $this->importTree('demo.ged');
317        $user         = $user_service->create('admin', 'Administrator', 'admin@example.com', 'secret');
318        $user->setPreference('canadmin', '1');
319        Auth::login($user);
320
321        $user->setPreference('auto_accept', '1');
322        $tree->createIndividual("0 @@ INDI\n1 SEX F\n1 NAME Foo /Bar/");
323        $this->assertFalse($tree->hasPendingEdit());
324
325        $user->setPreference('auto_accept', '0');
326        $tree->createIndividual("0 @@ INDI\n1 SEX F\n1 NAME Foo /Bar/");
327        $this->assertTrue($tree->hasPendingEdit());
328    }
329
330    /**
331     * @covers \Fisharebest\Webtrees\Tree::exportGedcom
332     * @return void
333     */
334    public function testExportGedcom(): void
335    {
336        $tree = $this->importTree('demo.ged');
337
338        $fp = fopen('php://memory', 'wb');
339
340        $tree->exportGedcom($fp);
341
342        rewind($fp);
343
344        $original = file_get_contents(__DIR__ . '/../data/demo.ged');
345        $export   = stream_get_contents($fp);
346
347        // The date and time in the HEAD record will be different.
348        $original = preg_replace('/\n1 DATE .. ... ..../', '', $original, 1);
349        $export   = preg_replace('/\n1 DATE .. ... ..../', '', $export, 1);
350        $original = preg_replace('/\n2 TIME ..:..:../', '', $original, 1);
351        $export   = preg_replace('/\n2 TIME ..:..:../', '', $export, 1);
352
353        $this->assertSame($original, $export);
354    }
355}
356