2 require_once 'CiviTest/CiviCaseTestCase.php';
5 * Class CRM_Case_PseudoConstantTest
8 class CRM_Case_XMLProcessor_ProcessTest
extends CiviCaseTestCase
{
10 public function setUp() {
13 $this->defaultAssigneeOptionsValues
= [];
15 $this->setupContacts();
16 $this->setupDefaultAssigneeOptions();
17 $this->setupRelationships();
18 $this->setupMoreRelationshipTypes();
19 $this->setupActivityDefinitions();
21 $this->process
= new CRM_Case_XMLProcessor_Process();
24 public function tearDown() {
25 $this->deleteMoreRelationshipTypes();
31 * Creates sample contacts.
33 protected function setUpContacts() {
35 'ana' => $this->individualCreate(),
36 'beto' => $this->individualCreate(),
37 'carlos' => $this->individualCreate(),
42 * Adds the default assignee group and options to the test database.
43 * It also stores the IDs of the options in an index.
45 protected function setupDefaultAssigneeOptions() {
47 'NONE', 'BY_RELATIONSHIP', 'SPECIFIC_CONTACT', 'USER_CREATING_THE_CASE',
50 CRM_Core_BAO_OptionGroup
::ensureOptionGroupExists([
51 'name' => 'activity_default_assignee',
54 foreach ($options as $option) {
55 $optionValue = CRM_Core_BAO_OptionValue
::ensureOptionValueExists([
56 'option_group_id' => 'activity_default_assignee',
61 $this->defaultAssigneeOptionsValues
[$option] = $optionValue['value'];
66 * Adds a relationship between the activity's target contact and default assignee.
68 protected function setupRelationships() {
69 $this->relationships
= [
70 'ana_is_pupil_of_beto' => [
72 'name_a_b' => 'Pupil of',
73 'name_b_a' => 'Instructor',
74 'contact_id_a' => $this->contacts
['ana'],
75 'contact_id_b' => $this->contacts
['beto'],
77 'ana_is_spouse_of_carlos' => [
79 'name_a_b' => 'Spouse of',
80 'name_b_a' => 'Spouse of',
81 'contact_id_a' => $this->contacts
['ana'],
82 'contact_id_b' => $this->contacts
['carlos'],
84 'unassigned_employee' => [
86 'name_a_b' => 'Employee of',
87 'name_b_a' => 'Employer',
91 foreach ($this->relationships
as $name => &$relationship) {
92 $relationship['type_id'] = $this->relationshipTypeCreate([
93 'contact_type_a' => 'Individual',
94 'contact_type_b' => 'Individual',
95 'name_a_b' => $relationship['name_a_b'],
96 'label_a_b' => $relationship['name_a_b'],
97 'name_b_a' => $relationship['name_b_a'],
98 'label_b_a' => $relationship['name_b_a'],
101 if (isset($relationship['contact_id_a'])) {
102 $this->callAPISuccess('Relationship', 'create', [
103 'contact_id_a' => $relationship['contact_id_a'],
104 'contact_id_b' => $relationship['contact_id_b'],
105 'relationship_type_id' => $relationship['type_id'],
112 * Set up some additional relationship types for some specific tests.
114 protected function setupMoreRelationshipTypes() {
115 $this->moreRelationshipTypes
= [
116 'unidirectional_name_label_different' => [
118 'name_a_b' => 'jm7ab',
119 'label_a_b' => 'Jedi Master is',
120 'name_b_a' => 'jm7ba',
121 'label_b_a' => 'Jedi Master for',
122 'description' => 'Jedi Master',
124 'unidirectional_name_label_same' => [
126 'name_a_b' => 'Quilt Maker is',
127 'label_a_b' => 'Quilt Maker is',
128 'name_b_a' => 'Quilt Maker for',
129 'label_b_a' => 'Quilt Maker for',
130 'description' => 'Quilt Maker',
132 'bidirectional_name_label_different' => [
135 'label_a_b' => 'Friend of',
137 'label_b_a' => 'Friend of',
138 'description' => 'Friend',
140 'bidirectional_name_label_same' => [
142 'name_a_b' => 'Enemy of',
143 'label_a_b' => 'Enemy of',
144 'name_b_a' => 'Enemy of',
145 'label_b_a' => 'Enemy of',
146 'description' => 'Enemy',
150 foreach ($this->moreRelationshipTypes
as &$relationship) {
151 $relationship['type_id'] = $this->relationshipTypeCreate([
152 'contact_type_a' => 'Individual',
153 'contact_type_b' => 'Individual',
154 'name_a_b' => $relationship['name_a_b'],
155 'label_a_b' => $relationship['label_a_b'],
156 'name_b_a' => $relationship['name_b_a'],
157 'label_b_a' => $relationship['label_b_a'],
158 'description' => $relationship['description'],
164 * Clean up additional relationship types (tearDown).
166 protected function deleteMoreRelationshipTypes() {
167 foreach ($this->moreRelationshipTypes
as $relationship) {
168 $this->callAPISuccess('relationship_type', 'delete', ['id' => $relationship['type_id']]);
173 * Defines the the activity parameters and XML definitions. These can be used
174 * to create the activity.
176 protected function setupActivityDefinitions() {
177 $activityTypeXml = '<activity-type><name>Open Case</name></activity-type>';
178 $this->activityTypeXml
= new SimpleXMLElement($activityTypeXml);
179 $this->activityParams
= [
180 'activity_date_time' => date('Ymd'),
181 'caseID' => $this->caseTypeId
,
182 'clientID' => $this->contacts
['ana'],
183 'creatorID' => $this->_loggedInUser
,
188 * Tests the creation of activities where the default assignee should be the
189 * target contact's instructor. Beto is the instructor for Ana.
191 public function testCreateActivityWithDefaultContactByRelationship() {
192 $relationship = $this->relationships
['ana_is_pupil_of_beto'];
193 $this->activityTypeXml
->default_assignee_type
= $this->defaultAssigneeOptionsValues
['BY_RELATIONSHIP'];
194 $this->activityTypeXml
->default_assignee_relationship
= "{$relationship['type_id']}_b_a";
196 $this->process
->createActivity($this->activityTypeXml
, $this->activityParams
);
197 $this->assertActivityAssignedToContactExists($this->contacts
['beto']);
201 * Tests when the default assignee relationship exists, but in the other direction only.
202 * Ana is a pupil, but has no pupils related to her.
204 public function testCreateActivityWithDefaultContactByRelationshipMissing() {
205 $relationship = $this->relationships
['ana_is_pupil_of_beto'];
206 $this->activityTypeXml
->default_assignee_type
= $this->defaultAssigneeOptionsValues
['BY_RELATIONSHIP'];
207 $this->activityTypeXml
->default_assignee_relationship
= "{$relationship['type_id']}_a_b";
209 $this->process
->createActivity($this->activityTypeXml
, $this->activityParams
);
210 $this->assertActivityAssignedToContactExists(NULL);
214 * Tests when the the default assignee relationship exists and is a bidirectional
215 * relationship. Ana and Carlos are spouses.
217 public function testCreateActivityWithDefaultContactByRelationshipBidirectional() {
218 $relationship = $this->relationships
['ana_is_spouse_of_carlos'];
219 $this->activityParams
['clientID'] = $this->contacts
['carlos'];
220 $this->activityTypeXml
->default_assignee_type
= $this->defaultAssigneeOptionsValues
['BY_RELATIONSHIP'];
221 $this->activityTypeXml
->default_assignee_relationship
= "{$relationship['type_id']}_a_b";
223 $this->process
->createActivity($this->activityTypeXml
, $this->activityParams
);
224 $this->assertActivityAssignedToContactExists($this->contacts
['ana']);
228 * Tests when the default assignee relationship does not exist. Ana is not an
229 * employee for anyone.
231 public function testCreateActivityWithDefaultContactByRelationButTheresNoRelationship() {
232 $relationship = $this->relationships
['unassigned_employee'];
233 $this->activityTypeXml
->default_assignee_type
= $this->defaultAssigneeOptionsValues
['BY_RELATIONSHIP'];
234 $this->activityTypeXml
->default_assignee_relationship
= "{$relationship['type_id']}_b_a";
236 $this->process
->createActivity($this->activityTypeXml
, $this->activityParams
);
237 $this->assertActivityAssignedToContactExists(NULL);
241 * Tests the creation of activities with default assignee set to a specific contact.
243 public function testCreateActivityAssignedToSpecificContact() {
244 $this->activityTypeXml
->default_assignee_type
= $this->defaultAssigneeOptionsValues
['SPECIFIC_CONTACT'];
245 $this->activityTypeXml
->default_assignee_contact
= $this->contacts
['carlos'];
247 $this->process
->createActivity($this->activityTypeXml
, $this->activityParams
);
248 $this->assertActivityAssignedToContactExists($this->contacts
['carlos']);
252 * Tests the creation of activities with default assignee set to a specific contact,
253 * but the contact does not exist.
255 public function testCreateActivityAssignedToNonExistantSpecificContact() {
256 $this->activityTypeXml
->default_assignee_type
= $this->defaultAssigneeOptionsValues
['SPECIFIC_CONTACT'];
257 $this->activityTypeXml
->default_assignee_contact
= 987456321;
259 $this->process
->createActivity($this->activityTypeXml
, $this->activityParams
);
260 $this->assertActivityAssignedToContactExists(NULL);
264 * Tests the creation of activities with the default assignee being the one
265 * creating the case's activity.
267 public function testCreateActivityAssignedToUserCreatingTheCase() {
268 $this->activityTypeXml
->default_assignee_type
= $this->defaultAssigneeOptionsValues
['USER_CREATING_THE_CASE'];
270 $this->process
->createActivity($this->activityTypeXml
, $this->activityParams
);
271 $this->assertActivityAssignedToContactExists($this->_loggedInUser
);
275 * Tests the creation of activities when the default assignee is set to NONE.
277 public function testCreateActivityAssignedNoUser() {
278 $this->activityTypeXml
->default_assignee_type
= $this->defaultAssigneeOptionsValues
['NONE'];
280 $this->process
->createActivity($this->activityTypeXml
, $this->activityParams
);
281 $this->assertActivityAssignedToContactExists(NULL);
285 * Tests the creation of activities when the default assignee is set to NONE.
287 public function testCreateActivityWithNoDefaultAssigneeOption() {
288 $this->process
->createActivity($this->activityTypeXml
, $this->activityParams
);
289 $this->assertActivityAssignedToContactExists(NULL);
293 * Asserts that an activity was created where the assignee was the one related
294 * to the target contact.
296 * @param int|null $assigneeContactId the ID of the expected assigned contact or NULL if expected to be empty.
298 protected function assertActivityAssignedToContactExists($assigneeContactId) {
299 $expectedContact = $assigneeContactId === NULL ?
[] : [$assigneeContactId];
300 $result = $this->callAPISuccess('Activity', 'get', [
301 'target_contact_id' => $this->activityParams
['clientID'],
302 'return' => ['assignee_contact_id'],
304 $activity = CRM_Utils_Array
::first($result['values']);
306 $this->assertNotNull($activity, 'Target contact has no activities assigned to them');
307 $this->assertEquals($expectedContact, $activity['assignee_contact_id'], 'Activity is not assigned to expected contact');
311 * Test that caseRoles() doesn't have name and label mixed up.
313 * @param $key string The array key in the moreRelationshipTypes array that
314 * is the relationship type we're currently testing. So not necessarily
315 * unique for each entry in the dataprovider since want to test a given
316 * relationship type against multiple xml strings. It's not a test
317 * identifier, it's an array key to use to look up something.
318 * @param $xmlString string
319 * @param $expected array
320 * @param $dontcare array We're re-using the data provider for two tests and
321 * we don't care about those expected values.
323 * @dataProvider xmlCaseRoleDataProvider
325 public function testCaseRoles($key, $xmlString, $expected, $dontcare) {
326 $xmlObj = new SimpleXMLElement($xmlString);
328 // element 0 is direction (a_b), 1 is the text we want
329 $expectedArray = empty($expected) ?
[] : ["{$this->moreRelationshipTypes[$key]['type_id']}_{$expected[0]}" => $expected[1]];
331 $this->assertEquals($expectedArray, $this->process
->caseRoles($xmlObj->CaseRoles
, FALSE));
335 * Test that locateNameOrLabel doesn't have name and label mixed up.
337 * @param $key string The array key in the moreRelationshipTypes array that
338 * is the relationship type we're currently testing. So not necessarily
339 * unique for each entry in the dataprovider since want to test a given
340 * relationship type against multiple xml strings. It's not a test
341 * identifier, it's an array key to use to look up something.
342 * @param $xmlString string
343 * @param $dontcare array We're re-using the data provider for two tests and
344 * we don't care about those expected values.
345 * @param $expected array
347 * @dataProvider xmlCaseRoleDataProvider
349 public function testLocateNameOrLabel($key, $xmlString, $dontcare, $expected) {
350 $xmlObj = new SimpleXMLElement($xmlString);
352 // element 0 is direction (a_b), 1 is the text we want.
353 // In case of failure, the function is expected to return FALSE for the
354 // direction and then for the text it just gives us back the string we
356 $expectedArray = empty($expected[0])
357 ?
[FALSE, $expected[1]]
358 : ["{$this->moreRelationshipTypes[$key]['type_id']}_{$expected[0]}", $expected[1]];
360 $this->assertEquals($expectedArray, $this->process
->locateNameOrLabel($xmlObj->CaseRoles
->RelationshipType
));
364 * Data provider for testCaseRoles and testLocateNameOrLabel
367 public function xmlCaseRoleDataProvider() {
369 // Simulate one that has been converted to the format it should be going
370 // forward, where name is the actual name, i.e. same as machineName.
372 // this is the array key in the $this->moreRelationshipTypes array
373 'unidirectional_name_label_different',
375 '<CaseType><CaseRoles><RelationshipType><name>jm7ba</name><creator>1</creator><manager>1</manager></RelationshipType></CaseRoles></CaseType>',
376 // this is the expected for testCaseRoles
377 ['a_b', 'Jedi Master is'],
378 // this is the expected for testLocateNameOrLabel
381 // Simulate one that is still in label format, i.e. one that is still in
382 // xml files that haven't been updated, or in the db but upgrade script
385 'unidirectional_name_label_different',
386 '<CaseType><CaseRoles><RelationshipType><name>Jedi Master for</name><creator>1</creator><manager>1</manager></RelationshipType></CaseRoles></CaseType>',
387 ['a_b', 'Jedi Master is'],
390 // Ditto but where we know name and label are the same in the db.
392 'unidirectional_name_label_same',
393 '<CaseType><CaseRoles><RelationshipType><name>Quilt Maker for</name><creator>1</creator><manager>1</manager></RelationshipType></CaseRoles></CaseType>',
394 ['a_b', 'Quilt Maker is'],
395 ['a_b', 'Quilt Maker for'],
397 // Simulate one that is messed up and should fail, e.g. like a typo
398 // in an xml file. Here we've made a typo on purpose.
400 'unidirectional_name_label_different',
401 '<CaseType><CaseRoles><RelationshipType><name>Jedi Masterrrr for</name><creator>1</creator><manager>1</manager></RelationshipType></CaseRoles></CaseType>',
403 [FALSE, 'Jedi Masterrrr for'],
405 // Now some similar tests to above but for bidirectional relationships.
406 // Bidirectional relationship, name and label different, using machine name.
408 'bidirectional_name_label_different',
409 '<CaseType><CaseRoles><RelationshipType><name>f12</name><creator>1</creator><manager>1</manager></RelationshipType></CaseRoles></CaseType>',
410 ['b_a', 'Friend of'],
413 // Bidirectional relationship, name and label different, using display label.
415 'bidirectional_name_label_different',
416 '<CaseType><CaseRoles><RelationshipType><name>Friend of</name><creator>1</creator><manager>1</manager></RelationshipType></CaseRoles></CaseType>',
417 ['b_a', 'Friend of'],
420 // Bidirectional relationship, name and label same.
422 'bidirectional_name_label_same',
423 '<CaseType><CaseRoles><RelationshipType><name>Enemy of</name><creator>1</creator><manager>1</manager></RelationshipType></CaseRoles></CaseType>',