Passed
Push — develop ( 28c299...928e2a )
by Mathias
12:40
created

MailContext   A

Complexity

Total Complexity 20

Size/Duplication

Total Lines 187
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 1

Importance

Changes 0
Metric Value
wmc 20
lcom 1
cbo 1
dl 0
loc 187
rs 10
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * YAWIK
5
 *
6
 * @filesource
7
 * @license MIT
8
 * @copyright  2013 - 2017 Cross Solution <http://cross-solution.de>
9
 */
10
11
namespace Yawik\Behat;
12
13
use Behat\Behat\Context\Context;
14
use Behat\Behat\Hook\Scope\BeforeScenarioScope;
15
use Core\Mail\FileTransport;
16
use Webmozart\Assert\Assert;
17
18
class MailContext implements Context
19
{
20
    use CommonContextTrait;
21
22
    /**
23
     * @var array
24
     */
25
    private $messages = array();
26
27
    /**
28
     * @var array
29
     */
30
    private $toMails = [];
31
32
    /**
33
     * @var array
34
     */
35
    private $fromMails = [];
36
37
    /**
38
     * @var array
39
     */
40
    private $subjects = [];
41
42
    /**
43
     * Cleans all files before start test
44
     * @BeforeScenario @mail
45
     * @param BeforeScenarioScope $scope
46
     */
47
    public function beforeScenario(BeforeScenarioScope $scope)
48
    {
49
        $core = $scope->getEnvironment()->getContext(CoreContext::class);
50
        /* @var FileTransport $transport */
51
        $transport = $core->getServiceManager()->get('Core/MailService')->getTransport();
52
        $path = $transport->getOptions()->getPath() . '/*.eml';
53
        foreach (glob($path) as $filename) {
54
            unlink($filename);
55
        }
56
57
        $this->subjects = $this->fromMails = $this->toMails = array();
58
    }
59
60
    /**
61
     * @Then an email should be sent to :address
62
     * @param string $email
63
     */
64
    public function mailShouldBeSentTo($email)
65
    {
66
        $this->iHaveEmailSent();
67
        Assert::oneOf(
68
            $email,
69
            $this->toMails
70
        );
71
    }
72
73
    /**
74
     * @Then an email should be sent from :address
75
     * @param string $email
76
     */
77
    public function mailShouldBeSentFrom($email)
78
    {
79
        $this->iHaveEmailSent();
80
        Assert::oneOf(
81
            $email,
82
            $this->fromMails
83
        );
84
    }
85
86
    /**
87
     * @Then email subject should contain :subject
88
     * @param string $subject
89
     */
90
    public function mailSubjectShouldBe($subject)
91
    {
92
        $this->iHaveEmailSent();
93
        Assert::oneOf(
94
            $subject,
95
            $this->subjects
96
        );
97
    }
98
99
    /**
100
     * @Then sent email should be contain :text
101
     */
102
    public function sentEmailShouldBeContain($text)
103
    {
104
        $this->iHaveEmailSent();
105
        $regex = '/.*('.preg_quote($text).').*/im';
106
        $matches = [];
107
        $multiMessages = false;
108
        if(count($this->messages) > 1){
109
            $multiMessages = true;
110
        }
111
        $content = "";
112
        foreach($this->messages as $key=>$definition){
113
            $content = $definition['contents'];
114
            if(preg_match($regex,$content,$match)){
115
                $matches[] = $match;
116
            }
117
        }
118
        $failMessage = sprintf('Can not find text "%s" in any email sent',$text);
119
        if(!$multiMessages){
120
            $failMessage = sprintf(
121
                'Can not find text "%s" in sent email. Here\'s the email content: %s',
122
                $text,
123
                PHP_EOL.PHP_EOL.$content
124
            );
125
        }
126
        Assert::true(count($matches)>0,$failMessage);
127
    }
128
129
    /**
130
     * @Then I have email sent
131
     */
132
    public function iHaveEmailSent()
133
    {
134
        /* @var FileTransport $transport */
135
        $transport = $this->getService('Core/MailService')->getTransport();
136
137
        $path = $transport->getOptions()->getPath().'/*.eml';
138
139
        foreach(glob($path) as $filename){
140
            $id = md5($filename);
141
            if(!isset($this->messages[$id])){
142
                $contents = file_get_contents($filename);
143
                $this->messages[$id]  = $this->parseEmail($contents);
144
            }
145
        }
146
147
        Assert::true(
148
            count($this->messages)>0,
149
            'No email have been sent'
150
        );
151
    }
152
153
    private function parseEmail($contents)
154
    {
155
        $addresses = $this->parseEmailAddress($contents);
156
        $subject =$this->parseSubject($contents);
157
158
        $contents = strip_tags($contents);
159
        $contents = preg_replace("/(^[\r\n]*|[\r\n]+)[\s\t]*[\r\n]+/", "\n", $contents);
160
161
        return array_merge($addresses,$subject,['contents' => $contents]);
162
    }
163
164
    private function parseEmailAddress($contents)
165
    {
166
        // pattern to get email address
167
        $radd =  '(\b[A-Z0-9._%+-]+@(?:[A-Z0-9-]+\.)+[A-Z]{2,6}\b)';
168
169
        // get email from address
170
        $regex = sprintf('/^From\:.*%s/im',$radd);
171
        $hasMatch = preg_match($regex,$contents,$matches);
172
        $fromAddress = $hasMatch ? $matches[1]:null;
173
174
        // get email to address
175
        $regex = sprintf('/^To\:\s+%s/im',$radd);
176
        $hasMatch = preg_match($regex,$contents,$matches);
177
        $toAddress1 = $hasMatch ? $matches[1]:null;
178
179
        // get email to address
180
        $regex = sprintf('/^To\:.*%s/im',$radd);
181
        $hasMatch = preg_match($regex,$contents,$matches);
182
        $toAddress2 = $hasMatch ? $matches[1]:null;
183
184
        $this->fromMails[] = $fromAddress;
185
        $this->toMails[] = $toAddress1;
186
        $this->toMails[] = $toAddress2;
187
188
        return [
189
            'from' => $fromAddress,
190
            'to' => [$toAddress1,$toAddress2],
191
        ];
192
    }
193
194
    private function parseSubject($contents)
195
    {
196
        $pattern = '/Subject\:(.*)/i';
197
        preg_match($pattern,$contents,$matches);
198
        $subject = isset($matches[1]) ? $matches[1]:null;
199
        $this->subjects[] = $subject;
200
        return [
201
            'subject' => trim($subject)
202
        ];
203
    }
204
}
205