Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ba975ffed4 | |||
| cec136d7e1 | |||
| cdf9436a2e | |||
| 527c79e3cd | |||
| 658f5b0d7e | |||
| 55d9312f51 | |||
| efb912c3dc | |||
| d0a44ea8b2 | |||
| bc3dd3c0cf | |||
| 28f698de11 | |||
| 13968ae8ad | |||
| 1a3ec64292 |
@@ -9,20 +9,26 @@ on:
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: actions/setup-python@v5
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.11'
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install -e ".[dev]"
|
||||
pip install click>=8.0 requests>=2.28 pyyaml>=6.0
|
||||
pip install pytest pytest-cov
|
||||
|
||||
- name: Run tests
|
||||
run: pytest tests/ -v
|
||||
run: |
|
||||
python -m pytest tests/ -v
|
||||
|
||||
- name: Check code style (ruff)
|
||||
run: pip install ruff && ruff check .
|
||||
- name: Check linting
|
||||
run: |
|
||||
pip install ruff
|
||||
python -m ruff check .
|
||||
@@ -1,3 +1,3 @@
|
||||
"""Curl Converter CLI - Convert curl commands to code snippets."""
|
||||
{"""Curl Converter CLI - Convert curl commands to code."""
|
||||
|
||||
__version__ = "0.1.0"
|
||||
@@ -1,6 +1,5 @@
|
||||
"""CLI module for curl converter."""
|
||||
{"""CLI application for curl-converter."""
|
||||
|
||||
import sys
|
||||
import click
|
||||
from curlconverter.parser import parse_curl
|
||||
from curlconverter.generators import generate_code, get_supported_languages, get_language_display_name
|
||||
@@ -8,70 +7,43 @@ from curlconverter.generators import generate_code, get_supported_languages, get
|
||||
|
||||
@click.group()
|
||||
def cli():
|
||||
"""Convert curl commands to code in multiple programming languages."""
|
||||
"""Curl Converter CLI - Convert curl commands to code."""
|
||||
pass
|
||||
|
||||
|
||||
@cli.command()
|
||||
@click.option("-c", "--curl", "curl_input", help="The curl command to convert")
|
||||
@click.option("-l", "--language", default="python", help="Target programming language")
|
||||
@click.option("-o", "--output", type=click.Path(), help="Output file path")
|
||||
@click.option("-i", "--interactive", is_flag=True, help="Interactive mode - paste curl command")
|
||||
def convert(curl_input, language, output, interactive):
|
||||
@click.option('--curl', '-c', help='Curl command to convert')
|
||||
@click.option('--language', '-l', default='python', help='Target language')
|
||||
@click.option('--output', '-o', type=click.Path(), help='Output file')
|
||||
def convert(curl, language, output):
|
||||
"""Convert a curl command to code."""
|
||||
if interactive:
|
||||
click.echo("Paste your curl command (press Ctrl+D or Ctrl+Z when done):")
|
||||
try:
|
||||
curl_input = click.edit()
|
||||
except Exception:
|
||||
curl_input = click.prompt("", type=str)
|
||||
if not curl:
|
||||
curl = click.prompt('Enter curl command', type=str)
|
||||
|
||||
if not curl_input:
|
||||
click.echo("Error: No curl command provided. Use --curl or --interactive", err=True)
|
||||
sys.exit(1)
|
||||
|
||||
try:
|
||||
parsed = parse_curl(curl_input)
|
||||
parsed = parse_curl(curl)
|
||||
code = generate_code(parsed, language)
|
||||
|
||||
if output:
|
||||
with open(output, "w") as f:
|
||||
with open(output, 'w') as f:
|
||||
f.write(code)
|
||||
click.echo(f"Code written to {output}")
|
||||
click.echo(f'Code written to {output}')
|
||||
else:
|
||||
click.echo(code)
|
||||
|
||||
except ValueError as e:
|
||||
click.echo(f"Error: {e}", err=True)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
@cli.command()
|
||||
def languages():
|
||||
"""List supported programming languages."""
|
||||
click.echo("Supported languages:")
|
||||
"""List supported languages."""
|
||||
for lang in get_supported_languages():
|
||||
display = get_language_display_name(lang)
|
||||
click.echo(f" {lang:12} - {display}")
|
||||
click.echo(f"{lang}: {get_language_display_name(lang)}")
|
||||
|
||||
|
||||
@cli.command()
|
||||
@click.option("-c", "--curl", "curl_input", help="The curl command to analyze")
|
||||
@click.option("-i", "--interactive", is_flag=True, help="Interactive mode")
|
||||
def analyze(curl_input, interactive):
|
||||
"""Analyze and display parsed curl command details."""
|
||||
if interactive:
|
||||
click.echo("Paste your curl command:")
|
||||
curl_input = click.prompt("", type=str)
|
||||
@click.argument('curl')
|
||||
def analyze(curl):
|
||||
"""Analyze a curl command without generating code."""
|
||||
parsed = parse_curl(curl)
|
||||
|
||||
if not curl_input:
|
||||
click.echo("Error: No curl command provided", err=True)
|
||||
sys.exit(1)
|
||||
|
||||
try:
|
||||
parsed = parse_curl(curl_input)
|
||||
|
||||
click.echo("Parsed curl command:")
|
||||
click.echo(f"URL: {parsed.url}")
|
||||
click.echo(f"Method: {parsed.method}")
|
||||
|
||||
@@ -84,7 +56,7 @@ def analyze(curl_input, interactive):
|
||||
click.echo(f"Data: {parsed.data}")
|
||||
|
||||
if parsed.auth:
|
||||
click.echo(f" Auth: {parsed.auth[0]}:****")
|
||||
click.echo(f"Auth: {parsed.auth}")
|
||||
|
||||
if parsed.cookies:
|
||||
click.echo(f"Cookies: {parsed.cookies}")
|
||||
@@ -92,14 +64,6 @@ def analyze(curl_input, interactive):
|
||||
if parsed.user_agent:
|
||||
click.echo(f"User-Agent: {parsed.user_agent}")
|
||||
|
||||
except ValueError as e:
|
||||
click.echo(f"Error: {e}", err=True)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def main():
|
||||
if __name__ == '__main__':
|
||||
cli()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
"""Code generators for different programming languages."""
|
||||
{"""Code generators for different programming languages."""
|
||||
|
||||
from abc import ABC, abstractmethod
|
||||
from typing import Dict, Callable
|
||||
|
||||
from curlconverter.parser import ParsedCurl
|
||||
|
||||
|
||||
@@ -57,8 +58,8 @@ def get_language_display_name(lang: str) -> str:
|
||||
return names.get(lang.lower(), lang.capitalize())
|
||||
|
||||
|
||||
from curlconverter.generators import python
|
||||
from curlconverter.generators import javascript
|
||||
from curlconverter.generators import go
|
||||
from curlconverter.generators import ruby
|
||||
from curlconverter.generators import php
|
||||
from curlconverter.generators import python # noqa: E402, F401
|
||||
from curlconverter.generators import javascript # noqa: E402, F401
|
||||
from curlconverter.generators import go # noqa: E402, F401
|
||||
from curlconverter.generators import ruby # noqa: E402, F401
|
||||
from curlconverter.generators import php # noqa: E402, F401
|
||||
@@ -1,6 +1,7 @@
|
||||
"""Go code generator."""
|
||||
{"""Go code generator."""
|
||||
|
||||
import json
|
||||
import re
|
||||
from curlconverter.parser import ParsedCurl
|
||||
from curlconverter.generators import register_generator
|
||||
|
||||
@@ -24,18 +25,19 @@ def _detect_content_type(headers: dict, data: str) -> str:
|
||||
def generate_go(parsed: ParsedCurl) -> str:
|
||||
"""Generate Go net/http code from parsed curl data."""
|
||||
lines = []
|
||||
|
||||
lines.append("package main")
|
||||
lines.append("")
|
||||
lines.append('import (')
|
||||
lines.append("import (")
|
||||
lines.append(' "bytes"')
|
||||
lines.append(' "fmt"')
|
||||
lines.append(' "net/http"')
|
||||
lines.append(' "io/ioutil"')
|
||||
lines.append(' "strings"')
|
||||
lines.append(")")
|
||||
lines.append("")
|
||||
|
||||
lines.append("func main() {")
|
||||
lines.append(f' url := "{parsed.url}"')
|
||||
lines.append(f' url := {repr(parsed.url)}')
|
||||
lines.append("")
|
||||
|
||||
headers = dict(parsed.headers) if parsed.headers else {}
|
||||
@@ -43,57 +45,50 @@ def generate_go(parsed: ParsedCurl) -> str:
|
||||
if parsed.user_agent and "User-Agent" not in headers and "user-agent" not in headers:
|
||||
headers["User-Agent"] = parsed.user_agent
|
||||
|
||||
if headers:
|
||||
lines.append(" headers := map[string]string{")
|
||||
for k, v in headers.items():
|
||||
lines.append(f' "{k}": "{v}",')
|
||||
lines.append(" }")
|
||||
lines.append("")
|
||||
if parsed.auth:
|
||||
auth_str = f"{parsed.auth[0]}:{parsed.auth[1]}"
|
||||
encoded = ""
|
||||
for _, c := range auth_str {
|
||||
encoded += string(c)
|
||||
}
|
||||
headers["Authorization"] = f"Basic " + encoded
|
||||
|
||||
method = parsed.method
|
||||
body := ""
|
||||
|
||||
body_var = ""
|
||||
if parsed.data:
|
||||
content_type = _detect_content_type(headers, parsed.data)
|
||||
body = repr(parsed.data)
|
||||
|
||||
if content_type == "application/json":
|
||||
try:
|
||||
json_data = json.loads(parsed.data)
|
||||
json_str = json.dumps(json_data)
|
||||
lines.append(f' jsonData := `{json_str}`')
|
||||
body_var = "bytes.NewBuffer([]byte(jsonData))"
|
||||
body = "strings.NewReader(" + repr(json.dumps(json_data)) + ")"
|
||||
headers["Content-Type"] = "application/json"
|
||||
except (json.JSONDecodeError, TypeError):
|
||||
escaped = parsed.data.replace("`", "\\`").replace("${", "\\$ {")
|
||||
lines.append(f' data := `{escaped}`')
|
||||
body_var = "bytes.NewBuffer([]byte(data))"
|
||||
body = "strings.NewReader(" + repr(parsed.data) + ")"
|
||||
else:
|
||||
escaped = parsed.data.replace("`", "\\`").replace("${", "\\$ {")
|
||||
lines.append(f' data := `{escaped}`')
|
||||
body_var = "bytes.NewBuffer([]byte(data))"
|
||||
body = "strings.NewReader(" + repr(parsed.data) + ")"
|
||||
|
||||
if "Content-Type" not in headers and "content-type" not in headers:
|
||||
headers["Content-Type"] = content_type
|
||||
if method == "GET":
|
||||
method = "POST"
|
||||
|
||||
lines.append("")
|
||||
|
||||
lines.append(f' req, err := http.NewRequest("{parsed.method}", url, {body_var or "nil"})')
|
||||
if headers:
|
||||
lines.append(" req, err := http.NewRequest(" + repr(method) + ", url, " + body + ")")
|
||||
lines.append(" if err != nil {")
|
||||
lines.append(" panic(err)")
|
||||
lines.append(" }")
|
||||
lines.append("")
|
||||
|
||||
if headers:
|
||||
lines.append(" for key, value := range headers {")
|
||||
lines.append(" req.Header.Add(key, value)")
|
||||
for k, v in headers.items():
|
||||
lines.append(f' req.Header.Add({repr(k)}, {repr(v)})')
|
||||
else:
|
||||
lines.append(" req, err := http.NewRequest(" + repr(method) + ", url, " + body + ")")
|
||||
lines.append(" if err != nil {")
|
||||
lines.append(" panic(err)")
|
||||
lines.append(" }")
|
||||
lines.append("")
|
||||
|
||||
if parsed.auth:
|
||||
lines.append(f' req.SetBasicAuth("{parsed.auth[0]}", "{parsed.auth[1]}")')
|
||||
lines.append("")
|
||||
|
||||
if parsed.cookies:
|
||||
lines.append(f' req.Header.Add("Cookie", "{parsed.cookies}")')
|
||||
lines.append("")
|
||||
|
||||
lines.append(" client := &http.Client{}")
|
||||
lines.append(" resp, err := client.Do(req)")
|
||||
lines.append(" if err != nil {")
|
||||
@@ -101,8 +96,7 @@ def generate_go(parsed: ParsedCurl) -> str:
|
||||
lines.append(" }")
|
||||
lines.append(" defer resp.Body.Close()")
|
||||
lines.append("")
|
||||
lines.append(" body, _ := ioutil.ReadAll(resp.Body)")
|
||||
lines.append(" fmt.Println(string(body))")
|
||||
lines.append(" fmt.Println(resp.Status)")
|
||||
lines.append("}")
|
||||
|
||||
return "\n".join(lines)
|
||||
@@ -1,4 +1,4 @@
|
||||
"""JavaScript code generator."""
|
||||
{"""JavaScript code generator."""
|
||||
|
||||
import json
|
||||
from curlconverter.parser import ParsedCurl
|
||||
@@ -24,7 +24,8 @@ def _detect_content_type(headers: dict, data: str) -> str:
|
||||
def generate_javascript(parsed: ParsedCurl) -> str:
|
||||
"""Generate JavaScript fetch code from parsed curl data."""
|
||||
lines = []
|
||||
lines.append("const url = " + repr(parsed.url) + ";")
|
||||
|
||||
lines.append(f"const url = {repr(parsed.url)};")
|
||||
lines.append("")
|
||||
|
||||
options = {"method": parsed.method}
|
||||
@@ -33,46 +34,37 @@ def generate_javascript(parsed: ParsedCurl) -> str:
|
||||
if parsed.user_agent and "User-Agent" not in headers and "user-agent" not in headers:
|
||||
headers["User-Agent"] = parsed.user_agent
|
||||
|
||||
if parsed.auth:
|
||||
encoded = btoa(f"{parsed.auth[0]}:{parsed.auth[1]}")
|
||||
headers["Authorization"] = f"Basic {encoded}"
|
||||
|
||||
if parsed.data:
|
||||
content_type = _detect_content_type(headers, parsed.data)
|
||||
|
||||
if content_type == "application/json":
|
||||
try:
|
||||
json_data = json.loads(parsed.data)
|
||||
lines.append("const jsonData = " + json.dumps(json_data, indent=2) + ";")
|
||||
options["body"] = "JSON.stringify(jsonData)"
|
||||
if "Content-Type" not in headers and "content-type" not in headers:
|
||||
options["body"] = json.dumps(json_data)
|
||||
headers["Content-Type"] = "application/json"
|
||||
except (json.JSONDecodeError, TypeError):
|
||||
lines.append("const data = " + repr(parsed.data) + ";")
|
||||
options["body"] = "data"
|
||||
options["body"] = repr(parsed.data)
|
||||
else:
|
||||
lines.append("const data = " + repr(parsed.data) + ";")
|
||||
options["body"] = "data"
|
||||
options["body"] = repr(parsed.data)
|
||||
|
||||
if parsed.cookies:
|
||||
if "Cookie" not in headers and "cookie" not in headers:
|
||||
headers["Cookie"] = parsed.cookies
|
||||
|
||||
if headers:
|
||||
lines.append("const headers = " + _format_object(headers) + ";")
|
||||
lines.append("const headers = " + json.dumps(headers, indent=2) + ";")
|
||||
options["headers"] = "headers"
|
||||
|
||||
if parsed.auth:
|
||||
auth_str = f"{parsed.auth[0]}:{parsed.auth[1]}"
|
||||
import base64
|
||||
encoded = base64.b64encode(auth_str.encode()).decode()
|
||||
lines.append("const auth = " + repr(encoded) + ";")
|
||||
if "Authorization" not in headers and "content-type" not in headers:
|
||||
lines.append("const headersWithAuth = {")
|
||||
lines.append(" ...headers,")
|
||||
lines.append(' "Authorization": `Basic ${auth}`')
|
||||
lines.append("};")
|
||||
options["headers"] = "headersWithAuth"
|
||||
|
||||
options_str = _format_options(options)
|
||||
if len(options) > 1:
|
||||
lines.append("const options = " + json.dumps(options, indent=2) + ";")
|
||||
lines.append("")
|
||||
lines.append(f"fetch(url, {options_str})")
|
||||
lines.append("fetch(url, options)")
|
||||
else:
|
||||
lines.append("fetch(url)")
|
||||
|
||||
lines.append(" .then(response => {")
|
||||
lines.append(" console.log(response.status);")
|
||||
lines.append(" return response.text();")
|
||||
@@ -81,23 +73,3 @@ def generate_javascript(parsed: ParsedCurl) -> str:
|
||||
lines.append(" .catch(error => console.error(error));")
|
||||
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
def _format_object(obj: dict) -> str:
|
||||
"""Format an object for JavaScript code."""
|
||||
if not obj:
|
||||
return "{}"
|
||||
items = []
|
||||
for k, v in obj.items():
|
||||
items.append(f' {repr(k)}: {repr(v)}')
|
||||
return "{\n" + ",\n".join(items) + "\n}"
|
||||
|
||||
|
||||
def _format_options(opts: dict) -> str:
|
||||
"""Format fetch options for JavaScript code."""
|
||||
if not opts:
|
||||
return "{}"
|
||||
items = []
|
||||
for k, v in opts.items():
|
||||
items.append(f" {k}: {v}")
|
||||
return "{\n" + ",\n".join(items) + "\n }"
|
||||
|
||||
90
curlconverter/generators/php.php
Normal file
90
curlconverter/generators/php.php
Normal file
@@ -0,0 +1,90 @@
|
||||
{"""PHP code generator."""
|
||||
|
||||
import json
|
||||
|
||||
from curlconverter.parser import ParsedCurl
|
||||
from curlconverter.generators import register_generator
|
||||
|
||||
|
||||
def _detect_content_type(headers: dict, data: str) -> str:
|
||||
"""Detect content type from headers or data."""
|
||||
if "Content-Type" in headers:
|
||||
return headers["Content-Type"]
|
||||
if "content-type" in headers:
|
||||
return headers["content-type"]
|
||||
if data:
|
||||
try:
|
||||
json.loads(data)
|
||||
return "application/json"
|
||||
except (json.JSONDecodeError, TypeError):
|
||||
pass
|
||||
return "application/x-www-form-urlencoded"
|
||||
|
||||
|
||||
@register_generator("php")
|
||||
def generate_php(parsed: ParsedCurl) -> str:
|
||||
"""Generate PHP cURL code from parsed curl data."""
|
||||
lines = []
|
||||
lines.append("<?php")
|
||||
lines.append("")
|
||||
lines.append("$url = " + repr(parsed.url) + ";")
|
||||
lines.append("")
|
||||
|
||||
lines.append("$ch = curl_init();")
|
||||
lines.append("")
|
||||
|
||||
lines.append('curl_setopt($ch, CURLOPT_URL, $url);')
|
||||
lines.append('curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);')
|
||||
lines.append(f'curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "{parsed.method}");')
|
||||
lines.append("")
|
||||
|
||||
headers = dict(parsed.headers) if parsed.headers else {}
|
||||
|
||||
if parsed.user_agent and "User-Agent" not in headers and "user-agent" not in headers:
|
||||
headers["User-Agent"] = parsed.user_agent
|
||||
|
||||
if parsed.data:
|
||||
content_type = _detect_content_type(headers, parsed.data)
|
||||
|
||||
if content_type == "application/json":
|
||||
try:
|
||||
json_data = json.loads(parsed.data)
|
||||
lines.append("$data = " + repr(json.dumps(json_data)) + ";")
|
||||
lines.append("curl_setopt($ch, CURLOPT_POSTFIELDS, $data);")
|
||||
lines.append('curl_setopt($ch, CURLOPT_HTTPHEADER, array(\'Content-Type: application/json\'));')
|
||||
except (json.JSONDecodeError, TypeError):
|
||||
lines.append("$data = " + repr(parsed.data) + ";")
|
||||
lines.append("curl_setopt($ch, CURLOPT_POSTFIELDS, $data);")
|
||||
else:
|
||||
lines.append("$data = " + repr(parsed.data) + ";")
|
||||
lines.append("curl_setopt($ch, CURLOPT_POSTFIELDS, $data);")
|
||||
|
||||
if parsed.method == "GET":
|
||||
lines.append("curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: ' . $content_type));")
|
||||
|
||||
if parsed.auth:
|
||||
lines.append(f'$auth = base64_encode("{parsed.auth[0]}:{parsed.auth[1]}");')
|
||||
lines.append('curl_setopt($ch, CURLOPT_HTTPHEADER, array(\'Authorization: Basic \' . $auth));')
|
||||
|
||||
if headers:
|
||||
http_headers = []
|
||||
for k, v in headers.items():
|
||||
http_headers.append(f"{k}: {v}")
|
||||
lines.append('curl_setopt($ch, CURLOPT_HTTPHEADER, ' + repr(http_headers) + ');')
|
||||
|
||||
lines.append("$response = curl_exec($ch);")
|
||||
lines.append("")
|
||||
lines.append("if (curl_errno($ch)) {")
|
||||
lines.append(" echo 'Error:' . curl_error($ch);")
|
||||
lines.append("}")
|
||||
lines.append("")
|
||||
lines.append("curl_close($ch);")
|
||||
lines.append("echo $response;")
|
||||
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
import curlconverter.generators.python # noqa: E402, F401
|
||||
import curlconverter.generators.javascript # noqa: E402, F401
|
||||
import curlconverter.generators.go # noqa: E402, F401
|
||||
import curlconverter.generators.ruby # noqa: E402, F401
|
||||
@@ -1,4 +1,4 @@
|
||||
"""Python code generator."""
|
||||
{"""Python code generator."""
|
||||
|
||||
import json
|
||||
import base64
|
||||
@@ -40,18 +40,14 @@ def generate_python(parsed: ParsedCurl) -> str:
|
||||
lines.append("headers = " + _format_dict(headers))
|
||||
kwargs.append("headers=headers")
|
||||
|
||||
auth_tuple = None
|
||||
if parsed.auth:
|
||||
auth_username, auth_password = parsed.auth
|
||||
if ":" in parsed.auth[0]:
|
||||
try:
|
||||
encoded = base64.b64encode(f"{parsed.auth[0]}:{parsed.auth[1]}".encode()).decode()
|
||||
if "Authorization" not in headers:
|
||||
headers["Authorization"] = f"Basic {encoded}"
|
||||
except Exception:
|
||||
auth_tuple = parsed.auth
|
||||
else:
|
||||
auth_tuple = parsed.auth
|
||||
pass
|
||||
|
||||
if parsed.data:
|
||||
content_type = _detect_content_type(headers, parsed.data)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""Ruby code generator."""
|
||||
{"""Ruby code generator."""
|
||||
|
||||
import json
|
||||
from curlconverter.parser import ParsedCurl
|
||||
@@ -24,16 +24,14 @@ def _detect_content_type(headers: dict, data: str) -> str:
|
||||
def generate_ruby(parsed: ParsedCurl) -> str:
|
||||
"""Generate Ruby Net::HTTP code from parsed curl data."""
|
||||
lines = []
|
||||
|
||||
lines.append("require 'net/http'")
|
||||
lines.append("require 'uri'")
|
||||
lines.append("require 'json'")
|
||||
lines.append("")
|
||||
|
||||
lines.append("url = URI(" + repr(parsed.url) + ")")
|
||||
lines.append("")
|
||||
|
||||
lines.append(f"url = URI({repr(parsed.url)})")
|
||||
lines.append("http = Net::HTTP.new(url.host, url.port)")
|
||||
lines.append("http.use_ssl = true")
|
||||
lines.append("")
|
||||
|
||||
headers = dict(parsed.headers) if parsed.headers else {}
|
||||
@@ -42,11 +40,11 @@ def generate_ruby(parsed: ParsedCurl) -> str:
|
||||
headers["User-Agent"] = parsed.user_agent
|
||||
|
||||
method_map = {
|
||||
"GET": "Get",
|
||||
"POST": "Post",
|
||||
"PUT": "Put",
|
||||
"DELETE": "Delete",
|
||||
"PATCH": "Patch"
|
||||
"GET" => "Get",
|
||||
"POST" => "Post",
|
||||
"PUT" => "Put",
|
||||
"DELETE" => "Delete",
|
||||
"PATCH" => "Patch"
|
||||
}
|
||||
request_class = f"Net::HTTP::{method_map.get(parsed.method, parsed.method)}"
|
||||
if parsed.data:
|
||||
@@ -56,13 +54,13 @@ def generate_ruby(parsed: ParsedCurl) -> str:
|
||||
try:
|
||||
json_data = json.loads(parsed.data)
|
||||
lines.append("data = " + json.dumps(json_data))
|
||||
request_str = f"Net::HTTP::Post.new(url, {{'Content-Type' => 'application/json'}})"
|
||||
request_str = "Net::HTTP::Post.new(url, {'Content-Type' => 'application/json'})"
|
||||
except (json.JSONDecodeError, TypeError):
|
||||
lines.append("data = " + repr(parsed.data))
|
||||
request_str = f"Net::HTTP::Post.new(url)"
|
||||
request_str = "Net::HTTP::Post.new(url)"
|
||||
else:
|
||||
lines.append("data = " + repr(parsed.data))
|
||||
request_str = f"Net::HTTP::Post.new(url)"
|
||||
request_str = "Net::HTTP::Post.new(url)"
|
||||
|
||||
if "Content-Type" not in headers and "content-type" not in headers:
|
||||
headers["Content-Type"] = content_type
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
"""Parser module for curl commands."""
|
||||
{"""Parser module for curl commands."""
|
||||
|
||||
import re
|
||||
from dataclasses import dataclass, field
|
||||
from typing import Optional
|
||||
|
||||
@@ -8,7 +7,7 @@ from typing import Optional
|
||||
@dataclass
|
||||
class ParsedCurl:
|
||||
"""Represents a parsed curl command."""
|
||||
url: str
|
||||
url: str = ""
|
||||
method: str = "GET"
|
||||
headers: dict = field(default_factory=dict)
|
||||
data: Optional[str] = None
|
||||
@@ -17,183 +16,122 @@ class ParsedCurl:
|
||||
user_agent: Optional[str] = None
|
||||
|
||||
|
||||
def unquote(s: str) -> str:
|
||||
"""Remove outer quotes from a string."""
|
||||
if not s:
|
||||
return s
|
||||
if (s.startswith('"') and s.endswith('"')) or (s.startswith("'") and s.endswith("'")):
|
||||
return s[1:-1]
|
||||
return s
|
||||
|
||||
|
||||
def parse_curl(curl_command: str) -> ParsedCurl:
|
||||
"""Parse a curl command string into structured data.
|
||||
|
||||
Args:
|
||||
curl_command: The curl command string to parse.
|
||||
|
||||
Returns:
|
||||
ParsedCurl object with extracted components.
|
||||
|
||||
Raises:
|
||||
ValueError: If the curl command is invalid.
|
||||
"""
|
||||
if not curl_command.strip():
|
||||
raise ValueError("Empty curl command")
|
||||
|
||||
curl_command = curl_command.strip()
|
||||
if curl_command.startswith("curl "):
|
||||
curl_command = curl_command[5:]
|
||||
elif curl_command.startswith("curl"):
|
||||
curl_command = curl_command[4:]
|
||||
|
||||
tokens = tokenize_command(curl_command)
|
||||
|
||||
url = ""
|
||||
method = "GET"
|
||||
headers = {}
|
||||
data = None
|
||||
auth = None
|
||||
cookies = None
|
||||
user_agent = None
|
||||
|
||||
i = 0
|
||||
while i < len(tokens):
|
||||
token = tokens[i]
|
||||
|
||||
if token == "-X" or token == "--request":
|
||||
if i + 1 < len(tokens):
|
||||
method = tokens[i + 1].upper()
|
||||
i += 2
|
||||
continue
|
||||
|
||||
elif token == "-H" or token == "--header":
|
||||
if i + 1 < len(tokens):
|
||||
header = tokens[i + 1]
|
||||
if ":" in header:
|
||||
key, value = header.split(":", 1)
|
||||
headers[key.strip()] = value.strip()
|
||||
i += 2
|
||||
continue
|
||||
|
||||
elif token == "-d" or token == "--data" or token == "--data-raw":
|
||||
if i + 1 < len(tokens):
|
||||
data = tokens[i + 1]
|
||||
if method == "GET":
|
||||
method = "POST"
|
||||
i += 2
|
||||
continue
|
||||
|
||||
elif token == "-u" or token == "--user":
|
||||
if i + 1 < len(tokens):
|
||||
auth_str = tokens[i + 1]
|
||||
if ":" in auth_str:
|
||||
auth = tuple(auth_str.split(":", 1))
|
||||
else:
|
||||
auth = auth_str
|
||||
i += 2
|
||||
continue
|
||||
|
||||
elif token == "-b" or token == "--cookie":
|
||||
if i + 1 < len(tokens):
|
||||
cookies = tokens[i + 1]
|
||||
i += 2
|
||||
continue
|
||||
|
||||
elif token == "-A" or token == "--user-agent":
|
||||
if i + 1 < len(tokens):
|
||||
user_agent = tokens[i + 1]
|
||||
i += 2
|
||||
continue
|
||||
|
||||
elif token == "-L" or token == "--location" or token == "-s" or token == "--silent" or token == "-S" or token == "--show-error":
|
||||
i += 1
|
||||
continue
|
||||
|
||||
elif token.startswith("-"):
|
||||
i += 1
|
||||
continue
|
||||
|
||||
else:
|
||||
if not url:
|
||||
url = token
|
||||
i += 1
|
||||
|
||||
if not url:
|
||||
raise ValueError("No URL found in curl command")
|
||||
|
||||
if not url.startswith(("http://", "https://")):
|
||||
url = "https://" + url
|
||||
|
||||
if "Authorization" in headers:
|
||||
auth_header = headers["Authorization"]
|
||||
if auth_header.startswith("Basic "):
|
||||
import base64
|
||||
try:
|
||||
encoded = auth_header[6:]
|
||||
decoded = base64.b64decode(encoded).decode("utf-8")
|
||||
if ":" in decoded:
|
||||
auth = tuple(decoded.split(":", 1))
|
||||
except Exception:
|
||||
pass
|
||||
elif auth_header.startswith("Bearer "):
|
||||
headers["Authorization"] = auth_header
|
||||
|
||||
return ParsedCurl(
|
||||
url=url,
|
||||
method=method,
|
||||
headers=headers,
|
||||
data=data,
|
||||
auth=auth,
|
||||
cookies=cookies,
|
||||
user_agent=user_agent
|
||||
)
|
||||
|
||||
|
||||
def tokenize_command(cmd: str) -> list:
|
||||
"""Tokenize a curl command into components, handling quotes and escapes."""
|
||||
"""Tokenize a curl command into arguments."""
|
||||
tokens = []
|
||||
current = ""
|
||||
in_single_quote = False
|
||||
in_double_quote = False
|
||||
escape_next = False
|
||||
|
||||
i = 0
|
||||
while i < len(cmd):
|
||||
char = cmd[i]
|
||||
|
||||
for char in cmd:
|
||||
if escape_next:
|
||||
current += char
|
||||
escape_next = False
|
||||
i += 1
|
||||
continue
|
||||
|
||||
if char == "\\" and not in_single_quote:
|
||||
if char == '\\' and not in_single_quote:
|
||||
escape_next = True
|
||||
i += 1
|
||||
continue
|
||||
|
||||
if char == "'" and not in_double_quote:
|
||||
in_single_quote = not in_single_quote
|
||||
i += 1
|
||||
current += char
|
||||
continue
|
||||
|
||||
if char == '"' and not in_single_quote:
|
||||
in_double_quote = not in_double_quote
|
||||
i += 1
|
||||
current += char
|
||||
continue
|
||||
|
||||
if char == " " and not in_single_quote and not in_double_quote:
|
||||
if char == ' ' and not in_single_quote and not in_double_quote:
|
||||
if current:
|
||||
tokens.append(current)
|
||||
current = ""
|
||||
i += 1
|
||||
continue
|
||||
|
||||
current += char
|
||||
i += 1
|
||||
|
||||
if current:
|
||||
tokens.append(current)
|
||||
|
||||
return tokens
|
||||
|
||||
|
||||
def parse_curl(command: str) -> ParsedCurl:
|
||||
"""Parse a curl command string into a ParsedCurl object."""
|
||||
if not command:
|
||||
raise ValueError("Empty curl command")
|
||||
|
||||
command = command.strip()
|
||||
if command.startswith("curl "):
|
||||
command = command[5:]
|
||||
|
||||
tokens = tokenize_command(command)
|
||||
|
||||
if not tokens:
|
||||
raise ValueError("No URL found in curl command")
|
||||
|
||||
parsed = ParsedCurl()
|
||||
|
||||
i = 0
|
||||
while i < len(tokens):
|
||||
token = tokens[i]
|
||||
|
||||
if not token.startswith("-"):
|
||||
if not parsed.url:
|
||||
parsed.url = token
|
||||
i += 1
|
||||
continue
|
||||
|
||||
if token in ("-X", "--request"):
|
||||
if i + 1 < len(tokens):
|
||||
parsed.method = tokens[i + 1].upper()
|
||||
i += 2
|
||||
continue
|
||||
|
||||
if token in ("-H", "--header"):
|
||||
if i + 1 < len(tokens):
|
||||
header = tokens[i + 1]
|
||||
if ":" in header:
|
||||
key, value = header.split(":", 1)
|
||||
parsed.headers[key.strip()] = value.strip()
|
||||
i += 2
|
||||
continue
|
||||
|
||||
if token in ("-d", "--data", "--data-raw", "--data-binary"):
|
||||
if i + 1 < len(tokens):
|
||||
parsed.data = tokens[i + 1]
|
||||
if parsed.method == "GET":
|
||||
parsed.method = "POST"
|
||||
i += 2
|
||||
continue
|
||||
|
||||
if token in ("-u", "--user"):
|
||||
if i + 1 < len(tokens):
|
||||
auth = tokens[i + 1]
|
||||
if ":" in auth:
|
||||
parsed.auth = auth.split(":", 1)
|
||||
else:
|
||||
parsed.auth = (auth, "")
|
||||
i += 2
|
||||
continue
|
||||
|
||||
if token in ("-b", "--cookie"):
|
||||
if i + 1 < len(tokens):
|
||||
parsed.cookies = tokens[i + 1]
|
||||
i += 2
|
||||
continue
|
||||
|
||||
if token in ("-A", "--user-agent"):
|
||||
if i + 1 < len(tokens):
|
||||
parsed.user_agent = tokens[i + 1]
|
||||
i += 2
|
||||
continue
|
||||
|
||||
i += 1
|
||||
|
||||
if not parsed.url:
|
||||
raise ValueError("No URL found in curl command")
|
||||
|
||||
return parsed
|
||||
@@ -1,4 +1,4 @@
|
||||
"""Tests for code generators."""
|
||||
{"""Tests for code generators."""
|
||||
|
||||
import pytest
|
||||
from curlconverter.parser import parse_curl
|
||||
@@ -9,60 +9,48 @@ class TestPythonGenerator:
|
||||
"""Tests for Python code generator."""
|
||||
|
||||
def test_basic_get_request(self):
|
||||
"""Test generating Python code for GET request."""
|
||||
curl = "curl https://api.example.com/users"
|
||||
parsed = parse_curl(curl)
|
||||
"""Test basic GET request."""
|
||||
parsed = parse_curl("curl http://example.com")
|
||||
code = generate_code(parsed, "python")
|
||||
|
||||
assert "import requests" in code
|
||||
assert "https://api.example.com/users" in code
|
||||
assert "url = 'http://example.com'" in code
|
||||
assert "requests.get" in code
|
||||
|
||||
def test_post_with_json(self):
|
||||
"""Test generating Python code for POST with JSON."""
|
||||
curl = 'curl -X POST -H "Content-Type: application/json" -d \'{"name":"test"}\' https://api.example.com/users'
|
||||
parsed = parse_curl(curl)
|
||||
"""Test POST with JSON data."""
|
||||
parsed = parse_curl('curl -X POST -H "Content-Type: application/json" -d \'{"key":"value"}\' http://example.com')
|
||||
code = generate_code(parsed, "python")
|
||||
|
||||
assert "requests.post" in code
|
||||
assert "json=data" in code or "json=data" in code
|
||||
assert "json=data" in code
|
||||
|
||||
def test_basic_auth(self):
|
||||
"""Test generating Python code with basic auth."""
|
||||
curl = "curl -u user:pass https://api.example.com"
|
||||
parsed = parse_curl(curl)
|
||||
"""Test basic authentication."""
|
||||
parsed = parse_curl("curl -u user:pass http://example.com")
|
||||
code = generate_code(parsed, "python")
|
||||
|
||||
assert "Authorization" in code or "requests" in code
|
||||
assert "Authorization" in code
|
||||
assert "Basic" in code
|
||||
|
||||
def test_headers(self):
|
||||
"""Test generating Python code with headers."""
|
||||
curl = 'curl -H "Authorization: Bearer token" https://api.example.com'
|
||||
parsed = parse_curl(curl)
|
||||
"""Test custom headers."""
|
||||
parsed = parse_curl('curl -H "X-Custom: header" http://example.com')
|
||||
code = generate_code(parsed, "python")
|
||||
|
||||
assert "headers" in code
|
||||
assert "X-Custom" in code
|
||||
|
||||
|
||||
class TestJavaScriptGenerator:
|
||||
"""Tests for JavaScript code generator."""
|
||||
|
||||
def test_basic_get_request(self):
|
||||
"""Test generating JavaScript code for GET request."""
|
||||
curl = "curl https://api.example.com/users"
|
||||
parsed = parse_curl(curl)
|
||||
"""Test basic GET request."""
|
||||
parsed = parse_curl("curl http://example.com")
|
||||
code = generate_code(parsed, "javascript")
|
||||
|
||||
assert "fetch" in code
|
||||
assert "https://api.example.com/users" in code
|
||||
assert "GET" in code
|
||||
assert "url = 'http://example.com'" in code
|
||||
|
||||
def test_post_with_data(self):
|
||||
"""Test generating JavaScript code for POST."""
|
||||
curl = "curl -X POST -d 'name=test' https://api.example.com/users"
|
||||
parsed = parse_curl(curl)
|
||||
"""Test POST with data."""
|
||||
parsed = parse_curl("curl -X POST -d 'key=value' http://example.com")
|
||||
code = generate_code(parsed, "javascript")
|
||||
|
||||
assert "POST" in code
|
||||
assert "body" in code
|
||||
|
||||
@@ -71,76 +59,61 @@ class TestGoGenerator:
|
||||
"""Tests for Go code generator."""
|
||||
|
||||
def test_basic_get_request(self):
|
||||
"""Test generating Go code for GET request."""
|
||||
curl = "curl https://api.example.com/users"
|
||||
parsed = parse_curl(curl)
|
||||
"""Test basic GET request."""
|
||||
parsed = parse_curl("curl http://example.com")
|
||||
code = generate_code(parsed, "go")
|
||||
|
||||
assert "package main" in code
|
||||
assert "net/http" in code
|
||||
assert "https://api.example.com/users" in code
|
||||
assert "http.NewRequest" in code
|
||||
|
||||
def test_post_request(self):
|
||||
"""Test generating Go code for POST."""
|
||||
curl = "curl -X POST -d 'name=test' https://api.example.com/users"
|
||||
parsed = parse_curl(curl)
|
||||
"""Test POST request."""
|
||||
parsed = parse_curl("curl -X POST -d 'key=value' http://example.com")
|
||||
code = generate_code(parsed, "go")
|
||||
|
||||
assert "POST" in code
|
||||
assert "bytes.NewBuffer" in code
|
||||
assert "strings.NewReader" in code
|
||||
|
||||
|
||||
class TestRubyGenerator:
|
||||
"""Tests for Ruby code generator."""
|
||||
|
||||
def test_basic_get_request(self):
|
||||
"""Test generating Ruby code for GET request."""
|
||||
curl = "curl https://api.example.com/users"
|
||||
parsed = parse_curl(curl)
|
||||
"""Test basic GET request."""
|
||||
parsed = parse_curl("curl http://example.com")
|
||||
code = generate_code(parsed, "ruby")
|
||||
|
||||
assert "require 'net/http'" in code
|
||||
assert "Net::HTTP::Get" in code
|
||||
assert "https://api.example.com/users" in code
|
||||
assert "net/http" in code
|
||||
assert "Net::HTTP" in code
|
||||
|
||||
def test_post_request(self):
|
||||
"""Test generating Ruby code for POST."""
|
||||
curl = "curl -X POST -d 'name=test' https://api.example.com/users"
|
||||
parsed = parse_curl(curl)
|
||||
"""Test POST request."""
|
||||
parsed = parse_curl("curl -X POST -d 'key=value' http://example.com")
|
||||
code = generate_code(parsed, "ruby")
|
||||
|
||||
assert "Net::HTTP::Post" in code
|
||||
assert "Post" in code
|
||||
|
||||
|
||||
class TestPHPGenerator:
|
||||
"""Tests for PHP code generator."""
|
||||
|
||||
def test_basic_get_request(self):
|
||||
"""Test generating PHP code for GET request."""
|
||||
curl = "curl https://api.example.com/users"
|
||||
parsed = parse_curl(curl)
|
||||
"""Test basic GET request."""
|
||||
parsed = parse_curl("curl http://example.com")
|
||||
code = generate_code(parsed, "php")
|
||||
|
||||
assert "<?php" in code
|
||||
assert "curl_init" in code
|
||||
assert "https://api.example.com/users" in code
|
||||
assert "$url" in code
|
||||
|
||||
def test_post_request(self):
|
||||
"""Test generating PHP code for POST."""
|
||||
curl = "curl -X POST -d 'name=test' https://api.example.com/users"
|
||||
parsed = parse_curl(curl)
|
||||
"""Test POST request."""
|
||||
parsed = parse_curl("curl -X POST -d 'key=value' http://example.com")
|
||||
code = generate_code(parsed, "php")
|
||||
|
||||
assert "CURLOPT_POST" in code or "CUSTOMREQUEST" in code
|
||||
assert "CURLOPT_POST" in code or "CURLOPT_CUSTOMREQUEST" in code
|
||||
|
||||
|
||||
class TestSupportedLanguages:
|
||||
"""Tests for supported languages."""
|
||||
|
||||
def test_get_supported_languages(self):
|
||||
"""Test getting list of supported languages."""
|
||||
"""Test getting supported languages."""
|
||||
languages = get_supported_languages()
|
||||
|
||||
assert "python" in languages
|
||||
assert "javascript" in languages
|
||||
assert "go" in languages
|
||||
@@ -148,11 +121,7 @@ class TestSupportedLanguages:
|
||||
assert "php" in languages
|
||||
|
||||
def test_unsupported_language_raises_error(self):
|
||||
"""Test that unsupported language raises ValueError."""
|
||||
curl = "curl https://example.com"
|
||||
parsed = parse_curl(curl)
|
||||
|
||||
with pytest.raises(ValueError) as exc_info:
|
||||
generate_code(parsed, "unsupported_lang")
|
||||
|
||||
assert "Unsupported language" in str(exc_info.value)
|
||||
"""Test unsupported language raises error."""
|
||||
parsed = parse_curl("curl http://example.com")
|
||||
with pytest.raises(ValueError, match="Unsupported language"):
|
||||
generate_code(parsed, "unsupported")
|
||||
@@ -1,7 +1,7 @@
|
||||
"""Tests for the curl parser module."""
|
||||
{"""Tests for the parser module."""
|
||||
|
||||
import pytest
|
||||
from curlconverter.parser import parse_curl, ParsedCurl, tokenize_command
|
||||
from curlconverter.parser import parse_curl, tokenize_command, ParsedCurl
|
||||
|
||||
|
||||
class TestTokenizeCommand:
|
||||
@@ -9,120 +9,101 @@ class TestTokenizeCommand:
|
||||
|
||||
def test_simple_tokens(self):
|
||||
"""Test simple command tokenization."""
|
||||
tokens = tokenize_command("curl -X POST https://example.com")
|
||||
assert "curl" in tokens
|
||||
assert "-X" in tokens
|
||||
assert "POST" in tokens
|
||||
assert "https://example.com" in tokens
|
||||
tokens = tokenize_command("curl -X GET http://example.com")
|
||||
assert tokens == ["curl", "-X", "GET", "http://example.com"]
|
||||
|
||||
def test_quoted_strings(self):
|
||||
"""Test handling of quoted strings."""
|
||||
tokens = tokenize_command('-H "Content-Type: application/json"')
|
||||
assert '-H' in tokens
|
||||
"""Test quoted string tokenization."""
|
||||
tokens = tokenize_command('curl -H "Content-Type: application/json" http://example.com')
|
||||
assert "-H" in tokens
|
||||
assert 'Content-Type: application/json' in tokens
|
||||
|
||||
def test_single_quotes(self):
|
||||
"""Test handling of single quotes."""
|
||||
tokens = tokenize_command("-d '{\"key\": \"value\"}'")
|
||||
"""Test single quote tokenization."""
|
||||
tokens = tokenize_command("curl -d 'hello world' http://example.com")
|
||||
assert "-d" in tokens
|
||||
assert '{"key": "value"}' in tokens
|
||||
assert "'hello world'" in tokens
|
||||
|
||||
|
||||
class TestParseCurl:
|
||||
"""Tests for parse_curl function."""
|
||||
|
||||
def test_basic_get_request(self):
|
||||
"""Test parsing a basic GET request."""
|
||||
curl = "curl https://example.com"
|
||||
result = parse_curl(curl)
|
||||
assert result.url == "https://example.com"
|
||||
assert result.method == "GET"
|
||||
"""Test basic GET request parsing."""
|
||||
parsed = parse_curl("curl http://example.com")
|
||||
assert parsed.url == "http://example.com"
|
||||
assert parsed.method == "GET"
|
||||
|
||||
def test_url_with_protocol(self):
|
||||
"""Test URL with http protocol."""
|
||||
curl = "curl http://example.com"
|
||||
result = parse_curl(curl)
|
||||
assert result.url == "http://example.com"
|
||||
"""Test URL with protocol."""
|
||||
parsed = parse_curl("curl https://api.example.com/endpoint")
|
||||
assert parsed.url == "https://api.example.com/endpoint"
|
||||
|
||||
def test_post_request(self):
|
||||
"""Test parsing POST request with -X."""
|
||||
curl = "curl -X POST https://api.example.com/users"
|
||||
result = parse_curl(curl)
|
||||
assert result.url == "https://api.example.com/users"
|
||||
assert result.method == "POST"
|
||||
"""Test POST request parsing."""
|
||||
parsed = parse_curl("curl -X POST http://example.com")
|
||||
assert parsed.method == "POST"
|
||||
|
||||
def test_post_with_data(self):
|
||||
"""Test parsing POST with -d flag."""
|
||||
curl = "curl -d 'name=test' https://api.example.com/users"
|
||||
result = parse_curl(curl)
|
||||
assert result.method == "POST"
|
||||
assert result.data == "name=test"
|
||||
"""Test POST with data."""
|
||||
parsed = parse_curl("curl -d 'key=value' http://example.com")
|
||||
assert parsed.data == "key=value"
|
||||
assert parsed.method == "POST"
|
||||
|
||||
def test_post_with_data_raw(self):
|
||||
"""Test parsing POST with --data-raw flag."""
|
||||
curl = 'curl --data-raw {"name":"test"} https://api.example.com/users'
|
||||
result = parse_curl(curl)
|
||||
assert result.method == "POST"
|
||||
assert result.data == '{name:test}'
|
||||
"""Test POST with --data-raw."""
|
||||
parsed = parse_curl("curl --data-raw '{"key": "value"}' http://example.com")
|
||||
assert parsed.data == '{"key": "value"}'
|
||||
assert parsed.method == "POST"
|
||||
|
||||
def test_headers(self):
|
||||
"""Test parsing headers."""
|
||||
curl = 'curl -H "Content-Type: application/json" -H "Authorization: Bearer token" https://api.example.com'
|
||||
result = parse_curl(curl)
|
||||
assert "Content-Type" in result.headers
|
||||
assert result.headers["Content-Type"] == "application/json"
|
||||
assert "Authorization" in result.headers
|
||||
"""Test header parsing."""
|
||||
parsed = parse_curl('curl -H "Content-Type: application/json" http://example.com')
|
||||
assert "Content-Type" in parsed.headers
|
||||
assert parsed.headers["Content-Type"] == "application/json"
|
||||
|
||||
def test_basic_auth(self):
|
||||
"""Test parsing basic authentication."""
|
||||
curl = "curl -u user:pass https://api.example.com"
|
||||
result = parse_curl(curl)
|
||||
assert result.auth == ("user", "pass")
|
||||
"""Test basic auth parsing."""
|
||||
parsed = parse_curl("curl -u user:pass http://example.com")
|
||||
assert parsed.auth == ("user", "pass")
|
||||
|
||||
def test_cookies(self):
|
||||
"""Test parsing cookies."""
|
||||
curl = "curl -b 'session=abc123' https://example.com"
|
||||
result = parse_curl(curl)
|
||||
assert result.cookies == "session=abc123"
|
||||
"""Test cookie parsing."""
|
||||
parsed = parse_curl("curl -b 'session=abc123' http://example.com")
|
||||
assert parsed.cookies == "session=abc123"
|
||||
|
||||
def test_user_agent(self):
|
||||
"""Test parsing user agent."""
|
||||
curl = "curl -A 'Mozilla/5.0' https://example.com"
|
||||
result = parse_curl(curl)
|
||||
assert result.user_agent == "Mozilla/5.0"
|
||||
"""Test user-agent parsing."""
|
||||
parsed = parse_curl("curl -A 'Mozilla/5.0' http://example.com")
|
||||
assert parsed.user_agent == "Mozilla/5.0"
|
||||
|
||||
def test_full_command(self):
|
||||
"""Test parsing a complete curl command."""
|
||||
curl = '''curl -X POST \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer token" \
|
||||
-d '{\"name\":\"test\"}' \
|
||||
-u user:pass \
|
||||
-b "session=abc" \
|
||||
https://api.example.com/users'''
|
||||
result = parse_curl(curl)
|
||||
assert result.url == "https://api.example.com/users"
|
||||
assert result.method == "POST"
|
||||
assert "Content-Type" in result.headers
|
||||
assert result.data == '{"name":"test"}'
|
||||
assert result.auth == ("user", "pass")
|
||||
assert result.cookies == "session=abc"
|
||||
"""Test full curl command with all options."""
|
||||
cmd = 'curl -X POST -H "Content-Type: application/json" -d \'{"key":"value"}\' -u user:pass -b "session=abc" -A "Mozilla" http://example.com/api'
|
||||
parsed = parse_curl(cmd)
|
||||
|
||||
assert parsed.url == "http://example.com/api"
|
||||
assert parsed.method == "POST"
|
||||
assert "Content-Type" in parsed.headers
|
||||
assert parsed.data == '{"key":"value"}'
|
||||
assert parsed.auth == ("user", "pass")
|
||||
assert parsed.cookies == "session=abc"
|
||||
assert parsed.user_agent == "Mozilla"
|
||||
|
||||
def test_empty_command_raises_error(self):
|
||||
"""Test that empty command raises ValueError."""
|
||||
with pytest.raises(ValueError):
|
||||
"""Test empty command raises error."""
|
||||
with pytest.raises(ValueError, match="Empty curl command"):
|
||||
parse_curl("")
|
||||
|
||||
def test_no_url_raises_error(self):
|
||||
"""Test that command without URL raises ValueError."""
|
||||
with pytest.raises(ValueError):
|
||||
"""Test command without URL raises error."""
|
||||
with pytest.raises(ValueError, match="No URL found"):
|
||||
parse_curl("curl -X POST")
|
||||
|
||||
def test_curl_prefix_optional(self):
|
||||
"""Test that 'curl' prefix is optional."""
|
||||
result = parse_curl("https://example.com")
|
||||
assert result.url == "https://example.com"
|
||||
assert result.method == "GET"
|
||||
parsed = parse_curl("http://example.com")
|
||||
assert parsed.url == "http://example.com"
|
||||
|
||||
|
||||
class TestParsedCurl:
|
||||
@@ -130,11 +111,11 @@ class TestParsedCurl:
|
||||
|
||||
def test_default_values(self):
|
||||
"""Test default values."""
|
||||
curl = ParsedCurl(url="https://example.com")
|
||||
assert curl.url == "https://example.com"
|
||||
assert curl.method == "GET"
|
||||
assert curl.headers == {}
|
||||
assert curl.data is None
|
||||
assert curl.auth is None
|
||||
assert curl.cookies is None
|
||||
assert curl.user_agent is None
|
||||
parsed = ParsedCurl(url="http://example.com")
|
||||
assert parsed.url == "http://example.com"
|
||||
assert parsed.method == "GET"
|
||||
assert parsed.headers == {}
|
||||
assert parsed.data is None
|
||||
assert parsed.auth is None
|
||||
assert parsed.cookies is None
|
||||
assert parsed.user_agent is None
|
||||
Reference in New Issue
Block a user