Completed
Push — fix/changelogger-in-subdir ( cf1128 )
by
unknown
44:01 queued 34:14
created

ApplicationTest::testDoRun_subdir_interactive_N()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 0
dl 0
loc 15
rs 9.7666
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
			$tester->setInputs( $options['inputs'] );
84
			unset( $options['inputs'] );
85
		}
86
87
		$options[] = 'decorated';
88
		$tester->run( array( 'command' => 'testDoRun' ), $options );
89
		return $tester;
90
	}
91
92
	/**
93
	 * Basic test of doRun().
94
	 */
95
	public function testDoRun() {
96
		$tester = $this->runApplication(
97
			function ( $input, $output ) {
98
				$this->assertSame(
99
					getcwd() . DIRECTORY_SEPARATOR . 'composer.json',
100
					TestingAccessWrapper::newFromClass( Config::class )->composerJsonPath
101
				);
102
				$this->assertTrue( $output->getFormatter()->hasStyle( 'warning' ) );
103
				return 42;
104
			}
105
		);
106
		$this->assertSame( 42, $tester->getStatusCode() );
107
		$this->assertSame( '', $tester->getDisplay() );
108
	}
109
110
	/**
111
	 * Test doRun(), command threw ConfigException.
112
	 */
113 View Code Duplication
	public function testDoRun_ConfigException() {
114
		$tester = $this->runApplication(
115
			function () {
116
				throw new ConfigException( 'Test config exception' );
117
			}
118
		);
119
		$this->assertSame( -1, $tester->getStatusCode() );
120
		$this->assertSame( "Test config exception\n", $tester->getDisplay() );
121
	}
122
123
	/**
124
	 * Test doRun(), command threw RuntimeException.
125
	 */
126 View Code Duplication
	public function testDoRun_RuntimeException() {
127
		$tester = $this->runApplication(
128
			function () {
129
				throw new RuntimeException( 'Test runtime exception' );
130
			},
131
			array( 'catch-exceptions' => true )
132
		);
133
		$this->assertSame( 1, $tester->getStatusCode() );
134
		$this->assertMatchesRegularExpression( '/In ApplicationTest.php line \d+:\n *\n  Test runtime exception *\n/', $tester->getDisplay() );
135
	}
136
137
	/**
138
	 * Test of doRun() with COMPOSER set
139
	 */
140
	public function testDoRun_env() {
141
		putenv( 'COMPOSER=composer.json' );
142
		$tester = $this->runApplication(
143
			function () {
144
				$this->assertNull( TestingAccessWrapper::newFromClass( Config::class )->composerJsonPath );
145
				return 42;
146
			}
147
		);
148
		$this->assertSame( 42, $tester->getStatusCode() );
149
		$this->assertSame( '', $tester->getDisplay() );
150
	}
151
152
	/**
153
	 * Test of doRun() with no composer.json
154
	 */
155
	public function testDoRun_noComposerJson() {
156
		unlink( 'composer.json' );
157
158
		// Sanity check.
159
		$dir = getcwd();
160
		do {
161
			if ( file_exists( "$dir/composer.json" ) ) {
162
				$this->fail( 'Precondition failed: This test requires that no composer.json exist above the temporary directory ' . getcwd() . ", but $dir/composer.json exists." );
163
			}
164
			$prev = $dir;
165
			$dir  = dirname( $dir );
166
		} while ( $prev !== $dir );
167
168
		$tester = $this->runApplication(
169
			function () {
170
				$this->fail( 'Command should not be called' );
171
			}
172
		);
173
		$this->assertSame( -1, $tester->getStatusCode() );
174
		$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() );
175
	}
176
177
	/**
178
	 * Test doRun() in a subdirectory, non-interactive.
179
	 */
180
	public function testDoRun_subdir_noninteractive() {
181
		$cwd = getcwd();
182
		mkdir( 'foo' );
183
		mkdir( 'foo/bar' );
184
		chdir( 'foo/bar' );
185
186
		$tester = $this->runApplication(
187
			function () {
188
				$this->fail( 'Command should not be called' );
189
			}
190
		);
191
		$this->assertSame( -1, $tester->getStatusCode() );
192
		$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() );
193
	}
194
195
	/**
196
	 * Test doRun() in a subdirectory, interactive, answer N.
197
	 */
198
	public function testDoRun_subdir_interactive_N() {
199
		$cwd = getcwd();
200
		mkdir( 'foo' );
201
		mkdir( 'foo/bar' );
202
		chdir( 'foo/bar' );
203
204
		$tester = $this->runApplication(
205
			function () {
206
				$this->fail( 'Command should not be called' );
207
			},
208
			array( 'inputs' => array( 'N' ) )
209
		);
210
		$this->assertSame( -1, $tester->getStatusCode() );
211
		$this->assertSame( "No composer.json in current directory, do you want to use the one at $cwd/composer.json? [Y/n] ", $tester->getDisplay() );
212
	}
213
214
	/**
215
	 * Test doRun() in a subdirectory, interactive, answer Y.
216
	 */
217
	public function testDoRun_subdir_interactive_Y() {
218
		$cwd = getcwd();
219
		mkdir( 'foo' );
220
		mkdir( 'foo/bar' );
221
		chdir( 'foo/bar' );
222
223
		$tester = $this->runApplication(
224
			function () use ( $cwd ) {
225
				$this->assertSame(
226
					$cwd . DIRECTORY_SEPARATOR . 'composer.json',
227
					TestingAccessWrapper::newFromClass( Config::class )->composerJsonPath
228
				);
229
				return 42;
230
			},
231
			array( 'inputs' => array( 'Y' ) )
232
		);
233
		$this->assertSame( 42, $tester->getStatusCode() );
234
		$this->assertSame( "No composer.json in current directory, do you want to use the one at $cwd/composer.json? [Y/n] ", $tester->getDisplay() );
235
	}
236
237
}
238