Passed
Branch merging-leagues-tournaments (1b2f12)
by Benedikt
06:40
created

UserControllerTest::testSuccessfulRegistration()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 70
Code Lines 51

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 51
c 0
b 0
f 0
dl 0
loc 70
rs 9.069
cc 1
nc 1
nop 0

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
/**
5
 * Created by PhpStorm.
6
 * User: benedikt
7
 * Date: 9/17/17
8
 * Time: 12:33 AM
9
 */
10
11
namespace Tfboe\FmLib\Tests\Unit\Http\Controllers;
12
13
use Doctrine\ORM\EntityManagerInterface;
14
use Illuminate\Contracts\Auth\Authenticatable;
15
use Illuminate\Contracts\Hashing\Hasher;
16
use Illuminate\Http\Request;
17
use Illuminate\Support\Facades\Auth;
18
use Illuminate\Support\Facades\Config;
19
use Illuminate\Validation\ValidationException;
20
use Laravel\Lumen\Application;
21
use PHPUnit\Framework\MockObject\MockObject;
22
use ReflectionException;
23
use Tfboe\FmLib\Entity\TermsInterface;
24
use Tfboe\FmLib\Entity\UserInterface;
25
use Tfboe\FmLib\Exceptions\AuthenticationException;
26
use Tfboe\FmLib\Http\Controllers\BaseController;
27
use Tfboe\FmLib\Http\Controllers\UserController;
28
use Tfboe\FmLib\Service\ObjectCreatorServiceInterface;
29
use Tfboe\FmLib\Service\TermsServiceInterface;
30
use Tfboe\FmLib\Tests\Helpers\UnitTestCase;
31
use Tymon\JWTAuth\Exceptions\JWTException;
32
33
/**
34
 * Class BaseControllerTest
35
 * @package Tests\Unit\App\Http\Controllers
36
 */
37
class UserControllerTest extends UnitTestCase
38
{
39
  //tests also private method disable this tests as soon as all are used in public interfaces
40
//<editor-fold desc="Public Methods">
41
42
  /**
43
   * @covers \Tfboe\FmLib\Http\Controllers\UserController::__construct
44
   * @throws ReflectionException
45
   * @uses   \Tfboe\FmLib\Http\Controllers\BaseController::__construct
46
   */
47
  public function testConstruct()
48
  {
49
    $controller = $this->controller();
50
    self::assertInstanceOf(BaseController::class, $controller);
51
  }
52
53
  /**
54
   * @covers \Tfboe\FmLib\Http\Controllers\UserController::login
55
   * @covers \Tfboe\FmLib\Http\Controllers\UserController::addAdditionalLoginSpecifications
56
   * @covers \Tfboe\FmLib\Http\Controllers\UserController::getCredentialSpecification
57
   * @covers \Tfboe\FmLib\Http\Controllers\UserController::preLogin
58
   * @throws AuthenticationException wrong credentials or errors during creating a token
59
   * @throws ValidationException
60
   * @throws ReflectionException
61
   * @uses   \Tfboe\FmLib\Http\Controllers\UserController::__construct
62
   * @uses   \Tfboe\FmLib\Exceptions\AuthenticationException::__construct
63
   * @uses   \Tfboe\FmLib\Helpers\SpecificationHandler::validateBySpecification
64
   * @uses   \Tfboe\FmLib\Http\Controllers\BaseController::__construct
65
   * @uses   \Tfboe\FmLib\Http\Controllers\BaseController::validateSpec
66
   */
67
  public function testFailToCreateToken()
68
  {
69
    $controller = $this->controller(null, null, ['validate']);
70
    /** @var Request|MockObject $request */
71
    $request = $this->createMock(Request::class);
72
    $data = ['email' => '[email protected]', 'password' => '12345678'];
73
    $request->expects(static::any())->method('only')
74
      ->with('email', 'password')
75
      ->willReturn($data);
76
77
    $controller->method('validate')->willReturnCallback(function ($r, $spec) use ($request) {
78
      self::assertEquals(['email' => 'required|email', 'password' => 'required|string|min:8'], $spec);
79
      self::assertTrue($request === $r);
80
    });
81
82
    $app = $this->createStub(Application::class, []);
83
84
    Auth::shouldReceive('attempt')
85
      ->once()
86
      ->with($data)
87
      ->andThrow(new JWTException());
88
89
90
    $this->expectException(AuthenticationException::class);
91
    $this->expectExceptionMessage("could not create token");
92
    $controller->login($request, $app);
93
  }
94
95
  /**
96
   * @covers \Tfboe\FmLib\Http\Controllers\UserController::getLatestTerms
97
   * @throws ReflectionException
98
   * @uses   \Tfboe\FmLib\Http\Controllers\BaseController::__construct
99
   * @uses   \Tfboe\FmLib\Http\Controllers\UserController::__construct
100
   */
101
  public function testGetLatestTerms()
102
  {
103
    $controller = $this->controller();
104
    $terms = $this->createStub(TermsInterface::class,
105
      ['getText' => 'text', 'getMinorVersion' => 1, 'getMajorVersion' => 2]);
106
    $termsService = $this->createStub(TermsServiceInterface::class, ['getLatestTerms' => $terms]);
107
    $response = $controller->getLatestTerms($termsService);
108
    self::assertEquals(200, $response->getStatusCode());
109
    self::assertEquals(['text' => 'text', 'minorVersion' => 1, 'majorVersion' => 2], $response->getData(true));
110
  }
111
112
  /**
113
   * @covers \Tfboe\FmLib\Http\Controllers\UserController::login
114
   * @covers \Tfboe\FmLib\Http\Controllers\UserController::addAdditionalLoginSpecifications
115
   * @covers \Tfboe\FmLib\Http\Controllers\UserController::getCredentialSpecification
116
   * @covers \Tfboe\FmLib\Http\Controllers\UserController::preLogin
117
   * @throws AuthenticationException wrong credentials or errors during creating a token
118
   * @throws ValidationException
119
   * @throws ReflectionException
120
   * @uses   \Tfboe\FmLib\Http\Controllers\UserController::__construct
121
   * @uses   \Tfboe\FmLib\Exceptions\AuthenticationException::__construct
122
   * @uses   \Tfboe\FmLib\Helpers\SpecificationHandler::validateBySpecification
123
   * @uses   \Tfboe\FmLib\Http\Controllers\BaseController::__construct
124
   * @uses   \Tfboe\FmLib\Http\Controllers\BaseController::validateSpec
125
   */
126
  public function testLoginInvalidCredentials()
127
  {
128
    $controller = $this->controller(null, null, ['validate']);
129
    /** @var Request|MockObject $request */
130
    $request = $this->createMock(Request::class);
131
    $data = ['email' => '[email protected]', 'password' => '12345678'];
132
    $request->expects(static::any())->method('only')
133
      ->with('email', 'password')
134
      ->willReturn($data);
135
136
    $controller->method('validate')->willReturnCallback(function ($r, $spec) use ($request) {
137
      self::assertEquals(['email' => 'required|email', 'password' => 'required|string|min:8'], $spec);
138
      self::assertTrue($request === $r);
139
    });
140
141
    $app = $this->createStub(Application::class, []);
142
143
    Auth::shouldReceive('attempt')
144
      ->once()
145
      ->with($data)
146
      ->andReturn(null);
147
148
149
    $this->expectException(AuthenticationException::class);
150
    $this->expectExceptionMessage("invalid credentials");
151
    $controller->login($request, $app);
152
  }
153
154
  /**
155
   * @covers   \Tfboe\FmLib\Http\Controllers\UserController::login
156
   * @covers   \Tfboe\FmLib\Http\Controllers\UserController::addAdditionalLoginSpecifications
157
   * @covers   \Tfboe\FmLib\Http\Controllers\UserController::getCredentialSpecification
158
   * @covers   \Tfboe\FmLib\Http\Controllers\UserController::getLoginResponse
159
   * @covers   \Tfboe\FmLib\Http\Controllers\UserController::preLogin
160
   * @throws AuthenticationException wrong credentials or errors during creating a token
161
   * @throws ValidationException
162
   * @throws ReflectionException
163
   * @uses     \Tfboe\FmLib\Helpers\SpecificationHandler::validateBySpecification
164
   * @uses     \Tfboe\FmLib\Http\Controllers\BaseController::__construct
165
   * @uses     \Tfboe\FmLib\Http\Controllers\UserController::__construct
166
   * @uses     \Tfboe\FmLib\Http\Controllers\BaseController::validateSpec
167
   */
168
  public function testSuccessfulLogin()
169
  {
170
    $controller = $this->controller(null, null, ['validate']);
171
    /** @var Request|MockObject $request */
172
    $request = $this->createMock(Request::class);
173
    $data = ['email' => '[email protected]', 'password' => '12345678'];
174
    $user = $this->createStubWithId(UserInterface::class, 'uid');
175
    $request->expects(static::any())->method('user')->willReturn($user);
176
    $request->expects(static::any())->method('only')
177
      ->with('email', 'password')
178
      ->willReturn($data);
179
180
    $controller->method('validate')->willReturnCallback(function ($r, $spec) use ($request) {
181
      self::assertEquals(['email' => 'required|email', 'password' => 'required|string|min:8'], $spec);
182
      self::assertTrue($request === $r);
183
    });
184
185
    $app = $this->createStub(Application::class, []);
186
187
    Auth::shouldReceive('attempt')
188
      ->once()
189
      ->with($data)
190
      ->andReturn('token');
191
192
    $response = $controller->login($request, $app);
193
    self::assertEquals(200, $response->getStatusCode());
194
    self::assertEquals(["id" => "uid"], $response->getData(true));
195
    self::assertEquals("token", $response->headers->get("jwt-token"));
196
  }
197
198
  /**
199
   * @covers \Tfboe\FmLib\Http\Controllers\UserController::register
200
   * @covers \Tfboe\FmLib\Http\Controllers\UserController::addAdditionalRegisterSpecifications
201
   * @covers \Tfboe\FmLib\Http\Controllers\UserController::createAdditionalRegisterEntities
202
   * @covers \Tfboe\FmLib\Http\Controllers\UserController::getCredentialSpecification
203
   * @covers \Tfboe\FmLib\Http\Controllers\UserController::getRegisterResponse
204
   * @covers \Tfboe\FmLib\Http\Controllers\UserController::newUser
205
   * @throws ReflectionException
206
   * @throws ValidationException
207
   * @uses   \Tfboe\FmLib\Entity\Traits\User::init
208
   * @uses   \Tfboe\FmLib\Helpers\SpecificationHandler::setFromSpecification
209
   * @uses   \Tfboe\FmLib\Helpers\SpecificationHandler::transformValue
210
   * @uses   \Tfboe\FmLib\Helpers\SpecificationHandler::validateBySpecification
211
   * @uses   \Tfboe\FmLib\Http\Controllers\BaseController::__construct
212
   * @uses   \Tfboe\FmLib\Http\Controllers\BaseController::getEntityManager
213
   * @uses   \Tfboe\FmLib\Http\Controllers\BaseController::validateSpec
214
   * @uses   \Tfboe\FmLib\Http\Controllers\UserController::__construct
215
   */
216
  public function testSuccessfulRegistration()
217
  {
218
    $data = ['email' => '[email protected]', 'password' => '12345678', 'confirmedTermsMinorVersion' => 1,
219
      'confirmedTermsMajorVersion' => 2];
220
221
    $user = $this->getMockedEntity("User", ["getId", "setEmail", "setPassword", "setConfirmedTermsMinorVersion",
222
      "setConfirmedTermsMajorVersion"]);
223
    $user->method('getId')->willReturn('uid');
224
    $set = [];
225
    $getCb = function ($field) use (&$set) {
226
      return function ($val) use ($field, &$set) {
227
        $set[$field] = $val;
228
      };
229
    };
230
    $user->expects(self::atLeastOnce())->method('setEmail')->with($data['email'])->willReturnCallback($getCb('email'));
231
    $user->expects(self::atLeastOnce())->method('setPassword')->with('passwordHash')
232
      ->willReturnCallback($getCb('password'));
233
    $user->expects(self::atLeastOnce())->method('setConfirmedTermsMinorVersion')
234
      ->with($data['confirmedTermsMinorVersion'])->willReturnCallback($getCb('minor'));
235
    $user->expects(self::atLeastOnce())->method('setConfirmedTermsMajorVersion')
236
      ->with($data['confirmedTermsMajorVersion'])->willReturnCallback($getCb('major'));
237
    /** @var ObjectCreatorServiceInterface|MockObject $objectCreatorService */
238
    $objectCreatorService = $this->createMock(ObjectCreatorServiceInterface::class);
239
    $objectCreatorService->method('createObjectFromInterface')->with(UserInterface::class)
240
      ->willReturn($user);
241
242
    /** @var EntityManagerInterface|MockObject $em */
243
    $em = $this->createMock(EntityManagerInterface::class);
244
    $userPersisted = false;
245
    $em->expects(self::once())->method('persist')->with($user)->willReturnCallback(
246
      function () use (&$set, &$userPersisted) {
247
        self::assertCount(4, $set);
248
        $userPersisted = true;
249
      });
250
    $em->expects(self::atLeastOnce())->method('flush')->willReturnCallback(function () use (&$userPersisted) {
251
      self::assertTrue($userPersisted);
252
    });
253
254
    $controller = $this->controller($em, $objectCreatorService, ['validate']);
255
    /** @var Request|MockObject $request */
256
    $request = $this->createMock(Request::class);
257
258
    $request->expects(static::any())->method('user')->willReturn($user);
259
    $request->expects(static::any())->method('input')
260
      ->willReturn($data);
261
262
    $controller->method('validate')->willReturnCallback(function ($r, $spec) use ($request) {
263
      self::assertEquals([
264
        'email' => 'required|email|unique:UserClass,email',
265
        'password' => 'required|string|min:8',
266
        'confirmedTermsMinorVersion' => 'required|integer|min:0',
267
        'confirmedTermsMajorVersion' => 'required|integer|min:1'
268
      ], $spec);
269
      self::assertTrue($request === $r);
270
    });
271
272
    /** @var MockObject|Application $app */
273
    $app = $this->createMock(Application::class);
274
    $hasher = $this->createMock(Hasher::class);
275
    $hasher->method('make')->with($data['password'])->willReturn('passwordHash');
276
    $app->method('offsetGet')->with('hash')->willReturn($hasher);
277
278
    Config::shouldReceive('get')
279
      ->once()
280
      ->with('fm-lib')
281
      ->andReturn(['entityMaps' => [UserInterface::class => 'UserClass']]);
282
283
    $response = $controller->register($request, $app);
284
    self::assertEquals(200, $response->getStatusCode());
285
    self::assertEquals(["id" => "uid"], $response->getData(true));
286
  }
287
288
  /**
289
   * @covers \Tfboe\FmLib\Http\Controllers\UserController::userId
290
   * @throws ReflectionException
291
   * @uses   \Tfboe\FmLib\Http\Controllers\UserController::__construct
292
   * @uses   \Tfboe\FmLib\Http\Controllers\BaseController::__construct
293
   */
294
  public function testUserId()
295
  {
296
    $auth = $this->createStub(Authenticatable::class, ["getAuthIdentifier" => "uid"]);
297
    Auth::shouldReceive('user')
298
      ->once()
299
      ->andReturn($auth);
300
    $controller = $this->controller();
301
    $response = $controller->userId();
302
    self::assertEquals(200, $response->getStatusCode());
303
    self::assertEquals(["id" => "uid"], $response->getData(true));
304
  }
305
//</editor-fold desc="Public Methods">
306
307
//<editor-fold desc="Private Methods">
308
  /**
309
   * @param EntityManagerInterface|null $entityManager
310
   * @param ObjectCreatorServiceInterface|null $objectCreatorService
311
   * @param array $stubbedMethods
312
   * @return UserController|MockObject
313
   * @throws ReflectionException
314
   */
315
  private function controller(?EntityManagerInterface $entityManager = null,
316
                              ?ObjectCreatorServiceInterface $objectCreatorService = null,
317
                              array $stubbedMethods = []): MockObject
318
  {
319
    if ($entityManager === null) {
320
      $entityManager = $this->createMock(EntityManagerInterface::class);
321
    }
322
    if ($objectCreatorService === null) {
323
      $objectCreatorService = $this->createMock(ObjectCreatorServiceInterface::class);
324
    }
325
    return $this->getMockForAbstractClass(UserController::class, [$entityManager, $objectCreatorService], '', true,
326
      true, true, $stubbedMethods);
327
  }
328
//</editor-fold desc="Private Methods">
329
}