From e23a9733373d50af9561489e0c8f2e8a507bb869 Mon Sep 17 00:00:00 2001 From: 7000pctAUTO Date: Mon, 2 Feb 2026 20:00:09 +0000 Subject: [PATCH] Add CLI test file --- tests/test_cli.py | 395 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 395 insertions(+) create mode 100644 tests/test_cli.py diff --git a/tests/test_cli.py b/tests/test_cli.py new file mode 100644 index 0000000..81972ba --- /dev/null +++ b/tests/test_cli.py @@ -0,0 +1,395 @@ +"""Tests for CLI commands.""" + +import pytest +import json +import tempfile +from pathlib import Path +from click.testing import CliRunner + +from src.cli.commands import cli + + +@pytest.fixture +def runner(): + """Create a Click CLI runner.""" + return CliRunner() + + +@pytest.fixture +def sample_openapi_yaml(): + """Sample OpenAPI specification in YAML format.""" + return """ +openapi: \"3.0.0\" +info: + title: Sample API + version: \"1.0.0\" +paths: + /users: + get: + summary: Get all users + parameters: + - name: page + in: query + schema: + type: integer + - name: limit + in: query + schema: + type: integer + responses: + '200': + description: Successful response + content: + application/json: + schema: + type: array + items: + type: object + properties: + id: + type: integer + name: + type: string + email: + type: string + format: email + createdAt: + type: string + format: date-time + /users/{userId}: + get: + summary: Get user by ID + parameters: + - name: userId + in: path + required: true + schema: + type: integer + responses: + '200': + description: Successful response + content: + application/json: + schema: + type: object + properties: + id: + type: integer + name: + type: string + email: + type: string + format: email + '404': + description: User not found + content: + application/json: + schema: + type: object + properties: + error: + type: string + message: + type: string + put: + summary: Update user + parameters: + - name: userId + in: path + required: true + schema: + type: integer + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + name: + type: string + email: + type: string + format: email + required: + - name + responses: + '200': + description: User updated + content: + application/json: + schema: + type: object + properties: + id: + type: integer + name: + type: string + /posts: + post: + summary: Create a post + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + title: + type: string + content: + type: string + authorId: + type: integer + responses: + '201': + description: Post created + content: + application/json: + schema: + type: object + properties: + id: + type: integer + title: + type: string + content: + type: string + authorId: + type: integer + publishedAt: + type: string + format: date-time +components: + schemas: + User: + type: object + properties: + id: + type: integer + name: + type: string + email: + type: string + format: email + createdAt: + type: string + format: date-time + Post: + type: object + properties: + id: + type: integer + title: + type: string + content: + type: string + authorId: + type: integer + publishedAt: + type: string + format: date-time + Error: + type: object + properties: + error: + type: string + message: + type: string +""" + + +@pytest.fixture +def temp_spec_file(sample_openapi_yaml, tmp_path): + """Create a temporary OpenAPI spec file.""" + spec_file = tmp_path / "openapi.yaml" + spec_file.write_text(sample_openapi_yaml) + return str(spec_file) + + +class TestCLIServe: + """Tests for serve command.""" + + def test_serve_validate_only(self, temp_spec_file, runner): + """Test serve command with validate-only option.""" + result = runner.invoke(cli, ["--spec-file", temp_spec_file, "serve", "--validate-only"]) + + assert result.exit_code == 0 + assert "valid" in result.output.lower() or "success" in result.output.lower() + + def test_serve_missing_spec_file(self, tmp_path, runner): + """Test serve command with missing spec file.""" + result = runner.invoke(cli, ["--spec-file", str(tmp_path / "nonexistent.yaml"), "serve", "--validate-only"]) + + assert result.exit_code != 0 + assert "not found" in result.output.lower() + + def test_serve_with_port(self, temp_spec_file, runner): + """Test serve command with custom port.""" + result = runner.invoke(cli, ["--spec-file", temp_spec_file, "serve", "--validate-only", "--port", "3000"]) + + assert result.exit_code == 0 + + def test_serve_with_delay(self, temp_spec_file, runner): + """Test serve command with delay.""" + result = runner.invoke(cli, ["--spec-file", temp_spec_file, "serve", "--validate-only", "--delay", "100"]) + + assert result.exit_code == 0 + + +class TestCLIGenerate: + """Tests for generate command.""" + + def test_generate_lists_endpoints(self, temp_spec_file, runner): + """Test generate command without path lists endpoints.""" + result = runner.invoke(cli, ["--spec-file", temp_spec_file, "generate"]) + + assert result.exit_code == 0 + assert "/users" in result.output + + def test_generate_specific_endpoint(self, temp_spec_file, runner): + """Test generate command for specific endpoint.""" + result = runner.invoke(cli, ["--spec-file", temp_spec_file, "generate", "/users", "get"]) + + assert result.exit_code == 0 + assert "status_code" in result.output or "200" in result.output + + def test_generate_with_format_json(self, temp_spec_file, runner): + """Test generate command with JSON output format.""" + result = runner.invoke(cli, ["--spec-file", temp_spec_file, "generate", "/users", "get", "--format", "json"]) + + assert result.exit_code == 0 + assert "{" in result.output + + def test_generate_with_format_yaml(self, temp_spec_file, runner): + """Test generate command with YAML output format.""" + result = runner.invoke(cli, ["--spec-file", temp_spec_file, "generate", "/users", "get", "--format", "yaml"]) + + assert result.exit_code == 0 + + def test_generate_path_not_found(self, temp_spec_file, runner): + """Test generate command with invalid path.""" + result = runner.invoke(cli, ["--spec-file", temp_spec_file, "generate", "/nonexistent", "get"]) + + assert result.exit_code != 0 + assert "not found" in result.output.lower() + + +class TestCLIValidate: + """Tests for validate command.""" + + def test_validate_spec(self, temp_spec_file, runner): + """Test validate command for valid spec.""" + result = runner.invoke(cli, ["--spec-file", temp_spec_file, "validate"]) + + assert result.exit_code == 0 + assert "valid" in result.output.lower() + + def test_validate_missing_file(self, tmp_path, runner): + """Test validate command with missing file.""" + result = runner.invoke(cli, ["--spec-file", str(tmp_path / "nonexistent.yaml"), "validate"]) + + assert result.exit_code != 0 + + +class TestCLIRoutes: + """Tests for routes command.""" + + def test_routes_lists_all(self, temp_spec_file, runner): + """Test routes command lists all routes.""" + result = runner.invoke(cli, ["--spec-file", temp_spec_file, "routes"]) + + assert result.exit_code == 0 + assert "/users" in result.output + assert "/posts" in result.output + + +class TestCLIInfo: + """Tests for info command.""" + + def test_info_displays_spec_info(self, temp_spec_file, runner): + """Test info command displays spec information.""" + result = runner.invoke(cli, ["--spec-file", temp_spec_file, "info"]) + + assert result.exit_code == 0 + assert "Sample API" in result.output + assert "1.0.0" in result.output + assert "Paths" in result.output + + +class TestCLITest: + """Tests for test command.""" + + def test_test_endpoint(self, temp_spec_file, runner): + """Test test command for specific endpoint.""" + result = runner.invoke(cli, ["--spec-file", temp_spec_file, "test", "/users", "--method", "get"]) + + assert result.exit_code == 0 + assert "Status" in result.output or "200" in result.output + + def test_test_with_query_params(self, temp_spec_file, runner): + """Test test command with query parameters.""" + result = runner.invoke(cli, ["--spec-file", temp_spec_file, "test", "/users", "--method", "get", "--query", "page=1"]) + + assert result.exit_code == 0 + + def test_test_with_body(self, temp_spec_file, runner): + """Test test command with request body.""" + body = json.dumps({"title": "Test Post", "content": "Content"}) + result = runner.invoke(cli, [ + "--spec-file", temp_spec_file, "test", "/posts", "--method", "post", + "--body", body + ]) + + assert result.exit_code == 0 + + def test_test_missing_path(self, temp_spec_file, runner): + """Test test command without path.""" + result = runner.invoke(cli, ["--spec-file", temp_spec_file, "test"]) + + assert result.exit_code != 0 + assert "path" in result.output.lower() + + +class TestCLIDocker: + """Tests for docker command.""" + + def test_docker_builds_image(self, runner): + """Test docker command builds image.""" + result = runner.invoke(cli, ["docker", "--no-build"]) + + assert result.exit_code == 0 + assert "docker run" in result.output + + def test_docker_with_custom_image_name(self, runner): + """Test docker command with custom image name.""" + result = runner.invoke(cli, ["docker", "--no-build", "--image-name", "my-mock-server"]) + + assert result.exit_code == 0 + assert "my-mock-server" in result.output + + +class TestCLIVersion: + """Tests for version option.""" + + def test_version_flag(self, runner): + """Test --version flag displays version.""" + result = runner.invoke(cli, ["--version"]) + + assert result.exit_code == 0 + assert "0.1.0" in result.output or "openapi-mock-generator" in result.output + + +class TestCLIHelp: + """Tests for help option.""" + + def test_help_displays_commands(self, runner): + """Test --help displays available commands.""" + result = runner.invoke(cli, ["--help"]) + + assert result.exit_code == 0 + assert "serve" in result.output + assert "generate" in result.output + assert "validate" in result.output + assert "routes" in result.output + assert "info" in result.output