MessageTemplateTest - Rearrange with data-provider. Add more tests.
authorTim Otten <totten@civicrm.org>
Thu, 18 Aug 2022 10:29:01 +0000 (03:29 -0700)
committerEileen McNaughton <emcnaughton@wikimedia.org>
Thu, 1 Sep 2022 06:51:02 +0000 (18:51 +1200)
tests/phpunit/CRM/Core/BAO/MessageTemplateTest.php

index 4d6a1c3b95638f72cf853117e5d654e2593e7117..b8d657498de568bf9544a695610659815674817b 100644 (file)
@@ -47,116 +47,68 @@ class CRM_Core_BAO_MessageTemplateTest extends CiviUnitTestCase {
     $this->assertStringContainsString('<p>Hello testRenderTemplate Abba Baab!</p>', $rendered['html']);
   }
 
-  /**
-   * Test that translated strings are rendered for templates where they exist.
-   *
-   * This system has a relatively open localization policy where any translation can be used,
-   * even if the system doesn't allow it in the web UI. Ex: The sysadmin has configured 'fr_FR'
-   * strings. The user has requested 'fr_CA', and we'll fallback to 'fr_CA'.
-   *
-   * @throws \API_Exception|\CRM_Core_Exception
-   * @group locale
-   */
-  public function testRenderTranslatedTemplate_AllowPartialLocales(): void {
-    $cleanup = \CRM_Utils_AutoClean::swapSettings(['partial_locales' => TRUE, 'uiLanguages' => ['en_US']]);
+  public function getLocaleConfigurations(): array {
+    $yesPartials = ['partial_locales' => TRUE, 'uiLanguages' => ['en_US']];
+    $noPartials = ['partial_locales' => FALSE, 'uiLanguages' => ['en_US'], 'format_locale' => 'en_US'];
 
-    $this->individualCreate(['preferred_language' => 'fr_FR']);
-    $contributionID = $this->contributionCreate(['contact_id' => $this->ids['Contact']['individual_0']]);
-    $messageTemplateID = MessageTemplate::get()
-      ->addWhere('is_default', '=', 1)
-      ->addWhere('workflow_name', '=', 'contribution_online_receipt')
-      ->addSelect('id')
-      ->execute()->first()['id'];
+    $allTemplates = [];
+    $allTemplates['*'] = ['subject' => 'Hello', 'html' => 'Looky there!', 'text' => '{contribution.total_amount}'];
+    $allTemplates['fr_FR'] = ['subject' => 'Bonjour', 'html' => 'Voila!', 'text' => '{contribution.total_amount}'];
+    $allTemplates['fr_CA'] = ['subject' => 'Bonjour Canada', 'html' => 'Voila! Canada', 'text' => '{contribution.total_amount}'];
+    $allTemplates['es_PR'] = ['subject' => 'Buenos dias', 'html' => 'Listo', 'text' => '{contribution.total_amount}'];
+    $allTemplates['th_TH'] = ['subject' => 'สวัสดี', 'html' => 'ดังนั้น', 'text' => '{contribution.total_amount}'];
 
-    Translation::save()->setRecords([
-      ['entity_field' => 'msg_subject', 'string' => 'Bonjour'],
-      ['entity_field' => 'msg_html', 'string' => 'Voila!'],
-      ['entity_field' => 'msg_text', 'string' => '{contribution.total_amount}'],
-    ])->setDefaults([
-      'entity_table' => 'civicrm_msg_template',
-      'entity_id' => $messageTemplateID,
-      'status_id:name' => 'active',
-      'language' => 'fr_FR',
-    ])->execute();
+    $onlyTemplates = function(array $locales) use ($allTemplates) {
+      return CRM_Utils_Array::subset($allTemplates, $locales);
+    };
 
-    $messageTemplateFrench = MessageTemplate::get()
-      ->addWhere('is_default', '=', 1)
-      ->addWhere('workflow_name', '=', 'contribution_online_receipt')
-      ->addSelect('id', 'msg_subject', 'msg_html')
-      ->setLanguage('fr_FR')
-      ->setTranslationMode('fuzzy')
-      ->execute()->first();
+    $rendered = [];
+    // $rendered['*'] = ['subject' => 'Hello', 'html' => 'Looky there!', 'text' => '$ 100.00'];
+    $rendered['*'] = ['subject' => 'Hello', 'html' => 'Looky there!', 'text' => '$100.00'];
+    $rendered['fr_FR'] = ['subject' => 'Bonjour', 'html' => 'Voila!', 'text' => '100,00 $US'];
+    $rendered['fr_CA'] = ['subject' => 'Bonjour Canada', 'html' => 'Voila! Canada', 'text' => '100,00 $ US'];
+    $rendered['es_PR'] = ['subject' => 'Buenos dias', 'html' => 'Listo', 'text' => '100.00 $US'];
+    $rendered['th_TH'] = ['subject' => 'สวัสดี', 'html' => 'ดังนั้น', 'text' => 'US$100.00'];
 
-    $this->assertEquals('Bonjour', $messageTemplateFrench['msg_subject']);
-    $this->assertEquals('Voila!', $messageTemplateFrench['msg_html']);
+    $result = [/* settings, templates, preferredLanguage, expectMessage */];
 
-    $rendered = CRM_Core_BAO_MessageTemplate::renderTemplate([
-      'workflow' => 'contribution_online_receipt',
-      'tokenContext' => [
-        'contactId' => $this->ids['Contact']['individual_0'],
-        'contributionId' => $contributionID,
-      ],
-    ]);
-    $this->assertEquals('Bonjour', $rendered['subject']);
-    $this->assertEquals('Voila!', $rendered['html']);
-    $this->assertEquals('100,00 $US', $rendered['text']);
+    $result['fr_FR matches fr_FR (all-tpls; yes-partials)'] = [$yesPartials, $allTemplates, 'fr_FR', $rendered['fr_FR']];
+    $result['fr_FR matches fr_FR (all-tpls; no-partials)'] = [$noPartials, $allTemplates, 'fr_FR', $rendered['fr_FR']];
+    $result['fr_FR falls back to fr_CA (ltd-tpls; yes-partials)'] = [$yesPartials, $onlyTemplates(['*', 'fr_CA']), 'fr_FR', $rendered['fr_CA']];
+    $result['fr_FR falls back to fr_CA (ltd-tpls; no-partials)'] = [$noPartials, $onlyTemplates(['*', 'fr_CA']), 'fr_FR', $rendered['fr_CA']];
 
-    // French Canadian should ALSO pick up French if there
-    //is no specific French Canadian.
-    $rendered = CRM_Core_BAO_MessageTemplate::renderTemplate([
-      'workflow' => 'contribution_online_receipt',
-      'tokenContext' => [
-        'contactId' => $this->ids['Contact']['individual_0'],
-        'contributionId' => $contributionID,
-      ],
-      'language' => 'fr_CA',
-    ]);
-    $this->assertEquals('Bonjour', $rendered['subject']);
-    $this->assertEquals('Voila!', $rendered['html']);
-    // Money is formatted per fr_FR locale as that is the found-template-locale.
-    $this->assertEquals('100,00 $US', $rendered['text']);
+    $result['fr_CA matches fr_CA (all-tpls; yes-partials)'] = [$yesPartials, $allTemplates, 'fr_CA', $rendered['fr_CA']];
+    $result['fr_CA matches fr_CA (all-tpls; no-partials)'] = [$noPartials, $allTemplates, 'fr_CA', $rendered['fr_CA']];
+    $result['fr_CA falls back to fr_FR (ltd-tpls; yes-partials)'] = [$yesPartials, $onlyTemplates(['*', 'fr_FR']), 'fr_CA', $rendered['fr_FR']];
+    $result['fr_CA falls back to fr_FR (ltd-tpls; no-partials)'] = [$noPartials, $onlyTemplates(['*', 'fr_FR']), 'fr_CA', $rendered['fr_FR']];
 
-    Translation::save()->setRecords([
-      ['entity_field' => 'msg_subject', 'string' => 'Bonjour Canada'],
-      ['entity_field' => 'msg_html', 'string' => 'Voila! Canada'],
-      ['entity_field' => 'msg_text', 'string' => '{contribution.total_amount}'],
-    ])->setDefaults([
-      'entity_table' => 'civicrm_msg_template',
-      'entity_id' => $messageTemplateID,
-      'status_id:name' => 'active',
-      'language' => 'fr_CA',
-    ])->execute();
+    $result['th_TH matches th_TH (all-tpls; yes-partials)'] = [$yesPartials, $allTemplates, 'th_TH', $rendered['th_TH']];
+    $result['th_TH falls back to system default (all-tpls; no-partials)'] = [$noPartials, $allTemplates, 'th_TH', $rendered['*']];
+    // ^^ The essence of the `partial_locales` setting -- whether partially-supported locales (th_TH) use mixed-mode or fallback to completely diff locale.
+    $result['th_TH falls back to system default (ltd-tpls; yes-partials)'] = [$yesPartials, $onlyTemplates(['*']), 'th_TH', $rendered['*']];
+    $result['th_TH falls back to system default (ltd-tpls; no-partials)'] = [$noPartials, $onlyTemplates(['*']), 'th_TH', $rendered['*']];
 
-    // But, prefer French Canadian where both exist.
-    $rendered = CRM_Core_BAO_MessageTemplate::renderTemplate([
-      'workflow' => 'contribution_online_receipt',
-      'tokenContext' => [
-        'contactId' => $this->ids['Contact']['individual_0'],
-        'contributionId' => $contributionID,
-      ],
-      'language' => 'fr_CA',
-    ]);
-    $this->assertEquals('Bonjour Canada', $rendered['subject']);
-    $this->assertEquals('Voila! Canada', $rendered['html']);
-    // Note that as there was a native-Canada format the money-formatting is
-    // also subtly different.
-    $this->assertEquals('100,00 $ US', $rendered['text']);
+    return $result;
   }
 
   /**
    * Test that translated strings are rendered for templates where they exist.
    *
-   * This system has a relatively closed localization policy where translations will only be
-   * used if the locale is fully supported by the app. Ex: Even though there are some strings
-   * for 'fr_FR', the language in "Admin=>Localizaton", so we don't use it.
+   * This system has a relatively open localization policy where any translation can be used,
+   * even if the system doesn't allow it in the web UI. Ex: The sysadmin has configured 'fr_FR'
+   * strings. The user has requested 'fr_CA', and we'll fallback to 'fr_CA'.
    *
    * @throws \API_Exception|\CRM_Core_Exception
    * @group locale
+   * @dataProvider getLocaleConfigurations
    */
-  public function testRenderTranslatedTemplate_OnlyFullLocales(): void {
-    $cleanup = \CRM_Utils_AutoClean::swapSettings(['partial_locales' => FALSE, 'uiLanguages' => ['en_US']]);
+  public function testRenderTranslatedTemplate($settings, $templates, $preferredLanguage, $expectRendered): void {
+    if (empty($settings['partial_locales']) && count(\CRM_Core_I18n::languages(FALSE)) <= 1) {
+      $this->markTestIncomplete('Full testing of localization requires l10n data.');
+    }
+    $cleanup = \CRM_Utils_AutoClean::swapSettings($settings);
 
-    $this->individualCreate(['preferred_language' => 'fr_FR']);
+    $this->individualCreate(['preferred_language' => $preferredLanguage]);
     $contributionID = $this->contributionCreate(['contact_id' => $this->ids['Contact']['individual_0']]);
     $messageTemplateID = MessageTemplate::get()
       ->addWhere('is_default', '=', 1)
@@ -164,27 +116,43 @@ class CRM_Core_BAO_MessageTemplateTest extends CiviUnitTestCase {
       ->addSelect('id')
       ->execute()->first()['id'];
 
-    Translation::save()->setRecords([
-      ['entity_field' => 'msg_subject', 'string' => 'Bonjour'],
-      ['entity_field' => 'msg_html', 'string' => 'Voila!'],
-      ['entity_field' => 'msg_text', 'string' => '{contribution.total_amount}'],
-    ])->setDefaults([
-      'entity_table' => 'civicrm_msg_template',
-      'entity_id' => $messageTemplateID,
-      'status_id:name' => 'active',
-      'language' => 'fr_FR',
-    ])->execute();
+    foreach ($templates as $tplLocale => $tplData) {
+      if ($tplLocale === '*') {
+        MessageTemplate::update()
+          ->addWhere('id', '=', $messageTemplateID)
+          ->setValues([
+            'msg_subject' => $tplData['subject'],
+            'msg_html' => $tplData['html'],
+            'msg_text' => $tplData['text'],
+          ])
+          ->execute();
+      }
+      else {
+        Translation::save()->setRecords([
+          ['entity_field' => 'msg_subject', 'string' => $tplData['subject']],
+          ['entity_field' => 'msg_html', 'string' => $tplData['html']],
+          ['entity_field' => 'msg_text', 'string' => $tplData['text']],
+        ])->setDefaults([
+          'entity_table' => 'civicrm_msg_template',
+          'entity_id' => $messageTemplateID,
+          'status_id:name' => 'active',
+          'language' => $tplLocale,
+        ])->execute();
+      }
+    }
 
-    $messageTemplateFrench = MessageTemplate::get()
+    $myMessageTemplate = MessageTemplate::get()
       ->addWhere('is_default', '=', 1)
       ->addWhere('workflow_name', '=', 'contribution_online_receipt')
-      ->addSelect('id', 'msg_subject', 'msg_html')
-      ->setLanguage('fr_FR')
+      ->addSelect('id', 'msg_subject', 'msg_html', 'msg_text')
+      ->setLanguage($preferredLanguage)
       ->setTranslationMode('fuzzy')
       ->execute()->first();
 
-    $this->assertStringNotContainsString('Bonjour', $messageTemplateFrench['msg_subject']);
-    $this->assertStringNotContainsString('Voila!', $messageTemplateFrench['msg_html']);
+    // In our examples, subject+html are constant values, but text has tokens.
+    $this->assertEquals($expectRendered['subject'], $myMessageTemplate['msg_subject']);
+    $this->assertEquals($expectRendered['html'], $myMessageTemplate['msg_html']);
+    $this->assertNotEquals($expectRendered['text'], $myMessageTemplate['msg_text']);
 
     $rendered = CRM_Core_BAO_MessageTemplate::renderTemplate([
       'workflow' => 'contribution_online_receipt',
@@ -193,9 +161,10 @@ class CRM_Core_BAO_MessageTemplateTest extends CiviUnitTestCase {
         'contributionId' => $contributionID,
       ],
     ]);
-    $this->assertStringNotContainsString('Bonjour', $rendered['subject']);
-    $this->assertStringNotContainsString('Voila!', $rendered['html']);
-    $this->assertStringNotContainsString('100,00', $rendered['text']);
+    $this->assertEquals(
+      CRM_Utils_Array::subset($expectRendered, ['subject', 'html', 'text']),
+      CRM_Utils_Array::subset($rendered, ['subject', 'html', 'text'])
+    );
   }
 
   /**