diff --git a/api_testgen/cli/main.py b/api_testgen/cli/main.py index d228999..eada49a 100644 --- a/api_testgen/cli/main.py +++ b/api_testgen/cli/main.py @@ -1,10 +1,6 @@ """CLI interface for API TestGen.""" -from pathlib import Path -from typing import Optional - import click -import yaml from ..core import SpecParser, AuthConfig from ..core.exceptions import InvalidOpenAPISpecError, UnsupportedVersionError @@ -57,7 +53,7 @@ def parse_spec(ctx: click.Context): try: parser = SpecParser(spec_path) - spec = parser.load() + parser.load() info = parser.get_info() endpoints = parser.get_endpoints() diff --git a/api_testgen/core/auth.py b/api_testgen/core/auth.py index 71411cb..f1bbebb 100644 --- a/api_testgen/core/auth.py +++ b/api_testgen/core/auth.py @@ -1,6 +1,6 @@ """Authentication configuration for API TestGen.""" -from typing import Any, Dict, List, Optional, Union +from typing import Any, Dict, List, Optional from enum import Enum from .exceptions import AuthConfigError, MissingSecuritySchemeError @@ -293,21 +293,21 @@ func getAPIKeyHeaders() map[string]string {{ }} ''' elif method["type"] == AuthType.BEARER: - return f''' -func getBearerHeaders() map[string]string {{ - return map[string]string{{ + return ''' +func getBearerHeaders() map[string]string { + return map[string]string{ "Authorization": fmt.Sprintf("%s %s", os.Getenv("TOKEN_PREFIX"), os.Getenv("TOKEN")), - }} -}} + } +} ''' elif method["type"] == AuthType.BASIC: - return f''' -func getBasicHeaders(username, password string) map[string]string {{ + return ''' +func getBasicHeaders(username, password string) map[string]string { auth := username + ":" + password encoded := base64.StdEncoding.EncodeToString([]byte(auth)) - return map[string]string{{ + return map[string]string{ "Authorization": "Basic " + encoded, - }} -}} + } +} ''' return "" diff --git a/api_testgen/core/spec_parser.py b/api_testgen/core/spec_parser.py index 4da87db..aab1047 100644 --- a/api_testgen/core/spec_parser.py +++ b/api_testgen/core/spec_parser.py @@ -6,7 +6,6 @@ from pathlib import Path from typing import Any, Dict, List, Optional, Union from openapi_spec_validator import validate -from openapi_spec_validator.versions import consts as validator_consts from .exceptions import InvalidOpenAPISpecError, UnsupportedVersionError diff --git a/api_testgen/generators/go.py b/api_testgen/generators/go.py index dba899b..33ccd3c 100644 --- a/api_testgen/generators/go.py +++ b/api_testgen/generators/go.py @@ -6,8 +6,8 @@ from typing import Any, Dict, List, Optional from jinja2 import Environment, FileSystemLoader, TemplateSyntaxError, UndefinedError -from ..core import SpecParser, AuthConfig -from ..core.exceptions import GeneratorError, TemplateRenderError +from ..core import SpecParser +from ..core.exceptions import TemplateRenderError class GoGenerator: @@ -132,7 +132,6 @@ class GoGenerator: """ test_name = self._generate_test_name(endpoint) params = self._generate_params(endpoint) - url_params = self._generate_url_params(endpoint) test_code = f''' func Test{test_name}(t *testing.T) {{ @@ -201,11 +200,11 @@ func Test{test_name}(t *testing.T) {{ if param["in"] == "path": params.append(f'{param_name} := "test_{param_name}"') - params.append(f'url = strings.Replace(url, "{{'+param_name+'}}", {param_name}, 1)') + params.append('url = strings.Replace(url, "' + '{' + param_name + '}' + '", ' + param_name + ', 1)') elif param["in"] == "query": params.append(f'q := url.Values{{{param_name}: []string{{"test"}}}}') - params.append(f'url += "?" + q.Encode()') + params.append('url += "?" + q.Encode()') return "\n ".join(params) if params else "" @@ -219,11 +218,10 @@ func Test{test_name}(t *testing.T) {{ String containing URL parameter handling. """ path_params = [p for p in endpoint.get("parameters", []) if p["in"] == "path"] - query_params = [p for p in endpoint.get("parameters", []) if p["in"] == "query"] parts = [] for param in path_params: - parts.append(f'strings.Replace(url, "{{'+param['name']+'}}", "test_' + param['name'] + '", 1)') + parts.append('strings.Replace(url, "' + '{' + param['name'] + '}' + '", "test_' + param['name'] + '", 1)') return "" diff --git a/api_testgen/generators/jest.py b/api_testgen/generators/jest.py index 5798577..406b6bf 100644 --- a/api_testgen/generators/jest.py +++ b/api_testgen/generators/jest.py @@ -6,8 +6,8 @@ from typing import Any, Dict, List, Optional from jinja2 import Environment, FileSystemLoader, TemplateSyntaxError, UndefinedError -from ..core import SpecParser, AuthConfig -from ..core.exceptions import GeneratorError, TemplateRenderError +from ..core import SpecParser +from ..core.exceptions import TemplateRenderError class JestGenerator: @@ -106,7 +106,6 @@ class JestGenerator: Returns: String containing the test code. """ - test_name = self._generate_test_name(endpoint) describe_name = endpoint["summary"] or endpoint["path"] params = self._generate_params(endpoint) diff --git a/api_testgen/generators/pytest.py b/api_testgen/generators/pytest.py index 4a00d61..83504f0 100644 --- a/api_testgen/generators/pytest.py +++ b/api_testgen/generators/pytest.py @@ -7,7 +7,7 @@ from typing import Any, Dict, List, Optional from jinja2 import Environment, FileSystemLoader, TemplateSyntaxError, UndefinedError from ..core import SpecParser, AuthConfig -from ..core.exceptions import GeneratorError, TemplateRenderError +from ..core.exceptions import TemplateRenderError class PytestGenerator: diff --git a/api_testgen/mocks/generator.py b/api_testgen/mocks/generator.py index 4c0e099..06cacf0 100644 --- a/api_testgen/mocks/generator.py +++ b/api_testgen/mocks/generator.py @@ -2,7 +2,7 @@ import json from pathlib import Path -from typing import Any, Dict, List, Optional +from typing import List, Optional from ..core import SpecParser diff --git a/tests/conftest.py b/tests/conftest.py index 2446847..9bf225a 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -59,3 +59,193 @@ def flavor_manager(): """Provide the flavor manager.""" from regex_humanizer.flavors import get_flavor_manager return get_flavor_manager() + + +SAMPLE_OPENAPI_SPEC = { + "openapi": "3.0.0", + "info": { + "title": "Test Pet Store API", + "version": "1.0.0", + "description": "A sample API for testing purposes" + }, + "servers": [ + {"url": "https://api.example.com/v1"} + ], + "paths": { + "/pets": { + "get": { + "summary": "List all pets", + "description": "Returns a list of pets", + "operationId": "listPets", + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "Maximum number of pets to return", + "required": False, + "schema": {"type": "integer", "default": 10} + }, + { + "name": "status", + "in": "query", + "description": "Filter by pet status", + "required": False, + "schema": {"type": "string", "enum": ["available", "pending", "sold"]} + } + ], + "responses": { + "200": { + "description": "A list of pets", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": {"$ref": "#/components/schemas/Pet"} + } + } + } + } + } + }, + "post": { + "summary": "Create a new pet", + "description": "Creates a new pet in the store", + "operationId": "createPet", + "requestBody": { + "required": True, + "content": { + "application/json": { + "schema": {"$ref": "#/components/schemas/Pet"} + } + } + }, + "responses": { + "201": { + "description": "Pet created successfully", + "content": { + "application/json": { + "schema": {"$ref": "#/components/schemas/Pet"} + } + } + } + } + } + }, + "/pets/{petId}": { + "get": { + "summary": "Get a pet by ID", + "description": "Returns a single pet", + "operationId": "getPetById", + "parameters": [ + { + "name": "petId", + "in": "path", + "description": "ID of the pet to retrieve", + "required": True, + "schema": {"type": "string"} + } + ], + "responses": { + "200": { + "description": "Successful operation", + "content": { + "application/json": { + "schema": {"$ref": "#/components/schemas/Pet"} + } + } + }, + "404": { + "description": "Pet not found" + } + } + }, + "delete": { + "summary": "Delete a pet", + "description": "Deletes a pet from the store", + "operationId": "deletePet", + "parameters": [ + { + "name": "petId", + "in": "path", + "description": "ID of the pet to delete", + "required": True, + "schema": {"type": "string"} + } + ], + "responses": { + "204": { + "description": "Pet deleted successfully" + } + } + } + } + }, + "components": { + "schemas": { + "Pet": { + "type": "object", + "required": ["name", "status"], + "properties": { + "id": { + "type": "integer", + "format": "int64" + }, + "name": { + "type": "string", + "example": "Fluffy" + }, + "status": { + "type": "string", + "enum": ["available", "pending", "sold"], + "description": "Pet status in the store" + }, + "categoryId": { + "type": "integer", + "format": "int64" + }, + "categoryName": { + "type": "string" + } + } + } + }, + "securitySchemes": { + "ApiKeyAuth": { + "type": "apiKey", + "in": "header", + "name": "X-API-Key" + }, + "BearerAuth": { + "type": "http", + "scheme": "bearer", + "bearerFormat": "JWT" + } + } + } +} + + +@pytest.fixture +def sample_openapi_spec(): + """Provide a sample OpenAPI specification for testing.""" + return SAMPLE_OPENAPI_SPEC + + +@pytest.fixture +def temp_spec_file(sample_openapi_spec, tmp_path): + """Create a temporary YAML file with a sample OpenAPI spec.""" + import yaml + file_path = tmp_path / "test_spec.yaml" + with open(file_path, 'w') as f: + yaml.dump(sample_openapi_spec, f) + return file_path + + +@pytest.fixture +def temp_json_spec_file(sample_openapi_spec, tmp_path): + """Create a temporary JSON file with a sample OpenAPI spec.""" + import json + file_path = tmp_path / "test_spec.json" + with open(file_path, 'w') as f: + json.dump(sample_openapi_spec, f, indent=2) + return file_path