Completed
Push — master ( bd2868...16a7fa )
by Jeroen De
12s
created

getSucceedingPolicyValidatorMock()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 9
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 9
rs 9.6666
c 0
b 0
f 0
cc 1
eloc 6
nc 1
nop 0
1
<?php
2
3
declare( strict_types = 1 );
4
5
namespace WMDE\Fundraising\Frontend\DonationContext\Tests\Integration\UseCases\AddDonation;
6
7
use PHPUnit_Framework_MockObject_MockObject;
8
use WMDE\Euro\Euro;
9
use WMDE\Fundraising\Frontend\DonationContext\Authorization\DonationTokenFetcher;
10
use WMDE\Fundraising\Frontend\DonationContext\Authorization\DonationTokens;
11
use WMDE\Fundraising\Frontend\DonationContext\Domain\Model\Donation;
12
use WMDE\Fundraising\Frontend\DonationContext\Domain\Model\DonorName;
13
use WMDE\Fundraising\Frontend\DonationContext\Domain\Repositories\DonationRepository;
14
use WMDE\Fundraising\Frontend\DonationContext\Infrastructure\DonationConfirmationMailer;
15
use WMDE\Fundraising\Frontend\DonationContext\Tests\Fixtures\FakeDonationRepository;
16
use WMDE\Fundraising\Frontend\DonationContext\Tests\Fixtures\FixedDonationTokenFetcher;
17
use WMDE\Fundraising\Frontend\DonationContext\UseCases\AddDonation\AddDonationPolicyValidator;
18
use WMDE\Fundraising\Frontend\DonationContext\UseCases\AddDonation\AddDonationRequest;
19
use WMDE\Fundraising\Frontend\DonationContext\UseCases\AddDonation\AddDonationUseCase;
20
use WMDE\Fundraising\Frontend\DonationContext\UseCases\AddDonation\AddDonationValidationResult;
21
use WMDE\Fundraising\Frontend\DonationContext\UseCases\AddDonation\AddDonationValidator;
22
use WMDE\Fundraising\Frontend\DonationContext\UseCases\AddDonation\ReferrerGeneralizer;
23
use WMDE\Fundraising\Frontend\PaymentContext\Domain\Model\PaymentType;
24
use WMDE\Fundraising\Frontend\PaymentContext\Domain\TransferCodeGenerator;
25
use WMDE\Fundraising\Frontend\DonationContext\Tests\Data\ValidDonation;
26
use WMDE\Fundraising\Frontend\Validation\ConstraintViolation;
27
28
/**
29
 * @covers WMDE\Fundraising\Frontend\DonationContext\UseCases\AddDonation\AddDonationUseCase
30
 *
31
 * @license GNU GPL v2+
32
 * @author Kai Nissen < [email protected] >
33
 * @author Jeroen De Dauw < [email protected] >
34
 */
35
class AddDonationUseCaseTest extends \PHPUnit\Framework\TestCase {
36
37
	private const UPDATE_TOKEN = 'a very nice token';
38
	private const ACCESS_TOKEN = 'kindly allow me access';
39
40
	/**
41
	 * @var \DateTime
42
	 */
43
	private $oneHourInTheFuture;
44
45
	public function setUp() {
46
		$this->oneHourInTheFuture = ( new \DateTime() )->add( $this->newOneHourInterval() );
47
	}
48
49
	public function testWhenValidationSucceeds_successResponseIsCreated() {
50
		$useCase = $this->newValidationSucceedingUseCase();
51
52
		$this->assertTrue( $useCase->addDonation( $this->newMinimumDonationRequest() )->isSuccessful() );
53
	}
54
55
	private function newValidationSucceedingUseCase(): AddDonationUseCase {
56
		return new AddDonationUseCase(
57
			$this->newRepository(),
58
			$this->getSucceedingValidatorMock(),
59
			$this->getSucceedingPolicyValidatorMock(),
60
			new ReferrerGeneralizer( 'http://foo.bar', [] ),
61
			$this->newMailer(),
0 ignored issues
show
Bug introduced by
It seems like $this->newMailer() targeting WMDE\Fundraising\Fronten...seCaseTest::newMailer() can also be of type object<PHPUnit_Framework_MockObject_MockObject>; however, WMDE\Fundraising\Fronten...nUseCase::__construct() does only seem to accept object<WMDE\Fundraising\...tionConfirmationMailer>, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
62
			$this->newTransferCodeGenerator(),
63
			$this->newTokenFetcher()
64
		);
65
	}
66
67
	/**
68
	 * @return DonationConfirmationMailer|PHPUnit_Framework_MockObject_MockObject
69
	 */
70
	private function newMailer(): DonationConfirmationMailer {
71
		return $this->getMockBuilder( DonationConfirmationMailer::class )
72
			->disableOriginalConstructor()
73
			->getMock();
74
	}
75
76
	private function newTokenFetcher(): DonationTokenFetcher {
77
		return new FixedDonationTokenFetcher( new DonationTokens(
78
			self::ACCESS_TOKEN,
79
			self::UPDATE_TOKEN
80
		) );
81
	}
82
83
	private function newOneHourInterval(): \DateInterval {
84
		return new \DateInterval( 'PT1H' );
85
	}
86
87
	private function newRepository(): DonationRepository {
88
		return new FakeDonationRepository();
89
	}
90
91
	public function testValidationFails_responseObjectContainsViolations() {
92
		$useCase = new AddDonationUseCase(
93
			$this->newRepository(),
94
			$this->getFailingValidatorMock( new ConstraintViolation( 'foo', 'bar' ) ),
95
			$this->getSucceedingPolicyValidatorMock(),
96
			new ReferrerGeneralizer( 'http://foo.bar', [] ),
97
			$this->newMailer(),
0 ignored issues
show
Bug introduced by
It seems like $this->newMailer() targeting WMDE\Fundraising\Fronten...seCaseTest::newMailer() can also be of type object<PHPUnit_Framework_MockObject_MockObject>; however, WMDE\Fundraising\Fronten...nUseCase::__construct() does only seem to accept object<WMDE\Fundraising\...tionConfirmationMailer>, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
98
			$this->newTransferCodeGenerator(),
99
			$this->newTokenFetcher()
100
		);
101
102
		$result = $useCase->addDonation( $this->newMinimumDonationRequest() );
103
		$this->assertEquals( [ new ConstraintViolation( 'foo', 'bar' ) ], $result->getValidationErrors() );
104
	}
105
106
	public function testValidationFails_responseObjectContainsRequestObject() {
107
		$useCase = new AddDonationUseCase(
108
			$this->newRepository(),
109
			$this->getFailingValidatorMock( new ConstraintViolation( 'foo', 'bar' ) ),
110
			$this->getSucceedingPolicyValidatorMock(),
111
			new ReferrerGeneralizer( 'http://foo.bar', [] ),
112
			$this->newMailer(),
0 ignored issues
show
Bug introduced by
It seems like $this->newMailer() targeting WMDE\Fundraising\Fronten...seCaseTest::newMailer() can also be of type object<PHPUnit_Framework_MockObject_MockObject>; however, WMDE\Fundraising\Fronten...nUseCase::__construct() does only seem to accept object<WMDE\Fundraising\...tionConfirmationMailer>, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
113
			$this->newTransferCodeGenerator(),
114
			$this->newTokenFetcher()
115
		);
116
117
		$request = $this->newInvalidDonationRequest();
118
		$useCase->addDonation( $request );
119
		$this->assertEquals( $this->newInvalidDonationRequest(), $request );
120
	}
121
122
	private function getSucceedingValidatorMock(): AddDonationValidator {
123
		$validator = $this->getMockBuilder( AddDonationValidator::class )
124
			->disableOriginalConstructor()
125
			->getMock();
126
127
		$validator->method( 'validate' )->willReturn( new AddDonationValidationResult() );
128
129
		return $validator;
130
	}
131
132
	private function getFailingValidatorMock( ConstraintViolation $violation ): AddDonationValidator {
133
		$validator = $this->getMockBuilder( AddDonationValidator::class )
134
			->disableOriginalConstructor()
135
			->getMock();
136
137
		$validator->method( 'validate' )->willReturn( new AddDonationValidationResult( $violation ) );
138
139
		return $validator;
140
	}
141
142
	private function getSucceedingPolicyValidatorMock(): AddDonationPolicyValidator {
143
		$validator = $this->getMockBuilder( AddDonationPolicyValidator::class )
144
			->disableOriginalConstructor()
145
			->getMock();
146
147
		$validator->method( 'needsModeration' )->willReturn( false );
148
149
		return $validator;
150
	}
151
152
	private function getFailingPolicyValidatorMock(): AddDonationPolicyValidator {
153
		$validator = $this->getMockBuilder( AddDonationPolicyValidator::class )
154
			->disableOriginalConstructor()
155
			->getMock();
156
157
		$validator->method( 'needsModeration' )->willReturn( true );
158
159
		return $validator;
160
	}
161
162
	private function newMinimumDonationRequest(): AddDonationRequest {
163
		$donationRequest = new AddDonationRequest();
164
		$donationRequest->setAmount( Euro::newFromString( '1.00' ) );
165
		$donationRequest->setPaymentType( PaymentType::BANK_TRANSFER );
166
		$donationRequest->setDonorType( DonorName::PERSON_ANONYMOUS );
167
		return $donationRequest;
168
	}
169
170
	private function newInvalidDonationRequest(): AddDonationRequest {
171
		$donationRequest = new AddDonationRequest();
172
		$donationRequest->setPaymentType( PaymentType::DIRECT_DEBIT );
173
		$donationRequest->setAmount( Euro::newFromInt( 0 ) );
174
		$donationRequest->setDonorType( DonorName::PERSON_ANONYMOUS );
175
		return $donationRequest;
176
	}
177
178
	public function testGivenInvalidRequest_noConfirmationEmailIsSend() {
179
		$mailer = $this->newMailer();
180
181
		$mailer->expects( $this->never() )->method( $this->anything() );
0 ignored issues
show
Bug introduced by
The method expects does only exist in PHPUnit_Framework_MockObject_MockObject, but not in WMDE\Fundraising\Fronten...ationConfirmationMailer.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
182
183
		$useCase = new AddDonationUseCase(
184
			$this->newRepository(),
185
			$this->getFailingValidatorMock( new ConstraintViolation( 'foo', 'bar' ) ),
186
			$this->getSucceedingPolicyValidatorMock(),
187
			new ReferrerGeneralizer( 'http://foo.bar', [] ),
188
			$mailer,
0 ignored issues
show
Bug introduced by
It seems like $mailer defined by $this->newMailer() on line 179 can also be of type object<PHPUnit_Framework_MockObject_MockObject>; however, WMDE\Fundraising\Fronten...nUseCase::__construct() does only seem to accept object<WMDE\Fundraising\...tionConfirmationMailer>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
189
			$this->newTransferCodeGenerator(),
190
			$this->newTokenFetcher()
191
		);
192
193
		$useCase->addDonation( $this->newMinimumDonationRequest() );
194
	}
195
196
	private function newTransferCodeGenerator(): TransferCodeGenerator {
197
		return $this->createMock( TransferCodeGenerator::class );
198
	}
199
200
	public function testGivenValidRequest_confirmationEmailIsSent() {
201
		$mailer = $this->newMailer();
202
		$donation = $this->newValidAddDonationRequestWithEmail( '[email protected]' );
203
204
		$mailer->expects( $this->once() )
0 ignored issues
show
Bug introduced by
The method expects does only exist in PHPUnit_Framework_MockObject_MockObject, but not in WMDE\Fundraising\Fronten...ationConfirmationMailer.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
205
			->method( 'sendConfirmationMailFor' )
206
			->with( $this->isInstanceOf( Donation::class ) );
207
208
		$useCase = $this->newUseCaseWithMailer( $mailer );
0 ignored issues
show
Bug introduced by
It seems like $mailer defined by $this->newMailer() on line 201 can also be of type object<PHPUnit_Framework_MockObject_MockObject>; however, WMDE\Fundraising\Fronten...:newUseCaseWithMailer() does only seem to accept object<WMDE\Fundraising\...tionConfirmationMailer>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
209
210
		$useCase->addDonation( $donation );
211
	}
212
213
	public function testGivenValidRequestWithExternalPaymentType_confirmationEmailIsNotSent() {
214
		$mailer = $this->newMailer();
215
216
		$mailer->expects( $this->never() )->method( $this->anything() );
0 ignored issues
show
Bug introduced by
The method expects does only exist in PHPUnit_Framework_MockObject_MockObject, but not in WMDE\Fundraising\Fronten...ationConfirmationMailer.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
217
218
		$useCase = $this->newUseCaseWithMailer( $mailer );
0 ignored issues
show
Bug introduced by
It seems like $mailer defined by $this->newMailer() on line 214 can also be of type object<PHPUnit_Framework_MockObject_MockObject>; however, WMDE\Fundraising\Fronten...:newUseCaseWithMailer() does only seem to accept object<WMDE\Fundraising\...tionConfirmationMailer>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
219
220
		$request = $this->newValidAddDonationRequestWithEmail( '[email protected]' );
221
		$request->setPaymentType( 'PPL' );
222
		$useCase->addDonation( $request );
223
	}
224
225
	public function testGivenValidRequestWithPolicyViolation_donationIsModerated() {
226
		$useCase = new AddDonationUseCase(
227
			$this->newRepository(),
228
			$this->getSucceedingValidatorMock(),
229
			$this->getFailingPolicyValidatorMock(),
230
			new ReferrerGeneralizer( 'http://foo.bar', [] ),
231
			$this->newMailer(),
0 ignored issues
show
Bug introduced by
It seems like $this->newMailer() targeting WMDE\Fundraising\Fronten...seCaseTest::newMailer() can also be of type object<PHPUnit_Framework_MockObject_MockObject>; however, WMDE\Fundraising\Fronten...nUseCase::__construct() does only seem to accept object<WMDE\Fundraising\...tionConfirmationMailer>, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
232
			$this->newTransferCodeGenerator(),
233
			$this->newTokenFetcher()
234
		);
235
236
		$response = $useCase->addDonation( $this->newValidAddDonationRequestWithEmail( '[email protected]' ) );
237
		$this->assertTrue( $response->getDonation()->needsModeration() );
238
	}
239
240
	public function testGivenPolicyViolationForExternalPaymentDonation_donationIsNotModerated() {
241
		$useCase = new AddDonationUseCase(
242
			$this->newRepository(),
243
			$this->getSucceedingValidatorMock(),
244
			$this->getFailingPolicyValidatorMock(),
245
			new ReferrerGeneralizer( 'http://foo.bar', [] ),
246
			$this->newMailer(),
0 ignored issues
show
Bug introduced by
It seems like $this->newMailer() targeting WMDE\Fundraising\Fronten...seCaseTest::newMailer() can also be of type object<PHPUnit_Framework_MockObject_MockObject>; however, WMDE\Fundraising\Fronten...nUseCase::__construct() does only seem to accept object<WMDE\Fundraising\...tionConfirmationMailer>, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
247
			$this->newTransferCodeGenerator(),
248
			$this->newTokenFetcher()
249
		);
250
251
		$request = $this->newValidAddDonationRequestWithEmail( '[email protected]' );
252
		$request->setPaymentType( 'PPL' );
253
		$response = $useCase->addDonation( $request );
254
		$this->assertFalse( $response->getDonation()->needsModeration() );
255
	}
256
257
	private function newUseCaseWithMailer( DonationConfirmationMailer $mailer ) {
258
		return new AddDonationUseCase(
259
			$this->newRepository(),
260
			$this->getSucceedingValidatorMock(),
261
			$this->getSucceedingPolicyValidatorMock(),
262
			new ReferrerGeneralizer( 'http://foo.bar', [] ),
263
			$mailer,
264
			$this->newTransferCodeGenerator(),
265
			$this->newTokenFetcher()
266
		);
267
	}
268
269
	private function newValidAddDonationRequestWithEmail( string $email ): AddDonationRequest {
270
		$request = $this->newMinimumDonationRequest();
271
272
		$request->setDonorType( DonorName::PERSON_PRIVATE );
273
		$request->setDonorFirstName( ValidDonation::DONOR_FIRST_NAME );
274
		$request->setDonorLastName( ValidDonation::DONOR_LAST_NAME );
275
		$request->setDonorCompany( '' );
276
		$request->setDonorSalutation( ValidDonation::DONOR_SALUTATION );
277
		$request->setDonorTitle( ValidDonation::DONOR_TITLE );
278
		$request->setDonorStreetAddress( ValidDonation::DONOR_STREET_ADDRESS );
279
		$request->setDonorCity( ValidDonation::DONOR_CITY );
280
		$request->setDonorPostalCode( ValidDonation::DONOR_POSTAL_CODE );
281
		$request->setDonorCountryCode( ValidDonation::DONOR_COUNTRY_CODE );
282
		$request->setDonorEmailAddress( $email );
283
284
		return $request;
285
	}
286
287
	private function newValidCompanyDonationRequest(): AddDonationRequest {
288
		$request = $this->newMinimumDonationRequest();
289
290
		$request->setDonorType( DonorName::PERSON_COMPANY );
291
		$request->setDonorFirstName( '' );
292
		$request->setDonorLastName( '' );
293
		$request->setDonorCompany( ValidDonation::DONOR_LAST_NAME );
294
		$request->setDonorSalutation( '' );
295
		$request->setDonorTitle( '' );
296
		$request->setDonorStreetAddress( ValidDonation::DONOR_STREET_ADDRESS );
297
		$request->setDonorCity( ValidDonation::DONOR_CITY );
298
		$request->setDonorPostalCode( ValidDonation::DONOR_POSTAL_CODE );
299
		$request->setDonorCountryCode( ValidDonation::DONOR_COUNTRY_CODE );
300
		$request->setDonorEmailAddress( ValidDonation::DONOR_EMAIL_ADDRESS );
301
302
		return $request;
303
	}
304
305
	public function testWhenAdditionWorks_successResponseContainsTokens() {
306
		$useCase = $this->newValidationSucceedingUseCase();
307
308
		$response = $useCase->addDonation( $this->newMinimumDonationRequest() );
309
310
		$this->assertSame( self::UPDATE_TOKEN, $response->getUpdateToken() );
311
		$this->assertSame( self::ACCESS_TOKEN, $response->getAccessToken() );
312
	}
313
314
	public function testWhenAddingCompanyDonation_salutationFieldIsSet() {
315
		$useCase = $this->newValidationSucceedingUseCase();
316
317
		$response = $useCase->addDonation( $this->newValidCompanyDonationRequest() );
318
319
		$this->assertSame( DonorName::COMPANY_SALUTATION, $response->getDonation()->getDonor()->getName()->getSalutation() );
320
	}
321
322
}
323