Completed
Push — master ( 364c87...b1a20a )
by Jeroen De
111:53 queued 46:58
created

testGivenRecurringPaymentStatusMessage_currencyIsCheckedInDifferentField()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 16
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 16
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 13
nc 2
nop 0
1
<?php
2
3
namespace WMDE\Fundraising\Frontend\Tests\Unit\Infrastructure;
4
5
use GuzzleHttp\Client;
6
use GuzzleHttp\Psr7\Response;
7
use GuzzleHttp\Psr7\Stream;
8
use WMDE\Fundraising\Frontend\Infrastructure\PayPalPaymentNotificationVerifier;
9
use WMDE\Fundraising\Frontend\Infrastructure\PayPalPaymentNotificationVerifierException;
10
11
/**
12
 * @covers WMDE\Fundraising\Frontend\Infrastructure\PayPalPaymentNotificationVerifier
13
 * @licence GNU GPL v2+
14
 * @author Kai Nissen < [email protected] >
15
 */
16
class PayPalPaymentNotificationVerifierTest extends \PHPUnit_Framework_TestCase {
17
18
	const VALID_ACCOUNT_EMAIL = '[email protected]';
19
	const INVALID_ACCOUNT_EMAIL = '[email protected]';
20
	const DUMMY_API_URL = 'https://dummy-url.com';
21
	const VALID_PAYMENT_STATUS = 'Completed';
22
	const INVALID_PAYMENT_STATUS = 'Unknown';
23
	const ITEM_NAME = 'My donation';
24
	const CURRENCY_EUR = 'EUR';
25
	const RECURRING_NO_PAYMENT = 'recurring_payment_suspended_due_to_max_failed_payment';
26
27
	public function testReceiverAddressMismatches_verifierThrowsException() {
28
		$this->expectException( PayPalPaymentNotificationVerifierException::class );
29
30
		$this->newVerifier( new Client() )->verify( [
31
			'receiver_email' => self::INVALID_ACCOUNT_EMAIL,
32
			'payment_status' => self::VALID_PAYMENT_STATUS
33
		] );
34
	}
35
36
	public function testReceiverAddressNotGiven_verifierThrowsException() {
37
		$this->expectException( PayPalPaymentNotificationVerifierException::class );
38
39
		$this->newVerifier( new Client() )->verify( [] );
40
	}
41
42
	public function testPaymentStatusNotGiven_verifierThrowsException() {
43
		$this->expectException( PayPalPaymentNotificationVerifierException::class );
44
		$this->newVerifier( new Client() )->verify( [
45
			'receiver_email' => self::VALID_ACCOUNT_EMAIL
46
		] );
47
	}
48
49
	public function testPaymentStatusNotConfirmable_verifierThrowsException() {
50
		$this->expectException( PayPalPaymentNotificationVerifierException::class );
51
		$this->newVerifier( new Client() )->verify( [
52
			'receiver_email' => self::VALID_ACCOUNT_EMAIL,
53
			'payment_status' => self::INVALID_PAYMENT_STATUS,
54
		] );
55
	}
56
57
	public function testReassuringReceivedDataSucceeds_verifierDoesNotThrowException() {
58
		try {
59
			$this->newVerifier( $this->newSucceedingClient() )->verify( $this->newRequest() );
60
		} catch ( PayPalPaymentNotificationVerifierException $e ) {
61
			$this->fail( 'There should be no exception with valid data and succeeding client.' );
62
		}
63
	}
64
65
	public function testReassuringReceivedDataFails_verifierThrowsException() {
66
		$this->expectException( PayPalPaymentNotificationVerifierException::class );
67
		$verifier = $this->newVerifier( $this->newFailingClient() );
68
		$verifier->verify( $this->newRequest() );
69
	}
70
71
	public function testGivenRecurringPaymentStatusMessage_currencyIsCheckedInDifferentField() {
72
		try {
73
			$expectedParams = [
74
				'cmd' => '_notify-validate',
75
				'receiver_email' => self::VALID_ACCOUNT_EMAIL,
76
				'payment_status' => self::VALID_PAYMENT_STATUS,
77
				'item_name' => self::ITEM_NAME,
78
				'txn_type' => self::RECURRING_NO_PAYMENT,
79
				'currency_code' => self::CURRENCY_EUR
80
			];
81
			$this->newVerifier( $this->newSucceedingClientExpectingParams( $expectedParams ) )
82
				->verify( $this->newFailedRecurringPaymentRequest() );
83
		} catch ( PayPalPaymentNotificationVerifierException $e ) {
84
			$this->fail( 'Currency in different field should be ok for non-payment-complete recurring notices.' );
85
		}
86
	}
87
88
	private function newRequest(): array {
89
		return [
90
			'receiver_email' => self::VALID_ACCOUNT_EMAIL,
91
			'payment_status' => self::VALID_PAYMENT_STATUS,
92
			'item_name' => self::ITEM_NAME,
93
			'mc_currency' => self::CURRENCY_EUR
94
		];
95
	}
96
97
	private function newFailedRecurringPaymentRequest(): array {
98
		return [
99
			'receiver_email' => self::VALID_ACCOUNT_EMAIL,
100
			'payment_status' => self::VALID_PAYMENT_STATUS,
101
			'item_name' => self::ITEM_NAME,
102
			'txn_type' => self::RECURRING_NO_PAYMENT,
103
			'currency_code' => self::CURRENCY_EUR
104
		];
105
	}
106
107
	private function newVerifier( Client $httpClient ): PayPalPaymentNotificationVerifier {
108
		return new PayPalPaymentNotificationVerifier(
109
			$httpClient,
110
			self::DUMMY_API_URL,
111
			self::VALID_ACCOUNT_EMAIL
112
		);
113
	}
114
115
	private function newSucceedingClient(): Client {
116
		$body = $this->getMockBuilder( Stream::class )
117
			->disableOriginalConstructor()
118
			->setMethods( [ 'getContents' ] )
119
			->getMock();
120
121
		$body->expects( $this->once() )
122
			->method( 'getContents' )
123
			->willReturn( 'VERIFIED' );
124
125
		return $this->newClient( $body );
126
	}
127
128
	private function newSucceedingClientExpectingParams( array $expectedParams ): Client {
129
		$body = $this->getMockBuilder( Stream::class )
130
			->disableOriginalConstructor()
131
			->setMethods( [ 'getContents' ] )
132
			->getMock();
133
134
		$body->expects( $this->once() )
135
			->method( 'getContents' )
136
			->willReturn( 'VERIFIED' );
137
138
		return $this->newClient( $body, $expectedParams );
139
	}
140
141
	private function newFailingClient(): Client {
142
		$body = $this->getMockBuilder( Stream::class )
143
			->disableOriginalConstructor()
144
			->setMethods( [ 'getContents' ] )
145
			->getMock();
146
147
		$body->expects( $this->once() )
148
			->method( 'getContents' )
149
			->willReturn( 'INVALID' );
150
151
		return $this->newClient( $body );
152
	}
153
154
	private function newClient( Stream $body, array $expectedParams = null ): Client {
155
		$response = $this->getMockBuilder( Response::class )
156
			->disableOriginalConstructor()
157
			->setMethods( [ 'getBody' ] )
158
			->getMock();
159
160
		$response->expects( $this->once() )
161
			->method( 'getBody' )
162
			->willReturn( $body );
163
164
		$client = $this->getMockBuilder( Client::class )
165
			->disableOriginalConstructor()
166
			->setMethods( [ 'post' ] )
167
			->getMock();
168
169
		if ( is_null( $expectedParams ) ) {
170
			$expectedParams = [
171
				'cmd' => '_notify-validate',
172
				'receiver_email' => self::VALID_ACCOUNT_EMAIL,
173
				'payment_status' => self::VALID_PAYMENT_STATUS,
174
				'item_name' => self::ITEM_NAME,
175
				'mc_currency' => self::CURRENCY_EUR
176
			];
177
		}
178
		$client->expects( $this->once() )
179
			->method( 'post' )
180
			->with( self::DUMMY_API_URL, [
181
				'form_params' => $expectedParams
182
			] )
183
			->willReturn( $response );
184
185
		return $client;
186
	}
187
188
}
189