*/ declare(strict_types = 1); use PHPUnit\Framework\TestCase; use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\Attributes\Medium; require_once __DIR__ . '/../../MDMysqli/test_connections.conf.php'; /** * Test for functions for looking up entry IDs by their (exact) names. */ #[Medium] #[CoversClass(\NodaIDGetter::class)] final class NodaIDGetterTest extends TestCase { private MDMysqli $_mysqli; /** * Quasi-constructor connects to DB. * * @return void */ protected function setUp():void { $this->_mysqli = md_noda_mysqli_connect(); } /** * Gets string and integer value from a mysql query. * * @param MDMysqli $mysqli DB connection. * @param string $query DB query. * * @return array{0: string, 1: integer} */ private static function _getNameAndIdFromDbQuery(MDMysqli $mysqli, string $query):array { $result = $mysqli->do_read_query($query . " LIMIT 1"); if (!($cur = $result->fetch_row())) { throw new Exception("Failed to get result for query: " . $query); } $result->close(); return [ (string)$cur[0], (int)$cur[1], ]; } /** * Replaces vowels in string with variants with diacritics for testing * exact matching. * * @param string $input Input string. * * @return string */ public static function _replaceVowelsWithDiacriticVariants(string $input):string { return strtr($input, [ 'a' => 'ä', 'o' => 'ö', 'u' => 'ü', 'i' => 'ï', 'e' => 'è', ]); } /** * Runs regular tests on the term: * - Matching by exact same name works. * - Matching by same name with different capitalization works. * - Matching by same name with diacritics replacing non-diacritic vowels fails * (counter to MySQL's _ci-type notations rules). * * @param string $function NodaIDGetter's callback function for identification. * @param string $name Name of the entry. * @param integer $expected_id Expected target ID. * * @return void */ private function runRegularComparisonTests(string $function, string $name, int $expected_id):void { self::assertEquals($expected_id, NodaIDGetter::$function($this->_mysqli, "de", $name), "Entry " . $name . " is not matched in exact lookup. Expected ID: " . $expected_id); // Ensure that different capitalization does not influence the results self::assertEquals($expected_id, NodaIDGetter::$function($this->_mysqli, "de", strtoupper($name))); self::assertEquals($expected_id, NodaIDGetter::$function($this->_mysqli, "de", strtolower($name))); // Ensure that diacritics will stop the entry from matching $nameReplaced = self::_replaceVowelsWithDiacriticVariants($name); self::assertNotEquals($expected_id, NodaIDGetter::$function($this->_mysqli, "de", $nameReplaced)); } // PersinstIDByName /** * Returns a test actor name. * * @return array */ public static function persinstByNameProvider():array { $mysqli = md_noda_mysqli_connect(); $persinstByNameSimple = self::_getNameAndIdFromDbQuery($mysqli, "SELECT `persinst_name`, `persinst_id` FROM `persinst` WHERE INSTR(`persinst_name`, 'i')"); $persinstByDisplayNameSimple = self::_getNameAndIdFromDbQuery($mysqli, "SELECT `persinst_anzeigename`, `persinst_id` FROM `persinst` WHERE INSTR(`persinst_anzeigename`, 'i') AND `persinst_sterbejahr` != ''"); $persinstByDisplayNameSimple = self::_getNameAndIdFromDbQuery($mysqli, "SELECT `trans_name`, `persinst_id` FROM `persinst_translation` WHERE INSTR(`trans_name`, 'i') AND `trans_language` = 'de'"); $mysqli->close(); return [ 'Persinst ID by name: ' . $persinstByNameSimple[0] => $persinstByNameSimple, 'Persinst ID by display name: ' . $persinstByDisplayNameSimple[0] => $persinstByDisplayNameSimple, 'Persinst ID by translated name: ' . $persinstByDisplayNameSimple[0] => $persinstByDisplayNameSimple, ]; } /** * Test getting persinst by name works. * * @param string $name Name of the entry. * @param integer $expected_id Expected target ID. * * @return void */ #[DataProvider('persinstByNameProvider')] public function testGetPersinstIdByNameWorks(string $name, int $expected_id):void { $this->runRegularComparisonTests("getPersinstIDByName", $name, $expected_id); } // PersinstIDByRewrite /** * Returns a test actor name. * * @return array */ public static function persinstByRewriteProvider():array { $mysqli = md_noda_mysqli_connect(); $persinstByRewriteSimple = self::_getNameAndIdFromDbQuery($mysqli, "SELECT `input_name`, `persinst_id` FROM `persinst_rewriting` WHERE INSTR(`input_name`, 'i')"); $mysqli->close(); return [ 'Persinst ID by rewrite: ' . $persinstByRewriteSimple[0] => $persinstByRewriteSimple, ]; } /** * Test getting persinst by rewrite works. * * @param string $name Name of the entry. * @param integer $expected_id Expected target ID. * * @return void */ #[DataProvider('persinstByRewriteProvider')] public function testGetPersinstIdByRewriteWorks(string $name, int $expected_id):void { $this->runRegularComparisonTests("getPersinstIDByRewrite", $name, $expected_id); } // PlaceIDByName /** * Returns a test place name. * * @return array */ public static function placeByNameProvider():array { $mysqli = md_noda_mysqli_connect(); $placeByNameSimple = self::_getNameAndIdFromDbQuery($mysqli, "SELECT `ort_name`, `ort_id` FROM `orte` WHERE INSTR(`ort_name`, 'i')"); $placeByDisplayNameSimple = self::_getNameAndIdFromDbQuery($mysqli, "SELECT `trans_name`, `ort_id` FROM `ort_translation` WHERE INSTR(`trans_name`, 'i') AND `trans_language` = 'de'"); $mysqli->close(); return [ 'Place ID by name: ' . $placeByNameSimple[0] => $placeByNameSimple, 'Place ID by translated name: ' . $placeByDisplayNameSimple[0] => $placeByDisplayNameSimple, ]; } /** * Test getting persinst by name works. * * @param string $name Name of the entry. * @param integer $expected_id Expected target ID. * * @return void */ #[DataProvider('placeByNameProvider')] public function testGetPlaceIdByNameWorks(string $name, int $expected_id):void { $this->runRegularComparisonTests("getPlaceIDByName", $name, $expected_id); } // PlaceIDByRewrite /** * Returns a test place name registered for rewriting. * * @return array */ public static function placeByRewriteProvider():array { $mysqli = md_noda_mysqli_connect(); $placeByRewriteSimple = self::_getNameAndIdFromDbQuery($mysqli, "SELECT `input_name`, `ort_id` FROM `ort_rewriting` WHERE INSTR(`input_name`, 'i')"); $mysqli->close(); return [ 'Place ID by rewrite: ' . $placeByRewriteSimple[0] => $placeByRewriteSimple, ]; } /** * Test getting places by rewrite works. * * @param string $name Name of the entry. * @param integer $expected_id Expected target ID. * * @return void */ #[DataProvider('placeByRewriteProvider')] public function testGetPlaceIdByRewriteWorks(string $name, int $expected_id):void { $this->runRegularComparisonTests("getPlaceIDByRewrite", $name, $expected_id); } // TagIDByName /** * Returns a test tag name. * * @return array */ public static function tagByNameProvider():array { $mysqli = md_noda_mysqli_connect(); $tagByNameSimple = self::_getNameAndIdFromDbQuery($mysqli, "SELECT `tag_name`, `tag_id` FROM `tag` WHERE INSTR(`tag_name`, 'i')"); $tagByDisplayNameSimple = self::_getNameAndIdFromDbQuery($mysqli, "SELECT `trans_name`, `tag_id` FROM `tag_translation` WHERE INSTR(`trans_name`, 'i') AND `trans_language` = 'de'"); $mysqli->close(); return [ 'Tag ID by name: ' . $tagByNameSimple[0] => $tagByNameSimple, 'Tag ID by translated name: ' . $tagByDisplayNameSimple[0] => $tagByDisplayNameSimple, ]; } /** * Test getting tags by name works. * * @param string $name Name of the entry. * @param integer $expected_id Expected target ID. * * @return void */ #[DataProvider('tagByNameProvider')] public function testGetTagIdByNameWorks(string $name, int $expected_id):void { $this->runRegularComparisonTests("getTagIDByName", $name, $expected_id); } // TagIDByRewrite /** * Returns a test tag name registered for rewriting. * * @return array */ public static function tagByRewriteProvider():array { $mysqli = md_noda_mysqli_connect(); $tagByRewriteSimple = self::_getNameAndIdFromDbQuery($mysqli, "SELECT `input_name`, `tag_id` FROM `tag_rewriting` WHERE INSTR(`input_name`, 'i')"); $mysqli->close(); return [ 'Tag ID by rewrite: ' . $tagByRewriteSimple[0] => $tagByRewriteSimple, ]; } /** * Test getting tags by rewrite works. * * @param string $name Name of the entry. * @param integer $expected_id Expected target ID. * * @return void */ #[DataProvider('tagByRewriteProvider')] public function testGetTagIdByRewriteWorks(string $name, int $expected_id):void { self::assertContains($expected_id, NodaIDGetter::getTagIDByRewrite($this->_mysqli, "de", $name)); // Ensure that different capitalization does not influence the results self::assertContains($expected_id, NodaIDGetter::getTagIDByRewrite($this->_mysqli, "de", strtoupper($name))); self::assertContains($expected_id, NodaIDGetter::getTagIDByRewrite($this->_mysqli, "de", strtolower($name))); // Ensure that diacritics will stop the entry from matching $nameReplaced = self::_replaceVowelsWithDiacriticVariants($name); self::assertFalse(in_array($expected_id, NodaIDGetter::getTagIDByRewrite($this->_mysqli, "de", $nameReplaced), true)); } // TimeIDByName /** * Returns a test time name. * * @return array */ public static function timeByNameProvider():array { $mysqli = md_noda_mysqli_connect(); $timeByNameSimple = self::_getNameAndIdFromDbQuery($mysqli, "SELECT `zeit_name`, `zeit_id` FROM `zeiten` WHERE INSTR(`zeit_name`, 'i')"); $timeByDisplayNameSimple = self::_getNameAndIdFromDbQuery($mysqli, "SELECT `trans_name`, `zeit_id` FROM `zeit_translation` WHERE INSTR(`trans_name`, 'i') AND `trans_language` = 'de'"); $mysqli->close(); return [ 'Time ID by name: ' . $timeByNameSimple[0] => $timeByNameSimple, 'Time ID by translated name: ' . $timeByDisplayNameSimple[0] => $timeByDisplayNameSimple, ]; } /** * Test getting persinst by name works. * * @param string $name Name of the entry. * @param integer $expected_id Expected target ID. * * @return void */ #[DataProvider('timeByNameProvider')] public function testGetTimeIdByNameWorks(string $name, int $expected_id):void { $this->runRegularComparisonTests("getTimeIDByName", $name, $expected_id); } // timeIDByRewrite /** * Returns a test time name registered for rewriting. * * @return array */ public static function timeByRewriteProvider():array { $mysqli = md_noda_mysqli_connect(); $timeByRewriteSimple = self::_getNameAndIdFromDbQuery($mysqli, "SELECT `input_name`, `zeit_id` FROM `zeit_rewriting` WHERE INSTR(`input_name`, 'i')"); $mysqli->close(); return [ 'Time ID by rewrite: ' . $timeByRewriteSimple[0] => $timeByRewriteSimple, ]; } /** * Test getting times by rewrite works. * * @param string $name Name of the entry. * @param integer $expected_id Expected target ID. * * @return void */ #[DataProvider('timeByRewriteProvider')] public function testGetTimeIdByRewriteWorks(string $name, int $expected_id):void { $this->runRegularComparisonTests("getTimeIDByRewrite", $name, $expected_id); } // Entity getters by norm data references /** * Data provider for norm data reference for actors. * * @return array */ public static function nodaRefForActorsProvider():array { $mysqli = md_noda_mysqli_connect(); $nodaSimple = self::_getNameAndIdFromDbQuery($mysqli, "SELECT `noda_link`, `persinst_id` FROM `noda` WHERE `noda_source` = 'Wikidata' AND `noda_link` != ''"); $mysqli->close(); return [ 'Valid actor ID by norm data reference: ' . $nodaSimple[0] => [ new MDNodaLink(MDNodaRepository::wikidata, $nodaSimple[0]), $nodaSimple[1], ], 'Invalid, non-existing Wikidata ID' => [ new MDNodaLink(MDNodaRepository::wikidata, 'Q11111111111111'), 0, ], ]; } /** * Test getting actor ID by norm data reference. * * @param MDNodaLink $link Noda link. * @param integer $expected_id Expected target ID. * * @return void */ #[DataProvider('nodaRefForActorsProvider')] public function testGetPersinstByNodaLinkWorks(MDNodaLink $link, int $expected_id):void { self::assertEquals($expected_id, NodaIDGetter::getPersinstIDByNodaLink($this->_mysqli, $link)); } /** * Data provider for norm data reference for places. * * @return array */ public static function nodaRefForPlacesProvider():array { $mysqli = md_noda_mysqli_connect(); $nodaSimple = self::_getNameAndIdFromDbQuery($mysqli, "SELECT `noda_link`, `ort_id` FROM `noda_orte` WHERE `noda_source` = 'Wikidata' AND `noda_link` != ''"); $mysqli->close(); return [ 'Valid place ID by norm data reference: ' . $nodaSimple[0] => [ new MDNodaLink(MDNodaRepository::wikidata, $nodaSimple[0]), $nodaSimple[1], ], 'Invalid, non-existing Wikidata ID' => [ new MDNodaLink(MDNodaRepository::wikidata, 'Q11111111111111'), 0, ], ]; } /** * Test getting place ID by norm data reference. * * @param MDNodaLink $link Noda link. * @param integer $expected_id Expected target ID. * * @return void */ #[DataProvider('nodaRefForPlacesProvider')] public function testGetPlaceByNodaLinkWorks(MDNodaLink $link, int $expected_id):void { self::assertEquals($expected_id, NodaIDGetter::getPlaceIDByNodaLink($this->_mysqli, $link)); } /** * Data provider for norm data reference for tags. * * @return array */ public static function nodaRefForTagsProvider():array { $mysqli = md_noda_mysqli_connect(); $nodaSimple = self::_getNameAndIdFromDbQuery($mysqli, "SELECT `noda_link`, `tag_id` FROM `noda_tag` WHERE `noda_source` = 'Wikidata' AND `noda_link` != ''"); $mysqli->close(); return [ 'Valid tag ID by norm data reference: ' . $nodaSimple[0] => [ new MDNodaLink(MDNodaRepository::wikidata, $nodaSimple[0]), $nodaSimple[1], ], 'Invalid, non-existing Wikidata ID' => [ new MDNodaLink(MDNodaRepository::wikidata, 'Q11111111111111'), 0, ], ]; } /** * Test getting tag ID by norm data reference. * * @param MDNodaLink $link Noda link. * @param integer $expected_id Expected target ID. * * @return void */ #[DataProvider('nodaRefForTagsProvider')] public function testGetTagByNodaLinkWorks(MDNodaLink $link, int $expected_id):void { self::assertEquals($expected_id, NodaIDGetter::getTagIDByNodaLink($this->_mysqli, $link)); } }