xref: /webtrees/tests/app/TreeTest.php (revision 5afbc57a5c33b9caec67458db57f44e54a90f745)
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 */
17declare(strict_types=1);
18
19namespace Fisharebest\Webtrees;
20
21use Fisharebest\Webtrees\Functions\FunctionsImport;
22use Fisharebest\Webtrees\Services\TreeService;
23use Fisharebest\Webtrees\Services\UserService;
24use InvalidArgumentException;
25
26use function stream_get_contents;
27
28/**
29 * Test harness for the class Tree
30 */
31class TreeTest extends TestCase
32{
33    protected static $uses_database = true;
34
35    /**
36     * @covers \Fisharebest\Webtrees\Tree::__construct
37     * @covers \Fisharebest\Webtrees\Tree::create
38     * @covers \Fisharebest\Webtrees\Tree::id
39     * @covers \Fisharebest\Webtrees\Tree::name
40     * @covers \Fisharebest\Webtrees\Tree::title
41     * @return void
42     */
43    public function testConstructor(): void
44    {
45        $tree = Tree::create('tree-name', 'Tree title');
46
47        $this->assertSame('tree-name', $tree->name());
48        $this->assertSame('Tree title', $tree->title());
49    }
50
51    /**
52     * @covers \Fisharebest\Webtrees\Tree::getPreference
53     * @covers \Fisharebest\Webtrees\Tree::setPreference
54     * @return void
55     */
56    public function testTreePreferences(): void
57    {
58        $tree = Tree::create('tree-name', 'Tree title');
59
60        $pref = $tree->getPreference('foo', 'default');
61        $this->assertSame('default', $pref);
62
63        $tree->setPreference('foo', 'bar');
64        $pref = $tree->getPreference('foo', 'default');
65        $this->assertSame('bar', $pref);
66    }
67
68    /**
69     * @covers \Fisharebest\Webtrees\Tree::getUserPreference
70     * @covers \Fisharebest\Webtrees\Tree::setUserPreference
71     * @return void
72     */
73    public function testUserTreePreferences(): void
74    {
75        $user_service = new UserService();
76        $tree         = Tree::create('tree-name', 'Tree title');
77        $user         = $user_service->create('user', 'User', 'user@example.com', 'secret');
78
79        $pref = $tree->getUserPreference($user, 'foo', 'default');
80        $this->assertSame('default', $pref);
81
82        $tree->setUserPreference($user, 'foo', 'bar');
83        $pref = $tree->getUserPreference($user, 'foo', 'default');
84        $this->assertSame('bar', $pref);
85    }
86
87    /**
88     * @covers \Fisharebest\Webtrees\Tree::getNewXref
89     * @return void
90     */
91    public function testGetNewXref(): void
92    {
93        $tree_service = new TreeService();
94        $tree         = $tree_service->create('tree-name', 'Tree title');
95
96        // New trees have an individual X1.
97        $this->assertSame('X2', $tree->getNewXref());
98        $this->assertSame('X3', $tree->getNewXref());
99        $this->assertSame('X4', $tree->getNewXref());
100        $this->assertSame('X5', $tree->getNewXref());
101    }
102
103    /**
104     * @covers \Fisharebest\Webtrees\Tree::createIndividual
105     * @return void
106     */
107    public function testCreateInvalidIndividual(): void
108    {
109        $this->expectException(InvalidArgumentException::class);
110
111        $user_service = new UserService();
112        $tree         = Tree::create('tree-name', 'Tree title');
113        $user         = $user_service->create('user', 'User', 'user@example.com', 'secret');
114        $user->setPreference('canadmin', '1');
115        Auth::login($user);
116
117        $tree->createIndividual("0 @@ FOO\n1 SEX U");
118    }
119
120    /**
121     * @covers \Fisharebest\Webtrees\Tree::createIndividual
122     * @return void
123     */
124    public function testCreateIndividual(): void
125    {
126        $user_service = new UserService();
127        $tree         = Tree::create('tree-name', 'Tree title');
128        $user         = $user_service->create('user', 'User', 'user@example.com', 'secret');
129        $user->setPreference('canadmin', '1');
130        Auth::login($user);
131
132        $record = $tree->createIndividual("0 @@ INDI\n1 SEX F\n1 NAME Foo /Bar/");
133        $this->assertTrue($record->isPendingAddition());
134
135        $user->setPreference('auto_accept', '1');
136        $record = $tree->createIndividual("0 @@ INDI\n1 SEX F\n1 NAME Foo /Bar/");
137        $this->assertFalse($record->isPendingAddition());
138    }
139
140    /**
141     * @covers \Fisharebest\Webtrees\Tree::createFamily
142     * @return void
143     */
144    public function testCreateInvalidFamily(): void
145    {
146        $this->expectException(InvalidArgumentException::class);
147
148        $user_service = new UserService();
149        $tree         = Tree::create('tree-name', 'Tree title');
150        $user         = $user_service->create('user', 'User', 'user@example.com', 'secret');
151        $user->setPreference('canadmin', '1');
152        Auth::login($user);
153
154        $tree->createFamily("0 @@ FOO\n1 MARR Y");
155    }
156
157    /**
158     * @covers \Fisharebest\Webtrees\Tree::createFamily
159     * @return void
160     */
161    public function testCreateFamily(): void
162    {
163        $user_service = new UserService();
164        $tree         = Tree::create('tree-name', 'Tree title');
165        $user         = $user_service->create('user', 'User', 'user@example.com', 'secret');
166        $user->setPreference('canadmin', '1');
167        Auth::login($user);
168
169        $record = $tree->createFamily("0 @@ FAM\n1 MARR Y");
170        $this->assertTrue($record->isPendingAddition());
171
172        $user->setPreference('auto_accept', '1');
173        $record = $tree->createFamily("0 @@ FAM\n1 MARR Y");
174        $this->assertFalse($record->isPendingAddition());
175    }
176
177    /**
178     * @covers \Fisharebest\Webtrees\Tree::createMediaObject
179     * @return void
180     */
181    public function testCreateInvalidMediaObject(): void
182    {
183        $this->expectException(InvalidArgumentException::class);
184
185        $user_service = new UserService();
186        $tree         = Tree::create('tree-name', 'Tree title');
187        $user         = $user_service->create('user', 'User', 'user@example.com', 'secret');
188        $user->setPreference('canadmin', '1');
189        Auth::login($user);
190
191        $tree->createMediaObject("0 @@ FOO\n1 MARR Y");
192    }
193
194    /**
195     * @covers \Fisharebest\Webtrees\Tree::createMediaObject
196     * @return void
197     */
198    public function testCreateMediaObject(): void
199    {
200        $user_service = new UserService();
201        $tree         = Tree::create('tree-name', 'Tree title');
202        $user         = $user_service->create('user', 'User', 'user@example.com', 'secret');
203        $user->setPreference('canadmin', '1');
204        Auth::login($user);
205
206        $record = $tree->createMediaObject("0 @@ OBJE\n1 FILE foo.jpeg");
207        $this->assertTrue($record->isPendingAddition());
208
209        $user->setPreference('auto_accept', '1');
210        $record = $tree->createMediaObject("0 @@ OBJE\n1 FILE foo.jpeg");
211        $this->assertFalse($record->isPendingAddition());
212    }
213
214    /**
215     * @covers \Fisharebest\Webtrees\Tree::createRecord
216     * @return void
217     */
218    public function testCreateInvalidRecord(): void
219    {
220        $this->expectException(InvalidArgumentException::class);
221
222        $user_service = new UserService();
223        $tree         = Tree::create('tree-name', 'Tree title');
224        $user         = $user_service->create('user', 'User', 'user@example.com', 'secret');
225        $user->setPreference('canadmin', '1');
226        Auth::login($user);
227
228        $tree->createRecord("0 @@FOO\n1 NOTE noted");
229    }
230
231    /**
232     * @covers \Fisharebest\Webtrees\Tree::createRecord
233     * @return void
234     */
235    public function testCreateRecord(): void
236    {
237        $user_service = new UserService();
238        $tree         = Tree::create('tree-name', 'Tree title');
239        $user         = $user_service->create('user', 'User', 'user@example.com', 'secret');
240        $user->setPreference('canadmin', '1');
241        Auth::login($user);
242
243        $record = $tree->createRecord("0 @@ FOO\n1 NOTE noted");
244        $this->assertTrue($record->isPendingAddition());
245
246        $user->setPreference('auto_accept', '1');
247        $record = $tree->createRecord("0 @@ FOO\n1 NOTE noted");
248        $this->assertFalse($record->isPendingAddition());
249    }
250
251    /**
252     * @covers \Fisharebest\Webtrees\Tree::significantIndividual
253     * @return void
254     */
255    public function testSignificantIndividual(): void
256    {
257        $user_service = new UserService();
258        $tree         = Tree::create('tree-name', 'Tree title');
259        $user         = $user_service->create('user', 'User', 'user@example.com', 'secret');
260        $user->setPreference('auto_accept', '1');
261        Auth::login($user);
262
263        // Delete the tree's default individual.
264        FunctionsImport::updateRecord('0 @X1@ INDI', $tree, true);
265
266        // No individuals in tree?  Dummy individual
267        $this->assertSame('I', $tree->significantIndividual($user)->xref());
268
269        $record1 = $tree->createIndividual("0 @@ INDI\n1 SEX F\n1 NAME Foo /Bar/");
270        $record2 = $tree->createIndividual("0 @@ INDI\n1 SEX F\n1 NAME Foo /Bar/");
271        $record3 = $tree->createIndividual("0 @@ INDI\n1 SEX F\n1 NAME Foo /Bar/");
272        $record4 = $tree->createIndividual("0 @@ INDI\n1 SEX F\n1 NAME Foo /Bar/");
273
274        // Individuals exist?  First one (lowest XREF).
275        $this->assertSame($record1->xref(), $tree->significantIndividual($user)->xref());
276
277        // Preference for tree?
278        $tree->setPreference('PEDIGREE_ROOT_ID', $record2->xref());
279        $this->assertSame($record2->xref(), $tree->significantIndividual($user)->xref());
280
281        // User preference
282        $tree->setUserPreference($user, 'gedcomid', $record3->xref());
283        $this->assertSame($record3->xref(), $tree->significantIndividual($user)->xref());
284
285        // User record
286        $tree->setUserPreference($user, 'rootid', $record4->xref());
287        $this->assertSame($record4->xref(), $tree->significantIndividual($user)->xref());
288    }
289
290    /**
291     * @covers \Fisharebest\Webtrees\Tree::importGedcomFile
292     * @covers \Fisharebest\Webtrees\Tree::deleteGenealogyData
293     * @return void
294     */
295    public function testImportAndDeleteGedcomFile(): void
296    {
297        $tree_service = new TreeService();
298        $tree = $this->importTree('demo.ged');
299        $this->assertNotNull($tree_service->findByName('demo.ged'));
300        Site::setPreference('DEFAULT_GEDCOM', $tree->name());
301
302        $tree_service->delete($tree);
303        app('cache.array')->flush();
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