. */ declare(strict_types=1); namespace Fisharebest\Webtrees; use Fisharebest\Webtrees\Contracts\CacheFactoryInterface; use Fisharebest\Webtrees\Contracts\UserInterface; use Fisharebest\Webtrees\Functions\FunctionsImport; use Fisharebest\Webtrees\Services\GedcomExportService; use Fisharebest\Webtrees\Services\TreeService; use Fisharebest\Webtrees\Services\UserService; use InvalidArgumentException; use Symfony\Component\Cache\Adapter\NullAdapter; use function fclose; use function file_get_contents; use function preg_replace; use function stream_get_contents; /** * Test harness for the class Tree */ class TreeTest extends TestCase { protected static bool $uses_database = true; public function setUp(): void { parent::setUp(); $cache_factory = $this->createMock(CacheFactoryInterface::class); $cache_factory->method('array')->willReturn(new Cache(new NullAdapter())); Registry::cache($cache_factory); } /** * @covers \Fisharebest\Webtrees\Tree::__construct * @covers \Fisharebest\Webtrees\Tree::id * @covers \Fisharebest\Webtrees\Tree::name * @covers \Fisharebest\Webtrees\Tree::title * @return void */ public function testConstructor(): void { $tree_service = new TreeService(); $tree = $tree_service->create('name', 'title'); self::assertSame('name', $tree->name()); self::assertSame('title', $tree->title()); } /** * @covers \Fisharebest\Webtrees\Tree::getPreference * @covers \Fisharebest\Webtrees\Tree::setPreference * @return void */ public function testTreePreferences(): void { $tree_service = new TreeService(); $tree = $tree_service->create('name', 'title'); $tree->setPreference('foo', 'bar'); $pref = $tree->getPreference('foo'); self::assertSame('bar', $pref); } /** * @covers \Fisharebest\Webtrees\Tree::getUserPreference * @covers \Fisharebest\Webtrees\Tree::setUserPreference * @return void */ public function testUserTreePreferences(): void { $user_service = new UserService(); $tree_service = new TreeService(); $tree = $tree_service->create('name', 'title'); $user = $user_service->create('user', 'User', 'user@example.com', 'secret'); $pref = $tree->getUserPreference($user, 'foo', 'default'); self::assertSame('default', $pref); $tree->setUserPreference($user, 'foo', 'bar'); $pref = $tree->getUserPreference($user, 'foo', 'default'); self::assertSame('bar', $pref); } /** * @covers \Fisharebest\Webtrees\Tree::createIndividual * @return void */ public function testCreateInvalidIndividual(): void { $this->expectException(InvalidArgumentException::class); $user_service = new UserService(); $tree_service = new TreeService(); $tree = $tree_service->create('name', 'title'); $user = $user_service->create('user', 'User', 'user@example.com', 'secret'); $user->setPreference(UserInterface::PREF_IS_ADMINISTRATOR, '1'); Auth::login($user); $tree->createIndividual("0 @@ FOO\n1 SEX U"); } /** * @covers \Fisharebest\Webtrees\Tree::createIndividual * @return void */ public function testCreateIndividual(): void { $user_service = new UserService(); $tree_service = new TreeService(); $tree = $tree_service->create('name', 'title'); $user = $user_service->create('user', 'User', 'user@example.com', 'secret'); $user->setPreference(UserInterface::PREF_IS_ADMINISTRATOR, '1'); Auth::login($user); $record = $tree->createIndividual("0 @@ INDI\n1 SEX F\n1 NAME Foo /Bar/"); self::assertTrue($record->isPendingAddition()); $user->setPreference(UserInterface::PREF_AUTO_ACCEPT_EDITS, '1'); $record = $tree->createIndividual("0 @@ INDI\n1 SEX F\n1 NAME Foo /Bar/"); self::assertFalse($record->isPendingAddition()); } /** * @covers \Fisharebest\Webtrees\Tree::createFamily * @return void */ public function testCreateInvalidFamily(): void { $this->expectException(InvalidArgumentException::class); $user_service = new UserService(); $tree_service = new TreeService(); $tree = $tree_service->create('name', 'title'); $user = $user_service->create('user', 'User', 'user@example.com', 'secret'); $user->setPreference(UserInterface::PREF_IS_ADMINISTRATOR, '1'); Auth::login($user); $tree->createFamily("0 @@ FOO\n1 MARR Y"); } /** * @covers \Fisharebest\Webtrees\Tree::createFamily * @return void */ public function testCreateFamily(): void { $user_service = new UserService(); $tree_service = new TreeService(); $tree = $tree_service->create('name', 'title'); $user = $user_service->create('user', 'User', 'user@example.com', 'secret'); $user->setPreference(UserInterface::PREF_IS_ADMINISTRATOR, '1'); Auth::login($user); $record = $tree->createFamily("0 @@ FAM\n1 MARR Y"); self::assertTrue($record->isPendingAddition()); $user->setPreference(UserInterface::PREF_AUTO_ACCEPT_EDITS, '1'); $record = $tree->createFamily("0 @@ FAM\n1 MARR Y"); self::assertFalse($record->isPendingAddition()); } /** * @covers \Fisharebest\Webtrees\Tree::createMediaObject * @return void */ public function testCreateInvalidMediaObject(): void { $this->expectException(InvalidArgumentException::class); $user_service = new UserService(); $tree_service = new TreeService(); $tree = $tree_service->create('name', 'title'); $user = $user_service->create('user', 'User', 'user@example.com', 'secret'); $user->setPreference(UserInterface::PREF_IS_ADMINISTRATOR, '1'); Auth::login($user); $tree->createMediaObject("0 @@ FOO\n1 MARR Y"); } /** * @covers \Fisharebest\Webtrees\Tree::createMediaObject * @return void */ public function testCreateMediaObject(): void { $user_service = new UserService(); $tree_service = new TreeService(); $tree = $tree_service->create('name', 'title'); $user = $user_service->create('user', 'User', 'user@example.com', 'secret'); $user->setPreference(UserInterface::PREF_IS_ADMINISTRATOR, '1'); Auth::login($user); $record = $tree->createMediaObject("0 @@ OBJE\n1 FILE foo.jpeg"); self::assertTrue($record->isPendingAddition()); $user->setPreference(UserInterface::PREF_AUTO_ACCEPT_EDITS, '1'); $record = $tree->createMediaObject("0 @@ OBJE\n1 FILE foo.jpeg"); self::assertFalse($record->isPendingAddition()); } /** * @covers \Fisharebest\Webtrees\Tree::createRecord * @return void */ public function testCreateInvalidRecord(): void { $this->expectException(InvalidArgumentException::class); $user_service = new UserService(); $tree_service = new TreeService(); $tree = $tree_service->create('name', 'title'); $user = $user_service->create('user', 'User', 'user@example.com', 'secret'); $user->setPreference(UserInterface::PREF_IS_ADMINISTRATOR, '1'); Auth::login($user); $tree->createRecord("0 @@FOO\n1 NOTE noted"); } /** * @covers \Fisharebest\Webtrees\Tree::createRecord * @return void */ public function testCreateRecord(): void { $user_service = new UserService(); $tree_service = new TreeService(); $tree = $tree_service->create('name', 'title'); $user = $user_service->create('user', 'User', 'user@example.com', 'secret'); $user->setPreference(UserInterface::PREF_IS_ADMINISTRATOR, '1'); Auth::login($user); $record = $tree->createRecord("0 @@ FOO\n1 NOTE noted"); self::assertTrue($record->isPendingAddition()); $user->setPreference(UserInterface::PREF_AUTO_ACCEPT_EDITS, '1'); $record = $tree->createRecord("0 @@ FOO\n1 NOTE noted"); self::assertFalse($record->isPendingAddition()); } /** * @covers \Fisharebest\Webtrees\Tree::significantIndividual * @return void */ public function testSignificantIndividual(): void { $user_service = new UserService(); $tree_service = new TreeService(); $tree = $tree_service->create('name', 'title'); $user = $user_service->create('user', 'User', 'user@example.com', 'secret'); $user->setPreference(UserInterface::PREF_AUTO_ACCEPT_EDITS, '1'); Auth::login($user); // Delete the tree's default individual. FunctionsImport::updateRecord('0 @X1@ INDI', $tree, true); // No individuals in tree? Fake individual self::assertSame('I', $tree->significantIndividual($user)->xref()); $record1 = $tree->createIndividual("0 @@ INDI\n1 SEX F\n1 NAME Foo /Bar/"); $record2 = $tree->createIndividual("0 @@ INDI\n1 SEX F\n1 NAME Foo /Bar/"); $record3 = $tree->createIndividual("0 @@ INDI\n1 SEX F\n1 NAME Foo /Bar/"); $record4 = $tree->createIndividual("0 @@ INDI\n1 SEX F\n1 NAME Foo /Bar/"); // Individuals exist? First one (lowest XREF). self::assertSame($record1->xref(), $tree->significantIndividual($user)->xref()); // Preference for tree? $tree->setPreference('PEDIGREE_ROOT_ID', $record2->xref()); self::assertSame($record2->xref(), $tree->significantIndividual($user)->xref()); // User preference $tree->setUserPreference($user, UserInterface::PREF_TREE_ACCOUNT_XREF, $record3->xref()); self::assertSame($record3->xref(), $tree->significantIndividual($user)->xref()); // User record $tree->setUserPreference($user, UserInterface::PREF_TREE_DEFAULT_XREF, $record4->xref()); self::assertSame($record4->xref(), $tree->significantIndividual($user)->xref()); } /** * @covers \Fisharebest\Webtrees\Services\TreeService::importGedcomFile * @covers \Fisharebest\Webtrees\Services\TreeService::deleteGenealogyData * @return void */ public function testImportAndDeleteGedcomFile(): void { $tree_service = new TreeService(); $tree = $this->importTree('demo.ged'); self::assertNotNull($tree_service->all()->get('demo.ged')); Site::setPreference('DEFAULT_GEDCOM', $tree->name()); $tree_service->delete($tree); self::assertNull($tree_service->all()->get('demo.ged')); self::assertSame('', Site::getPreference('DEFAULT_GEDCOM')); } /** * @covers \Fisharebest\Webtrees\Tree::hasPendingEdit * @return void */ public function testHasPendingEdits(): void { $user_service = new UserService(); $tree = $this->importTree('demo.ged'); $user = $user_service->create('admin', 'Administrator', 'admin@example.com', 'secret'); $user->setPreference(UserInterface::PREF_IS_ADMINISTRATOR, '1'); Auth::login($user); $user->setPreference(UserInterface::PREF_AUTO_ACCEPT_EDITS, '1'); $tree->createIndividual("0 @@ INDI\n1 SEX F\n1 NAME Foo /Bar/"); self::assertFalse($tree->hasPendingEdit()); $user->setPreference(UserInterface::PREF_AUTO_ACCEPT_EDITS, ''); $tree->createIndividual("0 @@ INDI\n1 SEX F\n1 NAME Foo /Bar/"); self::assertTrue($tree->hasPendingEdit()); } /** * @covers \Fisharebest\Webtrees\Services\GedcomExportService::export * @return void */ public function testExportGedcom(): void { $tree = $this->importTree('demo.ged'); $gedcom_export_service = new GedcomExportService(); $resource = $gedcom_export_service->export($tree, true); $original = file_get_contents(__DIR__ . '/../data/demo.ged'); $export = stream_get_contents($resource); fclose($resource); // The version, date and time in the HEAD record will be different. $original = preg_replace('/\n2 VERS .*/', '', $original, 1); $export = preg_replace('/\n2 VERS .*/', '', $export, 1); $original = preg_replace('/\n1 DATE .. ... ..../', '', $original, 1); $export = preg_replace('/\n1 DATE .. ... ..../', '', $export, 1); $original = preg_replace('/\n2 TIME ..:..:../', '', $original, 1); $export = preg_replace('/\n2 TIME ..:..:../', '', $export, 1); self::assertSame($original, $export); } }