Completed
Push — fix/parent-selector-for-premiu... ( cac9af...425486 )
by Jeremy
20:54 queued 09:58
created

ApplicationTest::testDoRun_noComposerJson()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 21

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
nc 2
nop 0
dl 0
loc 21
rs 9.584
c 0
b 0
f 0
1
<?php // phpcs:ignore WordPress.Files.FileName.InvalidClassFileName
2
/**
3
 * Tests for the changelogger Application class.
4
 *
5
 * @package automattic/jetpack-changelogger
6
 */
7
8
// phpcs:disable WordPress.WP.AlternativeFunctions, WordPress.PHP.DiscouragedPHPFunctions.runtime_configuration_putenv
9
10
namespace Automattic\Jetpack\Changelogger\Tests;
11
12
use Automattic\Jetpack\Changelogger\Application;
13
use Automattic\Jetpack\Changelogger\Config;
14
use Automattic\Jetpack\Changelogger\ConfigException;
15
use RuntimeException;
16
use Symfony\Component\Console\Command\Command;
17
use Symfony\Component\Console\Tester\ApplicationTester;
18
use Wikimedia\TestingAccessWrapper;
19
20
/**
21
 * Tests for the changelogger Application class.
22
 *
23
 * @covers \Automattic\Jetpack\Changelogger\Application
24
 */
25
class ApplicationTest extends TestCase {
26
	use \Yoast\PHPUnitPolyfills\Polyfills\AssertionRenames;
27
	use \Yoast\PHPUnitPolyfills\Polyfills\AssertIsType;
28
29
	/**
30
	 * Set up.
31
	 *
32
	 * @before
33
	 */
34
	public function set_up() {
35
		$this->useTempDir();
36
		file_put_contents( 'composer.json', "{}\n" );
37
	}
38
39
	/**
40
	 * Test the application.
41
	 */
42
	public function testBasics() {
43
		$app = new Application();
44
45
		$this->assertSame( 'Jetpack Changelogger', $app->getName() );
46
		$this->assertSame( Application::VERSION, $app->getVersion() );
47
48
		$app->setAutoExit( false );
49
		$tester = new ApplicationTester( $app );
50
		$tester->run( array( 'command' => 'list' ) );
51
		$output = $tester->getDisplay();
52
		$this->assertMatchesRegularExpression( '/Available commands:/', $output );
53
		$this->assertMatchesRegularExpression( '/add\s*Adds a change file/', $output );
54
	}
55
56
	/**
57
	 * Run the application.
58
	 *
59
	 * @param callable $callback Command callback.
60
	 * @param array    $options Options:
61
	 *     - catch-exceptions: (bool) Whether the application should catch exceptions. Default false.
62
	 *     - inputs: (array) Value to pass to $tester->setInputs().
63
	 * @return ApplicationTester
64
	 */
65
	private function runApplication( $callback, array $options = array( 'interactive' => false ) ) {
66
		$app = new Application();
67
		$app->setAutoExit( false );
68
		$app->setCatchExceptions( false );
69
70
		if ( isset( $options['catch-exceptions'] ) ) {
71
			$app->setCatchExceptions( $options['catch-exceptions'] );
72
			unset( $options['catch-exceptions'] );
73
		}
74
75
		$command = new Command( 'testDoRun' );
76
		$command->setCode( $callback );
77
		$app->add( $command );
78
79
		$tester = new ApplicationTester( $app );
80
81
		$options['interactive'] = isset( $options['inputs'] );
82
		if ( $options['interactive'] ) {
83
			if ( ! is_callable( array( $tester, 'setInputs' ) ) ) {
84
				$this->markTestSkipped( 'This test requires a newer version of symfony/console' );
85
			}
86
			$tester->setInputs( $options['inputs'] );
87
			unset( $options['inputs'] );
88
		}
89
90
		$options[] = 'decorated';
91
		$tester->run( array( 'command' => 'testDoRun' ), $options );
92
		return $tester;
93
	}
94
95
	/**
96
	 * Basic test of doRun().
97
	 */
98
	public function testDoRun() {
99
		$tester = $this->runApplication(
100
			function ( $input, $output ) {
101
				$this->assertSame(
102
					getcwd() . DIRECTORY_SEPARATOR . 'composer.json',
103
					TestingAccessWrapper::newFromClass( Config::class )->composerJsonPath
104
				);
105
				$this->assertTrue( $output->getFormatter()->hasStyle( 'warning' ) );
106
				return 42;
107
			}
108
		);
109
		$this->assertSame( 42, $tester->getStatusCode() );
110
		$this->assertSame( '', $tester->getDisplay() );
111
	}
112
113
	/**
114
	 * Test doRun(), command threw ConfigException.
115
	 */
116 View Code Duplication
	public function testDoRun_ConfigException() {
117
		$tester = $this->runApplication(
118
			function () {
119
				throw new ConfigException( 'Test config exception' );
120
			}
121
		);
122
		$this->assertSame( -1, $tester->getStatusCode() );
123
		$this->assertSame( "Test config exception\n", $tester->getDisplay() );
124
	}
125
126
	/**
127
	 * Test doRun(), command threw RuntimeException.
128
	 */
129 View Code Duplication
	public function testDoRun_RuntimeException() {
130
		$tester = $this->runApplication(
131
			function () {
132
				throw new RuntimeException( 'Test runtime exception' );
133
			},
134
			array( 'catch-exceptions' => true )
135
		);
136
		$this->assertSame( 1, $tester->getStatusCode() );
137
		$this->assertMatchesRegularExpression( '/In ApplicationTest.php line \d+:\n *\n  Test runtime exception *\n/', $tester->getDisplay() );
138
	}
139
140
	/**
141
	 * Test of doRun() with COMPOSER set
142
	 */
143
	public function testDoRun_env() {
144
		putenv( 'COMPOSER=composer.json' );
145
		$tester = $this->runApplication(
146
			function () {
147
				$this->assertNull( TestingAccessWrapper::newFromClass( Config::class )->composerJsonPath );
148
				return 42;
149
			}
150
		);
151
		$this->assertSame( 42, $tester->getStatusCode() );
152
		$this->assertSame( '', $tester->getDisplay() );
153
	}
154
155
	/**
156
	 * Test of doRun() with no composer.json
157
	 */
158
	public function testDoRun_noComposerJson() {
159
		unlink( 'composer.json' );
160
161
		// Sanity check.
162
		$dir = getcwd();
163
		do {
164
			if ( file_exists( "$dir/composer.json" ) ) {
165
				$this->fail( 'Precondition failed: This test requires that no composer.json exist above the temporary directory ' . getcwd() . ", but $dir/composer.json exists." );
166
			}
167
			$prev = $dir;
168
			$dir  = dirname( $dir );
169
		} while ( $prev !== $dir );
170
171
		$tester = $this->runApplication(
172
			function () {
173
				$this->fail( 'Command should not be called' );
174
			}
175
		);
176
		$this->assertSame( -1, $tester->getStatusCode() );
177
		$this->assertSame( 'File composer.json is not found in ' . getcwd() . ".\nRun changelogger from the appropriate directory, or set the environment variable COMPOSER to point to composer.json.\n", $tester->getDisplay() );
178
	}
179
180
	/**
181
	 * Test doRun() in a subdirectory, non-interactive.
182
	 */
183
	public function testDoRun_subdir_noninteractive() {
184
		$cwd = getcwd();
185
		mkdir( 'foo' );
186
		mkdir( 'foo/bar' );
187
		chdir( 'foo/bar' );
188
189
		$tester = $this->runApplication(
190
			function () {
191
				$this->fail( 'Command should not be called' );
192
			}
193
		);
194
		$this->assertSame( -1, $tester->getStatusCode() );
195
		$this->assertSame( "File composer.json is not found in $cwd/foo/bar.\nRun changelogger from the appropriate directory, or set the environment variable COMPOSER to point to composer.json.\n", $tester->getDisplay() );
196
	}
197
198
	/**
199
	 * Test doRun() in a subdirectory, interactive, answer N.
200
	 */
201
	public function testDoRun_subdir_interactive_N() {
202
		$cwd = getcwd();
203
		mkdir( 'foo' );
204
		mkdir( 'foo/bar' );
205
		chdir( 'foo/bar' );
206
207
		$tester = $this->runApplication(
208
			function () {
209
				$this->fail( 'Command should not be called' );
210
			},
211
			array( 'inputs' => array( 'N' ) )
212
		);
213
		$this->assertSame( -1, $tester->getStatusCode() );
214
		$this->assertSame( "No composer.json in current directory, do you want to use the one at $cwd/composer.json? [Y/n] ", $tester->getDisplay() );
215
	}
216
217
	/**
218
	 * Test doRun() in a subdirectory, interactive, answer Y.
219
	 */
220
	public function testDoRun_subdir_interactive_Y() {
221
		$cwd = getcwd();
222
		mkdir( 'foo' );
223
		mkdir( 'foo/bar' );
224
		chdir( 'foo/bar' );
225
226
		$tester = $this->runApplication(
227
			function () use ( $cwd ) {
228
				$this->assertSame(
229
					$cwd . DIRECTORY_SEPARATOR . 'composer.json',
230
					TestingAccessWrapper::newFromClass( Config::class )->composerJsonPath
231
				);
232
				return 42;
233
			},
234
			array( 'inputs' => array( 'Y' ) )
235
		);
236
		$this->assertSame( 42, $tester->getStatusCode() );
237
		$this->assertSame( "No composer.json in current directory, do you want to use the one at $cwd/composer.json? [Y/n] ", $tester->getDisplay() );
238
	}
239
240
}
241