CRM-14476 - CRM_Case_BAO_CaseType - Add test for XML<=>array conversions. Fix corner...
authorTim Otten <totten@civicrm.org>
Tue, 3 Jun 2014 03:32:21 +0000 (20:32 -0700)
committerTim Otten <totten@civicrm.org>
Tue, 3 Jun 2014 06:19:09 +0000 (23:19 -0700)
CRM/Case/BAO/CaseType.php
tests/phpunit/CRM/Case/BAO/CaseTypeTest.php [new file with mode: 0644]

index 21a3f1e987b80f1fb75e95e91f75b80a8ce62b58..6fea8d02f46e18215cbe3fcde72b881c9763f137 100644 (file)
@@ -91,7 +91,7 @@ class CRM_Case_BAO_CaseType extends CRM_Case_DAO_CaseType {
     $xmlFile = '<?xml version="1.0" encoding="iso-8859-1" ?>' . "\n\n<CaseType>\n";
     $xmlFile .= "<name>{$name}</name>\n";
 
-    if (!empty($definition['activityTypes'])) {
+    if (isset($definition['activityTypes'])) {
       $xmlFile .= "<ActivityTypes>\n";
       foreach ($definition['activityTypes'] as $values) {
         $xmlFile .= "<ActivityType>\n";
@@ -103,7 +103,7 @@ class CRM_Case_BAO_CaseType extends CRM_Case_DAO_CaseType {
       $xmlFile .= "</ActivityTypes>\n";
     }
 
-    if (!empty($definition['activitySets'])) {
+    if (isset($definition['activitySets'])) {
       $xmlFile .= "<ActivitySets>\n";
       foreach ($definition['activitySets'] as $k => $val) {
         $xmlFile .= "<ActivitySet>\n";
@@ -132,7 +132,7 @@ class CRM_Case_BAO_CaseType extends CRM_Case_DAO_CaseType {
       $xmlFile .= "</ActivitySets>\n";
     }
 
-    if (!empty($definition['caseRoles'])) {
+    if (isset($definition['caseRoles'])) {
       $xmlFile .= "<CaseRoles>\n";
       foreach ($definition['caseRoles'] as $values) {
         $xmlFile .= "<RelationshipType>\n";
@@ -161,32 +161,39 @@ class CRM_Case_BAO_CaseType extends CRM_Case_DAO_CaseType {
     $definition = array();
 
     // set activity types
-    $activityTypes = json_decode(json_encode($xml->ActivityTypes), TRUE);
-    $definition['activityTypes'] = $activityTypes['ActivityType'];
-
-    // set activity sets
-    $activitySets = json_decode(json_encode($xml->ActivitySets), TRUE);
-
-    // hack to fix the case when we have only one activityset
-    if (!empty($activitySets['ActivitySet']['name'])) {
-      $temp = $activitySets['ActivitySet'];
-      $activitySets['ActivitySet'] = array($temp);
+    if (isset($xml->ActivityTypes)) {
+      $definition['activityTypes'] = array();
+      foreach ($xml->ActivityTypes->ActivityType as $activityTypeXML) {
+        $definition['activityTypes'][] = json_decode(json_encode($activityTypeXML), TRUE);
+      }
     }
 
-    foreach ($activitySets['ActivitySet'] as $key => $value) {
-      foreach ($value as $k => $val) {
-        if ( $k == 'ActivityTypes') {
-          $definition['activitySets'][$key]['activityTypes'] = array_pop(array_values($val));
-        }
-        else {
-          $definition['activitySets'][$key][$k] = $val;
+    // set activity sets
+    if (isset($xml->ActivitySets)) {
+      $definition['activitySets'] = array();
+      foreach ($xml->ActivitySets->ActivitySet as $activitySetXML) {
+        // parse basic properties
+        $activitySet = json_decode(json_encode($activitySetXML), TRUE);
+        unset($activitySet['ActivityTypes']); // not parsed reliably (eg single-tag vs multi-tag)
+
+        // parse activity-types
+        if (isset($activitySetXML->ActivityTypes)) {
+          $activitySet['activityTypes'] = array();
+          foreach ($activitySetXML->ActivityTypes->ActivityType as $activityTypeXML) {
+            $activitySet['activityTypes'][] = json_decode(json_encode($activityTypeXML), TRUE);
+          }
         }
+        $definition['activitySets'][] = $activitySet;
       }
     }
 
     // set case roles
-    $caseRoles = json_decode(json_encode($xml->CaseRoles), TRUE);
-    $definition['caseRoles'] = $caseRoles['RelationshipType'];
+    if (isset($xml->CaseRoles)) {
+      $definition['caseRoles'] = array();
+      foreach ($xml->CaseRoles->RelationshipType as $caseRoleXml) {
+        $definition['caseRoles'][] = json_decode(json_encode($caseRoleXml), TRUE);
+      }
+    }
 
     return $definition;
   }
diff --git a/tests/phpunit/CRM/Case/BAO/CaseTypeTest.php b/tests/phpunit/CRM/Case/BAO/CaseTypeTest.php
new file mode 100644 (file)
index 0000000..d26c9dd
--- /dev/null
@@ -0,0 +1,262 @@
+<?php
+require_once 'CiviTest/CiviUnitTestCase.php';
+
+/**
+ * Class CRM_Case_BAO_CaseTypeTest
+ */
+class CRM_Case_BAO_CaseTypeTest extends CiviUnitTestCase {
+
+  /**
+   * Provide a series of test-scenarios. Each scenario includes a case-type defintion expressed as
+   * JSON and equivalent XML.
+   *
+   * @return array
+   */
+  function definitionProvider() {
+    $fixtures['empty-defn'] = array(
+      'json' => json_encode(array()),
+      'xml' => '<?xml version="1.0" encoding="iso-8859-1" ?>
+<CaseType>
+  <name>Housing Support</name>
+</CaseType>
+      ',
+    );
+
+    $fixtures['empty-lists'] = array(
+      'json' => json_encode(array(
+        'activitySets' => array(),
+        'activityTypes' => array(),
+        'caseRoles' => array(),
+      )),
+      'xml' => '<?xml version="1.0" encoding="iso-8859-1" ?>
+<CaseType>
+  <name>Housing Support</name>
+  <ActivityTypes></ActivityTypes>
+  <ActivitySets></ActivitySets>
+  <CaseRoles></CaseRoles>
+</CaseType>
+      ',
+    );
+
+    $fixtures['one-item-in-each'] = array(
+      'json' => json_encode(array(
+        'activityTypes' => array(
+          array('name' => 'First act'),
+        ),
+        'activitySets' => array(
+          array(
+            'name' => 'set1',
+            'label' => 'Label 1',
+            'timeline' => 'true',
+            'activityTypes' => array(
+              array('name' => 'Open Case', 'status' => 'Completed'),
+            ),
+          ),
+        ),
+        'caseRoles' => array(
+          array('name' => 'First role', 'creator' => 1, 'manager' => 1),
+        ),
+      )),
+      'xml' => '<?xml version="1.0" encoding="iso-8859-1" ?>
+<CaseType>
+  <name>Housing Support</name>
+  <ActivityTypes>
+    <ActivityType>
+      <name>First act</name>
+    </ActivityType>
+  </ActivityTypes>
+  <ActivitySets>
+    <ActivitySet>
+      <name>set1</name>
+      <label>Label 1</label>
+      <timeline>true</timeline>
+      <ActivityTypes>
+        <ActivityType>
+          <name>Open Case</name>
+          <status>Completed</status>
+        </ActivityType>
+      </ActivityTypes>
+    </ActivitySet>
+  </ActivitySets>
+  <CaseRoles>
+    <RelationshipType>
+      <name>First role</name>
+      <creator>1</creator>
+      <manager>1</manager>
+    </RelationshipType>
+  </CaseRoles>
+</CaseType>
+      ',
+    );
+
+    $fixtures['two-items-in-each'] = array(
+      'json' => json_encode(array(
+        'activityTypes' => array(
+          array('name' => 'First act'),
+          array('name' => 'Second act'),
+        ),
+        'activitySets' => array(
+          array(
+            'name' => 'set1',
+            'label' => 'Label 1',
+            'timeline' => 'true',
+            'activityTypes' => array(
+              array('name' => 'Open Case', 'status' => 'Completed'),
+              array(
+                'name' => 'Meeting',
+                'reference_activity' => 'Open Case',
+                'reference_offset' => 1,
+                'reference_select' => 'newest',
+              ),
+            ),
+          ),
+          array(
+            'name' => 'set2',
+            'label' => 'Label 2',
+            'sequence' => 'true',
+            'activityTypes' => array(
+              array('name' => 'First act'),
+              array('name' => 'Second act'),
+            ),
+          ),
+        ),
+        'caseRoles' => array(
+          array('name' => 'First role', 'creator' => 1, 'manager' => 1),
+          array('name' => 'Second role'),
+        ),
+      )),
+      'xml' => '<?xml version="1.0" encoding="iso-8859-1" ?>
+<CaseType>
+  <name>Housing Support</name>
+  <ActivityTypes>
+    <ActivityType>
+      <name>First act</name>
+    </ActivityType>
+    <ActivityType>
+      <name>Second act</name>
+    </ActivityType>
+  </ActivityTypes>
+  <ActivitySets>
+    <ActivitySet>
+      <name>set1</name>
+      <label>Label 1</label>
+      <timeline>true</timeline>
+      <ActivityTypes>
+        <ActivityType>
+          <name>Open Case</name>
+          <status>Completed</status>
+        </ActivityType>
+        <ActivityType>
+          <name>Meeting</name>
+          <reference_activity>Open Case</reference_activity>
+          <reference_offset>1</reference_offset>
+          <reference_select>newest</reference_select>
+        </ActivityType>
+      </ActivityTypes>
+    </ActivitySet>
+    <ActivitySet>
+      <name>set2</name>
+      <label>Label 2</label>
+      <sequence>true</sequence>
+      <ActivityTypes>
+        <ActivityType>
+          <name>First act</name>
+        </ActivityType>
+        <ActivityType>
+          <name>Second act</name>
+        </ActivityType>
+      </ActivityTypes>
+    </ActivitySet>
+  </ActivitySets>
+  <CaseRoles>
+    <RelationshipType>
+      <name>First role</name>
+      <creator>1</creator>
+      <manager>1</manager>
+    </RelationshipType>
+    <RelationshipType>
+      <name>Second role</name>
+    </RelationshipType>
+  </CaseRoles>
+</CaseType>
+      ',
+    );
+
+    $cases = array();
+    foreach (array(
+               'empty-defn',
+               'empty-lists',
+               'one-item-in-each',
+               'two-items-in-each',
+             ) as $key) {
+      $cases[] = array($key, $fixtures[$key]['json'], $fixtures[$key]['xml']);
+    }
+    return $cases;
+  }
+
+  /**
+   * @param string $fixtureName
+   * @param string $expectedJson
+   * @param string $inputXml
+   * @dataProvider definitionProvider
+   */
+  function testConvertXmlToDefinition($fixtureName, $expectedJson, $inputXml) {
+    $xml = simplexml_load_string($inputXml);
+    $expectedDefinition = json_decode($expectedJson, TRUE);
+    $actualDefinition = CRM_Case_BAO_CaseType::convertXmlToDefinition($xml);
+    $this->assertEquals($expectedDefinition, $actualDefinition);
+  }
+
+  /**
+   * @param string $fixtureName
+   * @param string $inputJson
+   * @param string $expectedXml
+   * @dataProvider definitionProvider
+   */
+  function testConvertDefinitionToXml($fixtureName, $inputJson, $expectedXml) {
+    $inputDefinition = json_decode($inputJson, TRUE);
+    $actualXml = CRM_Case_BAO_CaseType::convertDefinitionToXML('Housing Support', $inputDefinition);
+    $this->assertEquals($this->normalizeXml($expectedXml), $this->normalizeXml($actualXml));
+  }
+
+  /**
+   * @param string $fixtureName
+   * @param string $ignore
+   * @param string $inputXml
+   * @dataProvider definitionProvider
+   */
+  function testRoundtrip_XmlToJsonToXml($fixtureName, $ignore, $inputXml) {
+    $tempDefinition = CRM_Case_BAO_CaseType::convertXmlToDefinition(simplexml_load_string($inputXml));
+    $actualXml = CRM_Case_BAO_CaseType::convertDefinitionToXML('Housing Support', $tempDefinition);
+    $this->assertEquals($this->normalizeXml($inputXml), $this->normalizeXml($actualXml));
+  }
+
+  /**
+   * @param string $fixtureName
+   * @param string $inputJson
+   * @param string $ignore
+   * @dataProvider definitionProvider
+   */
+  function testRoundtrip_JsonToXmlToJson($fixtureName, $inputJson, $ignore) {
+    $tempXml = CRM_Case_BAO_CaseType::convertDefinitionToXML('Housing Support', json_decode($inputJson, TRUE));
+    $actualDefinition = CRM_Case_BAO_CaseType::convertXmlToDefinition(simplexml_load_string($tempXml));
+    $expectedDefinition = json_decode($inputJson, TRUE);
+    $this->assertEquals($expectedDefinition, $actualDefinition);
+  }
+
+  /**
+   * Normalize the whitespace in an XML document
+   *
+   * @param string $xml
+   * @return string
+   */
+  function normalizeXml($xml) {
+    return trim(
+      preg_replace(":\n*<:", "\n<", // tags on new lines
+        preg_replace("/\n[\n ]+/", "\n", // no leading whitespace
+          $xml
+        )
+      )
+    );
+  }
+}
\ No newline at end of file