*/ declare(strict_types = 1); use PHPUnit\Framework\TestCase; use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\Attributes\DataProviderExternal; use PHPUnit\Framework\Attributes\Small; use PHPUnit\Framework\Attributes\CoversClass; /** * Tests for MD_STD. */ #[small] #[CoversClass(\MD_STD::class)] final class MD_STD_Test extends TestCase { /** * Data provider for returning a tmp file. * * @return array */ public static function file_name_in_tmp_provider():array { $temp_file = \tempnam(\sys_get_temp_dir(), 'test_md_std'); if (!$temp_file) throw new Exception("Failed to get tmp dir"); return [ $temp_file => [$temp_file], ]; } /** * Data provider for invalid directories. * * @return array */ public static function invalid_directory_provider():array { $non_existent = __DIR__ . '/' . uniqid(); return [ "File, not directory" => [__FILE__], "Non-existent directory" => [$non_existent], ]; } /** * Data provider for invalid files for file_get_contents. * * @return array */ public static function invalid_files_for_file_get_contents():array { return [ 'External path: FTP' => ["ftp://test", MDFileDoesNotExist::class], // Invalid external 'Non-existent file' => ["jklsdjfklasdjfklasdkl.jpg", MDFileDoesNotExist::class], // Non-existent file ]; } /** * Data provider for invalid files for file_get_contents. * * @return array, 2: string}> */ public static function failure_cases_ensure_file():array { return [ 'Non-existent file' => ["jklsdjfklasdjfklasdkl.jpg", [], MDFileDoesNotExist::class], // Non-existent file 'Invalid mime type' => [__FILE__, ["image/jpeg"], MDWrongFileType::class], // Non-existent file ]; } /** * Returns sample dates and their equivalent integer values according * to MD_STD::date_to_int(). * * @return array */ public static function date_to_int_provider():array { $values = [ ["2022-01-01", 20220101], ["0022-01-01", 220101], ["-0022-01-01", -220101], ["-2022-01-01", -20220101], ["-0001-01-01", -10101], ["0000-01-01", 101], ["100000-01-01", 1000000101], ]; $output = []; foreach ($values as $value) { $output[$value[0]] = $value; } return $output; } /** * Checks if a file can be read. * * @return void */ public function test_file_get_contents_works():void { self::assertNotEmpty(MD_STD::file_get_contents(__DIR__ . '/../phpunit.xml')); } /** * Checks if a file can be written. * * @param non-empty-string $temp_file Tmp file. * * @return void */ #[DataProvider('file_name_in_tmp_provider')] public function test_file_put_contents_works(string $temp_file):void { MD_STD::file_put_contents($temp_file, "Test"); self::assertEquals("Test", MD_STD::file_get_contents($temp_file)); MD_STD::unlink($temp_file); } /** * Check MD_STD::realpath returns absolute file path of an existing file. * * @return void */ public function test_realpath_works():void { self::assertEquals(__FILE__, MD_STD::realpath(__FILE__)); } /** * Check MD_STD::realpath throws exception on non-existing path. * * @param non-empty-string $to_validate Input to validate. * @param class-string $exceptionClass Exception class. * * @return void */ #[DataProvider('invalid_files_for_file_get_contents')] public function test_realpath_fails(string $to_validate, string $exceptionClass):void { self::expectException($exceptionClass); MD_STD::realpath($to_validate); } /** * Checks if a file can be read. * * @param non-empty-string $to_validate Input to validate. * @param class-string $exceptionClass Exception class. * * @return void */ #[DataProvider('invalid_files_for_file_get_contents')] public function test_file_get_contents_fails_as_expected(string $to_validate, string $exceptionClass):void { self::expectException($exceptionClass); MD_STD::file_get_contents($to_validate); } /** * Checks that json_encode works. * * @return void */ public function test_json_encode_works():void { self::assertEquals('[0]', MD_STD::json_encode([0])); } /** * Checks that json_encode_object works. * * @return void */ public function test_json_encode_object_works():void { self::assertEquals('{"0":0}', MD_STD::json_encode_object((object)[0])); } /** * Checks that mkdir works. * * @return void */ public function test_mkdir_works():void { $testDir = sys_get_temp_dir() . '/' . uniqid("_test_"); if (file_exists($testDir)) { throw new Exception("Test dir already exists"); } MD_STD::mkdir($testDir); self::assertTrue(is_dir($testDir)); } /** * Checks that nothing happens with mkdir. * * @return void */ public function test_mkdir_works_with_invalid():void { MD_STD::mkdir(__DIR__); self::assertTrue(is_dir(__DIR__)); } /** * Checks if nothing happens if a file does not exist. * * @param non-empty-string $temp_file Tmp file. * * @return void */ #[DataProvider('file_name_in_tmp_provider')] public function test_unlink_if_exists_passes_if_not_exists(string $temp_file):void { if (file_exists($temp_file)) { MD_STD::unlink($temp_file); } MD_STD::unlink_if_exists($temp_file); self::assertFalse(is_file($temp_file)); } /** * Checks unlink_if_exists works. * * @param non-empty-string $temp_file Tmp file. * * @return void */ #[DataProvider('file_name_in_tmp_provider')] public function test_unlink_if_exists_works(string $temp_file):void { touch($temp_file); MD_STD::unlink_if_exists($temp_file); self::assertFalse(is_file($temp_file)); } /** * Checks scandir works. * * @return void */ public function test_scandir():void { if (empty($files = scandir(__DIR__))) { throw new Exception("Running regular scandir() failed on script directory: " . __DIR__); } $filesChecked = MD_STD::scandir(__DIR__); foreach ($filesChecked as $file) { self::assertTrue(in_array($file, $files, true)); } foreach (['.', '..', '.git'] as $excluded) { self::assertFalse(in_array($excluded, $filesChecked, true)); } } /** * Checks invalid directory. * * @param non-empty-string $dir Dir name. * * @return void */ #[DataProvider('invalid_directory_provider')] public function test_invalid_directory_throws_error_on_scandir(string $dir):void { self::expectException(MDFileDoesNotExist::class); MD_STD::scandir($dir); } /** * Checks that startsWithAny works. * * @return void */ public function test_startsWithAny():void { self::assertTrue(MD_STD::startsWithAny("abc", ["a"])); self::assertFalse(MD_STD::startsWithAny("abc", ["b"])); } /** * Checks that stri_contains works. * * @return void */ public function test_stri_contains():void { self::assertTrue(MD_STD::stri_contains("abc", "a")); self::assertTrue(MD_STD::stri_contains("abc", "b")); self::assertTrue(MD_STD::stri_contains("abc", "C")); self::assertFalse(MD_STD::stri_contains("abc", "u")); } /** * Checks that stri_contains_any works. * * @return void */ public function test_stri_contains_any():void { self::assertTrue(MD_STD::stri_contains_any("abc", ["a"])); self::assertTrue(MD_STD::stri_contains_any("abc", ["b"])); self::assertTrue(MD_STD::stri_contains_any("abc", ["C"])); self::assertTrue(MD_STD::stri_contains_any("abc", ["C", "u"])); self::assertFalse(MD_STD::stri_contains_any("abc", ["u"])); self::assertFalse(MD_STD::stri_contains_any("abc", ["u", "z"])); } /** * Checks that strtotime works. * * @return void */ public function test_strtotime_works():void { self::assertEquals(strtotime("2024-01-01"), MD_STD::strtotime("2024-01-01")); } /** * Checks that strtotime works. * * @return void */ public function test_strtotime_fails_as_expected():void { self::expectException(MDInvalidInputDate::class); MD_STD::strtotime("test"); } /** * Checks that strtotime_for_public_apis works. * * @return void */ public function test_strtotime_for_pulic_apis_works():void { self::assertEquals(strtotime("2024-01-01"), MD_STD::strtotime_for_public_apis("2024-01-01")); } /** * Checks that strtotime_for_public_apis works. * * @return void */ public function test_strtotime_for_pulic_apis_fails_as_expected():void { self::expectException(MDParseException::class); MD_STD::strtotime_for_public_apis("test"); } /** * Checks that curl_init works. * * @return void */ public function test_curl_init():void { self::expectNotToPerformAssertions(); MD_STD::curl_init("https://example.com", 2000); } /** * Checks that runCurl works. * * @return void */ public function test_runCurl():void { self::assertNotEmpty(MD_STD::runCurl("https://example.com", headers: ['X-TEST: Test'])); } /** * Checks that runCurl works. * * @return void */ public function test_runCurlMulti():void { $output = MD_STD::runCurlMulti(["https://example.com" => "https://example.com"], headers: ['X-TEST: Test']); self::assertEquals(["https://example.com"], array_keys($output)); } /** * Checks that checkUrlIsReachable works. * * @return void */ public function test_checkUrlIsReachable():void { self::assertTrue(MD_STD::checkUrlIsReachable("https://example.com")); self::assertFalse(MD_STD::checkUrlIsReachable("https://example.com/404")); } /** * Checks that checkUrlIsReachable fails as expected. * * @param string $invalid_url Input to validate. * * @return void */ #[DataProviderExternal(\MD_STD_TEST_PROVIDERS::class, 'invalid_url_provider')] public function test_checkUrlIsReachable_fails_as_expected(string $invalid_url):void { self::expectException(MDInvalidUrl::class); self::assertTrue(MD_STD::checkUrlIsReachable($invalid_url)); } /** * Checks that checkUrlIsReachable fails as expected. * * @return void */ public function test_checkUrlIsReachable_fails_as_expected_on_empty_input():void { self::expectException(MDInvalidUrl::class); self::assertTrue(MD_STD::checkUrlIsReachable("")); } /** * Checks that filesize works. * * @return void */ public function test_filesize():void { self::assertNotEmpty(MD_STD::filesize(__FILE__)); } /** * Checks that human_filesize works. * * @return void */ public function test_human_filesize_works():void { self::assertEquals("2.00B", MD_STD::human_filesize(2)); self::assertEquals("2.00kB", MD_STD::human_filesize(2048)); } /** * Checks that minimizeHTMLString works. * * @return void */ public function test_minimizeHTMLString():void { self::assertEquals("hi" . PHP_EOL . "hi" . PHP_EOL, MD_STD::minimizeHTMLString(" hi" . PHP_EOL . " hi")); } /** * Checks that createTextSnippet works. * * @return void */ public function test_createTextSnippet():void { self::assertEquals("Hallo...", MD_STD::createTextSnippet("Hallo Hallo, jkfljksdlajkfas", 8)); } /** * Checks that ensure_file works. * * @return void */ public function test_ensure_file_works():void { self::expectNotToPerformAssertions(); MD_STD::ensure_file(__FILE__); } /** * Checks that minimizeHTMLString works. * * @param non-empty-string $filepath File path. * @param array $mime_types Mime types expected. * @param class-string $exception Exception class. * * @return void */ #[DataProvider('failure_cases_ensure_file')] public function test_ensure_file_fails_as_expected(string $filepath, array $mime_types, string $exception):void { self::expectException($exception); MD_STD::ensure_file($filepath, $mime_types); } /** * Checks that levenshtein works. * * @return void */ public function test_levensthein_works():void { self::expectNotToPerformAssertions(); MD_STD::levenshtein(str_repeat("hi", 500), str_repeat("ho", 500)); } /** * Checks if dates can be translated to int and back. * * @param string $date Date to translate. * @param integer $expectedInt Expected integer value for it. * * @return void */ #[DataProvider('date_to_int_provider')] public function test_date_to_int(string $date, int $expectedInt):void { $toInt = MD_STD::date_to_int($date); $toStr = MD_STD::int_to_date($toInt); self::assertEquals($expectedInt, $toInt); self::assertEquals($date, $toStr); } /** * Checks check_is_writable does not work with non-existent or non-directory paths. * * @param non-empty-string $dir Dir name. * * @return void */ #[DataProvider('invalid_directory_provider')] public function test_invalid_directory_throws_error_on_check_is_writable(string $dir):void { self::expectException(MDFileDoesNotExist::class); MD_STD::check_is_writable($dir); } /** * Checks check_is_writable does not work with non-existent or non-directory paths. * * @return void */ public function test_is_writable_returns_false_without_permissions():void { self::expectException(MDFileIsNotWritable::class); MD_STD::check_is_writable("/etc"); } /** * Checks check_is_writable does not work with non-existent or non-directory paths. * * @return void */ public function test_remote_mime_content_type_works():void { self::assertEquals("text/html", MD_STD::remote_mime_content_type("https://example.com")); } /** * Checks string_to_color_code works. * * @return void */ public function test_string_to_color_code():void { self::assertEquals(6, strlen(MD_STD::string_to_color_code(""))); self::assertEquals(6, strlen(MD_STD::string_to_color_code("a"))); self::assertEquals(6, strlen(MD_STD::string_to_color_code("dsaf"))); } /** * Checks split_int_array_into_sized_parts works. * * @return void */ public function test_split_int_array_into_sized_parts():void { self::assertEquals([[0 => 1], [0 => 1], [0 => 1], [0 => 1]], MD_STD::split_int_array_into_sized_parts([1, 1, 1, 1], 1)); } /** * Checks split_string_array_into_sized_parts works. * * @return void */ public function test_split_string_array_into_sized_parts():void { self::assertEquals([[0 => "1"], [0 => "1"], [0 => "1"], [0 => "1"]], MD_STD::split_string_array_into_sized_parts(["1", "1", "1", "1"], 1)); } /** * Checks openssl_random_pseudo_bytes works. * * @return void */ public function test_openssl_random_pseudo_bytes():void { self::assertNotEmpty(MD_STD::openssl_random_pseudo_bytes(12)); } /** * Checks lang_getfrombrowser works by getting value from HTTP header HTTP_ACCEPT_LANGUAGE. * * @return void */ public function test_lang_getfrombrowser_via_http_header():void { $_SERVER = [ 'HTTP_ACCEPT_LANGUAGE' => 'de', ]; self::assertEquals("de", MD_STD::lang_getfrombrowser(["de", "en"], "en", "")); $_SERVER = [ 'HTTP_ACCEPT_LANGUAGE' => 'es_ES', ]; self::assertEquals("en", MD_STD::lang_getfrombrowser(["de", "en"], "en", "")); } /** * Checks lang_getfrombrowser returns default without any further information being provided. * * @return void */ public function test_lang_getfrombrowser_get_default():void { self::assertEquals("en", MD_STD::lang_getfrombrowser(["de", "en"], "en", "")); } /** * Checks get_user_lang_no_cookie works with GET variable set. * * @return void */ public function test_get_user_lang_no_cookie_works_from_get_var():void { $_GET = [ 'navlang' => 'de', ]; self::assertEquals("de", MD_STD::get_user_lang_no_cookie(["de", "en"], "en")); } /** * Checks get_user_lang_no_cookie works with GET variable set. * * @return void */ public function test_get_user_lang_no_cookie_works_without_get():void { self::assertEquals("en", MD_STD::get_user_lang_no_cookie(["de", "en"], "en")); } /** * Data provider for returning a tmp file. * * @return array, 2: int}> */ public static function strpos_multi_provider():array { return [ "Search quotation markes on when='" => ["when='", ['"', '\''], 5], "Search quotation markes on when=\"" => ["when=\"", ['"', '\''], 5], "Search quotation markes on when=\"'" => ["when=\"'", ['"', '\''], 5], "Search quotation markes on when= (non-existent)" => ["when=", ['"', '\''], -1], ]; } /** * Checks unlink_if_exists works. * * @param non-empty-string $haystack Haystack. * @param non-empty-array $needles Needles. * @param integer $expected Expected position. * * @return void */ #[DataProvider('strpos_multi_provider')] public function test_strpos_multi(string $haystack, array $needles, int $expected):void { if ($expected === -1) { self::assertEmpty(MD_STD::strpos_multi($haystack, $needles)); } else { self::assertEquals($expected, MD_STD::strpos_multi($haystack, $needles)['position']); } } }