Skip to content

Commit

Permalink
Add tests and support for more cases
Browse files Browse the repository at this point in the history
  • Loading branch information
shalvah committed Jul 16, 2022
1 parent 1150e68 commit 3276487
Show file tree
Hide file tree
Showing 3 changed files with 115 additions and 75 deletions.
35 changes: 26 additions & 9 deletions src/Extracting/Strategies/UrlParameters/GetFromLaravelAPI.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,18 +46,35 @@ protected function inferUrlParamDescription(string $url, string $paramName): str
// If $url is sth like /users/{id}, return "The ID of the user."
// If $url is sth like /anything/{user_id}, return "The ID of the user."

return collect(["id", "slug"])->flatMap(function ($name) use ($url, $paramName) {
$strategies = collect(["id", "slug"])->map(function ($name) {
$friendlyName = $name === 'id' ? "ID" : $name;

if ($paramName == $name) {
$thing = $this->getNameOfUrlThing($url, $paramName);
return ["The $friendlyName of the $thing."];
} else if (Str::is("*_$name", $paramName)) {
$thing = str_replace(["_", "-"], " ", str_replace("_$name", '', $paramName));
return ["The $friendlyName of the $thing."];
return function ($url, $paramName) use ($name, $friendlyName) {
if ($paramName == $name) {
$thing = $this->getNameOfUrlThing($url, $paramName);
return "The $friendlyName of the $thing.";
} else if (Str::is("*_$name", $paramName)) {
$thing = str_replace(["_", "-"], " ", str_replace("_$name", '', $paramName));
return "The $friendlyName of the $thing.";
}
};
})->toArray();

// If $url is sth like /categories/{category}, return "The category."
$strategies[] = function ($url, $paramName) {
$thing = $this->getNameOfUrlThing($url, $paramName);
if ($thing === $paramName) {
return "The $thing.";
}
return [];
})->first() ?: '';
};

foreach ($strategies as $strategy) {
if ($inferred = $strategy($url, $paramName)) {
return $inferred;
}
}

return '';
}

protected function inferBetterTypesAndExamplesForEloquentUrlParameters(array $parameters, ExtractedEndpointData $endpointData): array
Expand Down
3 changes: 3 additions & 0 deletions tests/Fixtures/TestUser.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@

class TestUser extends Model
{
protected $guarded = [];

public $timestamps = false;

public function children()
{
Expand Down
152 changes: 86 additions & 66 deletions tests/Strategies/UrlParameters/GetFromLaravelAPITest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,16 @@

namespace Knuckles\Scribe\Tests\Strategies\UrlParameters;

use Illuminate\Routing\Route;
use Closure;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Routing\Router;
use Illuminate\Support\Facades\Schema;
use Knuckles\Camel\Extraction\ExtractedEndpointData;
use Knuckles\Scribe\Extracting\Strategies\UrlParameters\GetFromLaravelAPI;
use Knuckles\Scribe\Extracting\UrlParamsNormalizer;
use Knuckles\Scribe\Tests\BaseLaravelTest;
use Knuckles\Scribe\Tests\Fixtures\TestController;
use Knuckles\Scribe\Tests\Fixtures\TestUser;
use Knuckles\Scribe\Tools\DocumentationConfig;
use DMS\PHPUnitExtensions\ArraySubset\ArraySubsetAsserts;

Expand All @@ -17,43 +20,33 @@ class GetFromLaravelAPITest extends BaseLaravelTest
use ArraySubsetAsserts;

/** @test */
public function can_fetch_from_url()
public function can_infer_type_from_model_binding()
{
$endpoint = new class extends ExtractedEndpointData {
public function __construct(array $parameters = [])
{
$this->method = new \ReflectionMethod(TestController::class, 'withInjectedModel');
$this->route = app(Router::class)->addRoute(['GET'], "users/{id}", ['uses' => [TestController::class, 'withInjectedModel']]);
$this->uri = $this->route->uri;
}
};

$strategy = new GetFromLaravelAPI(new DocumentationConfig([]));
$results = $strategy($endpoint, []);
$endpoint = $this->endpointForRoute("users/{id}", TestController::class, 'withInjectedModel');
// $endpoint = $this->endpointForRoute("categories/{category}/users/{id}/", TestController::class, 'withInjectedEnumAndModel');
$results = $this->fetch($endpoint);

$this->assertArraySubset([
"name" => "id",
"description" => "The ID of the user.",
"required" => true,
"type" => "integer",
], $results['id']);
], $results['id']);/*
$this->assertArraySubset([
"name" => "category",
"description" => "The category.",
"required" => true,
"type" => "string",
"example" => \Knuckles\Scribe\Tests\Fixtures\Category::cases()[0]->value,
], $results['category']);*/
$this->assertIsInt($results['id']['example']);
}

/** @test */
public function can_infer_description_from_url()
{
$endpoint = new class extends ExtractedEndpointData {
public function __construct(array $parameters = [])
{
$this->method = new \ReflectionMethod(TestController::class, 'dummy');
$this->route = app(Router::class)->addRoute(['GET'], "everything/{cat_id}", ['uses' => [TestController::class, 'dummy']]);
$this->uri = $this->route->uri;
}
};

$strategy = new GetFromLaravelAPI(new DocumentationConfig([]));
$results = $strategy($endpoint, []);
$endpoint = $this->endpointForRoute("everything/{cat_id}", TestController::class, 'dummy');
$results = $this->fetch($endpoint);

$this->assertArraySubset([
"name" => "cat_id",
Expand All @@ -64,7 +57,7 @@ public function __construct(array $parameters = [])

$endpoint->route = app(Router::class)->addRoute(['GET'], 'dogs/{id}', ['uses' => [TestController::class, 'dummy']]);;
$endpoint->uri = $endpoint->route->uri;
$results = $strategy($endpoint, []);
$results = $this->fetch($endpoint);

$this->assertArraySubset([
"name" => "id",
Expand All @@ -77,28 +70,22 @@ public function __construct(array $parameters = [])
/** @test */
public function can_infer_example_from_wheres()
{
$endpoint = new class extends ExtractedEndpointData {
public function __construct(array $parameters = [])
{
$this->method = new \ReflectionMethod(TestController::class, 'dummy');

$route = app(Router::class)->addRoute(['GET'], "everything/{cat_id}", ['uses' => [TestController::class, 'dummy']]);
$this->regex = '/catz\d+-\d/';
$this->route = $route->where('cat_id', $this->regex);
$this->uri = $this->route->uri;
}
};

$strategy = new GetFromLaravelAPI(new DocumentationConfig([]));
$results = $strategy($endpoint, []);
$regex = '/catz\d+-\d/';
$endpoint = $this->endpoint(function (ExtractedEndpointData $e) use ($regex) {
$e->method = new \ReflectionMethod(TestController::class, 'dummy');
$e->route = app(Router::class)->addRoute(['GET'], "everything/{cat_id}", ['uses' => [TestController::class, 'dummy']])
->where('cat_id', $regex);
$e->uri = UrlParamsNormalizer::normalizeParameterNamesInRouteUri($e->route, $e->method);
});
$results = $this->fetch($endpoint);

$this->assertArraySubset([
"name" => "cat_id",
"description" => "The ID of the cat.",
"required" => true,
"type" => "string",
], $results['cat_id']);
$this->assertMatchesRegularExpression($endpoint->regex, $results['cat_id']['example']);
$this->assertMatchesRegularExpression($regex, $results['cat_id']['example']);
}

/** @test */
Expand All @@ -109,20 +96,8 @@ public function can_infer_data_from_field_bindings()
return;
}

$strategy = new GetFromLaravelAPI(new DocumentationConfig([]));

$endpoint = new class extends ExtractedEndpointData {
public function __construct(array $parameters = [])
{
$this->method = new \ReflectionMethod(TestController::class, 'dummy');

$route = app(Router::class)->addRoute(['GET'], "audio/{audio:slug}", ['uses' => [TestController::class, 'dummy']]);
$this->route = $route;
$this->uri = UrlParamsNormalizer::normalizeParameterNamesInRouteUri($route, $this->method);
}
};

$results = $strategy($endpoint, []);
$endpoint = $this->endpointForRoute("audio/{audio:slug}", TestController::class, 'dummy');
$results = $this->fetch($endpoint);

$this->assertArraySubset([
"name" => "audio_slug",
Expand All @@ -131,24 +106,69 @@ public function __construct(array $parameters = [])
"type" => "string",
], $results['audio_slug']);

$endpoint = new class extends ExtractedEndpointData {
public function __construct(array $parameters = [])
{
$this->method = new \ReflectionMethod(TestController::class, 'withInjectedModel');
Schema::create('test_users', function (Blueprint $table) {
$table->id();
$table->string('name');
});
$user = TestUser::create(['name' => 'Bully Maguire', 'id' => 23]);

$route = app(Router::class)->addRoute(['GET'], "users/{user:id}", ['uses' => [TestController::class, 'withInjectedModel']]);
$this->route = $route;
$this->uri = UrlParamsNormalizer::normalizeParameterNamesInRouteUri($route, $this->method);
}
};

$results = $strategy($endpoint, []);
$endpoint = $this->endpointForRoute("users/{user:id}", TestController::class, 'withInjectedModel');
$results = $this->fetch($endpoint);

$this->assertArraySubset([
"name" => "user_id",
"description" => "The ID of the user.",
"required" => true,
"type" => "integer",
"example" => $user->id,
], $results['user_id']);
}

/** @test */
public function can_infer_from_model_even_if_not_bound()
{
$oldNamespace = $this->app->getNamespace();
$reflectedApp = new \ReflectionClass($this->app);
$property = $reflectedApp->getProperty('namespace');
$property->setAccessible(true);
$property->setValue($this->app, "Knuckles\\Scribe\\Tests\\Fixtures\\");

$endpoint = $this->endpointForRoute("test-users/{id}", TestController::class, 'dummy');
$results = $this->fetch($endpoint);

$this->assertArraySubset([
"name" => "id",
"description" => "The ID of the test user.",
"required" => true,
"type" => "integer",
], $results['id']);

$property->setValue($this->app, $oldNamespace);
}

protected function endpointForRoute($path, $controller, $method): ExtractedEndpointData
{
return $this->endpoint(function (ExtractedEndpointData $e) use ($path, $method, $controller) {
$e->method = new \ReflectionMethod($controller, $method);
$e->route = app(Router::class)->addRoute(['GET'], $path, ['uses' => [$controller, $method]]);
$e->uri = UrlParamsNormalizer::normalizeParameterNamesInRouteUri($e->route, $e->method);
});
}

protected function endpoint(Closure $configure): ExtractedEndpointData
{
$endpoint = new class extends ExtractedEndpointData {
public function __construct(array $parameters = [])
{
}
};
$configure($endpoint);
return $endpoint;
}

protected function fetch($endpoint): array
{
$strategy = new GetFromLaravelAPI(new DocumentationConfig([]));
return $strategy($endpoint, []);
}
}

0 comments on commit 3276487

Please sign in to comment.