Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
Stripe
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Container Registry
Model registry
Operate
Environments
Monitor
Incidents
Service Desk
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
Extensions
Stripe
Commits
16def2fb
Commit
16def2fb
authored
3 years ago
by
mattwire
Browse files
Options
Downloads
Patches
Plain Diff
Code cleanup
parent
b0d8cc3f
No related branches found
No related tags found
No related merge requests found
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
tests/phpunit/CRM/Stripe/BaseTest.php
+2
-5
2 additions, 5 deletions
tests/phpunit/CRM/Stripe/BaseTest.php
tests/phpunit/CRM/Stripe/IpnTest.php
+156
-134
156 additions, 134 deletions
tests/phpunit/CRM/Stripe/IpnTest.php
with
158 additions
and
139 deletions
tests/phpunit/CRM/Stripe/BaseTest.php
+
2
−
5
View file @
16def2fb
...
@@ -184,10 +184,10 @@ class CRM_Stripe_BaseTest extends \PHPUnit\Framework\TestCase implements Headles
...
@@ -184,10 +184,10 @@ class CRM_Stripe_BaseTest extends \PHPUnit\Framework\TestCase implements Headles
$processor
->
setAPIParams
();
$processor
->
setAPIParams
();
try
{
try
{
$results
=
$processor
->
stripeClient
->
charges
->
retrieve
([
"id"
=>
$this
->
trxn_id
]);
$processor
->
stripeClient
->
charges
->
retrieve
([
"id"
=>
$this
->
trxn_id
]);
$found
=
TRUE
;
$found
=
TRUE
;
}
}
catch
(
Stripe_Error
$e
)
{
catch
(
Exception
$e
)
{
$found
=
FALSE
;
$found
=
FALSE
;
}
}
...
@@ -200,15 +200,12 @@ class CRM_Stripe_BaseTest extends \PHPUnit\Framework\TestCase implements Headles
...
@@ -200,15 +200,12 @@ class CRM_Stripe_BaseTest extends \PHPUnit\Framework\TestCase implements Headles
public
function
setupTransaction
(
$params
=
[])
{
public
function
setupTransaction
(
$params
=
[])
{
$contribution
=
civicrm_api3
(
'contribution'
,
'create'
,
array_merge
([
$contribution
=
civicrm_api3
(
'contribution'
,
'create'
,
array_merge
([
'contact_id'
=>
$this
->
contactID
,
'contact_id'
=>
$this
->
contactID
,
'contribution_status_id'
=>
2
,
'payment_processor_id'
=>
$this
->
paymentProcessorID
,
'payment_processor_id'
=>
$this
->
paymentProcessorID
,
// processor provided ID - use contact ID as proxy.
// processor provided ID - use contact ID as proxy.
'processor_id'
=>
$this
->
contactID
,
'processor_id'
=>
$this
->
contactID
,
'total_amount'
=>
$this
->
total
,
'total_amount'
=>
$this
->
total
,
'financial_type_id'
=>
$this
->
financialTypeID
,
'financial_type_id'
=>
$this
->
financialTypeID
,
'contribution_status_id'
=>
'Pending'
,
'contribution_status_id'
=>
'Pending'
,
'contact_id'
=>
$this
->
contactID
,
'payment_processor_id'
=>
$this
->
paymentProcessorID
,
'is_test'
=>
1
,
'is_test'
=>
1
,
],
$params
));
],
$params
));
$this
->
assertEquals
(
0
,
$contribution
[
'is_error'
]);
$this
->
assertEquals
(
0
,
$contribution
[
'is_error'
]);
...
...
This diff is collapsed.
Click to expand it.
tests/phpunit/CRM/Stripe/IpnTest.php
+
156
−
134
View file @
16def2fb
...
@@ -47,7 +47,7 @@ class CRM_Stripe_IpnTest extends CRM_Stripe_BaseTest {
...
@@ -47,7 +47,7 @@ class CRM_Stripe_IpnTest extends CRM_Stripe_BaseTest {
// This test is particularly dirty for some reason so we have to
// This test is particularly dirty for some reason so we have to
// force a reset.
// force a reset.
public
function
setUpHeadless
()
{
public
function
setUpHeadless
()
{
$force
=
false
;
$force
=
FALSE
;
return
\Civi\Test
::
headless
()
return
\Civi\Test
::
headless
()
->
install
(
'mjwshared'
)
->
install
(
'mjwshared'
)
->
installMe
(
__DIR__
)
->
installMe
(
__DIR__
)
...
@@ -65,7 +65,7 @@ class CRM_Stripe_IpnTest extends CRM_Stripe_BaseTest {
...
@@ -65,7 +65,7 @@ class CRM_Stripe_IpnTest extends CRM_Stripe_BaseTest {
'type'
=>
'invoice.payment_succeeded'
,
'type'
=>
'invoice.payment_succeeded'
,
'id'
=>
'evt_mock'
,
'id'
=>
'evt_mock'
,
'object'
=>
'event'
,
// ?
'object'
=>
'event'
,
// ?
'livemode'
=>
false
,
'livemode'
=>
FALSE
,
'pending_webhooks'
=>
0
,
'pending_webhooks'
=>
0
,
'request'
=>
[
'id'
=>
NULL
],
'request'
=>
[
'id'
=>
NULL
],
'data'
=>
[
'data'
=>
[
...
@@ -103,7 +103,7 @@ class CRM_Stripe_IpnTest extends CRM_Stripe_BaseTest {
...
@@ -103,7 +103,7 @@ class CRM_Stripe_IpnTest extends CRM_Stripe_BaseTest {
'type'
=>
'charge.succeeded'
,
'type'
=>
'charge.succeeded'
,
'id'
=>
'evt_mock'
,
'id'
=>
'evt_mock'
,
'object'
=>
'event'
,
'object'
=>
'event'
,
'livemode'
=>
false
,
'livemode'
=>
FALSE
,
'pending_webhooks'
=>
0
,
'pending_webhooks'
=>
0
,
'request'
=>
[
'id'
=>
NULL
],
'request'
=>
[
'id'
=>
NULL
],
'data'
=>
[
'data'
=>
[
...
@@ -141,7 +141,7 @@ class CRM_Stripe_IpnTest extends CRM_Stripe_BaseTest {
...
@@ -141,7 +141,7 @@ class CRM_Stripe_IpnTest extends CRM_Stripe_BaseTest {
'type'
=>
'charge.failed'
,
'type'
=>
'charge.failed'
,
'id'
=>
'evt_mock'
,
'id'
=>
'evt_mock'
,
'object'
=>
'event'
,
'object'
=>
'event'
,
'livemode'
=>
false
,
'livemode'
=>
FALSE
,
'pending_webhooks'
=>
0
,
'pending_webhooks'
=>
0
,
'request'
=>
[
'id'
=>
NULL
],
'request'
=>
[
'id'
=>
NULL
],
'data'
=>
[
'data'
=>
[
...
@@ -182,7 +182,7 @@ class CRM_Stripe_IpnTest extends CRM_Stripe_BaseTest {
...
@@ -182,7 +182,7 @@ class CRM_Stripe_IpnTest extends CRM_Stripe_BaseTest {
'id'
=>
'evt_mock'
,
'id'
=>
'evt_mock'
,
'object'
=>
'event'
,
'object'
=>
'event'
,
'type'
=>
'invoice.payment_failed'
,
'type'
=>
'invoice.payment_failed'
,
'livemode'
=>
false
,
'livemode'
=>
FALSE
,
'pending_webhooks'
=>
0
,
'pending_webhooks'
=>
0
,
'request'
=>
[
'id'
=>
NULL
],
'request'
=>
[
'id'
=>
NULL
],
'data'
=>
[
'data'
=>
[
...
@@ -231,7 +231,7 @@ class CRM_Stripe_IpnTest extends CRM_Stripe_BaseTest {
...
@@ -231,7 +231,7 @@ class CRM_Stripe_IpnTest extends CRM_Stripe_BaseTest {
'type'
=>
'invoice.finalized'
,
'type'
=>
'invoice.finalized'
,
'id'
=>
'evt_mock_2'
,
'id'
=>
'evt_mock_2'
,
'object'
=>
'event'
,
'object'
=>
'event'
,
'livemode'
=>
false
,
'livemode'
=>
FALSE
,
'pending_webhooks'
=>
0
,
'pending_webhooks'
=>
0
,
'request'
=>
[
'id'
=>
NULL
],
'request'
=>
[
'id'
=>
NULL
],
'data'
=>
[
'data'
=>
[
...
@@ -255,7 +255,7 @@ class CRM_Stripe_IpnTest extends CRM_Stripe_BaseTest {
...
@@ -255,7 +255,7 @@ class CRM_Stripe_IpnTest extends CRM_Stripe_BaseTest {
'type'
=>
'invoice.payment_succeeded'
,
'type'
=>
'invoice.payment_succeeded'
,
'id'
=>
'evt_mock_3'
,
'id'
=>
'evt_mock_3'
,
'object'
=>
'event'
,
'object'
=>
'event'
,
'livemode'
=>
false
,
'livemode'
=>
FALSE
,
'pending_webhooks'
=>
0
,
'pending_webhooks'
=>
0
,
'request'
=>
[
'id'
=>
NULL
],
'request'
=>
[
'id'
=>
NULL
],
'data'
=>
[
'data'
=>
[
...
@@ -301,7 +301,7 @@ class CRM_Stripe_IpnTest extends CRM_Stripe_BaseTest {
...
@@ -301,7 +301,7 @@ class CRM_Stripe_IpnTest extends CRM_Stripe_BaseTest {
'type'
=>
'invoice.payment_succeeded'
,
'type'
=>
'invoice.payment_succeeded'
,
'id'
=>
'evt_mock_2'
,
'id'
=>
'evt_mock_2'
,
'object'
=>
'event'
,
'object'
=>
'event'
,
'livemode'
=>
false
,
'livemode'
=>
FALSE
,
'pending_webhooks'
=>
0
,
'pending_webhooks'
=>
0
,
'request'
=>
[
'id'
=>
NULL
],
'request'
=>
[
'id'
=>
NULL
],
'data'
=>
[
'data'
=>
[
...
@@ -332,7 +332,7 @@ class CRM_Stripe_IpnTest extends CRM_Stripe_BaseTest {
...
@@ -332,7 +332,7 @@ class CRM_Stripe_IpnTest extends CRM_Stripe_BaseTest {
'type'
=>
'invoice.finalized'
,
'type'
=>
'invoice.finalized'
,
'id'
=>
'evt_mock_3'
,
'id'
=>
'evt_mock_3'
,
'object'
=>
'event'
,
'object'
=>
'event'
,
'livemode'
=>
false
,
'livemode'
=>
FALSE
,
'pending_webhooks'
=>
0
,
'pending_webhooks'
=>
0
,
'request'
=>
[
'id'
=>
NULL
],
'request'
=>
[
'id'
=>
NULL
],
'data'
=>
[
'data'
=>
[
...
@@ -377,23 +377,23 @@ class CRM_Stripe_IpnTest extends CRM_Stripe_BaseTest {
...
@@ -377,23 +377,23 @@ class CRM_Stripe_IpnTest extends CRM_Stripe_BaseTest {
// To do this we'll need a new invoice and a new charge.
// To do this we'll need a new invoice and a new charge.
// and pending balance transaction
// and pending balance transaction
$mockInvoice2
=
new
PropertySpy
(
'invoice2'
,
[
$mockInvoice2
=
new
PropertySpy
(
'invoice2'
,
[
'id'
=>
'in_mock_2'
,
'id'
=>
'in_mock_2'
,
'object'
=>
'invoice'
,
'object'
=>
'invoice'
,
'amount_due'
=>
$this
->
total
*
100
,
'amount_due'
=>
$this
->
total
*
100
,
'charge'
=>
'ch_mock_2'
,
'charge'
=>
'ch_mock_2'
,
'subscription'
=>
'sub_mock'
,
'subscription'
=>
'sub_mock'
,
'customer'
=>
'cus_mock'
,
'customer'
=>
'cus_mock'
,
'created'
=>
time
(),
'created'
=>
time
(),
]);
]);
$mockCharge2
=
new
PropertySpy
(
'charge2'
,
[
$mockCharge2
=
new
PropertySpy
(
'charge2'
,
[
'id'
=>
'ch_mock_2'
,
'id'
=>
'ch_mock_2'
,
'object'
=>
'charge'
,
'object'
=>
'charge'
,
'balance_transaction'
=>
'txn_mock_2'
,
'balance_transaction'
=>
'txn_mock_2'
,
'amount'
=>
$this
->
total
*
100
,
'amount'
=>
$this
->
total
*
100
,
'subscription'
=>
'sub_mock'
,
'subscription'
=>
'sub_mock'
,
'customer'
=>
'cus_mock'
,
'customer'
=>
'cus_mock'
,
'created'
=>
time
(),
'created'
=>
time
(),
]);
]);
$balanceTransaction2
=
new
PropertySpy
(
'balance_transaction2'
,
[
$balanceTransaction2
=
new
PropertySpy
(
'balance_transaction2'
,
[
'id'
=>
'txn_mock_2'
,
'id'
=>
'txn_mock_2'
,
'object'
=>
'balance_transaction'
,
'object'
=>
'balance_transaction'
,
...
@@ -426,7 +426,7 @@ class CRM_Stripe_IpnTest extends CRM_Stripe_BaseTest {
...
@@ -426,7 +426,7 @@ class CRM_Stripe_IpnTest extends CRM_Stripe_BaseTest {
'type'
=>
'invoice.finalized'
,
'type'
=>
'invoice.finalized'
,
'id'
=>
'evt_mock_3'
,
'id'
=>
'evt_mock_3'
,
'object'
=>
'event'
,
'object'
=>
'event'
,
'livemode'
=>
false
,
'livemode'
=>
FALSE
,
'pending_webhooks'
=>
0
,
'pending_webhooks'
=>
0
,
'request'
=>
[
'id'
=>
NULL
],
'request'
=>
[
'id'
=>
NULL
],
'data'
=>
[
'data'
=>
[
...
@@ -452,7 +452,7 @@ class CRM_Stripe_IpnTest extends CRM_Stripe_BaseTest {
...
@@ -452,7 +452,7 @@ class CRM_Stripe_IpnTest extends CRM_Stripe_BaseTest {
'id'
=>
'evt_mock_4'
,
'id'
=>
'evt_mock_4'
,
'object'
=>
'event'
,
'object'
=>
'event'
,
'type'
=>
'invoice.payment_failed'
,
'type'
=>
'invoice.payment_failed'
,
'livemode'
=>
false
,
'livemode'
=>
FALSE
,
'pending_webhooks'
=>
0
,
'pending_webhooks'
=>
0
,
'request'
=>
[
'id'
=>
NULL
],
'request'
=>
[
'id'
=>
NULL
],
'data'
=>
[
'data'
=>
[
...
@@ -479,14 +479,14 @@ class CRM_Stripe_IpnTest extends CRM_Stripe_BaseTest {
...
@@ -479,14 +479,14 @@ class CRM_Stripe_IpnTest extends CRM_Stripe_BaseTest {
// Now simulate an invoice.payment_succeeded - e.g. a 2nd charge attempt worked.
// Now simulate an invoice.payment_succeeded - e.g. a 2nd charge attempt worked.
//
//
$mockCharge3
=
new
PropertySpy
(
'charge3'
,
[
$mockCharge3
=
new
PropertySpy
(
'charge3'
,
[
'id'
=>
'ch_mock_3'
,
'id'
=>
'ch_mock_3'
,
'object'
=>
'charge'
,
'object'
=>
'charge'
,
'balance_transaction'
=>
'txn_mock_3'
,
'balance_transaction'
=>
'txn_mock_3'
,
'amount'
=>
$this
->
total
*
100
,
'amount'
=>
$this
->
total
*
100
,
'subscription'
=>
'sub_mock'
,
'subscription'
=>
'sub_mock'
,
'customer'
=>
'cus_mock'
,
'customer'
=>
'cus_mock'
,
'created'
=>
time
(),
'created'
=>
time
(),
]);
]);
$balanceTransaction2
=
new
PropertySpy
(
'balance_transaction3'
,
[
$balanceTransaction2
=
new
PropertySpy
(
'balance_transaction3'
,
[
'id'
=>
'txn_mock_3'
,
'id'
=>
'txn_mock_3'
,
'object'
=>
'balance_transaction'
,
'object'
=>
'balance_transaction'
,
...
@@ -515,7 +515,7 @@ class CRM_Stripe_IpnTest extends CRM_Stripe_BaseTest {
...
@@ -515,7 +515,7 @@ class CRM_Stripe_IpnTest extends CRM_Stripe_BaseTest {
'id'
=>
'evt_mock_5'
,
'id'
=>
'evt_mock_5'
,
'object'
=>
'event'
,
'object'
=>
'event'
,
'type'
=>
'invoice.payment_succeeded'
,
'type'
=>
'invoice.payment_succeeded'
,
'livemode'
=>
false
,
'livemode'
=>
FALSE
,
'pending_webhooks'
=>
0
,
'pending_webhooks'
=>
0
,
'request'
=>
[
'id'
=>
NULL
],
'request'
=>
[
'id'
=>
NULL
],
'data'
=>
[
'data'
=>
[
...
@@ -537,17 +537,13 @@ class CRM_Stripe_IpnTest extends CRM_Stripe_BaseTest {
...
@@ -537,17 +537,13 @@ class CRM_Stripe_IpnTest extends CRM_Stripe_BaseTest {
'contribution_status_id'
=>
'Completed'
,
'contribution_status_id'
=>
'Completed'
,
'trxn_id'
=>
'in_mock_2,ch_mock_3'
,
'trxn_id'
=>
'in_mock_2,ch_mock_3'
,
],
$contributions
[
1
]);
],
$contributions
[
1
]);
}
}
/**
/**
* Tests situation when the initial recurring payment came in OK,
* Tests situation when the initial recurring payment came in OK,
* but the subscription is then deleted.
* but the subscription is then deleted.
*/
*/
public
function
testRecurringDeletedAfterInitialSuccess
()
{
public
function
testRecurringDeletedAfterInitialSuccess
()
{
// Initial payment comes in...
// Initial payment comes in...
$this
->
testNewRecurringInvoicePaymentSucceeded
();
$this
->
testNewRecurringInvoicePaymentSucceeded
();
...
@@ -567,10 +563,10 @@ class CRM_Stripe_IpnTest extends CRM_Stripe_BaseTest {
...
@@ -567,10 +563,10 @@ class CRM_Stripe_IpnTest extends CRM_Stripe_BaseTest {
$stripeClient
=
$this
->
paymentObject
->
stripeClient
;
$stripeClient
=
$this
->
paymentObject
->
stripeClient
;
$stripeClient
->
subscriptions
=
$this
->
createMock
(
'Stripe\\Service\\SubscriptionService'
);
$stripeClient
->
subscriptions
=
$this
->
createMock
(
'Stripe\\Service\\SubscriptionService'
);
$stripeClient
->
subscriptions
$stripeClient
->
subscriptions
->
method
(
'retrieve'
)
->
method
(
'retrieve'
)
->
will
(
$this
->
returnValueMapOrDie
([
->
will
(
$this
->
returnValueMapOrDie
([
[
'sub_mock'
,
NULL
,
NULL
,
$mockSubscription
],
[
'sub_mock'
,
NULL
,
NULL
,
$mockSubscription
],
]));
]));
//
//
// Now test if we get customer.subscription.deleted .
// Now test if we get customer.subscription.deleted .
//
//
...
@@ -578,7 +574,7 @@ class CRM_Stripe_IpnTest extends CRM_Stripe_BaseTest {
...
@@ -578,7 +574,7 @@ class CRM_Stripe_IpnTest extends CRM_Stripe_BaseTest {
'type'
=>
'customer.subscription.deleted'
,
'type'
=>
'customer.subscription.deleted'
,
'id'
=>
'evt_mock_2'
,
'id'
=>
'evt_mock_2'
,
'object'
=>
'event'
,
'object'
=>
'event'
,
'livemode'
=>
false
,
'livemode'
=>
FALSE
,
'pending_webhooks'
=>
0
,
'pending_webhooks'
=>
0
,
'request'
=>
[
'id'
=>
NULL
],
'request'
=>
[
'id'
=>
NULL
],
'data'
=>
[
'data'
=>
[
...
@@ -588,9 +584,9 @@ class CRM_Stripe_IpnTest extends CRM_Stripe_BaseTest {
...
@@ -588,9 +584,9 @@ class CRM_Stripe_IpnTest extends CRM_Stripe_BaseTest {
// Recur should be Cancelled.
// Recur should be Cancelled.
$this
->
checkContribRecur
(
[
$this
->
checkContribRecur
(
[
'contribution_status_id'
=>
'Cancelled'
,
'contribution_status_id'
=>
'Cancelled'
,
'cancel_date'
=>
date
(
'Y-m-d H:i:s'
,
$cancelTimestamp
),
'cancel_date'
=>
date
(
'Y-m-d H:i:s'
,
$cancelTimestamp
),
]);
]);
// We should still have 1 contrib which should be unaffected.
// We should still have 1 contrib which should be unaffected.
$this
->
getContributionsAndAssertCount
(
1
);
$this
->
getContributionsAndAssertCount
(
1
);
...
@@ -599,6 +595,7 @@ class CRM_Stripe_IpnTest extends CRM_Stripe_BaseTest {
...
@@ -599,6 +595,7 @@ class CRM_Stripe_IpnTest extends CRM_Stripe_BaseTest {
'trxn_id'
=>
'in_mock,ch_mock'
,
'trxn_id'
=>
'in_mock,ch_mock'
,
]);
]);
}
}
/**
/**
* Retrieve the event with a matching subscription id
* Retrieve the event with a matching subscription id
*
*
...
@@ -635,7 +632,7 @@ class CRM_Stripe_IpnTest extends CRM_Stripe_BaseTest {
...
@@ -635,7 +632,7 @@ class CRM_Stripe_IpnTest extends CRM_Stripe_BaseTest {
/**
/**
* Run the webhook/ipn
* Run the webhook/ipn
*
*
* @return bool whether it was successful (nb.
false
might be valid where we
* @return bool whether it was successful (nb.
FALSE
might be valid where we
* want stripe to resend something again later)
* want stripe to resend something again later)
*/
*/
public
function
ipn
(
$event
,
$verifyRequest
=
TRUE
,
$exceptionOnFailure
=
FALSE
)
{
public
function
ipn
(
$event
,
$verifyRequest
=
TRUE
,
$exceptionOnFailure
=
FALSE
)
{
...
@@ -721,6 +718,7 @@ class CRM_Stripe_IpnTest extends CRM_Stripe_BaseTest {
...
@@ -721,6 +718,7 @@ class CRM_Stripe_IpnTest extends CRM_Stripe_BaseTest {
$this
->
assertEquals
(
$expect
,
$contribution
[
$field
],
"Expected Contribution.
$field
= "
.
json_encode
(
$expect
));
$this
->
assertEquals
(
$expect
,
$contribution
[
$field
],
"Expected Contribution.
$field
= "
.
json_encode
(
$expect
));
}
}
}
}
/**
/**
* Sugar for checking things on the contribution recur.
* Sugar for checking things on the contribution recur.
*/
*/
...
@@ -736,6 +734,7 @@ class CRM_Stripe_IpnTest extends CRM_Stripe_BaseTest {
...
@@ -736,6 +734,7 @@ class CRM_Stripe_IpnTest extends CRM_Stripe_BaseTest {
$this
->
assertEquals
(
$expect
,
$contribution
[
$field
]);
$this
->
assertEquals
(
$expect
,
$contribution
[
$field
]);
}
}
}
}
/**
/**
* Returns an array of arrays of contributions.
* Returns an array of arrays of contributions.
*/
*/
...
@@ -749,34 +748,34 @@ class CRM_Stripe_IpnTest extends CRM_Stripe_BaseTest {
...
@@ -749,34 +748,34 @@ class CRM_Stripe_IpnTest extends CRM_Stripe_BaseTest {
$this
->
assertEquals
(
$expectedCount
,
$contributions
[
'count'
]);
$this
->
assertEquals
(
$expectedCount
,
$contributions
[
'count'
]);
return
$contributions
[
'values'
];
return
$contributions
[
'values'
];
}
}
/**
/**
* DRY code
* DRY code
*/
*/
protected
function
getMocksForRecurringInvoiceFinalized
()
:
array
{
protected
function
getMocksForRecurringInvoiceFinalized
()
:
array
{
$common
=
[
$common
=
[
'subscription'
=>
'sub_mock'
,
'subscription'
=>
'sub_mock'
,
'customer'
=>
'cus_mock'
,
'customer'
=>
'cus_mock'
,
'created'
=>
time
(),
'created'
=>
time
(),
];
];
$mockCharge1
=
new
PropertySpy
(
'charge1'
,
$common
+
[
$mockCharge1
=
new
PropertySpy
(
'charge1'
,
$common
+
[
'id'
=>
'ch_mock'
,
'id'
=>
'ch_mock'
,
'object'
=>
'charge'
,
'object'
=>
'charge'
,
'balance_transaction'
=>
'txn_mock'
,
'balance_transaction'
=>
'txn_mock'
,
'amount'
=>
$this
->
total
*
100
,
'amount'
=>
$this
->
total
*
100
,
]);
]);
$mockCharge2
=
new
PropertySpy
(
'charge2'
,
$common
+
[
$mockCharge2
=
new
PropertySpy
(
'charge2'
,
$common
+
[
'id'
=>
'ch_mock_2'
,
'id'
=>
'ch_mock_2'
,
'object'
=>
'charge'
,
'object'
=>
'charge'
,
'balance_transaction'
=>
'txn_mock_2'
,
'balance_transaction'
=>
'txn_mock_2'
,
'amount'
=>
$this
->
total
*
100
,
'amount'
=>
$this
->
total
*
100
,
]);
]);
$mockInvoice2
=
new
PropertySpy
(
'invoice2'
,
$common
+
[
$mockInvoice2
=
new
PropertySpy
(
'invoice2'
,
$common
+
[
'id'
=>
'in_mock_2'
,
'id'
=>
'in_mock_2'
,
'object'
=>
'invoice'
,
'object'
=>
'invoice'
,
'amount_due'
=>
$this
->
total
*
100
,
'amount_due'
=>
$this
->
total
*
100
,
'charge'
=>
'ch_mock_2'
,
'charge'
=>
'ch_mock_2'
,
]);
]);
$balanceTransaction2
=
new
PropertySpy
(
'balance_transaction2'
,
[
$balanceTransaction2
=
new
PropertySpy
(
'balance_transaction2'
,
[
'id'
=>
'txn_mock_2'
,
'id'
=>
'txn_mock_2'
,
'object'
=>
'balance_transaction'
,
'object'
=>
'balance_transaction'
,
...
@@ -805,6 +804,7 @@ class CRM_Stripe_IpnTest extends CRM_Stripe_BaseTest {
...
@@ -805,6 +804,7 @@ class CRM_Stripe_IpnTest extends CRM_Stripe_BaseTest {
return
[
$mockCharge1
,
$mockCharge2
,
$mockInvoice2
,
$balanceTransaction2
];
return
[
$mockCharge1
,
$mockCharge2
,
$mockInvoice2
,
$balanceTransaction2
];
}
}
/**
/**
* DRY code. Sets up the database as it would be after a recurring contrib
* DRY code. Sets up the database as it would be after a recurring contrib
* has been set up with Stripe.
* has been set up with Stripe.
...
@@ -837,32 +837,32 @@ class CRM_Stripe_IpnTest extends CRM_Stripe_BaseTest {
...
@@ -837,32 +837,32 @@ class CRM_Stripe_IpnTest extends CRM_Stripe_BaseTest {
// Mock the payment methods service.
// Mock the payment methods service.
$mockPaymentMethod
=
$this
->
createMock
(
'Stripe\\PaymentMethod'
);
$mockPaymentMethod
=
$this
->
createMock
(
'Stripe\\PaymentMethod'
);
$mockPaymentMethod
->
method
(
'__get'
)
$mockPaymentMethod
->
method
(
'__get'
)
->
will
(
$this
->
returnValueMap
([
->
will
(
$this
->
returnValueMap
([
[
'id'
,
'pm_mock'
]
[
'id'
,
'pm_mock'
]
]));
]));
$stripeClient
->
paymentMethods
=
$this
->
createMock
(
'Stripe\\Service\\PaymentMethodService'
);
$stripeClient
->
paymentMethods
=
$this
->
createMock
(
'Stripe\\Service\\PaymentMethodService'
);
$stripeClient
->
paymentMethods
$stripeClient
->
paymentMethods
->
method
(
'create'
)
->
method
(
'create'
)
->
willReturn
(
$mockPaymentMethod
);
->
willReturn
(
$mockPaymentMethod
);
$stripeClient
->
paymentMethods
$stripeClient
->
paymentMethods
->
expects
(
$this
->
atLeastOnce
())
->
expects
(
$this
->
atLeastOnce
())
->
method
(
'retrieve'
)
->
method
(
'retrieve'
)
->
with
(
$this
->
equalTo
(
'pm_mock'
))
->
with
(
$this
->
equalTo
(
'pm_mock'
))
->
willReturn
(
$mockPaymentMethod
);
->
willReturn
(
$mockPaymentMethod
);
// Mock the Customers service
// Mock the Customers service
$stripeClient
->
customers
=
$this
->
createMock
(
'Stripe\\Service\\CustomerService'
);
$stripeClient
->
customers
=
$this
->
createMock
(
'Stripe\\Service\\CustomerService'
);
$stripeClient
->
customers
$stripeClient
->
customers
->
method
(
'create'
)
->
method
(
'create'
)
->
willReturn
(
->
willReturn
(
new
PropertySpy
(
'customers.create'
,
[
'id'
=>
'cus_mock'
])
new
PropertySpy
(
'customers.create'
,
[
'id'
=>
'cus_mock'
])
);
);
$stripeClient
->
customers
$stripeClient
->
customers
->
method
(
'retrieve'
)
->
method
(
'retrieve'
)
->
with
(
$this
->
equalTo
(
'cus_mock'
))
->
with
(
$this
->
equalTo
(
'cus_mock'
))
->
willReturn
(
->
willReturn
(
new
PropertySpy
(
'customers.retrieve'
,
[
'id'
=>
'cus_mock'
])
new
PropertySpy
(
'customers.retrieve'
,
[
'id'
=>
'cus_mock'
])
);
);
$mockPlan
=
$this
->
createMock
(
'Stripe\\Plan'
);
$mockPlan
=
$this
->
createMock
(
'Stripe\\Plan'
);
$mockPlan
$mockPlan
...
@@ -896,54 +896,54 @@ class CRM_Stripe_IpnTest extends CRM_Stripe_BaseTest {
...
@@ -896,54 +896,54 @@ class CRM_Stripe_IpnTest extends CRM_Stripe_BaseTest {
]));
]));
$mockSubscription
=
new
PropertySpy
(
'subscription.create'
,
[
$mockSubscription
=
new
PropertySpy
(
'subscription.create'
,
[
'id'
=>
'sub_mock'
,
'id'
=>
'sub_mock'
,
'current_period_end'
=>
time
()
+
60
*
60
*
24
,
'current_period_end'
=>
time
()
+
60
*
60
*
24
,
'latest_invoice'
=>
[
'latest_invoice'
=>
[
'id'
=>
'in_mock'
,
'id'
=>
'in_mock'
,
'payment_intent'
=>
$mockPaymentIntent
,
'payment_intent'
=>
$mockPaymentIntent
,
],
],
'pending_setup_intent'
=>
''
,
'pending_setup_intent'
=>
''
,
]);
]);
$stripeClient
->
subscriptions
=
$this
->
createMock
(
'Stripe\\Service\\SubscriptionService'
);
$stripeClient
->
subscriptions
=
$this
->
createMock
(
'Stripe\\Service\\SubscriptionService'
);
$stripeClient
->
subscriptions
$stripeClient
->
subscriptions
->
method
(
'create'
)
->
method
(
'create'
)
->
willReturn
(
$mockSubscription
);
->
willReturn
(
$mockSubscription
);
$stripeClient
->
subscriptions
$stripeClient
->
subscriptions
->
method
(
'retrieve'
)
->
method
(
'retrieve'
)
->
with
(
$this
->
equalTo
(
'sub_mock'
))
->
with
(
$this
->
equalTo
(
'sub_mock'
))
->
willReturn
(
$mockSubscription
);
->
willReturn
(
$mockSubscription
);
$stripeClient
->
balanceTransactions
=
$this
->
createMock
(
'Stripe\\Service\\BalanceTransactionService'
);
$stripeClient
->
balanceTransactions
=
$this
->
createMock
(
'Stripe\\Service\\BalanceTransactionService'
);
$stripeClient
->
balanceTransactions
$stripeClient
->
balanceTransactions
->
method
(
'retrieve'
)
->
method
(
'retrieve'
)
->
with
(
$this
->
equalTo
(
'txn_mock'
))
->
with
(
$this
->
equalTo
(
'txn_mock'
))
->
willReturn
(
new
PropertySpy
(
'balanceTransaction'
,
[
->
willReturn
(
new
PropertySpy
(
'balanceTransaction'
,
[
'id'
=>
'txn_mock'
,
'id'
=>
'txn_mock'
,
'fee'
=>
1190
,
/* means $11.90 */
'fee'
=>
1190
,
/* means $11.90 */
'currency'
=>
'usd'
,
'currency'
=>
'usd'
,
'exchange_rate'
=>
NULL
,
'exchange_rate'
=>
NULL
,
'object'
=>
'balance_transaction'
,
'object'
=>
'balance_transaction'
,
]));
]));
// $stripeClient->paymentIntents = $this->createMock('Stripe\\Service\\PaymentIntentService');
// $stripeClient->paymentIntents = $this->createMock('Stripe\\Service\\PaymentIntentService');
// todo change the status from requires_capture to ?
// todo change the status from requires_capture to ?
//$stripeClient->paymentIntents ->method('update') ->willReturn();
//$stripeClient->paymentIntents ->method('update') ->willReturn();
$mockInvoice
=
new
PropertySpy
(
'Invoice'
,
[
$mockInvoice
=
new
PropertySpy
(
'Invoice'
,
[
'amount_due'
=>
$this
->
total
*
100
,
'amount_due'
=>
$this
->
total
*
100
,
'charge_id'
=>
'ch_mock'
,
//xxx
'charge_id'
=>
'ch_mock'
,
//xxx
'created'
=>
time
(),
'created'
=>
time
(),
'currency'
=>
'usd'
,
'currency'
=>
'usd'
,
'customer'
=>
'cus_mock'
,
'customer'
=>
'cus_mock'
,
'id'
=>
'in_mock'
,
'id'
=>
'in_mock'
,
'object'
=>
'invoice'
,
'object'
=>
'invoice'
,
'subscription'
=>
'sub_mock'
,
'subscription'
=>
'sub_mock'
,
]);
]);
$stripeClient
->
invoices
=
$this
->
createMock
(
'Stripe\\Service\\InvoiceService'
);
$stripeClient
->
invoices
=
$this
->
createMock
(
'Stripe\\Service\\InvoiceService'
);
$stripeClient
->
invoices
$stripeClient
->
invoices
->
expects
(
$this
->
never
())
->
expects
(
$this
->
never
())
->
method
(
$this
->
anything
())
->
method
(
$this
->
anything
())
;
;
/*
/*
->method('all')
->method('all')
->willReturn(['data' => $mockInvoice]);
->willReturn(['data' => $mockInvoice]);
...
@@ -951,9 +951,9 @@ class CRM_Stripe_IpnTest extends CRM_Stripe_BaseTest {
...
@@ -951,9 +951,9 @@ class CRM_Stripe_IpnTest extends CRM_Stripe_BaseTest {
$stripeClient
->
charges
=
$this
->
createMock
(
'Stripe\\Service\\ChargeService'
);
$stripeClient
->
charges
=
$this
->
createMock
(
'Stripe\\Service\\ChargeService'
);
$stripeClient
->
charges
$stripeClient
->
charges
->
method
(
'retrieve'
)
->
method
(
'retrieve'
)
->
with
(
$this
->
equalTo
(
'ch_mock'
))
->
with
(
$this
->
equalTo
(
'ch_mock'
))
->
willReturn
(
$mockCharge
);
->
willReturn
(
$mockCharge
);
// Setup a recurring contribution for $this->total per month.
// Setup a recurring contribution for $this->total per month.
$this
->
setupRecurringTransaction
();
$this
->
setupRecurringTransaction
();
...
@@ -991,12 +991,14 @@ class CRM_Stripe_IpnTest extends CRM_Stripe_BaseTest {
...
@@ -991,12 +991,14 @@ class CRM_Stripe_IpnTest extends CRM_Stripe_BaseTest {
'processor_id'
=>
'sub_mock'
,
'processor_id'
=>
'sub_mock'
,
]);
]);
}
}
/**
/**
*
*
*/
*/
protected
function
returnValueMapOrDie
(
$map
)
:
ValueMapOrDie
{
protected
function
returnValueMapOrDie
(
$map
)
:
ValueMapOrDie
{
return
new
ValueMapOrDie
(
$map
);
return
new
ValueMapOrDie
(
$map
);
}
}
/**
/**
* Simulate an event being sent from Stripe and processed by our IPN code.
* Simulate an event being sent from Stripe and processed by our IPN code.
*
*
...
@@ -1006,20 +1008,19 @@ class CRM_Stripe_IpnTest extends CRM_Stripe_BaseTest {
...
@@ -1006,20 +1008,19 @@ class CRM_Stripe_IpnTest extends CRM_Stripe_BaseTest {
* @return bool result from ipn()
* @return bool result from ipn()
*/
*/
protected
function
simulateEvent
(
$eventData
,
$exceptionOnFailure
=
TRUE
)
{
protected
function
simulateEvent
(
$eventData
,
$exceptionOnFailure
=
TRUE
)
{
// Mock Event service.
// Mock Event service.
$stripeClient
=
$this
->
paymentObject
->
stripeClient
;
$stripeClient
=
$this
->
paymentObject
->
stripeClient
;
$stripeClient
->
events
=
$this
->
createMock
(
'Stripe\\Service\\EventService'
);
$stripeClient
->
events
=
$this
->
createMock
(
'Stripe\\Service\\EventService'
);
$mockEvent
=
PropertySpy
::
fromMixed
(
'simulate '
.
$eventData
[
'type'
],
$eventData
);
$mockEvent
=
PropertySpy
::
fromMixed
(
'simulate '
.
$eventData
[
'type'
],
$eventData
);
$stripeClient
->
events
$stripeClient
->
events
->
method
(
'all'
)
->
method
(
'all'
)
->
willReturn
(
new
PropertySpy
(
'events.all'
,
[
'data'
=>
[
$mockEvent
]
]));
->
willReturn
(
new
PropertySpy
(
'events.all'
,
[
'data'
=>
[
$mockEvent
]
]));
$stripeClient
->
events
$stripeClient
->
events
->
expects
(
$this
->
atLeastOnce
())
->
expects
(
$this
->
atLeastOnce
())
->
method
(
'retrieve'
)
->
method
(
'retrieve'
)
->
with
(
$this
->
equalTo
(
$eventData
[
'id'
]))
->
with
(
$this
->
equalTo
(
$eventData
[
'id'
]))
->
willReturn
(
new
PropertySpy
(
'events.retrieve'
,
$mockEvent
));
->
willReturn
(
new
PropertySpy
(
'events.retrieve'
,
$mockEvent
));
// Fetch the event
// Fetch the event
// Previously used the following - but see docblock of getEvent()
// Previously used the following - but see docblock of getEvent()
...
@@ -1054,6 +1055,7 @@ class PropertySpy implements ArrayAccess, Iterator, Countable, JsonSerializable
...
@@ -1054,6 +1055,7 @@ class PropertySpy implements ArrayAccess, Iterator, Countable, JsonSerializable
* mocked we can figure it out quickly.
* mocked we can figure it out quickly.
*/
*/
public
static
$outputMode
=
'print'
;
public
static
$outputMode
=
'print'
;
/**
/**
* @var string $buffer
* @var string $buffer
*
*
...
@@ -1074,21 +1076,26 @@ class PropertySpy implements ArrayAccess, Iterator, Countable, JsonSerializable
...
@@ -1074,21 +1076,26 @@ class PropertySpy implements ArrayAccess, Iterator, Countable, JsonSerializable
// $this->warning("Iterating " . array_keys($this->_props)[$this->key()]);
// $this->warning("Iterating " . array_keys($this->_props)[$this->key()]);
return
current
(
$this
->
_props
);
return
current
(
$this
->
_props
);
}
}
/**
/**
* Implemetns Countable
* Implemetns Countable
*/
*/
public
function
count
()
{
public
function
count
()
{
return
\count
(
$this
->
_props
);
return
\count
(
$this
->
_props
);
}
}
public
function
key
(
)
{
public
function
key
()
{
return
key
(
$this
->
_props
);
return
key
(
$this
->
_props
);
}
}
public
function
next
()
{
public
function
next
()
{
return
next
(
$this
->
_props
);
return
next
(
$this
->
_props
);
}
}
public
function
rewind
()
{
public
function
rewind
()
{
return
reset
(
$this
->
_props
);
return
reset
(
$this
->
_props
);
}
}
public
function
valid
()
{
public
function
valid
()
{
return
array_key_exists
(
key
(
$this
->
_props
),
$this
->
_props
);
return
array_key_exists
(
key
(
$this
->
_props
),
$this
->
_props
);
}
}
...
@@ -1100,6 +1107,7 @@ class PropertySpy implements ArrayAccess, Iterator, Countable, JsonSerializable
...
@@ -1100,6 +1107,7 @@ class PropertySpy implements ArrayAccess, Iterator, Countable, JsonSerializable
}
}
static
::
$globalObjects
++
;
static
::
$globalObjects
++
;
}
}
/**
/**
* Factory method
* Factory method
*
*
...
@@ -1113,14 +1121,15 @@ class PropertySpy implements ArrayAccess, Iterator, Countable, JsonSerializable
...
@@ -1113,14 +1121,15 @@ class PropertySpy implements ArrayAccess, Iterator, Countable, JsonSerializable
return
new
static
(
$name
,
$data
);
return
new
static
(
$name
,
$data
);
}
}
throw
new
\Exception
(
"PropertySpy::fromMixed requires array|PropertySpy, got "
throw
new
\Exception
(
"PropertySpy::fromMixed requires array|PropertySpy, got "
.
is_object
(
$data
)
?
get_class
(
$data
)
:
gettype
(
$data
)
.
is_object
(
$data
)
?
get_class
(
$data
)
:
gettype
(
$data
)
);
);
}
}
public
function
__destruct
()
{
public
function
__destruct
()
{
static
::
$globalObjects
--
;
static
::
$globalObjects
--
;
if
(
static
::
$buffer
===
'local'
)
{
if
(
static
::
$buffer
===
'local'
)
{
$msg
=
"PropertySpy:
$this->_name
\n
"
$msg
=
"PropertySpy:
$this->_name
\n
"
.
json_encode
(
$this
->
localLog
,
JSON_PRETTY_PRINT
)
.
"
\n
"
;
.
json_encode
(
$this
->
localLog
,
JSON_PRETTY_PRINT
)
.
"
\n
"
;
if
(
static
::
$outputMode
===
'print'
)
{
if
(
static
::
$outputMode
===
'print'
)
{
print
$msg
;
print
$msg
;
}
}
...
@@ -1145,6 +1154,7 @@ class PropertySpy implements ArrayAccess, Iterator, Countable, JsonSerializable
...
@@ -1145,6 +1154,7 @@ class PropertySpy implements ArrayAccess, Iterator, Countable, JsonSerializable
}
}
}
}
}
}
protected
function
warning
(
$msg
)
{
protected
function
warning
(
$msg
)
{
if
(
static
::
$buffer
===
'none'
)
{
if
(
static
::
$buffer
===
'none'
)
{
// Immediate output
// Immediate output
...
@@ -1162,6 +1172,7 @@ class PropertySpy implements ArrayAccess, Iterator, Countable, JsonSerializable
...
@@ -1162,6 +1172,7 @@ class PropertySpy implements ArrayAccess, Iterator, Countable, JsonSerializable
$this
->
localLog
[]
=
$msg
;
$this
->
localLog
[]
=
$msg
;
}
}
}
}
public
function
__get
(
$prop
)
{
public
function
__get
(
$prop
)
{
if
(
$prop
===
'log'
)
{
if
(
$prop
===
'log'
)
{
throw
new
\Exception
(
"stop"
);
throw
new
\Exception
(
"stop"
);
...
@@ -1172,6 +1183,7 @@ class PropertySpy implements ArrayAccess, Iterator, Countable, JsonSerializable
...
@@ -1172,6 +1183,7 @@ class PropertySpy implements ArrayAccess, Iterator, Countable, JsonSerializable
$this
->
warning
(
"->
$prop
requested but not defined"
);
$this
->
warning
(
"->
$prop
requested but not defined"
);
return
NULL
;
return
NULL
;
}
}
public
function
__set
(
$prop
,
$value
)
{
public
function
__set
(
$prop
,
$value
)
{
$this
->
_props
[
$prop
]
=
$value
;
$this
->
_props
[
$prop
]
=
$value
;
...
@@ -1181,12 +1193,14 @@ class PropertySpy implements ArrayAccess, Iterator, Countable, JsonSerializable
...
@@ -1181,12 +1193,14 @@ class PropertySpy implements ArrayAccess, Iterator, Countable, JsonSerializable
}
}
$this
->
_props
[
$prop
]
=
$value
;
$this
->
_props
[
$prop
]
=
$value
;
}
}
public
function
offsetGet
(
$prop
)
{
public
function
offsetGet
(
$prop
)
{
if
(
array_key_exists
(
$prop
,
$this
->
_props
))
{
if
(
array_key_exists
(
$prop
,
$this
->
_props
))
{
return
$this
->
_props
[
$prop
];
return
$this
->
_props
[
$prop
];
}
}
$this
->
warning
(
"['
$prop
'] requested but not defined"
);
$this
->
warning
(
"['
$prop
'] requested but not defined"
);
}
}
public
function
offsetExists
(
$prop
)
{
public
function
offsetExists
(
$prop
)
{
if
(
!
array_key_exists
(
$prop
,
$this
->
_props
))
{
if
(
!
array_key_exists
(
$prop
,
$this
->
_props
))
{
$this
->
warning
(
"['
$prop
'] offsetExists requested but not defined"
);
$this
->
warning
(
"['
$prop
'] offsetExists requested but not defined"
);
...
@@ -1194,27 +1208,33 @@ class PropertySpy implements ArrayAccess, Iterator, Countable, JsonSerializable
...
@@ -1194,27 +1208,33 @@ class PropertySpy implements ArrayAccess, Iterator, Countable, JsonSerializable
}
}
return
TRUE
;
return
TRUE
;
}
}
public
function
__isset
(
$prop
)
{
public
function
__isset
(
$prop
)
{
if
(
!
array_key_exists
(
$prop
,
$this
->
_props
))
{
if
(
!
array_key_exists
(
$prop
,
$this
->
_props
))
{
$this
->
warning
(
"isset(->
$prop
) but not defined"
);
$this
->
warning
(
"isset(->
$prop
) but not defined"
);
}
}
return
isset
(
$this
->
_props
[
$prop
]);
return
isset
(
$this
->
_props
[
$prop
]);
}
}
public
function
offsetSet
(
$prop
,
$value
)
{
public
function
offsetSet
(
$prop
,
$value
)
{
$this
->
warning
(
"['
$prop
'] offsetSet"
);
$this
->
warning
(
"['
$prop
'] offsetSet"
);
$this
->
_props
[
$prop
]
=
$value
;
$this
->
_props
[
$prop
]
=
$value
;
}
}
public
function
offsetUnset
(
$prop
)
{
public
function
offsetUnset
(
$prop
)
{
$this
->
warning
(
"['
$prop
'] offsetUnset"
);
$this
->
warning
(
"['
$prop
'] offsetUnset"
);
unset
(
$this
->
_props
[
$prop
]);
unset
(
$this
->
_props
[
$prop
]);
}
}
/**
/**
* Implement JsonSerializable
* Implement JsonSerializable
*/
*/
public
function
jsonSerialize
()
{
public
function
jsonSerialize
()
{
return
$this
->
_props
;
return
$this
->
_props
;
}
}
}
}
/**
/**
* Stubs a method by returning a value from a map.
* Stubs a method by returning a value from a map.
*/
*/
...
@@ -1247,7 +1267,9 @@ class ValueMapOrDie implements \PHPUnit\Framework\MockObject\Stub {
...
@@ -1247,7 +1267,9 @@ class ValueMapOrDie implements \PHPUnit\Framework\MockObject\Stub {
throw
new
\InvalidArgumentException
(
"Mock called with unexpected arguments: "
throw
new
\InvalidArgumentException
(
"Mock called with unexpected arguments: "
.
$invocation
->
toString
());
.
$invocation
->
toString
());
}
}
public
function
toString
():
string
{
public
function
toString
():
string
{
return
'return value from a map or throw InvalidArgumentException'
;
return
'return value from a map or throw InvalidArgumentException'
;
}
}
}
}
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment