From f968e9d52fc7c42b239e1973bb7093c747cf065e Mon Sep 17 00:00:00 2001 From: Adam Silverstein Date: Tue, 8 Jan 2019 19:55:31 +0000 Subject: [PATCH] Media: improve the `human_readable_duration` function and tests. Improve the `human_readable_duration` added in #39667: * Remove upper limit. * More resilient handling: remove negative prefix, trim. * Correct @since to 5.1.0. * Adds more test cases and improve inline docs. Props birgire. Fixes #39667. git-svn-id: https://develop.svn.wordpress.org/trunk@44481 602fd350-edb4-49c9-b593-d223f7449a82 --- src/wp-includes/functions.php | 66 +++++++++++++++----------- tests/phpunit/tests/functions.php | 77 +++++++++++++++++++++++-------- 2 files changed, 98 insertions(+), 45 deletions(-) diff --git a/src/wp-includes/functions.php b/src/wp-includes/functions.php index c36bae97ad..9a8b4cf911 100644 --- a/src/wp-includes/functions.php +++ b/src/wp-includes/functions.php @@ -323,54 +323,68 @@ function size_format( $bytes, $decimals = 0 ) { } /** - * Convert a filelength to human readable format. + * Convert a duration to human readable format. * - * @since 5.0 + * @since 5.1.0 * - * @param string $filelength Duration will be in string format (HH:ii:ss) OR (ii:ss). - * @return boolean|string A human readable filelength string, false on failure. + * @param string $duration Duration will be in string format (HH:ii:ss) OR (ii:ss), + * with a possible prepended negative sign (-). + * @return string|false A human readable duration string, false on failure. */ -function human_readable_duration( $filelength = '' ) { - // Return false if filelength is empty or not in format. - if ( ( empty( $filelength ) || ! is_string( $filelength ) ) ) { +function human_readable_duration( $duration = '' ) { + if ( ( empty( $duration ) || ! is_string( $duration ) ) ) { return false; } - // Validate filelength format. - if ( ! ( (bool) preg_match( '/^(([0-3]?[0-9])|([2][0-3])):([0-5]?[0-9])(:([0-5]?[0-9]))?$/', $filelength ) ) ) { + $duration = trim( $duration ); + + // Remove prepended negative sign. + if ( '-' === substr( $duration, 0, 1 ) ) { + $duration = substr( $duration, 1 ); + } + + // Extract duration parts. + $duration_parts = array_reverse( explode( ':', $duration ) ); + $duration_count = count( $duration_parts ); + + $hour = null; + $minute = null; + $second = null; + + if ( 3 === $duration_count ) { + // Validate HH:ii:ss duration format. + if ( ! ( (bool) preg_match( '/^([0-9]+):([0-5]?[0-9]):([0-5]?[0-9])$/', $duration ) ) ) { + return false; + } + // Three parts: hours, minutes & seconds. + list( $second, $minute, $hour ) = $duration_parts; + } elseif ( 2 === $duration_count ) { + // Validate ii:ss duration format. + if ( ! ( (bool) preg_match( '/^([0-5]?[0-9]):([0-5]?[0-9])$/', $duration ) ) ) { + return false; + } + // Two parts: minutes & seconds. + list( $second, $minute ) = $duration_parts; + } else { return false; } $human_readable_duration = array(); - // Extract duration. - $durations = array_reverse( explode( ':', $filelength ) ); - $duration_count = count( $durations ); - - if ( 3 === $duration_count ) { - // Three parts: hours, minutes & seconds. - list( $second, $minute, $hour ) = $durations; - } elseif ( 2 === $duration_count ) { - // Two parts: minutes & seconds. - list( $second, $minute ) = $durations; - } else { - return false; - } - // Add the hour part to the string. - if ( ! empty( $hour ) && is_numeric( $hour ) ) { + if ( is_numeric( $hour ) ) { /* translators: Time duration in hour or hours. */ $human_readable_duration[] = sprintf( _n( '%s hour', '%s hours', $hour ), (int) $hour ); } // Add the minute part to the string. - if ( ! empty( $minute ) && is_numeric( $minute ) ) { + if ( is_numeric( $minute ) ) { /* translators: Time duration in minute or minutes. */ $human_readable_duration[] = sprintf( _n( '%s minute', '%s minutes', $minute ), (int) $minute ); } // Add the second part to the string. - if ( ! empty( $second ) && is_numeric( $second ) ) { + if ( is_numeric( $second ) ) { /* translators: Time duration in second or seconds. */ $human_readable_duration[] = sprintf( _n( '%s second', '%s seconds', $second ), (int) $second ); } diff --git a/tests/phpunit/tests/functions.php b/tests/phpunit/tests/functions.php index 84d032dd95..efbc88a762 100644 --- a/tests/phpunit/tests/functions.php +++ b/tests/phpunit/tests/functions.php @@ -1579,22 +1579,60 @@ class Tests_Functions extends WP_UnitTestCase { } /** - * Test the human_readable_duration function. + * Test human_readable_duration(). * * @ticket 39667 - * @dataProvider _datahuman_readable_duration() + * @dataProvider data_test_human_readable_duration * - * @param $input - * @param $expected + * @param string $input Duration. + * @param string $expected Expected human readable duration. */ - public function test_duration_format( $input, $expected ) { + public function test_human_readable_duration( $input, $expected ) { $this->assertSame( $expected, human_readable_duration( $input ) ); } - public function _datahuman_readable_duration() { + /** + * Dataprovider for test_duration_format(). + * + * @return array { + * @type array { + * @type string $input Duration. + * @type string $expect Expected human readable duration. + * } + * } + */ + public function data_test_human_readable_duration() { return array( - array( array(), false ), + // Valid ii:ss cases. + array( '0:0', '0 minutes, 0 seconds' ), + array( '00:00', '0 minutes, 0 seconds' ), + array( '0:5', '0 minutes, 5 seconds' ), + array( '0:05', '0 minutes, 5 seconds' ), + array( '01:01', '1 minute, 1 second' ), array( '30:00', '30 minutes, 0 seconds' ), + array( ' 30:00 ', '30 minutes, 0 seconds' ), + // Valid HH:ii:ss cases. + array( '0:0:0', '0 hours, 0 minutes, 0 seconds' ), + array( '00:00:00', '0 hours, 0 minutes, 0 seconds' ), + array( '00:30:34', '0 hours, 30 minutes, 34 seconds' ), + array( '01:01:01', '1 hour, 1 minute, 1 second' ), + array( '1:02:00', '1 hour, 2 minutes, 0 seconds' ), + array( '10:30:34', '10 hours, 30 minutes, 34 seconds' ), + array( '1234567890:59:59', '1234567890 hours, 59 minutes, 59 seconds' ), + // Valid ii:ss cases with negative sign. + array( '-00:00', '0 minutes, 0 seconds' ), + array( '-3:00', '3 minutes, 0 seconds' ), + array( '-03:00', '3 minutes, 0 seconds' ), + array( '-30:00', '30 minutes, 0 seconds' ), + // Valid HH:ii:ss cases with negative sign. + array( '-00:00:00', '0 hours, 0 minutes, 0 seconds' ), + array( '-1:02:00', '1 hour, 2 minutes, 0 seconds' ), + // Invalid cases. + array( null, false ), + array( '', false ), + array( ':', false ), + array( '::', false ), + array( array(), false ), array( 'Batman Begins !', false ), array( '', false ), array( '-1', false ), @@ -1602,18 +1640,19 @@ class Tests_Functions extends WP_UnitTestCase { array( 0, false ), array( 1, false ), array( '00', false ), - array( '00:00', '0 minutes, 0 seconds' ), - array( '00:00:00', '0 hours, 0 minutes, 0 seconds' ), - array( '10:30:34', '10 hours, 30 minutes, 34 seconds' ), - array( '00:30:34', '0 hours, 30 minutes, 34 seconds' ), - array( 'MM:30:00', false ), - array( '30:MM', false ), - array( 'MM:00', false ), - array( 'MM:MM', false ), - array( '01:01', '1 minute, 1 second' ), - array( '01:01:01', '1 hour, 1 minute, 1 second' ), - array( '0:05', '5 seconds' ), - array( '1:02:00', '1 hour, 2 minutes, 0 seconds' ), + array( '30:-10', false ), + array( ':30:00', false ), // Missing HH. + array( 'MM:30:00', false ), // Invalid HH. + array( '30:MM:00', false ), // Invalid ii. + array( '30:30:MM', false ), // Invalid ss. + array( '30:MM', false ), // Invalid ss. + array( 'MM:00', false ), // Invalid ii. + array( 'MM:MM', false ), // Invalid ii and ss. + array( '10 :30', false ), // Containing a space. + array( '59:61', false ), // Out of bound. + array( '61:59', false ), // Out of bound. + array( '3:59:61', false ), // Out of bound. + array( '03:61:59', false ), // Out of bound. ); } }