LoginContext   A
last analyzed

Complexity

Total Complexity 16

Size/Duplication

Total Lines 168
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 7

Importance

Changes 8
Bugs 0 Features 0
Metric Value
c 8
b 0
f 0
dl 0
loc 168
rs 10
wmc 16
lcom 2
cbo 7

9 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 5 1
A getSession() 0 4 1
A stepIAmLoggedIn() 0 13 2
B iAmLoggedInWithPermissions() 0 38 4
A stepIAmNotLoggedIn() 0 5 1
B stepILogInWith() 0 34 4
A stepIShouldSeeALogInForm() 0 6 1
A stepIWillSeeALogInMessage() 0 6 1
A stepPasswordForEmailShouldBe() 0 6 1
1
<?php
2
3
namespace SilverStripe\BehatExtension\Context;
4
5
use Behat\Behat\Context\BehatContext;
6
use Behat\Behat\Context\Step;
7
use SilverStripe\ORM\DataObject;
8
use SilverStripe\Security\Group;
9
use SilverStripe\Security\Member;
10
11
// PHPUnit
12
require_once BASE_PATH . '/vendor/phpunit/phpunit/src/Framework/Assert/Functions.php';
13
14
/**
15
 * LoginContext
16
 *
17
 * Context used to define steps related to login and logout functionality
18
 */
19
class LoginContext extends BehatContext
20
{
21
    protected $context;
22
23
    /**
24
     * Cache for logInWithPermission()
25
     */
26
    protected $cache_generatedMembers = array();
27
28
    /**
29
     * Initializes context.
30
     * Every scenario gets it's own context object.
31
     *
32
     * @param array $parameters context parameters (set them up through behat.yml)
33
     */
34
    public function __construct(array $parameters)
35
    {
36
        // Initialize your context here
37
        $this->context = $parameters;
38
    }
39
40
    /**
41
     * Get Mink session from MinkContext
42
     */
43
    public function getSession($name = null)
44
    {
45
        return $this->getMainContext()->getSession($name);
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Behat\Behat\Context\ExtendedContextInterface as the method getSession() does only exist in the following implementations of said interface: Behat\MinkExtension\Context\MinkContext, Behat\MinkExtension\Context\RawMinkContext, SilverStripe\BehatExtension\Context\BasicContext, SilverStripe\BehatExtension\Context\EmailContext, SilverStripe\BehatExtension\Context\FixtureContext, SilverStripe\BehatExtension\Context\LoginContext, SilverStripe\BehatExtens...ext\SilverStripeContext.

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...
46
    }
47
48
    /**
49
     * @Given /^I am logged in$/
50
     */
51
    public function stepIAmLoggedIn()
52
    {
53
        $c = $this->getMainContext();
54
        $adminUrl = $c->joinUrlParts($c->getBaseUrl(), $c->getAdminUrl());
55
        $loginUrl = $c->joinUrlParts($c->getBaseUrl(), $c->getLoginUrl());
56
57
        $this->getSession()->visit($adminUrl);
58
59
        if (0 == strpos($this->getSession()->getCurrentUrl(), $loginUrl)) {
60
            $this->stepILogInWith('admin', 'password');
61
            assertStringStartsWith($adminUrl, $this->getSession()->getCurrentUrl());
62
        }
63
    }
64
65
    /**
66
     * Creates a member in a group with the correct permissions.
67
     * Example: Given I am logged in with "ADMIN" permissions
68
     *
69
     * @Given /^I am logged in with "([^"]*)" permissions$/
70
     */
71
    public function iAmLoggedInWithPermissions($permCode)
72
    {
73
        if (!isset($this->cache_generatedMembers[$permCode])) {
74
            $group = Group::get()->filter('Title', "$permCode group")->first();
75
            if (!$group) {
76
                $group = \Injector::inst()->create('SilverStripe\\Security\\Group');
77
            }
78
79
            $group->Title = "$permCode group";
80
            $group->write();
81
82
            $permission = \Injector::inst()->create('SilverStripe\\Security\\Permission');
83
            $permission->Code = $permCode;
84
            $permission->write();
85
            $group->Permissions()->add($permission);
86
87
            $member = DataObject::get_one('SilverStripe\\Security\\Member', sprintf('"Email" = \'%s\'', "[email protected]"));
88
            if (!$member) {
89
                $member = \Injector::inst()->create('SilverStripe\\Security\\Member');
90
            }
91
92
            // make sure any validation for password is skipped, since we're not testing complexity here
93
            $validator = Member::password_validator();
94
            Member::set_password_validator(null);
0 ignored issues
show
Documentation introduced by
null is of type null, but the function expects a object<SilverStripe\Security\PasswordValidator>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
95
            $member->FirstName = $permCode;
96
            $member->Surname = "User";
97
            $member->Email = "[email protected]";
98
            $member->PasswordEncryption = "none";
99
            $member->changePassword('Secret!123');
100
            $member->write();
101
            $group->Members()->add($member);
102
            Member::set_password_validator($validator);
103
104
            $this->cache_generatedMembers[$permCode] = $member;
105
        }
106
107
        return new Step\Given(sprintf('I log in with "%s" and "%s"', "[email protected]", 'Secret!123'));
108
    }
109
110
    /**
111
     * @Given /^I am not logged in$/
112
     */
113
    public function stepIAmNotLoggedIn()
114
    {
115
        $c = $this->getMainContext();
116
        $this->getSession()->visit($c->joinUrlParts($c->getBaseUrl(), 'Security/logout'));
117
    }
118
119
     /**
120
     * @When /^I log in with "(?<username>[^"]*)" and "(?<password>[^"]*)"$/
121
     */
122
    public function stepILogInWith($email, $password)
123
    {
124
        $c = $this->getMainContext();
125
        $loginUrl = $c->joinUrlParts($c->getBaseUrl(), $c->getLoginUrl());
126
        $this->getSession()->visit($loginUrl);
127
        $page = $this->getSession()->getPage();
128
        $forms = $page->findAll('xpath', '//form[contains(@action, "Security/LoginForm")]');
129
        assertNotNull($forms, 'Login form not found');
130
131
        // Try to find visible forms again on login page.
132
        $visibleForm = null;
133
        foreach ($forms as $form) {
134
            if ($form->isVisible() && $form->find('css', '[name=Email]')) {
135
                $visibleForm = $form;
136
            }
137
        }
138
139
        assertNotNull($visibleForm, 'Could not find login form');
140
141
        $emailField = $visibleForm->find('css', '[name=Email]');
142
        $passwordField = $visibleForm->find('css', '[name=Password]');
143
        $submitButton = $visibleForm->find('css', '[type=submit]');
144
        $securityID = $visibleForm->find('css', '[name=SecurityID]');
0 ignored issues
show
Unused Code introduced by
$securityID is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
145
146
        assertNotNull($emailField, 'Email field on login form not found');
147
        assertNotNull($passwordField, 'Password field on login form not found');
148
        assertNotNull($submitButton, 'Submit button on login form not found');
149
        // @todo Once CSRF is mandatory, uncomment this
150
        // assertNotNull($securityID, 'CSRF token not found');
151
152
        $emailField->setValue($email);
153
        $passwordField->setValue($password);
154
        $submitButton->press();
155
    }
156
157
    /**
158
     * @Given /^I should see a log-in form$/
159
     */
160
    public function stepIShouldSeeALogInForm()
161
    {
162
        $page = $this->getSession()->getPage();
163
        $loginForm = $page->find('css', '#MemberLoginForm_LoginForm');
164
        assertNotNull($loginForm, 'I should see a log-in form');
165
    }
166
167
    /**
168
     * @Then /^I will see a "([^"]*)" log-in message$/
169
     */
170
    public function stepIWillSeeALogInMessage($type)
171
    {
172
        $page = $this->getSession()->getPage();
173
        $message = $page->find('css', sprintf('.message.%s', $type));
174
        assertNotNull($message, sprintf('%s message not found.', $type));
175
    }
176
177
    /**
178
     * @Then /^the password for "([^"]*)" should be "([^"]*)"$/
179
     */
180
    public function stepPasswordForEmailShouldBe($id, $password)
181
    {
182
        $member = Member::get()->filter('Email', $id)->First();
183
        assertNotNull($member);
184
        assertTrue($member->checkPassword($password)->valid());
185
    }
186
}
187