Skip to content

Commit

Permalink
Implemented mock checking
Browse files Browse the repository at this point in the history
  • Loading branch information
andrey-helldar committed Jun 26, 2024
1 parent d778961 commit bf46b12
Show file tree
Hide file tree
Showing 14 changed files with 153 additions and 84 deletions.
1 change: 1 addition & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
"deeplcom/deepl-php": "^1.7",
"guzzlehttp/guzzle": "^7.8",
"illuminate/support": "^10.0 || ^11.0",
"laravel-lang/config": "^1.0@dev",
"laravel-lang/locale-list": "^1.4",
"stichoza/google-translate-php": "^5.1"
},
Expand Down
9 changes: 9 additions & 0 deletions phpunit.xml
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,14 @@

<env name="SESSION_DRIVER" value="array" />
<env name="CACHE_STORE" value="array" />

<env name="TRANSLATION_GOOGLE_ENABLED" value="true" />

<env name="TRANSLATION_DEEPL_ENABLED" value="true" />
<env name="TRANSLATION_DEEPL_KEY" value="foo" />

<env name="TRANSLATION_YANDEX_ENABLED" value="true" />
<env name="TRANSLATION_YANDEX_KEY" value="foo" />
<env name="TRANSLATION_FOLDER_ID" value="123" />
</php>
</phpunit>
6 changes: 5 additions & 1 deletion src/Contracts/Translator.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,9 @@ interface Translator
{
public function can(Locale|string $to): bool;

public function translate(array|string $text, Locale|string $to, Locale|string|null $from = null): array|string;
public function translate(
iterable|string $text,
Locale|string|null $to,
Locale|string|null $from = null
): array|string;
}
4 changes: 3 additions & 1 deletion src/Integrations/Deepl.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@

class Deepl extends Integration
{
public static string $integration = DeeplTranslator::class;

protected array $map = [
Locale::French->value => 'fr',
];
Expand All @@ -20,6 +22,6 @@ public function __construct(

protected function request(iterable|string $text, Locale|string $to, Locale|string|null $from): Collection
{
return collect($this->translator->translateText($text, $this->lang($from), $this->lang($to)));
return collect($this->translator->translateText($text, $this->locale($from), $this->locale($to)));
}
}
8 changes: 5 additions & 3 deletions src/Integrations/Google.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,15 @@

class Google extends Integration
{
public static string $integration = GoogleTranslate::class;

protected array $map = [
Locale::French->value => 'fr',
];

public function __construct(
protected GoogleTranslate $translator,
protected string|true $regex = true
protected string|bool $regex = true
) {}

protected function request(iterable|string $text, Locale|string $to, Locale|string|null $from): Collection
Expand All @@ -30,7 +32,7 @@ protected function translator(Locale|string $to, Locale|string|null $from): Goog
{
return $this->translator
->preserveParameters($this->regex)
->setSource($this->lang($from))
->setTarget($this->lang($to));
->setSource($this->locale($from))
->setTarget($this->locale($to));
}
}
31 changes: 21 additions & 10 deletions src/Integrations/Integration.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@

abstract class Integration implements Translator
{
public static string $integration;

protected array $map = [];

abstract protected function request(
Expand All @@ -20,35 +22,44 @@ abstract protected function request(

public function can(Locale|string $to): bool
{
return $this->lang($to) !== null;
return $this->locale($to) !== null;
}

public function translate(
array|string $text,
Locale|string $to,
iterable|string $text,
Locale|string|null $to,
Locale|string|null $from = null
): array|string {
return is_array($text)
if ($this->invalidLocale($to)) {
return is_string($text) ? $text : collect($text)->all();
}

return is_iterable($text)
? $this->request($text, $to, $from)->all()
: $this->request($text, $to, $from)->first();
}

protected function lang(Locale|string|null $lang): ?string
protected function locale(Locale|string|null $locale): ?string
{
$lang = $lang?->value ?? $lang;
$locale = $locale?->value ?? $locale;

if (empty($lang)) {
if (empty($locale)) {
return null;
}

if ($value = $this->map[$lang] ?? false) {
if ($value = $this->map[$locale] ?? false) {
return $value;
}

if (in_array($lang, $this->map, true)) {
return $lang;
if (in_array($locale, $this->map, true)) {
return $locale;
}

return null;
}

protected function invalidLocale(Locale|string|null $locale): bool
{
return ! $this->locale($locale);
}
}
4 changes: 3 additions & 1 deletion src/Integrations/Yandex.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@

class Yandex extends Integration
{
public static string $integration = YandexCloud::class;

protected array $map = [
Locale::French->value => 'fr',
];
Expand All @@ -20,6 +22,6 @@ public function __construct(

protected function request(iterable|string $text, Locale|string $to, Locale|string|null $from): Collection
{
return collect($this->translator->translate($text, $this->lang($to), $this->lang($from)));
return collect($this->translator->translate($text, $this->locale($to), $this->locale($from)));
}
}
45 changes: 19 additions & 26 deletions src/ServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,39 +4,32 @@

namespace LaravelLang\Translator;

use DeepL\Translator;
use Illuminate\Foundation\Application;
use Illuminate\Support\ServiceProvider as BaseServiceProvider;
use LaravelLang\Translator\Integrations\Deepl;
use LaravelLang\Translator\Integrations\Google;
use LaravelLang\Translator\Integrations\Yandex;
use LaravelLang\Translator\Requests\YandexCloud;
use Stichoza\GoogleTranslate\GoogleTranslate;
use LaravelLang\Config\Data\Shared\TranslatorData;
use LaravelLang\Config\Facades\Config;
use LaravelLang\Translator\Contracts\Translator;

class ServiceProvider extends BaseServiceProvider
{
public function boot(): void
{
$this->app->singleton(Deepl::class, function (Application $app) {
return new Deepl(
translator: new Translator($app['config']->get('services.deepl.key')),
);
});
foreach ($this->translators() as $config) {
$this->bootTranslator($config->translator, $config->credentials);
}
}

$this->app->singleton(Google::class, function (Application $app) {
return new Google(
translator: new GoogleTranslate(),
regex : $app['config']->get('services.google_translate.regex_parameters') ?: true,
);
});
protected function bootTranslator(Translator|string $translator, array $credentials): void
{
$this->app->singleton($translator, fn () => new $translator(
new $translator::$integration(...$credentials)
));
}

$this->app->singleton(Yandex::class, function (Application $app) {
return new Yandex(
new YandexCloud(
key : $app['config']->get('services.yandex_translate.key'),
folderId: $app['config']->get('services.yandex_translate.folder_id'),
)
);
});
/**
* @return array<TranslatorData>
*/
protected function translators(): array
{
return Config::shared()->translators->enabled;
}
}
11 changes: 8 additions & 3 deletions src/Services/Translate.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

namespace LaravelLang\Translator\Services;

use LaravelLang\Config\Data\Shared\TranslatorData;
use LaravelLang\Config\Facades\Config;
use LaravelLang\LocaleList\Locale;
use LaravelLang\Translator\Contracts\Translator;
use LaravelLang\Translator\Integrations\Deepl;
Expand All @@ -14,8 +16,8 @@ class Translate
{
public function text(iterable|string $text, Locale|string $to, Locale|string|null $from = null): array|string
{
foreach ($this->translators() as $class) {
if ($translated = $this->translate($class, $text, $to, $from)) {
foreach ($this->translators() as $service) {
if ($translated = $this->translate($service->translator, $text, $to, $from)) {
return $translated;
}
}
Expand Down Expand Up @@ -65,9 +67,12 @@ protected function translate(
return null;
}

/**
* @return array<TranslatorData>
*/
protected function translators(): array
{
return config('localization.translators');
return Config::shared()->translators->enabled;
}

protected function initialize(string $class): Translator
Expand Down
6 changes: 3 additions & 3 deletions tests/Datasets/Translators.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
use LaravelLang\Translator\Integrations\Yandex;

dataset('translators', fn () => [
Deepl::class => [Deepl::class],
Google::class => [Google::class],
Yandex::class => [Yandex::class],
class_basename(Deepl::class) => [Deepl::class],
class_basename(Google::class) => [Google::class],
class_basename(Yandex::class) => [Yandex::class],
]);
72 changes: 42 additions & 30 deletions tests/Helpers/Mocks.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,45 +2,57 @@

declare(strict_types=1);

use DeepL\Translator as DeeplTranslator;
use DeepL\Translator as DeeplTranslate;
use Illuminate\Support\Arr;
use LaravelLang\Translator\Integrations\Deepl;
use LaravelLang\Translator\Integrations\Google;
use LaravelLang\Translator\Integrations\Yandex;
use LaravelLang\Translator\Requests\YandexCloud;
use LaravelLang\Translator\Requests\YandexCloud as YandexTranslate;
use Stichoza\GoogleTranslate\GoogleTranslate;
use Tests\Constants\Value;

function mockTranslator(string $translator, string $integration, array $methods = []): void
function mockTranslators(array|string $text = null): void
{
$service = mock($integration);
mockDeeplTranslator($text);
mockGoogleTranslator($text);
mockYandexTranslator($text);
}

foreach ($methods as $key => $value) {
is_string($key)
? $service->shouldReceive($key)->andReturn($value)
: $service->shouldReceive($value)->andReturnSelf();
}
function mockDeeplTranslator(array|string|null $text = null): void
{
$mock = mock(DeeplTranslate::class);

app()->forgetInstance($translator);
app()->singleton($translator, fn () => new $translator($service));
$mock->shouldReceive('translateText')->andReturn($text ?? Value::Text1French);

mockTranslator(Deepl::class, $mock);
}

function mockTranslators(
array|string|null $deepl = null,
array|string|null $google = null,
array|string|null $yandex = null,
): void {
mockTranslator(Deepl::class, DeeplTranslator::class, [
'translateText' => $deepl ?? Value::Text1French,
]);

mockTranslator(Google::class, GoogleTranslate::class, [
'translate' => $google ?? Value::Text1French,
'preserveParameters',
'setSource',
'setTarget',
]);

mockTranslator(Yandex::class, YandexCloud::class, [
'translate' => $yandex ?? [Value::Text1French],
]);
function mockGoogleTranslator(array|string|null $text = null): void
{
$mock = mock(GoogleTranslate::class);

$mock->shouldReceive('preserveParameters', 'setSource', 'setTarget')->andReturnSelf();

is_array($text)
? $mock->shouldReceive('translate')->andReturn(...$text)
: $mock->shouldReceive('translate')->andReturn($text ?? Value::Text1French);

mockTranslator(Google::class, $mock);
}

function mockYandexTranslator(array|string|null $text = null): void
{
$mock = mock(YandexTranslate::class);

$mock->shouldReceive('translate')->andReturn(
Arr::wrap($text ?? [Value::Text1French])
);

mockTranslator(Yandex::class, $mock);
}

function mockTranslator(string $translator, mixed $mock): void
{
app()->forgetInstance($translator);
app()->singleton($translator, fn () => new $translator($mock));
}
23 changes: 18 additions & 5 deletions tests/TestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,36 @@
namespace Tests;

use Illuminate\Config\Repository;
use LaravelLang\Translator\ServiceProvider;
use LaravelLang\Config\Enums\Name;
use LaravelLang\Config\ServiceProvider as ConfigServiceProvider;
use LaravelLang\Translator\Integrations\Deepl;
use LaravelLang\Translator\Integrations\Google;
use LaravelLang\Translator\Integrations\Yandex;
use LaravelLang\Translator\ServiceProvider as TranslatorServiceProvider;
use Orchestra\Testbench\TestCase as BaseTestCase;

abstract class TestCase extends BaseTestCase
{
protected function getPackageProviders($app): array
{
return [ServiceProvider::class];
return [
TranslatorServiceProvider::class,
ConfigServiceProvider::class,
];
}

protected function defineEnvironment($app): void
{
tap($app['config'], function (Repository $config) {
$config->set('services.deepl.key', 'foo');
$config->set(Name::Shared() . '.translators.google.translator', Google::class);
$config->set(Name::Shared() . '.translators.google.credentials.key', 'foo');

$config->set('services.yandex_translate.key', 'foo');
$config->set('services.yandex_translate.folder_id', 'bar');
$config->set(Name::Shared() . '.translators.deepl.translator', Deepl::class);
$config->set(Name::Shared() . '.translators.deepl.credentials.key', 'foo');

$config->set(Name::Shared() . '.translators.yandex.translator', Yandex::class);
$config->set(Name::Shared() . '.translators.yandex.credentials.key', 'foo');
$config->set(Name::Shared() . '.translators.yandex.credentials.folter', '123');
});
}
}
2 changes: 1 addition & 1 deletion tests/Unit/Can/IntegrationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,5 @@
test('cannot be translatable', function (string $translator) {
$translator = translator($translator);

expect($translator->can('qwerty'))->toBeTrue();
expect($translator->can('qwerty'))->toBeFalse();
})->with('translators');
Loading

0 comments on commit bf46b12

Please sign in to comment.