Browse Source

Refactor logoService to the laravel manager+driver pattern

Bubka 2 months ago
parent
commit
bff3bd7182

+ 4 - 4
app/Api/v1/Controllers/IconController.php

@@ -4,10 +4,10 @@ namespace App\Api\v1\Controllers;
 
 
 use App\Api\v1\Requests\IconFetchRequest;
 use App\Api\v1\Requests\IconFetchRequest;
 use App\Facades\IconStore;
 use App\Facades\IconStore;
+use App\Facades\LogoLib;
 use App\Helpers\Helpers;
 use App\Helpers\Helpers;
 use App\Http\Controllers\Controller;
 use App\Http\Controllers\Controller;
 use App\Models\TwoFAccount;
 use App\Models\TwoFAccount;
-use App\Services\LogoService;
 use Exception;
 use Exception;
 use Illuminate\Http\Request;
 use Illuminate\Http\Request;
 use Illuminate\Http\UploadedFile;
 use Illuminate\Http\UploadedFile;
@@ -48,12 +48,12 @@ class IconController extends Controller
      *
      *
      * @return \Illuminate\Http\JsonResponse
      * @return \Illuminate\Http\JsonResponse
      */
      */
-    public function fetch(IconFetchRequest $request, LogoService $logoService)
+    public function fetch(IconFetchRequest $request)
     {
     {
         $validated = $request->validated();
         $validated = $request->validated();
 
 
-        $icon = $logoService->getIcon($validated['service']);
-
+        $icon = LogoLib::driver('tfa')->getIcon($validated['service']);
+        
         return $icon
         return $icon
             ? response()->json(['filename' => $icon], 201)
             ? response()->json(['filename' => $icon], 201)
             : response()->json(null, 204);
             : response()->json(null, 204);

+ 16 - 0
app/Facades/LogoLib.php

@@ -0,0 +1,16 @@
+<?php
+
+namespace App\Facades;
+
+use Illuminate\Support\Facades\Facade;
+
+/**
+ * 
+ */
+class LogoLib extends Facade
+{
+    protected static function getFacadeAccessor()
+    {
+        return 'logolib';
+    }
+}

+ 6 - 6
app/Providers/TwoFAuthServiceProvider.php

@@ -5,7 +5,7 @@ namespace App\Providers;
 use App\Factories\MigratorFactoryInterface;
 use App\Factories\MigratorFactoryInterface;
 use App\Services\IconService;
 use App\Services\IconService;
 use App\Services\IconStoreService;
 use App\Services\IconStoreService;
-use App\Services\LogoService;
+use App\Services\LogoLib\LogoLibManager;
 use App\Services\ReleaseRadarService;
 use App\Services\ReleaseRadarService;
 use App\Services\SettingService;
 use App\Services\SettingService;
 use App\Services\TwoFAccountService;
 use App\Services\TwoFAccountService;
@@ -35,10 +35,6 @@ class TwoFAuthServiceProvider extends ServiceProvider implements DeferrableProvi
             return new IconStoreService($app->make(Sanitizer::class));
             return new IconStoreService($app->make(Sanitizer::class));
         });
         });
 
 
-        $this->app->singleton(LogoService::class, function ($app) {
-            return new LogoService;
-        });
-
         $this->app->singleton(IconService::class, function ($app) {
         $this->app->singleton(IconService::class, function ($app) {
             return new IconService;
             return new IconService;
         });
         });
@@ -47,6 +43,10 @@ class TwoFAuthServiceProvider extends ServiceProvider implements DeferrableProvi
             return new ReleaseRadarService;
             return new ReleaseRadarService;
         });
         });
 
 
+        $this->app->singleton('logolib', function ($app) {
+            return new LogoLibManager($app);
+        });
+
         $this->app->bind(QrReader::class, function ($app, array $parameters) {
         $this->app->bind(QrReader::class, function ($app, array $parameters) {
             return new QrReader($parameters['imgSource'], $parameters['sourceType']);
             return new QrReader($parameters['imgSource'], $parameters['sourceType']);
         });
         });
@@ -74,7 +74,7 @@ class TwoFAuthServiceProvider extends ServiceProvider implements DeferrableProvi
         return [
         return [
             IconService::class,
             IconService::class,
             IconStoreService::class,
             IconStoreService::class,
-            LogoService::class,
+            LogoLibManager::class,
             QrReader::class,
             QrReader::class,
             ReleaseRadarService::class,
             ReleaseRadarService::class,
         ];
         ];

+ 2 - 2
app/Services/IconService.php

@@ -3,8 +3,8 @@
 namespace App\Services;
 namespace App\Services;
 
 
 use App\Facades\IconStore;
 use App\Facades\IconStore;
+use App\Facades\LogoLib;
 use App\Helpers\Helpers;
 use App\Helpers\Helpers;
-use Illuminate\Support\Facades\App;
 use Illuminate\Support\Facades\Http;
 use Illuminate\Support\Facades\Http;
 use Illuminate\Support\Facades\Log;
 use Illuminate\Support\Facades\Log;
 use Illuminate\Support\Facades\Storage;
 use Illuminate\Support\Facades\Storage;
@@ -18,7 +18,7 @@ class IconService
      */
      */
     public function buildFromOfficialLogo(?string $service) : ?string
     public function buildFromOfficialLogo(?string $service) : ?string
     {
     {
-        return App::make(LogoService::class)->getIcon($service);
+        return LogoLib::driver('tfa')->getIcon($service);
     }
     }
 
 
     /**
     /**

+ 56 - 0
app/Services/LogoLib/AbstractLogoLib.php

@@ -0,0 +1,56 @@
+<?php
+
+namespace App\Services\LogoLib;
+
+use App\Facades\IconStore;
+use App\Services\LogoLib\LogoLibInterface;
+use Illuminate\Support\Facades\Http;
+use Illuminate\Support\Facades\Log;
+use Illuminate\Support\Facades\Storage;
+
+abstract class AbstractLogoLib implements LogoLibInterface
+{
+    /**
+     * Url to use in http request to get a specific logo from the logo lib
+     */
+    abstract protected function logoUrl(string $logoFilename) : string;
+
+    /**
+     * Prepare service name to match logo libs naming convention
+     */
+    abstract protected function sanitizeServiceName(string $service) : string;
+
+    /**
+     * Fetch and cache a logo from the logo library
+     *
+     * @param  string  $logoFilename  Logo filename to fetch
+     */
+    protected function fetchLogo(string $logoFilename) : void
+    {
+        try {
+            $response = Http::withOptions([
+                'proxy' => config('2fauth.config.outgoingProxy'),
+            ])->retry(3, 100)->get($this->logoUrl($logoFilename));
+
+            if ($response->successful()) {
+                Storage::disk('logos')->put($logoFilename, $response->body())
+                    ? Log::info(sprintf('Logo "%s" saved to logos dir.', $logoFilename))
+                    : Log::notice(sprintf('Cannot save logo "%s" to logos dir', $logoFilename));
+            }
+        } catch (\Exception $exception) {
+            Log::error(sprintf('Fetching of logo "%s" failed.', $logoFilename));
+        }
+    }
+
+    /**
+     * Copy a logo file to the icons store with a new name
+     */
+    protected function copyToIconStore(string $logoFilename, string $iconFilename) : bool
+    {
+        if ($content = Storage::disk('logos')->get($logoFilename)) {
+            return IconStore::store($iconFilename, $content);
+        }
+
+        return false;
+    }
+}

+ 8 - 0
app/Services/LogoLib/LogoLibInterface.php

@@ -0,0 +1,8 @@
+<?php
+
+namespace App\Services\LogoLib;
+
+interface LogoLibInterface
+{
+    public function getIcon(?string $serviceName): string|null;
+}

+ 24 - 0
app/Services/LogoLib/LogoLibManager.php

@@ -0,0 +1,24 @@
+<?php
+
+namespace App\Services\LogoLib;
+
+use App\Services\LogoLib\TfaLogoLib;
+use Illuminate\Support\Manager;
+
+class LogoLibManager extends Manager
+{
+    public function getDefaultDriver()
+    {
+        return 'tfa';
+    }
+
+    public function createTfaDriver() : TfaLogoLib
+    {
+        return new TfaLogoLib();
+    }
+
+    // public function createSelfhDriver()
+    // {
+    //     return new SelfhLogoLib();
+    // }
+}

+ 16 - 44
app/Services/LogoService.php → app/Services/LogoLib/TfaLogoLib.php

@@ -1,14 +1,15 @@
 <?php
 <?php
 
 
-namespace App\Services;
+namespace App\Services\LogoLib;
 
 
-use App\Facades\IconStore;
+use App\Services\LogoLib\AbstractLogoLib;
+use App\Services\LogoLib\LogoLibInterface;
 use Illuminate\Support\Collection;
 use Illuminate\Support\Collection;
 use Illuminate\Support\Facades\Http;
 use Illuminate\Support\Facades\Http;
 use Illuminate\Support\Facades\Log;
 use Illuminate\Support\Facades\Log;
 use Illuminate\Support\Facades\Storage;
 use Illuminate\Support\Facades\Storage;
 
 
-class LogoService
+class TfaLogoLib extends AbstractLogoLib implements LogoLibInterface
 {
 {
     /**
     /**
      * @var \Illuminate\Support\Collection<string, string>
      * @var \Illuminate\Support\Collection<string, string>
@@ -28,8 +29,11 @@ class LogoService
     /**
     /**
      * @var string
      * @var string
      */
      */
-    const TFA_IMG_URL = 'https://raw.githubusercontent.com/2factorauth/twofactorauth/master/img/';
+    const IMG_URL = 'https://raw.githubusercontent.com/2factorauth/twofactorauth/master/img/';
 
 
+    /**
+     * 
+     */
     public function __construct()
     public function __construct()
     {
     {
         $this->setTfaCollection();
         $this->setTfaCollection();
@@ -41,7 +45,7 @@ class LogoService
      * @param  string|null  $serviceName  Name of the service to fetch a logo for
      * @param  string|null  $serviceName  Name of the service to fetch a logo for
      * @return string|null The icon filename or null if no logo has been found
      * @return string|null The icon filename or null if no logo has been found
      */
      */
-    public function getIcon(?string $serviceName)
+    public function getIcon(?string $serviceName) : string|null
     {
     {
         $logoFilename = $this->getLogo(strval($serviceName));
         $logoFilename = $this->getLogo(strval($serviceName));
 
 
@@ -63,7 +67,7 @@ class LogoService
      */
      */
     protected function getLogo(string $serviceName)
     protected function getLogo(string $serviceName)
     {
     {
-        $domain       = $this->tfas->get($this->cleanDomain(strval($serviceName)));
+        $domain       = $this->tfas->get($this->sanitizeServiceName(strval($serviceName)));
         $logoFilename = $domain . '.svg';
         $logoFilename = $domain . '.svg';
 
 
         if ($domain && ! Storage::disk('logos')->exists($logoFilename)) {
         if ($domain && ! Storage::disk('logos')->exists($logoFilename)) {
@@ -118,50 +122,18 @@ class LogoService
     }
     }
 
 
     /**
     /**
-     * Fetch and cache a logo from 2fa.Directory repository
-     *
-     * @param  string  $logoFile  Logo filename to fetch
-     */
-    protected function fetchLogo(string $logoFile) : void
-    {
-        try {
-            $response = Http::withOptions([
-                'proxy' => config('2fauth.config.outgoingProxy'),
-            ])->retry(3, 100)->get(self::TFA_IMG_URL . $logoFile[0] . '/' . $logoFile);
-
-            if ($response->successful()) {
-                Storage::disk('logos')->put($logoFile, $response->body())
-                    ? Log::info(sprintf('Logo "%s" saved to logos dir.', $logoFile))
-                    : Log::notice(sprintf('Cannot save logo "%s" to logos dir', $logoFile));
-            }
-        } catch (\Exception $exception) {
-            Log::error(sprintf('Fetching of logo "%s" failed.', $logoFile));
-        }
-    }
-
-    /**
-     * Prepare and make some replacement to optimize logo fetching
-     *
-     * @return string Optimized domain name
+     * Url to use in http request to get a specific logo from the logo lib
      */
      */
-    protected function cleanDomain(string $domain) : string
+    protected function logoUrl(string $logoFilename) : string
     {
     {
-        return strtolower(str_replace(['+'], ['plus'], $domain));
+        return self::IMG_URL . $logoFilename[0] . '/' . $logoFilename;
     }
     }
 
 
     /**
     /**
-     * Copy a logo file to the icons store with a new name
-     *
-     * @param  string  $logoFilename
-     * @param  string  $iconFilename
-     * @return bool Whether the copy succeed or not
+     * Prepare service name to match logo libs naming convention
      */
      */
-    protected function copyToIconStore($logoFilename, $iconFilename) : bool
+    protected function sanitizeServiceName(string $service) : string
     {
     {
-        if ($content = Storage::disk('logos')->get($logoFilename)) {
-            return IconStore::store($iconFilename, $content);
-        }
-
-        return false;
+        return strtolower(str_replace(['+'], ['plus'], $service));
     }
     }
 }
 }

+ 3 - 3
tests/Api/v1/Controllers/IconControllerTest.php

@@ -6,7 +6,7 @@ use App\Api\v1\Controllers\IconController;
 use App\Facades\IconStore;
 use App\Facades\IconStore;
 use App\Models\TwoFAccount;
 use App\Models\TwoFAccount;
 use App\Models\User;
 use App\Models\User;
-use App\Services\LogoService;
+use App\Services\LogoLib\TfaLogoLib;
 use Illuminate\Http\Testing\FileFactory;
 use Illuminate\Http\Testing\FileFactory;
 use Illuminate\Http\UploadedFile;
 use Illuminate\Http\UploadedFile;
 use Illuminate\Support\Facades\Http;
 use Illuminate\Support\Facades\Http;
@@ -38,8 +38,8 @@ class IconControllerTest extends FeatureTestCase
 
 
         Http::preventStrayRequests();
         Http::preventStrayRequests();
         Http::fake([
         Http::fake([
-            LogoService::TFA_IMG_URL . '*' => Http::response(HttpRequestTestData::SVG_LOGO_BODY, 200),
-            LogoService::TFA_URL           => Http::response(HttpRequestTestData::TFA_JSON_BODY, 200),
+            TfaLogoLib::IMG_URL . '*' => Http::response(HttpRequestTestData::SVG_LOGO_BODY, 200),
+            TfalogoLib::TFA_URL           => Http::response(HttpRequestTestData::TFA_JSON_BODY, 200),
         ]);
         ]);
         Http::fake([
         Http::fake([
             OtpTestData::EXTERNAL_IMAGE_URL_DECODED => Http::response((new FileFactory)->image('file.png', 10, 10)->tempFile, 200),
             OtpTestData::EXTERNAL_IMAGE_URL_DECODED => Http::response((new FileFactory)->image('file.png', 10, 10)->tempFile, 200),

+ 3 - 3
tests/Api/v1/Controllers/TwoFAccountControllerTest.php

@@ -16,7 +16,7 @@ use App\Models\User;
 use App\Policies\TwoFAccountPolicy;
 use App\Policies\TwoFAccountPolicy;
 use App\Providers\MigrationServiceProvider;
 use App\Providers\MigrationServiceProvider;
 use App\Providers\TwoFAuthServiceProvider;
 use App\Providers\TwoFAuthServiceProvider;
-use App\Services\LogoService;
+use App\Services\LogoLib\TfaLogoLib;
 use Illuminate\Http\Testing\FileFactory;
 use Illuminate\Http\Testing\FileFactory;
 use Illuminate\Support\Facades\DB;
 use Illuminate\Support\Facades\DB;
 use Illuminate\Support\Facades\Http;
 use Illuminate\Support\Facades\Http;
@@ -242,8 +242,8 @@ class TwoFAccountControllerTest extends FeatureTestCase
 
 
         Http::preventStrayRequests();
         Http::preventStrayRequests();
         Http::fake([
         Http::fake([
-            LogoService::TFA_IMG_URL . '*'                   => Http::response(HttpRequestTestData::SVG_LOGO_BODY, 200),
-            LogoService::TFA_URL                             => Http::response(HttpRequestTestData::TFA_JSON_BODY, 200),
+            TfaLogoLib::IMG_URL . '*'                   => Http::response(HttpRequestTestData::SVG_LOGO_BODY, 200),
+            TfaLogoLib::TFA_URL                             => Http::response(HttpRequestTestData::TFA_JSON_BODY, 200),
             OtpTestData::EXTERNAL_IMAGE_URL_DECODED          => Http::response((new FileFactory)->image('file.png', 10, 10)->tempFile, 200),
             OtpTestData::EXTERNAL_IMAGE_URL_DECODED          => Http::response((new FileFactory)->image('file.png', 10, 10)->tempFile, 200),
             OtpTestData::EXTERNAL_INFECTED_IMAGE_URL_DECODED => Http::response((new FileFactory)->createWithContent('infected.svg', OtpTestData::ICON_SVG_DATA_INFECTED)->tempFile, 200),
             OtpTestData::EXTERNAL_INFECTED_IMAGE_URL_DECODED => Http::response((new FileFactory)->createWithContent('infected.svg', OtpTestData::ICON_SVG_DATA_INFECTED)->tempFile, 200),
             'example.com/*'                                  => Http::response(null, 400),
             'example.com/*'                                  => Http::response(null, 400),

+ 3 - 3
tests/Feature/Models/TwoFAccountModelTest.php

@@ -5,7 +5,7 @@ namespace Tests\Feature\Models;
 use App\Facades\Icons;
 use App\Facades\Icons;
 use App\Models\TwoFAccount;
 use App\Models\TwoFAccount;
 use App\Models\User;
 use App\Models\User;
-use App\Services\LogoService;
+use App\Services\LogoLib\TfaLogoLib;
 use Illuminate\Http\Testing\FileFactory;
 use Illuminate\Http\Testing\FileFactory;
 use Illuminate\Support\Facades\Http;
 use Illuminate\Support\Facades\Http;
 use Illuminate\Support\Facades\Storage;
 use Illuminate\Support\Facades\Storage;
@@ -269,8 +269,8 @@ class TwoFAccountModelTest extends FeatureTestCase
         $this->user['preferences->getOfficialIcons'] = false;
         $this->user['preferences->getOfficialIcons'] = false;
         $this->user->save();
         $this->user->save();
 
 
-        $this->mock(LogoService::class, function (MockInterface $logoService) {
-            $logoService->shouldNotReceive('getIcon');
+        $this->mock(TfaLogoLib::class, function (MockInterface $logoLib) {
+            $logoLib->shouldNotReceive('getIcon');
         });
         });
 
 
         $twofaccount = new TwoFAccount;
         $twofaccount = new TwoFAccount;

+ 10 - 7
tests/Feature/Services/IconServiceTest.php

@@ -2,8 +2,9 @@
 
 
 namespace Tests\Feature\Services;
 namespace Tests\Feature\Services;
 
 
+use App\Facades\LogoLib;
 use App\Services\IconService;
 use App\Services\IconService;
-use App\Services\LogoService;
+use App\Services\LogoLib\TfaLogoLib;
 use Illuminate\Foundation\Testing\WithoutMiddleware;
 use Illuminate\Foundation\Testing\WithoutMiddleware;
 use Illuminate\Http\Testing\FileFactory;
 use Illuminate\Http\Testing\FileFactory;
 use Illuminate\Support\Facades\Http;
 use Illuminate\Support\Facades\Http;
@@ -38,8 +39,8 @@ class IconServiceTest extends FeatureTestCase
 
 
         Http::preventStrayRequests();
         Http::preventStrayRequests();
         Http::fake([
         Http::fake([
-            LogoService::TFA_IMG_URL . '*' => Http::response(HttpRequestTestData::SVG_LOGO_BODY, 200),
-            LogoService::TFA_URL           => Http::response(HttpRequestTestData::TFA_JSON_BODY, 200),
+            TfaLogoLib::IMG_URL . '*' => Http::response(HttpRequestTestData::SVG_LOGO_BODY, 200),
+            TfaLogoLib::TFA_URL           => Http::response(HttpRequestTestData::TFA_JSON_BODY, 200),
         ]);
         ]);
         Http::fake([
         Http::fake([
             OtpTestData::EXTERNAL_IMAGE_URL_DECODED => Http::response((new FileFactory)->image('file.png', 10, 10)->tempFile, 200),
             OtpTestData::EXTERNAL_IMAGE_URL_DECODED => Http::response((new FileFactory)->image('file.png', 10, 10)->tempFile, 200),
@@ -47,14 +48,16 @@ class IconServiceTest extends FeatureTestCase
     }
     }
 
 
     #[Test]
     #[Test]
-    public function test_buildFromOfficialLogo_calls_logoservice_to_get_the_icon()
+    public function test_buildFromOfficialLogo_calls_logoLib_to_get_the_icon()
     {
     {
-        $logoServiceSpy = $this->spy(LogoService::class);
+        // LogoLib::spy();
+        LogoLib::shouldReceive('driver->getIcon')
+            ->once()
+            ->with('fakeService')
+            ->andReturn('value');
 
 
         $this->iconService = $this->app->make(IconService::class);
         $this->iconService = $this->app->make(IconService::class);
         $this->iconService->buildFromOfficialLogo('fakeService');
         $this->iconService->buildFromOfficialLogo('fakeService');
-
-        $logoServiceSpy->shouldHaveReceived('getIcon')->once()->with('fakeService');
     }
     }
 
 
     #[Test]
     #[Test]

+ 109 - 0
tests/Feature/Services/LogoLib/TfaLogoLibTest.php

@@ -0,0 +1,109 @@
+<?php
+
+namespace Tests\Feature\Services;
+
+use App\Services\LogoLib\TfaLogoLib;
+use Illuminate\Foundation\Testing\WithoutMiddleware;
+use Illuminate\Support\Facades\Http;
+use Illuminate\Support\Facades\Storage;
+use PHPUnit\Framework\Attributes\CoversClass;
+use PHPUnit\Framework\Attributes\Test;
+use Tests\Data\HttpRequestTestData;
+use Tests\FeatureTestCase;
+
+/**
+ * TfalogoLibTest test class
+ */
+#[CoversClass(TfalogoLib::class)]
+class TfaLogoLibTest extends FeatureTestCase
+{
+    use WithoutMiddleware;
+
+    protected TfaLogoLib $tfaLogoLib;
+
+    public function setUp() : void
+    {
+        parent::setUp();
+
+        Storage::fake('icons');
+        Storage::fake('logos');
+        Storage::fake('imagesLink');
+    }
+
+    #[Test]
+    public function test_getIcon_returns_stored_icon_file_when_logo_exists()
+    {
+        Http::preventStrayRequests();
+        Http::fake([
+            TfalogoLib::IMG_URL . '*' => Http::response(HttpRequestTestData::SVG_LOGO_BODY, 200),
+            TfalogoLib::TFA_URL           => Http::response(HttpRequestTestData::TFA_JSON_BODY, 200),
+        ]);
+
+        $this->tfaLogoLib = $this->app->make(TfalogoLib::class);
+        $icon              = $this->tfaLogoLib->getIcon('service');
+
+        $this->assertNotNull($icon);
+        Storage::disk('icons')->assertExists($icon);
+    }
+
+    #[Test]
+    public function test_getIcon_returns_null_when_github_request_fails()
+    {
+        Http::preventStrayRequests();
+        Http::fake([
+            TfalogoLib::IMG_URL . '*' => Http::response(HttpRequestTestData::SVG_LOGO_BODY, 200),
+            TfalogoLib::TFA_URL           => Http::response('not found', 404),
+        ]);
+
+        $this->tfaLogoLib = $this->app->make(TfalogoLib::class);
+        $icon              = $this->tfaLogoLib->getIcon('service');
+
+        $this->assertEquals(null, $icon);
+    }
+
+    #[Test]
+    public function test_getIcon_returns_null_when_logo_fetching_fails()
+    {
+        Http::preventStrayRequests();
+        Http::fake([
+            TfalogoLib::IMG_URL . '*' => Http::response('not found', 404),
+            TfalogoLib::TFA_URL           => Http::response(HttpRequestTestData::TFA_JSON_BODY, 200),
+        ]);
+
+        $this->tfaLogoLib = $this->app->make(TfalogoLib::class);
+        $icon              = $this->tfaLogoLib->getIcon('service');
+
+        $this->assertEquals(null, $icon);
+    }
+
+    #[Test]
+    public function test_getIcon_returns_null_when_no_logo_exists()
+    {
+        Http::preventStrayRequests();
+        Http::fake([
+            TfalogoLib::IMG_URL . '*' => Http::response(HttpRequestTestData::SVG_LOGO_BODY, 200),
+            TfalogoLib::TFA_URL           => Http::response(HttpRequestTestData::TFA_JSON_BODY, 200),
+        ]);
+
+        $this->tfaLogoLib = $this->app->make(TfalogoLib::class);
+        $icon              = $this->tfaLogoLib->getIcon('no_logo_should_exists_with_this_name');
+
+        $this->assertEquals(null, $icon);
+    }
+
+    #[Test]
+    public function test_TfalogoLib_loads_empty_collection_when_tfajson_fetching_fails()
+    {
+        Http::preventStrayRequests();
+        Http::fake([
+            TfalogoLib::IMG_URL . '*' => Http::response(HttpRequestTestData::SVG_LOGO_BODY, 200),
+            TfalogoLib::TFA_URL           => Http::response('not found', 404),
+        ]);
+
+        $this->tfaLogoLib = $this->app->make(TfalogoLib::class);
+        $icon              = $this->tfaLogoLib->getIcon('service');
+
+        $this->assertNull($icon);
+        Storage::disk('logos')->assertMissing(TfalogoLib::TFA_JSON);
+    }
+}

+ 0 - 109
tests/Feature/Services/LogoServiceTest.php

@@ -1,109 +0,0 @@
-<?php
-
-namespace Tests\Feature\Services;
-
-use App\Services\LogoService;
-use Illuminate\Foundation\Testing\WithoutMiddleware;
-use Illuminate\Support\Facades\Http;
-use Illuminate\Support\Facades\Storage;
-use PHPUnit\Framework\Attributes\CoversClass;
-use PHPUnit\Framework\Attributes\Test;
-use Tests\Data\HttpRequestTestData;
-use Tests\FeatureTestCase;
-
-/**
- * LogoServiceTest test class
- */
-#[CoversClass(LogoService::class)]
-class LogoServiceTest extends FeatureTestCase
-{
-    use WithoutMiddleware;
-
-    protected LogoService $logoService;
-
-    public function setUp() : void
-    {
-        parent::setUp();
-
-        Storage::fake('icons');
-        Storage::fake('logos');
-        Storage::fake('imagesLink');
-    }
-
-    #[Test]
-    public function test_getIcon_returns_stored_icon_file_when_logo_exists()
-    {
-        Http::preventStrayRequests();
-        Http::fake([
-            LogoService::TFA_IMG_URL . '*' => Http::response(HttpRequestTestData::SVG_LOGO_BODY, 200),
-            LogoService::TFA_URL           => Http::response(HttpRequestTestData::TFA_JSON_BODY, 200),
-        ]);
-
-        $this->logoService = $this->app->make(LogoService::class);
-        $icon              = $this->logoService->getIcon('service');
-
-        $this->assertNotNull($icon);
-        Storage::disk('icons')->assertExists($icon);
-    }
-
-    #[Test]
-    public function test_getIcon_returns_null_when_github_request_fails()
-    {
-        Http::preventStrayRequests();
-        Http::fake([
-            LogoService::TFA_IMG_URL . '*' => Http::response(HttpRequestTestData::SVG_LOGO_BODY, 200),
-            LogoService::TFA_URL           => Http::response('not found', 404),
-        ]);
-
-        $this->logoService = $this->app->make(LogoService::class);
-        $icon              = $this->logoService->getIcon('service');
-
-        $this->assertEquals(null, $icon);
-    }
-
-    #[Test]
-    public function test_getIcon_returns_null_when_logo_fetching_fails()
-    {
-        Http::preventStrayRequests();
-        Http::fake([
-            LogoService::TFA_IMG_URL . '*' => Http::response('not found', 404),
-            LogoService::TFA_URL           => Http::response(HttpRequestTestData::TFA_JSON_BODY, 200),
-        ]);
-
-        $this->logoService = $this->app->make(LogoService::class);
-        $icon              = $this->logoService->getIcon('service');
-
-        $this->assertEquals(null, $icon);
-    }
-
-    #[Test]
-    public function test_getIcon_returns_null_when_no_logo_exists()
-    {
-        Http::preventStrayRequests();
-        Http::fake([
-            LogoService::TFA_IMG_URL . '*' => Http::response(HttpRequestTestData::SVG_LOGO_BODY, 200),
-            LogoService::TFA_URL           => Http::response(HttpRequestTestData::TFA_JSON_BODY, 200),
-        ]);
-
-        $this->logoService = $this->app->make(LogoService::class);
-        $icon              = $this->logoService->getIcon('no_logo_should_exists_with_this_name');
-
-        $this->assertEquals(null, $icon);
-    }
-
-    #[Test]
-    public function test_logoService_loads_empty_collection_when_tfajson_fetching_fails()
-    {
-        Http::preventStrayRequests();
-        Http::fake([
-            LogoService::TFA_IMG_URL . '*' => Http::response(HttpRequestTestData::SVG_LOGO_BODY, 200),
-            LogoService::TFA_URL           => Http::response('not found', 404),
-        ]);
-
-        $this->logoService = $this->app->make(LogoService::class);
-        $icon              = $this->logoService->getIcon('service');
-
-        $this->assertNull($icon);
-        Storage::disk('logos')->assertMissing(LogoService::TFA_JSON);
-    }
-}