Merge pull request #17720 from alifrumin/5.27.0-releasenotes
[civicrm-core.git] / tests / phpunit / Civi / Payment / PropertyBagTest.php
1 <?php
2 namespace Civi\Payment;
3
4 use Civi\Test\HeadlessInterface;
5 use Civi\Test\TransactionalInterface;
6
7 /**
8 * @group headless
9 */
10 class PropertyBagTest extends \PHPUnit\Framework\TestCase implements HeadlessInterface, TransactionalInterface {
11
12 /**
13 * @return \Civi\Test\CiviEnvBuilder
14 */
15 public function setUpHeadless() {
16 return \Civi\Test::headless()->apply();
17 }
18
19 /**
20 * Test we can set a contact ID.
21 */
22 public function testSetContactID() {
23 // Do things proper.
24 $propertyBag = new PropertyBag();
25 $propertyBag->setContactID(123);
26 $this->assertEquals(123, $propertyBag->getContactID());
27
28 // Same but this time set contact ID with string.
29 // (php should throw its own warnings about this because of the signature)
30 $propertyBag = new PropertyBag();
31 $propertyBag->setContactID('123');
32 $this->assertInternalType('int', $propertyBag->getContactID());
33 $this->assertEquals(123, $propertyBag->getContactID());
34
35 // Test we can have different labels
36 $propertyBag = new PropertyBag();
37 $propertyBag->setContactID(123);
38 $propertyBag->setContactID(456, 'new');
39 $this->assertEquals(123, $propertyBag->getContactID());
40 $this->assertEquals(456, $propertyBag->getContactID('new'));
41 }
42
43 /**
44 * Test we cannot set an invalid contact ID.
45 *
46 * @expectedException \InvalidArgumentException
47 */
48 public function testSetContactIDFailsIfInvalid() {
49 $propertyBag = new PropertyBag();
50 $propertyBag->setContactID(0);
51 }
52
53 /**
54 * Test we can set a contact ID the wrong way
55 */
56 public function testSetContactIDLegacyWay() {
57 $propertyBag = new PropertyBag();
58 $propertyBag['contactID'] = 123;
59 $this->assertEquals(123, $propertyBag->getContactID());
60 $this->assertEquals(123, $propertyBag['contactID']);
61 // There should not be any warnings yet.
62 $this->assertEquals("", $propertyBag->lastWarning);
63
64 // Now access via legacy name - should work but generate warning.
65 $this->assertEquals(123, $propertyBag['contact_id']);
66 $this->assertEquals("We have translated 'contact_id' to 'contactID' for you, but please update your code to use the propper setters and getters.", $propertyBag->lastWarning);
67
68 // Repeat but this time set the property using a legacy name, fetch by new name.
69 $propertyBag = new PropertyBag();
70 $propertyBag['contact_id'] = 123;
71 $this->assertEquals("We have translated 'contact_id' to 'contactID' for you, but please update your code to use the propper setters and getters.", $propertyBag->lastWarning);
72 $this->assertEquals(123, $propertyBag->getContactID());
73 $this->assertEquals(123, $propertyBag['contactID']);
74 $this->assertEquals(123, $propertyBag['contact_id']);
75 }
76
77 /**
78 * Test that emails set by the legacy method of 'email-5' can be retrieved with getEmail.
79 */
80 public function testSetBillingEmailLegacy() {
81 $localPropertyBag = new PropertyBag();
82 $localPropertyBag->mergeLegacyInputParams(['email-' . \CRM_Core_BAO_LocationType::getBilling() => 'a@b.com']);
83 $this->assertEquals('a@b.com', $localPropertyBag->getEmail());
84 }
85
86 /**
87 * Test that null is valid for recurring contribution ID.
88 *
89 * See https://github.com/civicrm/civicrm-core/pull/17292
90 */
91 public function testRecurProcessorIDNull() {
92 $bag = new PropertyBag();
93 $bag->setRecurProcessorID(NULL);
94 $value = $bag->getRecurProcessorID();
95 $this->assertNull($value);
96 }
97
98 /**
99 */
100 public function testMergeInputs() {
101 $propertyBag = new PropertyBag();
102 $propertyBag->mergeLegacyInputParams([
103 'contactID' => 123,
104 'contributionRecurID' => 456,
105 ]);
106 $this->assertEquals('We have merged input params into the property bag for now but please rewrite code to not use this.', $propertyBag->lastWarning);
107 $this->assertEquals(123, $propertyBag->getContactID());
108 $this->assertEquals(456, $propertyBag->getContributionRecurID());
109 }
110
111 /**
112 * Test we can set and access custom props.
113 */
114 public function testSetCustomProp() {
115 $propertyBag = new PropertyBag();
116 $propertyBag->setCustomProperty('customThingForMyProcessor', 'fidget');
117 $this->assertEquals('fidget', $propertyBag->getCustomProperty('customThingForMyProcessor'));
118 $this->assertEquals('', $propertyBag->lastWarning);
119
120 // Test we can do this with array, although we should get a warning.
121 $propertyBag = new PropertyBag();
122 $propertyBag['customThingForMyProcessor'] = 'fidget';
123 $this->assertEquals('fidget', $propertyBag->getCustomProperty('customThingForMyProcessor'));
124 $this->assertEquals("Unknown property 'customThingForMyProcessor'. We have merged this in for now as a custom property. Please rewrite your code to use PropertyBag->setCustomProperty if it is a genuinely custom property, or a standardised setter like PropertyBag->setContactID for standard properties", $propertyBag->lastWarning);
125 }
126
127 /**
128 * Test we can't set a custom prop that we know about.
129 *
130 * @expectedException \InvalidArgumentException
131 * @expectedExceptionMessage Attempted to set 'contactID' via setCustomProperty - must use using its setter.
132 */
133 public function testSetCustomPropFails() {
134 $propertyBag = new PropertyBag();
135 $propertyBag->setCustomProperty('contactID', 123);
136 }
137
138 /**
139 *
140 * @dataProvider otherParamsDataProvider
141 */
142 public function testOtherParams($prop, $legacy_names, $valid_values, $invalid_values) {
143 $setter = 'set' . ucfirst($prop);
144 $getter = 'get' . ucfirst($prop);
145
146 // Using the setter and getter, check we can pass stuff in and get expected out.
147 foreach ($valid_values as $_) {
148 list($given, $expect) = $_;
149 $propertyBag = new PropertyBag();
150 try {
151 $propertyBag->$setter($given);
152 }
153 catch (\Exception $e) {
154 $this->fail("Expected to be able to set '$prop' to '$given' but got " . get_class($e) . ": " . $e->getMessage());
155 }
156 try {
157 $this->assertEquals($expect, $propertyBag->$getter());
158 }
159 catch (\Exception $e) {
160 $this->fail("Expected to be able to call $getter, having called $setter with '$given' but got " . get_class($e) . ": " . $e->getMessage());
161 }
162 }
163 // Using the setter and getter, check we get an error for invalid data.
164 foreach ($invalid_values as $given) {
165 try {
166 $propertyBag = new PropertyBag();
167 $propertyBag->$setter($given);
168 }
169 catch (\InvalidArgumentException $e) {
170 // counts this assertion.
171 $this->assertTrue(TRUE);
172 continue;
173 }
174 $this->fail("Expected an error trying to set $prop to " . json_encode($given) . " but did not get one.");
175 }
176
177 // Check array access for the proper property name and any aliases.
178 foreach (array_merge([$prop], $legacy_names) as $name) {
179 // Check array access
180 foreach ($valid_values as $_) {
181 list($given, $expect) = $_;
182 $propertyBag = new PropertyBag();
183 $propertyBag[$name] = $given;
184 $this->assertEquals($expect, $propertyBag->$getter(), "Failed to set $prop via array access on $name");
185 // Nb. I don't feel the need to repeat all the checks above for every alias.
186 // We only really need to test that the array access works for each alias.
187 break;
188 }
189 }
190 }
191
192 /**
193 * Test the require method works.
194 */
195 public function testRequire() {
196 $propertyBag = new PropertyBag();
197 $propertyBag->setContactID(123);
198 $propertyBag->setDescription('foo');
199 // This one should not error.
200 $propertyBag->require(['contactID', 'description']);
201 try {
202 $propertyBag->require(['contactID', 'description', 'contributionID', 'somethingthatdoesntexist']);
203 }
204 catch (\InvalidArgumentException $e) {
205 $this->assertEquals('Required properties missing: contributionID, somethingthatdoesntexist', $e->getMessage());
206 }
207 }
208
209 /**
210 * Test retrieves using CRM_Utils_Array::value still work.
211 */
212 public function testUtilsArray() {
213 $propertyBag = new PropertyBag();
214 $propertyBag->setContactID(123);
215 $this->assertEquals(123, \CRM_Utils_Array::value('contact_id', $propertyBag));
216
217 // Test that using utils array value to get a nonexistent property returns the default.
218 $this->assertEquals(456, \CRM_Utils_Array::value('ISawAManWhoWasntThere', $propertyBag, 456));
219 }
220
221 /**
222 *
223 * Data provider for testOtherParams
224 *
225 */
226 public function otherParamsDataProvider() {
227 $valid_bools = [['0' , FALSE], ['', FALSE], [0, FALSE], [FALSE, FALSE], [TRUE, TRUE], [1, TRUE], ['1', TRUE]];
228 $valid_strings = [['foo' , 'foo'], ['', '']];
229 $valid_strings_inc_null = [['foo' , 'foo'], ['', ''], [NULL, '']];
230 $valid_ints = [[123, 123], ['123', 123]];
231 $invalid_ints = [-1, 0, NULL, ''];
232 return [
233 ['billingStreetAddress', [], $valid_strings_inc_null, []],
234 ['billingSupplementalAddress1', [], $valid_strings_inc_null, []],
235 ['billingSupplementalAddress2', [], $valid_strings_inc_null, []],
236 ['billingSupplementalAddress3', [], $valid_strings_inc_null, []],
237 ['billingCity', [], $valid_strings_inc_null, []],
238 ['billingPostalCode', [], $valid_strings_inc_null, []],
239 ['billingCounty', [], $valid_strings_inc_null, []],
240 ['billingCountry', [], [['GB', 'GB'], ['NZ', 'NZ']], ['XX', '', NULL, 0]],
241 ['contributionID', ['contribution_id'], $valid_ints, $invalid_ints],
242 ['contributionRecurID', ['contribution_recur_id'], $valid_ints, $invalid_ints],
243 ['description', [], [['foo' , 'foo'], ['', '']], []],
244 ['feeAmount', ['fee_amount'], [[1.23, 1.23], ['4.56', 4.56]], [NULL]],
245 ['firstName', [], $valid_strings_inc_null, []],
246 ['invoiceID', ['invoice_id'], $valid_strings, []],
247 ['isBackOffice', ['is_back_office'], $valid_bools, [NULL]],
248 ['isRecur', ['is_recur'], $valid_bools, [NULL]],
249 ['lastName', [], $valid_strings_inc_null, []],
250 ['paymentToken', [], $valid_strings, []],
251 ['recurFrequencyInterval', ['frequency_interval'], $valid_ints, $invalid_ints],
252 ['recurFrequencyUnit', [], [['month', 'month'], ['day', 'day'], ['year', 'year']], ['', NULL, 0]],
253 ['recurProcessorID', [], [['foo', 'foo']], [str_repeat('x', 256)]],
254 ['transactionID', ['transaction_id'], $valid_strings, []],
255 ['trxnResultCode', [], $valid_strings, []],
256 ];
257 }
258
259 /**
260 * Test generic getter, setter methods.
261 *
262 */
263 public function testGetterAndSetter() {
264 $propertyBag = new PropertyBag();
265
266 $propertyBag->setter('contactID', 123);
267 $this->assertEquals(123, $propertyBag->getContactID(), "Failed testing that a valid property was set correctly");
268
269 $result = $propertyBag->getter('contactID');
270 $this->assertEquals(123, $result, "Failed testing the getter on a set property");
271
272 $result = $propertyBag->getter('contactID', TRUE, 456);
273 $this->assertEquals(123, $result, "Failed testing the getter on a set property when providing a default");
274
275 $result = $propertyBag->getter('contributionRecurID', TRUE, 456);
276 $this->assertEquals(456, $result, "Failed testing the getter on an unset property when providing a default");
277
278 try {
279 $result = $propertyBag->getter('contributionRecurID', FALSE);
280 $this->fail("getter called with unset property should throw exception but none was thrown");
281 }
282 catch (\BadMethodCallException $e) {
283 }
284
285 $result = $propertyBag->getter('contribution_recur_id', TRUE, NULL);
286 $this->assertNull($result, "Failed testing the getter on an invalid property when providing a default");
287
288 try {
289 $result = $propertyBag->getter('contribution_recur_id');
290 }
291 catch (\InvalidArgumentException $e) {
292 $this->assertEquals("Attempted to get 'contribution_recur_id' via getCustomProperty - must use using its getter.", $e->getMessage());
293 }
294
295 // Nb. hmmm. the custom property getter does not throw an exception if the property is unset, it just returns NULL.
296 $result = $propertyBag->getter('something_custom');
297 $this->assertNull($result, "Failed testing the getter on an unset custom property when not providing a default");
298
299 try {
300 $propertyBag->setter('some_custom_thing', 'foo');
301 $this->fail("Expected to get an exception when trying to use setter for a non-standard property.");
302 }
303 catch (\BadMethodCallException $e) {
304 $this->assertEquals("Cannot use generic setter with non-standard properties; you must use setCustomProperty for custom properties.", $e->getMessage());
305 }
306
307 // Test labels.
308 $propertyBag->setter('contactID', '100', 'original');
309 $this->assertEquals(123, $propertyBag->getContactID(), "Looks like the setter did not respect the label.");
310 $this->assertEquals(100, $propertyBag->getContactID('original'), "Failed to retrieve the labelled property");
311 $this->assertEquals(100, $propertyBag->getter('contactID', FALSE, NULL, 'original'), "Failed using the getter to retrieve the labelled property");
312
313 }
314
315 }