truncate unicode strings better
authordemeritcowboy <demeritcowboy@hotmail.com>
Mon, 26 Oct 2020 23:48:37 +0000 (19:48 -0400)
committerdemeritcowboy <demeritcowboy@hotmail.com>
Tue, 27 Oct 2020 14:13:56 +0000 (10:13 -0400)
CRM/Contact/BAO/Contact.php
tests/phpunit/CRM/Contact/BAO/ContactTest.php

index d258641cb70ae7fe95619484b4f3ca979f12402d..988cab9a5f527e969886de1bf583749514652a1a 100644 (file)
@@ -157,11 +157,18 @@ class CRM_Contact_BAO_Contact extends CRM_Contact_DAO_Contact {
       CRM_Contact_BAO_Individual::format($params, $contact);
     }
 
-    if (strlen($contact->display_name) > 128) {
-      $contact->display_name = substr($contact->display_name, 0, 128);
-    }
-    if (strlen($contact->sort_name) > 128) {
-      $contact->sort_name = substr($contact->sort_name, 0, 128);
+    // Note that copyValues() above might already call this, via
+    // CRM_Utils_String::ellipsify(), but e.g. for Individual it gets put
+    // back or altered by Individual::format() just above, so we need to
+    // check again.
+    // Note also orgs will get ellipsified, but if we do that here then
+    // some existing tests on individual fail.
+    // Also api v3 will enforce org naming length by failing, v4 will truncate.
+    if (mb_strlen($contact->display_name, 'UTF-8') > 128) {
+      $contact->display_name = mb_substr($contact->display_name, 0, 128, 'UTF-8');
+    }
+    if (mb_strlen($contact->sort_name, 'UTF-8') > 128) {
+      $contact->sort_name = mb_substr($contact->sort_name, 0, 128, 'UTF-8');
     }
 
     $privacy = $params['privacy'] ?? NULL;
index b4fc988a67003eff1185ee5152cb2b214e694a9b..075655206d1d07a26fff0e57aff91bd9bee10e2e 100644 (file)
@@ -1656,4 +1656,137 @@ class CRM_Contact_BAO_ContactTest extends CiviUnitTestCase {
     }
   }
 
+  /**
+   * Test that long unicode individual names are truncated properly when
+   * creating sort/display name.
+   *
+   * @dataProvider longUnicodeIndividualNames
+   *
+   * @param array $input
+   * @param array $expected
+   */
+  public function testLongUnicodeIndividualName(array $input, array $expected) {
+    // needs to be passed by reference
+    $params = [
+      'contact_type' => 'Individual',
+      'first_name' => $input['first_name'],
+      'last_name' => $input['last_name'],
+    ];
+    $contact = CRM_Contact_BAO_Contact::add($params);
+
+    $this->assertEquals($expected['sort_name'], $contact->sort_name);
+    $this->assertEquals($expected['display_name'], $contact->display_name);
+
+    $this->contactDelete($contact->id);
+  }
+
+  /**
+   * Data provider for testLongUnicodeIndividualName
+   * @return array
+   */
+  public function longUnicodeIndividualNames():array {
+    return [
+      'much less than 128' => [
+        [
+          'first_name' => 'асдадасда',
+          'last_name' => 'лнплнплнп',
+        ],
+        [
+          'sort_name' => 'лнплнплнп, асдадасда',
+          'display_name' => 'асдадасда лнплнплнп',
+        ],
+      ],
+      'less than 128 but still too big' => [
+        [
+          'first_name' => 'асдадасдашасдадасдашасдадасдашасдадасдашасдадасдашасдадасдаш',
+          'last_name' => 'лнплнплнпшлнплнплнпшлнплнплнпшлнплнплнпшлнплнплнпшлнплнплнпш',
+        ],
+        [
+          'sort_name' => 'лнплнплнпшлнплнплнпшлнплнплнпшлнплнплнпшлнплнплнпшлнплнплнпш, асдадасдашасдадасдашасдадасдашасдадасдашасдадасдашасдадасдаш',
+          'display_name' => 'асдадасдашасдадасдашасдадасдашасдадасдашасдадасдашасдадасдаш лнплнплнпшлнплнплнпшлнплнплнпшлнплнплнпшлнплнплнпшлнплнплнпш',
+        ],
+      ],
+      // note we have to account for the comma and space
+      'equal 128 sort_name' => [
+        [
+          'first_name' => 'асдадасдашасдадасдашасдадасдашасдадасдашасдадасдашасдадасдашасд',
+          'last_name' => 'лнплнплнпшлнплнплнпшлнплнплнпшлнплнплнпшлнплнплнпшлнплнплнпшлнп',
+        ],
+        [
+          'sort_name' => 'лнплнплнпшлнплнплнпшлнплнплнпшлнплнплнпшлнплнплнпшлнплнплнпшлнп, асдадасдашасдадасдашасдадасдашасдадасдашасдадасдашасдадасдашасд',
+          'display_name' => 'асдадасдашасдадасдашасдадасдашасдадасдашасдадасдашасдадасдашасд лнплнплнпшлнплнплнпшлнплнплнпшлнплнплнпшлнплнплнпшлнплнплнпшлнп',
+        ],
+      ],
+      // note we have to account for the space
+      'equal 128 display_name' => [
+        [
+          'first_name' => 'асдадасдашасдадасдашасдадасдашасдадасдашасдадасдашасдадасдашасдa',
+          'last_name' => 'лнплнплнпшлнплнплнпшлнплнплнпшлнплнплнпшлнплнплнпшлнплнплнпшлнп',
+        ],
+        [
+          'sort_name' => 'лнплнплнпшлнплнплнпшлнплнплнпшлнплнплнпшлнплнплнпшлнплнплнпшлнп, асдадасдашасдадасдашасдадасдашасдадасдашасдадасдашасдадасдашасд',
+          'display_name' => 'асдадасдашасдадасдашасдадасдашасдадасдашасдадасдашасдадасдашасдa лнплнплнпшлнплнплнпшлнплнплнпшлнплнплнпшлнплнплнпшлнплнплнпшлнп',
+        ],
+      ],
+      'longer than 128' => [
+        [
+          'first_name' => 'асдадасдашасдадасдашасдадасдашасдадасдашасдадасдашасдадасдашасдадасдаш',
+          'last_name' => 'лнплнплнпшлнплнплнпшлнплнплнпшлнплнплнпшлнплнплнпшлнплнплнпшлнплнплнпш',
+        ],
+        [
+          'sort_name' => 'лнплнплнпшлнплнплнпшлнплнплнпшлнплнплнпшлнплнплнпшлнплнплнпшлнплнплнпш, асдадасдашасдадасдашасдадасдашасдадасдашасдадасдашасдада',
+          'display_name' => 'асдадасдашасдадасдашасдадасдашасдадасдашасдадасдашасдадасдашасдадасдаш лнплнплнпшлнплнплнпшлнплнплнпшлнплнплнпшлнплнплнпшлнплнпл',
+        ],
+      ],
+    ];
+  }
+
+  /**
+   * Test that long unicode org names are truncated properly when creating
+   * sort/display name.
+   *
+   * @dataProvider longUnicodeOrgNames
+   *
+   * @param string $input
+   * @param string $expected
+   */
+  public function testLongUnicodeOrgName(string $input, string $expected) {
+    // needs to be passed by reference
+    $params = [
+      'contact_type' => 'Organization',
+      'organization_name' => $input,
+    ];
+    $contact = CRM_Contact_BAO_Contact::add($params);
+
+    $this->assertEquals($expected, $contact->sort_name);
+    $this->assertEquals($expected, $contact->display_name);
+
+    $this->contactDelete($contact->id);
+  }
+
+  /**
+   * Data provider for testLongUnicodeOrgName
+   * @return array
+   */
+  public function longUnicodeOrgNames():array {
+    return [
+      'much less than 128' => [
+        'асдадасда шшшшшшшшшш',
+        'асдадасда шшшшшшшшшш',
+      ],
+      'less than 128 but still too big' => [
+        'асдадасда шшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшасд',
+        'асдадасда шшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшасд',
+      ],
+      'equal 128' => [
+        'асдадасда шшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшасд',
+        'асдадасда шшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшасд',
+      ],
+      'longer than 128' => [
+        'асдадасда шшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшасдасд',
+        'асдадасда шшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшшш...',
+      ],
+    ];
+  }
+
 }