From 867e3de92f9ff8081667dd1bb84f6318f3647679 Mon Sep 17 00:00:00 2001 From: Roland Franssen Date: Sun, 4 Aug 2019 08:07:53 +0200 Subject: [PATCH 01/15] [Intl] Order alpha2 to alpha3 mapping + phpdoc fixes --- src/Symfony/Component/Intl/Countries.php | 11 ++++- .../Data/Generator/LanguageDataGenerator.php | 2 + src/Symfony/Component/Intl/Languages.php | 10 +++-- src/Symfony/Component/Intl/Locales.php | 2 +- .../Intl/Resources/data/languages/meta.json | 42 +++++++++---------- src/Symfony/Component/Intl/Scripts.php | 2 +- .../AbstractLanguageDataProviderTest.php | 38 ++++++++--------- .../Component/Intl/Tests/LanguagesTest.php | 38 ++++++++--------- 8 files changed, 79 insertions(+), 66 deletions(-) diff --git a/src/Symfony/Component/Intl/Countries.php b/src/Symfony/Component/Intl/Countries.php index 81e17a5d59..f47a67418c 100644 --- a/src/Symfony/Component/Intl/Countries.php +++ b/src/Symfony/Component/Intl/Countries.php @@ -31,13 +31,16 @@ final class Countries extends ResourceBundle * * This list only contains "officially assigned ISO 3166-1 alpha-2" country codes. * - * @return string[] an array of canonical ISO 3166 country codes + * @return string[] an array of canonical ISO 3166 alpha-2 country codes */ public static function getCountryCodes(): array { return self::readEntry(['Regions'], 'meta'); } + /** + * @param string $country Alpha2 country code + */ public static function exists(string $country): bool { try { @@ -50,6 +53,8 @@ final class Countries extends ResourceBundle } /** + * Get country name from alpha2 code. + * * @throws MissingResourceException if the country code does not exists */ public static function getName(string $country, string $displayLocale = null): string @@ -58,9 +63,11 @@ final class Countries extends ResourceBundle } /** + * Get list of country names indexed with alpha2 codes as keys. + * * @return string[] */ - public static function getNames($displayLocale = null) + public static function getNames($displayLocale = null): array { return self::asort(self::readEntry(['Names'], $displayLocale), $displayLocale); } diff --git a/src/Symfony/Component/Intl/Data/Generator/LanguageDataGenerator.php b/src/Symfony/Component/Intl/Data/Generator/LanguageDataGenerator.php index 55815145da..f87a58bd1c 100644 --- a/src/Symfony/Component/Intl/Data/Generator/LanguageDataGenerator.php +++ b/src/Symfony/Component/Intl/Data/Generator/LanguageDataGenerator.php @@ -204,6 +204,8 @@ class LanguageDataGenerator extends AbstractDataGenerator } } + asort($alpha2ToAlpha3); + return $alpha2ToAlpha3; } } diff --git a/src/Symfony/Component/Intl/Languages.php b/src/Symfony/Component/Intl/Languages.php index 127f15f3e8..3f597b8eeb 100644 --- a/src/Symfony/Component/Intl/Languages.php +++ b/src/Symfony/Component/Intl/Languages.php @@ -22,7 +22,7 @@ use Symfony\Component\Intl\Exception\MissingResourceException; final class Languages extends ResourceBundle { /** - * Returns all available languages. + * Returns all available languages as two-letter codes. * * Languages are returned as lowercase ISO 639-1 two-letter language codes. * For languages that don't have a two-letter code, the ISO 639-2 @@ -31,7 +31,7 @@ final class Languages extends ResourceBundle * A full table of ISO 639 language codes can be found here: * http://www-01.sil.org/iso639-3/codes.asp * - * @return string[] an array of canonical ISO 639 language codes + * @return string[] an array of canonical ISO 639-1 language codes */ public static function getLanguageCodes(): array { @@ -50,6 +50,8 @@ final class Languages extends ResourceBundle } /** + * Get language name from alpha2 code. + * * @throws MissingResourceException if the language code does not exists */ public static function getName(string $language, string $displayLocale = null): string @@ -58,6 +60,8 @@ final class Languages extends ResourceBundle } /** + * Get list of language names indexed with alpha2 codes as keys. + * * @return string[] */ public static function getNames(string $displayLocale = null): array @@ -66,7 +70,7 @@ final class Languages extends ResourceBundle } /** - * Returns the ISO 639-2 three-letter code of a language. + * Returns the ISO 639-2 three-letter code of a language, given a two-letter code. * * @throws MissingResourceException if the language has no corresponding three-letter code */ diff --git a/src/Symfony/Component/Intl/Locales.php b/src/Symfony/Component/Intl/Locales.php index 1f434ee267..aee16beb16 100644 --- a/src/Symfony/Component/Intl/Locales.php +++ b/src/Symfony/Component/Intl/Locales.php @@ -67,7 +67,7 @@ final class Locales extends ResourceBundle /** * @return string[] */ - public static function getNames($displayLocale = null) + public static function getNames($displayLocale = null): array { return self::asort(self::readEntry(['Names'], $displayLocale), $displayLocale); } diff --git a/src/Symfony/Component/Intl/Resources/data/languages/meta.json b/src/Symfony/Component/Intl/Resources/data/languages/meta.json index 8b2308aea9..92eb9ba19f 100644 --- a/src/Symfony/Component/Intl/Resources/data/languages/meta.json +++ b/src/Symfony/Component/Intl/Resources/data/languages/meta.json @@ -623,14 +623,11 @@ "Alpha2ToAlpha3": { "aa": "aar", "ab": "abk", - "dz": "dzo", "af": "afr", "ak": "aka", - "sq": "sqi", "am": "amh", "ar": "ara", "an": "arg", - "hy": "hye", "as": "asm", "av": "ava", "ae": "ave", @@ -638,7 +635,6 @@ "az": "aze", "ba": "bak", "bm": "bam", - "eu": "eus", "be": "bel", "bn": "ben", "bi": "bis", @@ -646,12 +642,10 @@ "bs": "bos", "br": "bre", "bg": "bul", - "my": "mya", "ca": "cat", "cs": "ces", "ch": "cha", "ce": "che", - "zh": "zho", "cu": "chu", "cv": "chv", "kw": "cor", @@ -661,13 +655,12 @@ "da": "dan", "de": "deu", "dv": "div", - "mn": "mon", - "nl": "nld", - "et": "est", + "dz": "dzo", "el": "ell", "en": "eng", "eo": "epo", - "ik": "ipk", + "et": "est", + "eu": "eus", "ee": "ewe", "fo": "fao", "fa": "fas", @@ -676,8 +669,6 @@ "fr": "fra", "fy": "fry", "ff": "ful", - "om": "orm", - "ka": "kat", "gd": "gla", "ga": "gle", "gl": "glg", @@ -692,31 +683,34 @@ "ho": "hmo", "hr": "hrv", "hu": "hun", + "hy": "hye", "ig": "ibo", - "is": "isl", "io": "ido", "ii": "iii", "iu": "iku", "ie": "ile", "ia": "ina", "id": "ind", + "ik": "ipk", + "is": "isl", "it": "ita", "jv": "jav", "ja": "jpn", "kl": "kal", "kn": "kan", "ks": "kas", + "ka": "kat", "kr": "kau", "kk": "kaz", "km": "khm", "ki": "kik", "rw": "kin", "ky": "kir", - "ku": "kur", - "kg": "kon", "kv": "kom", + "kg": "kon", "ko": "kor", "kj": "kua", + "ku": "kur", "lo": "lao", "la": "lat", "lv": "lav", @@ -726,40 +720,43 @@ "lb": "ltz", "lu": "lub", "lg": "lug", - "mk": "mkd", "mh": "mah", "ml": "mal", - "mi": "mri", "mr": "mar", - "ms": "msa", + "mk": "mkd", "mg": "mlg", "mt": "mlt", - "ro": "ron", + "mn": "mon", + "mi": "mri", + "ms": "msa", + "my": "mya", "na": "nau", "nv": "nav", "nr": "nbl", "nd": "nde", "ng": "ndo", "ne": "nep", + "nl": "nld", "nn": "nno", "nb": "nob", "ny": "nya", "oc": "oci", "oj": "oji", "or": "ori", + "om": "orm", "os": "oss", "pa": "pan", - "ps": "pus", "pi": "pli", "pl": "pol", "pt": "por", + "ps": "pus", "qu": "que", "rm": "roh", + "ro": "ron", "rn": "run", "ru": "rus", "sg": "sag", "sa": "san", - "sr": "srp", "si": "sin", "sk": "slk", "sl": "slv", @@ -770,7 +767,9 @@ "so": "som", "st": "sot", "es": "spa", + "sq": "sqi", "sc": "srd", + "sr": "srp", "ss": "ssw", "su": "sun", "sw": "swa", @@ -800,6 +799,7 @@ "yi": "yid", "yo": "yor", "za": "zha", + "zh": "zho", "zu": "zul" } } diff --git a/src/Symfony/Component/Intl/Scripts.php b/src/Symfony/Component/Intl/Scripts.php index bf26969c06..943ef8b469 100644 --- a/src/Symfony/Component/Intl/Scripts.php +++ b/src/Symfony/Component/Intl/Scripts.php @@ -51,7 +51,7 @@ final class Scripts extends ResourceBundle /** * @return string[] */ - public static function getNames($displayLocale = null) + public static function getNames($displayLocale = null): array { return self::asort(self::readEntry(['Names'], $displayLocale), $displayLocale); } diff --git a/src/Symfony/Component/Intl/Tests/Data/Provider/AbstractLanguageDataProviderTest.php b/src/Symfony/Component/Intl/Tests/Data/Provider/AbstractLanguageDataProviderTest.php index 50ccf78fd2..e2a24288b5 100644 --- a/src/Symfony/Component/Intl/Tests/Data/Provider/AbstractLanguageDataProviderTest.php +++ b/src/Symfony/Component/Intl/Tests/Data/Provider/AbstractLanguageDataProviderTest.php @@ -648,11 +648,9 @@ abstract class AbstractLanguageDataProviderTest extends AbstractDataProviderTest 'ab' => 'abk', 'af' => 'afr', 'ak' => 'aka', - 'sq' => 'sqi', 'am' => 'amh', 'ar' => 'ara', 'an' => 'arg', - 'hy' => 'hye', 'as' => 'asm', 'av' => 'ava', 'ae' => 'ave', @@ -660,7 +658,6 @@ abstract class AbstractLanguageDataProviderTest extends AbstractDataProviderTest 'az' => 'aze', 'ba' => 'bak', 'bm' => 'bam', - 'eu' => 'eus', 'be' => 'bel', 'bn' => 'ben', 'bi' => 'bis', @@ -668,12 +665,10 @@ abstract class AbstractLanguageDataProviderTest extends AbstractDataProviderTest 'bs' => 'bos', 'br' => 'bre', 'bg' => 'bul', - 'my' => 'mya', 'ca' => 'cat', 'cs' => 'ces', 'ch' => 'cha', 'ce' => 'che', - 'zh' => 'zho', 'cu' => 'chu', 'cv' => 'chv', 'kw' => 'cor', @@ -683,13 +678,12 @@ abstract class AbstractLanguageDataProviderTest extends AbstractDataProviderTest 'da' => 'dan', 'de' => 'deu', 'dv' => 'div', - 'nl' => 'nld', 'dz' => 'dzo', - 'et' => 'est', 'el' => 'ell', 'en' => 'eng', 'eo' => 'epo', - 'ik' => 'ipk', + 'et' => 'est', + 'eu' => 'eus', 'ee' => 'ewe', 'fo' => 'fao', 'fa' => 'fas', @@ -698,8 +692,6 @@ abstract class AbstractLanguageDataProviderTest extends AbstractDataProviderTest 'fr' => 'fra', 'fy' => 'fry', 'ff' => 'ful', - 'om' => 'orm', - 'ka' => 'kat', 'gd' => 'gla', 'ga' => 'gle', 'gl' => 'glg', @@ -714,32 +706,34 @@ abstract class AbstractLanguageDataProviderTest extends AbstractDataProviderTest 'ho' => 'hmo', 'hr' => 'hrv', 'hu' => 'hun', + 'hy' => 'hye', 'ig' => 'ibo', - 'is' => 'isl', 'io' => 'ido', 'ii' => 'iii', 'iu' => 'iku', 'ie' => 'ile', 'ia' => 'ina', 'id' => 'ind', + 'ik' => 'ipk', + 'is' => 'isl', 'it' => 'ita', 'jv' => 'jav', 'ja' => 'jpn', 'kl' => 'kal', 'kn' => 'kan', 'ks' => 'kas', + 'ka' => 'kat', 'kr' => 'kau', 'kk' => 'kaz', - 'mn' => 'mon', 'km' => 'khm', 'ki' => 'kik', 'rw' => 'kin', 'ky' => 'kir', - 'ku' => 'kur', - 'kg' => 'kon', 'kv' => 'kom', + 'kg' => 'kon', 'ko' => 'kor', 'kj' => 'kua', + 'ku' => 'kur', 'lo' => 'lao', 'la' => 'lat', 'lv' => 'lav', @@ -749,32 +743,36 @@ abstract class AbstractLanguageDataProviderTest extends AbstractDataProviderTest 'lb' => 'ltz', 'lu' => 'lub', 'lg' => 'lug', - 'mk' => 'mkd', 'mh' => 'mah', 'ml' => 'mal', - 'mi' => 'mri', 'mr' => 'mar', - 'ms' => 'msa', + 'mk' => 'mkd', 'mg' => 'mlg', 'mt' => 'mlt', + 'mn' => 'mon', + 'mi' => 'mri', + 'ms' => 'msa', + 'my' => 'mya', 'na' => 'nau', 'nv' => 'nav', 'nr' => 'nbl', 'nd' => 'nde', 'ng' => 'ndo', 'ne' => 'nep', + 'nl' => 'nld', 'nn' => 'nno', 'nb' => 'nob', 'ny' => 'nya', 'oc' => 'oci', 'oj' => 'oji', 'or' => 'ori', + 'om' => 'orm', 'os' => 'oss', 'pa' => 'pan', - 'ps' => 'pus', 'pi' => 'pli', 'pl' => 'pol', 'pt' => 'por', + 'ps' => 'pus', 'qu' => 'que', 'rm' => 'roh', 'ro' => 'ron', @@ -782,7 +780,6 @@ abstract class AbstractLanguageDataProviderTest extends AbstractDataProviderTest 'ru' => 'rus', 'sg' => 'sag', 'sa' => 'san', - 'sr' => 'srp', 'si' => 'sin', 'sk' => 'slk', 'sl' => 'slv', @@ -793,7 +790,9 @@ abstract class AbstractLanguageDataProviderTest extends AbstractDataProviderTest 'so' => 'som', 'st' => 'sot', 'es' => 'spa', + 'sq' => 'sqi', 'sc' => 'srd', + 'sr' => 'srp', 'ss' => 'ssw', 'su' => 'sun', 'sw' => 'swa', @@ -823,6 +822,7 @@ abstract class AbstractLanguageDataProviderTest extends AbstractDataProviderTest 'yi' => 'yid', 'yo' => 'yor', 'za' => 'zha', + 'zh' => 'zho', 'zu' => 'zul', ]; diff --git a/src/Symfony/Component/Intl/Tests/LanguagesTest.php b/src/Symfony/Component/Intl/Tests/LanguagesTest.php index 4febf34df6..18249097e8 100644 --- a/src/Symfony/Component/Intl/Tests/LanguagesTest.php +++ b/src/Symfony/Component/Intl/Tests/LanguagesTest.php @@ -645,11 +645,9 @@ class LanguagesTest extends ResourceBundleTestCase 'ab' => 'abk', 'af' => 'afr', 'ak' => 'aka', - 'sq' => 'sqi', 'am' => 'amh', 'ar' => 'ara', 'an' => 'arg', - 'hy' => 'hye', 'as' => 'asm', 'av' => 'ava', 'ae' => 'ave', @@ -657,7 +655,6 @@ class LanguagesTest extends ResourceBundleTestCase 'az' => 'aze', 'ba' => 'bak', 'bm' => 'bam', - 'eu' => 'eus', 'be' => 'bel', 'bn' => 'ben', 'bi' => 'bis', @@ -665,12 +662,10 @@ class LanguagesTest extends ResourceBundleTestCase 'bs' => 'bos', 'br' => 'bre', 'bg' => 'bul', - 'my' => 'mya', 'ca' => 'cat', 'cs' => 'ces', 'ch' => 'cha', 'ce' => 'che', - 'zh' => 'zho', 'cu' => 'chu', 'cv' => 'chv', 'kw' => 'cor', @@ -680,13 +675,12 @@ class LanguagesTest extends ResourceBundleTestCase 'da' => 'dan', 'de' => 'deu', 'dv' => 'div', - 'nl' => 'nld', 'dz' => 'dzo', - 'et' => 'est', 'el' => 'ell', 'en' => 'eng', 'eo' => 'epo', - 'ik' => 'ipk', + 'et' => 'est', + 'eu' => 'eus', 'ee' => 'ewe', 'fo' => 'fao', 'fa' => 'fas', @@ -695,8 +689,6 @@ class LanguagesTest extends ResourceBundleTestCase 'fr' => 'fra', 'fy' => 'fry', 'ff' => 'ful', - 'om' => 'orm', - 'ka' => 'kat', 'gd' => 'gla', 'ga' => 'gle', 'gl' => 'glg', @@ -711,32 +703,34 @@ class LanguagesTest extends ResourceBundleTestCase 'ho' => 'hmo', 'hr' => 'hrv', 'hu' => 'hun', + 'hy' => 'hye', 'ig' => 'ibo', - 'is' => 'isl', 'io' => 'ido', 'ii' => 'iii', 'iu' => 'iku', 'ie' => 'ile', 'ia' => 'ina', 'id' => 'ind', + 'ik' => 'ipk', + 'is' => 'isl', 'it' => 'ita', 'jv' => 'jav', 'ja' => 'jpn', 'kl' => 'kal', 'kn' => 'kan', 'ks' => 'kas', + 'ka' => 'kat', 'kr' => 'kau', 'kk' => 'kaz', - 'mn' => 'mon', 'km' => 'khm', 'ki' => 'kik', 'rw' => 'kin', 'ky' => 'kir', - 'ku' => 'kur', - 'kg' => 'kon', 'kv' => 'kom', + 'kg' => 'kon', 'ko' => 'kor', 'kj' => 'kua', + 'ku' => 'kur', 'lo' => 'lao', 'la' => 'lat', 'lv' => 'lav', @@ -746,32 +740,36 @@ class LanguagesTest extends ResourceBundleTestCase 'lb' => 'ltz', 'lu' => 'lub', 'lg' => 'lug', - 'mk' => 'mkd', 'mh' => 'mah', 'ml' => 'mal', - 'mi' => 'mri', 'mr' => 'mar', - 'ms' => 'msa', + 'mk' => 'mkd', 'mg' => 'mlg', 'mt' => 'mlt', + 'mn' => 'mon', + 'mi' => 'mri', + 'ms' => 'msa', + 'my' => 'mya', 'na' => 'nau', 'nv' => 'nav', 'nr' => 'nbl', 'nd' => 'nde', 'ng' => 'ndo', 'ne' => 'nep', + 'nl' => 'nld', 'nn' => 'nno', 'nb' => 'nob', 'ny' => 'nya', 'oc' => 'oci', 'oj' => 'oji', 'or' => 'ori', + 'om' => 'orm', 'os' => 'oss', 'pa' => 'pan', - 'ps' => 'pus', 'pi' => 'pli', 'pl' => 'pol', 'pt' => 'por', + 'ps' => 'pus', 'qu' => 'que', 'rm' => 'roh', 'ro' => 'ron', @@ -779,7 +777,6 @@ class LanguagesTest extends ResourceBundleTestCase 'ru' => 'rus', 'sg' => 'sag', 'sa' => 'san', - 'sr' => 'srp', 'si' => 'sin', 'sk' => 'slk', 'sl' => 'slv', @@ -790,7 +787,9 @@ class LanguagesTest extends ResourceBundleTestCase 'so' => 'som', 'st' => 'sot', 'es' => 'spa', + 'sq' => 'sqi', 'sc' => 'srd', + 'sr' => 'srp', 'ss' => 'ssw', 'su' => 'sun', 'sw' => 'swa', @@ -820,6 +819,7 @@ class LanguagesTest extends ResourceBundleTestCase 'yi' => 'yid', 'yo' => 'yor', 'za' => 'zha', + 'zh' => 'zho', 'zu' => 'zul', ]; From 226bdd18fb2e4735b59a6e15ca2b2572e342d001 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Deruss=C3=A9?= Date: Sun, 4 Aug 2019 18:55:16 +0200 Subject: [PATCH 02/15] Use PHPunit assertion --- .php_cs.dist | 2 +- .../Filesystem/Tests/FilesystemTest.php | 36 +++++++++---------- .../Handler/NativeFileSessionHandlerTest.php | 2 +- src/Symfony/Component/Intl/Tests/IntlTest.php | 2 +- .../Intl/Tests/Util/GitRepositoryTest.php | 2 +- 5 files changed, 22 insertions(+), 22 deletions(-) diff --git a/.php_cs.dist b/.php_cs.dist index 960f153ae6..e288ca8bc4 100644 --- a/.php_cs.dist +++ b/.php_cs.dist @@ -9,7 +9,7 @@ return PhpCsFixer\Config::create() '@Symfony' => true, '@Symfony:risky' => true, '@PHPUnit75Migration:risky' => true, - 'php_unit_dedicate_assert' => ['target' => '3.5'], + 'php_unit_dedicate_assert' => ['target' => '5.6'], 'phpdoc_no_empty_return' => false, // triggers almost always false positive 'array_syntax' => ['syntax' => 'short'], 'fopen_flags' => false, diff --git a/src/Symfony/Component/Filesystem/Tests/FilesystemTest.php b/src/Symfony/Component/Filesystem/Tests/FilesystemTest.php index 9b8d1a716a..a5b7f6dceb 100644 --- a/src/Symfony/Component/Filesystem/Tests/FilesystemTest.php +++ b/src/Symfony/Component/Filesystem/Tests/FilesystemTest.php @@ -153,7 +153,7 @@ class FilesystemTest extends FilesystemTestCase $this->filesystem->copy($sourceFilePath, $targetFilePath); - $this->assertTrue(is_dir($targetFileDirectory)); + $this->assertDirectoryExists($targetFileDirectory); $this->assertFileExists($targetFilePath); $this->assertStringEqualsFile($targetFilePath, 'SOURCE FILE'); } @@ -185,7 +185,7 @@ class FilesystemTest extends FilesystemTestCase $this->filesystem->mkdir($directory); - $this->assertTrue(is_dir($directory)); + $this->assertDirectoryExists($directory); } public function testMkdirCreatesDirectoriesFromArray() @@ -197,9 +197,9 @@ class FilesystemTest extends FilesystemTestCase $this->filesystem->mkdir($directories); - $this->assertTrue(is_dir($basePath.'1')); - $this->assertTrue(is_dir($basePath.'2')); - $this->assertTrue(is_dir($basePath.'3')); + $this->assertDirectoryExists($basePath.'1'); + $this->assertDirectoryExists($basePath.'2'); + $this->assertDirectoryExists($basePath.'3'); } public function testMkdirCreatesDirectoriesFromTraversableObject() @@ -211,9 +211,9 @@ class FilesystemTest extends FilesystemTestCase $this->filesystem->mkdir($directories); - $this->assertTrue(is_dir($basePath.'1')); - $this->assertTrue(is_dir($basePath.'2')); - $this->assertTrue(is_dir($basePath.'3')); + $this->assertDirectoryExists($basePath.'1'); + $this->assertDirectoryExists($basePath.'2'); + $this->assertDirectoryExists($basePath.'3'); } public function testMkdirCreatesDirectoriesFails() @@ -347,7 +347,7 @@ class FilesystemTest extends FilesystemTestCase // create symlink to dir using trailing forward slash $this->filesystem->symlink($basePath.'dir/', $basePath.'dir-link'); - $this->assertTrue(is_dir($basePath.'dir-link')); + $this->assertDirectoryExists($basePath.'dir-link'); // create symlink to nonexistent dir rmdir($basePath.'dir'); @@ -825,7 +825,7 @@ class FilesystemTest extends FilesystemTestCase $this->assertFalse(is_link($link)); $this->assertFalse(is_file($link)); - $this->assertFalse(is_dir($link)); + $this->assertDirectoryNotExists($link); } public function testSymlinkIsOverwrittenIfPointsToDifferentTarget() @@ -1170,8 +1170,8 @@ class FilesystemTest extends FilesystemTestCase $this->filesystem->mirror($sourcePath, $targetPath); - $this->assertTrue(is_dir($targetPath)); - $this->assertTrue(is_dir($targetPath.'directory')); + $this->assertDirectoryExists($targetPath); + $this->assertDirectoryExists($targetPath.'directory'); $this->assertFileEquals($file1, $targetPath.'directory'.\DIRECTORY_SEPARATOR.'file1'); $this->assertFileEquals($file2, $targetPath.'file2'); @@ -1204,7 +1204,7 @@ class FilesystemTest extends FilesystemTestCase $this->filesystem->mirror($sourcePath, $targetPath); - $this->assertTrue(is_dir($targetPath)); + $this->assertDirectoryExists($targetPath); $this->filesystem->remove($sourcePath); } @@ -1223,7 +1223,7 @@ class FilesystemTest extends FilesystemTestCase $this->filesystem->mirror($sourcePath, $targetPath); - $this->assertTrue(is_dir($targetPath)); + $this->assertDirectoryExists($targetPath); $this->assertFileEquals($sourcePath.'file1', $targetPath.'link1'); $this->assertTrue(is_link($targetPath.\DIRECTORY_SEPARATOR.'link1')); } @@ -1243,7 +1243,7 @@ class FilesystemTest extends FilesystemTestCase $this->filesystem->mirror($sourcePath, $targetPath); - $this->assertTrue(is_dir($targetPath)); + $this->assertDirectoryExists($targetPath); $this->assertFileEquals($sourcePath.'/nested/file1.txt', $targetPath.'link1/file1.txt'); $this->assertTrue(is_link($targetPath.\DIRECTORY_SEPARATOR.'link1')); } @@ -1267,7 +1267,7 @@ class FilesystemTest extends FilesystemTestCase $this->filesystem->mirror($sourcePath, $targetPath); - $this->assertTrue(is_dir($targetPath)); + $this->assertDirectoryExists($targetPath); $this->assertFileEquals($sourcePath.'/nested/file1.txt', $targetPath.'link1/file1.txt'); $this->assertTrue(is_link($targetPath.\DIRECTORY_SEPARATOR.'link1')); $this->assertEquals('\\' === \DIRECTORY_SEPARATOR ? realpath($sourcePath.'\nested') : 'nested', readlink($targetPath.\DIRECTORY_SEPARATOR.'link1')); @@ -1290,7 +1290,7 @@ class FilesystemTest extends FilesystemTestCase chdir($oldPath); - $this->assertTrue(is_dir($targetPath)); + $this->assertDirectoryExists($targetPath); $this->assertFileExists($targetPath.'source'); $this->assertFileExists($targetPath.'target'); } @@ -1315,7 +1315,7 @@ class FilesystemTest extends FilesystemTestCase chdir($oldPath); - $this->assertTrue(is_dir($targetPath)); + $this->assertDirectoryExists($targetPath); $this->assertFileExists($targetPath.'source'); $this->assertFileNotExists($targetPath.'target'); } diff --git a/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/NativeFileSessionHandlerTest.php b/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/NativeFileSessionHandlerTest.php index 348714a260..9daf1a0eee 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/NativeFileSessionHandlerTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/NativeFileSessionHandlerTest.php @@ -43,7 +43,7 @@ class NativeFileSessionHandlerTest extends TestCase { $handler = new NativeFileSessionHandler($savePath); $this->assertEquals($expectedSavePath, ini_get('session.save_path')); - $this->assertTrue(is_dir(realpath($path))); + $this->assertDirectoryExists(realpath($path)); rmdir($path); } diff --git a/src/Symfony/Component/Intl/Tests/IntlTest.php b/src/Symfony/Component/Intl/Tests/IntlTest.php index de722baf94..d45a1ded5c 100644 --- a/src/Symfony/Component/Intl/Tests/IntlTest.php +++ b/src/Symfony/Component/Intl/Tests/IntlTest.php @@ -61,7 +61,7 @@ class IntlTest extends TestCase public function testGetDataDirectoryReturnsThePathToIcuData() { - $this->assertTrue(is_dir(Intl::getDataDirectory())); + $this->assertDirectoryExists(Intl::getDataDirectory()); } /** diff --git a/src/Symfony/Component/Intl/Tests/Util/GitRepositoryTest.php b/src/Symfony/Component/Intl/Tests/Util/GitRepositoryTest.php index 0932d60433..0d98392ac2 100644 --- a/src/Symfony/Component/Intl/Tests/Util/GitRepositoryTest.php +++ b/src/Symfony/Component/Intl/Tests/Util/GitRepositoryTest.php @@ -51,7 +51,7 @@ class GitRepositoryTest extends TestCase $git = GitRepository::download(self::REPO_URL, $this->targetDir); $this->assertInstanceOf(GitRepository::class, $git); - $this->assertTrue(is_dir($this->targetDir.'/.git')); + $this->assertDirectoryExists($this->targetDir.'/.git'); $this->assertSame($this->targetDir, $git->getPath()); $this->assertSame(self::REPO_URL, $git->getUrl()); $this->assertRegExp('#^[0-9a-z]{40}$#', $git->getLastCommitHash()); From c7aad8d8009f0d609683d56345fa2692b7f6f90a Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Mon, 5 Aug 2019 07:56:08 +0200 Subject: [PATCH 03/15] fixed phpdocs --- src/Symfony/Component/Intl/Countries.php | 4 ++-- src/Symfony/Component/Intl/Languages.php | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/Intl/Countries.php b/src/Symfony/Component/Intl/Countries.php index f47a67418c..07812f5131 100644 --- a/src/Symfony/Component/Intl/Countries.php +++ b/src/Symfony/Component/Intl/Countries.php @@ -53,7 +53,7 @@ final class Countries extends ResourceBundle } /** - * Get country name from alpha2 code. + * Gets the country name from alpha2 code. * * @throws MissingResourceException if the country code does not exists */ @@ -63,7 +63,7 @@ final class Countries extends ResourceBundle } /** - * Get list of country names indexed with alpha2 codes as keys. + * Gets the list of country names indexed with alpha2 codes as keys. * * @return string[] */ diff --git a/src/Symfony/Component/Intl/Languages.php b/src/Symfony/Component/Intl/Languages.php index 3f597b8eeb..a70a7e8b9c 100644 --- a/src/Symfony/Component/Intl/Languages.php +++ b/src/Symfony/Component/Intl/Languages.php @@ -50,7 +50,7 @@ final class Languages extends ResourceBundle } /** - * Get language name from alpha2 code. + * Gets the language name from alpha2 code. * * @throws MissingResourceException if the language code does not exists */ @@ -60,7 +60,7 @@ final class Languages extends ResourceBundle } /** - * Get list of language names indexed with alpha2 codes as keys. + * Gets the list of language names indexed with alpha2 codes as keys. * * @return string[] */ From 920db2fc18f1a767c762f527b3e73cf86f713685 Mon Sep 17 00:00:00 2001 From: Amrouche Hamza Date: Mon, 5 Aug 2019 09:00:45 +0200 Subject: [PATCH 04/15] [Lock] Legacy test should implement legacy interface --- src/Symfony/Component/Lock/Tests/LockTest.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/Lock/Tests/LockTest.php b/src/Symfony/Component/Lock/Tests/LockTest.php index 1239ddba0f..38f8fc81af 100644 --- a/src/Symfony/Component/Lock/Tests/LockTest.php +++ b/src/Symfony/Component/Lock/Tests/LockTest.php @@ -18,6 +18,7 @@ use Symfony\Component\Lock\Exception\LockConflictedException; use Symfony\Component\Lock\Key; use Symfony\Component\Lock\Lock; use Symfony\Component\Lock\PersistingStoreInterface; +use Symfony\Component\Lock\StoreInterface; /** * @author Jérémy Derussé @@ -56,7 +57,7 @@ class LockTest extends TestCase public function testPassingOldStoreInterface() { $key = new Key(uniqid(__METHOD__, true)); - $store = $this->getMockBuilder(PersistingStoreInterface::class)->getMock(); + $store = $this->getMockBuilder(StoreInterface::class)->getMock(); $lock = new Lock($key, $store); $store From 2cfc5c7dd6ea3e3f7bd596f084c8aed68e238864 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Wed, 17 Apr 2019 21:13:54 +0200 Subject: [PATCH 05/15] [Security] add support for opportunistic password migrations --- .../Security/User/EntityUserProvider.php | 19 +++++++- .../Security/User/EntityUserProviderTest.php | 18 ++++++++ src/Symfony/Bridge/Doctrine/composer.json | 5 ++- .../SecurityBundle/Resources/config/guard.xml | 1 + .../Ldap/Security/LdapUserProvider.php | 28 +++++++++++- src/Symfony/Component/Security/CHANGELOG.md | 3 ++ .../Provider/DaoAuthenticationProvider.php | 9 +++- .../DaoAuthenticationProviderTest.php | 44 ++++++++++++++++++- .../Encoder/MigratingPasswordEncoderTest.php | 6 --- .../Encoder/TestPasswordEncoderInterface.php | 19 ++++++++ .../Core/Tests/User/ChainUserProviderTest.php | 24 ++++++++++ .../Security/Core/User/ChainUserProvider.php | 18 +++++++- .../Core/User/PasswordUpgraderInterface.php | 27 ++++++++++++ .../Guard/PasswordAuthenticatedInterface.php | 25 +++++++++++ .../Provider/GuardAuthenticationProvider.php | 12 +++-- 15 files changed, 242 insertions(+), 16 deletions(-) create mode 100644 src/Symfony/Component/Security/Core/Tests/Encoder/TestPasswordEncoderInterface.php create mode 100644 src/Symfony/Component/Security/Core/User/PasswordUpgraderInterface.php create mode 100644 src/Symfony/Component/Security/Guard/PasswordAuthenticatedInterface.php diff --git a/src/Symfony/Bridge/Doctrine/Security/User/EntityUserProvider.php b/src/Symfony/Bridge/Doctrine/Security/User/EntityUserProvider.php index 20f6839957..9a3ff10b82 100644 --- a/src/Symfony/Bridge/Doctrine/Security/User/EntityUserProvider.php +++ b/src/Symfony/Bridge/Doctrine/Security/User/EntityUserProvider.php @@ -14,6 +14,7 @@ namespace Symfony\Bridge\Doctrine\Security\User; use Doctrine\Common\Persistence\ManagerRegistry; use Symfony\Component\Security\Core\Exception\UnsupportedUserException; use Symfony\Component\Security\Core\Exception\UsernameNotFoundException; +use Symfony\Component\Security\Core\User\PasswordUpgraderInterface; use Symfony\Component\Security\Core\User\UserInterface; use Symfony\Component\Security\Core\User\UserProviderInterface; @@ -25,7 +26,7 @@ use Symfony\Component\Security\Core\User\UserProviderInterface; * @author Fabien Potencier * @author Johannes M. Schmitt */ -class EntityUserProvider implements UserProviderInterface +class EntityUserProvider implements UserProviderInterface, PasswordUpgraderInterface { private $registry; private $managerName; @@ -107,6 +108,22 @@ class EntityUserProvider implements UserProviderInterface return $class === $this->getClass() || is_subclass_of($class, $this->getClass()); } + /** + * {@inheritdoc} + */ + public function upgradePassword(UserInterface $user, string $newEncodedPassword): void + { + $class = $this->getClass(); + if (!$user instanceof $class) { + throw new UnsupportedUserException(sprintf('Instances of "%s" are not supported.', \get_class($user))); + } + + $repository = $this->getRepository(); + if ($repository instanceof PasswordUpgraderInterface) { + $repository->upgradePassword($user, $newEncodedPassword); + } + } + private function getObjectManager() { return $this->registry->getManager($this->managerName); diff --git a/src/Symfony/Bridge/Doctrine/Tests/Security/User/EntityUserProviderTest.php b/src/Symfony/Bridge/Doctrine/Tests/Security/User/EntityUserProviderTest.php index 50edcab8d0..c0b4a56e50 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Security/User/EntityUserProviderTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Security/User/EntityUserProviderTest.php @@ -16,6 +16,7 @@ use PHPUnit\Framework\TestCase; use Symfony\Bridge\Doctrine\Security\User\EntityUserProvider; use Symfony\Bridge\Doctrine\Test\DoctrineTestHelper; use Symfony\Bridge\Doctrine\Tests\Fixtures\User; +use Symfony\Component\Security\Core\User\PasswordUpgraderInterface; class EntityUserProviderTest extends TestCase { @@ -175,6 +176,23 @@ class EntityUserProviderTest extends TestCase $provider->loadUserByUsername('name'); } + public function testPasswordUpgrades() + { + $user = new User(1, 1, 'user1'); + + $repository = $this->getMockBuilder(PasswordUpgraderInterface::class)->getMock(); + $repository->expects($this->once()) + ->method('upgradePassword') + ->with($user, 'foobar'); + + $provider = new EntityUserProvider( + $this->getManager($this->getObjectManager($repository)), + 'Symfony\Bridge\Doctrine\Tests\Fixtures\User' + ); + + $provider->upgradePassword($user, 'foobar'); + } + private function getManager($em, $name = null) { $manager = $this->getMockBuilder('Doctrine\Common\Persistence\ManagerRegistry')->getMock(); diff --git a/src/Symfony/Bridge/Doctrine/composer.json b/src/Symfony/Bridge/Doctrine/composer.json index 3256c521fd..8017af5acf 100644 --- a/src/Symfony/Bridge/Doctrine/composer.json +++ b/src/Symfony/Bridge/Doctrine/composer.json @@ -33,7 +33,7 @@ "symfony/property-access": "^3.4|^4.0|^5.0", "symfony/property-info": "^3.4|^4.0|^5.0", "symfony/proxy-manager-bridge": "^3.4|^4.0|^5.0", - "symfony/security-core": "^3.4|^4.0|^5.0", + "symfony/security-core": "^4.4|^5.0", "symfony/expression-language": "^3.4|^4.0|^5.0", "symfony/validator": "^3.4|^4.0|^5.0", "symfony/translation": "^3.4|^4.0|^5.0", @@ -49,7 +49,8 @@ "phpunit/phpunit": "<4.8.35|<5.4.3,>=5.0", "symfony/dependency-injection": "<3.4", "symfony/form": "<4.4", - "symfony/messenger": "<4.3" + "symfony/messenger": "<4.3", + "symfony/security-core": "<4.4" }, "suggest": { "symfony/form": "", diff --git a/src/Symfony/Bundle/SecurityBundle/Resources/config/guard.xml b/src/Symfony/Bundle/SecurityBundle/Resources/config/guard.xml index 43321494e0..7b17aff868 100644 --- a/src/Symfony/Bundle/SecurityBundle/Resources/config/guard.xml +++ b/src/Symfony/Bundle/SecurityBundle/Resources/config/guard.xml @@ -29,6 +29,7 @@ + * @author Robin Chalas */ -class LdapUserProvider implements UserProviderInterface +class LdapUserProvider implements UserProviderInterface, PasswordUpgraderInterface { private $ldap; private $baseDn; @@ -109,6 +111,30 @@ class LdapUserProvider implements UserProviderInterface return new LdapUser($user->getEntry(), $user->getUsername(), $user->getPassword(), $user->getRoles()); } + /** + * {@inheritdoc} + */ + public function upgradePassword(UserInterface $user, string $newEncodedPassword): void + { + if (!$user instanceof LdapUser) { + throw new UnsupportedUserException(sprintf('Instances of "%s" are not supported.', \get_class($user))); + } + + if (null === $this->passwordAttribute) { + return; + } + + try { + if ($user->isEqualTo($this->loadUserByUsername($user->getUsername()))) { + $user->getEntry()->setAttribute($this->passwordAttribute, [$newEncodedPassword]); + $this->ldap->getEntryManager()->update($user->getEntry()); + $user->setPassword($newEncodedPassword); + } + } catch (ExceptionInterface $e) { + // ignore failed password upgrades + } + } + /** * {@inheritdoc} */ diff --git a/src/Symfony/Component/Security/CHANGELOG.md b/src/Symfony/Component/Security/CHANGELOG.md index 3ac23ef992..6c14764368 100644 --- a/src/Symfony/Component/Security/CHANGELOG.md +++ b/src/Symfony/Component/Security/CHANGELOG.md @@ -7,6 +7,9 @@ CHANGELOG * Deprecated class `LdapUserProvider`, use `Symfony\Component\Ldap\Security\LdapUserProvider` instead * Added method `needsRehash()` to `PasswordEncoderInterface` and `UserPasswordEncoderInterface` * Added `MigratingPasswordEncoder` + * Added and implemented `PasswordUpgraderInterface`, for opportunistic password migrations + * Added `Guard\PasswordAuthenticatedInterface`, an optional interface + for "guard" authenticators that deal with user passwords 4.3.0 ----- diff --git a/src/Symfony/Component/Security/Core/Authentication/Provider/DaoAuthenticationProvider.php b/src/Symfony/Component/Security/Core/Authentication/Provider/DaoAuthenticationProvider.php index f8a1019723..ac635357d6 100644 --- a/src/Symfony/Component/Security/Core/Authentication/Provider/DaoAuthenticationProvider.php +++ b/src/Symfony/Component/Security/Core/Authentication/Provider/DaoAuthenticationProvider.php @@ -16,6 +16,7 @@ use Symfony\Component\Security\Core\Encoder\EncoderFactoryInterface; use Symfony\Component\Security\Core\Exception\AuthenticationServiceException; use Symfony\Component\Security\Core\Exception\BadCredentialsException; use Symfony\Component\Security\Core\Exception\UsernameNotFoundException; +use Symfony\Component\Security\Core\User\PasswordUpgraderInterface; use Symfony\Component\Security\Core\User\UserCheckerInterface; use Symfony\Component\Security\Core\User\UserInterface; use Symfony\Component\Security\Core\User\UserProviderInterface; @@ -54,9 +55,15 @@ class DaoAuthenticationProvider extends UserAuthenticationProvider throw new BadCredentialsException('The presented password cannot be empty.'); } - if (!$this->encoderFactory->getEncoder($user)->isPasswordValid($user->getPassword(), $presentedPassword, $user->getSalt())) { + $encoder = $this->encoderFactory->getEncoder($user); + + if (!$encoder->isPasswordValid($user->getPassword(), $presentedPassword, $user->getSalt())) { throw new BadCredentialsException('The presented password is invalid.'); } + + if ($this->userProvider instanceof PasswordUpgraderInterface && method_exists($encoder, 'needsRehash') && $encoder->needsRehash($user->getPassword())) { + $this->userProvider->upgradePassword($user, $encoder->encodePassword($presentedPassword, $user->getSalt())); + } } } diff --git a/src/Symfony/Component/Security/Core/Tests/Authentication/Provider/DaoAuthenticationProviderTest.php b/src/Symfony/Component/Security/Core/Tests/Authentication/Provider/DaoAuthenticationProviderTest.php index d9f8a54a75..0981b13c8f 100644 --- a/src/Symfony/Component/Security/Core/Tests/Authentication/Provider/DaoAuthenticationProviderTest.php +++ b/src/Symfony/Component/Security/Core/Tests/Authentication/Provider/DaoAuthenticationProviderTest.php @@ -15,6 +15,10 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\Security\Core\Authentication\Provider\DaoAuthenticationProvider; use Symfony\Component\Security\Core\Encoder\PlaintextPasswordEncoder; use Symfony\Component\Security\Core\Exception\UsernameNotFoundException; +use Symfony\Component\Security\Core\Tests\Encoder\TestPasswordEncoderInterface; +use Symfony\Component\Security\Core\User\PasswordUpgraderInterface; +use Symfony\Component\Security\Core\User\User; +use Symfony\Component\Security\Core\User\UserProviderInterface; class DaoAuthenticationProviderTest extends TestCase { @@ -247,6 +251,44 @@ class DaoAuthenticationProviderTest extends TestCase $method->invoke($provider, $this->getMockBuilder('Symfony\\Component\\Security\\Core\\User\\UserInterface')->getMock(), $token); } + public function testPasswordUpgrades() + { + $user = new User('user', 'pwd'); + + $encoder = $this->getMockBuilder(TestPasswordEncoderInterface::class)->getMock(); + $encoder->expects($this->once()) + ->method('isPasswordValid') + ->willReturn(true) + ; + $encoder->expects($this->once()) + ->method('encodePassword') + ->willReturn('foobar') + ; + $encoder->expects($this->once()) + ->method('needsRehash') + ->willReturn(true) + ; + + $provider = $this->getProvider(null, null, $encoder); + + $userProvider = ((array) $provider)[sprintf("\0%s\0userProvider", DaoAuthenticationProvider::class)]; + $userProvider->expects($this->once()) + ->method('upgradePassword') + ->with($user, 'foobar') + ; + + $method = new \ReflectionMethod($provider, 'checkAuthentication'); + $method->setAccessible(true); + + $token = $this->getSupportedToken(); + $token->expects($this->once()) + ->method('getCredentials') + ->willReturn('foo') + ; + + $method->invoke($provider, $user, $token); + } + protected function getSupportedToken() { $mock = $this->getMockBuilder('Symfony\\Component\\Security\\Core\\Authentication\\Token\\UsernamePasswordToken')->setMethods(['getCredentials', 'getUser', 'getProviderKey'])->disableOriginalConstructor()->getMock(); @@ -261,7 +303,7 @@ class DaoAuthenticationProviderTest extends TestCase protected function getProvider($user = null, $userChecker = null, $passwordEncoder = null) { - $userProvider = $this->getMockBuilder('Symfony\\Component\\Security\\Core\\User\\UserProviderInterface')->getMock(); + $userProvider = $this->getMockBuilder([UserProviderInterface::class, PasswordUpgraderInterface::class])->getMock(); if (null !== $user) { $userProvider->expects($this->once()) ->method('loadUserByUsername') diff --git a/src/Symfony/Component/Security/Core/Tests/Encoder/MigratingPasswordEncoderTest.php b/src/Symfony/Component/Security/Core/Tests/Encoder/MigratingPasswordEncoderTest.php index 245d6c182d..468c326f35 100644 --- a/src/Symfony/Component/Security/Core/Tests/Encoder/MigratingPasswordEncoderTest.php +++ b/src/Symfony/Component/Security/Core/Tests/Encoder/MigratingPasswordEncoderTest.php @@ -14,7 +14,6 @@ namespace Symfony\Component\Security\Core\Tests\Encoder; use PHPUnit\Framework\TestCase; use Symfony\Component\Security\Core\Encoder\MigratingPasswordEncoder; use Symfony\Component\Security\Core\Encoder\NativePasswordEncoder; -use Symfony\Component\Security\Core\Encoder\PasswordEncoderInterface; class MigratingPasswordEncoderTest extends TestCase { @@ -66,8 +65,3 @@ class MigratingPasswordEncoderTest extends TestCase $this->assertTrue($encoder->isPasswordValid('abc', 'foo', 'salt')); } } - -interface TestPasswordEncoderInterface extends PasswordEncoderInterface -{ - public function needsRehash(string $encoded): bool; -} diff --git a/src/Symfony/Component/Security/Core/Tests/Encoder/TestPasswordEncoderInterface.php b/src/Symfony/Component/Security/Core/Tests/Encoder/TestPasswordEncoderInterface.php new file mode 100644 index 0000000000..13e2d0d3b3 --- /dev/null +++ b/src/Symfony/Component/Security/Core/Tests/Encoder/TestPasswordEncoderInterface.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Security\Core\Tests\Encoder; + +use Symfony\Component\Security\Core\Encoder\PasswordEncoderInterface; + +interface TestPasswordEncoderInterface extends PasswordEncoderInterface +{ + public function needsRehash(string $encoded): bool; +} diff --git a/src/Symfony/Component/Security/Core/Tests/User/ChainUserProviderTest.php b/src/Symfony/Component/Security/Core/Tests/User/ChainUserProviderTest.php index 1592bcd2fe..aa9ade7020 100644 --- a/src/Symfony/Component/Security/Core/Tests/User/ChainUserProviderTest.php +++ b/src/Symfony/Component/Security/Core/Tests/User/ChainUserProviderTest.php @@ -15,6 +15,8 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\Security\Core\Exception\UnsupportedUserException; use Symfony\Component\Security\Core\Exception\UsernameNotFoundException; use Symfony\Component\Security\Core\User\ChainUserProvider; +use Symfony\Component\Security\Core\User\PasswordUpgraderInterface; +use Symfony\Component\Security\Core\User\User; class ChainUserProviderTest extends TestCase { @@ -188,6 +190,28 @@ class ChainUserProviderTest extends TestCase $this->assertSame($account, $provider->refreshUser($this->getAccount())); } + public function testPasswordUpgrades() + { + $user = new User('user', 'pwd'); + + $provider1 = $this->getMockBuilder(PasswordUpgraderInterface::class)->getMock(); + $provider1 + ->expects($this->once()) + ->method('upgradePassword') + ->willThrowException(new UnsupportedUserException('unsupported')) + ; + + $provider2 = $this->getMockBuilder(PasswordUpgraderInterface::class)->getMock(); + $provider2 + ->expects($this->once()) + ->method('upgradePassword') + ->with($user, 'foobar') + ; + + $provider = new ChainUserProvider([$provider1, $provider2]); + $provider->upgradePassword($user, 'foobar'); + } + protected function getAccount() { return $this->getMockBuilder('Symfony\Component\Security\Core\User\UserInterface')->getMock(); diff --git a/src/Symfony/Component/Security/Core/User/ChainUserProvider.php b/src/Symfony/Component/Security/Core/User/ChainUserProvider.php index 4106ad190a..b5dff59870 100644 --- a/src/Symfony/Component/Security/Core/User/ChainUserProvider.php +++ b/src/Symfony/Component/Security/Core/User/ChainUserProvider.php @@ -22,7 +22,7 @@ use Symfony\Component\Security\Core\Exception\UsernameNotFoundException; * * @author Johannes M. Schmitt */ -class ChainUserProvider implements UserProviderInterface +class ChainUserProvider implements UserProviderInterface, PasswordUpgraderInterface { private $providers; @@ -104,4 +104,20 @@ class ChainUserProvider implements UserProviderInterface return false; } + + /** + * {@inheritdoc} + */ + public function upgradePassword(UserInterface $user, string $newEncodedPassword): void + { + foreach ($this->providers as $provider) { + if ($provider instanceof PasswordUpgraderInterface) { + try { + $provider->upgradePassword($user, $newEncodedPassword); + } catch (UnsupportedUserException $e) { + // ignore: password upgrades are opportunistic + } + } + } + } } diff --git a/src/Symfony/Component/Security/Core/User/PasswordUpgraderInterface.php b/src/Symfony/Component/Security/Core/User/PasswordUpgraderInterface.php new file mode 100644 index 0000000000..9c65298b07 --- /dev/null +++ b/src/Symfony/Component/Security/Core/User/PasswordUpgraderInterface.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Security\Core\User; + +/** + * @author Nicolas Grekas + */ +interface PasswordUpgraderInterface +{ + /** + * Upgrades the encoded password of a user, typically for using a better hash algorithm. + * + * This method should persist the new password in the user storage and update the $user object accordingly. + * Because you don't want your users not being able to log in, this method should be opportunistic: + * it's fine if it does nothing or if it fails without throwing any exception. + */ + public function upgradePassword(UserInterface $user, string $newEncodedPassword): void; +} diff --git a/src/Symfony/Component/Security/Guard/PasswordAuthenticatedInterface.php b/src/Symfony/Component/Security/Guard/PasswordAuthenticatedInterface.php new file mode 100644 index 0000000000..4dd7a7b446 --- /dev/null +++ b/src/Symfony/Component/Security/Guard/PasswordAuthenticatedInterface.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Security\Guard; + +/** + * An optional interface for "guard" authenticators that deal with user passwords. + */ +interface PasswordAuthenticatedInterface +{ + /** + * Returns the clear-text password contained in credentials if any. + * + * @param mixed The user credentials + */ + public function getPassword($credentials): ?string; +} diff --git a/src/Symfony/Component/Security/Guard/Provider/GuardAuthenticationProvider.php b/src/Symfony/Component/Security/Guard/Provider/GuardAuthenticationProvider.php index ece66a8df0..ac295a6d08 100644 --- a/src/Symfony/Component/Security/Guard/Provider/GuardAuthenticationProvider.php +++ b/src/Symfony/Component/Security/Guard/Provider/GuardAuthenticationProvider.php @@ -13,14 +13,17 @@ namespace Symfony\Component\Security\Guard\Provider; use Symfony\Component\Security\Core\Authentication\Provider\AuthenticationProviderInterface; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; +use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface; use Symfony\Component\Security\Core\Exception\AuthenticationException; use Symfony\Component\Security\Core\Exception\AuthenticationExpiredException; use Symfony\Component\Security\Core\Exception\BadCredentialsException; use Symfony\Component\Security\Core\Exception\UsernameNotFoundException; +use Symfony\Component\Security\Core\User\PasswordUpgraderInterface; use Symfony\Component\Security\Core\User\UserCheckerInterface; use Symfony\Component\Security\Core\User\UserInterface; use Symfony\Component\Security\Core\User\UserProviderInterface; use Symfony\Component\Security\Guard\AuthenticatorInterface; +use Symfony\Component\Security\Guard\PasswordAuthenticatedInterface; use Symfony\Component\Security\Guard\Token\GuardTokenInterface; use Symfony\Component\Security\Guard\Token\PreAuthenticationGuardToken; @@ -39,19 +42,19 @@ class GuardAuthenticationProvider implements AuthenticationProviderInterface private $userProvider; private $providerKey; private $userChecker; + private $passwordEncoder; /** * @param iterable|AuthenticatorInterface[] $guardAuthenticators The authenticators, with keys that match what's passed to GuardAuthenticationListener - * @param UserProviderInterface $userProvider The user provider * @param string $providerKey The provider (i.e. firewall) key - * @param UserCheckerInterface $userChecker */ - public function __construct($guardAuthenticators, UserProviderInterface $userProvider, string $providerKey, UserCheckerInterface $userChecker) + public function __construct($guardAuthenticators, UserProviderInterface $userProvider, string $providerKey, UserCheckerInterface $userChecker, UserPasswordEncoderInterface $passwordEncoder = null) { $this->guardAuthenticators = $guardAuthenticators; $this->userProvider = $userProvider; $this->providerKey = $providerKey; $this->userChecker = $userChecker; + $this->passwordEncoder = $passwordEncoder; } /** @@ -113,6 +116,9 @@ class GuardAuthenticationProvider implements AuthenticationProviderInterface if (true !== $guardAuthenticator->checkCredentials($token->getCredentials(), $user)) { throw new BadCredentialsException(sprintf('Authentication failed because %s::checkCredentials() did not return true.', \get_class($guardAuthenticator))); } + if ($this->userProvider instanceof PasswordUpgraderInterface && $guardAuthenticator instanceof PasswordAuthenticatedInterface && null !== $this->passwordEncoder && (null !== $password = $guardAuthenticator->getPassword($token->getCredentials())) && method_exists($this->passwordEncoder, 'needsRehash') && $this->passwordEncoder->needsRehash($user)) { + $this->userProvider->upgradePassword($user, $this->passwordEncoder->encodePassword($user, $password)); + } $this->userChecker->checkPostAuth($user); // turn the UserInterface into a TokenInterface From fbef8543cdf49e3f9593f1688ed9e1879ec33922 Mon Sep 17 00:00:00 2001 From: Pierre du Plessis Date: Mon, 5 Aug 2019 10:53:31 +0200 Subject: [PATCH 06/15] [Yaml] Removed unused $nullAsTilde property --- src/Symfony/Component/Yaml/Inline.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Symfony/Component/Yaml/Inline.php b/src/Symfony/Component/Yaml/Inline.php index c028ccf071..2d4e1be2fd 100644 --- a/src/Symfony/Component/Yaml/Inline.php +++ b/src/Symfony/Component/Yaml/Inline.php @@ -33,7 +33,6 @@ class Inline private static $objectSupport = false; private static $objectForMap = false; private static $constantSupport = false; - private static $nullAsTilde = false; /** * @param int $flags @@ -46,7 +45,6 @@ class Inline self::$objectSupport = (bool) (Yaml::PARSE_OBJECT & $flags); self::$objectForMap = (bool) (Yaml::PARSE_OBJECT_FOR_MAP & $flags); self::$constantSupport = (bool) (Yaml::PARSE_CONSTANT & $flags); - self::$nullAsTilde = (bool) (Yaml::DUMP_NULL_AS_TILDE & $flags); self::$parsedFilename = $parsedFilename; if (null !== $parsedLineNumber) { From 0c9539fdb47fbd13f2657231b3ac87aa965240c3 Mon Sep 17 00:00:00 2001 From: karser Date: Fri, 2 Aug 2019 22:29:48 +0300 Subject: [PATCH 07/15] [PhpUnitBridge] fixed PHPUnit 8.3 compatibility: method handleError was renamed to __invoke --- .../PhpUnit/DeprecationErrorHandler.php | 40 ++++++++++++++----- 1 file changed, 31 insertions(+), 9 deletions(-) diff --git a/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler.php b/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler.php index fc60cbd436..8b355c31ff 100644 --- a/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler.php +++ b/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler.php @@ -11,6 +11,9 @@ namespace Symfony\Bridge\PhpUnit; +use PHPUnit\Framework\TestResult; +use PHPUnit\Util\ErrorHandler; + /** * Catch deprecation notices and print a summary report at the end of the test suite. * @@ -23,6 +26,7 @@ class DeprecationErrorHandler const MODE_DISABLED = 'disabled'; private static $isRegistered = false; + private static $isAtLeastPhpUnit83; /** * Registers and configures the deprecation handler. @@ -44,6 +48,7 @@ class DeprecationErrorHandler } $UtilPrefix = class_exists('PHPUnit_Util_ErrorHandler') ? 'PHPUnit_Util_' : 'PHPUnit\Util\\'; + self::$isAtLeastPhpUnit83 = method_exists('PHPUnit\Util\ErrorHandler', '__invoke'); $getMode = function () use ($mode) { static $memoizedMode = false; @@ -106,9 +111,7 @@ class DeprecationErrorHandler ); $deprecationHandler = function ($type, $msg, $file, $line, $context = array()) use (&$deprecations, $getMode, $UtilPrefix, $inVendors) { if ((E_USER_DEPRECATED !== $type && E_DEPRECATED !== $type) || DeprecationErrorHandler::MODE_DISABLED === $mode = $getMode()) { - $ErrorHandler = $UtilPrefix.'ErrorHandler'; - - return $ErrorHandler::handleError($type, $msg, $file, $line, $context); + return \call_user_func(DeprecationErrorHandler::getPhpUnitErrorHandler(), $type, $msg, $file, $line, $context); } $trace = debug_backtrace(); @@ -183,7 +186,7 @@ class DeprecationErrorHandler if (null !== $oldErrorHandler) { restore_error_handler(); - if (array($UtilPrefix.'ErrorHandler', 'handleError') === $oldErrorHandler) { + if ($oldErrorHandler instanceof ErrorHandler || array($UtilPrefix.'ErrorHandler', 'handleError') === $oldErrorHandler) { restore_error_handler(); self::register($mode); } @@ -285,12 +288,8 @@ class DeprecationErrorHandler if ($previousErrorHandler) { return $previousErrorHandler($type, $msg, $file, $line, $context); } - static $autoload = true; - $ErrorHandler = class_exists('PHPUnit_Util_ErrorHandler', $autoload) ? 'PHPUnit_Util_ErrorHandler' : 'PHPUnit\Util\ErrorHandler'; - $autoload = false; - - return $ErrorHandler::handleError($type, $msg, $file, $line, $context); + return \call_user_func(DeprecationErrorHandler::getPhpUnitErrorHandler(), $type, $msg, $file, $line, $context); } $deprecations[] = array(error_reporting(), $msg, $file); }); @@ -300,6 +299,29 @@ class DeprecationErrorHandler }); } + /** + * @internal + */ + public static function getPhpUnitErrorHandler() + { + if (!self::$isAtLeastPhpUnit83) { + return (class_exists('PHPUnit_Util_ErrorHandler', false) ? 'PHPUnit_Util_' : 'PHPUnit\Util\\').'ErrorHandler::handleError'; + } + + foreach (debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT | DEBUG_BACKTRACE_IGNORE_ARGS) as $frame) { + if (isset($frame['object']) && $frame['object'] instanceof TestResult) { + return new ErrorHandler( + $frame['object']->getConvertDeprecationsToExceptions(), + $frame['object']->getConvertErrorsToExceptions(), + $frame['object']->getConvertNoticesToExceptions(), + $frame['object']->getConvertWarningsToExceptions() + ); + } + } + + return function () { return false; }; + } + /** * Returns true if STDOUT is defined and supports colorization. * From b1e160c41e62aec2c496092505763e09e0bc8f15 Mon Sep 17 00:00:00 2001 From: Pierre du Plessis Date: Mon, 5 Aug 2019 12:19:56 +0200 Subject: [PATCH 08/15] Support DateTimeInterface in IntlDateFormatter::format --- .../Component/Intl/DateFormatter/IntlDateFormatter.php | 6 +++--- .../DateFormatter/AbstractIntlDateFormatterTest.php | 9 +++++++++ 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/Intl/DateFormatter/IntlDateFormatter.php b/src/Symfony/Component/Intl/DateFormatter/IntlDateFormatter.php index 0f19310f22..197a2e3db0 100644 --- a/src/Symfony/Component/Intl/DateFormatter/IntlDateFormatter.php +++ b/src/Symfony/Component/Intl/DateFormatter/IntlDateFormatter.php @@ -176,7 +176,7 @@ class IntlDateFormatter /** * Format the date/time value (timestamp) as a string. * - * @param int|\DateTime $timestamp The timestamp to format + * @param int|\DateTimeInterface $timestamp The timestamp to format * * @return string|bool The formatted value or false if formatting failed * @@ -195,7 +195,7 @@ class IntlDateFormatter // behave like the intl extension $argumentError = null; - if (!\is_int($timestamp) && !$timestamp instanceof \DateTime) { + if (!\is_int($timestamp) && !$timestamp instanceof \DateTimeInterface) { $argumentError = sprintf('datefmt_format: string \'%s\' is not numeric, which would be required for it to be a valid date', $timestamp); } @@ -207,7 +207,7 @@ class IntlDateFormatter return false; } - if ($timestamp instanceof \DateTime) { + if ($timestamp instanceof \DateTimeInterface) { $timestamp = $timestamp->getTimestamp(); } diff --git a/src/Symfony/Component/Intl/Tests/DateFormatter/AbstractIntlDateFormatterTest.php b/src/Symfony/Component/Intl/Tests/DateFormatter/AbstractIntlDateFormatterTest.php index e472000974..682380bf54 100644 --- a/src/Symfony/Component/Intl/Tests/DateFormatter/AbstractIntlDateFormatterTest.php +++ b/src/Symfony/Component/Intl/Tests/DateFormatter/AbstractIntlDateFormatterTest.php @@ -76,6 +76,7 @@ abstract class AbstractIntlDateFormatterTest extends TestCase public function formatProvider() { $dateTime = new \DateTime('@0'); + $dateTimeImmutable = new \DateTimeImmutable('@0'); $formatData = [ /* general */ @@ -250,6 +251,12 @@ abstract class AbstractIntlDateFormatterTest extends TestCase $formatData[] = ['h:mm a', $dateTime, '12:00 AM']; $formatData[] = ['yyyyy.MMMM.dd hh:mm aaa', $dateTime, '01970.January.01 12:00 AM']; + /* general, DateTimeImmutable */ + $formatData[] = ['y-M-d', $dateTimeImmutable, '1970-1-1']; + $formatData[] = ["EEE, MMM d, ''yy", $dateTimeImmutable, "Thu, Jan 1, '70"]; + $formatData[] = ['h:mm a', $dateTimeImmutable, '12:00 AM']; + $formatData[] = ['yyyyy.MMMM.dd hh:mm aaa', $dateTimeImmutable, '01970.January.01 12:00 AM']; + if (IcuVersion::compare(Intl::getIcuVersion(), '59.1', '>=', 1)) { // Before ICU 59.1 GMT was used instead of UTC $formatData[] = ["yyyy.MM.dd 'at' HH:mm:ss zzz", 0, '1970.01.01 at 00:00:00 UTC']; @@ -272,6 +279,8 @@ abstract class AbstractIntlDateFormatterTest extends TestCase $this->assertSame('1970.01.01 at 00:00:00 GMT', $gmtFormatter->format(new \DateTime('@0'))); $this->assertSame('1970.01.01 at 00:00:00 UTC', $utcFormatter->format(new \DateTime('@0'))); + $this->assertSame('1970.01.01 at 00:00:00 GMT', $gmtFormatter->format(new \DateTimeImmutable('@0'))); + $this->assertSame('1970.01.01 at 00:00:00 UTC', $utcFormatter->format(new \DateTimeImmutable('@0'))); } /** From 4cd60d61cc116eb5087805215d9b4a204499bfea Mon Sep 17 00:00:00 2001 From: Tobias Schultze Date: Mon, 5 Aug 2019 14:35:29 +0200 Subject: [PATCH 09/15] [Form] remove leftover int child phpdoc --- src/Symfony/Component/Form/Button.php | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/Symfony/Component/Form/Button.php b/src/Symfony/Component/Form/Button.php index ed1106b467..50acb8db0c 100644 --- a/src/Symfony/Component/Form/Button.php +++ b/src/Symfony/Component/Form/Button.php @@ -38,8 +38,6 @@ class Button implements \IteratorAggregate, FormInterface /** * Creates a new button from a form configuration. - * - * @param FormConfigInterface $config The button's configuration */ public function __construct(FormConfigInterface $config) { @@ -128,10 +126,6 @@ class Button implements \IteratorAggregate, FormInterface * * This method should not be invoked. * - * @param int|string|FormInterface $child - * @param null $type - * @param array $options - * * @throws BadMethodCallException */ public function add($child, $type = null, array $options = []) From e9293108c4d849fa70c788f989855bbbb2f3017e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Pineau?= Date: Mon, 5 Aug 2019 12:19:47 +0200 Subject: [PATCH 10/15] [Messenger] Fixed ConsumeMessagesCommand configuration --- .../Component/Messenger/Command/ConsumeMessagesCommand.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Messenger/Command/ConsumeMessagesCommand.php b/src/Symfony/Component/Messenger/Command/ConsumeMessagesCommand.php index 79c4aa3597..86ecaa284a 100644 --- a/src/Symfony/Component/Messenger/Command/ConsumeMessagesCommand.php +++ b/src/Symfony/Component/Messenger/Command/ConsumeMessagesCommand.php @@ -96,7 +96,7 @@ class ConsumeMessagesCommand extends Command new InputOption('memory-limit', 'm', InputOption::VALUE_REQUIRED, 'The memory limit the worker can consume'), new InputOption('time-limit', 't', InputOption::VALUE_REQUIRED, 'The time limit in seconds the worker can run'), new InputOption('sleep', null, InputOption::VALUE_REQUIRED, 'Seconds to sleep before asking for new messages after no messages were found', 1), - new InputOption('bus', 'b', InputOption::VALUE_REQUIRED, 'Name of the bus to which received messages should be dispatched (if not passed, bus is determined automatically.'), + new InputOption('bus', 'b', InputOption::VALUE_REQUIRED, 'Name of the bus to which received messages should be dispatched (if not passed, bus is determined automatically)'), ]) ->setDescription('Consumes messages') ->setHelp(<<<'EOF' From b7520f738d7f2b9b166679830b0d60229c64635a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Deruss=C3=A9?= Date: Mon, 5 Aug 2019 09:58:49 +0200 Subject: [PATCH 11/15] Add polyfill for PhpUnit namespace --- src/Symfony/Bridge/PhpUnit/CHANGELOG.md | 1 + .../Bridge/PhpUnit/CoverageListener.php | 2 +- .../PhpUnit/DeprecationErrorHandler.php | 19 ++-- .../DeprecationErrorHandler/Deprecation.php | 6 +- .../PhpUnit/Legacy/CoverageListenerTrait.php | 10 +-- .../PhpUnit/Legacy/PolyfillTestCaseTrait.php | 8 +- .../Legacy/SymfonyTestsListenerTrait.php | 52 +++-------- .../Bridge/PhpUnit/SymfonyTestsListener.php | 2 +- .../Fixtures/coverage/tests/bootstrap.php | 2 +- .../PhpUnit/Tests/ProcessIsolationTest.php | 3 +- src/Symfony/Bridge/PhpUnit/TextUI/Command.php | 2 +- src/Symfony/Bridge/PhpUnit/bootstrap.php | 89 +++++++++++++++++++ 12 files changed, 123 insertions(+), 73 deletions(-) diff --git a/src/Symfony/Bridge/PhpUnit/CHANGELOG.md b/src/Symfony/Bridge/PhpUnit/CHANGELOG.md index 92907ea25c..b85364ad7d 100644 --- a/src/Symfony/Bridge/PhpUnit/CHANGELOG.md +++ b/src/Symfony/Bridge/PhpUnit/CHANGELOG.md @@ -6,6 +6,7 @@ CHANGELOG * made the bridge act as a polyfill for newest PHPUnit features * added `SetUpTearDownTrait` to allow working around the `void` return-type added by PHPUnit 8 + * added namespace aliases for PHPUnit < 6 4.3.0 ----- diff --git a/src/Symfony/Bridge/PhpUnit/CoverageListener.php b/src/Symfony/Bridge/PhpUnit/CoverageListener.php index d41c26968f..805f9222a5 100644 --- a/src/Symfony/Bridge/PhpUnit/CoverageListener.php +++ b/src/Symfony/Bridge/PhpUnit/CoverageListener.php @@ -11,7 +11,7 @@ namespace Symfony\Bridge\PhpUnit; -if (class_exists('PHPUnit_Runner_Version') && version_compare(\PHPUnit_Runner_Version::id(), '6.0.0', '<')) { +if (version_compare(\PHPUnit\Runner\Version::id(), '6.0.0', '<')) { class_alias('Symfony\Bridge\PhpUnit\Legacy\CoverageListenerForV5', 'Symfony\Bridge\PhpUnit\CoverageListener'); } elseif (version_compare(\PHPUnit\Runner\Version::id(), '7.0.0', '<')) { class_alias('Symfony\Bridge\PhpUnit\Legacy\CoverageListenerForV6', 'Symfony\Bridge\PhpUnit\CoverageListener'); diff --git a/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler.php b/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler.php index e059fe2a9d..ca2805b923 100644 --- a/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler.php +++ b/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler.php @@ -11,6 +11,7 @@ namespace Symfony\Bridge\PhpUnit; +use PHPUnit\Util\ErrorHandler; use Symfony\Bridge\PhpUnit\DeprecationErrorHandler\Configuration; use Symfony\Bridge\PhpUnit\DeprecationErrorHandler\Deprecation; @@ -48,7 +49,6 @@ class DeprecationErrorHandler ]; private static $isRegistered = false; - private static $utilPrefix; /** * Registers and configures the deprecation handler. @@ -72,15 +72,13 @@ class DeprecationErrorHandler return; } - self::$utilPrefix = class_exists('PHPUnit_Util_ErrorHandler') ? 'PHPUnit_Util_' : 'PHPUnit\Util\\'; - $handler = new self(); $oldErrorHandler = set_error_handler([$handler, 'handleError']); if (null !== $oldErrorHandler) { restore_error_handler(); - if ([self::$utilPrefix.'ErrorHandler', 'handleError'] === $oldErrorHandler) { + if ([ErrorHandler::class, 'handleError'] === $oldErrorHandler) { restore_error_handler(); self::register($mode); } @@ -100,12 +98,7 @@ class DeprecationErrorHandler return $previousErrorHandler($type, $msg, $file, $line, $context); } - static $autoload = true; - - $ErrorHandler = class_exists('PHPUnit_Util_ErrorHandler', $autoload) ? 'PHPUnit_Util_ErrorHandler' : 'PHPUnit\Util\ErrorHandler'; - $autoload = false; - - return $ErrorHandler::handleError($type, $msg, $file, $line, $context); + return ErrorHandler::handleError($type, $msg, $file, $line, $context); } $deprecations[] = [error_reporting(), $msg, $file]; @@ -122,9 +115,7 @@ class DeprecationErrorHandler public function handleError($type, $msg, $file, $line, $context = []) { if ((E_USER_DEPRECATED !== $type && E_DEPRECATED !== $type) || !$this->getConfiguration()->isEnabled()) { - $ErrorHandler = self::$utilPrefix.'ErrorHandler'; - - return $ErrorHandler::handleError($type, $msg, $file, $line, $context); + return ErrorHandler::handleError($type, $msg, $file, $line, $context); } $deprecation = new Deprecation($msg, debug_backtrace(), $file); @@ -140,7 +131,7 @@ class DeprecationErrorHandler if (0 !== error_reporting()) { $group = 'unsilenced'; - } elseif ($deprecation->isLegacy(self::$utilPrefix)) { + } elseif ($deprecation->isLegacy()) { $group = 'legacy'; } else { $group = [ diff --git a/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler/Deprecation.php b/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler/Deprecation.php index 2d6aa29224..e5d2dc35d7 100644 --- a/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler/Deprecation.php +++ b/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler/Deprecation.php @@ -11,6 +11,7 @@ namespace Symfony\Bridge\PhpUnit\DeprecationErrorHandler; +use PHPUnit\Util\Test; use Symfony\Bridge\PhpUnit\Legacy\SymfonyTestsListenerFor; /** @@ -156,9 +157,8 @@ class Deprecation * * @return bool */ - public function isLegacy($utilPrefix) + public function isLegacy() { - $test = $utilPrefix.'Test'; $class = $this->originatingClass(); $method = $this->originatingMethod(); @@ -166,7 +166,7 @@ class Deprecation || 0 === strpos($method, 'provideLegacy') || 0 === strpos($method, 'getLegacy') || strpos($class, '\Legacy') - || \in_array('legacy', $test::getGroups($class, $method), true); + || \in_array('legacy', Test::getGroups($class, $method), true); } /** diff --git a/src/Symfony/Bridge/PhpUnit/Legacy/CoverageListenerTrait.php b/src/Symfony/Bridge/PhpUnit/Legacy/CoverageListenerTrait.php index 52d28cfbf8..1817004bf9 100644 --- a/src/Symfony/Bridge/PhpUnit/Legacy/CoverageListenerTrait.php +++ b/src/Symfony/Bridge/PhpUnit/Legacy/CoverageListenerTrait.php @@ -13,6 +13,7 @@ namespace Symfony\Bridge\PhpUnit\Legacy; use PHPUnit\Framework\TestCase; use PHPUnit\Framework\Warning; +use PHPUnit\Util\Test; /** * PHP 5.3 compatible trait-like shared implementation. @@ -65,12 +66,7 @@ class CoverageListenerTrait return; } - $testClass = \PHPUnit\Util\Test::class; - if (!class_exists($testClass, false)) { - $testClass = \PHPUnit_Util_Test::class; - } - - $r = new \ReflectionProperty($testClass, 'annotationCache'); + $r = new \ReflectionProperty(Test::class, 'annotationCache'); $r->setAccessible(true); $cache = $r->getValue(); @@ -79,7 +75,7 @@ class CoverageListenerTrait 'covers' => \is_array($sutFqcn) ? $sutFqcn : array($sutFqcn), ), )); - $r->setValue($testClass, $cache); + $r->setValue(Test::class, $cache); } private function findSutFqcn($test) diff --git a/src/Symfony/Bridge/PhpUnit/Legacy/PolyfillTestCaseTrait.php b/src/Symfony/Bridge/PhpUnit/Legacy/PolyfillTestCaseTrait.php index 69609c5ea4..5331b3af55 100644 --- a/src/Symfony/Bridge/PhpUnit/Legacy/PolyfillTestCaseTrait.php +++ b/src/Symfony/Bridge/PhpUnit/Legacy/PolyfillTestCaseTrait.php @@ -66,7 +66,7 @@ trait PolyfillTestCaseTrait */ public function expectException($exception) { - $property = new \ReflectionProperty(class_exists('PHPUnit_Framework_TestCase') ? 'PHPUnit_Framework_TestCase' : TestCase::class, 'expectedException'); + $property = new \ReflectionProperty(TestCase::class, 'expectedException'); $property->setAccessible(true); $property->setValue($this, $exception); } @@ -78,7 +78,7 @@ trait PolyfillTestCaseTrait */ public function expectExceptionCode($code) { - $property = new \ReflectionProperty(class_exists('PHPUnit_Framework_TestCase') ? 'PHPUnit_Framework_TestCase' : TestCase::class, 'expectedExceptionCode'); + $property = new \ReflectionProperty(TestCase::class, 'expectedExceptionCode'); $property->setAccessible(true); $property->setValue($this, $code); } @@ -90,7 +90,7 @@ trait PolyfillTestCaseTrait */ public function expectExceptionMessage($message) { - $property = new \ReflectionProperty(class_exists('PHPUnit_Framework_TestCase') ? 'PHPUnit_Framework_TestCase' : TestCase::class, 'expectedExceptionMessage'); + $property = new \ReflectionProperty(TestCase::class, 'expectedExceptionMessage'); $property->setAccessible(true); $property->setValue($this, $message); } @@ -102,7 +102,7 @@ trait PolyfillTestCaseTrait */ public function expectExceptionMessageRegExp($messageRegExp) { - $property = new \ReflectionProperty(class_exists('PHPUnit_Framework_TestCase') ? 'PHPUnit_Framework_TestCase' : TestCase::class, 'expectedExceptionMessageRegExp'); + $property = new \ReflectionProperty(TestCase::class, 'expectedExceptionMessageRegExp'); $property->setAccessible(true); $property->setValue($this, $messageRegExp); } diff --git a/src/Symfony/Bridge/PhpUnit/Legacy/SymfonyTestsListenerTrait.php b/src/Symfony/Bridge/PhpUnit/Legacy/SymfonyTestsListenerTrait.php index 803f7114b8..0ac3ee4a1b 100644 --- a/src/Symfony/Bridge/PhpUnit/Legacy/SymfonyTestsListenerTrait.php +++ b/src/Symfony/Bridge/PhpUnit/Legacy/SymfonyTestsListenerTrait.php @@ -15,7 +15,9 @@ use Doctrine\Common\Annotations\AnnotationRegistry; use PHPUnit\Framework\AssertionFailedError; use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestSuite; +use PHPUnit\Runner\BaseTestRunner; use PHPUnit\Util\Blacklist; +use PHPUnit\Util\Test; use Symfony\Bridge\PhpUnit\ClockMock; use Symfony\Bridge\PhpUnit\DnsMock; use Symfony\Component\Debug\DebugClassLoader as LegacyDebugClassLoader; @@ -48,11 +50,7 @@ class SymfonyTestsListenerTrait */ public function __construct(array $mockedNamespaces = array()) { - if (class_exists('PHPUnit_Util_Blacklist')) { - \PHPUnit_Util_Blacklist::$blacklistedClassNames['\Symfony\Bridge\PhpUnit\Legacy\SymfonyTestsListenerTrait'] = 2; - } else { - Blacklist::$blacklistedClassNames['\Symfony\Bridge\PhpUnit\Legacy\SymfonyTestsListenerTrait'] = 2; - } + Blacklist::$blacklistedClassNames['\Symfony\Bridge\PhpUnit\Legacy\SymfonyTestsListenerTrait'] = 2; $enableDebugClassLoader = class_exists(DebugClassLoader::class) || class_exists(LegacyDebugClassLoader::class); @@ -113,11 +111,6 @@ class SymfonyTestsListenerTrait public function startTestSuite($suite) { - if (class_exists('PHPUnit_Util_Blacklist', false)) { - $Test = 'PHPUnit_Util_Test'; - } else { - $Test = 'PHPUnit\Util\Test'; - } $suiteName = $suite->getName(); $this->testsWithWarnings = array(); @@ -125,7 +118,7 @@ class SymfonyTestsListenerTrait if (!($test instanceof \PHPUnit\Framework\TestCase || $test instanceof TestCase)) { continue; } - if (null === $Test::getPreserveGlobalStateSettings(\get_class($test), $test->getName(false))) { + if (null === Test::getPreserveGlobalStateSettings(\get_class($test), $test->getName(false))) { $test->setPreserveGlobalState(false); } } @@ -157,12 +150,12 @@ class SymfonyTestsListenerTrait $testSuites = array($suite); for ($i = 0; isset($testSuites[$i]); ++$i) { foreach ($testSuites[$i]->tests() as $test) { - if ($test instanceof \PHPUnit_Framework_TestSuite || $test instanceof TestSuite) { + if ($test instanceof TestSuite) { if (!class_exists($test->getName(), false)) { $testSuites[] = $test; continue; } - $groups = $Test::getGroups($test->getName()); + $groups = Test::getGroups($test->getName()); if (\in_array('time-sensitive', $groups, true)) { ClockMock::register($test->getName()); } @@ -213,14 +206,7 @@ class SymfonyTestsListenerTrait putenv('SYMFONY_DEPRECATIONS_SERIALIZE='.$this->runsInSeparateProcess); } - if (class_exists('PHPUnit_Util_Blacklist', false)) { - $Test = 'PHPUnit_Util_Test'; - $AssertionFailedError = 'PHPUnit_Framework_AssertionFailedError'; - } else { - $Test = 'PHPUnit\Util\Test'; - $AssertionFailedError = 'PHPUnit\Framework\AssertionFailedError'; - } - $groups = $Test::getGroups(\get_class($test), $test->getName(false)); + $groups = Test::getGroups(\get_class($test), $test->getName(false)); if (!$this->runsInSeparateProcess) { if (\in_array('time-sensitive', $groups, true)) { @@ -232,14 +218,14 @@ class SymfonyTestsListenerTrait } } - $annotations = $Test::parseTestMethodAnnotations(\get_class($test), $test->getName(false)); + $annotations = Test::parseTestMethodAnnotations(\get_class($test), $test->getName(false)); if (isset($annotations['class']['expectedDeprecation'])) { - $test->getTestResultObject()->addError($test, new $AssertionFailedError('`@expectedDeprecation` annotations are not allowed at the class level.'), 0); + $test->getTestResultObject()->addError($test, new AssertionFailedError('`@expectedDeprecation` annotations are not allowed at the class level.'), 0); } if (isset($annotations['method']['expectedDeprecation'])) { if (!\in_array('legacy', $groups, true)) { - $this->error = new $AssertionFailedError('Only tests with the `@group legacy` annotation can have `@expectedDeprecation`.'); + $this->error = new AssertionFailedError('Only tests with the `@group legacy` annotation can have `@expectedDeprecation`.'); } $test->getTestResultObject()->beStrictAboutTestsThatDoNotTestAnything(false); @@ -259,18 +245,8 @@ class SymfonyTestsListenerTrait public function endTest($test, $time) { - if (class_exists('PHPUnit_Util_Blacklist', false)) { - $Test = 'PHPUnit_Util_Test'; - $BaseTestRunner = 'PHPUnit_Runner_BaseTestRunner'; - $Warning = 'PHPUnit_Framework_Warning'; - } else { - $Test = 'PHPUnit\Util\Test'; - $BaseTestRunner = 'PHPUnit\Runner\BaseTestRunner'; - $Warning = 'PHPUnit\Framework\Warning'; - } $className = \get_class($test); - $classGroups = $Test::getGroups($className); - $groups = $Test::getGroups($className, $test->getName(false)); + $groups = Test::getGroups($className, $test->getName(false)); if (null !== $this->reportUselessTests) { $test->getTestResultObject()->beStrictAboutTestsThatDoNotTestAnything($this->reportUselessTests); @@ -299,20 +275,18 @@ class SymfonyTestsListenerTrait } if ($this->expectedDeprecations) { - if (!\in_array($test->getStatus(), array($BaseTestRunner::STATUS_SKIPPED, $BaseTestRunner::STATUS_INCOMPLETE), true)) { + if (!\in_array($test->getStatus(), array(BaseTestRunner::STATUS_SKIPPED, BaseTestRunner::STATUS_INCOMPLETE), true)) { $test->addToAssertionCount(\count($this->expectedDeprecations)); } restore_error_handler(); - if (!$errored && !\in_array($test->getStatus(), array($BaseTestRunner::STATUS_SKIPPED, $BaseTestRunner::STATUS_INCOMPLETE, $BaseTestRunner::STATUS_FAILURE, $BaseTestRunner::STATUS_ERROR), true)) { + if (!$errored && !\in_array($test->getStatus(), array(BaseTestRunner::STATUS_SKIPPED, BaseTestRunner::STATUS_INCOMPLETE, BaseTestRunner::STATUS_FAILURE, BaseTestRunner::STATUS_ERROR), true)) { try { $prefix = "@expectedDeprecation:\n"; $test->assertStringMatchesFormat($prefix.'%A '.implode("\n%A ", $this->expectedDeprecations)."\n%A", $prefix.' '.implode("\n ", $this->gatheredDeprecations)."\n"); } catch (AssertionFailedError $e) { $test->getTestResultObject()->addFailure($test, $e, $time); - } catch (\PHPUnit_Framework_AssertionFailedError $e) { - $test->getTestResultObject()->addFailure($test, $e, $time); } } diff --git a/src/Symfony/Bridge/PhpUnit/SymfonyTestsListener.php b/src/Symfony/Bridge/PhpUnit/SymfonyTestsListener.php index a753525b76..d3cd7563bd 100644 --- a/src/Symfony/Bridge/PhpUnit/SymfonyTestsListener.php +++ b/src/Symfony/Bridge/PhpUnit/SymfonyTestsListener.php @@ -11,7 +11,7 @@ namespace Symfony\Bridge\PhpUnit; -if (class_exists('PHPUnit_Runner_Version') && version_compare(\PHPUnit_Runner_Version::id(), '6.0.0', '<')) { +if (version_compare(\PHPUnit\Runner\Version::id(), '6.0.0', '<')) { class_alias('Symfony\Bridge\PhpUnit\Legacy\SymfonyTestsListenerForV5', 'Symfony\Bridge\PhpUnit\SymfonyTestsListener'); } elseif (version_compare(\PHPUnit\Runner\Version::id(), '7.0.0', '<')) { class_alias('Symfony\Bridge\PhpUnit\Legacy\SymfonyTestsListenerForV6', 'Symfony\Bridge\PhpUnit\SymfonyTestsListener'); diff --git a/src/Symfony/Bridge/PhpUnit/Tests/Fixtures/coverage/tests/bootstrap.php b/src/Symfony/Bridge/PhpUnit/Tests/Fixtures/coverage/tests/bootstrap.php index 241006431a..3e45381dce 100644 --- a/src/Symfony/Bridge/PhpUnit/Tests/Fixtures/coverage/tests/bootstrap.php +++ b/src/Symfony/Bridge/PhpUnit/Tests/Fixtures/coverage/tests/bootstrap.php @@ -14,7 +14,7 @@ require __DIR__.'/../src/FooCov.php'; require __DIR__.'/../../../../Legacy/CoverageListenerTrait.php'; -if (class_exists('PHPUnit_Runner_Version') && version_compare(\PHPUnit_Runner_Version::id(), '6.0.0', '<')) { +if (version_compare(\PHPUnit\Runner\Version::id(), '6.0.0', '<')) { require_once __DIR__.'/../../../../Legacy/CoverageListenerForV5.php'; } elseif (version_compare(\PHPUnit\Runner\Version::id(), '7.0.0', '<')) { require_once __DIR__.'/../../../../Legacy/CoverageListenerForV6.php'; diff --git a/src/Symfony/Bridge/PhpUnit/Tests/ProcessIsolationTest.php b/src/Symfony/Bridge/PhpUnit/Tests/ProcessIsolationTest.php index b8125dc558..b4789ad1f3 100644 --- a/src/Symfony/Bridge/PhpUnit/Tests/ProcessIsolationTest.php +++ b/src/Symfony/Bridge/PhpUnit/Tests/ProcessIsolationTest.php @@ -24,8 +24,7 @@ class ProcessIsolationTest extends TestCase public function testCallingOtherErrorHandler() { - $class = class_exists('PHPUnit\Framework\Exception') ? 'PHPUnit\Framework\Exception' : 'PHPUnit_Framework_Exception'; - $this->expectException($class); + $this->expectException(\class_exists('PHPUnit_Framework_Exception') ? 'PHPUnit_Framework_Exception' : 'PHPUnit\Framework\Exception'); $this->expectExceptionMessage('Test that PHPUnit\'s error handler fires.'); trigger_error('Test that PHPUnit\'s error handler fires.', E_USER_WARNING); diff --git a/src/Symfony/Bridge/PhpUnit/TextUI/Command.php b/src/Symfony/Bridge/PhpUnit/TextUI/Command.php index 4a26fc7fad..be73e4d2be 100644 --- a/src/Symfony/Bridge/PhpUnit/TextUI/Command.php +++ b/src/Symfony/Bridge/PhpUnit/TextUI/Command.php @@ -11,7 +11,7 @@ namespace Symfony\Bridge\PhpUnit\TextUI; -if (class_exists('PHPUnit_Runner_Version') && version_compare(\PHPUnit_Runner_Version::id(), '6.0.0', '<')) { +if (version_compare(\PHPUnit\Runner\Version::id(), '6.0.0', '<')) { class_alias('Symfony\Bridge\PhpUnit\Legacy\CommandForV5', 'Symfony\Bridge\PhpUnit\TextUI\Command'); } else { class_alias('Symfony\Bridge\PhpUnit\Legacy\CommandForV6', 'Symfony\Bridge\PhpUnit\TextUI\Command'); diff --git a/src/Symfony/Bridge/PhpUnit/bootstrap.php b/src/Symfony/Bridge/PhpUnit/bootstrap.php index 5de9467891..26bde7335d 100644 --- a/src/Symfony/Bridge/PhpUnit/bootstrap.php +++ b/src/Symfony/Bridge/PhpUnit/bootstrap.php @@ -12,6 +12,95 @@ use Doctrine\Common\Annotations\AnnotationRegistry; use Symfony\Bridge\PhpUnit\DeprecationErrorHandler; +if (class_exists('PHPUnit_Runner_Version') && version_compare(\PHPUnit_Runner_Version::id(), '6.0.0', '<')) { + $classes = [ + 'PHPUnit_Framework_Assert', // override PhpUnit's ForwardCompat child class + 'PHPUnit_Framework_AssertionFailedError', // override PhpUnit's ForwardCompat child class + 'PHPUnit_Framework_BaseTestListener', // override PhpUnit's ForwardCompat child class + + 'PHPUnit_Framework_Constraint', + 'PHPUnit_Framework_Constraint_And', + 'PHPUnit_Framework_Constraint_ArrayHasKey', + 'PHPUnit_Framework_Constraint_ArraySubset', + 'PHPUnit_Framework_Constraint_Attribute', + 'PHPUnit_Framework_Constraint_Callback', + 'PHPUnit_Framework_Constraint_ClassHasAttribute', + 'PHPUnit_Framework_Constraint_ClassHasStaticAttribute', + 'PHPUnit_Framework_Constraint_Composite', + 'PHPUnit_Framework_Constraint_Count', + 'PHPUnit_Framework_Constraint_Exception', + 'PHPUnit_Framework_Constraint_ExceptionCode', + 'PHPUnit_Framework_Constraint_ExceptionMessage', + 'PHPUnit_Framework_Constraint_ExceptionMessageRegExp', + 'PHPUnit_Framework_Constraint_FileExists', + 'PHPUnit_Framework_Constraint_GreaterThan', + 'PHPUnit_Framework_Constraint_IsAnything', + 'PHPUnit_Framework_Constraint_IsEmpty', + 'PHPUnit_Framework_Constraint_IsEqual', + 'PHPUnit_Framework_Constraint_IsFalse', + 'PHPUnit_Framework_Constraint_IsIdentical', + 'PHPUnit_Framework_Constraint_IsInstanceOf', + 'PHPUnit_Framework_Constraint_IsJson', + 'PHPUnit_Framework_Constraint_IsNull', + 'PHPUnit_Framework_Constraint_IsTrue', + 'PHPUnit_Framework_Constraint_IsType', + 'PHPUnit_Framework_Constraint_JsonMatches', + 'PHPUnit_Framework_Constraint_JsonMatches_ErrorMessageProvider', + 'PHPUnit_Framework_Constraint_LessThan', + 'PHPUnit_Framework_Constraint_Not', + 'PHPUnit_Framework_Constraint_ObjectHasAttribute', + 'PHPUnit_Framework_Constraint_Or', + 'PHPUnit_Framework_Constraint_PCREMatch', + 'PHPUnit_Framework_Constraint_SameSize', + 'PHPUnit_Framework_Constraint_StringContains', + 'PHPUnit_Framework_Constraint_StringEndsWith', + 'PHPUnit_Framework_Constraint_StringMatches', + 'PHPUnit_Framework_Constraint_StringStartsWith', + 'PHPUnit_Framework_Constraint_TraversableContains', + 'PHPUnit_Framework_Constraint_TraversableContainsOnly', + 'PHPUnit_Framework_Constraint_Xor', + + 'PHPUnit_Framework_Error', + 'PHPUnit_Framework_Error_Deprecated', + 'PHPUnit_Framework_Error_Notice', + 'PHPUnit_Framework_Error_Warning', + 'PHPUnit_Framework_Exception', + 'PHPUnit_Framework_ExpectationFailedException', + + 'PHPUnit_Framework_MockObject_MockObject', + + 'PHPUnit_Framework_IncompleteTest', + 'PHPUnit_Framework_IncompleteTestCase', + 'PHPUnit_Framework_IncompleteTestError', + 'PHPUnit_Framework_RiskyTest', + 'PHPUnit_Framework_RiskyTestError', + 'PHPUnit_Framework_SkippedTest', + 'PHPUnit_Framework_SkippedTestCase', + 'PHPUnit_Framework_SkippedTestError', + 'PHPUnit_Framework_SkippedTestSuiteError', + + 'PHPUnit_Framework_SyntheticError', + + 'PHPUnit_Framework_Test', + 'PHPUnit_Framework_TestCase', // override PhpUnit's ForwardCompat child class + 'PHPUnit_Framework_TestFailure', + 'PHPUnit_Framework_TestListener', + 'PHPUnit_Framework_TestResult', + 'PHPUnit_Framework_TestSuite', // override PhpUnit's ForwardCompat child class + + 'PHPUnit_Runner_BaseTestRunner', + 'PHPUnit_Runner_Version', + + 'PHPUnit_Util_Blacklist', + 'PHPUnit_Util_ErrorHandler', + 'PHPUnit_Util_Test', + 'PHPUnit_Util_XML', + ]; + foreach ($classes as $class) { + class_alias($class, '\\'.strtr($class, '_', '\\'), true); + } +} + // Detect if we need to serialize deprecations to a file. if ($file = getenv('SYMFONY_DEPRECATIONS_SERIALIZE')) { DeprecationErrorHandler::collectDeprecations($file); From 797ea2e4e21af932671da04f1fad7268bede3296 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Deruss=C3=A9?= Date: Mon, 5 Aug 2019 10:06:54 +0200 Subject: [PATCH 12/15] Use namespaced Phpunit classes --- .travis.yml | 1 + .../ResolveInstanceofConditionalsPassTest.php | 4 +-- ...ContainerParametersResourceCheckerTest.php | 7 +++--- .../Tests/Resources/TranslationFilesTest.php | 6 +---- ...mptyControllerArgumentLocatorsPassTest.php | 2 +- .../AbstractNumberFormatterTest.php | 25 +++---------------- .../Tests/Resources/TranslationFilesTest.php | 6 +---- .../Tests/Resources/TranslationFilesTest.php | 6 +---- .../Component/Yaml/Tests/ParserTest.php | 4 --- 9 files changed, 15 insertions(+), 46 deletions(-) diff --git a/.travis.yml b/.travis.yml index 1e9ea20b62..fc3ff15d0f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -209,6 +209,7 @@ install: git checkout -q FETCH_HEAD -- src/Symfony/Bridge/PhpUnit SYMFONY_VERSION=$(cat src/Symfony/Bridge/PhpUnit/composer.json | grep '^ *"dev-master". *"[1-9]' | grep -o '[0-9.]*') sed -i 's/"symfony\/phpunit-bridge": ".*"/"symfony\/phpunit-bridge": "'$SYMFONY_VERSION'.x@dev"/' composer.json + rm -rf .phpunit fi - | diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/ResolveInstanceofConditionalsPassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/ResolveInstanceofConditionalsPassTest.php index 1996216aa6..83be84bd0c 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/ResolveInstanceofConditionalsPassTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/ResolveInstanceofConditionalsPassTest.php @@ -201,7 +201,7 @@ class ResolveInstanceofConditionalsPassTest extends TestCase public function testProcessThrowsExceptionForAutoconfiguredCalls() { $this->expectException('Symfony\Component\DependencyInjection\Exception\InvalidArgumentException'); - $this->expectExceptionMessage('Autoconfigured instanceof for type "PHPUnit\Framework\TestCase" defines method calls but these are not supported and should be removed.'); + $this->expectExceptionMessageRegExp('/Autoconfigured instanceof for type "PHPUnit[\\\\_]Framework[\\\\_]TestCase" defines method calls but these are not supported and should be removed\./'); $container = new ContainerBuilder(); $container->registerForAutoconfiguration(parent::class) ->addMethodCall('setFoo'); @@ -212,7 +212,7 @@ class ResolveInstanceofConditionalsPassTest extends TestCase public function testProcessThrowsExceptionForArguments() { $this->expectException('Symfony\Component\DependencyInjection\Exception\InvalidArgumentException'); - $this->expectExceptionMessage('Autoconfigured instanceof for type "PHPUnit\Framework\TestCase" defines arguments but these are not supported and should be removed.'); + $this->expectExceptionMessageRegExp('/Autoconfigured instanceof for type "PHPUnit[\\\\_]Framework[\\\\_]TestCase" defines arguments but these are not supported and should be removed\./'); $container = new ContainerBuilder(); $container->registerForAutoconfiguration(parent::class) ->addArgument('bar'); diff --git a/src/Symfony/Component/DependencyInjection/Tests/Config/ContainerParametersResourceCheckerTest.php b/src/Symfony/Component/DependencyInjection/Tests/Config/ContainerParametersResourceCheckerTest.php index eb5fc5a99d..51af451c16 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Config/ContainerParametersResourceCheckerTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Config/ContainerParametersResourceCheckerTest.php @@ -11,6 +11,7 @@ namespace Symfony\Component\DependencyInjection\Tests\Config; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Symfony\Component\Config\ResourceCheckerInterface; use Symfony\Component\DependencyInjection\Config\ContainerParametersResource; @@ -52,15 +53,15 @@ class ContainerParametersResourceCheckerTest extends TestCase public function isFreshProvider() { - yield 'not fresh on missing parameter' => [function (\PHPUnit_Framework_MockObject_MockObject $container) { + yield 'not fresh on missing parameter' => [function (MockObject $container) { $container->method('hasParameter')->with('locales')->willReturn(false); }, false]; - yield 'not fresh on different value' => [function (\PHPUnit_Framework_MockObject_MockObject $container) { + yield 'not fresh on different value' => [function (MockObject $container) { $container->method('getParameter')->with('locales')->willReturn(['nl', 'es']); }, false]; - yield 'fresh on every identical parameters' => [function (\PHPUnit_Framework_MockObject_MockObject $container) { + yield 'fresh on every identical parameters' => [function (MockObject $container) { $container->expects($this->exactly(2))->method('hasParameter')->willReturn(true); $container->expects($this->exactly(2))->method('getParameter') ->withConsecutive( diff --git a/src/Symfony/Component/Form/Tests/Resources/TranslationFilesTest.php b/src/Symfony/Component/Form/Tests/Resources/TranslationFilesTest.php index d0bc82e759..49e69ef190 100644 --- a/src/Symfony/Component/Form/Tests/Resources/TranslationFilesTest.php +++ b/src/Symfony/Component/Form/Tests/Resources/TranslationFilesTest.php @@ -20,11 +20,7 @@ class TranslationFilesTest extends TestCase */ public function testTranslationFileIsValid($filePath) { - if (class_exists('PHPUnit_Util_XML')) { - \PHPUnit_Util_XML::loadfile($filePath, false, false, true); - } else { - \PHPUnit\Util\XML::loadfile($filePath, false, false, true); - } + \PHPUnit\Util\XML::loadfile($filePath, false, false, true); $this->addToAssertionCount(1); } diff --git a/src/Symfony/Component/HttpKernel/Tests/DependencyInjection/RemoveEmptyControllerArgumentLocatorsPassTest.php b/src/Symfony/Component/HttpKernel/Tests/DependencyInjection/RemoveEmptyControllerArgumentLocatorsPassTest.php index 713ab5441a..84d7351560 100644 --- a/src/Symfony/Component/HttpKernel/Tests/DependencyInjection/RemoveEmptyControllerArgumentLocatorsPassTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/DependencyInjection/RemoveEmptyControllerArgumentLocatorsPassTest.php @@ -26,7 +26,7 @@ class RemoveEmptyControllerArgumentLocatorsPassTest extends TestCase $resolver = $container->register('argument_resolver.service')->addArgument([]); $container->register('stdClass', 'stdClass'); - $container->register(parent::class, 'stdClass'); + $container->register(TestCase::class, 'stdClass'); $container->register('c1', RemoveTestController1::class)->addTag('controller.service_arguments'); $container->register('c2', RemoveTestController2::class)->addTag('controller.service_arguments') ->addMethodCall('setTestCase', [new Reference('c1')]); diff --git a/src/Symfony/Component/Intl/Tests/NumberFormatter/AbstractNumberFormatterTest.php b/src/Symfony/Component/Intl/Tests/NumberFormatter/AbstractNumberFormatterTest.php index 0d382341f5..464a0aac0c 100644 --- a/src/Symfony/Component/Intl/Tests/NumberFormatter/AbstractNumberFormatterTest.php +++ b/src/Symfony/Component/Intl/Tests/NumberFormatter/AbstractNumberFormatterTest.php @@ -11,6 +11,7 @@ namespace Symfony\Component\Intl\Tests\NumberFormatter; +use PHPUnit\Framework\Error\Warning; use PHPUnit\Framework\TestCase; use Symfony\Component\Intl\Globals\IntlGlobals; use Symfony\Component\Intl\NumberFormatter\NumberFormatter; @@ -323,13 +324,7 @@ abstract class AbstractNumberFormatterTest extends TestCase */ public function testFormatTypeCurrency($formatter, $value) { - $exceptionCode = 'PHPUnit\Framework\Error\Warning'; - - if (class_exists('PHPUnit_Framework_Error_Warning')) { - $exceptionCode = 'PHPUnit_Framework_Error_Warning'; - } - - $this->expectException($exceptionCode); + $this->expectException(Warning::class); $formatter->format($value, NumberFormatter::TYPE_CURRENCY); } @@ -706,13 +701,7 @@ abstract class AbstractNumberFormatterTest extends TestCase public function testParseTypeDefault() { - $exceptionCode = 'PHPUnit\Framework\Error\Warning'; - - if (class_exists('PHPUnit_Framework_Error_Warning')) { - $exceptionCode = 'PHPUnit_Framework_Error_Warning'; - } - - $this->expectException($exceptionCode); + $this->expectException(Warning::class); $formatter = $this->getNumberFormatter('en', NumberFormatter::DECIMAL); $formatter->parse('1', NumberFormatter::TYPE_DEFAULT); @@ -832,13 +821,7 @@ abstract class AbstractNumberFormatterTest extends TestCase public function testParseTypeCurrency() { - $exceptionCode = 'PHPUnit\Framework\Error\Warning'; - - if (class_exists('PHPUnit_Framework_Error_Warning')) { - $exceptionCode = 'PHPUnit_Framework_Error_Warning'; - } - - $this->expectException($exceptionCode); + $this->expectException(Warning::class); $formatter = $this->getNumberFormatter('en', NumberFormatter::DECIMAL); $formatter->parse('1', NumberFormatter::TYPE_CURRENCY); diff --git a/src/Symfony/Component/Security/Core/Tests/Resources/TranslationFilesTest.php b/src/Symfony/Component/Security/Core/Tests/Resources/TranslationFilesTest.php index f4e0d9e6e8..bc21d272fc 100644 --- a/src/Symfony/Component/Security/Core/Tests/Resources/TranslationFilesTest.php +++ b/src/Symfony/Component/Security/Core/Tests/Resources/TranslationFilesTest.php @@ -20,11 +20,7 @@ class TranslationFilesTest extends TestCase */ public function testTranslationFileIsValid($filePath) { - if (class_exists('PHPUnit_Util_XML')) { - \PHPUnit_Util_XML::loadfile($filePath, false, false, true); - } else { - \PHPUnit\Util\XML::loadfile($filePath, false, false, true); - } + \PHPUnit\Util\XML::loadfile($filePath, false, false, true); $this->addToAssertionCount(1); } diff --git a/src/Symfony/Component/Validator/Tests/Resources/TranslationFilesTest.php b/src/Symfony/Component/Validator/Tests/Resources/TranslationFilesTest.php index 64b3f78934..56ff24d2fd 100644 --- a/src/Symfony/Component/Validator/Tests/Resources/TranslationFilesTest.php +++ b/src/Symfony/Component/Validator/Tests/Resources/TranslationFilesTest.php @@ -20,11 +20,7 @@ class TranslationFilesTest extends TestCase */ public function testTranslationFileIsValid($filePath) { - if (class_exists('PHPUnit_Util_XML')) { - \PHPUnit_Util_XML::loadfile($filePath, false, false, true); - } else { - \PHPUnit\Util\XML::loadfile($filePath, false, false, true); - } + \PHPUnit\Util\XML::loadfile($filePath, false, false, true); $this->addToAssertionCount(1); } diff --git a/src/Symfony/Component/Yaml/Tests/ParserTest.php b/src/Symfony/Component/Yaml/Tests/ParserTest.php index 8cc95d7bfe..a806723025 100644 --- a/src/Symfony/Component/Yaml/Tests/ParserTest.php +++ b/src/Symfony/Component/Yaml/Tests/ParserTest.php @@ -45,10 +45,6 @@ class ParserTest extends TestCase if (E_USER_DEPRECATED !== $type) { restore_error_handler(); - if (class_exists('PHPUnit_Util_ErrorHandler')) { - return \call_user_func_array('PHPUnit_Util_ErrorHandler::handleError', \func_get_args()); - } - return \call_user_func_array('PHPUnit\Util\ErrorHandler::handleError', \func_get_args()); } From 356341bc1965425f354be85296712b38488277b9 Mon Sep 17 00:00:00 2001 From: Thomas Calvet Date: Mon, 5 Aug 2019 14:30:21 +0200 Subject: [PATCH 13/15] [HttpClient] Minor fixes --- .../FrameworkBundle/DependencyInjection/Configuration.php | 2 +- src/Symfony/Component/HttpClient/Response/MockResponse.php | 4 ++-- src/Symfony/Contracts/HttpClient/Test/HttpClientTestCase.php | 3 +-- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php index b4ce6a2c6a..ba2dbb1a32 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php @@ -1481,7 +1481,7 @@ class Configuration implements ConfigurationInterface ->info('A comma separated list of hosts that do not require a proxy to be reached.') ->end() ->floatNode('timeout') - ->info('Defaults to "default_socket_timeout" ini parameter.') + ->info('The idle timeout, defaults to the "default_socket_timeout" ini parameter.') ->end() ->scalarNode('bindto') ->info('A network interface name, IP address, a host name or a UNIX socket to bind to.') diff --git a/src/Symfony/Component/HttpClient/Response/MockResponse.php b/src/Symfony/Component/HttpClient/Response/MockResponse.php index 90bb0df339..fe94bc3436 100644 --- a/src/Symfony/Component/HttpClient/Response/MockResponse.php +++ b/src/Symfony/Component/HttpClient/Response/MockResponse.php @@ -37,7 +37,7 @@ class MockResponse implements ResponseInterface /** * @param string|string[]|iterable $body The response body as a string or an iterable of strings, - * yielding an empty string simulates a timeout, + * yielding an empty string simulates an idle timeout, * exceptions are turned to TransportException * * @see ResponseInterface::getInfo() for possible info, e.g. "response_headers" @@ -277,7 +277,7 @@ class MockResponse implements ResponseInterface if (!\is_string($body)) { foreach ($body as $chunk) { if ('' === $chunk = (string) $chunk) { - // simulate a timeout + // simulate an idle timeout $response->body[] = new ErrorChunk($offset); } else { $response->body[] = $chunk; diff --git a/src/Symfony/Contracts/HttpClient/Test/HttpClientTestCase.php b/src/Symfony/Contracts/HttpClient/Test/HttpClientTestCase.php index 075f73a2c1..7d31a22217 100644 --- a/src/Symfony/Contracts/HttpClient/Test/HttpClientTestCase.php +++ b/src/Symfony/Contracts/HttpClient/Test/HttpClientTestCase.php @@ -580,7 +580,7 @@ abstract class HttpClientTestCase extends TestCase $response = null; $this->expectException(TransportExceptionInterface::class); - $client->request('GET', 'http://symfony.com:8057/', ['timeout' => 3]); + $client->request('GET', 'http://symfony.com:8057/', ['timeout' => 1]); } public function testTimeoutOnAccess() @@ -643,7 +643,6 @@ abstract class HttpClientTestCase extends TestCase { $client = $this->getHttpClient(__FUNCTION__); - $downloaded = 0; $start = microtime(true); $client->request('GET', 'http://localhost:8057/timeout-long'); $client = null; From 77951de0e39142bd732c993826e698b14ded6ec4 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Mon, 5 Aug 2019 15:28:06 +0200 Subject: [PATCH 14/15] [Mailer] fixed dispatcher not available in Mailer --- .../Resources/config/mailer.xml | 1 + src/Symfony/Component/Mailer/Mailer.php | 26 +++++++++++-------- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/mailer.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/mailer.xml index becf0d1b71..fa10ebaae3 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/mailer.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/mailer.xml @@ -8,6 +8,7 @@ + diff --git a/src/Symfony/Component/Mailer/Mailer.php b/src/Symfony/Component/Mailer/Mailer.php index db87602022..8ac505b03d 100644 --- a/src/Symfony/Component/Mailer/Mailer.php +++ b/src/Symfony/Component/Mailer/Mailer.php @@ -17,6 +17,7 @@ use Symfony\Component\Mailer\Messenger\SendEmailMessage; use Symfony\Component\Mailer\Transport\TransportInterface; use Symfony\Component\Messenger\MessageBusInterface; use Symfony\Component\Mime\RawMessage; +use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; /** * @author Fabien Potencier @@ -25,8 +26,9 @@ class Mailer implements MailerInterface { private $transport; private $bus; + private $dispatcher; - public function __construct(TransportInterface $transport, MessageBusInterface $bus = null) + public function __construct(TransportInterface $transport, MessageBusInterface $bus = null, EventDispatcherInterface $dispatcher = null) { $this->transport = $transport; $this->bus = $bus; @@ -40,18 +42,20 @@ class Mailer implements MailerInterface return; } - $message = clone $message; - if (null !== $envelope) { - $envelope = clone $envelope; - } else { - try { - $envelope = new DelayedSmtpEnvelope($message); - } catch (\Exception $e) { - throw new TransportException('Cannot send message without a valid envelope.', 0, $e); + if (null !== $this->dispatcher) { + $message = clone $message; + if (null !== $envelope) { + $envelope = clone $envelope; + } else { + try { + $envelope = new DelayedSmtpEnvelope($message); + } catch (\Exception $e) { + throw new TransportException('Cannot send message without a valid envelope.', 0, $e); + } } + $event = new MessageEvent($message, $envelope, $this->transport->getName()); + $this->dispatcher->dispatch($event); } - $event = new MessageEvent($message, $envelope, $this->transport->getName()); - $this->dispatcher->dispatch($event); $this->bus->dispatch(new SendEmailMessage($message, $envelope)); } From b1312781e2c4cc8a81c19f23a795081ca15fddbf Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Mon, 5 Aug 2019 15:40:23 +0200 Subject: [PATCH 15/15] Minor fixes --- src/Symfony/Component/Finder/Tests/FinderTest.php | 6 +----- src/Symfony/Component/VarDumper/Cloner/AbstractCloner.php | 2 ++ 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/Symfony/Component/Finder/Tests/FinderTest.php b/src/Symfony/Component/Finder/Tests/FinderTest.php index 6e58056068..442186d2be 100644 --- a/src/Symfony/Component/Finder/Tests/FinderTest.php +++ b/src/Symfony/Component/Finder/Tests/FinderTest.php @@ -703,11 +703,7 @@ class FinderTest extends Iterator\RealIteratorTestCase } catch (\Exception $e) { $expectedExceptionClass = 'Symfony\\Component\\Finder\\Exception\\AccessDeniedException'; if ($e instanceof \PHPUnit\Framework\ExpectationFailedException) { - $this->fail(sprintf("Expected exception:\n%s\nGot:\n%s\nWith comparison failure:\n%s", $expectedExceptionClass, 'PHPUnit_Framework_ExpectationFailedException', $e->getComparisonFailure()->getExpectedAsString())); - } - - if ($e instanceof \PHPUnit\Framework\ExpectationFailedException) { - $this->fail(sprintf("Expected exception:\n%s\nGot:\n%s\nWith comparison failure:\n%s", $expectedExceptionClass, '\PHPUnit\Framework\ExpectationFailedException', $e->getComparisonFailure()->getExpectedAsString())); + $this->fail(sprintf("Expected exception:\n%s\nGot:\n%s\nWith comparison failure:\n%s", $expectedExceptionClass, 'PHPUnit\Framework\ExpectationFailedException', $e->getComparisonFailure()->getExpectedAsString())); } $this->assertInstanceOf($expectedExceptionClass, $e); diff --git a/src/Symfony/Component/VarDumper/Cloner/AbstractCloner.php b/src/Symfony/Component/VarDumper/Cloner/AbstractCloner.php index de09f1803d..10d78b244a 100644 --- a/src/Symfony/Component/VarDumper/Cloner/AbstractCloner.php +++ b/src/Symfony/Component/VarDumper/Cloner/AbstractCloner.php @@ -82,6 +82,8 @@ abstract class AbstractCloner implements ClonerInterface 'Symfony\Component\Debug\Exception\SilencedErrorContext' => ['Symfony\Component\VarDumper\Caster\ExceptionCaster', 'castSilencedErrorContext'], 'PHPUnit_Framework_MockObject_MockObject' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'cutInternals'], + 'PHPUnit\Framework\MockObject\MockObject' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'cutInternals'], + 'PHPUnit\Framework\MockObject\Stub' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'cutInternals'], 'Prophecy\Prophecy\ProphecySubjectInterface' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'cutInternals'], 'Mockery\MockInterface' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'cutInternals'],