Dave's tests
authorlarssandergreen <lars@wildsight.ca>
Wed, 26 Apr 2023 20:33:15 +0000 (14:33 -0600)
committerlarssandergreen <lars@wildsight.ca>
Wed, 26 Apr 2023 20:33:15 +0000 (14:33 -0600)
tests/phpunit/CRM/Activity/Form/ActivityViewTest.php

index 5215221919225d4312a67b979c943ca24aa427d1..ec5eef08e8d01afe45095c731de55b041f7c8f98 100644 (file)
@@ -5,6 +5,41 @@
  */
 class CRM_Activity_Form_ActivityViewTest extends CiviUnitTestCase {
 
+  /**
+   * @var int
+   */
+  protected $source_contact_id;
+
+  /**
+   * @var int
+   */
+  protected $target_contact_id;
+
+  /**
+   * @var int
+   */
+  protected $mailing_id;
+
+  /**
+   * @var int
+   */
+  protected $case_id;
+
+  public function setUp(): void {
+    parent::setUp();
+    $this->source_contact_id = $this->createLoggedInUser();
+    $this->target_contact_id = $this->individualCreate([], 0, TRUE);
+    $this->mailing_id = $this->callAPISuccess('Mailing', 'create', [
+      'subject' => 'A Mailing Subject',
+      // We need the newlines to be early since this text gets truncated
+      'body_text' => "This\naddress\n\nis not ours: {domain.address}.\n\nDo not click this link {action.optOutUrl}.",
+      'name' => 'amailing',
+      'created_id' => $this->source_contact_id,
+    ]);
+    CRM_Core_BAO_ConfigSetting::enableComponent('CiviCase');
+    $this->case_id = $this->createCase($this->target_contact_id, $this->source_contact_id)->id;
+  }
+
   /**
    * Cleanup after class.
    *
@@ -12,10 +47,15 @@ class CRM_Activity_Form_ActivityViewTest extends CiviUnitTestCase {
    */
   public function tearDown(): void {
     $tablesToTruncate = [
+      'civicrm_case_activity',
+      'civicrm_case_contact',
       'civicrm_activity',
       'civicrm_activity_contact',
+      'civicrm_case',
+      'civicrm_contact',
     ];
     $this->quickCleanup($tablesToTruncate);
+    CRM_Core_BAO_ConfigSetting::disableComponent('CiviCase');
     parent::tearDown();
   }
 
@@ -81,4 +121,432 @@ class CRM_Activity_Form_ActivityViewTest extends CiviUnitTestCase {
     $this->assertEquals($expected, $templateVar);
   }
 
+  /**
+   * Test that the text is neither squished nor double-spaced.
+   * @dataProvider activityTypesProvider
+   * @dataProvider caseActivityTypesProvider
+   * @param array $input
+   * @param string $expected
+   */
+  public function testNewlinesLookRight(array $input, string $expected) {
+    if (!empty($input['skip'])) {
+      $this->markTestSkipped('This test is boring.');
+      return;
+    }
+
+    $activity = $this->activityCreate([
+      'source_contact_id' => $this->source_contact_id,
+      'target_contact_id' => $this->target_contact_id,
+      'details' => $input['details'],
+      'activity_type_id' => $input['activity_type'],
+      'source_record_id' => ($input['activity_type'] === 'Bulk Email' ? $this->mailing_id : NULL),
+      'case_id' => (strpos($input['url'], 'caseid') === FALSE ? NULL : $this->case_id),
+    ]);
+
+    // We have to replace these at runtime because dataproviders are
+    // evaluated even before setUp() runs.
+    $input['url'] = str_replace('%%id%%', $activity['id'], $input['url']);
+    $input['url'] = str_replace('%%aid%%', $activity['id'], $input['url']);
+    $input['url'] = str_replace('%%cid%%', $this->source_contact_id, $input['url']);
+    $input['url'] = str_replace('%%atype%%', CRM_Core_PseudoConstant::getKey('CRM_Activity_BAO_Activity', 'activity_type_id', $input['activity_type']), $input['url']);
+    $input['url'] = str_replace('%%caseid%%', $this->case_id, $input['url']);
+
+    $this->setRequestVars($input['url']);
+
+    $item = CRM_Core_Invoke::getItem([$_GET['q']]);
+    ob_start();
+    CRM_Core_Invoke::runItem($item);
+    $contents = ob_get_clean();
+
+    $this->unsetRequestVars($input['url']);
+
+    // See note in activityTypesProvider why we do this
+    $contents = str_replace(["\r", "\n"], '', $contents);
+
+    $this->assertStringContainsString($expected, $contents);
+  }
+
+  /**
+   * data provider for testNewlinesLookRight() for non-case activities
+   *
+   * Unfortunately there seem to be differences in the output of `purify` on
+   * unix vs windows, and also on unix it seems to even work differently in
+   * tests than when run normally! So we strip all chr(10) and chr(13) when
+   * comparing the result.
+   *
+   * @return array
+   */
+  public function activityTypesProvider(): array {
+    $data = [
+      'meeting-text' => [
+        [
+          'activity_type' => 'Meeting',
+          'url' => 'civicrm/activity?atype=%%atype%%&action=view&reset=1&id=%%id%%&cid=%%cid%%&context=activity',
+          'details' => <<<'ENDDETAILS'
+This is text only
+and has two consecutive lines.
+
+And one blank line.
+ENDDETAILS
+        ],
+        '<span class="crm-frozen-field">This is text only<br />and has two consecutive lines.<br /><br />And one blank line.</span>',
+      ],
+
+      'bulkemail-text' => [
+        [
+          'activity_type' => 'Bulk Email',
+          'url' => 'civicrm/activity/view?atype=%%atype%%&action=view&reset=1&id=%%id%%&cid=%%cid%%&context=activity',
+          'details' => <<<'ENDDETAILS'
+This is text only
+and has two consecutive lines.
+
+And one blank line.
+ENDDETAILS
+        ],
+        // Note this is the summary of the actual bulk mailing text. The above details are a bit irrelevant for what we're testing here.
+        '<td class="label nowrap">Text Message</td><td>This<br />address<br /><br />is not ours:...<br />',
+      ],
+
+      'email-text' => [
+        [
+          'activity_type' => 'Email',
+          'url' => 'civicrm/activity/view?atype=%%atype%%&action=view&reset=1&id=%%id%%&cid=%%cid%%&context=activity',
+          'details' => <<<'ENDDETAILS'
+This is text only
+and has two consecutive lines.
+
+And one blank line.
+ENDDETAILS
+        ],
+        '<td class="view-value report">                   This is text only<br />and has two consecutive lines.<br /><br />And one blank line.',
+      ],
+
+      'inbound-text' => [
+        [
+          'activity_type' => 'Inbound Email',
+          'url' => 'civicrm/contact/view/activity?atype=%%atype%%&action=view&reset=1&id=%%id%%&cid=%%cid%%&context=activity',
+          'details' => <<<'ENDDETAILS'
+This is text only
+and has two consecutive lines.
+
+And one blank line.
+ENDDETAILS
+        ],
+        '<span class="crm-frozen-field">This is text only<br />and has two consecutive lines.<br /><br />And one blank line.</span>',
+      ],
+
+      // Now html only
+      'meeting-html' => [
+        [
+          'activity_type' => 'Meeting',
+          'url' => 'civicrm/activity?atype=%%atype%%&action=view&reset=1&id=%%id%%&cid=%%cid%%&context=activity',
+          'details' => <<<'ENDDETAILS'
+<p>This is html only</p>
+
+<p>And it usually looks like this.</p>
+
+<p>With p&#39;s and newlines between the p&#39;s.</p>
+ENDDETAILS
+        ],
+        '<span class="crm-frozen-field"><p>This is html only</p><p>And it usually looks like this.</p><p>With p\'s and newlines between the p\'s.</p></span>',
+      ],
+
+      'bulkemail-html' => [
+        [
+          'activity_type' => 'Bulk Email',
+          'url' => 'civicrm/activity/view?atype=%%atype%%&action=view&reset=1&id=%%id%%&cid=%%cid%%&context=activity',
+          'details' => <<<'ENDDETAILS'
+<p>This is html only</p>
+
+<p>And it usually looks like this.</p>
+
+<p>With p&#39;s and newlines between the p&#39;s.</p>
+ENDDETAILS
+        ],
+        // Note this is the summary of the actual bulk mailing text. The above details are a bit irrelevant for what we're testing here.
+        '<td class="label nowrap">Text Message</td><td>This<br />address<br /><br />is not ours:...<br />',
+      ],
+
+      'email-html' => [
+        [
+          'activity_type' => 'Email',
+          'url' => 'civicrm/activity/view?atype=%%atype%%&action=view&reset=1&id=%%id%%&cid=%%cid%%&context=activity',
+          'details' => <<<'ENDDETAILS'
+<p>This is html only</p>
+
+<p>And it usually looks like this.</p>
+
+<p>With p&#39;s and newlines between the p&#39;s.</p>
+ENDDETAILS
+        ],
+        '<td class="view-value report">                   <p>This is html only</p><p>And it usually looks like this.</p><p>With p\'s and newlines between the p\'s.</p>',
+      ],
+
+      'inbound-html' => [
+        [
+          'activity_type' => 'Inbound Email',
+          'url' => 'civicrm/contact/view/activity?atype=%%atype%%&action=view&reset=1&id=%%id%%&cid=%%cid%%&context=activity',
+          // This is probably unusual in real life. It would almost always be mixed. But there's nothing to stop custom code from creating these.
+          'details' => <<<'ENDDETAILS'
+<p>This is html only</p>
+
+<p>And it usually looks like this.</p>
+
+<p>With p&#39;s and newlines between the p&#39;s.</p>
+ENDDETAILS
+        ],
+        '<span class="crm-frozen-field"><p>This is html only</p><p>And it usually looks like this.</p><p>With p\'s and newlines between the p\'s.</p></span>',
+      ],
+
+      // Now mixed with text first
+      'meeting-mixed-text' => [
+        [
+          'activity_type' => 'Meeting',
+          'url' => 'civicrm/activity?atype=%%atype%%&action=view&reset=1&id=%%id%%&cid=%%cid%%&context=activity',
+          'details' => <<<'ENDDETAILS'
+-ALTERNATIVE ITEM 0-
+This is mixed
+and has two consecutive lines.
+
+And one blank line.
+-ALTERNATIVE ITEM 1-
+<p>This is mixed<br />
+and has two consecutive lines.</p>
+
+<p>And one blank line.</p>
+-ALTERNATIVE END-
+ENDDETAILS
+        ],
+        'This is mixed<br />and has two consecutive lines.<br /><br />And one blank line.',
+      ],
+
+      'bulkemail-mixed-text' => [
+        [
+          'activity_type' => 'Bulk Email',
+          'url' => 'civicrm/activity/view?atype=%%atype%%&action=view&reset=1&id=%%id%%&cid=%%cid%%&context=activity',
+          'details' => <<<'ENDDETAILS'
+-ALTERNATIVE ITEM 0-
+This is mixed
+and has two consecutive lines.
+
+And one blank line.
+-ALTERNATIVE ITEM 1-
+<p>This is mixed<br />
+and has two consecutive lines.</p>
+
+<p>And one blank line.</p>
+-ALTERNATIVE END-
+ENDDETAILS
+        ],
+        // Note this is the summary of the actual bulk mailing text. The above details are a bit irrelevant for what we're testing here.
+        '<td class="label nowrap">Text Message</td><td>This<br />address<br /><br />is not ours:...<br />',
+      ],
+
+      'email-mixed-text' => [
+        [
+          'activity_type' => 'Email',
+          'url' => 'civicrm/activity/view?atype=%%atype%%&action=view&reset=1&id=%%id%%&cid=%%cid%%&context=activity',
+          'details' => <<<'ENDDETAILS'
+-ALTERNATIVE ITEM 0-
+This is mixed
+and has two consecutive lines.
+
+And one blank line.
+-ALTERNATIVE ITEM 1-
+<p>This is mixed<br />
+and has two consecutive lines.</p>
+
+<p>And one blank line.</p>
+-ALTERNATIVE END-
+ENDDETAILS
+        ],
+        '<td class="view-value report">                   <br />This is mixed<br />and has two consecutive lines.<br /><br />And one blank line.<br />',
+      ],
+
+      'inbound-mixed-text' => [
+        [
+          'activity_type' => 'Inbound Email',
+          'url' => 'civicrm/contact/view/activity?atype=%%atype%%&action=view&reset=1&id=%%id%%&cid=%%cid%%&context=activity',
+          'details' => <<<'ENDDETAILS'
+-ALTERNATIVE ITEM 0-
+This is mixed
+and has two consecutive lines.
+
+And one blank line.
+-ALTERNATIVE ITEM 1-
+<p>This is mixed<br />
+and has two consecutive lines.</p>
+
+<p>And one blank line.</p>
+-ALTERNATIVE END-
+ENDDETAILS
+        ],
+        '<td class="view-value">       <br />This is mixed<br />and has two consecutive lines.<br /><br />And one blank line.<br />',
+      ],
+
+      // Now mixed with html first
+      'meeting-mixed-html' => [
+        [
+          'activity_type' => 'Meeting',
+          'url' => 'civicrm/activity?atype=%%atype%%&action=view&reset=1&id=%%id%%&cid=%%cid%%&context=activity',
+          'details' => <<<'ENDDETAILS'
+-ALTERNATIVE ITEM 0-
+<p>This is mixed<br />
+and has two consecutive lines.</p>
+
+<p>And one blank line.</p>
+-ALTERNATIVE ITEM 1-
+This is mixed
+and has two consecutive lines.
+
+And one blank line.
+-ALTERNATIVE END-
+ENDDETAILS
+        ],
+        '<td class="view-value">       <p>This is mixed<br />and has two consecutive lines.</p><p>And one blank line.</p>',
+      ],
+
+      'bulkemail-mixed-html' => [
+        [
+          'activity_type' => 'Bulk Email',
+          'url' => 'civicrm/activity/view?atype=%%atype%%&action=view&reset=1&id=%%id%%&cid=%%cid%%&context=activity',
+          'details' => <<<'ENDDETAILS'
+-ALTERNATIVE ITEM 0-
+<p>This is mixed<br />
+and has two consecutive lines.</p>
+
+<p>And one blank line.</p>
+-ALTERNATIVE ITEM 1-
+This is mixed
+and has two consecutive lines.
+
+And one blank line.
+-ALTERNATIVE END-
+ENDDETAILS
+        ],
+        // Note this is the summary of the actual bulk mailing text. The above details are a bit irrelevant for what we're testing here.
+        '<td class="label nowrap">Text Message</td><td>This<br />address<br /><br />is not ours:...<br />',
+      ],
+
+      'email-mixed-html' => [
+        [
+          'activity_type' => 'Email',
+          'url' => 'civicrm/activity/view?atype=%%atype%%&action=view&reset=1&id=%%id%%&cid=%%cid%%&context=activity',
+          'details' => <<<'ENDDETAILS'
+-ALTERNATIVE ITEM 0-
+<p>This is mixed<br />
+and has two consecutive lines.</p>
+
+<p>And one blank line.</p>
+-ALTERNATIVE ITEM 1-
+This is mixed
+and has two consecutive lines.
+
+And one blank line.
+-ALTERNATIVE END-
+ENDDETAILS
+        ],
+        '<p>This is mixed<br />and has two consecutive lines.</p><p>And one blank line.</p>',
+      ],
+
+      'inbound-mixed-html' => [
+        [
+          'activity_type' => 'Inbound Email',
+          'url' => 'civicrm/contact/view/activity?atype=%%atype%%&action=view&reset=1&id=%%id%%&cid=%%cid%%&context=activity',
+          'details' => <<<'ENDDETAILS'
+-ALTERNATIVE ITEM 0-
+<p>This is mixed<br />
+and has two consecutive lines.</p>
+
+<p>And one blank line.</p>
+-ALTERNATIVE ITEM 1-
+This is mixed
+and has two consecutive lines.
+
+And one blank line.
+-ALTERNATIVE END-
+ENDDETAILS
+        ],
+        '<p>This is mixed<br />and has two consecutive lines.</p><p>And one blank line.</p>',
+      ],
+    ];
+
+    // The output of these is wrong, but they are very rare and it has always
+    // been wrong, so just skip these tests. But we want them to be present in
+    // the array because they are used in caseActivityTypesProvider correctly.
+    $data['meeting-text'][0]['skip'] = TRUE;
+    $data['meeting-mixed-text'][0]['skip'] = TRUE;
+    return $data;
+  }
+
+  /**
+   * data provider for testNewlinesLookRight() for case activities
+   * @return array
+   */
+  public function caseActivityTypesProvider(): array {
+    // We want the same set as non-case, but the url is different, and expected results might change.
+    $data = $this->activityTypesProvider();
+    $newData = [];
+    foreach ($data as $key => $value) {
+      $newData['case-' . $key] = $data[$key];
+      // The url is always the same for case, despite there being places in
+      // civi that give a non-case link to the activity, but those are bugs
+      // IMO since can lead to data loss.
+      $newData['case-' . $key][0]['url'] = 'civicrm/case/activity/view?reset=1&aid=%%id%%&cid=%%cid%%&caseid=%%caseid%%';
+    }
+    $newData['case-meeting-text'][0]['skip'] = FALSE;
+    $newData['case-meeting-text'][1] = 'This is text only<br />and has two consecutive lines.<br /><br />And one blank line.';
+    $newData['case-bulkemail-text'][1] = 'This is text only<br />and has two consecutive lines.<br /><br />And one blank line.';
+    $newData['case-email-text'][1] = 'This is text only<br />and has two consecutive lines.<br /><br />And one blank line.';
+    $newData['case-inbound-text'][1] = 'This is text only<br />and has two consecutive lines.<br /><br />And one blank line.';
+
+    $newData['case-meeting-html'][1] = "<p>This is html only</p><p>And it usually looks like this.</p><p>With p's and newlines between the p's.</p>";
+    $newData['case-bulkemail-html'][1] = "<p>This is html only</p><p>And it usually looks like this.</p><p>With p's and newlines between the p's.</p>";
+    $newData['case-email-html'][1] = "<p>This is html only</p><p>And it usually looks like this.</p><p>With p's and newlines between the p's.</p>";
+    $newData['case-inbound-html'][1] = "<p>This is html only</p><p>And it usually looks like this.</p><p>With p's and newlines between the p's.</p>";
+
+    $newData['case-meeting-mixed-text'][0]['skip'] = FALSE;
+    $newData['case-meeting-mixed-text'][1] = 'This is mixed<br />and has two consecutive lines.<br /><br />And one blank line.';
+    $newData['case-bulkemail-mixed-text'][1] = 'This is mixed<br />and has two consecutive lines.<br /><br />And one blank line.';
+    $newData['case-email-mixed-text'][1] = 'This is mixed<br />and has two consecutive lines.<br /><br />And one blank line.';
+    $newData['case-inbound-mixed-text'][1] = 'This is mixed<br />and has two consecutive lines.<br /><br />And one blank line.';
+
+    $newData['case-meeting-mixed-html'][1] = '<p>This is mixed<br />and has two consecutive lines.</p><p>And one blank line.</p>';
+    $newData['case-bulkemail-mixed-html'][1] = '<p>This is mixed<br />and has two consecutive lines.</p><p>And one blank line.</p>';
+    $newData['case-email-mixed-html'][1] = '<p>This is mixed<br />and has two consecutive lines.</p><p>And one blank line.</p>';
+    $newData['case-inbound-mixed-html'][1] = '<p>This is mixed<br />and has two consecutive lines.</p><p>And one blank line.</p>';
+
+    return $newData;
+  }
+
+  /**
+   * Invoke and preProcess often need these set.
+   * @param string $url
+   */
+  private function setRequestVars(string $url): void {
+    $_SERVER['REQUEST_URI'] = $url;
+    $urlParts = explode('?', $url);
+    $_GET['q'] = $urlParts[0];
+
+    $parsed = [];
+    parse_str($urlParts[1], $parsed);
+    foreach ($parsed as $param => $value) {
+      $_GET[$param] = $value;
+      $_REQUEST[$param] = $value;
+    }
+  }
+
+  /**
+   * @param string $url
+   */
+  private function unsetRequestVars(string $url): void {
+    unset($_GET['q']);
+    $urlParts = explode('?', $url);
+    $parsed = [];
+    parse_str($urlParts[1], $parsed);
+    foreach ($parsed as $param => $value) {
+      unset($_GET[$param], $_REQUEST[$param]);
+    }
+  }
+
 }