Completed
Pull Request — master (#830)
by Jeroen De
65:14
created

testWhenAuthorizationSucceedsForAnonymousDonation_confirmationMail()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 12
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 12
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 8
nc 1
nop 0
1
<?php
2
3
declare( strict_types = 1 );
4
5
namespace WMDE\Fundraising\Frontend\DonationContext\Tests\Integration\UseCases\CreditCardPaymentNotification;
6
7
use Psr\Log\NullLogger;
8
use WMDE\Euro\Euro;
9
use WMDE\Fundraising\Frontend\DonationContext\DataAccess\DoctrineDonationRepository;
10
use WMDE\Fundraising\Frontend\DonationContext\Infrastructure\DonationConfirmationMailer;
11
use WMDE\Fundraising\Frontend\DonationContext\Infrastructure\DonationEventLogger;
12
use WMDE\Fundraising\Frontend\DonationContext\Tests\Fixtures\DonationEventLoggerSpy;
13
use WMDE\Fundraising\Frontend\DonationContext\Tests\Fixtures\DonationRepositorySpy;
14
use WMDE\Fundraising\Frontend\DonationContext\Tests\Fixtures\FailingDonationAuthorizer;
15
use WMDE\Fundraising\Frontend\DonationContext\Tests\Fixtures\FakeDonationRepository;
16
use WMDE\Fundraising\Frontend\DonationContext\Tests\Fixtures\SucceedingDonationAuthorizer;
17
use WMDE\Fundraising\Frontend\DonationContext\UseCases\CreditCardPaymentNotification\CreditCardNotificationUseCase;
18
use WMDE\Fundraising\Frontend\DonationContext\UseCases\CreditCardPaymentNotification\CreditCardPaymentHandlerException;
19
use WMDE\Fundraising\Frontend\MembershipContext\Tests\Data\ValidCreditCardNotificationRequest;
20
use WMDE\Fundraising\Frontend\DonationContext\Tests\Data\ValidDonation;
21
use WMDE\Fundraising\Frontend\Tests\Fixtures\FakeCreditCardService;
22
use WMDE\Fundraising\Frontend\Tests\Fixtures\ThrowingEntityManager;
23
24
/**
25
 * @covers WMDE\Fundraising\Frontend\DonationContext\UseCases\CreditCardPaymentNotification\CreditCardNotificationUseCase
26
 *
27
 * @licence GNU GPL v2+
28
 * @author Kai Nissen < [email protected] >
29
 */
30
class CreditCardNotificationUseCaseTest extends \PHPUnit\Framework\TestCase {
31
32
	/** @var DoctrineDonationRepository|FakeDonationRepository|DonationRepositorySpy */
33
	private $repository;
34
	private $authorizer;
35
	/** @var DonationConfirmationMailer|\PHPUnit_Framework_MockObject_MockObject */
36
	private $mailer;
37
	private $eventLogger;
38
	private $creditCardService;
39
40
	public function setUp() {
41
		$this->repository = new FakeDonationRepository();
42
		$this->authorizer = new SucceedingDonationAuthorizer();
43
		$this->mailer = $this->newMailer();
44
		$this->eventLogger = $this->newEventLogger();
45
		$this->creditCardService = new FakeCreditCardService();
46
	}
47
48
	public function testWhenRepositoryThrowsException_handlerThrowsException() {
49
		$this->repository = new DoctrineDonationRepository( ThrowingEntityManager::newInstance( $this ) );
50
		$this->authorizer = new FailingDonationAuthorizer();
51
		$useCase = $this->newCreditCardNotificationUseCase();
52
		$request = ValidCreditCardNotificationRequest::newBillingNotification( 1 );
53
54
		$this->expectException( CreditCardPaymentHandlerException::class );
55
		$useCase->handleNotification( $request );
56
	}
57
58
	public function testWhenAuthorizationFails_handlerThrowsException() {
59
		$this->authorizer = new FailingDonationAuthorizer();
60
		$this->repository->storeDonation( ValidDonation::newIncompleteCreditCardDonation() );
61
62
		$useCase = $this->newCreditCardNotificationUseCase();
63
64
		$request = ValidCreditCardNotificationRequest::newBillingNotification( 1 );
65
66
		$this->expectException( CreditCardPaymentHandlerException::class );
67
		$useCase->handleNotification( $request );
68
	}
69
70
	public function testWhenAuthorizationSucceeds_handlerDoesNotThrowException() {
71
		$this->repository->storeDonation( ValidDonation::newIncompleteCreditCardDonation() );
72
73
		$useCase = $this->newCreditCardNotificationUseCase();
74
75
		$request = ValidCreditCardNotificationRequest::newBillingNotification( 1 );
76
77
		try {
78
			$useCase->handleNotification( $request );
79
		} catch ( \Exception $e ) {
80
			$this->fail();
81
		}
82
	}
83
84
	public function testWhenPaymentTypeIsIncorrect_handlerThrowsException() {
85
		$this->repository->storeDonation( ValidDonation::newDirectDebitDonation() );
86
87
		$useCase = $this->newCreditCardNotificationUseCase();
88
89
		$request = ValidCreditCardNotificationRequest::newBillingNotification( 1 );
90
91
		$this->expectException( CreditCardPaymentHandlerException::class );
92
		$useCase->handleNotification( $request );
93
	}
94
95
	public function testWhenAuthorizationSucceeds_confirmationMailIsSent() {
96
		$donation = ValidDonation::newIncompleteCreditCardDonation();
97
		$this->repository->storeDonation( $donation );
98
99
		$this->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...
100
			->method( 'sendConfirmationMailFor' );
101
			// TODO: assert that the correct values are passed to the mailer
102
103
		$useCase = $this->newCreditCardNotificationUseCase();
104
105
		$request = ValidCreditCardNotificationRequest::newBillingNotification( 1 );
106
		$useCase->handleNotification( $request );
107
	}
108
109
	public function testWhenAuthorizationSucceedsForAnonymousDonation_confirmationMailIsNotSent() {
110
		$donation = ValidDonation::newIncompleteAnonymousCreditCardDonation();
111
		$this->repository->storeDonation( $donation );
112
113
		$this->mailer->expects( $this->never() )
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...
114
			->method( 'sendConfirmationMailFor' );
115
116
		$useCase = $this->newCreditCardNotificationUseCase();
117
118
		$request = ValidCreditCardNotificationRequest::newBillingNotification( 1 );
119
		$useCase->handleNotification( $request );
120
	}
121
122
	public function testWhenAuthorizationSucceeds_donationIsStored() {
123
		$donation = ValidDonation::newIncompleteCreditCardDonation();
124
		$this->repository = new DonationRepositorySpy( $donation );
125
126
		$useCase = $this->newCreditCardNotificationUseCase();
127
128
		$request = ValidCreditCardNotificationRequest::newBillingNotification( 1 );
129
		$useCase->handleNotification( $request );
130
		$this->assertCount( 1, $this->repository->getStoreDonationCalls() );
131
	}
132
133
	public function testWhenAuthorizationSucceeds_donationIsBooked() {
134
		$donation = ValidDonation::newIncompleteCreditCardDonation();
135
		$this->repository = new DonationRepositorySpy( $donation );
136
137
		$useCase = $this->newCreditCardNotificationUseCase();
138
139
		$request = ValidCreditCardNotificationRequest::newBillingNotification( 1 );
140
		$useCase->handleNotification( $request );
141
		$this->assertTrue( $this->repository->getDonationById( $donation->getId() )->isBooked() );
142
	}
143
144
	public function testWhenAuthorizationSucceeds_bookingEventIsLogged() {
145
		$donation = ValidDonation::newIncompleteCreditCardDonation();
146
		$this->repository = new DonationRepositorySpy( $donation );
147
		$this->eventLogger = new DonationEventLoggerSpy();
148
149
		$useCase = $this->newCreditCardNotificationUseCase();
150
151
		$request = ValidCreditCardNotificationRequest::newBillingNotification( 1 );
152
		$useCase->handleNotification( $request );
153
154
		$this->assertEventLogContainsExpression( $this->eventLogger, $donation->getId(), '/booked/' );
155
	}
156
157
	public function testWhenSendingConfirmationMailFails_handlerDoesNotThrowException() {
158
		$this->repository->storeDonation( ValidDonation::newIncompleteCreditCardDonation() );
159
160
		$this->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...
161
			->method( 'sendConfirmationMailFor' )
162
			->willThrowException( new \RuntimeException( 'Oh noes!' ) );
163
164
		$useCase = $this->newCreditCardNotificationUseCase();
165
166
		$request = ValidCreditCardNotificationRequest::newBillingNotification( 1 );
167
		try {
168
			$useCase->handleNotification( $request );
169
		} catch ( \Exception $e ) {
170
			$this->fail();
171
		}
172
	}
173
174
	private function assertEventLogContainsExpression( DonationEventLoggerSpy $eventLoggerSpy, int $donationId, string $expr ) {
175
		$foundCalls = array_filter( $eventLoggerSpy->getLogCalls(), function( $call ) use ( $donationId, $expr ) {
176
			return $call[0] == $donationId && preg_match( $expr, $call[1] );
177
		} );
178
		$assertMsg = 'Failed to assert that donation event log log contained "' . $expr . '" for donation id '.$donationId;
179
		$this->assertCount( 1, $foundCalls, $assertMsg );
180
	}
181
182
	/**
183
	 * @return DonationConfirmationMailer|\PHPUnit_Framework_MockObject_MockObject
184
	 */
185
	private function newMailer(): DonationConfirmationMailer {
186
		return $this->getMockBuilder( DonationConfirmationMailer::class )->disableOriginalConstructor()->getMock();
187
	}
188
189
	/**
190
	 * @return DonationEventLogger|\PHPUnit_Framework_MockObject_MockObject
191
	 */
192
	private function newEventLogger(): DonationEventLogger {
193
		return $this->createMock( DonationEventLogger::class );
194
	}
195
196
	private function newCreditCardNotificationUseCase() {
197
		return new CreditCardNotificationUseCase(
198
			$this->repository,
199
			$this->authorizer,
200
			$this->creditCardService,
201
			$this->mailer,
202
			new NullLogger(),
203
			$this->eventLogger
204
		);
205
	}
206
207
	public function testWhenPaymentAmountMismatches_handlerThreepwoodsException() {
208
		$this->repository->storeDonation( ValidDonation::newIncompleteCreditCardDonation() );
209
210
		$useCase = $this->newCreditCardNotificationUseCase();
211
212
		$request = ValidCreditCardNotificationRequest::newBillingNotification( 1 );
213
		$request->setAmount( Euro::newFromInt( 35505 ) );
214
215
		$this->expectException( CreditCardPaymentHandlerException::class );
216
		$useCase->handleNotification( $request );
217
	}
218
219
}
220