Skip to content

Commit c5aace5

Browse files
authored
💊 Add Is Valid Url Constraint (LaraCrafts#7)
1 parent 950467c commit c5aace5

13 files changed

+199
-57
lines changed

‎phpunit.xml.dist

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<phpunit backupGlobals="false"
33
backupStaticAttributes="false"
4-
bootstrap="vendor/autoload.php"
4+
bootstrap="tests/bootstrap.php"
55
colors="true"
66
convertErrorsToExceptions="true"
77
convertNoticesToExceptions="true"

‎tests/Concerns/FollowsRedirects.php

-39
This file was deleted.
+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
<?php
2+
3+
namespace LaraCrafts\UrlShortener\Tests\Concerns;
4+
5+
use LaraCrafts\UrlShortener\Tests\Constraints\IsValidUrl;
6+
use LaraCrafts\UrlShortener\Tests\Constraints\RedirectsTo;
7+
8+
trait HasUrlAssertions
9+
{
10+
/**
11+
* Assert that the given value redirects to the expected value.
12+
*
13+
* @param \Psr\Http\Message\UriInterface|string $expected
14+
* @param \Psr\Http\Message\UriInterface|string $actual
15+
* @param int $redirects
16+
* @return void
17+
*/
18+
public static function assertRedirectsTo($expected, $actual, int $redirects = 1)
19+
{
20+
static::assertThat($actual, static::redirectsTo($expected, $redirects));
21+
}
22+
23+
/**
24+
* Assert that the given value is valid URL.
25+
*
26+
* @param mixed $actual
27+
*/
28+
public static function assertValidUrl($actual)
29+
{
30+
static::assertThat($actual, static::isValidUrl());
31+
}
32+
33+
/**
34+
* Create a IsValidUrl instance
35+
*
36+
* @return IsValidUrl
37+
*/
38+
public static function isValidUrl(): IsValidUrl
39+
{
40+
return new IsValidUrl;
41+
}
42+
43+
/**
44+
* Create a RedirectsTo instance
45+
*
46+
* @param $expected
47+
* @param int $redirects
48+
* @return RedirectsTo
49+
*/
50+
public static function redirectsTo($expected, int $redirects = 1): RedirectsTo
51+
{
52+
return new RedirectsTo($expected, $redirects);
53+
}
54+
}

‎tests/Constraints/IsValidUrl.php

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?php
2+
3+
namespace LaraCrafts\UrlShortener\Tests\Constraints;
4+
5+
use PHPUnit\Framework\Constraint\Constraint;
6+
7+
class IsValidUrl extends Constraint
8+
{
9+
/**
10+
* {@inheritDoc}
11+
*/
12+
protected function matches($other): bool
13+
{
14+
return filter_var((string)$other, FILTER_VALIDATE_URL);
15+
}
16+
17+
/**
18+
* {@inheritDoc}
19+
*/
20+
public function toString(): string
21+
{
22+
return 'is a valid URL';
23+
}
24+
}

‎tests/Constraints/RedirectsTo.php

+69
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
<?php
2+
3+
namespace LaraCrafts\UrlShortener\Tests\Constraints;
4+
5+
use GuzzleHttp\Client;
6+
use GuzzleHttp\TransferStats;
7+
use PHPUnit\Framework\Constraint\Constraint;
8+
9+
class RedirectsTo extends Constraint
10+
{
11+
protected $client;
12+
protected $destination;
13+
protected $redirects;
14+
15+
/**
16+
* Create a new RedirectsTo constraint.
17+
*
18+
* @param \Psr\Http\Message\UriInterface|string $destination
19+
* @param int $redirects
20+
* @return void
21+
*/
22+
public function __construct($destination, int $redirects = 1)
23+
{
24+
$this->client = new Client();
25+
$this->destination = rtrim($destination, '/');
26+
$this->redirects = $redirects;
27+
}
28+
29+
/**
30+
* {@inheritDoc}
31+
*/
32+
public function evaluate($other, $description = '', $returnResult = false)
33+
{
34+
$stack = [];
35+
36+
$this->client->get($other, [
37+
'allow_redirects' => [
38+
'max' => max($this->redirects, 5),
39+
],
40+
'on_stats' => function (TransferStats $stats) use (&$stack) {
41+
$stack[] = (string)$stats->getEffectiveUri();
42+
},
43+
]);
44+
45+
if (($actualRedirects = count($stack) - 1) < $this->redirects) {
46+
$this->fail($other, "Expected $this->redirects redirects, received $actualRedirects");
47+
}
48+
49+
if (!$this->matches($actual = $stack[$this->redirects])) {
50+
$this->fail($actual, "Expected $this->destination, received $actual");
51+
}
52+
}
53+
54+
/**
55+
* {@inheritDoc}
56+
*/
57+
public function matches($other): bool
58+
{
59+
return rtrim($other, '/') === $this->destination;
60+
}
61+
62+
/**
63+
* {@inheritDoc}
64+
*/
65+
public function toString(): string
66+
{
67+
return 'redirects to ' . $this->destination;
68+
}
69+
}

‎tests/Integration/BitLyShortenerTest.php

+6-3
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,12 @@
55
use GuzzleHttp\Client;
66
use GuzzleHttp\Promise\PromiseInterface;
77
use LaraCrafts\UrlShortener\Http\BitLyShortener;
8-
use LaraCrafts\UrlShortener\Tests\Concerns\FollowsRedirects;
8+
use LaraCrafts\UrlShortener\Tests\Concerns\HasUrlAssertions;
99
use Orchestra\Testbench\TestCase;
1010

1111
class BitLyShortenerTest extends TestCase
1212
{
13-
use FollowsRedirects;
13+
use HasUrlAssertions;
1414

1515
/**
1616
* @var \LaraCrafts\UrlShortener\Http\BitLyShortener
@@ -39,6 +39,8 @@ public function setUp(): void
3939
public function testShorten()
4040
{
4141
$shortUrl = $this->shortener->shorten('https://google.com');
42+
43+
$this->assertValidUrl($shortUrl);
4244
$this->assertRedirectsTo('https://google.com', $shortUrl, 1);
4345
}
4446

@@ -52,6 +54,7 @@ public function testShortenAsync()
5254
$promise = $this->shortener->shortenAsync('https://google.com');
5355

5456
$this->assertInstanceOf(PromiseInterface::class, $promise);
55-
$this->assertRedirectsTo('https://google.com', $promise->wait(), 1);
57+
$this->assertValidUrl($shortUrl = $promise->wait());
58+
$this->assertRedirectsTo('https://google.com', $shortUrl, 1);
5659
}
5760
}

‎tests/Integration/FirebaseShortenerTest.php

+7-2
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,13 @@
55
use GuzzleHttp\Client;
66
use GuzzleHttp\Promise\PromiseInterface;
77
use LaraCrafts\UrlShortener\Http\FirebaseShortener;
8+
use LaraCrafts\UrlShortener\Tests\Concerns\HasUrlAssertions;
89
use Orchestra\Testbench\TestCase;
910

1011
class FirebaseShortenerTest extends TestCase
1112
{
13+
use HasUrlAssertions;
14+
1215
/**
1316
* @var string
1417
*/
@@ -63,7 +66,8 @@ public function testShorten(string $suffix)
6366
$shortener = new FirebaseShortener(new Client, $this->token, $this->prefix, $suffix);
6467
$shortUrl = $shortener->shorten('https://google.com');
6568

66-
$this->assertInternalType('string', $shortUrl);
69+
$this->assertValidUrl($shortUrl);
70+
$this->assertRedirectsTo('https://google.com', $shortUrl, 1);
6771
}
6872

6973
/**
@@ -79,6 +83,7 @@ public function testShortenAsync(string $suffix)
7983
$promise = $shortener->shortenAsync('https://google.com');
8084

8185
$this->assertInstanceOf(PromiseInterface::class, $promise);
82-
$this->assertInternalType('string', $promise->wait());
86+
$this->assertValidUrl($shortUrl = $promise->wait());
87+
$this->assertRedirectsTo('https://google.com', $shortUrl, 1);
8388
}
8489
}

‎tests/Integration/IsGdShortenerTest.php

+7-3
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,12 @@
55
use GuzzleHttp\Client;
66
use GuzzleHttp\Promise\PromiseInterface;
77
use LaraCrafts\UrlShortener\Http\IsGdShortener;
8-
use LaraCrafts\UrlShortener\Tests\Concerns\FollowsRedirects;
8+
use LaraCrafts\UrlShortener\Tests\Concerns\HasUrlAssertions;
99
use Orchestra\Testbench\TestCase;
1010

1111
class IsGdShortenerTest extends TestCase
1212
{
13-
use FollowsRedirects;
13+
use HasUrlAssertions;
1414

1515
/**
1616
* @var \LaraCrafts\UrlShortener\Http\IsGdShortener
@@ -34,6 +34,8 @@ public function setUp(): void
3434
public function testShorten()
3535
{
3636
$shortUrl = $this->shortener->shorten('https://google.com');
37+
38+
$this->assertValidUrl($shortUrl);
3739
$this->assertRedirectsTo('https://google.com', $shortUrl, 1);
3840
}
3941

@@ -45,7 +47,9 @@ public function testShorten()
4547
public function testShortenAsync()
4648
{
4749
$promise = $this->shortener->shortenAsync('https://google.com');
50+
4851
$this->assertInstanceOf(PromiseInterface::class, $promise);
49-
$this->assertRedirectsTo('https://google.com', $promise->wait(), 1);
52+
$this->assertValidUrl($shortUrl = $promise->wait());
53+
$this->assertRedirectsTo('https://google.com', $shortUrl, 1);
5054
}
5155
}

‎tests/Integration/OuoIoShortenerTest.php

+6-2
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,13 @@
66
use GuzzleHttp\Promise\PromiseInterface;
77
use Illuminate\Support\Str;
88
use LaraCrafts\UrlShortener\Http\OuoIoShortener;
9+
use LaraCrafts\UrlShortener\Tests\Concerns\HasUrlAssertions;
910
use Orchestra\Testbench\TestCase;
1011

1112
class OuoIoShortenerTest extends TestCase
1213
{
14+
use HasUrlAssertions;
15+
1316
/**
1417
* @var \LaraCrafts\UrlShortener\Http\OuoIoShortener
1518
*/
@@ -37,7 +40,8 @@ public function setUp(): void
3740
public function testShorten()
3841
{
3942
$shortUrl = $this->shortener->shorten('https://google.com');
40-
$this->assertInternalType('string', $shortUrl);
43+
44+
$this->assertValidUrl($shortUrl);
4145
$this->assertTrue(Str::startsWith($shortUrl, 'https://ouo.io/'));
4246
}
4347

@@ -51,7 +55,7 @@ public function testShortenAsync()
5155
$promise = $this->shortener->shortenAsync('https://google.com');
5256

5357
$this->assertInstanceOf(PromiseInterface::class, $promise);
54-
$this->assertInternalType('string', $shortUrl = $promise->wait());
58+
$this->assertValidUrl($shortUrl = $promise->wait());
5559
$this->assertTrue(Str::startsWith($shortUrl, 'https://ouo.io/'));
5660
}
5761
}

‎tests/Integration/ShorteStShortenerTest.php

+6-2
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,13 @@
55
use GuzzleHttp\Client;
66
use GuzzleHttp\Promise\PromiseInterface;
77
use LaraCrafts\UrlShortener\Http\ShorteStShortener;
8+
use LaraCrafts\UrlShortener\Tests\Concerns\HasUrlAssertions;
89
use Orchestra\Testbench\TestCase;
910

1011
class ShorteStShortenerTest extends TestCase
1112
{
13+
use HasUrlAssertions;
14+
1215
/**
1316
* @var \LaraCrafts\UrlShortener\Http\ShorteStShortener
1417
*/
@@ -36,7 +39,8 @@ public function setUp(): void
3639
public function testShorten()
3740
{
3841
$shortUrl = $this->shortener->shorten('https://google.com');
39-
$this->assertInternalType('string', $shortUrl);
42+
43+
$this->assertValidUrl($shortUrl);
4044
}
4145

4246
/**
@@ -49,6 +53,6 @@ public function testShortenAsync()
4953
$promise = $this->shortener->shortenAsync('https://google.com');
5054

5155
$this->assertInstanceOf(PromiseInterface::class, $promise);
52-
$this->assertInternalType('string', $promise->wait());
56+
$this->assertValidUrl($shortUrl = $promise->wait());
5357
}
5458
}

‎tests/Integration/TinyUrlShortenerTest.php

+7-3
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,12 @@
55
use GuzzleHttp\Client;
66
use GuzzleHttp\Promise\PromiseInterface;
77
use LaraCrafts\UrlShortener\Http\TinyUrlShortener;
8-
use LaraCrafts\UrlShortener\Tests\Concerns\FollowsRedirects;
8+
use LaraCrafts\UrlShortener\Tests\Concerns\HasUrlAssertions;
99
use Orchestra\Testbench\TestCase;
1010

1111
class TinyUrlShortenerTest extends TestCase
1212
{
13-
use FollowsRedirects;
13+
use HasUrlAssertions;
1414

1515
/**
1616
* @var \LaraCrafts\UrlShortener\Http\TinyUrlShortener
@@ -34,6 +34,8 @@ public function setUp(): void
3434
public function testShorten()
3535
{
3636
$shortUrl = $this->shortener->shorten('https://google.com');
37+
38+
$this->assertValidUrl($shortUrl);
3739
$this->assertRedirectsTo('https://google.com', $shortUrl, 1);
3840
}
3941

@@ -45,7 +47,9 @@ public function testShorten()
4547
public function testShortenAsync()
4648
{
4749
$promise = $this->shortener->shortenAsync('https://google.com');
50+
4851
$this->assertInstanceOf(PromiseInterface::class, $promise);
49-
$this->assertRedirectsTo('https://google.com', $promise->wait(), 1);
52+
$this->assertValidUrl($shortUrl = $promise->wait());
53+
$this->assertRedirectsTo('https://google.com', $shortUrl, 1);
5054
}
5155
}

0 commit comments

Comments
 (0)