Completed
Push — master ( 7f572e...bf04a1 )
by Benedikt
02:39
created

PlayerServiceTest::testMergePlayer()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 65
Code Lines 41

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 65
c 0
b 0
f 0
cc 1
eloc 41
nc 1
nop 0
rs 9.3571

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
declare(strict_types=1);
3
/**
4
 * Created by PhpStorm.
5
 * User: benedikt
6
 * Date: 1/3/18
7
 * Time: 3:53 PM
8
 */
9
10
namespace Tfboe\FmLib\Tests\Unit\Service;
11
12
use Doctrine\Common\Collections\ArrayCollection;
13
use Doctrine\ORM\EntityManagerInterface;
14
use PHPUnit\Framework\MockObject\MockObject;
15
use Tfboe\FmLib\Entity\CompetitionInterface;
16
use Tfboe\FmLib\Entity\GameInterface;
17
use Tfboe\FmLib\Entity\MatchInterface;
18
use Tfboe\FmLib\Entity\PhaseInterface;
19
use Tfboe\FmLib\Entity\PlayerInterface;
20
use Tfboe\FmLib\Entity\TeamInterface;
21
use Tfboe\FmLib\Entity\TeamMembershipInterface;
22
use Tfboe\FmLib\Entity\TournamentInterface;
23
use Tfboe\FmLib\Service\DeletionServiceInterface;
24
use Tfboe\FmLib\Service\LoadingServiceInterface;
25
use Tfboe\FmLib\Service\PlayerService;
26
use Tfboe\FmLib\Service\RankingSystemServiceInterface;
27
use Tfboe\FmLib\Tests\Helpers\UnitTestCase;
28
29
30
/**
31
 * Class DeletionServiceTest
32
 * @package Tfboe\FmLib\Tests\Unit\Service
33
 * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
34
 */
35
class PlayerServiceTest extends UnitTestCase
36
{
37
//<editor-fold desc="Public Methods">
38
  /**
39
   * @covers \Tfboe\FmLib\Service\PlayerService::__construct
40
   */
41
  public function testConstruct()
42
  {
43
    /** @var EntityManagerInterface $em */
44
    $em = $this->createMock(EntityManagerInterface::class);
45
    /** @var LoadingServiceInterface $ls */
46
    $ls = $this->createMock(LoadingServiceInterface::class);
47
    /** @var DeletionServiceInterface $deletionService */
48
    $deletionService = $this->createMock(DeletionServiceInterface::class);
49
    /** @var RankingSystemServiceInterface $rankingSystemService */
50
    $rankingSystemService = $this->createMock(RankingSystemServiceInterface::class);
51
    $service = new PlayerService($em, $ls, $deletionService, $rankingSystemService);
52
    self::assertInstanceOf(PlayerService::class, $service);
53
  }
54
55
  /**
56
   * @covers \Tfboe\FmLib\Service\PlayerService::mergePlayers
57
   * @uses   \Tfboe\FmLib\Service\PlayerService::__construct
58
   */
59
  public function testMergeBothPlayersInSameTournament()
60
  {
61
    $player1 = $this->createStubWithId(PlayerInterface::class, "p1");
62
    $player2 = $this->createStubWithId(PlayerInterface::class, "p2");
63
    $team1 = $this->createStub(TeamInterface::class, [
64
      'getMemberships' => new ArrayCollection([$this->createStub(TeamMembershipInterface::class, [
65
        'getPlayer' => $player1
66
      ])])
67
    ]);
68
    $team2 = $this->createStub(TeamInterface::class, [
69
      'getMemberships' => new ArrayCollection([$this->createStub(TeamMembershipInterface::class, [
70
        'getPlayer' => $player2
71
      ])])
72
    ]);
73
74
    $competition = $this->createStub(CompetitionInterface::class, [
75
      'getTeams' => new ArrayCollection([$team1, $team2])
76
    ]);
77
78
    $tournament = $this->createStub(TournamentInterface::class, [
79
      'getCompetitions' => new ArrayCollection([$competition]),
80
      'getName' => 'Tournament',
81
      'getId' => 't',
82
      'getStartTime' => new \DateTime("2000-01-01")
83
    ]);
84
85
    /** @var EntityManagerInterface $em */
86
    $em = $this->getEntityManagerMockForQuery([$tournament],
87
      'SELECT t FROM Tfboe\FmLib\Entity\TournamentInterface t INNER JOIN t.competitions c INNER JOIN c.teams te ' .
88
      'INNER JOIN te.memberships m WHERE m.player = (:id)');
89
90
    $service = new PlayerService($em,
91
      $this->createStub(LoadingServiceInterface::class),
0 ignored issues
show
Documentation introduced by
$this->createStub(\Tfboe...erviceInterface::class) is of type object<PHPUnit\Framework\MockObject\MockObject>, but the function expects a object<Tfboe\FmLib\Servi...oadingServiceInterface>.

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...
92
      $this->createStub(DeletionServiceInterface::class),
0 ignored issues
show
Documentation introduced by
$this->createStub(\Tfboe...erviceInterface::class) is of type object<PHPUnit\Framework\MockObject\MockObject>, but the function expects a object<Tfboe\FmLib\Servi...letionServiceInterface>.

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...
93
      $this->createStub(RankingSystemServiceInterface::class)
0 ignored issues
show
Documentation introduced by
$this->createStub(\Tfboe...erviceInterface::class) is of type object<PHPUnit\Framework\MockObject\MockObject>, but the function expects a object<Tfboe\FmLib\Servi...SystemServiceInterface>.

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...
94
    );
95
96
    self::assertEquals('Player 1 and player 2 both attended the tournament Tournament(01.01.2000 12:01, id=\'t\')',
97
      $service->mergePlayers($player1, $player2));
0 ignored issues
show
Documentation introduced by
$player1 is of type object<PHPUnit\Framework\MockObject\MockObject>, but the function expects a object<Tfboe\FmLib\Entity\PlayerInterface>.

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...
Documentation introduced by
$player2 is of type object<PHPUnit\Framework\MockObject\MockObject>, but the function expects a object<Tfboe\FmLib\Entity\PlayerInterface>.

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...
98
  }
99
100
  /**
101
   * @covers \Tfboe\FmLib\Service\PlayerService::mergePlayers
102
   * @uses   \Tfboe\FmLib\Service\PlayerService::__construct
103
   */
104
  public function testMergeIdenticalPlayer()
105
  {
106
    $player1 = $this->createStubWithId(PlayerInterface::class, "p1");
107
    $player2 = $this->createStubWithId(PlayerInterface::class, "p1");
108
109
110
    $service = new PlayerService(
111
      $this->createStub(EntityManagerInterface::class),
0 ignored issues
show
Documentation introduced by
$this->createStub(\Doctr...anagerInterface::class) is of type object<PHPUnit\Framework\MockObject\MockObject>, but the function expects a object<Doctrine\ORM\EntityManagerInterface>.

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...
112
      $this->createStub(LoadingServiceInterface::class),
0 ignored issues
show
Documentation introduced by
$this->createStub(\Tfboe...erviceInterface::class) is of type object<PHPUnit\Framework\MockObject\MockObject>, but the function expects a object<Tfboe\FmLib\Servi...oadingServiceInterface>.

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...
113
      $this->createStub(DeletionServiceInterface::class),
0 ignored issues
show
Documentation introduced by
$this->createStub(\Tfboe...erviceInterface::class) is of type object<PHPUnit\Framework\MockObject\MockObject>, but the function expects a object<Tfboe\FmLib\Servi...letionServiceInterface>.

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...
114
      $this->createStub(RankingSystemServiceInterface::class)
0 ignored issues
show
Documentation introduced by
$this->createStub(\Tfboe...erviceInterface::class) is of type object<PHPUnit\Framework\MockObject\MockObject>, but the function expects a object<Tfboe\FmLib\Servi...SystemServiceInterface>.

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...
115
    );
116
117
    self::assertEquals('Players are identical!', $service->mergePlayers($player1, $player2));
0 ignored issues
show
Documentation introduced by
$player1 is of type object<PHPUnit\Framework\MockObject\MockObject>, but the function expects a object<Tfboe\FmLib\Entity\PlayerInterface>.

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...
Documentation introduced by
$player2 is of type object<PHPUnit\Framework\MockObject\MockObject>, but the function expects a object<Tfboe\FmLib\Entity\PlayerInterface>.

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...
118
  }
119
120
  /**
121
   * @covers \Tfboe\FmLib\Service\PlayerService::mergePlayers
122
   * @uses   \Tfboe\FmLib\Service\PlayerService::__construct
123
   */
124
  public function testMergePlayer()
125
  {
126
    $tournament = $this->createStub(TournamentInterface::class);
127
    $player1 = $this->createStubWithId(PlayerInterface::class, "p1");
128
    $player2 = $this->createStubWithId(PlayerInterface::class, "p2");
129
    $otherPlayer = $this->createStubWithId(PlayerInterface::class, "oP");
130
    $team1Membership = $this->createStub(TeamMembershipInterface::class, ['getPlayer' => $player2]);
131
    $team1Membership->method('setPlayer')->with($player1);
132
    $team1 = $this->createStub(TeamInterface::class, [
133
      'getMemberships' => new ArrayCollection([$team1Membership])
134
    ]);
135
    $otherTeam = $this->createStub(TeamInterface::class, [
136
      'getMemberships' => new ArrayCollection([$this->createStub(TeamMembershipInterface::class, [
137
        'getPlayer' => $otherPlayer
138
      ])])
139
    ]);
140
141
    $game1PlayersB = new ArrayCollection([$player2->getId() => $player2]);
142
    $game1 = $this->createStub(GameInterface::class, [
143
      'getPlayersA' => new ArrayCollection([$otherPlayer->getId() => $otherPlayer]),
144
      'getPlayersB' => $game1PlayersB
145
    ]);
146
147
    $game2PlayersA = new ArrayCollection([$player2->getId() => $player2]);
148
    $game2 = $this->createStub(GameInterface::class, [
149
      'getPlayersA' => $game2PlayersA,
150
      'getPlayersB' => new ArrayCollection([$otherPlayer->getId() => $otherPlayer])
151
    ]);
152
153
    $competition = $this->createStub(CompetitionInterface::class, [
154
      'getTeams' => new ArrayCollection([$team1, $otherTeam]),
155
      'getPhases' => new ArrayCollection([$this->createStub(PhaseInterface::class, [
156
        'getMatches' => new ArrayCollection([$this->createStub(MatchInterface::class, [
157
          'getGames' => new ArrayCollection([$game1, $game2])
158
        ])])
159
      ])])
160
    ]);
161
162
163
    /** @var EntityManagerInterface $em */
164
    $em = $this->getEntityManagerMockForQuery([$tournament],
165
      'SELECT t FROM Tfboe\FmLib\Entity\TournamentInterface t INNER JOIN t.competitions c INNER JOIN c.teams te ' .
166
      'INNER JOIN te.memberships m WHERE m.player = (:id)');
167
    /** @var LoadingServiceInterface|MockObject $ls */
168
    $ls = $this->createMock(LoadingServiceInterface::class);
169
    $ls->expects(self::once())->method('loadEntities')->with([$tournament])->willReturnCallback(
0 ignored issues
show
Bug introduced by
The method expects does only exist in PHPUnit\Framework\MockObject\MockObject, but not in Tfboe\FmLib\Service\LoadingServiceInterface.

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...
170
      function ($a) use ($competition) {
171
        /** @var TournamentInterface|MockObject $t */
172
        $t = $a[0];
173
        $t->method('getCompetitions')->willReturn(new ArrayCollection([$competition]));
174
      });
175
    /** @var DeletionServiceInterface|MockObject $deletionService */
176
    $deletionService = $this->createMock(DeletionServiceInterface::class);
177
    $deletionService->expects(self::once())->method('deletePlayer')->with($player2);
0 ignored issues
show
Bug introduced by
The method expects does only exist in PHPUnit\Framework\MockObject\MockObject, but not in Tfboe\FmLib\Service\DeletionServiceInterface.

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...
178
    /** @var RankingSystemServiceInterface|MockObject $rankingSystemService */
179
    $rankingSystemService = $this->createMock(RankingSystemServiceInterface::class);
180
    $rankingSystemService->method('adaptOpenSyncFromValues')->with($tournament, []);
181
182
    $service = new PlayerService($em, $ls, $deletionService, $rankingSystemService);
0 ignored issues
show
Bug introduced by
It seems like $ls defined by $this->createMock(\Tfboe...erviceInterface::class) on line 168 can also be of type object<PHPUnit\Framework\MockObject\MockObject>; however, Tfboe\FmLib\Service\PlayerService::__construct() does only seem to accept object<Tfboe\FmLib\Servi...oadingServiceInterface>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
Bug introduced by
It seems like $deletionService defined by $this->createMock(\Tfboe...erviceInterface::class) on line 176 can also be of type object<PHPUnit\Framework\MockObject\MockObject>; however, Tfboe\FmLib\Service\PlayerService::__construct() does only seem to accept object<Tfboe\FmLib\Servi...letionServiceInterface>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
Bug introduced by
It seems like $rankingSystemService defined by $this->createMock(\Tfboe...erviceInterface::class) on line 179 can also be of type object<PHPUnit\Framework\MockObject\MockObject>; however, Tfboe\FmLib\Service\PlayerService::__construct() does only seem to accept object<Tfboe\FmLib\Servi...SystemServiceInterface>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
183
184
    self::assertEquals(true, $service->mergePlayers($player1, $player2));
0 ignored issues
show
Documentation introduced by
$player1 is of type object<PHPUnit\Framework\MockObject\MockObject>, but the function expects a object<Tfboe\FmLib\Entity\PlayerInterface>.

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...
Documentation introduced by
$player2 is of type object<PHPUnit\Framework\MockObject\MockObject>, but the function expects a object<Tfboe\FmLib\Entity\PlayerInterface>.

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...
185
186
    self::assertEquals($game1PlayersB, new ArrayCollection([$player1->getId() => $player1]));
187
    self::assertEquals($game2PlayersA, new ArrayCollection([$player1->getId() => $player1]));
188
  }
189
//</editor-fold desc="Public Methods">
190
}