1919namespace FastForward \DevTools \Tests \Console \Command ;
2020
2121use FastForward \DevTools \Console \Command \GitIgnoreCommand ;
22- use FastForward \DevTools \GitIgnore \GitIgnore ;
2322use FastForward \DevTools \GitIgnore \GitIgnoreInterface ;
24- use FastForward \DevTools \GitIgnore \Merger ;
2523use FastForward \DevTools \GitIgnore \MergerInterface ;
26- use FastForward \DevTools \GitIgnore \Reader ;
2724use FastForward \DevTools \GitIgnore \ReaderInterface ;
28- use FastForward \DevTools \GitIgnore \Writer ;
2925use FastForward \DevTools \GitIgnore \WriterInterface ;
3026use PHPUnit \Framework \Attributes \CoversClass ;
3127use PHPUnit \Framework \Attributes \Test ;
32- use PHPUnit \Framework \Attributes \ UsesClass ;
28+ use PHPUnit \Framework \TestCase ;
3329use Prophecy \Argument ;
3430use Prophecy \PhpUnit \ProphecyTrait ;
3531use Prophecy \Prophecy \ObjectProphecy ;
32+ use ReflectionMethod ;
33+ use Symfony \Component \Config \FileLocatorInterface ;
34+ use Symfony \Component \Console \Input \InputInterface ;
35+ use Symfony \Component \Console \Output \OutputInterface ;
3636
37- /**
38- * Test suite for the GitIgnoreCommand.
39- *
40- * This test class verifies that the GitIgnoreCommand correctly merges and
41- * synchronizes .gitignore files using the Reader, Merger, and Writer components.
42- */
4337#[CoversClass(GitIgnoreCommand::class)]
44- #[UsesClass(Reader::class)]
45- #[UsesClass(GitIgnore::class)]
46- #[UsesClass(Merger::class)]
47- #[UsesClass(Writer::class)]
48- final class GitIgnoreCommandTest extends AbstractCommandTestCase
38+ final class GitIgnoreCommandTest extends TestCase
4939{
5040 use ProphecyTrait;
5141
52- /**
53- * @var ObjectProphecy<ReaderInterface>
54- */
55- private ObjectProphecy $ reader ;
56-
57- /**
58- * @var ObjectProphecy<MergerInterface>
59- */
42+ /** @var ObjectProphecy<MergerInterface> */
6043 private ObjectProphecy $ merger ;
6144
62- /**
63- * @var ObjectProphecy<WriterInterface>
64- */
45+ /** @var ObjectProphecy<ReaderInterface> */
46+ private ObjectProphecy $ reader ;
47+
48+ /** @var ObjectProphecy<WriterInterface> */
6549 private ObjectProphecy $ writer ;
6650
67- /**
68- * @var ObjectProphecy<GitIgnoreInterface>
69- */
51+ /** @var ObjectProphecy<FileLocatorInterface> */
52+ private ObjectProphecy $ fileLocator ;
53+
54+ /** @var ObjectProphecy<InputInterface> */
55+ private ObjectProphecy $ input ;
56+
57+ /** @var ObjectProphecy<OutputInterface> */
58+ private ObjectProphecy $ output ;
59+
60+ /** @var ObjectProphecy<GitIgnoreInterface> */
7061 private ObjectProphecy $ gitIgnoreSource ;
7162
72- /**
73- * @var ObjectProphecy<GitIgnoreInterface>
74- */
75- private ObjectProphecy $ gitIgnoreMerge ;
63+ /** @var ObjectProphecy<GitIgnoreInterface> */
64+ private ObjectProphecy $ gitIgnoreTarget ;
65+
66+ /** @var ObjectProphecy<GitIgnoreInterface> */
67+ private ObjectProphecy $ gitIgnoreMerged ;
7668
77- /**
78- * @var string The source .gitignore path.
79- */
80- private string $ sourcePath ;
69+ private GitIgnoreCommand $ command ;
8170
82- /**
83- * @var string The target .gitignore path.
84- */
85- private string $ targetPath ;
71+ private const string SOURCE_PATH = '/path/to/source/.gitignore ' ;
72+ private const string TARGET_PATH = '/path/to/target/.gitignore ' ;
8673
87- /**
88- * Sets up the test fixtures.
89- */
9074 protected function setUp (): void
9175 {
92- $ this ->reader = $ this ->prophesize (ReaderInterface::class);
76+ $ this ->fileLocator = $ this ->prophesize (FileLocatorInterface::class);
77+ $ this ->fileLocator ->locate (Argument::cetera ())
78+ ->willReturn ('/default/path/to/.gitignore ' );
79+
9380 $ this ->merger = $ this ->prophesize (MergerInterface::class);
81+ $ this ->reader = $ this ->prophesize (ReaderInterface::class);
9482 $ this ->writer = $ this ->prophesize (WriterInterface::class);
83+ $ this ->input = $ this ->prophesize (InputInterface::class);
84+ $ this ->output = $ this ->prophesize (OutputInterface::class);
85+
9586 $ this ->gitIgnoreSource = $ this ->prophesize (GitIgnoreInterface::class);
96- $ this ->gitIgnoreMerge = $ this ->prophesize (GitIgnoreInterface::class);
87+ $ this ->gitIgnoreTarget = $ this ->prophesize (GitIgnoreInterface::class);
88+ $ this ->gitIgnoreMerged = $ this ->prophesize (GitIgnoreInterface::class);
9789
98- $ this ->sourcePath = uniqid ('source_ ' , true ) . '/.gitignore ' ;
99- $ this ->targetPath = uniqid ('target_ ' , true ) . '/.gitignore ' ;
90+ $ this ->input ->getOption ('source ' )
91+ ->willReturn (self ::SOURCE_PATH );
92+ $ this ->input ->getOption ('target ' )
93+ ->willReturn (self ::TARGET_PATH );
10094
101- $ this ->reader ->read ($ this -> sourcePath )
95+ $ this ->reader ->read (self :: SOURCE_PATH )
10296 ->willReturn ($ this ->gitIgnoreSource ->reveal ());
103- $ this ->reader ->read ($ this -> targetPath )
104- ->willReturn ($ this ->gitIgnoreMerge ->reveal ());
97+ $ this ->reader ->read (self :: TARGET_PATH )
98+ ->willReturn ($ this ->gitIgnoreTarget ->reveal ());
10599
106- parent :: setUp ();
107- }
100+ $ this -> merger -> merge ( $ this -> gitIgnoreSource -> reveal (), $ this -> gitIgnoreTarget -> reveal ())
101+ -> willReturn ( $ this -> gitIgnoreMerged -> reveal ());
108102
109- /**
110- * Returns the command class under test.
111- */
112- protected function getCommandClass (): GitIgnoreCommand
113- {
114- return new GitIgnoreCommand (
103+ $ this ->writer ->write (Argument::any ());
104+ $ this ->output ->writeln (Argument::any ());
105+
106+ $ this ->command = new GitIgnoreCommand (
115107 $ this ->merger ->reveal (),
116108 $ this ->reader ->reveal (),
117109 $ this ->writer ->reveal (),
118- $ this ->filesystem ->reveal ()
110+ $ this ->fileLocator ->reveal (),
119111 );
120112 }
121113
122- /**
123- * Returns the expected command name.
124- */
125- protected function getCommandName (): string
114+ #[Test]
115+ public function commandWillSetExpectedNameDescriptionAndHelp (): void
126116 {
127- return 'gitignore ' ;
117+ self ::assertSame ('gitignore ' , $ this ->command ->getName ());
118+ self ::assertSame (
119+ 'Merges and synchronizes .gitignore files. ' ,
120+ $ this ->command ->getDescription ()
121+ );
122+ self ::assertSame (
123+ "This command merges the canonical .gitignore from dev-tools with the project's existing .gitignore. " ,
124+ $ this ->command ->getHelp ()
125+ );
128126 }
129127
130- /**
131- * Returns the expected command description.
132- */
133- protected function getCommandDescription (): string
128+ #[Test]
129+ public function commandWillHaveExpectedOptions (): void
134130 {
135- return 'Merges and synchronizes .gitignore files. ' ;
136- }
131+ $ definition = $ this ->command ->getDefinition ();
137132
138- /**
139- * Returns the expected command help text.
140- */
141- protected function getCommandHelp (): string
142- {
143- return "This command merges the canonical .gitignore from dev-tools with the project's existing .gitignore. " ;
133+ self ::assertTrue ($ definition ->hasOption ('source ' ));
134+ self ::assertTrue ($ definition ->hasOption ('target ' ));
144135 }
145136
146- /**
147- * Tests that execute() returns SUCCESS and correctly merges files.
148- */
149137 #[Test]
150- public function executeWillReturnSuccessAndMergeFiles (): void
138+ public function executeWillReturnSuccessWhenMergeSucceeds (): void
151139 {
152- $ this ->gitIgnoreSource ->entries ()
153- ->willReturn (['# Canonical ' , 'vendor/ ' , 'node_modules/ ' ]);
154- $ this ->gitIgnoreMerge ->entries ()
155- ->willReturn (['# Project ' , '*.log ' , 'tmp/ ' ]);
156-
157- $ this ->merger ->merge ($ this ->gitIgnoreSource ->reveal (), $ this ->gitIgnoreMerge ->reveal ())
158- ->willReturn (new GitIgnore ($ this ->targetPath , ['vendor/ ' , 'node_modules/ ' , '*.log ' , 'tmp/ ' ]));
159-
160- $ this ->writer ->write (Argument::that (
161- static fn ($ gitIgnore ): bool => $ gitIgnore instanceof GitIgnore && $ gitIgnore ->entries () === [
162- 'vendor/ ' ,
163- 'node_modules/ ' ,
164- '*.log ' ,
165- 'tmp/ ' ,
166- ]
167- ))->shouldBeCalled ();
140+ $ this ->writer ->write ($ this ->gitIgnoreMerged ->reveal ())
141+ ->shouldBeCalled ();
168142
169143 $ this ->output ->writeln ('<info>Merging .gitignore files...</info> ' )
170144 ->shouldBeCalled ();
171145 $ this ->output ->writeln ('<info>Successfully merged .gitignore file.</info> ' )
172146 ->shouldBeCalled ();
173147
174- $ this ->input ->getOption ('source ' )
175- ->willReturn ($ this ->sourcePath );
176- $ this ->input ->getOption ('target ' )
177- ->willReturn ($ this ->targetPath );
148+ $ result = $ this ->executeCommand ();
149+
150+ self ::assertSame (GitIgnoreCommand::SUCCESS , $ result );
151+ }
152+
153+ private function executeCommand (): int
154+ {
155+ $ reflectionMethod = new ReflectionMethod ($ this ->command , 'execute ' );
178156
179- self :: assertSame (GitIgnoreCommand:: SUCCESS , $ this ->invokeExecute ());
157+ return $ reflectionMethod -> invoke ( $ this -> command , $ this ->input -> reveal (), $ this -> output -> reveal ());
180158 }
181- }
159+ }
0 commit comments