Repository: composer-unused/composer-unused (php)

Issue:
ext-zip is reported as unused when using `\ZipArchive`
HI @icanhazstring, thanks for the lib ; I just found a small bug (or is it me mis-understanding something ?)

## Describe the bug
 I have a file with does
```
$zip = new \ZipArchive();
```
but `composer-unused` reports `ext-zip` as unused.


Pull request description:
fix: Add tests to cover extensions marked unused
Resolve #637, #631

Patch:
diff --git a/.docker/php8.1/Dockerfile b/.docker/php8.1/Dockerfile
index 9f097de..b8103ab 100644
--- a/.docker/php8.1/Dockerfile
+++ b/.docker/php8.1/Dockerfile
@@ -2,7 +2,7 @@ FROM php:8.1-alpine
 
 ADD https://github.com/mlocati/docker-php-extension-installer/releases/latest/download/install-php-extensions /usr/bin/
 RUN chmod +x /usr/bin/install-php-extensions
-RUN install-php-extensions ds xdebug opcache
+RUN install-php-extensions ds xdebug opcache http ds
 
 COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
 ENV COMPOSER_ALLOW_SUPERUSER 1
diff --git a/.docker/php8.2/Dockerfile b/.docker/php8.2/Dockerfile
index addba7e..a43f1ea 100644
--- a/.docker/php8.2/Dockerfile
+++ b/.docker/php8.2/Dockerfile
@@ -2,7 +2,7 @@ FROM php:8.2-alpine
 
 ADD https://github.com/mlocati/docker-php-extension-installer/releases/latest/download/install-php-extensions /usr/bin/
 RUN chmod +x /usr/bin/install-php-extensions
-RUN install-php-extensions ds xdebug opcache
+RUN install-php-extensions ds xdebug opcache http ds
 
 COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
 ENV COMPOSER_ALLOW_SUPERUSER 1
diff --git a/.docker/php8.3/Dockerfile b/.docker/php8.3/Dockerfile
index d51c14a..5d76bda 100644
--- a/.docker/php8.3/Dockerfile
+++ b/.docker/php8.3/Dockerfile
@@ -2,7 +2,7 @@ FROM php:8.3-alpine
 
 ADD https://github.com/mlocati/docker-php-extension-installer/releases/latest/download/install-php-extensions /usr/bin/
 RUN chmod +x /usr/bin/install-php-extensions
-RUN install-php-extensions ds xdebug opcache
+RUN install-php-extensions ds xdebug opcache http ds
 
 COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
 ENV COMPOSER_ALLOW_SUPERUSER 1
diff --git a/.docker/php8.4/Dockerfile b/.docker/php8.4/Dockerfile
index 032c6d6..f291766 100644
--- a/.docker/php8.4/Dockerfile
+++ b/.docker/php8.4/Dockerfile
@@ -2,7 +2,7 @@ FROM php:8.4-alpine
 
 ADD https://github.com/mlocati/docker-php-extension-installer/releases/latest/download/install-php-extensions /usr/bin/
 RUN chmod +x /usr/bin/install-php-extensions
-RUN install-php-extensions ds xdebug opcache
+RUN install-php-extensions ds xdebug opcache http ds
 
 COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
 ENV COMPOSER_ALLOW_SUPERUSER 1
diff --git a/.github/workflows/validate-code.yml b/.github/workflows/validate-code.yml
index 8a0a40a..89c0d26 100644
--- a/.github/workflows/validate-code.yml
+++ b/.github/workflows/validate-code.yml
@@ -25,7 +25,6 @@ jobs:
         with:
           php-version: ${{ matrix.php }}
           tools: composer:v2
-          extensions: ds
 
       - name: Install dependencies
         run: composer update --no-progress --prefer-dist --optimize-autoloader
@@ -50,7 +49,6 @@ jobs:
         with:
           php-version: ${{ matrix.php }}
           tools: composer:v2
-          extensions: ds
 
       - name: Install dependencies
         run: composer update --no-progress --prefer-dist --optimize-autoloader
@@ -83,11 +81,13 @@ jobs:
         uses: actions/checkout@v4
 
       - name: Setup PHP
-        uses: shivammathur/setup-php@2.30.0
+        uses: shivammathur/setup-php@2.32.0
         with:
           php-version: ${{ matrix.php }}
           tools: composer:v2
-          extensions: ds
+          extensions: http, ds, zip
+        env:
+          fail-fast: true
 
       - name: Install dependencies
         run: composer update --no-progress --prefer-dist --optimize-autoloader ${{ matrix.composer-options }}
@@ -120,7 +120,6 @@ jobs:
         with:
           php-version: ${{ matrix.php }}
           tools: composer:v2
-          extensions: ds
 
       - name: Install dependencies
         run: composer update --prefer-dist --no-progress --no-suggest ${{ matrix.composer-options }}


Test patch:
diff --git a/tests/Integration/UnusedCommandTest.php b/tests/Integration/UnusedCommandTest.php
index dc15924..a27a41a 100644
--- a/tests/Integration/UnusedCommandTest.php
+++ b/tests/Integration/UnusedCommandTest.php
@@ -581,4 +581,36 @@ TEXT,
 
         self::assertSame(1, $exitCode);
     }
+
+    /**
+     * @test
+     * @requires extension ds
+     */
+    public function itShouldNotReportExtZipAsUnused(): void
+    {
+        $commandTester = new CommandTester(self::$container->get(UnusedCommand::class));
+        $exitCode = $commandTester->execute(['composer-json' => __DIR__ . '/../assets/TestProjects/ExtZipRequirement/composer.json']);
+
+        self::assertSame(0, $exitCode);
+        self::assertStringContainsString(
+            'Found 2 used, 0 unused, 0 ignored and 0 zombie packages',
+            $commandTester->getDisplay()
+        );
+    }
+
+    /**
+     * @test
+     * @requires extension ds
+     */
+    public function itShouldNotReportExtHttpAsUnused(): void
+    {
+        $commandTester = new CommandTester(self::$container->get(UnusedCommand::class));
+        $exitCode = $commandTester->execute(['composer-json' => __DIR__ . '/../assets/TestProjects/ExtHttpRequirement/composer.json']);
+
+        self::assertSame(0, $exitCode);
+        self::assertStringContainsString(
+            'Found 2 used, 0 unused, 0 ignored and 0 zombie packages',
+            $commandTester->getDisplay()
+        );
+    }
 }
diff --git a/tests/assets/TestProjects/ExtHttpRequirement/composer.json b/tests/assets/TestProjects/ExtHttpRequirement/composer.json
new file mode 100644
index 0000000..dd6898c
--- /dev/null
+++ b/tests/assets/TestProjects/ExtHttpRequirement/composer.json
@@ -0,0 +1,12 @@
+{
+  "name": "foo/bar",
+  "require": {
+    "php": ">=8.0",
+    "ext-http": "*"
+  },
+  "autoload": {
+    "psr-4": {
+      "OnlyLanguageRequirement\\": "src/"
+    }
+  }
+}
diff --git a/tests/assets/TestProjects/ExtHttpRequirement/src/TestClass.php b/tests/assets/TestProjects/ExtHttpRequirement/src/TestClass.php
new file mode 100644
index 0000000..61dd2fc
--- /dev/null
+++ b/tests/assets/TestProjects/ExtHttpRequirement/src/TestClass.php
@@ -0,0 +1,13 @@
+<?php
+
+declare(strict_types=1);
+
+namespace ExtHttpRequirement;
+
+class TestClass
+{
+    public function testMethod(): void
+    {
+        $client = new \http\Client();
+    }
+}
diff --git a/tests/assets/TestProjects/ExtHttpRequirement/vendor/composer/installed.php b/tests/assets/TestProjects/ExtHttpRequirement/vendor/composer/installed.php
new file mode 100644
index 0000000..0c33fe1
--- /dev/null
+++ b/tests/assets/TestProjects/ExtHttpRequirement/vendor/composer/installed.php
@@ -0,0 +1,17 @@
+<?php return array(
+    'root' => array(
+        'pretty_version' => '1.0.0+no-version-set',
+        'version' => '1.0.0.0',
+        'type' => 'library',
+        'install_path' => __DIR__ . '/../../',
+        'aliases' => array(),
+        'reference' => NULL,
+        'name' => 'foo/bar',
+        'dev' => true,
+    ),
+    'versions' => array(
+        'foo/bar' => array(
+            'install_path' => __DIR__ . '/../../',
+        ),
+    ),
+);
diff --git a/tests/assets/TestProjects/ExtZipRequirement/composer.json b/tests/assets/TestProjects/ExtZipRequirement/composer.json
new file mode 100644
index 0000000..218bf1b
--- /dev/null
+++ b/tests/assets/TestProjects/ExtZipRequirement/composer.json
@@ -0,0 +1,12 @@
+{
+  "name": "foo/bar",
+  "require": {
+    "php": ">=8.0",
+    "ext-zip": "*"
+  },
+  "autoload": {
+    "psr-4": {
+      "OnlyLanguageRequirement\\": "src/"
+    }
+  }
+}
diff --git a/tests/assets/TestProjects/ExtZipRequirement/src/TestClass.php b/tests/assets/TestProjects/ExtZipRequirement/src/TestClass.php
new file mode 100644
index 0000000..5f0a36f
--- /dev/null
+++ b/tests/assets/TestProjects/ExtZipRequirement/src/TestClass.php
@@ -0,0 +1,13 @@
+<?php
+
+declare(strict_types=1);
+
+namespace ExtZipRequirement;
+
+class TestClass
+{
+    public function testMethod(): void
+    {
+        $set = new \ZipArchive();
+    }
+}
diff --git a/tests/assets/TestProjects/ExtZipRequirement/vendor/composer/installed.php b/tests/assets/TestProjects/ExtZipRequirement/vendor/composer/installed.php
new file mode 100644
index 0000000..0c33fe1
--- /dev/null
+++ b/tests/assets/TestProjects/ExtZipRequirement/vendor/composer/installed.php
@@ -0,0 +1,17 @@
+<?php return array(
+    'root' => array(
+        'pretty_version' => '1.0.0+no-version-set',
+        'version' => '1.0.0.0',
+        'type' => 'library',
+        'install_path' => __DIR__ . '/../../',
+        'aliases' => array(),
+        'reference' => NULL,
+        'name' => 'foo/bar',
+        'dev' => true,
+    ),
+    'versions' => array(
+        'foo/bar' => array(
+            'install_path' => __DIR__ . '/../../',
+        ),
+    ),
+);