Tokens - "|upper" and "|lower" should work differently in text+html
authorTim Otten <totten@civicrm.org>
Fri, 3 Mar 2023 09:38:29 +0000 (01:38 -0800)
committerTim Otten <totten@civicrm.org>
Fri, 3 Mar 2023 10:23:15 +0000 (02:23 -0800)
Civi/Token/StandardFilters.php
tests/phpunit/Civi/Token/TokenProcessorTest.php

index 69f1b867835997a9c1bc2a2ab42355a2a8989904..54c4f3996e3f3886d054ef30c11886742fbcc2ab 100644 (file)
@@ -24,11 +24,29 @@ class StandardFilters {
    * @return mixed
    */
   public static function upper($value, array $filter, string $format) {
-    return mb_strtoupper($value);
+    switch ($format) {
+      case 'text/plain':
+        return mb_strtoupper($value);
+
+      case 'text/html':
+        return \CRM_Utils_XML::filterMarkupText((string) $value, 'mb_strtoupper');
+
+      default:
+        throw new \CRM_Core_Exception(sprintf('Filter %s does not support format %s', __FUNCTION__, $format));
+    }
   }
 
   public static function lower($value, array $filter, string $format) {
-    return mb_strtolower($value);
+    switch ($format) {
+      case 'text/plain':
+        return mb_strtolower($value);
+
+      case 'text/html':
+        return \CRM_Utils_XML::filterMarkupText((string) $value, 'mb_strtolower');
+
+      default:
+        throw new \CRM_Core_Exception(sprintf('Filter %s does not support format %s', __FUNCTION__, $format));
+    }
   }
 
   public static function boolean($value, array $filter, string $format) {
index ba90ef4fb8003ca92f2eb954b9003744ccff2084..053e50a814629b07591093026cb258e64970534f 100644 (file)
@@ -384,20 +384,79 @@ class TokenProcessorTest extends \CiviUnitTestCase {
     $this->assertEquals(1, $this->counts['onEvalTokens']);
   }
 
-  public function testFilter(): void {
-    $exampleTokens['foo_bar']['whiz_bang'] = 'Some Text';
-    $exampleTokens['foo_bar']['whiz_bop'] = '';
-    $exampleMessages = [
-      'This is {foo_bar.whiz_bang}.' => 'This is Some Text.',
-      'This is {foo_bar.whiz_bang|lower}...' => 'This is some text...',
-      'This is {foo_bar.whiz_bang|upper}!' => 'This is SOME TEXT!',
-      'This is {foo_bar.whiz_bang|boolean}!' => 'This is 1!',
-      'This is {foo_bar.whiz_bop|boolean}!' => 'This is 0!',
-      'This is {foo_bar.whiz_bang|default:"bang"}.' => 'This is Some Text.',
-      'This is {foo_bar.whiz_bop|default:"bop"}.' => 'This is bop.',
+  public function getFilterExamples() {
+    $exampleTokens = [
+      // All the "{my_text.*}" tokens will be treated as plain-text ("text/plain").
+      'my_text' => [
+        'whiz_bang' => 'Some Text',
+        'empty_string' => '',
+        'emotive' => 'The Test :>',
+      ],
+      // All the "{my_rich_text.*}" tokens will be treated as markup ("text/html").
+      'my_rich_text' => [
+        'whiz_bang' => '<b>Some &ldquo;Text&rdquo;</b>',
+        'empty_string' => '',
+        'and_such' => '<strong>testing &amp; such</strong>',
+      ],
+    ];
+
+    $testCases = [];
+    $testCases['TextMessages with TextData'] = [
+      'text/plain',
+      [
+        'This is {my_text.whiz_bang}.' => 'This is Some Text.',
+        'This is {my_text.whiz_bang|lower}...' => 'This is some text...',
+        'This is {my_text.whiz_bang|upper}!' => 'This is SOME TEXT!',
+        'This is {my_text.whiz_bang|boolean}!' => 'This is 1!',
+        'This is {my_text.empty_string|boolean}!' => 'This is 0!',
+        'This is {my_text.whiz_bang|default:"bang"}.' => 'This is Some Text.',
+        'This is {my_text.empty_string|default:"bop"}.' => 'This is bop.',
+      ],
+      $exampleTokens,
+    ];
+    $testCases['HtmlMessages with HtmlData'] = [
+      'text/html',
+      [
+        'This is {my_rich_text.whiz_bang}.' => 'This is <b>Some &ldquo;Text&rdquo;</b>.',
+        'This is {my_rich_text.whiz_bang|lower}...' => 'This is <b>some &ldquo;text&rdquo;</b>...',
+        'This is {my_rich_text.whiz_bang|upper}!' => 'This is <b>SOME &ldquo;TEXT&rdquo;</b>!',
+        'This is {my_rich_text.whiz_bang|boolean}!' => 'This is 1!',
+        'This is {my_rich_text.empty_string|boolean}!' => 'This is 0!',
+        'This is {my_rich_text.whiz_bang|default:"bang"}.' => 'This is <b>Some &ldquo;Text&rdquo;</b>.',
+        'This is {my_rich_text.empty_string|default:"bop"}.' => 'This is bop.',
+      ],
+      $exampleTokens,
     ];
-    // We expect 7 messages to be parsed 2 times each - ie 14 times.
-    $expectExampleCount = 14;
+    $testCases['HtmlMessages with TextData'] = [
+      'text/html',
+      [
+        'This is {my_text.emotive}...' => 'This is The Test :&gt;...',
+        'This is {my_text.emotive|lower}...' => 'This is the test :&gt;...',
+        'This is {my_text.emotive|upper}!' => 'This is THE TEST :&gt;!',
+      ],
+      $exampleTokens,
+    ];
+    $testCases['TextMessages with HtmlData'] = [
+      'text/plain',
+      [
+        'This is {my_rich_text.and_such}...' => 'This is testing & such...',
+        'This is {my_rich_text.and_such|lower}...' => 'This is testing & such...',
+        'This is {my_rich_text.and_such|upper}!' => 'This is TESTING & SUCH!',
+      ],
+      $exampleTokens,
+    ];
+    return $testCases;
+  }
+
+  /**
+   * @param string $messageFormat
+   * @param array $exampleMessages
+   * @param array $exampleTokens
+   * @return void
+   * @dataProvider getFilterExamples
+   */
+  public function testFilters(string $messageFormat, array $exampleMessages, array $exampleTokens): void {
+    $expectExampleCount = 2 * count($exampleMessages);
     $actualExampleCount = 0;
 
     foreach ($exampleMessages as $inputMessage => $expectOutput) {
@@ -406,9 +465,10 @@ class TokenProcessorTest extends \CiviUnitTestCase {
           'controller' => __CLASS__,
           'smarty' => $useSmarty,
         ]);
-        $p->addMessage('example', $inputMessage, 'text/plain');
+        $p->addMessage('example', $inputMessage, $messageFormat);
         $p->addRow()
-          ->format('text/plain')->tokens($exampleTokens);
+          ->format('text/plain')->tokens(\CRM_Utils_Array::subset($exampleTokens, ['my_text']))
+          ->format('text/html')->tokens(\CRM_Utils_Array::subset($exampleTokens, ['my_rich_text']));
         foreach ($p->evaluate()->getRows() as $row) {
           $this->assertEquals($expectOutput, $row->render('example'));
           $actualExampleCount++;