diff --git a/framework/CHANGELOG.md b/framework/CHANGELOG.md index 66240661bb..c199c76185 100644 --- a/framework/CHANGELOG.md +++ b/framework/CHANGELOG.md @@ -12,6 +12,7 @@ Yii Framework 2 Change Log - Enh #18676: Added method `yii\helpers\BaseFileHelper::changeOwnership()` and properties `newFileMode`/`newFileOwnership` in `yii\console\controllers\BaseMigrateController` (rhertogh) - Bug #18678: Fix `yii\caching\DbCache` to use configured cache table name instead of the default one in case of MSSQL varbinary column type detection (aidanbek) - Enh #18695: Added `yii\web\Cookie::SAME_SITE_NONE` constant (rhertogh) +- Enh #18712: Added `$scheme` option to `yii\i18n\Formatter::asUrl()` (bizley) - Bug #18648: Fix `yii\web\Request` to properly handle HTTP Basic Auth headers (olegbaturin) - Enh #18726: Added `yii\helpers\Json::$prettyPrint` (rhertogh) diff --git a/framework/i18n/Formatter.php b/framework/i18n/Formatter.php index 0af9e3e4ed..3f8c33d870 100644 --- a/framework/i18n/Formatter.php +++ b/framework/i18n/Formatter.php @@ -210,7 +210,7 @@ class Formatter extends Component */ public $calendar; /** - * @var string the character displayed as the decimal point when formatting a number. + * @var string|null the character displayed as the decimal point when formatting a number. * If not set, the decimal separator corresponding to [[locale]] will be used. * If [PHP intl extension](https://secure.php.net/manual/en/book.intl.php) is not available, the default value is '.'. */ @@ -223,7 +223,7 @@ class Formatter extends Component */ public $currencyDecimalSeparator; /** - * @var string the character displayed as the thousands separator (also called grouping separator) character when formatting a number. + * @var string|null the character displayed as the thousands separator (also called grouping separator) character when formatting a number. * If not set, the thousand separator corresponding to [[locale]] will be used. * If [PHP intl extension](https://secure.php.net/manual/en/book.intl.php) is not available, the default value is ','. */ @@ -286,7 +286,7 @@ class Formatter extends Component */ public $numberFormatterSymbols = []; /** - * @var string the 3-letter ISO 4217 currency code indicating the default currency to use for [[asCurrency]]. + * @var string|null the 3-letter ISO 4217 currency code indicating the default currency to use for [[asCurrency]]. * If not set, the currency code corresponding to [[locale]] will be used. * Note that in this case the [[locale]] has to be specified with a country code, e.g. `en-US` otherwise it * is not possible to determine the default currency. @@ -443,8 +443,9 @@ class Formatter extends Component public function format($value, $format) { if ($format instanceof Closure) { - return call_user_func($format, $value, $this); - } elseif (is_array($format)) { + return $format($value, $this); + } + if (is_array($format)) { if (!isset($format[0])) { throw new InvalidArgumentException('The $format array must contain at least one element.'); } @@ -463,10 +464,8 @@ class Formatter extends Component throw new InvalidArgumentException("Unknown format type: $format"); } - // simple formats - /** * Formats the value as is without any formatting. * This method simply returns back the parameter without any format. @@ -578,16 +577,30 @@ class Formatter extends Component * Formats the value as a hyperlink. * @param mixed $value the value to be formatted. * @param array $options the tag options in terms of name-value pairs. See [[Html::a()]]. + * @param bool|string $scheme the URI scheme to use in the formatted hyperlink (available since 2.0.43): + * + * - `false (default)`: adding non-secure protocol scheme if there is none added already + * - `true`: adding secure protocol scheme if there is none added already + * - string: adding the specified scheme (either `http`, `https` or empty string + * for protocol-relative URL) if there is none added already + * * @return string the formatted result. */ - public function asUrl($value, $options = []) + public function asUrl($value, $options = [], $scheme = false) { if ($value === null) { return $this->nullDisplay; } $url = $value; + if (strpos($url, '://') === false) { - $url = 'http://' . $url; + if ($scheme === false || $scheme === 'http') { + $url = 'http://' . $url; + } elseif ($scheme === true || $scheme === 'https') { + $url = 'https://' . $url; + } elseif ($scheme === '') { + $url = '//' . $url; + } } return Html::a(Html::encode($value), $url, $options); @@ -608,10 +621,8 @@ class Formatter extends Component return $value ? $this->booleanFormat[1] : $this->booleanFormat[0]; } - // date and time formats - /** * Formats the value as a date. * @param int|string|DateTime|DateTimeInterface $value the value to be formatted. The following @@ -754,7 +765,7 @@ class Formatter extends Component // avoid time zone conversion for date-only and time-only values if ($type === 'date' || $type === 'time') { list($timestamp, $hasTimeInfo, $hasDateInfo) = $this->normalizeDatetimeValue($value, true); - if ($type === 'date' && !$hasTimeInfo || $type === 'time' && !$hasDateInfo) { + if (($type === 'date' && !$hasTimeInfo) || ($type === 'time' && !$hasDateInfo)) { $timeZone = $this->defaultTimeZone; } } else { @@ -772,18 +783,41 @@ class Formatter extends Component } if (isset($this->_dateFormats[$format])) { if ($type === 'date') { - $formatter = new IntlDateFormatter($this->locale, $this->_dateFormats[$format], IntlDateFormatter::NONE, $timeZone, $this->calendar); + $formatter = new IntlDateFormatter( + $this->locale, + $this->_dateFormats[$format], + IntlDateFormatter::NONE, + $timeZone, + $this->calendar + ); } elseif ($type === 'time') { - $formatter = new IntlDateFormatter($this->locale, IntlDateFormatter::NONE, $this->_dateFormats[$format], $timeZone, $this->calendar); + $formatter = new IntlDateFormatter( + $this->locale, + IntlDateFormatter::NONE, + $this->_dateFormats[$format], + $timeZone, + $this->calendar + ); } else { - $formatter = new IntlDateFormatter($this->locale, $this->_dateFormats[$format], $this->_dateFormats[$format], $timeZone, $this->calendar); + $formatter = new IntlDateFormatter( + $this->locale, + $this->_dateFormats[$format], + $this->_dateFormats[$format], + $timeZone, + $this->calendar + ); } } else { - $formatter = new IntlDateFormatter($this->locale, IntlDateFormatter::NONE, IntlDateFormatter::NONE, $timeZone, $this->calendar, $format); - } - if ($formatter === null) { - throw new InvalidConfigException(intl_get_error_message()); + $formatter = new IntlDateFormatter( + $this->locale, + IntlDateFormatter::NONE, + IntlDateFormatter::NONE, + $timeZone, + $this->calendar, + $format + ); } + // make IntlDateFormatter work with DateTimeImmutable if ($timestamp instanceof \DateTimeImmutable) { $timestamp = new DateTime($timestamp->format(DateTime::ISO8601), $timestamp->getTimezone()); @@ -824,7 +858,7 @@ class Formatter extends Component * timestamp, the second a boolean indicating whether the timestamp has time information and third a boolean indicating * whether the timestamp has date information. * This parameter is available since version 2.0.1. - * @return DateTime|array the normalized datetime value. + * @return DateTime|array the normalized datetime value * Since version 2.0.1 this may also return an array if `$checkDateTimeInfo` is true. * The first element of the array is the normalized timestamp and the second is a boolean indicating whether * the timestamp has time information or it is just a date value. @@ -846,9 +880,23 @@ class Formatter extends Component if (is_numeric($value)) { // process as unix timestamp, which is always in UTC $timestamp = new DateTime('@' . (int) $value, new DateTimeZone('UTC')); return $checkDateTimeInfo ? [$timestamp, true, true] : $timestamp; - } elseif (($timestamp = DateTime::createFromFormat('Y-m-d|', $value, new DateTimeZone($this->defaultTimeZone))) !== false) { // try Y-m-d format (support invalid dates like 2012-13-01) + } + if ( + ($timestamp = DateTime::createFromFormat( + 'Y-m-d|', + $value, + new DateTimeZone($this->defaultTimeZone)) + ) !== false + ) { // try Y-m-d format (support invalid dates like 2012-13-01) return $checkDateTimeInfo ? [$timestamp, false, true] : $timestamp; - } elseif (($timestamp = DateTime::createFromFormat('Y-m-d H:i:s', $value, new DateTimeZone($this->defaultTimeZone))) !== false) { // try Y-m-d H:i:s format (support invalid dates like 2012-13-01 12:63:12) + } + if ( + ($timestamp = DateTime::createFromFormat( + 'Y-m-d H:i:s', + $value, + new DateTimeZone($this->defaultTimeZone)) + ) !== false + ) { // try Y-m-d H:i:s format (support invalid dates like 2012-13-01 12:63:12) return $checkDateTimeInfo ? [$timestamp, true, true] : $timestamp; } // finally try to create a DateTime object with the value @@ -923,30 +971,17 @@ class Formatter extends Component $interval = $value; } else { $timestamp = $this->normalizeDatetimeValue($value); + $timeZone = new DateTimeZone($this->timeZone); - if ($timestamp === false) { - // $value is not a valid date/time value, so we try - // to create a DateInterval with it - try { - $interval = new DateInterval($value); - } catch (\Exception $e) { - // invalid date/time and invalid interval - return $this->nullDisplay; - } + if ($referenceTime === null) { + $dateNow = new DateTime('now', $timeZone); } else { - $timeZone = new DateTimeZone($this->timeZone); - - if ($referenceTime === null) { - $dateNow = new DateTime('now', $timeZone); - } else { - $dateNow = $this->normalizeDatetimeValue($referenceTime); - $dateNow->setTimezone($timeZone); - } - - $dateThen = $timestamp->setTimezone($timeZone); - - $interval = $dateThen->diff($dateNow); + $dateNow = $this->normalizeDatetimeValue($referenceTime); + $dateNow->setTimezone($timeZone); } + + $dateThen = $timestamp->setTimezone($timeZone); + $interval = $dateThen->diff($dateNow); } if ($interval->invert) { @@ -1213,7 +1248,8 @@ class Formatter extends Component * If not given, the number of digits depends in the input value and is determined based on * `NumberFormatter::MIN_FRACTION_DIGITS` and `NumberFormatter::MAX_FRACTION_DIGITS`, which can be configured * using [[$numberFormatterOptions]]. - * If the [PHP intl extension](https://secure.php.net/manual/en/book.intl.php) is not available, the default value depends on your PHP configuration. + * If the [PHP intl extension](https://secure.php.net/manual/en/book.intl.php) is not available, the default value + * depends on your PHP configuration. * If you want consistent behavior between environments where intl is available and not, you should explicitly * specify a value here. * @param array $options optional configuration for the number formatter. This parameter will be merged with [[numberFormatterOptions]]. @@ -1497,7 +1533,7 @@ class Formatter extends Component */ public function asLength($value, $decimals = null, $numberOptions = [], $textOptions = []) { - return $this->formatUnit(self::UNIT_LENGTH, self::FORMAT_WIDTH_LONG, $value, null, null, $decimals, $numberOptions, $textOptions); + return $this->formatUnit(self::UNIT_LENGTH, self::FORMAT_WIDTH_LONG, $value, $decimals, $numberOptions, $textOptions); } /** @@ -1520,7 +1556,7 @@ class Formatter extends Component */ public function asShortLength($value, $decimals = null, $options = [], $textOptions = []) { - return $this->formatUnit(self::UNIT_LENGTH, self::FORMAT_WIDTH_SHORT, $value, null, null, $decimals, $options, $textOptions); + return $this->formatUnit(self::UNIT_LENGTH, self::FORMAT_WIDTH_SHORT, $value, $decimals, $options, $textOptions); } /** @@ -1540,7 +1576,7 @@ class Formatter extends Component */ public function asWeight($value, $decimals = null, $options = [], $textOptions = []) { - return $this->formatUnit(self::UNIT_WEIGHT, self::FORMAT_WIDTH_LONG, $value, null, null, $decimals, $options, $textOptions); + return $this->formatUnit(self::UNIT_WEIGHT, self::FORMAT_WIDTH_LONG, $value, $decimals, $options, $textOptions); } /** @@ -1562,38 +1598,29 @@ class Formatter extends Component */ public function asShortWeight($value, $decimals = null, $options = [], $textOptions = []) { - return $this->formatUnit(self::UNIT_WEIGHT, self::FORMAT_WIDTH_SHORT, $value, null, null, $decimals, $options, $textOptions); + return $this->formatUnit(self::UNIT_WEIGHT, self::FORMAT_WIDTH_SHORT, $value, $decimals, $options, $textOptions); } /** * @param string $unitType one of [[UNIT_WEIGHT]], [[UNIT_LENGTH]] * @param string $unitFormat one of [[FORMAT_WIDTH_SHORT]], [[FORMAT_WIDTH_LONG]] * @param float|int|null $value to be formatted - * @param float $baseUnit unit of value as the multiplier of the smallest unit. When `null`, property [[baseUnits]] - * will be used to determine base unit using $unitType and $unitSystem. - * @param string $unitSystem either [[UNIT_SYSTEM_METRIC]] or [[UNIT_SYSTEM_IMPERIAL]]. When `null`, property [[systemOfUnits]] will be used. - * @param int $decimals the number of digits after the decimal point. + * @param int|null $decimals the number of digits after the decimal point. * @param array $options optional configuration for the number formatter. This parameter will be merged with [[numberFormatterOptions]]. * @param array $textOptions optional configuration for the number formatter. This parameter will be merged with [[numberFormatterTextOptions]]. * @return string * @throws InvalidConfigException when INTL is not installed or does not contain required information */ - private function formatUnit($unitType, $unitFormat, $value, $baseUnit, $unitSystem, $decimals, $options, $textOptions) + private function formatUnit($unitType, $unitFormat, $value, $decimals, $options, $textOptions) { if ($value === null) { return $this->nullDisplay; } - if ($unitSystem === null) { - $unitSystem = $this->systemOfUnits; - } - if ($baseUnit === null) { - $baseUnit = $this->baseUnits[$unitType][$unitSystem]; - } - $multipliers = array_values($this->measureUnits[$unitType][$unitSystem]); + $multipliers = array_values($this->measureUnits[$unitType][$this->systemOfUnits]); list($params, $position) = $this->formatNumber( - $this->normalizeNumericValue($value) * $baseUnit, + $this->normalizeNumericValue($value) * $this->baseUnits[$unitType][$this->systemOfUnits], $decimals, null, $multipliers, @@ -1601,7 +1628,7 @@ class Formatter extends Component $textOptions ); - $message = $this->getUnitMessage($unitType, $unitFormat, $unitSystem, $position); + $message = $this->getUnitMessage($unitType, $unitFormat, $this->systemOfUnits, $position); return (new \MessageFormatter($this->locale, $message))->format([ '0' => $params['nFormatted'], @@ -1638,7 +1665,10 @@ class Formatter extends Component $unitBundle = $this->_resourceBundle[$bundleKey][$unitType][$unitNames[$position]]; if ($unitBundle === null) { - throw new InvalidConfigException('Current ICU data version does not contain information about unit type "' . $unitType . '" and unit measure "' . $unitNames[$position] . '". Check system requirements.'); + throw new InvalidConfigException( + 'Current ICU data version does not contain information about unit type "' . $unitType + . '" and unit measure "' . $unitNames[$position] . '". Check system requirements.' + ); } $message = []; @@ -1656,7 +1686,7 @@ class Formatter extends Component * Given the value in bytes formats number part of the human readable form. * * @param string|int|float $value value in bytes to be formatted. - * @param int $decimals the number of digits after the decimal point + * @param int|null $decimals the number of digits after the decimal point * @param int $maxPosition maximum internal position of size unit, ignored if $formatBase is an array * @param array|int $formatBase the base at which each next unit is calculated, either 1000 or 1024, or an array * @param array $options optional configuration for the number formatter. This parameter will be merged with [[numberFormatterOptions]]. @@ -1881,7 +1911,7 @@ class Formatter extends Component * to the defined decimal digits. * * @param string|int|float $value the value to be formatted. - * @param int $decimals the number of digits after the decimal point. The default value is `2`. + * @param int|null $decimals the number of digits after the decimal point. The default value is `2`. * @return string the formatted result. * @see decimalSeparator * @see thousandSeparator diff --git a/tests/framework/i18n/FormatterDateTest.php b/tests/framework/i18n/FormatterDateTest.php index ceb1aa0d20..d6c8a58ff3 100644 --- a/tests/framework/i18n/FormatterDateTest.php +++ b/tests/framework/i18n/FormatterDateTest.php @@ -74,7 +74,7 @@ class FormatterDateTest extends TestCase $this->assertSame(date('n/j/y', $value->getTimestamp()), $this->formatter->asDate($value, 'short')); $this->assertSame(date('F j, Y', $value->getTimestamp()), $this->formatter->asDate($value, 'long')); - if (version_compare(PHP_VERSION, '5.5.0', '>=')) { + if (PHP_VERSION_ID >= 50500) { $value = new \DateTimeImmutable(); $this->assertSame(date('M j, Y', $value->getTimestamp()), $this->formatter->asDate($value)); $this->assertSame(date('Y/m/d', $value->getTimestamp()), $this->formatter->asDate($value, 'php:Y/m/d')); @@ -410,6 +410,9 @@ class FormatterDateTest extends TestCase // just now $this->assertSame('just now', $this->formatter->asRelativeTime($t = time(), $t)); $this->assertSame('just now', $this->formatter->asRelativeTime(0, 0)); + $interval_0_seconds = new DateInterval('PT0S'); + $interval_0_seconds->invert = true; + $this->assertSame('just now', $this->formatter->asRelativeTime($interval_0_seconds)); // empty input $this->assertSame('just now', $this->formatter->asRelativeTime(false, 0)); @@ -418,6 +421,10 @@ class FormatterDateTest extends TestCase // null display $this->assertSame($this->formatter->nullDisplay, $this->formatter->asRelativeTime(null)); $this->assertSame($this->formatter->nullDisplay, $this->formatter->asRelativeTime(null, time())); + + // no reference time + $now = new DateTime('-1 minute'); + $this->assertSame('a minute ago', $this->formatter->asRelativeTime($now)); } public function testIntlAsDuration() diff --git a/tests/framework/i18n/FormatterNumberTest.php b/tests/framework/i18n/FormatterNumberTest.php index 6d1b7b7fa3..d475a98203 100755 --- a/tests/framework/i18n/FormatterNumberTest.php +++ b/tests/framework/i18n/FormatterNumberTest.php @@ -125,7 +125,6 @@ class FormatterNumberTest extends TestCase $this->formatter->numberFormatterTextOptions = [ \NumberFormatter::POSITIVE_PREFIX => '+', ]; - $this->assertSame('+2', $this->formatter->asInteger(2)); $this->assertSame('+10', $this->formatter->asInteger(10)); $this->assertSame('+12', $this->formatter->asInteger(12)); @@ -141,19 +140,15 @@ class FormatterNumberTest extends TestCase $this->assertSame('+123,456', $this->formatter->asInteger(123456.789)); } - /** - * @expectedException \yii\base\InvalidParamException - */ public function testAsIntegerException() { + $this->expectException('\yii\base\InvalidParamException'); $this->formatter->asInteger('a'); } - /** - * @expectedException \yii\base\InvalidParamException - */ public function testAsIntegerException2() { + $this->expectException('\yii\base\InvalidParamException'); $this->formatter->asInteger('-123abc'); } @@ -270,6 +265,7 @@ class FormatterNumberTest extends TestCase $this->assertSame('87,654,321,098,765,436.00', $this->formatter->asDecimal('87654321098765436')); $this->assertSame('95,836,208,451,783,051.86', $this->formatter->asDecimal('95836208451783051.864')); $this->assertSame('95,836,208,451,783,052', $this->formatter->asDecimal('95836208451783051.864', 0)); + $this->assertSame('95,836,208,451,783,051.9', $this->formatter->asDecimal('95836208451783051.864', 1)); $this->formatter->thousandSeparator = ' '; $this->formatter->decimalSeparator = ','; @@ -422,11 +418,9 @@ class FormatterNumberTest extends TestCase $this->assertIsOneOf($this->formatter->asCurrency('123'), ["123.00\xc2\xa0₽", "123.00\xc2\xa0руб."]); } - /** - * @expectedException \yii\base\InvalidConfigException - */ public function testAsCurrencyStringFallbackException() { + $this->expectException('\yii\base\InvalidConfigException'); $this->formatter->asCurrency('87654321098765436'); } @@ -555,6 +549,13 @@ class FormatterNumberTest extends TestCase $this->assertSame('8.765432E+16', $this->formatter->asScientific('87654321098765436')); } + public function testAsSpellout() + { + $this->expectException('\yii\base\InvalidConfigException'); + $this->expectExceptionMessage('Format as Spellout is only supported when PHP intl extension is installed.'); + $this->formatter->asSpellout(123); + } + public function testIntlAsSpellout() { $this->assertSame('one hundred twenty-three', $this->formatter->asSpellout(123)); @@ -611,6 +612,8 @@ class FormatterNumberTest extends TestCase $this->assertSame('999 B', $this->formatter->asShortSize(999)); $this->assertSame('999 B', $this->formatter->asShortSize('999')); $this->assertSame('1.05 MB', $this->formatter->asShortSize(1024 * 1024)); + $this->assertSame('1.07 GB', $this->formatter->asShortSize(1024 * 1024 * 1024)); + $this->assertSame('1.1 TB', $this->formatter->asShortSize(1024 * 1024 * 1024 * 1024)); $this->assertSame('1 kB', $this->formatter->asShortSize(1000)); $this->assertSame('1.02 kB', $this->formatter->asShortSize(1023)); $this->assertNotEquals('3 PB', $this->formatter->asShortSize(3 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000)); // this is 3 EB not 3 PB @@ -627,6 +630,7 @@ class FormatterNumberTest extends TestCase // https://github.com/yiisoft/yii2/issues/4960 $this->assertSame('1023 B', $this->formatter->asShortSize(1023)); $this->assertSame('5 GiB', $this->formatter->asShortSize(5 * 1024 * 1024 * 1024)); + $this->assertSame('6 TiB', $this->formatter->asShortSize(6 * 1024 * 1024 * 1024 * 1024)); $this->assertNotEquals('5 PiB', $this->formatter->asShortSize(5 * 1024 * 1024 * 1024 * 1024 * 1024 * 1024)); // this is 5 EiB not 5 PiB //$this->assertSame("1 YiB", $this->formatter->asShortSize(pow(2, 80))); $this->assertSame('2 GiB', $this->formatter->asShortSize(2147483647)); // round 1.999 up to 2 @@ -648,6 +652,8 @@ class FormatterNumberTest extends TestCase $this->assertSame('999 B', $this->formatter->asShortSize(999)); $this->assertSame('999 B', $this->formatter->asShortSize('999')); $this->assertSame('1.05 MB', $this->formatter->asShortSize(1024 * 1024)); + $this->assertSame('1.07 GB', $this->formatter->asShortSize(1024 * 1024 * 1024)); + $this->assertSame('1.10 TB', $this->formatter->asShortSize(1024 * 1024 * 1024 * 1024)); $this->assertSame('1.0486 MB', $this->formatter->asShortSize(1024 * 1024, 4)); $this->assertSame('1.00 kB', $this->formatter->asShortSize(1000)); $this->assertSame('1.02 kB', $this->formatter->asShortSize(1023)); @@ -665,6 +671,7 @@ class FormatterNumberTest extends TestCase // https://github.com/yiisoft/yii2/issues/4960 $this->assertSame('1023 B', $this->formatter->asShortSize(1023)); $this->assertSame('5.00 GiB', $this->formatter->asShortSize(5 * 1024 * 1024 * 1024)); + $this->assertSame('6.00 TiB', $this->formatter->asShortSize(6 * 1024 * 1024 * 1024 * 1024)); $this->assertNotEquals('5.00 PiB', $this->formatter->asShortSize(5 * 1024 * 1024 * 1024 * 1024 * 1024 * 1024)); // this is 5 EiB not 5 PiB //$this->assertSame("1 YiB", $this->formatter->asShortSize(pow(2, 80))); $this->assertSame('2.00 GiB', $this->formatter->asShortSize(2147483647)); // round 1.999 up to 2 @@ -693,6 +700,7 @@ class FormatterNumberTest extends TestCase $this->assertSame('1 kilobyte', $this->formatter->asSize(1000)); $this->assertSame('1.02 kilobytes', $this->formatter->asSize(1023)); $this->assertSame('3 gigabytes', $this->formatter->asSize(3 * 1000 * 1000 * 1000)); + $this->assertSame('4 terabytes', $this->formatter->asSize(4 * 1000 * 1000 * 1000 * 1000)); $this->assertNotEquals('3 PB', $this->formatter->asSize(3 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000)); // this is 3 EB not 3 PB // tests for base 1024 $this->formatter->sizeFormatBase = 1024; @@ -700,6 +708,7 @@ class FormatterNumberTest extends TestCase $this->assertSame('1 mebibyte', $this->formatter->asSize(1024 * 1024)); $this->assertSame('1023 bytes', $this->formatter->asSize(1023)); $this->assertSame('5 gibibytes', $this->formatter->asSize(5 * 1024 * 1024 * 1024)); + $this->assertSame('6 tebibytes', $this->formatter->asSize(6 * 1024 * 1024 * 1024 * 1024)); $this->assertNotEquals('5 pibibytes', $this->formatter->asSize(5 * 1024 * 1024 * 1024 * 1024 * 1024 * 1024)); // this is 5 EiB not 5 PiB $this->assertSame('2 gibibytes', $this->formatter->asSize(2147483647)); // round 1.999 up to 2 $this->formatter->decimalSeparator = ','; @@ -750,6 +759,7 @@ class FormatterNumberTest extends TestCase $this->assertSame('1.00 kilobyte', $this->formatter->asSize(1000)); $this->assertSame('1.02 kilobytes', $this->formatter->asSize(1023)); $this->assertSame('3.00 gigabytes', $this->formatter->asSize(3 * 1000 * 1000 * 1000)); + $this->assertSame('4.00 terabytes', $this->formatter->asSize(4 * 1000 * 1000 * 1000 * 1000)); $this->assertNotEquals('3 PB', $this->formatter->asSize(3 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000)); // this is 3 EB not 3 PB // tests for base 1024 $this->formatter->sizeFormatBase = 1024; @@ -757,6 +767,7 @@ class FormatterNumberTest extends TestCase $this->assertSame('1.00 mebibyte', $this->formatter->asSize(1024 * 1024)); $this->assertSame('1023 bytes', $this->formatter->asSize(1023)); $this->assertSame('5.00 gibibytes', $this->formatter->asSize(5 * 1024 * 1024 * 1024)); + $this->assertSame('6.00 tebibytes', $this->formatter->asSize(6 * 1024 * 1024 * 1024 * 1024)); $this->assertNotEquals('5.00 pibibytes', $this->formatter->asSize(5 * 1024 * 1024 * 1024 * 1024 * 1024 * 1024)); // this is 5 EiB not 5 PiB $this->assertSame('2.00 gibibytes', $this->formatter->asSize(2147483647)); // round 1.999 up to 2 $this->formatter->decimalSeparator = ','; diff --git a/tests/framework/i18n/FormatterTest.php b/tests/framework/i18n/FormatterTest.php index 4716c67827..d51b351938 100644 --- a/tests/framework/i18n/FormatterTest.php +++ b/tests/framework/i18n/FormatterTest.php @@ -7,7 +7,6 @@ namespace yiiunit\framework\i18n; -use Yii; use yii\i18n\Formatter; use yiiunit\TestCase; @@ -45,23 +44,51 @@ class FormatterTest extends TestCase $this->formatter = null; } - public function testFormat() { $value = time(); $this->assertSame(date('M j, Y', $value), $this->formatter->format($value, 'date')); $this->assertSame(date('M j, Y', $value), $this->formatter->format($value, 'DATE')); $this->assertSame(date('Y/m/d', $value), $this->formatter->format($value, ['date', 'php:Y/m/d'])); + } + + public function testInvalidFormat() + { + $value = time(); $this->expectException('\yii\base\InvalidParamException'); + $this->expectExceptionMessage('Unknown format type: data'); $this->assertSame(date('Y-m-d', $value), $this->formatter->format($value, 'data')); + } + + public function testInvalidFormatArray() + { + $value = time(); + $this->expectException('\yii\base\InvalidParamException'); + $this->expectExceptionMessage('Unknown format type: data'); + $this->assertSame(date('Y-m-d', $value), $this->formatter->format($value, ['data'])); + } + + public function testFormatArrayInvalidStructure() + { + $value = time(); + $this->expectException('\yii\base\InvalidParamException'); + $this->expectExceptionMessage('The $format array must contain at least one element.'); + $this->assertSame(date('Y-m-d', $value), $this->formatter->format($value, [])); + } + + public function testClosureFormat() + { + $value = time(); $this->assertSame(date('Y-m-d', $value), $this->formatter->format($value, function ($value) { return date('Y-m-d', $value); })); - $this->assertSame('from: ' . date('Y-m-d', $value), + $this->assertSame( + 'from: ' . date('Y-m-d', $value), $this->formatter->format($value, function ($value, $formatter) { - /** @var $formatter Formatter */ - return 'from: ' . $formatter->asDate($value, 'php:Y-m-d'); - })); + /** @var $formatter Formatter */ + return 'from: ' . $formatter->asDate($value, 'php:Y-m-d'); + }) + ); } public function testLocale() @@ -162,10 +189,16 @@ class FormatterTest extends TestCase $this->assertSame($this->formatter->nullDisplay, $this->formatter->asParagraphs(null)); } - /*public function testAsHtml() + public function testAsHtml() { - // todo: dependency on HtmlPurifier - }*/ + $value = 'no HTML tags'; + $this->assertSame($value, $this->formatter->asHtml($value)); + $value = '
paragraph
'; + $this->assertSame($value, $this->formatter->asHtml($value)); + // null display + $this->assertSame($this->formatter->nullDisplay, $this->formatter->asHtml(null)); + $this->assertSame('w1 w2
', $this->formatter->asHtml('w1 w2