Completed
Push — master ( 9c7552...7979b4 )
by Alejandro
04:30 queued 02:06
created

testAdapterAsInstance()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 13
Code Lines 9

Duplication

Lines 13
Ratio 100 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 13
loc 13
rs 9.4286
cc 1
eloc 9
nc 1
nop 0
1
<?php
2
namespace AcMailerTest\Service;
3
4
use AcMailer\Event\MailEvent;
5
use AcMailer\Options\MailOptions;
6
use AcMailer\Service\Factory\MailServiceAbstractFactory;
7
use AcMailer\Service\Factory\MailServiceFactory;
8
use AcMailerTest\Event\MailListenerMock;
9
use AcMailerTest\ServiceManager\ServiceManagerMock;
10
use Zend\EventManager\EventManagerAwareInterface;
11
use Zend\Mail\Transport\File;
12
use Zend\Mail\Transport\Sendmail;
13
use Zend\Mail\Transport\Smtp;
14
use Zend\ServiceManager\ServiceLocatorInterface;
15
use Zend\Stdlib\ArrayUtils;
16
use Zend\View\Renderer\PhpRenderer;
17
use Zend\View\Resolver\TemplatePathStack;
18
use PHPUnit_Framework_TestCase as TestCase;
19
20
/**
21
 * Class MailServiceFactoryTest
22
 * @author Alejandro Celaya Alastrué
23
 * @link http://www.alejandrocelaya.com
24
 */
25
class MailServiceAbstractFactoryTest extends TestCase
26
{
27
    /**
28
     * @var MailServiceAbstractFactory
29
     */
30
    private $mailServiceFactory;
31
    /**
32
     * @var ServiceLocatorInterface
33
     */
34
    private $serviceLocator;
35
36
    public function setUp()
37
    {
38
        $this->mailServiceFactory = new MailServiceAbstractFactory();
39
    }
40
41
    public function testMessageData()
42
    {
43
        $options = [
44
            'message_options' => [
45
                'from'          => '[email protected]',
46
                'from_name'     => 'Alejandro Celaya',
47
                'reply_to'      => '[email protected]',
48
                'reply_to_name' => 'Alejandro Celaya',
49
                'to'            => ['[email protected]', '[email protected]'],
50
                'cc'            => ['[email protected]'],
51
                'bcc'           => ['[email protected]'],
52
                'subject'       => 'The subject',
53
                'body'          => ['content' => 'The body'],
54
            ]
55
        ];
56
        $this->initServiceLocator($options);
57
        $mailService = $this->mailServiceFactory->createServiceWithName(
58
            $this->serviceLocator,
59
            'acmailer.mailservice.default',
60
            ''
61
        );
62
63
        $this->assertInstanceOf('AcMailer\Service\MailService', $mailService);
64
        $this->assertEquals(
65
            $options['message_options']['from_name'],
66
            $mailService->getMessage()->getFrom()->get($options['message_options']['from'])->getName()
67
        );
68
        $this->assertEquals(
69
            $options['message_options']['reply_to_name'],
70
            $mailService->getMessage()->getReplyTo()->get($options['message_options']['reply_to'])->getName()
71
        );
72
        $toArray = array_keys(ArrayUtils::iteratorToArray($mailService->getMessage()->getTo()));
73
        $ccArray = array_keys(ArrayUtils::iteratorToArray($mailService->getMessage()->getCc()));
74
        $bccArray = array_keys(ArrayUtils::iteratorToArray($mailService->getMessage()->getBcc()));
75
        $this->assertEquals($options['message_options']['to'], $toArray);
76
        $this->assertEquals($options['message_options']['cc'], $ccArray);
77
        $this->assertEquals($options['message_options']['bcc'], $bccArray);
78
        $this->assertEquals($options['message_options']['subject'], $mailService->getMessage()->getSubject());
79
        $this->assertInstanceof('Zend\Mime\Message', $mailService->getMessage()->getBody());
80
    }
81
82
    public function testSmtpAdapter()
83
    {
84
        $options = [
85
            'mail_adapter' => 'Zend\Mail\Transport\Smtp',
86
            'smtp_options' => [
87
                'host'  => 'the.host',
88
                'port'  => 465,
89
                'connection_config' => [
90
                    'username'  => 'alejandro',
91
                    'password'  => '1234',
92
                    'ssl'       => 'ssl',
93
                ]
94
            ]
95
        ];
96
        $this->initServiceLocator($options);
97
        $mailService = $this->mailServiceFactory->createServiceWithName(
98
            $this->serviceLocator,
99
            'acmailer.mailservice.default',
100
            ''
101
        );
102
103
        /* @var Smtp $transport */
104
        $transport = $mailService->getTransport();
105
        $this->assertInstanceOf($options['mail_adapter'], $transport);
106
        $connConfig = $transport->getOptions()->getConnectionConfig();
107
        $this->assertEquals($options['smtp_options']['connection_config']['username'], $connConfig['username']);
108
        $this->assertEquals($options['smtp_options']['connection_config']['password'], $connConfig['password']);
109
        $this->assertEquals($options['smtp_options']['connection_config']['ssl'], $connConfig['ssl']);
110
        $this->assertEquals($options['smtp_options']['host'], $transport->getOptions()->getHost());
111
        $this->assertEquals($options['smtp_options']['port'], $transport->getOptions()->getPort());
112
    }
113
114
    public function testFileAdapter()
115
    {
116
        $options = [
117
            'mail_adapter'  => 'file',
118
            'file_options' => [
119
                'path'     => __DIR__,
120
                'callback' => function ($transport) {
121
                    return get_class($transport);
122
                }
123
            ]
124
        ];
125
        $this->initServiceLocator($options);
126
        $mailService = $this->mailServiceFactory->createServiceWithName(
127
            $this->serviceLocator,
128
            'acmailer.mailservice.default',
129
            ''
130
        );
131
132
        /* @var File $transport */
133
        $transport = $mailService->getTransport();
134
        $this->assertInstanceOf('Zend\Mail\Transport\File', $transport);
135
        $this->assertEquals($options['file_options']['path'], $transport->getOptions()->getPath());
136
        $this->assertEquals($options['file_options']['callback'], $transport->getOptions()->getCallback());
137
    }
138
139 View Code Duplication
    public function testAdapterAsService()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
140
    {
141
        $this->initServiceLocator([
142
            'mail_adapter' => 'my_transport_service'
143
        ]);
144
        $transport = new Sendmail();
145
        $this->serviceLocator->set('my_transport_service', $transport);
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Zend\ServiceManager\ServiceLocatorInterface as the method set() does only exist in the following implementations of said interface: AcMailerTest\ServiceManager\ServiceManagerMock.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
146
        $mailService = $this->mailServiceFactory->createServiceWithName(
147
            $this->serviceLocator,
148
            'acmailer.mailservice.default',
149
            ''
150
        );
151
        $this->assertSame($transport, $mailService->getTransport());
152
    }
153
154
    /**
155
     * @expectedException \AcMailer\Exception\InvalidArgumentException
156
     */
157
    public function testAdapterAsInvalidService()
158
    {
159
        $this->initServiceLocator([
160
            'mail_adapter' => 'my_transport_service'
161
        ]);
162
        $this->mailServiceFactory->createServiceWithName(
163
            $this->serviceLocator,
164
            'acmailer.mailservice.default',
165
            ''
166
        );
167
    }
168
169
    /**
170
     * @expectedException \AcMailer\Exception\InvalidArgumentException
171
     */
172
    public function testAdapterAsAserviceNotReturningTransport()
173
    {
174
        $this->initServiceLocator([
175
            'mail_adapter' => 'my_transport_service'
176
        ]);
177
        $this->serviceLocator->set('my_transport_service', new \stdClass());
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Zend\ServiceManager\ServiceLocatorInterface as the method set() does only exist in the following implementations of said interface: AcMailerTest\ServiceManager\ServiceManagerMock.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
178
        $this->mailServiceFactory->createServiceWithName(
179
            $this->serviceLocator,
180
            'acmailer.mailservice.default',
181
            ''
182
        );
183
    }
184
185 View Code Duplication
    public function testAdapterAsInstance()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
186
    {
187
        $expected = new Sendmail();
188
        $this->initServiceLocator([
189
            'mail_adapter' => $expected
190
        ]);
191
        $mailService = $this->mailServiceFactory->createServiceWithName(
192
            $this->serviceLocator,
193
            'acmailer.mailservice.default',
194
            ''
195
        );
196
        $this->assertSame($expected, $mailService->getTransport());
197
    }
198
199
    public function testViewRendererService()
200
    {
201
        $this->initServiceLocator();
202
        // Create the service with default configuration
203
        $mailService = $this->mailServiceFactory->createServiceWithName(
204
            $this->serviceLocator,
205
            'acmailer.mailservice.default',
206
            ''
207
        );
208
        /** @var PhpRenderer $renderer */
209
        $renderer = $mailService->getRenderer();
210
        $this->assertInstanceOf('Zend\View\Renderer\PhpRenderer', $renderer);
211
        $this->assertInstanceOf('Zend\View\Resolver\TemplatePathStack', $renderer->resolver());
212
213
        // Set a template_map and unset the template_path_stack
214
        $config = $this->serviceLocator->get('Config');
215
        unset($config['view_manager']['template_path_stack']);
216
        $config['view_manager']['template_map'] = [];
217
        $this->serviceLocator->set('Config', $config);
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Zend\ServiceManager\ServiceLocatorInterface as the method set() does only exist in the following implementations of said interface: AcMailerTest\ServiceManager\ServiceManagerMock.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
218
        $mailService = $this->mailServiceFactory->createServiceWithName(
219
            $this->serviceLocator,
220
            'acmailer.mailservice.default',
221
            ''
222
        );
223
        /** @var PhpRenderer $renderer */
224
        $renderer = $mailService->getRenderer();
225
        $this->assertInstanceOf('Zend\View\Renderer\PhpRenderer', $renderer);
226
        $this->assertInstanceOf('Zend\View\Resolver\TemplateMapResolver', $renderer->resolver());
227
228
        // Set both a template_map and a template_path_stack
229
        $this->initServiceLocator();
230
        $config = $this->serviceLocator->get('Config');
231
        $config['view_manager']['template_map'] = [];
232
        $this->serviceLocator->set('Config', $config);
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Zend\ServiceManager\ServiceLocatorInterface as the method set() does only exist in the following implementations of said interface: AcMailerTest\ServiceManager\ServiceManagerMock.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
233
        $mailService = $this->mailServiceFactory->createServiceWithName(
234
            $this->serviceLocator,
235
            'acmailer.mailservice.default',
236
            ''
237
        );
238
        /** @var PhpRenderer $renderer */
239
        $renderer = $mailService->getRenderer();
240
        $this->assertInstanceOf('Zend\View\Renderer\PhpRenderer', $renderer);
241
        $this->assertInstanceOf('Zend\View\Resolver\AggregateResolver', $renderer->resolver());
242
243
        // Set a viewrenderer service and see if it is used
244
        $renderer = new PhpRenderer();
245
        $this->serviceLocator->set('mailviewrenderer', $renderer);
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Zend\ServiceManager\ServiceLocatorInterface as the method set() does only exist in the following implementations of said interface: AcMailerTest\ServiceManager\ServiceManagerMock.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
246
        $mailService = $this->mailServiceFactory->createServiceWithName(
247
            $this->serviceLocator,
248
            'acmailer.mailservice.default',
249
            ''
250
        );
251
        $this->assertSame($renderer, $mailService->getRenderer());
252
    }
253
254
    public function testTemplateBody()
255
    {
256
        $options = [
257
            'message_options' => [
258
                'body' => [
259
                    'content' => 'This body is not going to be used',
260
                    'use_template'  => true,
261
                    'template' => [
262
                        'path'          => 'ac-mailer/mail-templates/layout',
263
                        'children'      => [
264
                            'content'   => [
265
                                'path'   => 'ac-mailer/mail-templates/mail',
266
                            ]
267
                        ]
268
                    ],
269
                ]
270
            ]
271
        ];
272
        $this->initServiceLocator($options);
273
274
        $resolver = new TemplatePathStack();
275
        $resolver->addPath(__DIR__ . '/../../view');
276
        $renderer = new PhpRenderer();
277
        $renderer->setResolver($resolver);
278
        $this->serviceLocator->set('mailviewrenderer', $renderer);
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Zend\ServiceManager\ServiceLocatorInterface as the method set() does only exist in the following implementations of said interface: AcMailerTest\ServiceManager\ServiceManagerMock.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
279
        $mailService = $this->mailServiceFactory->createServiceWithName(
280
            $this->serviceLocator,
281
            'acmailer.mailservice.default',
282
            ''
283
        );
284
285
        $this->assertNotEquals($options ['message_options']['body']['content'], $mailService->getMessage()->getBody());
286
        $this->assertInstanceOf('Zend\Mime\Message', $mailService->getMessage()->getBody());
287
    }
288
289
    public function testWithDefaultLayout()
290
    {
291
        $options = [
292
            'message_options' => [
293
                'body' => [
294
                    'use_template'  => true,
295
                    'template' => [
296
                        'path'          => 'ac-mailer/mail-templates/mail',
297
                        'default_layout' => [
298
                            'path' => 'ac-mailer/mail-templates/layout',
299
                        ]
300
                    ],
301
                ]
302
            ]
303
        ];
304
        $this->initServiceLocator($options);
305
306
        $resolver = new TemplatePathStack();
307
        $resolver->addPath(__DIR__ . '/../../view');
308
        $renderer = new PhpRenderer();
309
        $renderer->setResolver($resolver);
310
        $this->serviceLocator->set('mailviewrenderer', $renderer);
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Zend\ServiceManager\ServiceLocatorInterface as the method set() does only exist in the following implementations of said interface: AcMailerTest\ServiceManager\ServiceManagerMock.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
311
        $mailService = $this->mailServiceFactory->createServiceWithName(
312
            $this->serviceLocator,
313
            'acmailer.mailservice.default',
314
            ''
315
        );
316
        $this->assertInstanceOf('Zend\Mime\Message', $mailService->getMessage()->getBody());
317
    }
318
319
    public function testFileAttachments()
320
    {
321
        $cwd = getcwd();
322
        chdir(dirname(__DIR__));
323
        $options = [
324
            'message_options' => [
325
                'attachments' => [
326
                    'files' => [
327
                        'attachments/file1',
328
                        'attachments/file2',
329
                    ],
330
                    'dir' => [
331
                        'iterate'   => true,
332
                        'path'      => 'attachments/dir',
333
                        'recursive' => true,
334
                    ],
335
                ],
336
            ]
337
        ];
338
        $this->initServiceLocator($options);
339
        $mailService = $this->mailServiceFactory->createServiceWithName(
340
            $this->serviceLocator,
341
            'acmailer.mailservice.default',
342
            ''
343
        );
344
345
        $this->assertCount(4, $mailService->getAttachments());
346
        chdir($cwd);
347
    }
348
349
    public function testListeners()
350
    {
351
        $options = [
352
            'mail_listeners' => [
353
                new MailListenerMock(),
354
                'mail_listener_service',
355
                'AcMailerTest\Event\MailListenerMock'
356
            ]
357
        ];
358
        $this->initServiceLocator($options);
359
        $this->serviceLocator->set('mail_listener_service', new MailListenerMock());
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Zend\ServiceManager\ServiceLocatorInterface as the method set() does only exist in the following implementations of said interface: AcMailerTest\ServiceManager\ServiceManagerMock.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
360
361
        /** @var EventManagerAwareInterface $mailService */
362
        $mailService = $this->mailServiceFactory->createServiceWithName(
363
            $this->serviceLocator,
364
            'acmailer.mailservice.default',
365
            ''
366
        );
367
        $this->assertCount(3, $mailService->getEventManager()->getListeners(MailEvent::EVENT_MAIL_PRE_SEND));
0 ignored issues
show
Deprecated Code introduced by
The method Zend\EventManager\EventM...terface::getListeners() has been deprecated with message: This method is deprecated with 2.6.0, and will be removed in 3.0.0. See {@link https://github.com/zendframework/zend-eventmanager/blob/develop/doc/book/migration/removed.md} for details.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
368
    }
369
370
    /**
371
     * @expectedException \AcMailer\Exception\InvalidArgumentException
372
     */
373
    public function testInvalidListenersThrowException()
374
    {
375
        $options = [
376
            'mail_listeners' => [
377
                new \stdClass(),
378
                'invalid_service',
379
                '\Nonsens\Foo'
380
            ]
381
        ];
382
        $this->initServiceLocator($options);
383
        $this->mailServiceFactory->createServiceWithName(
384
            $this->serviceLocator,
385
            'acmailer.mailservice.default',
386
            ''
387
        );
388
    }
389
390
    private function initServiceLocator(array $mailOptions = [])
391
    {
392
        $this->serviceLocator = new ServiceManagerMock([
393
            'acmailer.mailoptions.default' => new MailOptions($mailOptions),
394
            'Config' => include __DIR__ . '/../../config/module.config.php'
395
        ]);
396
    }
397
}
398