Browse Source

Add tests and support for more cases

shalvah 2 years ago
parent
commit
3276487c60

+ 26 - 9
src/Extracting/Strategies/UrlParameters/GetFromLaravelAPI.php

@@ -46,18 +46,35 @@ class GetFromLaravelAPI extends Strategy
         // 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

+ 3 - 0
tests/Fixtures/TestUser.php

@@ -6,6 +6,9 @@ use Illuminate\Database\Eloquent\Model;
 
 class TestUser extends Model
 {
+    protected $guarded = [];
+
+    public $timestamps = false;
 
     public function children()
     {

+ 86 - 66
tests/Strategies/UrlParameters/GetFromLaravelAPITest.php

@@ -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;
 
@@ -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",
@@ -64,7 +57,7 @@ class GetFromLaravelAPITest extends BaseLaravelTest
 
         $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",
@@ -77,20 +70,14 @@ class GetFromLaravelAPITest extends BaseLaravelTest
     /** @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",
@@ -98,7 +85,7 @@ class GetFromLaravelAPITest extends BaseLaravelTest
             "required" => true,
             "type" => "string",
         ], $results['cat_id']);
-        $this->assertMatchesRegularExpression($endpoint->regex, $results['cat_id']['example']);
+        $this->assertMatchesRegularExpression($regex, $results['cat_id']['example']);
     }
 
     /** @test */
@@ -109,20 +96,8 @@ class GetFromLaravelAPITest extends BaseLaravelTest
             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",
@@ -131,24 +106,69 @@ class GetFromLaravelAPITest extends BaseLaravelTest
             "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, []);
+    }
 }