xref: /webtrees/tests/app/TreeTest.php (revision 00b1984e374faddab4698e73088f0c964e529b65)
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::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_service = new TreeService();
46        $tree         = $tree_service->create('name', 'title');
47
48        $this->assertSame('name', $tree->name());
49        $this->assertSame('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_service = new TreeService();
60        $tree         = $tree_service->create('name', 'title');
61
62        $pref = $tree->getPreference('foo', 'default');
63        $this->assertSame('default', $pref);
64
65        $tree->setPreference('foo', 'bar');
66        $pref = $tree->getPreference('foo', 'default');
67        $this->assertSame('bar', $pref);
68    }
69
70    /**
71     * @covers \Fisharebest\Webtrees\Tree::getUserPreference
72     * @covers \Fisharebest\Webtrees\Tree::setUserPreference
73     * @return void
74     */
75    public function testUserTreePreferences(): void
76    {
77        $user_service = new UserService();
78        $tree_service = new TreeService();
79        $tree         = $tree_service->create('name', 'title');
80        $user         = $user_service->create('user', 'User', 'user@example.com', 'secret');
81
82        $pref = $tree->getUserPreference($user, 'foo', 'default');
83        $this->assertSame('default', $pref);
84
85        $tree->setUserPreference($user, 'foo', 'bar');
86        $pref = $tree->getUserPreference($user, 'foo', 'default');
87        $this->assertSame('bar', $pref);
88    }
89
90    /**
91     * @covers \Fisharebest\Webtrees\Tree::getNewXref
92     * @return void
93     */
94    public function testGetNewXref(): void
95    {
96        $tree_service = new TreeService();
97        $tree         = $tree_service->create('tree-name', 'Tree title');
98
99        // New trees have an individual X1.
100        $this->assertSame('X2', $tree->getNewXref());
101        $this->assertSame('X3', $tree->getNewXref());
102        $this->assertSame('X4', $tree->getNewXref());
103        $this->assertSame('X5', $tree->getNewXref());
104    }
105
106    /**
107     * @covers \Fisharebest\Webtrees\Tree::createIndividual
108     * @return void
109     */
110    public function testCreateInvalidIndividual(): void
111    {
112        $this->expectException(InvalidArgumentException::class);
113
114        $user_service = new UserService();
115        $tree_service = new TreeService();
116        $tree         = $tree_service->create('name', 'title');
117        $user         = $user_service->create('user', 'User', 'user@example.com', 'secret');
118        $user->setPreference(User::PREF_IS_ADMINISTRATOR, '1');
119        Auth::login($user);
120
121        $tree->createIndividual("0 @@ FOO\n1 SEX U");
122    }
123
124    /**
125     * @covers \Fisharebest\Webtrees\Tree::createIndividual
126     * @return void
127     */
128    public function testCreateIndividual(): void
129    {
130        $user_service = new UserService();
131        $tree_service = new TreeService();
132        $tree         = $tree_service->create('name', 'title');
133        $user         = $user_service->create('user', 'User', 'user@example.com', 'secret');
134        $user->setPreference(User::PREF_IS_ADMINISTRATOR, '1');
135        Auth::login($user);
136
137        $record = $tree->createIndividual("0 @@ INDI\n1 SEX F\n1 NAME Foo /Bar/");
138        $this->assertTrue($record->isPendingAddition());
139
140        $user->setPreference(User::PREF_AUTO_ACCEPT_EDITS, '1');
141        $record = $tree->createIndividual("0 @@ INDI\n1 SEX F\n1 NAME Foo /Bar/");
142        $this->assertFalse($record->isPendingAddition());
143    }
144
145    /**
146     * @covers \Fisharebest\Webtrees\Tree::createFamily
147     * @return void
148     */
149    public function testCreateInvalidFamily(): void
150    {
151        $this->expectException(InvalidArgumentException::class);
152
153        $user_service = new UserService();
154        $tree_service = new TreeService();
155        $tree         = $tree_service->create('name', 'title');
156        $user         = $user_service->create('user', 'User', 'user@example.com', 'secret');
157        $user->setPreference(User::PREF_IS_ADMINISTRATOR, '1');
158        Auth::login($user);
159
160        $tree->createFamily("0 @@ FOO\n1 MARR Y");
161    }
162
163    /**
164     * @covers \Fisharebest\Webtrees\Tree::createFamily
165     * @return void
166     */
167    public function testCreateFamily(): void
168    {
169        $user_service = new UserService();
170        $tree_service = new TreeService();
171        $tree         = $tree_service->create('name', 'title');
172        $user         = $user_service->create('user', 'User', 'user@example.com', 'secret');
173        $user->setPreference(User::PREF_IS_ADMINISTRATOR, '1');
174        Auth::login($user);
175
176        $record = $tree->createFamily("0 @@ FAM\n1 MARR Y");
177        $this->assertTrue($record->isPendingAddition());
178
179        $user->setPreference(User::PREF_AUTO_ACCEPT_EDITS, '1');
180        $record = $tree->createFamily("0 @@ FAM\n1 MARR Y");
181        $this->assertFalse($record->isPendingAddition());
182    }
183
184    /**
185     * @covers \Fisharebest\Webtrees\Tree::createMediaObject
186     * @return void
187     */
188    public function testCreateInvalidMediaObject(): void
189    {
190        $this->expectException(InvalidArgumentException::class);
191
192        $user_service = new UserService();
193        $tree_service = new TreeService();
194        $tree         = $tree_service->create('name', 'title');
195        $user         = $user_service->create('user', 'User', 'user@example.com', 'secret');
196        $user->setPreference(User::PREF_IS_ADMINISTRATOR, '1');
197        Auth::login($user);
198
199        $tree->createMediaObject("0 @@ FOO\n1 MARR Y");
200    }
201
202    /**
203     * @covers \Fisharebest\Webtrees\Tree::createMediaObject
204     * @return void
205     */
206    public function testCreateMediaObject(): void
207    {
208        $user_service = new UserService();
209        $tree_service = new TreeService();
210        $tree         = $tree_service->create('name', 'title');
211        $user         = $user_service->create('user', 'User', 'user@example.com', 'secret');
212        $user->setPreference(User::PREF_IS_ADMINISTRATOR, '1');
213        Auth::login($user);
214
215        $record = $tree->createMediaObject("0 @@ OBJE\n1 FILE foo.jpeg");
216        $this->assertTrue($record->isPendingAddition());
217
218        $user->setPreference(User::PREF_AUTO_ACCEPT_EDITS, '1');
219        $record = $tree->createMediaObject("0 @@ OBJE\n1 FILE foo.jpeg");
220        $this->assertFalse($record->isPendingAddition());
221    }
222
223    /**
224     * @covers \Fisharebest\Webtrees\Tree::createRecord
225     * @return void
226     */
227    public function testCreateInvalidRecord(): void
228    {
229        $this->expectException(InvalidArgumentException::class);
230
231        $user_service = new UserService();
232        $tree_service = new TreeService();
233        $tree         = $tree_service->create('name', 'title');
234        $user         = $user_service->create('user', 'User', 'user@example.com', 'secret');
235        $user->setPreference(User::PREF_IS_ADMINISTRATOR, '1');
236        Auth::login($user);
237
238        $tree->createRecord("0 @@FOO\n1 NOTE noted");
239    }
240
241    /**
242     * @covers \Fisharebest\Webtrees\Tree::createRecord
243     * @return void
244     */
245    public function testCreateRecord(): void
246    {
247        $user_service = new UserService();
248        $tree_service = new TreeService();
249        $tree         = $tree_service->create('name', 'title');
250        $user         = $user_service->create('user', 'User', 'user@example.com', 'secret');
251        $user->setPreference(User::PREF_IS_ADMINISTRATOR, '1');
252        Auth::login($user);
253
254        $record = $tree->createRecord("0 @@ FOO\n1 NOTE noted");
255        $this->assertTrue($record->isPendingAddition());
256
257        $user->setPreference(User::PREF_AUTO_ACCEPT_EDITS, '1');
258        $record = $tree->createRecord("0 @@ FOO\n1 NOTE noted");
259        $this->assertFalse($record->isPendingAddition());
260    }
261
262    /**
263     * @covers \Fisharebest\Webtrees\Tree::significantIndividual
264     * @return void
265     */
266    public function testSignificantIndividual(): void
267    {
268        $user_service = new UserService();
269        $tree_service = new TreeService();
270        $tree         = $tree_service->create('name', 'title');
271        $user         = $user_service->create('user', 'User', 'user@example.com', 'secret');
272        $user->setPreference(User::PREF_AUTO_ACCEPT_EDITS, '1');
273        Auth::login($user);
274
275        // Delete the tree's default individual.
276        FunctionsImport::updateRecord('0 @X1@ INDI', $tree, true);
277
278        // No individuals in tree?  Dummy individual
279        $this->assertSame('I', $tree->significantIndividual($user)->xref());
280
281        $record1 = $tree->createIndividual("0 @@ INDI\n1 SEX F\n1 NAME Foo /Bar/");
282        $record2 = $tree->createIndividual("0 @@ INDI\n1 SEX F\n1 NAME Foo /Bar/");
283        $record3 = $tree->createIndividual("0 @@ INDI\n1 SEX F\n1 NAME Foo /Bar/");
284        $record4 = $tree->createIndividual("0 @@ INDI\n1 SEX F\n1 NAME Foo /Bar/");
285
286        // Individuals exist?  First one (lowest XREF).
287        $this->assertSame($record1->xref(), $tree->significantIndividual($user)->xref());
288
289        // Preference for tree?
290        $tree->setPreference('PEDIGREE_ROOT_ID', $record2->xref());
291        $this->assertSame($record2->xref(), $tree->significantIndividual($user)->xref());
292
293        // User preference
294        $tree->setUserPreference($user, User::PREF_TREE_ACCOUNT_XREF, $record3->xref());
295        $this->assertSame($record3->xref(), $tree->significantIndividual($user)->xref());
296
297        // User record
298        $tree->setUserPreference($user, User::PREF_TREE_DEFAULT_XREF, $record4->xref());
299        $this->assertSame($record4->xref(), $tree->significantIndividual($user)->xref());
300    }
301
302    /**
303     * @covers \Fisharebest\Webtrees\Tree::importGedcomFile
304     * @covers \Fisharebest\Webtrees\Tree::deleteGenealogyData
305     * @return void
306     */
307    public function testImportAndDeleteGedcomFile(): void
308    {
309        $tree_service = new TreeService();
310        $tree = $this->importTree('demo.ged');
311        $this->assertNotNull($tree_service->all()->get('demo.ged'));
312        Site::setPreference('DEFAULT_GEDCOM', $tree->name());
313
314        $tree_service->delete($tree);
315
316        $this->assertNull($tree_service->all()->get('demo.ged'));
317        $this->assertSame('', Site::getPreference('DEFAULT_GEDCOM'));
318    }
319
320    /**
321     * @covers \Fisharebest\Webtrees\Tree::hasPendingEdit
322     * @return void
323     */
324    public function testHasPendingEdits(): void
325    {
326        $user_service = new UserService();
327        $tree         = $this->importTree('demo.ged');
328        $user         = $user_service->create('admin', 'Administrator', 'admin@example.com', 'secret');
329        $user->setPreference(User::PREF_IS_ADMINISTRATOR, '1');
330        Auth::login($user);
331
332        $user->setPreference(User::PREF_AUTO_ACCEPT_EDITS, '1');
333        $tree->createIndividual("0 @@ INDI\n1 SEX F\n1 NAME Foo /Bar/");
334        $this->assertFalse($tree->hasPendingEdit());
335
336        $user->setPreference(User::PREF_AUTO_ACCEPT_EDITS, '');
337        $tree->createIndividual("0 @@ INDI\n1 SEX F\n1 NAME Foo /Bar/");
338        $this->assertTrue($tree->hasPendingEdit());
339    }
340
341    /**
342     * @covers \Fisharebest\Webtrees\Tree::exportGedcom
343     * @return void
344     */
345    public function testExportGedcom(): void
346    {
347        $tree = $this->importTree('demo.ged');
348
349        $fp = fopen('php://memory', 'wb');
350
351        $tree->exportGedcom($fp);
352
353        rewind($fp);
354
355        $original = file_get_contents(__DIR__ . '/../data/demo.ged');
356        $export   = stream_get_contents($fp);
357
358        // The date and time in the HEAD record will be different.
359        $original = preg_replace('/\n1 DATE .. ... ..../', '', $original, 1);
360        $export   = preg_replace('/\n1 DATE .. ... ..../', '', $export, 1);
361        $original = preg_replace('/\n2 TIME ..:..:../', '', $original, 1);
362        $export   = preg_replace('/\n2 TIME ..:..:../', '', $export, 1);
363
364        $this->assertSame($original, $export);
365    }
366}
367