1010namespace  Youwe \Composer \DependencyInstaller \Tests ;
1111
1212use  Composer \Json \JsonFile ;
13+ use  PHPUnit \Framework \Attributes \CoversClass ;
14+ use  PHPUnit \Framework \Attributes \CoversMethod ;
15+ use  PHPUnit \Framework \Attributes \DataProvider ;
16+ use  PHPUnit \Framework \MockObject \Exception ;
1317use  Seld \JsonLint \ParsingException ;
1418use  Youwe \Composer \DependencyInstaller \DependencyInstaller ;
1519use  PHPUnit \Framework \TestCase ;
1620use  Symfony \Component \Console \Output \OutputInterface ;
1721
18- /** 
19-  * @coversDefaultClass \Youwe\Composer\DependencyInstaller\DependencyInstaller 
20-  */ 
22+ #[CoversClass(DependencyInstaller::class)]
23+ #[CoversMethod(DependencyInstaller::class, '__construct ' )]
24+ #[CoversMethod(DependencyInstaller::class, 'installPackage ' )]
25+ #[CoversMethod(DependencyInstaller::class, 'installRepository ' )]
2126class  DependencyInstallerTest extends  TestCase
2227{
23-     /** @var  string */ 
24-     private  static   $ directory  =  __DIR__  .  DIRECTORY_SEPARATOR  .  ' tmp '  ;
28+     private   static  string  $ directory  =  __DIR__  .  DIRECTORY_SEPARATOR  .  ' tmp ' ; 
29+     private  DependencyInstaller   $ dependencyInstaller  ;
2530
2631    /** 
27-      * @return void  
32+      * @throws Exception  
2833     */ 
29-     public   static   function  setUpBeforeClass () 
34+     protected   function  setUp ():  void 
3035    {
31-         static ::tearDownAfterClass ();
32- 
3336        mkdir (static ::$ directory );
3437        chdir (static ::$ directory );
3538        file_put_contents ('composer.json ' , '{} ' );
39+ 
40+         $ this  ->updateComposerFileReference ();
3641    }
3742
38-     /** 
39-      * @return void 
40-      */ 
41-     public  static  function  tearDownAfterClass ()
43+     protected  function  tearDown (): void 
4244    {
4345        if  (is_dir (static ::$ directory )) {
4446            static ::rrmdir (static ::$ directory );
4547        }
4648    }
4749
48-     /** 
49-      * @param string $src 
50-      * 
51-      * @return void 
52-      */ 
53-     private  static  function  rrmdir (string  $ src )
50+     private  static  function  rrmdir (string  $ src ): void 
5451    {
5552        $ dir  = opendir ($ src );
5653        while  (false  !== ($ file  = readdir ($ dir ))) {
@@ -67,45 +64,24 @@ private static function rrmdir(string $src)
6764        rmdir ($ src );
6865    }
6966
70- 
71-     /** 
72-      * @return DependencyInstaller 
73-      * @covers ::__construct 
74-      */ 
75-     public  function  testConstructor (): DependencyInstaller 
67+     public  function  testConstructor (): void 
7668    {
77-         $ installer  = new  DependencyInstaller (
78-             'composer.json ' ,
79-             $ this  ->createMock (OutputInterface::class)
80-         );
81- 
8269        $ this  ->assertInstanceOf (
8370            DependencyInstaller::class,
84-             $ installer 
71+             $ this -> dependencyInstaller 
8572        );
86- 
87-         return  $ installer ;
8873    }
8974
9075    /** 
91-      * @depends      testConstructor 
92-      * @dataProvider repositoryProvider 
93-      * 
94-      * @param string              $name 
95-      * @param string              $type 
96-      * @param string              $url 
97-      * @param DependencyInstaller $dependencyInstaller 
98-      * 
99-      * @return void 
100-      * @covers ::installRepository 
76+      * @throws ParsingException 
10177     */ 
78+     #[DataProvider('repositoryProvider ' )]
10279    public  function  testInstallRepository (
10380        string  $ name ,
10481        string  $ type ,
10582        string  $ url ,
106-         DependencyInstaller   $ dependencyInstaller
107-     ) {
108-         $ dependencyInstaller ->installRepository ($ name , $ type , $ url );
83+     ): void  {
84+         $ this  ->dependencyInstaller ->installRepository ($ name , $ type , $ url );
10985
11086        $ jsonFile    = new  JsonFile ('composer.json ' );
11187        $ definition  = $ jsonFile ->read ();
@@ -121,35 +97,25 @@ public function testInstallRepository(
12197    /** 
12298     * @return array 
12399     */ 
124-     public  function  repositoryProvider (): array 
100+     public  static   function  repositoryProvider (): array 
125101    {
126102        return  [
127103            ['mediact ' , 'composer ' , 'https://composer.mediact.nl ' ]
128104        ];
129105    }
130106
131107    /** 
132-      * @depends      testConstructor 
133-      * @dataProvider packageProvider 
134-      * 
135-      * @param string $name 
136-      * @param string $version 
137-      * @param bool $dev 
138-      * @param bool $updateDependencies 
139-      * @param DependencyInstaller $dependencyInstaller 
140-      * 
141-      * @return void 
142108     * @throws ParsingException 
143-      * @covers ::installPackage 
144109     */ 
110+     #[DataProvider('packageProvider ' )]
145111    public  function  testInstallPackage (
146112        string  $ name ,
147113        string  $ version ,
148114        bool  $ dev ,
149115        bool  $ updateDependencies ,
150-         DependencyInstaller   $ dependencyInstaller 
116+         bool   $ allowOverrideVersion 
151117    ) {
152-         $ dependencyInstaller ->installPackage ($ name , $ version , $ dev , $ updateDependencies );
118+         $ this -> dependencyInstaller ->installPackage ($ name , $ version , $ dev , $ updateDependencies,  $ allowOverrideVersion  );
153119
154120        $ jsonFile    = new  JsonFile ('composer.json ' );
155121        $ definition  = $ jsonFile ->read ();
@@ -161,14 +127,90 @@ public function testInstallPackage(
161127        $ this  ->assertEquals ($ version , $ definition [$ node ][$ name ]);
162128    }
163129
164-     /** 
165-      * @return array 
166-      */ 
167-     public  function  packageProvider (): array 
130+     public  static  function  packageProvider (): array 
168131    {
169132        return  [
170-             ['psr/log ' , '@stable ' , true , false ],
171-             ['psr/log ' , '@stable ' , false , false ]
133+             ['psr/log ' , '@stable ' , true , false ,  true ],
134+             ['psr/log ' , '@stable ' , false , false ,  true ]
172135        ];
173136    }
137+ 
138+     /** 
139+      * @throws ParsingException 
140+      * @throws Exception 
141+      */ 
142+     public  function  testOriginalPackageVersionCanBePreserved () {
143+         $ this  ->dependencyInstaller ->installPackage (
144+             'psr/link ' ,
145+             '1.1.1 ' ,
146+             false ,
147+             false ,
148+             false 
149+         );
150+ 
151+         $ this  ->updateComposerFileReference ();
152+ 
153+         $ this  ->dependencyInstaller ->installPackage (
154+             'psr/link ' ,
155+             '^2 ' ,
156+             false ,
157+             false ,
158+             false 
159+         );
160+ 
161+         $ this  ->updateComposerFileReference ();
162+ 
163+         $ jsonFile    = new  JsonFile ('composer.json ' );
164+         $ definition  = $ jsonFile ->read ();
165+ 
166+         // Assert the pre-existing composer versions was NOT wiped by a dependency installer package installation 
167+         $ this  ->assertArrayHasKey ('require ' , $ definition );
168+         $ this  ->assertArrayHasKey ('psr/link ' , $ definition ['require ' ]);
169+         $ this  ->assertEquals ('1.1.1 ' , $ definition ['require ' ]['psr/link ' ]);
170+     }
171+ 
172+     /** 
173+      * @throws ParsingException|Exception 
174+      */ 
175+     public  function  testOriginalPackageVersionCanBeOverridden (): void  {
176+         // Install and validate base package availability 
177+         $ this  ->dependencyInstaller ->installPackage (
178+             'psr/link ' ,
179+             '1.1.1 ' ,
180+             false 
181+         );
182+ 
183+         $ this  ->updateComposerFileReference ();
184+ 
185+         $ this  ->dependencyInstaller ->installPackage (
186+             'psr/link ' ,
187+             '@stable ' ,
188+             false 
189+         );
190+ 
191+         $ jsonFile    = new  JsonFile ('composer.json ' );
192+         $ definition  = $ jsonFile ->read ();
193+ 
194+         $ this  ->assertArrayHasKey ('require ' , $ definition );
195+         $ this  ->assertArrayHasKey ('psr/link ' , $ definition ['require ' ]);
196+         $ this  ->assertEquals ('@stable ' , $ definition ['require ' ]['psr/link ' ]);
197+     }
198+ 
199+     /** 
200+      * Update the composer file reference since it is loaded only once as part of the constructor. 
201+      * 
202+      * We refresh the composer file reference whenever the composer file is changed, otherwise the dependency 
203+      * installer will always hold a reference to the previous state of the composer file and not contain any 
204+      * changes if multiple installations happen in the same testing function. 
205+      * 
206+      * @return void 
207+      * @throws Exception 
208+      */ 
209+     private  function  updateComposerFileReference (): void 
210+     {
211+         $ this  ->dependencyInstaller  = new  DependencyInstaller (
212+             'composer.json ' ,
213+             $ this  ->createMock (OutputInterface::class)
214+         );
215+     }
174216}
0 commit comments