Completed
Pull Request — develop (#243)
by Tom
20:40 queued 07:41
created

TestApplication::getApplication()   B

Complexity

Conditions 4
Paths 4

Size

Total Lines 31
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 31
rs 8.5806
c 0
b 0
f 0
cc 4
eloc 17
nc 4
nop 0
1
<?php
2
/*
3
 * this file is part of magerun
4
 *
5
 * @author Tom Klingenberg <https://github.com/ktomk>
6
 */
7
8
namespace N98\Magento;
9
10
use PHPUnit_Framework_MockObject_Generator;
11
use PHPUnit_Framework_MockObject_Matcher_AnyInvokedCount;
12
use PHPUnit_Framework_MockObject_MockObject;
13
use PHPUnit_Framework_MockObject_Stub_Return;
14
use PHPUnit_Framework_SkippedTestError;
15
use RuntimeException;
16
17
/**
18
 * Magento test-application, the one used in unit and integration testing.
19
 *
20
 * @package N98\Magento
21
 */
22
class TestApplication
23
{
24
    /**
25
     * @var Application
26
     */
27
    private $application;
28
29
    /**
30
     * @var string|null
31
     */
32
    private $root;
33
34
    /**
35
     * @var string
36
     */
37
    private $varname;
38
39
    /**
40
     * @var string
41
     */
42
    private $basename;
43
44
    /**
45
     * @param string $varname name of the environment variable containing the test-root
46
     * @param string $basename name of the stopfile containing the test-root
47
     *
48
     * @return string|null
49
     */
50
    public static function getTestMagentoRootFromEnvironment($varname, $basename)
51
    {
52
        $root = getenv($varname);
53
        if (empty($root) && strlen($basename)) {
54
            $stopfile = getcwd() . '/' . $basename;
55
            if (is_readable($stopfile) && $buffer = rtrim(file_get_contents($stopfile))) {
56
                $root = $buffer;
57
            }
58
        }
59
        if (empty($root)) {
60
            return;
61
        }
62
63
        # directory test
64
        if (!is_dir($root)) {
65
            throw new RuntimeException(
66
                sprintf("%s path '%s' is not a directory", $varname, $root)
67
            );
68
        }
69
70
        # resolve root to realpath to be independent to current working directory
71
        $rootRealpath = realpath($root);
72
        if (false === $rootRealpath) {
73
            throw new RuntimeException(
74
                sprintf("Failed to resolve %s path '%s' with realpath()", $varname, $root)
75
            );
76
        }
77
78
        return $rootRealpath;
79
    }
80
81
    /**
82
     * @return array
83
     */
84
    public static function getConfig()
85
    {
86
        $testApplication = new TestApplication();
87
        $config = $testApplication->getApplication()->getConfig();
0 ignored issues
show
Bug introduced by
The method getConfig does only exist in N98\Magento\Application, but not in PHPUnit_Framework_MockObject_MockObject.

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...
88
89
        return $config;
90
    }
91
92
    /**
93
     * TestApplication constructor.
94
     *
95
     * @param string $varname [optional] name of the environment variable containing the path to magento-root
0 ignored issues
show
Documentation introduced by
Should the type for parameter $varname not be string|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
96
     */
97
    public function __construct($varname = null, $basename = null)
98
    {
99
        if (null === $varname) {
100
            $varname = 'N98_MAGERUN2_TEST_MAGENTO_ROOT';
101
        }
102
        if (null === $basename) {
103
            $basename = '.n98-magerun2';
104
        }
105
        $this->varname = $varname;
106
        $this->basename = $basename;
107
    }
108
109
    /**
110
     * getter for the magento root directory of the test-suite
111
     *
112
     * @see ApplicationTest::testExecute
113
     *
114
     * @return string
0 ignored issues
show
Documentation introduced by
Should the return type not be string|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
115
     */
116
    public function getTestMagentoRoot()
117
    {
118
        if ($this->root) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->root of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
119
            return $this->root;
120
        }
121
122
        $varname = $this->varname;
123
124
        $root = self::getTestMagentoRootFromEnvironment($varname, $this->basename);
125
126
        if (null === $root) {
127
            $this->markTestSkipped(
128
                "Please specify environment variable $varname with path to your test magento installation!"
129
            );
130
        }
131
132
        return $this->root = $root;
133
    }
134
135
    /**
136
     * @return Application|PHPUnit_Framework_MockObject_MockObject
137
     */
138
    public function getApplication()
139
    {
140
        if ($this->application === null) {
141
            $root = $this->getTestMagentoRoot();
142
143
            $mockObjectGenerator = new PHPUnit_Framework_MockObject_Generator;
144
145
            /** @var Application|PHPUnit_Framework_MockObject_MockObject $application */
146
            $application = $mockObjectGenerator->getMock('N98\Magento\Application', array('getMagentoRootFolder'));
147
148
            // Get the composer bootstraph
149
            if (defined('PHPUNIT_COMPOSER_INSTALL')) {
150
                $loader = require PHPUNIT_COMPOSER_INSTALL;
151
            } elseif (file_exists(__DIR__ . '/../../../../../autoload.php')) {
152
                // Installed via composer, already in vendor
153
                $loader = require __DIR__ . '/../../../../../autoload.php';
154
            } else {
155
                // Check if testing root package without PHPUnit
156
                $loader = require __DIR__ . '/../../../vendor/autoload.php';
157
            }
158
159
            $application->setAutoloader($loader);
0 ignored issues
show
Bug introduced by
The method setAutoloader does only exist in N98\Magento\Application, but not in PHPUnit_Framework_MockObject_MockObject.

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...
160
            $application->expects($this->any())->method('getMagentoRootFolder')->will($this->returnValue($root));
0 ignored issues
show
Bug introduced by
The method expects does only exist in PHPUnit_Framework_MockObject_MockObject, but not in N98\Magento\Application.

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
            $application->init();
0 ignored issues
show
Bug introduced by
The method init does only exist in N98\Magento\Application, but not in PHPUnit_Framework_MockObject_MockObject.

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...
162
            $application->initMagento();
0 ignored issues
show
Bug introduced by
The method initMagento does only exist in N98\Magento\Application, but not in PHPUnit_Framework_MockObject_MockObject.

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...
163
164
            $this->application = $application;
0 ignored issues
show
Documentation Bug introduced by
It seems like $application can also be of type object<PHPUnit_Framework_MockObject_MockObject>. However, the property $application is declared as type object<N98\Magento\Application>. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
165
        }
166
167
        return $this->application;
168
    }
169
170
    /*
171
     * PHPUnit TestCase methods
172
     */
173
174
    /**
175
     * Returns a matcher that matches when the method it is evaluated for
176
     * is executed zero or more times.
177
     *
178
     * @return PHPUnit_Framework_MockObject_Matcher_AnyInvokedCount
179
     * @since  Method available since Release 3.0.0
180
     */
181
    public static function any()
182
    {
183
        return new PHPUnit_Framework_MockObject_Matcher_AnyInvokedCount;
184
    }
185
186
    /**
187
     *
188
     *
189
     * @param  mixed $value
190
     * @return PHPUnit_Framework_MockObject_Stub_Return
191
     * @since  Method available since Release 3.0.0
192
     */
193
    public static function returnValue($value)
194
    {
195
        return new PHPUnit_Framework_MockObject_Stub_Return($value);
196
    }
197
198
    /**
199
     * Mark the test as skipped.
200
     *
201
     * @param  string $message
202
     * @throws PHPUnit_Framework_SkippedTestError
203
     * @since  Method available since Release 3.0.0
204
     */
205
    public static function markTestSkipped($message = '')
206
    {
207
        throw new PHPUnit_Framework_SkippedTestError($message);
208
    }
209
}
210