diff --git a/.gitattributes b/.gitattributes index a5666637cb..97cb2461f6 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,2 +1,3 @@ # Auto detect text files and perform EOL normalization * text=auto eol=lf +tests/data/*-win.php eol=crlf diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index fd7c014077..5ceb818902 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -159,7 +159,7 @@ private static function terminate_proc( $master_pid ) { $output = `ps -o ppid,pid,command | grep $master_pid`; - foreach ( explode( PHP_EOL, $output ) as $line ) { + foreach ( explode( "\n", $output ) as $line ) { if ( preg_match( '/^\s*(\d+)\s+(\d+)/', $line, $matches ) ) { $parent = $matches[1]; $child = $matches[2]; @@ -393,7 +393,7 @@ public function move_files( $src, $dest ) { public function add_line_to_wp_config( &$wp_config_code, $line ) { $token = "/* That's all, stop editing!"; - $wp_config_code = str_replace( $token, "$line\n\n$token", $wp_config_code ); + $wp_config_code = str_replace( $token, $line. PHP_EOL . PHP_EOL . $token, $wp_config_code ); } public function download_wp( $subdir = '' ) { diff --git a/features/bootstrap/support.php b/features/bootstrap/support.php index a37a064f65..390cdc3a03 100644 --- a/features/bootstrap/support.php +++ b/features/bootstrap/support.php @@ -143,7 +143,7 @@ function checkThatJsonStringContainsJsonString( $actualJson, $expectedJson ) { * @return bool Whether $actualCSV contains $expectedCSV */ function checkThatCsvStringContainsValues( $actualCSV, $expectedCSV ) { - $actualCSV = array_map( 'str_getcsv', explode( PHP_EOL, $actualCSV ) ); + $actualCSV = array_map( 'str_getcsv', explode( "\n", $actualCSV ) ); if ( empty( $actualCSV ) ) return false; diff --git a/features/steps/given.php b/features/steps/given.php index 4482327804..2d25157ecb 100644 --- a/features/steps/given.php +++ b/features/steps/given.php @@ -31,7 +31,7 @@ function ( $world, $path, PyStringNode $content ) { $content = (string) $content . "\n"; $full_path = $world->variables['RUN_DIR'] . "/$path"; Process::create( \WP_CLI\utils\esc_cmd( 'mkdir -p %s', dirname( $full_path ) ) )->run_check(); - file_put_contents( $full_path, $content ); + file_put_contents( $full_path, WP_CLI\Utils\denormalize_newlines( $content ) ); } ); @@ -88,7 +88,7 @@ function ( $world, $type = 'subdirectory' ) { $steps->Given( '/^these installed and active plugins:$/', function( $world, $stream ) { - $plugins = implode( ' ', array_map( 'trim', explode( PHP_EOL, (string)$stream ) ) ); + $plugins = implode( ' ', array_map( 'trim', explode( "\n", (string)$stream ) ) ); $world->proc( "wp plugin install $plugins --activate" )->run_check(); } ); diff --git a/features/steps/then.php b/features/steps/then.php index 8875554859..76d5354659 100644 --- a/features/steps/then.php +++ b/features/steps/then.php @@ -193,7 +193,7 @@ function ( $world, $path, $type, $action, $expected = null ) { foreach( $files as &$file ) { $file = str_replace( $path . '/', '', $file ); } - $contents = implode( PHP_EOL, $files ); + $contents = implode( "\n", $files ); } checkString( $contents, $expected, $action ); } diff --git a/features/steps/when.php b/features/steps/when.php index afe3f7a0df..659f53a674 100644 --- a/features/steps/when.php +++ b/features/steps/when.php @@ -29,6 +29,8 @@ function ( $world, $cmd ) { function ( $world, $mode, $cmd ) { $cmd = $world->replace_variables( $cmd ); $world->result = invoke_proc( $world->proc( $cmd ), $mode ); + $world->result->stdout = WP_CLI\Utils\normalize_newlines( $world->result->stdout ); + $world->result->stderr = WP_CLI\Utils\normalize_newlines( $world->result->stderr ); list( $world->result->stdout, $world->email_sends ) = capture_email_sends( $world->result->stdout ); } ); @@ -37,6 +39,8 @@ function ( $world, $mode, $cmd ) { function ( $world, $mode, $cmd, $subdir ) { $cmd = $world->replace_variables( $cmd ); $world->result = invoke_proc( $world->proc( $cmd, array(), $subdir ), $mode ); + $world->result->stdout = WP_CLI\Utils\normalize_newlines( $world->result->stdout ); + $world->result->stderr = WP_CLI\Utils\normalize_newlines( $world->result->stderr ); list( $world->result->stdout, $world->email_sends ) = capture_email_sends( $world->result->stdout ); } ); @@ -48,6 +52,8 @@ function ( $world, $mode ) { $proc = Process::create( $world->result->command, $world->result->cwd, $world->result->env ); $world->result = invoke_proc( $proc, $mode ); + $world->result->stdout = WP_CLI\Utils\normalize_newlines( $world->result->stdout ); + $world->result->stderr = WP_CLI\Utils\normalize_newlines( $world->result->stderr ); list( $world->result->stdout, $world->email_sends ) = capture_email_sends( $world->result->stdout ); } ); diff --git a/php/WP_CLI/Bootstrap/IncludeFrameworkAutoloader.php b/php/WP_CLI/Bootstrap/IncludeFrameworkAutoloader.php index 910ec8355c..d2301dcd73 100644 --- a/php/WP_CLI/Bootstrap/IncludeFrameworkAutoloader.php +++ b/php/WP_CLI/Bootstrap/IncludeFrameworkAutoloader.php @@ -43,7 +43,7 @@ protected function get_autoloader_paths() { protected function handle_failure() { fputs( STDERR, - "Internal error: Can't find Composer autoloader.\nTry running: composer install\n" + 'Internal error: Can\'t find Composer autoloader.' . PHP_EOL . 'Try running: composer install' . PHP_EOL ); exit( 3 ); } diff --git a/php/WP_CLI/Configurator.php b/php/WP_CLI/Configurator.php index 2def54f1e9..70fdf19555 100644 --- a/php/WP_CLI/Configurator.php +++ b/php/WP_CLI/Configurator.php @@ -200,7 +200,7 @@ private function unmix_assoc_args( $mixed_args, $global_assoc = array(), $local_ private function assoc_arg_to_runtime_config( $key, $value, &$runtime_config ) { $details = $this->spec[ $key ]; if ( isset( $details['deprecated'] ) ) { - fwrite( STDERR, "WP-CLI: The --{$key} global parameter is deprecated. {$details['deprecated']}\n" ); + fwrite( STDERR, "WP-CLI: The --{$key} global parameter is deprecated. {$details['deprecated']}" . PHP_EOL ); } if ( $details['multiple'] ) { diff --git a/php/WP_CLI/Dispatcher/Subcommand.php b/php/WP_CLI/Dispatcher/Subcommand.php index a50dcf8113..a21c621673 100644 --- a/php/WP_CLI/Dispatcher/Subcommand.php +++ b/php/WP_CLI/Dispatcher/Subcommand.php @@ -36,7 +36,7 @@ function __construct( $parent, $name, $docparser, $when_invoked ) { * @return string */ private static function extract_synopsis( $longdesc ) { - preg_match_all( '/(.+?)[\r\n]+:/', $longdesc, $matches ); + preg_match_all( '/(.+?)\n+:/', $longdesc, $matches ); return implode( ' ', $matches[1] ); } @@ -276,8 +276,8 @@ private function validate_args( $args, $assoc_args, $extra_args ) { $i = 0; $errors = array( 'fatal' => array(), 'warning' => array() ); $mock_doc = array( $this->get_shortdesc(), '' ); - $mock_doc = array_merge( $mock_doc, explode( PHP_EOL, $this->get_longdesc() ) ); - $mock_doc = '/**' . PHP_EOL . '* ' . implode( PHP_EOL . '* ', $mock_doc ) . PHP_EOL . '*/'; + $mock_doc = array_merge( $mock_doc, explode( "\n", $this->get_longdesc() ) ); + $mock_doc = "/**\n* " . implode( "\n* ", $mock_doc ) . "\n*/"; $docparser = new \WP_CLI\DocParser( $mock_doc ); foreach( $synopsis_spec as $spec ) { if ( 'positional' === $spec['type'] ) { @@ -335,7 +335,7 @@ private function validate_args( $args, $assoc_args, $extra_args ) { $errors['fatal'][] = sprintf( 'unknown --%s parameter%s', $key, - ! empty( $suggestion ) ? PHP_EOL . "Did you mean '--{$suggestion}'?" : '' + ! empty( $suggestion ) ? "\nDid you mean '--{$suggestion}'?" : '' ); } } diff --git a/php/WP_CLI/DocParser.php b/php/WP_CLI/DocParser.php index a6f4cb9338..daa3708ab6 100644 --- a/php/WP_CLI/DocParser.php +++ b/php/WP_CLI/DocParser.php @@ -19,6 +19,7 @@ class DocParser { * @param string $docComment */ public function __construct( $docComment ) { + $docComment = Utils\normalize_newlines( $docComment ); $this->docComment = self::remove_decorations( $docComment ); } @@ -29,7 +30,7 @@ public function __construct( $docComment ) { * @return string */ private static function remove_decorations( $comment ) { - $comment = preg_replace( '|^/\*\*[\r\n]+|', '', $comment ); + $comment = preg_replace( '|^/\*\*\n+|', '', $comment ); $comment = preg_replace( '|\n[\t ]*\*/$|', '', $comment ); $comment = preg_replace( '|^[\t ]*\* ?|m', '', $comment ); @@ -155,7 +156,7 @@ public function get_param_args( $key ) { * @return array|null Interpreted YAML document, or null. */ private function get_arg_or_param_args( $regex ) { - $bits = explode( PHP_EOL, $this->docComment ); + $bits = explode( "\n", $this->docComment ); $within_arg = $within_doc = false; $document = array(); foreach( $bits as $bit ) { @@ -182,7 +183,7 @@ private function get_arg_or_param_args( $regex ) { } if ( $document ) { - return Spyc::YAMLLoadString( implode( PHP_EOL, $document ) ); + return Spyc::YAMLLoadString( implode( "\n", $document ) ); } return null; } diff --git a/php/WP_CLI/Loggers/Base.php b/php/WP_CLI/Loggers/Base.php index 129ee70034..9e401e7271 100644 --- a/php/WP_CLI/Loggers/Base.php +++ b/php/WP_CLI/Loggers/Base.php @@ -54,7 +54,7 @@ public function debug( $message, $group = false ) { * @param string $str Message to write. */ protected function write( $handle, $str ) { - fwrite( $handle, $str ); + fwrite( $handle, \WP_CLI\Utils\denormalize_newlines( $str ) ); } /** diff --git a/php/WP_CLI/ProcessRun.php b/php/WP_CLI/ProcessRun.php index aedc5f65da..afd578417a 100644 --- a/php/WP_CLI/ProcessRun.php +++ b/php/WP_CLI/ProcessRun.php @@ -51,9 +51,9 @@ public function __construct( $props ) { * @return string */ public function __toString() { - $out = "$ $this->command\n"; - $out .= "$this->stdout\n$this->stderr"; - $out .= "cwd: $this->cwd\n"; + $out = "$ $this->command" . PHP_EOL; + $out .= Utils\denormalize_newlines( $this->stdout ) . PHP_EOL . Utils\denormalize_newlines( $this->stderr ); + $out .= "cwd: $this->cwd" . PHP_EOL; $out .= "exit status: $this->return_code"; return $out; diff --git a/php/WP_CLI/Runner.php b/php/WP_CLI/Runner.php index 44bab83291..0fd70b86f1 100644 --- a/php/WP_CLI/Runner.php +++ b/php/WP_CLI/Runner.php @@ -267,14 +267,14 @@ public function find_command_to_run( $args ) { $child, $parent_name, $parent_name, - ! empty( $suggestion ) ? PHP_EOL . "Did you mean '{$suggestion}'?" : '' + ! empty( $suggestion ) ? "\nDid you mean '{$suggestion}'?" : '' ); } else { $suggestion = $this->get_subcommand_suggestion( $full_name, $command ); return sprintf( "'%s' is not a registered wp command. See 'wp help'.%s", $full_name, - ! empty( $suggestion ) ? PHP_EOL . "Did you mean '{$suggestion}'?" : '' + ! empty( $suggestion ) ? "\nDid you mean '{$suggestion}'?" : '' ); } } @@ -430,7 +430,7 @@ public function is_command_disabled( $command ) { public function get_wp_config_code() { $wp_config_path = Utils\locate_wp_config(); - $wp_config_code = explode( "\n", file_get_contents( $wp_config_path ) ); + $wp_config_code = explode( "\n", Utils\normalize_newlines( file_get_contents( $wp_config_path ) ) ); $found_wp_settings = false; @@ -804,7 +804,7 @@ public function start() { $error_msg = "Alias '{$this->alias}' not found."; $suggestion = Utils\get_suggestion( $this->alias, array_keys( $this->aliases ), $threshold = 2 ); if ( $suggestion ) { - $error_msg .= PHP_EOL . "Did you mean '{$suggestion}'?"; + $error_msg .= "\nDid you mean '{$suggestion}'?"; } WP_CLI::error( $error_msg ); } diff --git a/php/boot-fs.php b/php/boot-fs.php index 7ee5da0746..f07b2b8f89 100644 --- a/php/boot-fs.php +++ b/php/boot-fs.php @@ -3,12 +3,12 @@ // This file needs to parse without error in PHP < 5.3 if ( 'cli' !== PHP_SAPI ) { - echo "Only CLI access.\n"; + echo 'Only CLI access.' . PHP_EOL; die(-1); } if ( version_compare( PHP_VERSION, '5.3.0', '<' ) ) { - printf( "Error: WP-CLI requires PHP %s or newer. You are running version %s.\n", '5.3.0', PHP_VERSION ); + printf( 'Error: WP-CLI requires PHP %s or newer. You are running version %s.' . PHP_EOL, '5.3.0', PHP_VERSION ); die(-1); } diff --git a/php/class-wp-cli.php b/php/class-wp-cli.php index 799bb3b307..91fe3dde03 100644 --- a/php/class-wp-cli.php +++ b/php/class-wp-cli.php @@ -488,9 +488,9 @@ public static function add_command( $name, $callable, $args = array() ) { $long_desc = ''; $bits = explode( ' ', $synopsis ); foreach( $args['synopsis'] as $key => $arg ) { - $long_desc .= $bits[ $key ] . PHP_EOL; + $long_desc .= $bits[ $key ] . "\n"; if ( ! empty( $arg['description'] ) ) { - $long_desc .= ': ' . $arg['description'] . PHP_EOL; + $long_desc .= ': ' . $arg['description'] . "\n"; } $yamlify = array(); foreach( array( 'default', 'options' ) as $key ) { @@ -500,13 +500,13 @@ public static function add_command( $name, $callable, $args = array() ) { } if ( ! empty( $yamlify ) ) { $long_desc .= Spyc::YAMLDump( $yamlify ); - $long_desc .= '---' . PHP_EOL; + $long_desc .= '---' . "\n"; } - $long_desc .= PHP_EOL; + $long_desc .= "\n"; } if ( ! empty( $long_desc ) ) { - $long_desc = rtrim( $long_desc, PHP_EOL ); - $long_desc = '## OPTIONS' . PHP_EOL . PHP_EOL . $long_desc; + $long_desc = rtrim( $long_desc, "\n" ); + $long_desc = '## OPTIONS' . "\n\n" . $long_desc; $leaf_command->set_longdesc( $long_desc ); } } @@ -587,7 +587,7 @@ public static function remove_deferred_addition( $name ) { * @return null */ public static function line( $message = '' ) { - echo $message . "\n"; + echo Utils\denormalize_newlines( $message . "\n" ); } /** @@ -862,7 +862,7 @@ public static function print_value( $value, $assoc_args = array() ) { $value = var_export( $value ); } - echo $value . "\n"; + echo Utils\denormalize_newlines( $value . "\n" ); } /** diff --git a/php/commands/help.php b/php/commands/help.php index c262561e98..6bdffc056e 100644 --- a/php/commands/help.php +++ b/php/commands/help.php @@ -105,6 +105,7 @@ private static function show_help( $command ) { // section headers $out = preg_replace( '/^## ([A-Z ]+)/m', WP_CLI::colorize( '%9\1%n' ), $out ); + $out = Utils\denormalize_newlines( $out ); self::pass_through_pager( $out ); } diff --git a/php/commands/src/CLI_Command.php b/php/commands/src/CLI_Command.php index 7de79f4f5b..3c24c5c902 100644 --- a/php/commands/src/CLI_Command.php +++ b/php/commands/src/CLI_Command.php @@ -310,7 +310,7 @@ public function update( $_, $assoc_args ) { $process = WP_CLI\Process::create( "{$php_binary} $temp --info {$allow_root}" ); $result = $process->run(); if ( 0 !== $result->return_code || false === stripos( $result->stdout, 'WP-CLI version:' ) ) { - $multi_line = explode( PHP_EOL, $result->stderr ); + $multi_line = explode( "\n", Utils\normalize_newlines( $result->stderr ) ); WP_CLI::error_multi_line( $multi_line ); WP_CLI::error( 'The downloaded PHAR is broken, try running wp cli update again.' ); } diff --git a/php/utils.php b/php/utils.php index 54c141b65d..05c4a8d7ac 100644 --- a/php/utils.php +++ b/php/utils.php @@ -56,7 +56,7 @@ function load_dependencies() { } if ( !$has_autoload ) { - fputs( STDERR, "Internal error: Can't find Composer autoloader.\nTry running: composer install\n" ); + fputs( STDERR, 'Internal error: Can\'t find Composer autoloader.' . PHP_EOL . 'Try running: composer install' . PHP_EOL ); exit(3); } } @@ -1023,3 +1023,28 @@ function force_env_on_nix_systems( $command ) { } return $command; } + +/** + * Normalize Windows newlines to Unix ones. + * + * @param string $str + * + * @return string + */ +function normalize_newlines( $str ) { + return str_replace( "\r\n", "\n", $str ); +} + +/** + * Denormalize Unix newlines to Windows ones if on Windows. + * + * @param string $str + * + * @return string + */ +function denormalize_newlines( $str ) { + if ( is_windows() ) { + return preg_replace( '/(?] + * + * ## EXAMPLES + * + * $ wp foo command2 --path=/**a/**b/**c/** + */ + +final + protected + static + function + command2() { + } + + /** + * Command3 function + * + * ## OPTIONS + * + * [--path=] + * + * ## EXAMPLES + * + * $ wp foo command3 --path=/**a/**b/**c/** + function*/public function command3( $function ) {} + + function command4() {} +} + +/** + * Basic class + * + * ## EXAMPLES + * + * # Foo. + * $ wp foo --final abstract + class*/abstract class + CommandFactoryTests_Get_Doc_Comment_2_Command_Win + extends WP_CLI_Command + { + function command1() {} + } diff --git a/tests/data/commandfactory-doc_comment-function-win.php b/tests/data/commandfactory-doc_comment-function-win.php new file mode 100644 index 0000000000..7fa1382e9a --- /dev/null +++ b/tests/data/commandfactory-doc_comment-function-win.php @@ -0,0 +1,19 @@ +invoke( null, $content ); $this->assertSame( $expected, $actual ); + + // Restore. + putenv( false === $is_windows ? 'WP_CLI_TEST_IS_WINDOWS' : "WP_CLI_TEST_IS_WINDOWS=$is_windows" ); + } + + /** + * @dataProvider dataProviderExtractLastDocComment + */ + function testExtractLastDocCommentWin( $content, $expected ) { + // Save and set test env var. + $is_windows = getenv( 'WP_CLI_TEST_IS_WINDOWS' ); + putenv( 'WP_CLI_TEST_IS_WINDOWS=1' ); + + static $extract_last_doc_comment = null; + if ( null === $extract_last_doc_comment ) { + $extract_last_doc_comment = new \ReflectionMethod( 'WP_CLI\Dispatcher\CommandFactory', 'extract_last_doc_comment' ); + $extract_last_doc_comment->setAccessible( true ); + } + + $actual = $extract_last_doc_comment->invoke( null, $content ); + $this->assertSame( $expected, $actual ); + + // Restore. + putenv( false === $is_windows ? 'WP_CLI_TEST_IS_WINDOWS' : "WP_CLI_TEST_IS_WINDOWS=$is_windows" ); } function dataProviderExtractLastDocComment() { @@ -29,6 +57,7 @@ function dataProviderExtractLastDocComment() { array( "/***/ */", false ), array( "/***/", "/***/" ), array( "\n /**\n \n \t\n */ \t\n \n ", "/**\n \n \t\n */" ), + array( "\r\n /**\r\n \r\n \t\r\n */ \t\r\n \r\n ", "/**\r\n \r\n \t\r\n */" ), array( "/**/ /***/ /***/", "/***/" ), array( "asdfasdf/** /** */", "/** /** */" ), array( "*//** /** */", "/** /** */" ), @@ -39,11 +68,13 @@ function dataProviderExtractLastDocComment() { array( "/** */class qwer", "/** */" ), array( "/**1*/class qwer{}/**2*/class asdf", "/**2*/" ), array( "/** */class qwer {}\nclass asdf", false ), + array( "/** */class qwer {}\r\nclass asdf", false ), array( "/** */function qwer", "/** */" ), array( "/** */function qwer( \$function ) {}", "/** */" ), array( "/**1*/function qwer() {}/**2*/function asdf()", "/**2*/" ), array( "/** */function qwer() {}\nfunction asdf()", false ), + array( "/** */function qwer() {}\r\nfunction asdf()", false ), array( "/** */function qwer() {}function asdf()", false ), array( "/** */function qwer() {};function asdf( \$function )", false ), ); @@ -51,14 +82,22 @@ function dataProviderExtractLastDocComment() { function testGetDocComment() { // Save and set test env var. - $prev_test_get_doc_comment = getenv( 'WP_CLI_TEST_GET_DOC_COMMENT' ); + $get_doc_comment = getenv( 'WP_CLI_TEST_GET_DOC_COMMENT' ); + $is_windows = getenv( 'WP_CLI_TEST_IS_WINDOWS' ); + putenv( 'WP_CLI_TEST_GET_DOC_COMMENT=1' ); + putenv( 'WP_CLI_TEST_IS_WINDOWS=0' ); // Make private function accessible. $get_doc_comment = new \ReflectionMethod( 'WP_CLI\Dispatcher\CommandFactory', 'get_doc_comment' ); $get_doc_comment->setAccessible( true ); - require __DIR__ . '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/data/commandfactory-doc_comment-class.php'; + if ( ! class_exists( 'CommandFactoryTests_Get_Doc_Comment_1_Command', false ) ) { + require __DIR__ . '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/data/commandfactory-doc_comment-class.php'; + } + if ( ! class_exists( 'CommandFactoryTests_Get_Doc_Comment_1_Command_Win', false ) ) { + require __DIR__ . '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/data/commandfactory-doc_comment-class-win.php'; + } // Class 1 @@ -101,6 +140,47 @@ function testGetDocComment() { $this->assertSame( $expected, $actual ); $this->assertFalse( $actual ); + // Class 1 Windows + + $reflection = new \ReflectionClass( 'CommandFactoryTests_Get_Doc_Comment_1_Command_Win' ); + $expected = $reflection->getDocComment(); + + $actual = $get_doc_comment->invoke( null, $reflection ); + $this->assertSame( $expected, $actual ); + + // Class method 1 + + $reflection = new \ReflectionMethod( 'CommandFactoryTests_Get_Doc_Comment_1_Command_Win', 'command1' ); + $expected = $reflection->getDocComment(); + + $actual = $get_doc_comment->invoke( null, $reflection ); + $this->assertSame( $expected, $actual ); + + // Class method 2 + + $reflection = new \ReflectionMethod( 'CommandFactoryTests_Get_Doc_Comment_1_Command_Win', 'command2' ); + $expected = $reflection->getDocComment(); + + $actual = $get_doc_comment->invoke( null, $reflection ); + $this->assertSame( $expected, $actual ); + + // Class method 3 + + $reflection = new \ReflectionMethod( 'CommandFactoryTests_Get_Doc_Comment_1_Command_Win', 'command3' ); + $expected = $reflection->getDocComment(); + + $actual = $get_doc_comment->invoke( null, $reflection ); + $this->assertSame( $expected, $actual ); + + // Class method 4 + + $reflection = new \ReflectionMethod( 'CommandFactoryTests_Get_Doc_Comment_1_Command_Win', 'command4' ); + $expected = $reflection->getDocComment(); + + $actual = $get_doc_comment->invoke( null, $reflection ); + $this->assertSame( $expected, $actual ); + $this->assertFalse( $actual ); + // Class 2 $reflection = new \ReflectionClass( 'CommandFactoryTests_Get_Doc_Comment_2_Command' ); @@ -118,6 +198,23 @@ function testGetDocComment() { $this->assertSame( $expected, $actual ); $this->assertFalse( $actual ); + // Class 2 Windows + + $reflection = new \ReflectionClass( 'CommandFactoryTests_Get_Doc_Comment_2_Command_Win' ); + $expected = $reflection->getDocComment(); + + $actual = $get_doc_comment->invoke( null, $reflection ); + $this->assertSame( $expected, $actual ); + + // Class method 1 + + $reflection = new \ReflectionMethod( 'CommandFactoryTests_Get_Doc_Comment_2_Command_Win', 'command1' ); + $expected = $reflection->getDocComment(); + + $actual = $get_doc_comment->invoke( null, $reflection ); + $this->assertSame( $expected, $actual ); + $this->assertFalse( $actual ); + // Functions require __DIR__ . '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/data/commandfactory-doc_comment-function.php'; @@ -147,8 +244,175 @@ function testGetDocComment() { $this->assertSame( $expected, $actual ); // Restore. + putenv( false === $get_doc_comment ? 'WP_CLI_TEST_GET_DOC_COMMENT' : "WP_CLI_TEST_GET_DOC_COMMENT=$get_doc_comment" ); + putenv( false === $is_windows ? 'WP_CLI_TEST_IS_WINDOWS' : "WP_CLI_TEST_IS_WINDOWS=$is_windows" ); + } + + function testGetDocCommentWin() { + // Save and set test env var. + $get_doc_comment = getenv( 'WP_CLI_TEST_GET_DOC_COMMENT' ); + $is_windows = getenv( 'WP_CLI_TEST_IS_WINDOWS' ); + + putenv( 'WP_CLI_TEST_GET_DOC_COMMENT=1' ); + putenv( 'WP_CLI_TEST_IS_WINDOWS=1' ); + + // Make private function accessible. + $get_doc_comment = new \ReflectionMethod( 'WP_CLI\Dispatcher\CommandFactory', 'get_doc_comment' ); + $get_doc_comment->setAccessible( true ); + + if ( ! class_exists( 'CommandFactoryTests_Get_Doc_Comment_1_Command', false ) ) { + require __DIR__ . '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/data/commandfactory-doc_comment-class.php'; + } + if ( ! class_exists( 'CommandFactoryTests_Get_Doc_Comment_1_Command_Win', false ) ) { + require __DIR__ . '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/data/commandfactory-doc_comment-class-win.php'; + } + + // Class 1 + + $reflection = new \ReflectionClass( 'CommandFactoryTests_Get_Doc_Comment_1_Command' ); + $expected = $reflection->getDocComment(); + + $actual = $get_doc_comment->invoke( null, $reflection ); + $this->assertSame( $expected, $actual ); + + // Class method 1 + + $reflection = new \ReflectionMethod( 'CommandFactoryTests_Get_Doc_Comment_1_Command', 'command1' ); + $expected = $reflection->getDocComment(); + + $actual = $get_doc_comment->invoke( null, $reflection ); + $this->assertSame( $expected, $actual ); + + // Class method 2 + + $reflection = new \ReflectionMethod( 'CommandFactoryTests_Get_Doc_Comment_1_Command', 'command2' ); + $expected = $reflection->getDocComment(); + + $actual = $get_doc_comment->invoke( null, $reflection ); + $this->assertSame( $expected, $actual ); + + // Class method 3 + + $reflection = new \ReflectionMethod( 'CommandFactoryTests_Get_Doc_Comment_1_Command', 'command3' ); + $expected = $reflection->getDocComment(); + + $actual = $get_doc_comment->invoke( null, $reflection ); + $this->assertSame( $expected, $actual ); + + // Class method 4 + + $reflection = new \ReflectionMethod( 'CommandFactoryTests_Get_Doc_Comment_1_Command', 'command4' ); + $expected = $reflection->getDocComment(); + + $actual = $get_doc_comment->invoke( null, $reflection ); + $this->assertSame( $expected, $actual ); + $this->assertFalse( $actual ); + + // Class 1 Windows + + $reflection = new \ReflectionClass( 'CommandFactoryTests_Get_Doc_Comment_1_Command_Win' ); + $expected = $reflection->getDocComment(); + + $actual = $get_doc_comment->invoke( null, $reflection ); + $this->assertSame( $expected, $actual ); + + // Class method 1 + + $reflection = new \ReflectionMethod( 'CommandFactoryTests_Get_Doc_Comment_1_Command_Win', 'command1' ); + $expected = $reflection->getDocComment(); + + $actual = $get_doc_comment->invoke( null, $reflection ); + $this->assertSame( $expected, $actual ); + + // Class method 2 + + $reflection = new \ReflectionMethod( 'CommandFactoryTests_Get_Doc_Comment_1_Command_Win', 'command2' ); + $expected = $reflection->getDocComment(); + + $actual = $get_doc_comment->invoke( null, $reflection ); + $this->assertSame( $expected, $actual ); + + // Class method 3 + + $reflection = new \ReflectionMethod( 'CommandFactoryTests_Get_Doc_Comment_1_Command_Win', 'command3' ); + $expected = $reflection->getDocComment(); + + $actual = $get_doc_comment->invoke( null, $reflection ); + $this->assertSame( $expected, $actual ); + + // Class method 4 + + $reflection = new \ReflectionMethod( 'CommandFactoryTests_Get_Doc_Comment_1_Command_Win', 'command4' ); + $expected = $reflection->getDocComment(); + + $actual = $get_doc_comment->invoke( null, $reflection ); + $this->assertSame( $expected, $actual ); + $this->assertFalse( $actual ); + + // Class 2 + + $reflection = new \ReflectionClass( 'CommandFactoryTests_Get_Doc_Comment_2_Command' ); + $expected = $reflection->getDocComment(); + + $actual = $get_doc_comment->invoke( null, $reflection ); + $this->assertSame( $expected, $actual ); + + // Class method 1 + + $reflection = new \ReflectionMethod( 'CommandFactoryTests_Get_Doc_Comment_2_Command', 'command1' ); + $expected = $reflection->getDocComment(); + + $actual = $get_doc_comment->invoke( null, $reflection ); + $this->assertSame( $expected, $actual ); + $this->assertFalse( $actual ); + + // Class 2 Windows + + $reflection = new \ReflectionClass( 'CommandFactoryTests_Get_Doc_Comment_2_Command_Win' ); + $expected = $reflection->getDocComment(); + + $actual = $get_doc_comment->invoke( null, $reflection ); + $this->assertSame( $expected, $actual ); + + // Class method 1 + + $reflection = new \ReflectionMethod( 'CommandFactoryTests_Get_Doc_Comment_2_Command_Win', 'command1' ); + $expected = $reflection->getDocComment(); + + $actual = $get_doc_comment->invoke( null, $reflection ); + $this->assertSame( $expected, $actual ); + $this->assertFalse( $actual ); + + // Functions + + require __DIR__ . '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/data/commandfactory-doc_comment-function-win.php'; + + // Function 1 Windows + + $reflection = new \ReflectionFunction( 'commandfactorytests_get_doc_comment_func_1_win' ); + $expected = $reflection->getDocComment(); + + $actual = $get_doc_comment->invoke( null, $reflection ); + $this->assertSame( $expected, $actual ); + + // Function 2 - putenv( false === $prev_test_get_doc_comment ? 'WP_CLI_TEST_GET_DOC_COMMENT' : "WP_CLI_TEST_GET_DOC_COMMENT=$prev_test_get_doc_comment" ); - $this->assertTrue( true ); + $reflection = new \ReflectionFunction( 'commandfactorytests_get_doc_comment_func_2_win' ); + $expected = $reflection->getDocComment(); + + $actual = $get_doc_comment->invoke( null, $reflection ); + $this->assertSame( $expected, $actual ); + + // Function 3 + + $reflection = new \ReflectionFunction( $commandfactorytests_get_doc_comment_func_3_win ); + $expected = $reflection->getDocComment(); + + $actual = $get_doc_comment->invoke( null, $reflection ); + $this->assertSame( $expected, $actual ); + + // Restore. + putenv( false === $get_doc_comment ? 'WP_CLI_TEST_GET_DOC_COMMENT' : "WP_CLI_TEST_GET_DOC_COMMENT=$get_doc_comment" ); + putenv( false === $is_windows ? 'WP_CLI_TEST_IS_WINDOWS' : "WP_CLI_TEST_IS_WINDOWS=$is_windows" ); } } diff --git a/tests/test-logging.php b/tests/test-logging.php index 98604965f2..cd366b73c5 100644 --- a/tests/test-logging.php +++ b/tests/test-logging.php @@ -11,7 +11,7 @@ protected function get_runner() { } protected function write( $handle, $str ) { - echo $str; + echo WP_CLI\Utils\denormalize_newlines( $str ); } } @@ -46,7 +46,7 @@ function testLogEscaping() { $message = 'foo%20bar'; - $this->expectOutputString( "Success: $message\n" ); + $this->expectOutputString( 'Success: ' . $message . PHP_EOL ); $logger->success( $message ); } } diff --git a/tests/test-utils.php b/tests/test-utils.php index 8ee3a589fe..20749e8edf 100644 --- a/tests/test-utils.php +++ b/tests/test-utils.php @@ -195,4 +195,39 @@ public function testGetHomeDir() { putenv( false === $homedrive ? 'HOMEDRIVE' : "HOME=$homedrive" ); putenv( false === $homepath ? 'HOMEPATH' : "HOME=$homepath" ); } + + /** + * @dataProvider dataProviderNormalizeNewlines + */ + public function testNormalizeNewlines( $in, $normalized, $out_win ) { + // Save and set test env var. + $is_windows = getenv( 'WP_CLI_TEST_IS_WINDOWS' ); + + putenv( 'WP_CLI_TEST_IS_WINDOWS=0' ); + + $actual = Utils\normalize_newlines( $in ); + $this->assertSame( $normalized, $actual ); + $actual = Utils\denormalize_newlines( $normalized ); + $this->assertSame( $normalized, $actual ); + + putenv( 'WP_CLI_TEST_IS_WINDOWS=1' ); + + $actual = Utils\normalize_newlines( $in ); + $this->assertSame( $normalized, $actual ); + $actual = Utils\denormalize_newlines( $normalized ); + $this->assertSame( $out_win, $actual ); + // Test leaves already denormalized alone. + $actual = Utils\denormalize_newlines( $out_win ); + $this->assertSame( $out_win, $actual ); + + // Restore. + putenv( false === $is_windows ? 'WP_CLI_TEST_IS_WINDOWS' : "WP_CLI_TEST_IS_WINDOWS=$is_windows" ); + } + + function dataProviderNormalizeNewlines() { + return array( + array( "blah\nblah\n\nblah\nblah\n\n", "blah\nblah\n\nblah\nblah\n\n", "blah\r\nblah\r\n\r\nblah\r\nblah\r\n\r\n" ), + array( "\r\nblah\nblah\r\n\r\nblah\nblah\r\n\n", "\nblah\nblah\n\nblah\nblah\n\n", "\r\nblah\r\nblah\r\n\r\nblah\r\nblah\r\n\r\n" ), + ); + } } diff --git a/utils/make-phar.php b/utils/make-phar.php index 43561b5cf3..6d555209b6 100644 --- a/utils/make-phar.php +++ b/utils/make-phar.php @@ -24,7 +24,7 @@ list( $args, $assoc_args, $runtime_config ) = $configurator->parse_args( array_slice( $GLOBALS['argv'], 1 ) ); if ( ! isset( $args[0] ) || empty( $args[0] ) ) { - echo "usage: php -dphar.readonly=0 $argv[0] [--quiet] [--version=same|patch|minor|major|x.y.z] [--store-version]\n"; + echo "usage: php -dphar.readonly=0 $argv[0] [--quiet] [--version=same|patch|minor|major|x.y.z] [--store-version]" . PHP_EOL; exit(1); } @@ -49,7 +49,7 @@ function add_file( $phar, $path ) { $key = str_replace( WP_CLI_BASE_PATH, '', $path ); if ( !BE_QUIET ) - echo "$key - $path\n"; + echo "$key - $path" . PHP_EOL; $phar[ $key ] = file_get_contents( $path ); } @@ -58,7 +58,7 @@ function set_file_contents( $phar, $path, $content ) { $key = str_replace( WP_CLI_BASE_PATH, '', $path ); if ( !BE_QUIET ) - echo "$key - $path\n"; + echo "$key - $path" . PHP_EOL; $phar[ $key ] = $content; } @@ -179,4 +179,4 @@ function set_file_contents( $phar, $path, $content ) { $phar->stopBuffering(); -echo "Generated " . DEST_PATH . "\n"; +echo "Generated " . DEST_PATH . PHP_EOL;