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