1919
2020namespace FastForward \DevTools \Tests \Console \Command ;
2121
22+ use FastForward \DevTools \Composer \Json \ComposerJsonInterface ;
2223use FastForward \DevTools \Console \Command \UpdateComposerJsonCommand ;
2324use FastForward \DevTools \Filesystem \FilesystemInterface ;
2425use PHPUnit \Framework \Attributes \CoversClass ;
3233use Symfony \Component \Console \Input \InputInterface ;
3334use Symfony \Component \Console \Output \OutputInterface ;
3435
36+ use function Safe \json_decode ;
37+
3538#[CoversClass(UpdateComposerJsonCommand::class)]
3639final class UpdateComposerJsonCommandTest extends TestCase
3740{
3841 use ProphecyTrait;
3942
4043 private ObjectProphecy $ filesystem ;
4144
45+ private ObjectProphecy $ composer ;
46+
4247 private ObjectProphecy $ fileLocator ;
4348
4449 private ObjectProphecy $ input ;
@@ -52,12 +57,17 @@ final class UpdateComposerJsonCommandTest extends TestCase
5257 */
5358 protected function setUp (): void
5459 {
60+ $ this ->composer = $ this ->prophesize (ComposerJsonInterface::class);
5561 $ this ->filesystem = $ this ->prophesize (FilesystemInterface::class);
5662 $ this ->fileLocator = $ this ->prophesize (FileLocatorInterface::class);
5763 $ this ->input = $ this ->prophesize (InputInterface::class);
5864 $ this ->output = $ this ->prophesize (OutputInterface::class);
5965
60- $ this ->command = new UpdateComposerJsonCommand ($ this ->filesystem ->reveal (), $ this ->fileLocator ->reveal ());
66+ $ this ->command = new UpdateComposerJsonCommand (
67+ $ this ->composer ->reveal (),
68+ $ this ->filesystem ->reveal (),
69+ $ this ->fileLocator ->reveal (),
70+ );
6171 }
6272
6373 /**
@@ -89,6 +99,10 @@ public function executeWillUpdateComposerJsonScriptsAndExtraConfiguration(): voi
8999 ->willReturn (true );
90100 $ this ->filesystem ->readFile ('/app/composer.json ' )
91101 ->willReturn ('{"name":"example/package"} ' );
102+ $ this ->composer ->getReadme ()
103+ ->willReturn ('' );
104+ $ this ->filesystem ->exists ('README.md ' , '/app ' )
105+ ->willReturn (false );
92106 $ this ->fileLocator ->locate ('grumphp.yml ' , Argument::type ('string ' ))
93107 ->willReturn ('/app/vendor/fast-forward/dev-tools/grumphp.yml ' );
94108 $ this ->filesystem ->dumpFile (
@@ -100,6 +114,96 @@ public function executeWillUpdateComposerJsonScriptsAndExtraConfiguration(): voi
100114 self ::assertSame (UpdateComposerJsonCommand::SUCCESS , $ this ->executeCommand ());
101115 }
102116
117+ /**
118+ * @return void
119+ */
120+ #[Test]
121+ public function executeWillAddReadmeMetadataWhenReadmeExistsAndComposerJsonDoesNotDeclareReadme (): void
122+ {
123+ $ this ->input ->getOption ('file ' )
124+ ->willReturn ('/app/composer.json ' );
125+ $ this ->filesystem ->exists ('/app/composer.json ' )
126+ ->willReturn (true );
127+ $ this ->filesystem ->readFile ('/app/composer.json ' )
128+ ->willReturn ('{"name":"example/package"} ' );
129+ $ this ->composer ->getReadme ()
130+ ->willReturn ('' );
131+ $ this ->filesystem ->exists ('README.md ' , '/app ' )
132+ ->willReturn (true );
133+ $ this ->fileLocator ->locate ('grumphp.yml ' , Argument::type ('string ' ))
134+ ->willReturn ('/app/vendor/fast-forward/dev-tools/grumphp.yml ' );
135+ $ this ->filesystem ->dumpFile (
136+ '/app/composer.json ' ,
137+ Argument::that (static function (string $ contents ): bool {
138+ $ composerJson = json_decode ($ contents , true );
139+
140+ return 'README.md ' === $ composerJson ['readme ' ];
141+ }),
142+ )->shouldBeCalledOnce ();
143+
144+ self ::assertSame (UpdateComposerJsonCommand::SUCCESS , $ this ->executeCommand ());
145+ }
146+
147+ /**
148+ * @return void
149+ */
150+ #[Test]
151+ public function executeWillPreserveExistingReadmeMetadata (): void
152+ {
153+ $ this ->input ->getOption ('file ' )
154+ ->willReturn ('/app/composer.json ' );
155+ $ this ->filesystem ->exists ('/app/composer.json ' )
156+ ->willReturn (true );
157+ $ this ->filesystem ->readFile ('/app/composer.json ' )
158+ ->willReturn ('{"name":"example/package","readme":"docs/readme.md"} ' );
159+ $ this ->composer ->getReadme ()
160+ ->willReturn ('docs/readme.md ' );
161+ $ this ->filesystem ->exists ('README.md ' , '/app ' )
162+ ->shouldNotBeCalled ();
163+ $ this ->fileLocator ->locate ('grumphp.yml ' , Argument::type ('string ' ))
164+ ->willReturn ('/app/vendor/fast-forward/dev-tools/grumphp.yml ' );
165+ $ this ->filesystem ->dumpFile (
166+ '/app/composer.json ' ,
167+ Argument::that (static function (string $ contents ): bool {
168+ $ composerJson = json_decode ($ contents , true );
169+
170+ return 'docs/readme.md ' === $ composerJson ['readme ' ];
171+ }),
172+ )->shouldBeCalledOnce ();
173+
174+ self ::assertSame (UpdateComposerJsonCommand::SUCCESS , $ this ->executeCommand ());
175+ }
176+
177+ /**
178+ * @return void
179+ */
180+ #[Test]
181+ public function executeWillSkipReadmeMetadataWhenReadmeDoesNotExist (): void
182+ {
183+ $ this ->input ->getOption ('file ' )
184+ ->willReturn ('/app/composer.json ' );
185+ $ this ->filesystem ->exists ('/app/composer.json ' )
186+ ->willReturn (true );
187+ $ this ->filesystem ->readFile ('/app/composer.json ' )
188+ ->willReturn ('{"name":"example/package"} ' );
189+ $ this ->composer ->getReadme ()
190+ ->willReturn ('' );
191+ $ this ->filesystem ->exists ('README.md ' , '/app ' )
192+ ->willReturn (false );
193+ $ this ->fileLocator ->locate ('grumphp.yml ' , Argument::type ('string ' ))
194+ ->willReturn ('/app/vendor/fast-forward/dev-tools/grumphp.yml ' );
195+ $ this ->filesystem ->dumpFile (
196+ '/app/composer.json ' ,
197+ Argument::that (static function (string $ contents ): bool {
198+ $ composerJson = json_decode ($ contents , true );
199+
200+ return ! \array_key_exists ('readme ' , $ composerJson );
201+ }),
202+ )->shouldBeCalledOnce ();
203+
204+ self ::assertSame (UpdateComposerJsonCommand::SUCCESS , $ this ->executeCommand ());
205+ }
206+
103207 /**
104208 * @return int
105209 */
0 commit comments