From 40041db7cbc34046b070042f4c5feb64acbb4915 Mon Sep 17 00:00:00 2001 From: Mathieu Santostefano Date: Wed, 5 May 2021 19:27:23 +0200 Subject: [PATCH] Refactored LocoProviderTest --- .../Translation/Bridge/Loco/LocoProvider.php | 184 +++--- .../Bridge/Loco/Tests/LocoProviderTest.php | 530 +++++++++--------- 2 files changed, 385 insertions(+), 329 deletions(-) diff --git a/src/Symfony/Component/Translation/Bridge/Loco/LocoProvider.php b/src/Symfony/Component/Translation/Bridge/Loco/LocoProvider.php index 1b3419b0aa..ea4232c4ee 100644 --- a/src/Symfony/Component/Translation/Bridge/Loco/LocoProvider.php +++ b/src/Symfony/Component/Translation/Bridge/Loco/LocoProvider.php @@ -59,19 +59,13 @@ final class LocoProvider implements ProviderInterface $catalogue = $translatorBag->getCatalogues()[0]; } - // Create keys on Loco foreach ($catalogue->all() as $domain => $messages) { - $ids = []; - foreach ($messages as $id => $message) { - $ids[] = $id; - $this->createAsset($id); - } - if ($ids) { - $this->tagsAssets($ids, $domain); + $createdIds = $this->createAssets(array_keys($messages)); + if ($createdIds) { + $this->tagsAssets($createdIds, $domain); } } - // Push translations in all locales and tag them with domain foreach ($translatorBag->getCatalogues() as $catalogue) { $locale = $catalogue->getLocale(); @@ -79,10 +73,9 @@ final class LocoProvider implements ProviderInterface $this->createLocale($locale); } - foreach ($catalogue->all() as $messages) { - foreach ($messages as $id => $message) { - $this->translateAsset($id, $message, $locale); - } + foreach ($catalogue->all() as $domain => $messages) { + $ids = $this->getAssetsIds($domain); + $this->translateAssets(array_combine($ids, array_values($messages)), $locale); } } } @@ -91,92 +84,142 @@ final class LocoProvider implements ProviderInterface { $domains = $domains ?: ['*']; $translatorBag = new TranslatorBag(); + $responses = []; foreach ($locales as $locale) { foreach ($domains as $domain) { - $response = $this->client->request('GET', sprintf('export/locale/%s.xlf?filter=%s&status=translated', $locale, $domain)); - - if (404 === $response->getStatusCode()) { - $this->logger->error(sprintf('Locale "%s" for domain "%s" does not exist in Loco.', $locale, $domain)); - continue; - } - - $responseContent = $response->getContent(false); - - if (200 !== $response->getStatusCode()) { - throw new ProviderException('Unable to read the Loco response: '.$responseContent, $response); - } - - $translatorBag->addCatalogue($this->loader->load($responseContent, $locale, $domain)); + $responses[] = [ + 'response' => $this->client->request('GET', sprintf('export/locale/%s.xlf', rawurlencode($locale)), [ + 'query' => [ + 'filter' => $domain, + 'status' => 'translated', + ], + ]), + 'locale' => $locale, + 'domain' => $domain, + ]; } } + foreach ($responses as $response) { + $locale = $response['locale']; + $domain = $response['domain']; + $response = $response['response']; + + if (404 === $response->getStatusCode()) { + $this->logger->warning(sprintf('Locale "%s" for domain "%s" does not exist in Loco.', $locale, $domain)); + continue; + } + + $responseContent = $response->getContent(false); + + if (200 !== $response->getStatusCode()) { + throw new ProviderException('Unable to read the Loco response: '.$responseContent, $response); + } + + $translatorBag->addCatalogue($this->loader->load($responseContent, $locale, $domain)); + } + return $translatorBag; } public function delete(TranslatorBagInterface $translatorBag): void { - $deletedIds = []; + $catalogue = $translatorBag->getCatalogue($this->defaultLocale); - foreach ($translatorBag->getCatalogues() as $catalogue) { - foreach ($catalogue->all() as $messages) { - foreach ($messages as $id => $message) { - if (\in_array($id, $deletedIds, true)) { - continue; - } + if (!$catalogue) { + $catalogue = $translatorBag->getCatalogues()[0]; + } - $this->deleteAsset($id); - $deletedIds[] = $id; - } + $responses = []; + + foreach (array_keys($catalogue->all()) as $domain) { + foreach ($this->getAssetsIds($domain) as $id) { + $responses[$id] = $this->client->request('DELETE', sprintf('assets/%s.json', $id)); + } + } + + foreach ($responses as $key => $response) { + if (403 === $response->getStatusCode()) { + $this->logger->error('The API key used does not have sufficient permissions to delete assets.'); + } + + if (200 !== $response->getStatusCode() && 404 !== $response->getStatusCode()) { + $this->logger->error(sprintf('Unable to delete translation key "%s" to Loco: "%s".', $key, $response->getContent(false))); } } } - private function createAsset(string $id): void + /** + * Returns array of internal Loco's unique ids. + */ + private function getAssetsIds(string $domain): array { - $response = $this->client->request('POST', 'assets', [ - 'body' => [ - 'name' => $id, - 'id' => $id, - 'type' => 'text', - 'default' => 'untranslated', - ], - ]); - - if (409 === $response->getStatusCode()) { - $this->logger->info(sprintf('Translation key "%s" already exists in Loco.', $id), [ - 'id' => $id, - ]); - } elseif (201 !== $response->getStatusCode()) { - $this->logger->error(sprintf('Unable to add new translation key "%s" to Loco: (status code: "%s") "%s".', $id, $response->getStatusCode(), $response->getContent(false))); - } - } - - private function translateAsset(string $id, string $message, string $locale): void - { - $response = $this->client->request('POST', sprintf('translations/%s/%s', $id, $locale), [ - 'body' => $message, - ]); + $response = $this->client->request('GET', 'assets', ['query' => ['filter' => $domain]]); if (200 !== $response->getStatusCode()) { - $this->logger->error(sprintf('Unable to add translation message "%s" (for key: "%s" in locale "%s") to Loco: "%s".', $message, $id, $locale, $response->getContent(false))); + $this->logger->error(sprintf('Unable to get assets from Loco: "%s".', $response->getContent(false))); + } + + return array_map(function ($asset) { + return $asset['id']; + }, $response->toArray(false)); + } + + private function createAssets(array $keys): array + { + $responses = $createdIds = []; + + foreach ($keys as $key) { + $responses[$key] = $this->client->request('POST', 'assets', [ + 'body' => [ + 'text' => $key, + 'type' => 'text', + 'default' => 'untranslated', + ], + ]); + } + + foreach ($responses as $key => $response) { + if (201 !== $response->getStatusCode()) { + $this->logger->error(sprintf('Unable to add new translation key "%s" to Loco: (status code: "%s") "%s".', $key, $response->getStatusCode(), $response->getContent(false))); + } else { + $createdIds[] = $response->toArray(false)['id']; + } + } + + return $createdIds; + } + + private function translateAssets(array $translations, string $locale): void + { + $responses = []; + + foreach ($translations as $id => $message) { + $responses[$id] = $this->client->request('POST', sprintf('translations/%s/%s', $id, $locale), [ + 'body' => $message, + ]); + } + + foreach ($responses as $id => $response) { + if (200 !== $response->getStatusCode()) { + $this->logger->error(sprintf('Unable to add translation for key "%s" in locale "%s" to Loco: "%s".', $id, $locale, $response->getContent(false))); + } } } private function tagsAssets(array $ids, string $tag): void { - $idsAsString = implode(',', array_unique($ids)); - if (!\in_array($tag, $this->getTags(), true)) { $this->createTag($tag); } $response = $this->client->request('POST', sprintf('tags/%s.json', $tag), [ - 'body' => $idsAsString, + 'body' => implode(',', $ids), ]); if (200 !== $response->getStatusCode()) { - $this->logger->error(sprintf('Unable to add tag "%s" on translation keys "%s" to Loco: "%s".', $tag, $idsAsString, $response->getContent(false))); + $this->logger->error(sprintf('Unable to tag assets with "%s" on Loco: "%s".', $tag, $response->getContent(false))); } } @@ -233,13 +276,4 @@ final class LocoProvider implements ProviderInterface return $carry; }, []); } - - private function deleteAsset(string $id): void - { - $response = $this->client->request('DELETE', sprintf('assets/%s.json', $id)); - - if (200 !== $response->getStatusCode()) { - $this->logger->error(sprintf('Unable to delete translation key "%s" to Loco: "%s".', $id, $response->getContent(false))); - } - } } diff --git a/src/Symfony/Component/Translation/Bridge/Loco/Tests/LocoProviderTest.php b/src/Symfony/Component/Translation/Bridge/Loco/Tests/LocoProviderTest.php index 6dc474d637..3d3dd8af98 100644 --- a/src/Symfony/Component/Translation/Bridge/Loco/Tests/LocoProviderTest.php +++ b/src/Symfony/Component/Translation/Bridge/Loco/Tests/LocoProviderTest.php @@ -4,6 +4,7 @@ namespace Symfony\Component\Translation\Bridge\Loco\Tests; use Psr\Log\LoggerInterface; use Symfony\Component\HttpClient\MockHttpClient; +use Symfony\Component\HttpClient\Response\MockResponse; use Symfony\Component\Translation\Bridge\Loco\LocoProvider; use Symfony\Component\Translation\Loader\ArrayLoader; use Symfony\Component\Translation\Loader\LoaderInterface; @@ -22,195 +23,201 @@ class LocoProviderTest extends ProviderTestCase return new LocoProvider($client, $loader, $logger, $defaultLocale, $endpoint); } + public function toStringProvider(): iterable + { + yield [ + $this->createProvider($this->getClient()->withOptions([ + 'base_uri' => 'https://localise.biz/api/', + 'headers' => [ + 'Authorization' => 'Loco API_KEY', + ], + ]), $this->getLoader(), $this->getLogger(), $this->getDefaultLocale(), 'localise.biz/api/'), + 'loco://localise.biz/api/', + ]; + + yield [ + $this->createProvider($this->getClient()->withOptions([ + 'base_uri' => 'https://example.com', + 'headers' => [ + 'Authorization' => 'Loco API_KEY', + ], + ]), $this->getLoader(), $this->getLogger(), $this->getDefaultLocale(), 'example.com'), + 'loco://example.com', + ]; + + yield [ + $this->createProvider($this->getClient()->withOptions([ + 'base_uri' => 'https://example.com:99', + 'headers' => [ + 'Authorization' => 'Loco API_KEY', + ], + ]), $this->getLoader(), $this->getLogger(), $this->getDefaultLocale(), 'example.com:99'), + 'loco://example.com:99', + ]; + } + public function testCompleteWriteProcess() { - $createAssetResponse = $this->createMock(ResponseInterface::class); - $createAssetResponse->expects($this->exactly(4)) - ->method('getStatusCode') - ->willReturn(201); - - $getLocalesResponse = $this->createMock(ResponseInterface::class); - $getLocalesResponse->expects($this->exactly(4)) - ->method('getStatusCode') - ->willReturn(200); - $getLocalesResponse->expects($this->exactly(2)) - ->method('getContent') - ->with(false) - ->willReturn('[{"code":"en"}]'); - - $createLocaleResponse = $this->createMock(ResponseInterface::class); - $createLocaleResponse->expects($this->exactly(2)) - ->method('getStatusCode') - ->willReturn(201); - - $translateAssetResponse = $this->createMock(ResponseInterface::class); - $translateAssetResponse->expects($this->exactly(8)) - ->method('getStatusCode') - ->willReturn(200); - - $getTagsEmptyResponse = $this->createMock(ResponseInterface::class); - $getTagsEmptyResponse->expects($this->exactly(2)) - ->method('getStatusCode') - ->willReturn(200); - $getTagsEmptyResponse->expects($this->once()) - ->method('getContent') - ->with(false) - ->willReturn('[]'); - - $getTagsNotEmptyResponse = $this->createMock(ResponseInterface::class); - $getTagsNotEmptyResponse->expects($this->exactly(2)) - ->method('getStatusCode') - ->willReturn(200); - $getTagsNotEmptyResponse->expects($this->once()) - ->method('getContent') - ->with(false) - ->willReturn('["messages"]'); - - $createTagResponse = $this->createMock(ResponseInterface::class); - $createTagResponse->expects($this->exactly(4)) - ->method('getStatusCode') - ->willReturn(201); - - $tagAssetResponse = $this->createMock(ResponseInterface::class); - $tagAssetResponse->expects($this->exactly(4)) - ->method('getStatusCode') - ->willReturn(200); - $expectedAuthHeader = 'Authorization: Loco API_KEY'; $responses = [ - 'createAsset1' => function (string $method, string $url, array $options = []) use ($createAssetResponse, $expectedAuthHeader): ResponseInterface { + 'createAsset1' => function (string $method, string $url, array $options = []) use ($expectedAuthHeader): ResponseInterface { $expectedBody = http_build_query([ - 'name' => 'a', - 'id' => 'a', + 'text' => 'a', 'type' => 'text', 'default' => 'untranslated', ]); - $this->assertEquals('POST', $method); - $this->assertEquals($expectedAuthHeader, $options['normalized_headers']['authorization'][0]); - $this->assertEquals($expectedBody, $options['body']); + $this->assertSame('POST', $method); + $this->assertSame($expectedAuthHeader, $options['normalized_headers']['authorization'][0]); + $this->assertSame($expectedBody, $options['body']); - return $createAssetResponse; + return new MockResponse('{"id": "1337"}', ['http_code' => 201]); }, - 'getTags1' => function (string $method, string $url, array $options = []) use ($getTagsEmptyResponse, $expectedAuthHeader): ResponseInterface { - $this->assertEquals('GET', $method); - $this->assertEquals('https://localise.biz/api/tags.json', $url); - $this->assertEquals($expectedAuthHeader, $options['normalized_headers']['authorization'][0]); + 'getTags1' => function (string $method, string $url, array $options = []) use ($expectedAuthHeader): ResponseInterface { + $this->assertSame('GET', $method); + $this->assertSame('https://localise.biz/api/tags.json', $url); + $this->assertSame($expectedAuthHeader, $options['normalized_headers']['authorization'][0]); - return $getTagsEmptyResponse; + return new MockResponse('[]'); }, - 'createTag1' => function (string $method, string $url, array $options = []) use ($createTagResponse, $expectedAuthHeader): ResponseInterface { - $this->assertEquals('POST', $method); - $this->assertEquals('https://localise.biz/api/tags.json', $url); - $this->assertEquals($expectedAuthHeader, $options['normalized_headers']['authorization'][0]); - $this->assertEquals(http_build_query(['name' => 'messages']), $options['body']); + 'createTag1' => function (string $method, string $url, array $options = []) use ($expectedAuthHeader): ResponseInterface { + $this->assertSame('POST', $method); + $this->assertSame('https://localise.biz/api/tags.json', $url); + $this->assertSame($expectedAuthHeader, $options['normalized_headers']['authorization'][0]); + $this->assertSame(http_build_query(['name' => 'messages']), $options['body']); - return $createTagResponse; + return new MockResponse('', ['http_code' => 201]); }, - 'tagAsset1' => function (string $method, string $url, array $options = []) use ($tagAssetResponse, $expectedAuthHeader): ResponseInterface { - $this->assertEquals('POST', $method); - $this->assertEquals('https://localise.biz/api/tags/messages.json', $url); - $this->assertEquals($expectedAuthHeader, $options['normalized_headers']['authorization'][0]); - $this->assertEquals('a', $options['body']); + 'tagAsset1' => function (string $method, string $url, array $options = []) use ($expectedAuthHeader): ResponseInterface { + $this->assertSame('POST', $method); + $this->assertSame('https://localise.biz/api/tags/messages.json', $url); + $this->assertSame($expectedAuthHeader, $options['normalized_headers']['authorization'][0]); + $this->assertSame('1337', $options['body']); - return $tagAssetResponse; + return new MockResponse(); }, - 'createAsset2' => function (string $method, string $url, array $options = []) use ($createAssetResponse, $expectedAuthHeader): ResponseInterface { + 'createAsset2' => function (string $method, string $url, array $options = []) use ($expectedAuthHeader): ResponseInterface { $expectedBody = http_build_query([ - 'name' => 'post.num_comments', - 'id' => 'post.num_comments', + 'text' => 'post.num_comments', 'type' => 'text', 'default' => 'untranslated', ]); - $this->assertEquals('POST', $method); - $this->assertEquals($expectedAuthHeader, $options['normalized_headers']['authorization'][0]); - $this->assertEquals($expectedBody, $options['body']); + $this->assertSame('POST', $method); + $this->assertSame($expectedAuthHeader, $options['normalized_headers']['authorization'][0]); + $this->assertSame($expectedBody, $options['body']); - return $createAssetResponse; + return new MockResponse('{"id": "1234"}', ['http_code' => 201]); }, - 'getTags2' => function (string $method, string $url, array $options = []) use ($getTagsNotEmptyResponse, $expectedAuthHeader): ResponseInterface { - $this->assertEquals('GET', $method); - $this->assertEquals('https://localise.biz/api/tags.json', $url); - $this->assertEquals($expectedAuthHeader, $options['normalized_headers']['authorization'][0]); + 'getTags2' => function (string $method, string $url, array $options = []) use ($expectedAuthHeader): ResponseInterface { + $this->assertSame('GET', $method); + $this->assertSame('https://localise.biz/api/tags.json', $url); + $this->assertSame($expectedAuthHeader, $options['normalized_headers']['authorization'][0]); - return $getTagsNotEmptyResponse; + return new MockResponse('["messages"]'); }, - 'createTag2' => function (string $method, string $url, array $options = []) use ($createTagResponse, $expectedAuthHeader): ResponseInterface { - $this->assertEquals('POST', $method); - $this->assertEquals('https://localise.biz/api/tags.json', $url); - $this->assertEquals($expectedAuthHeader, $options['normalized_headers']['authorization'][0]); - $this->assertEquals(http_build_query(['name' => 'validators']), $options['body']); + 'createTag2' => function (string $method, string $url, array $options = []) use ($expectedAuthHeader): ResponseInterface { + $this->assertSame('POST', $method); + $this->assertSame('https://localise.biz/api/tags.json', $url); + $this->assertSame($expectedAuthHeader, $options['normalized_headers']['authorization'][0]); + $this->assertSame(http_build_query(['name' => 'validators']), $options['body']); - return $createTagResponse; + return new MockResponse('', ['http_code' => 201]); }, - 'tagAsset2' => function (string $method, string $url, array $options = []) use ($tagAssetResponse, $expectedAuthHeader): ResponseInterface { - $this->assertEquals('POST', $method); - $this->assertEquals('https://localise.biz/api/tags/validators.json', $url); - $this->assertEquals($expectedAuthHeader, $options['normalized_headers']['authorization'][0]); - $this->assertEquals('post.num_comments', $options['body']); + 'tagAsset2' => function (string $method, string $url, array $options = []) use ($expectedAuthHeader): ResponseInterface { + $this->assertSame('POST', $method); + $this->assertSame('https://localise.biz/api/tags/validators.json', $url); + $this->assertSame($expectedAuthHeader, $options['normalized_headers']['authorization'][0]); + $this->assertSame('1234', $options['body']); - return $tagAssetResponse; + return new MockResponse(); }, + 'getLocales1' => function (string $method, string $url, array $options = []) use ($expectedAuthHeader): ResponseInterface { + $this->assertSame('GET', $method); + $this->assertSame('https://localise.biz/api/locales', $url); + $this->assertSame($expectedAuthHeader, $options['normalized_headers']['authorization'][0]); - 'getLocales1' => function (string $method, string $url, array $options = []) use ($getLocalesResponse, $expectedAuthHeader): ResponseInterface { - $this->assertEquals('GET', $method); - $this->assertEquals('https://localise.biz/api/locales', $url); - $this->assertEquals($expectedAuthHeader, $options['normalized_headers']['authorization'][0]); - - return $getLocalesResponse; + return new MockResponse('[{"code":"en"}]'); }, + 'getAssetsIds1' => function (string $method, string $url, array $options = []) use ($expectedAuthHeader): ResponseInterface { + $this->assertSame('GET', $method); + $this->assertSame('https://localise.biz/api/assets?filter=messages', $url); + $this->assertSame(['filter' => 'messages'], $options['query']); + $this->assertSame($expectedAuthHeader, $options['normalized_headers']['authorization'][0]); - 'translateAsset1' => function (string $method, string $url, array $options = []) use ($translateAssetResponse, $expectedAuthHeader): ResponseInterface { - $this->assertEquals('POST', $method); - $this->assertEquals('https://localise.biz/api/translations/a/en', $url); - $this->assertEquals($expectedAuthHeader, $options['normalized_headers']['authorization'][0]); - $this->assertEquals('trans_en_a', $options['body']); - - return $translateAssetResponse; + return new MockResponse('[{"id":"1337"}]'); }, - 'translateAsset2' => function (string $method, string $url, array $options = []) use ($translateAssetResponse, $expectedAuthHeader): ResponseInterface { - $this->assertEquals('POST', $method); - $this->assertEquals('https://localise.biz/api/translations/post.num_comments/en', $url); - $this->assertEquals($expectedAuthHeader, $options['normalized_headers']['authorization'][0]); - $this->assertEquals('{count, plural, one {# comment} other {# comments}}', $options['body']); + 'translateAsset1' => function (string $method, string $url, array $options = []) use ($expectedAuthHeader): ResponseInterface { + $this->assertSame('POST', $method); + $this->assertSame('https://localise.biz/api/translations/1337/en', $url); + $this->assertSame($expectedAuthHeader, $options['normalized_headers']['authorization'][0]); + $this->assertSame('trans_en_a', $options['body']); - return $translateAssetResponse; + return new MockResponse(); }, + 'getAssetsIds2' => function (string $method, string $url, array $options = []) use ($expectedAuthHeader): ResponseInterface { + $this->assertSame('GET', $method); + $this->assertSame('https://localise.biz/api/assets?filter=validators', $url); + $this->assertSame(['filter' => 'validators'], $options['query']); + $this->assertSame($expectedAuthHeader, $options['normalized_headers']['authorization'][0]); - 'getLocales2' => function (string $method, string $url, array $options = []) use ($getLocalesResponse, $expectedAuthHeader): ResponseInterface { - $this->assertEquals('GET', $method); - $this->assertEquals('https://localise.biz/api/locales', $url); - $this->assertEquals($expectedAuthHeader, $options['normalized_headers']['authorization'][0]); - - return $getLocalesResponse; + return new MockResponse('[{"id":"1234"}]'); }, + 'translateAsset2' => function (string $method, string $url, array $options = []) use ($expectedAuthHeader): ResponseInterface { + $this->assertSame('POST', $method); + $this->assertSame('https://localise.biz/api/translations/1234/en', $url); + $this->assertSame($expectedAuthHeader, $options['normalized_headers']['authorization'][0]); + $this->assertSame('{count, plural, one {# comment} other {# comments}}', $options['body']); - 'createLocale1' => function (string $method, string $url, array $options = []) use ($createLocaleResponse, $expectedAuthHeader): ResponseInterface { - $this->assertEquals('POST', $method); - $this->assertEquals('https://localise.biz/api/locales', $url); - $this->assertEquals($expectedAuthHeader, $options['normalized_headers']['authorization'][0]); - $this->assertEquals('code=fr', $options['body']); - - return $createLocaleResponse; + return new MockResponse(); }, + 'getLocales2' => function (string $method, string $url, array $options = []) use ($expectedAuthHeader): ResponseInterface { + $this->assertSame('GET', $method); + $this->assertSame('https://localise.biz/api/locales', $url); + $this->assertSame($expectedAuthHeader, $options['normalized_headers']['authorization'][0]); - 'translateAsset3' => function (string $method, string $url, array $options = []) use ($translateAssetResponse, $expectedAuthHeader): ResponseInterface { - $this->assertEquals('POST', $method); - $this->assertEquals('https://localise.biz/api/translations/a/fr', $url); - $this->assertEquals($expectedAuthHeader, $options['normalized_headers']['authorization'][0]); - $this->assertEquals('trans_fr_a', $options['body']); - - return $translateAssetResponse; + return new MockResponse('[{"code":"en"}]'); }, - 'translateAsset4' => function (string $method, string $url, array $options = []) use ($translateAssetResponse, $expectedAuthHeader): ResponseInterface { - $this->assertEquals('POST', $method); - $this->assertEquals('https://localise.biz/api/translations/post.num_comments/fr', $url); - $this->assertEquals($expectedAuthHeader, $options['normalized_headers']['authorization'][0]); - $this->assertEquals('{count, plural, one {# commentaire} other {# commentaires}}', $options['body']); + 'createLocale1' => function (string $method, string $url, array $options = []) use ($expectedAuthHeader): ResponseInterface { + $this->assertSame('POST', $method); + $this->assertSame('https://localise.biz/api/locales', $url); + $this->assertSame($expectedAuthHeader, $options['normalized_headers']['authorization'][0]); + $this->assertSame('code=fr', $options['body']); - return $translateAssetResponse; + return new MockResponse('', ['http_code' => 201]); + }, + 'getAssetsIds3' => function (string $method, string $url, array $options = []) use ($expectedAuthHeader): ResponseInterface { + $this->assertSame('GET', $method); + $this->assertSame('https://localise.biz/api/assets?filter=messages', $url); + $this->assertSame(['filter' => 'messages'], $options['query']); + $this->assertSame($expectedAuthHeader, $options['normalized_headers']['authorization'][0]); + + return new MockResponse('[{"id":"1337"}]'); + }, + 'translateAsset3' => function (string $method, string $url, array $options = []) use ($expectedAuthHeader): ResponseInterface { + $this->assertSame('POST', $method); + $this->assertSame('https://localise.biz/api/translations/1337/fr', $url); + $this->assertSame($expectedAuthHeader, $options['normalized_headers']['authorization'][0]); + $this->assertSame('trans_fr_a', $options['body']); + + return new MockResponse(); + }, + 'getAssetsIds4' => function (string $method, string $url, array $options = []) use ($expectedAuthHeader): ResponseInterface { + $this->assertSame('GET', $method); + $this->assertSame('https://localise.biz/api/assets?filter=validators', $url); + $this->assertSame(['filter' => 'validators'], $options['query']); + $this->assertSame($expectedAuthHeader, $options['normalized_headers']['authorization'][0]); + + return new MockResponse('[{"id":"1234"}]'); + }, + 'translateAsset4' => function (string $method, string $url, array $options = []) use ($expectedAuthHeader): ResponseInterface { + $this->assertSame('POST', $method); + $this->assertSame('https://localise.biz/api/translations/1234/fr', $url); + $this->assertSame($expectedAuthHeader, $options['normalized_headers']['authorization'][0]); + $this->assertSame('{count, plural, one {# commentaire} other {# commentaires}}', $options['body']); + + return new MockResponse(); }, ]; @@ -226,106 +233,126 @@ class LocoProviderTest extends ProviderTestCase $provider = $this->createProvider((new MockHttpClient($responses))->withOptions([ 'base_uri' => 'https://localise.biz/api/', - 'headers' => [ - 'Authorization' => 'Loco API_KEY', - ], + 'headers' => ['Authorization' => 'Loco API_KEY'], ]), $this->getLoader(), $this->getLogger(), $this->getDefaultLocale(), 'localise.biz/api/'); + $provider->write($translatorBag); } /** - * @dataProvider getLocoResponsesForOneLocaleAndOneDomain + * @dataProvider getResponsesForOneLocaleAndOneDomain */ public function testReadForOneLocaleAndOneDomain(string $locale, string $domain, string $responseContent, TranslatorBag $expectedTranslatorBag) { - $response = $this->createMock(ResponseInterface::class); - $response->expects($this->once()) - ->method('getContent') - ->willReturn($responseContent); - $response->expects($this->exactly(2)) - ->method('getStatusCode') - ->willReturn(200); - $loader = $this->getLoader(); $loader->expects($this->once()) ->method('load') - ->willReturn($expectedTranslatorBag->getCatalogue($locale)); + ->willReturn((new XliffFileLoader())->load($responseContent, $locale, $domain)); - $locoProvider = $this->createProvider((new MockHttpClient($response))->withOptions([ + $provider = $this->createProvider((new MockHttpClient(new MockResponse($responseContent)))->withOptions([ 'base_uri' => 'https://localise.biz/api/', 'headers' => [ 'Authorization' => 'Loco API_KEY', ], ]), $loader, $this->getLogger(), $this->getDefaultLocale(), 'localise.biz/api/'); - $translatorBag = $locoProvider->read([$domain], [$locale]); + $translatorBag = $provider->read([$domain], [$locale]); + // We don't want to assert equality of metadata here, due to the ArrayLoader usage. + foreach ($translatorBag->getCatalogues() as $catalogue) { + $catalogue->deleteMetadata('', ''); + } $this->assertEquals($expectedTranslatorBag->getCatalogues(), $translatorBag->getCatalogues()); } /** - * @dataProvider getLocoResponsesForManyLocalesAndManyDomains + * @dataProvider getResponsesForManyLocalesAndManyDomains */ - public function testReadForManyLocalesAndManyDomains(array $locales, array $domains, array $responseContents, array $expectedTranslatorBags) + public function testReadForManyLocalesAndManyDomains(array $locales, array $domains, array $responseContents, TranslatorBag $expectedTranslatorBag) { + $responses = []; + $consecutiveLoadArguments = []; + $consecutiveLoadReturns = []; + foreach ($locales as $locale) { foreach ($domains as $domain) { - $response = $this->createMock(ResponseInterface::class); - $response->expects($this->once()) - ->method('getContent') - ->willReturn($responseContents[$domain][$locale]); - $response->expects($this->exactly(2)) - ->method('getStatusCode') - ->willReturn(200); - - $locoProvider = new LocoProvider((new MockHttpClient($response))->withOptions([ - 'base_uri' => 'https://localise.biz/api/', - 'headers' => [ - 'Authorization' => 'Loco API_KEY', - ], - ]), new XliffFileLoader(), $this->getLogger(), $this->getDefaultLocale(), 'localise.biz/api/'); - $translatorBag = $locoProvider->read([$domain], [$locale]); - // We don't want to assert equality of metadata here, due to the ArrayLoader usage. - $translatorBag->getCatalogue($locale)->deleteMetadata('foo', ''); - - $this->assertEquals($expectedTranslatorBags[$domain]->getCatalogue($locale), $translatorBag->getCatalogue($locale)); + $responses[] = new MockResponse($responseContents[$locale][$domain]); + $consecutiveLoadArguments[] = [$responseContents[$locale][$domain], $locale, $domain]; + $consecutiveLoadReturns[] = (new XliffFileLoader())->load($responseContents[$locale][$domain], $locale, $domain); } } + + $loader = $this->getLoader(); + $loader->expects($this->exactly(\count($consecutiveLoadArguments))) + ->method('load') + ->withConsecutive(...$consecutiveLoadArguments) + ->willReturnOnConsecutiveCalls(...$consecutiveLoadReturns); + + $provider = $this->createProvider((new MockHttpClient($responses))->withOptions([ + 'base_uri' => 'https://localise.biz/api/', + 'headers' => [ + 'Authorization' => 'Loco API_KEY', + ], + ]), $loader, $this->getLogger(), $this->getDefaultLocale(), 'localise.biz/api/'); + $translatorBag = $provider->read($domains, $locales); + // We don't want to assert equality of metadata here, due to the ArrayLoader usage. + foreach ($translatorBag->getCatalogues() as $catalogue) { + $catalogue->deleteMetadata('', ''); + } + + $this->assertEquals($expectedTranslatorBag->getCatalogues(), $translatorBag->getCatalogues()); } - public function toStringProvider(): iterable + public function testDeleteProcess() { - yield [ - new LocoProvider($this->getClient()->withOptions([ - 'base_uri' => 'https://localise.biz/api/', - 'headers' => [ - 'Authorization' => 'Loco API_KEY', - ], - ]), $this->getLoader(), $this->getLogger(), $this->getDefaultLocale(), 'localise.biz/api/'), - 'loco://localise.biz/api/', - ]; + $translatorBag = new TranslatorBag(); + $translatorBag->addCatalogue(new MessageCatalogue('en', [ + 'messages' => ['a' => 'trans_en_a'], + 'validators' => ['post.num_comments' => '{count, plural, one {# comment} other {# comments}}'], + ])); + $translatorBag->addCatalogue(new MessageCatalogue('fr', [ + 'messages' => ['a' => 'trans_fr_a'], + 'validators' => ['post.num_comments' => '{count, plural, one {# commentaire} other {# commentaires}}'], + ])); - yield [ - new LocoProvider($this->getClient()->withOptions([ - 'base_uri' => 'https://example.com', - 'headers' => [ - 'Authorization' => 'Loco API_KEY', - ], - ]), $this->getLoader(), $this->getLogger(), $this->getDefaultLocale(), 'example.com'), - 'loco://example.com', - ]; + $provider = $this->createProvider( + new MockHttpClient([ + function (string $method, string $url, array $options = []): ResponseInterface { + $this->assertSame('GET', $method); + $this->assertSame('https://localise.biz/api/assets?filter=messages', $url); + $this->assertSame(['filter' => 'messages'], $options['query']); - yield [ - new LocoProvider($this->getClient()->withOptions([ - 'base_uri' => 'https://example.com:99', - 'headers' => [ - 'Authorization' => 'Loco API_KEY', - ], - ]), $this->getLoader(), $this->getLogger(), $this->getDefaultLocale(), 'example.com:99'), - 'loco://example.com:99', - ]; + return new MockResponse('[{"id":"1337"}]'); + }, + function (string $method, string $url): MockResponse { + $this->assertSame('DELETE', $method); + $this->assertSame('https://localise.biz/api/assets/1337.json', $url); + + return new MockResponse(); + }, + function (string $method, string $url, array $options = []): ResponseInterface { + $this->assertSame('GET', $method); + $this->assertSame('https://localise.biz/api/assets?filter=validators', $url); + $this->assertSame(['filter' => 'validators'], $options['query']); + + return new MockResponse('[{"id":"1234"}]'); + }, + function (string $method, string $url): MockResponse { + $this->assertSame('DELETE', $method); + $this->assertSame('https://localise.biz/api/assets/1234.json', $url); + + return new MockResponse(); + }, + ], 'https://localise.biz/api/'), + $this->getLoader(), + $this->getLogger(), + $this->getDefaultLocale(), + 'localise.biz/api/' + ); + + $provider->delete($translatorBag); } - public function getLocoResponsesForOneLocaleAndOneDomain(): \Generator + public function getResponsesForOneLocaleAndOneDomain(): \Generator { $arrayLoader = new ArrayLoader(); @@ -333,7 +360,7 @@ class LocoProviderTest extends ProviderTestCase $expectedTranslatorBagEn->addCatalogue($arrayLoader->load([ 'index.hello' => 'Hello', 'index.greetings' => 'Welcome, {firstname}!', - ], 'en', 'messages')); + ], 'en')); yield ['en', 'messages', <<<'XLIFF' @@ -363,7 +390,7 @@ XLIFF $expectedTranslatorBagFr->addCatalogue($arrayLoader->load([ 'index.hello' => 'Bonjour', 'index.greetings' => 'Bienvenue, {firstname} !', - ], 'fr', 'messages')); + ], 'fr')); yield ['fr', 'messages', <<<'XLIFF' @@ -390,26 +417,24 @@ XLIFF ]; } - public function getLocoResponsesForManyLocalesAndManyDomains(): \Generator + public function getResponsesForManyLocalesAndManyDomains(): \Generator { $arrayLoader = new ArrayLoader(); - $expectedTranslatorBagMessages = new TranslatorBag(); - $expectedTranslatorBagMessages->addCatalogue($arrayLoader->load([ + $expectedTranslatorBag = new TranslatorBag(); + $expectedTranslatorBag->addCatalogue($arrayLoader->load([ 'index.hello' => 'Hello', 'index.greetings' => 'Welcome, {firstname}!', - ], 'en', 'messages')); - $expectedTranslatorBagMessages->addCatalogue($arrayLoader->load([ + ], 'en')); + $expectedTranslatorBag->addCatalogue($arrayLoader->load([ 'index.hello' => 'Bonjour', 'index.greetings' => 'Bienvenue, {firstname} !', - ], 'fr', 'messages')); - - $expectedTranslatorBagValidators = new TranslatorBag(); - $expectedTranslatorBagValidators->addCatalogue($arrayLoader->load([ + ], 'fr')); + $expectedTranslatorBag->addCatalogue($arrayLoader->load([ 'firstname.error' => 'Firstname must contains only letters.', 'lastname.error' => 'Lastname must contains only letters.', ], 'en', 'validators')); - $expectedTranslatorBagValidators->addCatalogue($arrayLoader->load([ + $expectedTranslatorBag->addCatalogue($arrayLoader->load([ 'firstname.error' => 'Le prénom ne peut contenir que des lettres.', 'lastname.error' => 'Le nom de famille ne peut contenir que des lettres.', ], 'fr', 'validators')); @@ -418,8 +443,8 @@ XLIFF ['en', 'fr'], ['messages', 'validators'], [ - 'messages' => [ - 'en' => <<<'XLIFF' + 'en' => [ + 'messages' => <<<'XLIFF' @@ -440,30 +465,7 @@ XLIFF XLIFF , - 'fr' => <<<'XLIFF' - - - -
- -
- - - index.hello - Bonjour - - - index.greetings - Bienvenue, {firstname} ! - - -
-
-XLIFF - , - ], - 'validators' => [ - 'en' => <<<'XLIFF' + 'validators' => <<<'XLIFF' @@ -484,7 +486,30 @@ XLIFF XLIFF , - 'fr' => <<<'XLIFF' + ], + 'fr' => [ + 'messages' => <<<'XLIFF' + + + +
+ +
+ + + index.hello + Bonjour + + + index.greetings + Bienvenue, {firstname} ! + + +
+
+XLIFF + , + 'validators' => <<<'XLIFF' @@ -505,12 +530,9 @@ XLIFF XLIFF , + ], ], - ], - [ - 'messages' => $expectedTranslatorBagMessages, - 'validators' => $expectedTranslatorBagValidators, - ], + $expectedTranslatorBag, ]; } }