diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 211eaf06..32f79e5c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -154,4 +154,16 @@ ClientException with SocketException: Connection failed (OS Error: Operation not You can read more [here](https://docs.flutter.dev/platform-integration/macos/building#setting-up-entitlements) +### Android (Work in Progress) +Add the `multiDexEnabled true` line to the `defaultConfig` section at `android/app/build.gradle file` + +``` +android { + ... + defaultConfig { + ... + multiDexEnabled true + } +} +``` diff --git a/README.md b/README.md index f6f73d62..99a70e1f 100644 --- a/README.md +++ b/README.md @@ -127,6 +127,7 @@ API Dash currently supports API integration code generation for the following la | ---------------------- | ------------- | ------- | | cURL | | | | HAR | | | +| C# | `RestSharp` | | | Dart | `http` | | | Dart | `dio` | | | Go | `net/http` | | @@ -137,14 +138,18 @@ API Dash currently supports API integration code generation for the following la | Python | `requests` | | | Python | `http.client` | | | Kotlin | `okhttp3` | | +| Ruby | `faraday` | | +| Ruby | `net/http` | | | Rust | `reqwest` | | | Rust | `ureq` | | | Rust | `Actix Client` | | | Java | `asynchttpclient` | https://github.com/foss42/apidash/issues/136 | -| Java | `HttpClient` | https://github.com/foss42/apidash/issues/137 | +| Java | `HttpClient` | | | Java | `okhttp3` | | -| Julia | `HTTP` | https://github.com/foss42/apidash/issues/154 | +| Julia | `HTTP` | | +| PHP | `curl` | https://github.com/foss42/apidash/issues/375 | | PHP | `guzzle` | https://github.com/foss42/apidash/issues/143 | +| C | `libcurl` | | We welcome contributions to support other programming languages/libraries/frameworks. Please check out more details [here](https://github.com/foss42/apidash/discussions/80). @@ -157,7 +162,16 @@ Here is the complete list of mimetypes that can be directly previewed in API Das | File Type | Mimetype | Extension | Comment | | --------- | -------------------------- | ----------------- | -------- | | PDF | `application/pdf` | `.pdf` | | -| CSV | `text/csv` | `.csv` | Can be improved | +| Video | `video/mp4` | `.mp4` | | +| Video | `video/webm` | `.webm` | | +| Video | `video/x-ms-wmv` | `.wmv` | | +| Video | `video/x-ms-asf` | `.wmv` | | +| Video | `video/avi` | `.avi` | | +| Video | `video/msvideo` | `.avi` | | +| Video | `video/x-msvideo` | `.avi` | | +| Video | `video/quicktime` | `.mov` | | +| Video | `video/x-quicktime` | `.mov` | | +| Video | `video/x-matroska` | `.mkv` | | | Image | `image/apng` | `.apng` | Animated | | Image | `image/avif` | `.avif` | | | Image | `image/bmp` | `.bmp` | | @@ -188,6 +202,7 @@ Here is the complete list of mimetypes that can be directly previewed in API Das | Audio | `audio/x-m4a` | `.m4a` | | | Audio | `audio/wav` | `.wav` | | | Audio | `audio/wave` | `.wav` | | +| CSV | `text/csv` | `.csv` | Can be improved | We welcome PRs to add support for previewing other multimedia mimetypes. Please go ahead and raise an issue so that we can discuss the approach. We are adding support for other mimetypes with each release. But, if you are looking for any particular mimetype support, please go ahead and open an issue. We will prioritize it's addition. diff --git a/lib/app.dart b/lib/app.dart index f60198af..70e95213 100644 --- a/lib/app.dart +++ b/lib/app.dart @@ -57,7 +57,7 @@ class _AppState extends ConsumerState with WindowListener { bool isPreventClose = await windowManager.isPreventClose(); if (isPreventClose) { if (ref.watch( - settingsProvider.select((value) => value.promptBeforeClosing))) { + settingsProvider.select((value) => value.promptBeforeClosing)) && ref.watch(hasUnsavedChangesProvider)) { showDialog( context: context, builder: (_) => AlertDialog( diff --git a/lib/codegen/c/curl.dart b/lib/codegen/c/curl.dart new file mode 100644 index 00000000..3b363e3b --- /dev/null +++ b/lib/codegen/c/curl.dart @@ -0,0 +1,193 @@ +import 'package:apidash/consts.dart'; +import 'package:jinja/jinja.dart' as jj; +import 'package:apidash/utils/utils.dart' + show getValidRequestUri, requestModelToHARJsonRequest; +import 'package:apidash/models/models.dart' show RequestModel; + +class CCurlCodeGen { + final String kTemplateStart = """#include +#include +#include +#include +struct ResponseData { + char *data; + size_t size; +}; + +size_t write_callback(char *ptr, size_t size, size_t nmemb, void *userdata) { + struct ResponseData *response_data = (struct ResponseData *)userdata; + size_t real_size = size * nmemb; + + response_data->data = realloc(response_data->data, response_data->size + real_size + 1); + if (response_data->data == NULL) { + fprintf(stderr, "Memory allocation failed\\n"); + return 0; + } + + memcpy(&(response_data->data[response_data->size]), ptr, real_size); + response_data->size += real_size; + response_data->data[response_data->size] = 0; + + return real_size; +} +int main() { + CURL *curl; + CURLcode res; + curl = curl_easy_init(); + if(curl) { +"""; + + String kTemplateUrl = """\n curl_easy_setopt(curl, CURLOPT_URL, "{{url}}"); +"""; + + String kTemplateBody = """ + {% if body %} + const char *data = "{{body}}"; + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data); + {% endif %} + +"""; + + String kTemplateFormData = """ + + curl_mime *mime; + curl_mimepart *part; + mime = curl_mime_init(curl); + {% for field in fields %}{% if field.type == "file" %} + part = curl_mime_addpart(mime); + curl_mime_name(part, "{{field.name}}"); + curl_mime_filedata(part, "{{field.value}}"); + {% else %} + part = curl_mime_addpart(mime); + curl_mime_name(part, "{{field.name}}"); + curl_mime_data(part, "{{field.value}}", CURL_ZERO_TERMINATED); + {% endif %} + {% endfor %} +"""; + + String kTemplateHeader = """ + + struct curl_slist *headers = NULL; + {% if headers %}{% for header, value in headers %} headers = curl_slist_append(headers,"{{header}}: {{value}}");\n {% endfor %} + {% endif %} curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); +"""; + String kTemplateQueryParam = """"""; + + String kTemplateRequest = + """{% if method != "GET" and method != "POST" %}\n curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "{{method}}");{% endif %}"""; + + final String kTemplateEnd = """ +{% if formdata %}curl_easy_setopt(curl, CURLOPT_MIMEPOST, mime);{% endif %} + struct ResponseData response_data = {0}; + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response_data); + res = curl_easy_perform(curl); + long response_code; + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code); + printf("Response code: %ld\\n", response_code); + printf("Response body: %s\\n", response_data.data); + free(response_data.data);{% if formdata %}\n curl_mime_free(mime);{% endif %}{% if headers %}\n curl_slist_free_all(headers);{% endif %} + } + curl_easy_cleanup(curl); + return 0; +}"""; + + String? getCode( + RequestModel requestModel, + ) { + try { + String result = ""; + var hasBody = false; + var requestBody = requestModel.requestBody; + + String url = requestModel.url; + + var templateStart = jj.Template(kTemplateStart); + result += templateStart.render({ + "hasFormData": requestModel.hasFormData, + "hasFileInFormData": requestModel.hasFileInFormData, + }); + + var method = requestModel.method.name.toUpperCase(); + var templateRequest = jj.Template(kTemplateRequest); + result += templateRequest.render({ + "method": method, + "hasBody": hasBody, + }); + + var harJson = + requestModelToHARJsonRequest(requestModel, useEnabled: true); + var templateUrl = jj.Template(kTemplateUrl); + String correctUrl = harJson["url"]; + result += templateUrl.render({"url": correctUrl}); + + var rec = getValidRequestUri( + url, + requestModel.enabledRequestParams, + ); + + var headersList = requestModel.enabledRequestHeaders; + if (headersList != null || + requestModel.hasBody || + requestModel.hasTextData || + requestModel.hasJsonData) { + var headers = requestModel.enabledHeadersMap; + // if (requestModel.hasFormData) { + // headers.putIfAbsent("Content-Type", () => "multipart/form-data"); + // } + if (requestModel.hasTextData || requestModel.hasJsonData) { + headers.putIfAbsent(kHeaderContentType, + () => requestModel.requestBodyContentType.header); + } + if (headers.isNotEmpty) { + var templateHeader = jj.Template(kTemplateHeader); + result += templateHeader.render({ + "headers": headers, + }); + } + } + + Uri? uri = rec.$1; + + if (uri != null) { + if (requestModel.hasTextData || requestModel.hasJsonData) { + hasBody = true; + var templateRawBody = jj.Template(kTemplateBody); + String body = ""; + if (requestBody != null) { + body = requestBody.replaceAll('"', '\\"').replaceAll('\n', '\\n'); + } + result += templateRawBody.render({"body": body}); + } else if (requestModel.hasFormData) { + hasBody = true; + var templateFormData = jj.Template(kTemplateFormData); + result += templateFormData.render({ + "hasFileInFormData": requestModel.hasFileInFormData, + "fields": requestModel.formDataMapList, + }); + } + if (requestModel.hasTextData) {} + if (uri.hasQuery) { + var params = uri.queryParameters; + if (params.isNotEmpty) { + var templateQueryParam = jj.Template(kTemplateQueryParam); + result += templateQueryParam.render({"params": params}); + } + } + var headers = requestModel.enabledHeadersMap; + bool allow = headers.isNotEmpty || + requestModel.hasTextData || + requestModel.hasJsonData; + var templateEnd = jj.Template(kTemplateEnd); + result += templateEnd.render({ + "formdata": requestModel.hasFormData, + "headers": allow, + }); + } + + return result; + } catch (e) { + return null; + } + } +} diff --git a/lib/codegen/codegen.dart b/lib/codegen/codegen.dart index b7cfa349..9f82b4c9 100644 --- a/lib/codegen/codegen.dart +++ b/lib/codegen/codegen.dart @@ -1,15 +1,20 @@ -import 'package:apidash/codegen/java/unirest.dart'; import 'package:apidash/models/models.dart' show RequestModel; import 'package:apidash/consts.dart'; import 'package:apidash/utils/utils.dart' show getNewUuid; +import 'c/curl.dart'; +import 'csharp/rest_sharp.dart'; import 'dart/http.dart'; import 'dart/dio.dart'; import 'go/http.dart'; import 'kotlin/okhttp.dart'; import 'php/guzzle.dart'; +import 'php/curl.dart'; import 'python/http_client.dart'; import 'python/requests.dart'; +import 'ruby/faraday.dart'; +import 'ruby/net_http.dart'; import 'rust/actix.dart'; +import 'rust/curl_rust.dart'; import 'rust/reqwest.dart'; import 'rust/ureq.dart'; import 'js/axios.dart'; @@ -17,6 +22,7 @@ import 'js/fetch.dart'; import 'others/har.dart'; import 'others/curl.dart'; import 'julia/http.dart'; +import 'java/unirest.dart'; import 'java/okhttp.dart'; import 'java/async_http_client.dart'; import 'java/httpclient.dart'; @@ -60,11 +66,11 @@ class Codegen { case CodegenLanguage.javaAsyncHttpClient: return JavaAsyncHttpClientGen().getCode(rM); case CodegenLanguage.javaHttpClient: - return JavaHttpClientCodeGen().getCode(rM); - case CodegenLanguage.javaUnirest: - return JavaUnirestGen().getCode(rM, boundary); + return JavaHttpClientCodeGen().getCode(rM, boundary: boundary); case CodegenLanguage.javaOkHttp: return JavaOkHttpCodeGen().getCode(rM); + case CodegenLanguage.javaUnirest: + return JavaUnirestGen().getCode(rM, boundary); case CodegenLanguage.juliaHttp: return JuliaHttpClientCodeGen().getCode(rM); case CodegenLanguage.kotlinOkHttp: @@ -74,14 +80,26 @@ class Codegen { .getCode(rM, boundary: boundary ?? getNewUuid()); case CodegenLanguage.pythonRequests: return PythonRequestsCodeGen().getCode(rM, boundary: boundary); + case CodegenLanguage.rubyFaraday: + return RubyFaradayCodeGen().getCode(rM); + case CodegenLanguage.rubyNetHttp: + return RubyNetHttpCodeGen().getCode(rM); case CodegenLanguage.rustActix: return RustActixCodeGen().getCode(rM, boundary: boundary); + case CodegenLanguage.rustCurl: + return RustCurlCodeGen().getCode(rM); case CodegenLanguage.rustReqwest: return RustReqwestCodeGen().getCode(rM); case CodegenLanguage.rustUreq: return RustUreqCodeGen().getCode(rM, boundary: boundary); case CodegenLanguage.phpGuzzle: return PhpGuzzleCodeGen().getCode(rM); + case CodegenLanguage.phpCurl: + return PHPcURLCodeGen().getCode(rM); + case CodegenLanguage.cCurlCodeGen: + return CCurlCodeGen().getCode(rM); + case CodegenLanguage.cSharpRestSharp: + return CSharpRestSharp().getCode(rM); } } } diff --git a/lib/codegen/csharp/rest_sharp.dart b/lib/codegen/csharp/rest_sharp.dart new file mode 100644 index 00000000..d3c69193 --- /dev/null +++ b/lib/codegen/csharp/rest_sharp.dart @@ -0,0 +1,197 @@ +import 'dart:convert'; + +import 'package:apidash/consts.dart'; +import 'package:jinja/jinja.dart' as jj; +import '../../models/request_model.dart'; +import '../../extensions/extensions.dart'; +import '../../utils/http_utils.dart'; + +class CSharpRestSharp { + String kStringImports = """ +using System; +using RestSharp; +using System.Threading.Tasks; + + +"""; + + String kStringInit = """ +class Program +{ + static async Task Main(){ + try{ +"""; + + String kInitClientTemplate = """ + const String _baseUrl = "{{baseUrl}}"; + var client = new RestClient(_baseUrl); + + +"""; + + String kMethodTypeTemplate = """ + var request = new RestRequest("{{path}}", Method.{{method}}); + + +"""; + + String kTemplateParams = """ + request.AddQueryParameter("{{param}}", "{{value}}"); + +"""; + + String kTemplateHeaders = """ + request.AddHeader("{{header}}", "{{value}}"); + +"""; + + String kTemplateFormData = """ + {% if type == "text" -%} + request.AddParameter("{{name}}", "{{value}}", ParameterType.GetOrPost); +{% else -%} + request.AddFile("{{name}}", "{{value}}", options: options); +{% endif -%} +"""; + + String kStringFormDataOption = """ + request.AlwaysMultipartFormData = true; +"""; + + String kStringFormdataFileOption = """ + var options = new FileParameterOptions + { + DisableFilenameEncoding = true + }; +"""; + + String kTemplateJsonData = """ + var jsonBody = new {{jsonData}}; + request.AddJsonBody(jsonBody); + + +"""; + + String kTemplateTextData = """ + var textBody = {{textData}}; + request.AddStringBody(textBody, ContentType.Plain); + + +"""; + + String kStringEnd = """ + var response = await client.ExecuteAsync(request); + Console.WriteLine("Status Code: " + (int)response.StatusCode); + Console.WriteLine("Response Content: " + response.Content); + } + catch(Exception ex){ + Console.WriteLine("Error: " + ex); + } + } +} +"""; + + String? getCode(RequestModel requestModel) { + try { + String result = ""; + var rec = getValidRequestUri( + requestModel.url, + requestModel.enabledRequestParams, + ); + Uri? uri = rec.$1; + if (uri != null) { + jj.Template kNodejsImportTemplate = jj.Template(kStringImports); + String importsData = kNodejsImportTemplate.render(); + result += importsData; + + result += kStringInit; + + jj.Template templateInitClient = jj.Template(kInitClientTemplate); + String initClient = templateInitClient + .render({"baseUrl": "${uri.scheme}://${uri.authority}"}); + result += initClient; + + jj.Template templateMethodType = jj.Template(kMethodTypeTemplate); + String methodType = templateMethodType.render({ + "path": uri.path, + "method": requestModel.method.name.capitalize(), + }); + result += methodType; + + if (uri.hasQuery) { + var params = uri.queryParameters; + if (params.isNotEmpty) { + jj.Template templateParams = jj.Template(kTemplateParams); + String paramsResult = ""; + for (var item in params.entries) { + paramsResult += templateParams + .render({"param": item.key, "value": item.value}); + } + result += "$paramsResult\n"; + } + } + + var headersList = requestModel.enabledRequestHeaders; + if (headersList != null || + requestModel.hasJsonData || + requestModel.hasTextData) { + var headers = requestModel.enabledHeadersMap; + if (requestModel.hasJsonData || requestModel.hasTextData) { + headers[kHeaderContentType] = + requestModel.requestBodyContentType.header; + } + if (headers.isNotEmpty) { + jj.Template templateHeaders = jj.Template(kTemplateHeaders); + String headersResult = ""; + for (var item in headers.entries) { + headersResult += templateHeaders + .render({"header": item.key, "value": item.value}); + } + result += "$headersResult\n"; + } + } + + if (requestModel.hasFormData) { + jj.Template templateFormData = jj.Template(kTemplateFormData); + String formDataResult = ""; + for (var data in requestModel.formDataMapList) { + formDataResult += templateFormData.render({ + "name": data["name"], + "value": data["value"], + "type": data["type"] + }); + } + result += kStringFormDataOption; + if (requestModel.hasFileInFormData) { + result += kStringFormdataFileOption; + } + result += "$formDataResult\n"; + } + + if (requestModel.hasJsonData) { + var templateJsonData = jj.Template(kTemplateJsonData); + Map bodyData = + json.decode(requestModel.requestBody!); + List jsonArr = []; + + bodyData.forEach((key, value) { + jsonArr += ["$key = \"$value\""]; + }); + String jsonDataResult = "{\n${jsonArr.join(",\n")}\n}"; + + result += templateJsonData.render({"jsonData": jsonDataResult}); + } + + if (requestModel.hasTextData) { + jj.Template templateTextData = jj.Template(kTemplateTextData); + result += templateTextData + .render({"textData": jsonEncode(requestModel.requestBody)}); + } + + result += kStringEnd; + } + return result; + } catch (e) { + return null; + } + } +} diff --git a/lib/codegen/java/async_http_client.dart b/lib/codegen/java/async_http_client.dart index ec804cc1..86fdf553 100644 --- a/lib/codegen/java/async_http_client.dart +++ b/lib/codegen/java/async_http_client.dart @@ -148,9 +148,9 @@ public class Main { // especially sets up Content-Type header if the request has a body // and Content-Type is not explicitely set by the developer if (hasBody && - !requestModel.enabledHeadersMap.containsKey('Content-Type')) { + !requestModel.enabledHeadersMap.containsKey(kHeaderContentType)) { result += templateRequestHeader - .render({"name": 'Content-Type', "value": contentType}); + .render({"name": kHeaderContentType, "value": contentType}); } // setting up rest of the request headers diff --git a/lib/codegen/java/httpclient.dart b/lib/codegen/java/httpclient.dart index 037a9a87..01d45b05 100644 --- a/lib/codegen/java/httpclient.dart +++ b/lib/codegen/java/httpclient.dart @@ -1,183 +1,197 @@ -import 'dart:convert'; import 'package:jinja/jinja.dart' as jj; import 'package:apidash/utils/utils.dart' - show getValidRequestUri, requestModelToHARJsonRequest, stripUriParams; -import '../../models/request_model.dart'; + show getValidRequestUri, requestModelToHARJsonRequest; +import 'package:apidash/models/models.dart' show RequestModel; import 'package:apidash/consts.dart'; class JavaHttpClientCodeGen { - final String kTemplateStart = """ -import java.io.IOException; -import java.net.URI; -import java.net.URISyntaxException; + final String kTemplateStart = """import java.net.URI; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; -import java.net.http.HttpHeaders; -import java.net.http.HttpRequest.BodyPublishers; -import java.net.http.HttpResponse.BodyHandlers; +import java.io.IOException; +{% if hasFormData %}import java.util.HashMap; +import java.util.Map; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList;{% endif %} -public class JavaHttpClientExample { +public class Main { + public static void main(String[] args) { + try { + HttpClient client = HttpClient.newHttpClient(); - public static void main(String[] args) throws IOException, InterruptedException { - HttpClient client = HttpClient.newHttpClient(); -"""; - final String kTemplateUrl = ''' - - String url = "{{url}}"; - -'''; - - final String kTemplateUrlQuery = ''' - - String url = "{{url}}"; - try { - URI uri = new URI(url); - url = uri.resolve("{{params}}").toString(); - } catch (URISyntaxException e) { - e.printStackTrace(); - } - -'''; - - String kTemplateRequestBody = ''' - - String body = "{{body}}"; - -'''; - - final String kStringRequestStart = """ - - HttpRequest request = HttpRequest.newBuilder() - .uri(URI.create(url)) """; - final String kTemplateRequestEnd = """ - .{{method}}({{body}}) - .build(); + String kTemplateUrl = """ + URI uri = URI.create("{{url}}"); - HttpResponse response = client.send(request, BodyHandlers.ofString()); - System.out.println(response.statusCode()); - System.out.println(response.body()); +"""; + + String kTemplateFormHeaderContentType = ''' +multipart/form-data; boundary={{boundary}}'''; + + String kTemplateMethod = """ +{% if method == 'get' %} + HttpRequest.Builder requestBuilder = HttpRequest.newBuilder(uri).GET(); +{% elif method == 'post' %} + HttpRequest.Builder requestBuilder = HttpRequest.newBuilder(uri).POST({% if hasBody %}bodyPublisher{% else %}HttpRequest.BodyPublishers.noBody(){% endif %}); +{% elif method == 'put' %} + HttpRequest.Builder requestBuilder = HttpRequest.newBuilder(uri).PUT({% if hasBody %}bodyPublisher{% else %}HttpRequest.BodyPublishers.noBody(){% endif %}); +{% elif method == 'delete' %} + HttpRequest.Builder requestBuilder = HttpRequest.newBuilder(uri).method("DELETE", {% if hasBody %}bodyPublisher{% else %}HttpRequest.BodyPublishers.noBody(){% endif %}); +{% elif method == 'patch' %} + HttpRequest.Builder requestBuilder = HttpRequest.newBuilder(uri).method("PATCH", {% if hasBody %}bodyPublisher{% else %}HttpRequest.BodyPublishers.noBody(){% endif %}); +{% elif method == 'head' %} + HttpRequest.Builder requestBuilder = HttpRequest.newBuilder(uri).method("HEAD", HttpRequest.BodyPublishers.noBody()); +{% endif %} +"""; + + String kTemplateRawBody = """ + HttpRequest.BodyPublisher bodyPublisher = HttpRequest.BodyPublishers.ofString(\"\"\" + {{body}}\"\"\"); +"""; + + String kTemplateJsonBody = """ + HttpRequest.BodyPublisher bodyPublisher = HttpRequest.BodyPublishers.ofString(\"\"\" +{{body}}\"\"\"); +"""; + + String kTemplateFormData = """ + String boundary = "{{boundary}}"; + Map data = new HashMap<>(); + {% for field in fields %} + {% if field.type == "file" %}data.put("{{field.name}}", Paths.get("{{field.value}}"));{% else %}data.put("{{field.name}}", "{{field.value}}");{% endif %}{% endfor %} + HttpRequest.BodyPublisher bodyPublisher = buildMultipartFormData(data, boundary); +"""; + + String kTemplateHeader = """ + requestBuilder = requestBuilder.headers({% for header, value in headers %} + "{{header}}", "{{value}}"{% if not loop.last %},{% endif %}{% endfor %} + ); + +"""; + + final String kTemplateEnd = """ + HttpResponse response = client.send(requestBuilder.build(), HttpResponse.BodyHandlers.ofString()); + System.out.println("Response body: " + response.body()); + System.out.println("Response code: " + response.statusCode()); + } catch (IOException | InterruptedException e) { + System.out.println("An error occurred: " + e.getMessage()); } + } + {% if hasFormData %} + private static HttpRequest.BodyPublisher buildMultipartFormData(Map data, String boundary) throws IOException { + var byteArrays = new ArrayList(); + var CRLF = "\\r\\n".getBytes(StandardCharsets.UTF_8); + + for (Map.Entry entry : data.entrySet()) { + byteArrays.add(("--" + boundary + "\\r\\n").getBytes(StandardCharsets.UTF_8)); + if (entry.getValue() instanceof Path) { + var file = (Path) entry.getValue(); + var fileName = file.getFileName().toString(); + byteArrays.add(("Content-Disposition: form-data; name=\\"" + entry.getKey() + "\\"; filename=\\"" + fileName + "\\"\\r\\n").getBytes(StandardCharsets.UTF_8)); + byteArrays.add(("Content-Type: " + Files.probeContentType(file) + "\\r\\n\\r\\n").getBytes(StandardCharsets.UTF_8)); + byteArrays.add(Files.readAllBytes(file)); + byteArrays.add(CRLF); + } else { + byteArrays.add(("Content-Disposition: form-data; name=\\"" + entry.getKey() + "\\"\\r\\n\\r\\n").getBytes(StandardCharsets.UTF_8)); + byteArrays.add(entry.getValue().toString().getBytes(StandardCharsets.UTF_8)); + byteArrays.add(CRLF); + } + } + byteArrays.add(("--" + boundary + "--\\r\\n").getBytes(StandardCharsets.UTF_8)); + + return HttpRequest.BodyPublishers.ofByteArrays(byteArrays); + }{% endif %} } -\n """; String? getCode( - RequestModel requestModel, - ) { + RequestModel requestModel, { + String? boundary, + }) { try { String result = ""; - bool hasQuery = false; - bool hasBody = false; - bool hasJsonBody = false; + var requestBody = requestModel.requestBody; + String url = requestModel.url; + + result += jj.Template(kTemplateStart).render({ + "hasFormData": requestModel.hasFormData, + }); var rec = getValidRequestUri( - requestModel.url, + url, requestModel.enabledRequestParams, ); + Uri? uri = rec.$1; + var harJson = + requestModelToHARJsonRequest(requestModel, useEnabled: true); + if (uri != null) { - String url = stripUriParams(uri); + var templateUrl = jj.Template(kTemplateUrl); + result += templateUrl.render({"url": harJson["url"]}); - if (uri.hasQuery) { - var params = uri.queryParameters; - if (params.isNotEmpty) { - hasQuery = true; - var templateParams = jj.Template(kTemplateUrlQuery); - result += templateParams.render({"url": url, "params": uri.query}); - } + String? bodyPublisher = ""; + if (requestModel.hasTextData) { + var templateBody = jj.Template(kTemplateRawBody); + bodyPublisher = templateBody.render({"body": requestBody}); + } else if (requestModel.hasJsonData) { + var templateBody = jj.Template(kTemplateJsonBody); + bodyPublisher = templateBody.render({"body": requestBody}); + } else if (requestModel.hasFormData) { + var templateFormData = jj.Template(kTemplateFormData); + bodyPublisher = templateFormData.render({ + "fields": requestModel.formDataMapList, + "boundary": boundary, + }); } - if (!hasQuery) { - var templateUrl = jj.Template(kTemplateUrl); - result += templateUrl.render({"url": url}); - } - var rM = requestModel.copyWith(url: url); + result += bodyPublisher; - var harJson = requestModelToHARJsonRequest(rM, useEnabled: true); - - var method = requestModel.method; - var requestBody = requestModel.requestBody; - if (requestModel.hasFormData && - requestModel.formDataMapList.isNotEmpty && - kMethodsWithBody.contains(method)) { - var formDataList = requestModel.formDataMapList; - result += """ - StringBuilder formData = new StringBuilder(); - formData.append("""; - - for (var formDataMap in formDataList) { - result += '"""${formDataMap['name']}=${formDataMap['value']}&""",'; - } - - result = result.substring(0, result.length - 1); - result += ");\n"; - hasBody = true; - } else if (kMethodsWithBody.contains(method) && requestBody != null) { - var contentLength = utf8.encode(requestBody).length; - if (contentLength > 0) { - var templateBody = jj.Template(kTemplateRequestBody); - hasBody = true; - hasJsonBody = - requestBody.startsWith("{") && requestBody.endsWith("}"); - if (harJson["postData"]?["text"] != null) { - result += templateBody.render({ - "body": kEncoder.convert(harJson["postData"]["text"]).substring( - 1, kEncoder.convert(harJson["postData"]["text"]).length - 1) - }); - } - } - } - - result = kTemplateStart + result; - result += kStringRequestStart; + var methodTemplate = jj.Template(kTemplateMethod); + result += methodTemplate.render({ + "method": requestModel.method.name, + "hasBody": requestModel.hasBody, + }); var headersList = requestModel.enabledRequestHeaders; - var contentType = requestModel.requestBodyContentType.header; - if (hasBody && - !requestModel.enabledHeadersMap.containsKey('Content-Type')) { - result = - """$result .header("Content-Type", "$contentType")\n"""; - } - if (headersList != null) { + if (headersList != null || requestModel.hasBody) { var headers = requestModel.enabledHeadersMap; + if (requestModel.hasJsonData || requestModel.hasTextData) { + headers.putIfAbsent(kHeaderContentType, + () => requestModel.requestBodyContentType.header); + } + if (requestModel.hasFormData) { + var formDataHeader = jj.Template(kTemplateFormHeaderContentType); + headers.putIfAbsent( + kHeaderContentType, + () => formDataHeader.render({ + "boundary": boundary, + })); + } if (headers.isNotEmpty) { - result += getHeaders(headers, hasJsonBody); + var templateHeader = jj.Template(kTemplateHeader); + result += templateHeader.render({ + "headers": headers, + }); } } - var templateRequestEnd = jj.Template(kTemplateRequestEnd); - - if (kMethodsWithBody.contains(method)) { - result += templateRequestEnd.render({ - "method": method.name.toUpperCase(), - "body": hasBody - ? "BodyPublishers.ofString(body)" - : "BodyPublishers.noBody()" - }); - } else { - result += templateRequestEnd - .render({"method": method.name.toUpperCase(), "body": ""}); - } + var templateEnd = jj.Template(kTemplateEnd); + result += templateEnd.render({ + "hasFormData": requestModel.hasFormData, + "boundary": boundary, + }); } - return result; + + return result.replaceAll(RegExp('\\n\\n+'), '\n\n'); } catch (e) { return null; } } - - String getHeaders(Map headers, hasJsonBody) { - String result = ""; - for (final k in headers.keys) { - if (k.toLowerCase() == 'authorization') { - result = """$result .header("$k", "${headers[k]}")\n"""; - } else { - result = """$result .header("$k", "${headers[k]}")\n"""; - } - } - return result; - } } diff --git a/lib/codegen/js/axios.dart b/lib/codegen/js/axios.dart index 301ecf46..00d4d1a9 100644 --- a/lib/codegen/js/axios.dart +++ b/lib/codegen/js/axios.dart @@ -90,7 +90,7 @@ axios(config) m[i["name"]] = i["value"]; } if (requestModel.hasFormData) { - m[kHeaderContentType] = 'multipart/form-data'; + m[kHeaderContentType] = ContentType.formdata.header; } result += templateHeader .render({"headers": padMultilineString(kEncoder.convert(m), 2)}); diff --git a/lib/codegen/js/fetch.dart b/lib/codegen/js/fetch.dart index 9b5f8161..cd6732a6 100644 --- a/lib/codegen/js/fetch.dart +++ b/lib/codegen/js/fetch.dart @@ -99,7 +99,7 @@ fetch(url, options) var m = {}; for (var i in headers) { // fetch can automatically add the Content-Type header when FormData is passed as body - if (i["name"] == "Content-Type" && requestModel.hasFormData) { + if (i["name"] == kHeaderContentType && requestModel.hasFormData) { continue; } m[i["name"]] = i["value"]; diff --git a/lib/codegen/julia/http.dart b/lib/codegen/julia/http.dart index b1d1e96b..56ab744e 100644 --- a/lib/codegen/julia/http.dart +++ b/lib/codegen/julia/http.dart @@ -1,98 +1,73 @@ import 'dart:io'; -import 'dart:convert'; import 'package:jinja/jinja.dart' as jj; -import 'package:apidash/consts.dart'; import 'package:apidash/utils/utils.dart' - show getNewUuid, getValidRequestUri, padMultilineString, stripUriParams; + show getValidRequestUri, stripUriParams; import 'package:apidash/models/models.dart' show RequestModel; class JuliaHttpClientCodeGen { - final String kTemplateStart = """using HTTP,JSON + final String kTemplateStart = """ +using HTTP{% if hasJson %}, JSON{% endif %} +\n +"""; + final String kTemplateUrl = """ url = "{{url}}" - +\n """; String kTemplateParams = """ -{% set new_params = params | replace(":", "=>") | replace("{", "(") | replace("}", ")") %} - -params = Dict{{new_params}} -"""; - - int kParamsPadding = 9; - - String kTemplateBody = ''' -{% set new_params = body | replace(":", "=>") | replace("{", "(") | replace("}", ")") %} - -payload = Dict{{new_params}} -'''; - - String kTemplateJson = """ -{% set new_params = body | replace(":", "=>") | replace("{", "(") | replace("}", ")") %} - -payload = Dict{{new_params}} +params = Dict( +{%- for name, value in params %} + "{{ name }}" => "{{ value }}", +{%- endfor %} +) +\n """; String kTemplateHeaders = """ -{% set new_params = headers | replace(":", "=>") | replace("{", "(") | replace("}", ")") %} - -headers = Dict{{new_params}} +headers = Dict( +{%- for name, value in headers %} + "{{ name }}" => "{{ value }}", +{%- endfor %} +) +\n """; - String kTemplateFormHeaderContentType = ''' -multipart/form-data; boundary={{boundary}}'''; + final String kTemplateFormDataBody = ''' +data = Dict( +{%- for data in formdata %} +{%- if data.type == "text" %} + "{{ data.name }}" => "{{ data.value }}", +{%- else %} + "{{ data.name }}" => open("{{ data.value }}"), +{%- endif %} +{%- endfor %} +) - int kHeadersPadding = 10; +payload = HTTP.Form(data) +\n +'''; + + String kTemplateBody = ''' +payload = """{{ body }}""" +\n +'''; String kTemplateRequest = """ - - -response = HTTP.{{method}}(url +response = HTTP.request("{{ method | upper }}", url """; - final String kStringFormDataBody = r''' -function build_data_list(fields) - dataList = [] - for field in fields - name = field["name"] - value = field["value"] - type_ = get(field, "type", "text") - - push!(dataList, b"--{{boundary}}") - if type_ == "text" - push!(dataList, b"Content-Disposition: form-data; name=\"$name\"") - push!(dataList, b"Content-Type: text/plain") - push!(dataList, b"") - push!(dataList, codeunits(value)) - elseif type_ == "file" - push!(dataList, b"Content-Disposition: form-data; name=\"$name\"; filename=\"$value\"") - push!(dataList, b"Content-Type: $value") - push!(dataList, b"") - push!(dataList, String(read(value))) - end - end - push!(dataList, "--{{boundary}}--") - push!(dataList, b"") - return dataList -end - -dataList = build_data_list({{fields_list}}) -payload = join(dataList, b"\r\n") -'''; - String kStringRequestParams = """, query=params"""; - String kStringRequestBody = """, payload=payload"""; - - String kStringRequestJson = """, JSON.json(payload)"""; + String kStringRequestBody = """, body=payload"""; String kStringRequestHeaders = """, headers=headers"""; - final String kStringRequestEnd = """ -) + final String kStringRequestEnd = r""" +, status_exception=false) -println("Status Code:", response.status) -println("Response Body:", String(response.body)) +println("Status Code: $(response.status) $(HTTP.StatusCodes.statustext(response.status))") +println("Response Body: \n$(String(response.body))") """; String? getCode(RequestModel requestModel) { @@ -100,9 +75,7 @@ println("Response Body:", String(response.body)) String result = ""; bool hasQuery = false; bool hasHeaders = false; - bool hasBody = false; - bool hasJsonBody = false; - String uuid = getNewUuid(); + bool addHeaderForBody = false; var rec = getValidRequestUri( requestModel.url, @@ -110,86 +83,80 @@ println("Response Body:", String(response.body)) ); Uri? uri = rec.$1; if (uri != null) { - var templateStartUrl = jj.Template(kTemplateStart); - result += templateStartUrl.render({ - "url": stripUriParams(uri), + final templateStart = jj.Template(kTemplateStart); + result += templateStart.render({ + // "hasJson": requestModel.hasBody && requestModel.hasJsonContentType && requestModel.hasJsonData, + "hasJson": + false, // we manually send false because we do not require JSON package }); + final templateUrl = jj.Template(kTemplateUrl); + result += templateUrl.render({"url": stripUriParams(uri)}); + if (uri.hasQuery) { var params = uri.queryParameters; if (params.isNotEmpty) { hasQuery = true; - var templateParams = jj.Template(kTemplateParams); - var paramsString = kEncoder.convert(params); - paramsString = padMultilineString(paramsString, kParamsPadding); - result += templateParams.render({"params": paramsString}); + final templateParams = jj.Template(kTemplateParams); + result += templateParams.render({"params": params}); } } - if (requestModel.hasJsonData) { - hasJsonBody = true; - var templateBody = jj.Template(kTemplateJson); - result += templateBody.render({"body": requestModel.requestBody}); - } else if (requestModel.hasTextData) { - hasBody = true; - var templateBody = jj.Template(kTemplateBody); - result += templateBody.render({"body": requestModel.requestBody}); + if (requestModel.hasJsonData || requestModel.hasTextData) { + addHeaderForBody = true; + final templateBody = jj.Template(kTemplateBody); + var bodyStr = requestModel.requestBody; + result += templateBody.render({"body": bodyStr}); } - var headersList = requestModel.enabledRequestHeaders; - if (headersList != null || hasBody) { - var headers = requestModel.enabledHeadersMap; - if (requestModel.hasFormData) { - var formHeaderTemplate = - jj.Template(kTemplateFormHeaderContentType); - headers[HttpHeaders.contentTypeHeader] = formHeaderTemplate.render({ - "boundary": uuid, - }); - } - if (headers.isNotEmpty || hasBody) { - hasHeaders = true; - if (hasBody) { - headers[HttpHeaders.contentTypeHeader] = - requestModel.requestBodyContentType.header; - } - var headersString = kEncoder.convert(headers); - headersString = padMultilineString(headersString, kHeadersPadding); - var templateHeaders = jj.Template(kTemplateHeaders); - result += templateHeaders.render({"headers": headersString}); - } - } if (requestModel.hasFormData) { - var formDataBodyData = jj.Template(kStringFormDataBody); + final formDataBodyData = jj.Template(kTemplateFormDataBody); result += formDataBodyData.render( { - "fields_list": json.encode(requestModel.formDataMapList), - "boundary": uuid, + "hasFile": requestModel.hasFileInFormData, + "formdata": requestModel.formDataMapList, }, ); } + + var headersList = requestModel.enabledRequestHeaders; + if (headersList != null || addHeaderForBody) { + var headers = requestModel.enabledHeadersMap; + + if (!requestModel.hasContentTypeHeader) { + if (addHeaderForBody) { + headers[HttpHeaders.contentTypeHeader] = + requestModel.requestBodyContentType.header; + } + } + + if (headers.isNotEmpty) { + hasHeaders = true; + var templateHeaders = jj.Template(kTemplateHeaders); + result += templateHeaders.render({"headers": headers}); + } + } + var templateRequest = jj.Template(kTemplateRequest); result += templateRequest.render({ - "method": requestModel.method.name.toLowerCase(), + "method": requestModel.method.name, }); + if (hasHeaders) { + result += kStringRequestHeaders; + } + + if (requestModel.hasBody) { + result += kStringRequestBody; + } + if (hasQuery) { result += kStringRequestParams; } - if (hasBody || requestModel.hasFormData) { - result += kStringRequestBody; - } - - if (hasJsonBody || requestModel.hasFormData) { - result += kStringRequestJson; - } - - if (hasHeaders || requestModel.hasFormData) { - result += kStringRequestHeaders; - } - result += kStringRequestEnd; } + return result; } catch (e) { return null; diff --git a/lib/codegen/php/curl.dart b/lib/codegen/php/curl.dart new file mode 100644 index 00000000..974159ee --- /dev/null +++ b/lib/codegen/php/curl.dart @@ -0,0 +1,171 @@ +import 'package:jinja/jinja.dart' as jj; +import 'package:apidash/utils/utils.dart' + show getValidRequestUri, stripUriParams; +import 'package:apidash/models/models.dart' show RequestModel; +import 'package:apidash/consts.dart'; + +class PHPcURLCodeGen { + final String kTemplateStart = r''' + '{{ data.value }}', +{%- elif data.type == 'file' %} + '{{ data.name }}' => new CURLFILE('{{ data.value }}'), +{%- endif %} +{%- endfor %} +]; +{%- else -%} +$request_body = '{{body}}'; +{%- endif %} + + +'''; + + //defining query parameters + String kTemplateParams = r''' +$queryParams = [ +{%- for name, value in params %} + '{{ name }}' => '{{ value }}', +{%- endfor %} +]; +$uri .= '?' . http_build_query($queryParams); + + +'''; + + //specifying headers + String kTemplateHeaders = r''' +$headers = [ +{%- for name, value in headers %} + '{{ name }}: {{ value }}', +{%- endfor %} +]; + + +'''; + + //initialising the request + String kStringRequestInit = r''' +$request = curl_init($uri); + +'''; + + String kTemplateRequestOptsInit = r''' +curl_setopt_array($request, [ + CURLOPT_RETURNTRANSFER => 1, + CURLOPT_CUSTOMREQUEST => '{{ method|upper }}', + +'''; + String kStringHeaderOpt = r''' + CURLOPT_HTTPHEADER => $headers, +'''; + //passing the request body + String kStringRequestBodyOpt = r''' + CURLOPT_POSTFIELDS => $request_body, +'''; + + //ending template + final String kStringRequestEnd = r''' + CURLOPT_FOLLOWLOCATION => true, +]); + +$response = curl_exec($request); + +curl_close($request); + +$httpCode = curl_getinfo($request, CURLINFO_HTTP_CODE); +echo "Status Code: " . $httpCode . "\n"; +echo $response . "\n"; +'''; + + String? getCode(RequestModel requestModel) { + try { + String result = ""; + bool hasBody = false; + + var rec = getValidRequestUri( + requestModel.url, + requestModel.enabledRequestParams, + ); + + Uri? uri = rec.$1; + + //renders starting template + if (uri != null) { + var templateStart = jj.Template(kTemplateStart); + result += templateStart.render(); + + var templateUri = jj.Template(kTemplateUri); + result += templateUri.render({'uri': stripUriParams(uri)}); + + //renders the request body contains the HTTP method associated with the request + if (requestModel.hasBody) { + hasBody = true; + // contains the entire request body as a string if body is present + var templateBody = jj.Template(kTemplateBody); + result += templateBody.render({ + 'body': requestModel.hasFormData + ? requestModel.formDataMapList + : requestModel.requestBody, + }); + } + + //checking and adding query params + if (uri.hasQuery) { + if (requestModel.enabledParamsMap.isNotEmpty) { + var templateParams = jj.Template(kTemplateParams); + result += templateParams + .render({"params": requestModel.enabledParamsMap}); + } + } + + var headers = requestModel.enabledHeadersMap; + if (requestModel.hasBody && !requestModel.hasContentTypeHeader) { + if (requestModel.hasJsonData || requestModel.hasTextData) { + headers[kHeaderContentType] = + requestModel.requestBodyContentType.header; + } + } + + if (headers.isNotEmpty) { + var templateHeader = jj.Template(kTemplateHeaders); + result += templateHeader.render({'headers': headers}); + } + + // renders the initial request init function call + result += kStringRequestInit; + + //renders the request temlate + var templateRequestOptsInit = jj.Template(kTemplateRequestOptsInit); + result += templateRequestOptsInit + .render({'method': requestModel.method.name}); + if (headers.isNotEmpty) { + result += kStringHeaderOpt; + } + if (hasBody || requestModel.hasFormData) { + result += kStringRequestBodyOpt; + } + + //and of the request + result += kStringRequestEnd; + } + return result; + } catch (e) { + return null; + } + } +} diff --git a/lib/codegen/php/guzzle.dart b/lib/codegen/php/guzzle.dart index c0e5562e..c7d498da 100644 --- a/lib/codegen/php/guzzle.dart +++ b/lib/codegen/php/guzzle.dart @@ -107,7 +107,7 @@ echo \$res->getBody(); headersString += "\t\t\t\t'$key' => '$value', \n"; }); if (requestModel.hasFormData) { - m['Content-Type'] = 'multipart/form-data'; + m[kHeaderContentType] = ContentType.formdata.header; } headersString = headersString.substring( 0, headersString.length - 2); // Removing trailing comma and space diff --git a/lib/codegen/ruby/faraday.dart b/lib/codegen/ruby/faraday.dart new file mode 100644 index 00000000..da552479 --- /dev/null +++ b/lib/codegen/ruby/faraday.dart @@ -0,0 +1,182 @@ +import 'package:apidash/consts.dart'; +import 'package:jinja/jinja.dart' as jj; +import 'package:apidash/utils/utils.dart' show getValidRequestUri; +import 'package:apidash/utils/http_utils.dart' show stripUriParams; + +import 'package:apidash/models/models.dart' show RequestModel; + +// Note that delete is a special case in Faraday as API Dash supports request +// body inside delete reqest, but Faraday does not. Hence we need to manually +// setup request body for delete request and add that to request. +// +// Refer https://lostisland.github.io/faraday/#/getting-started/quick-start?id=get-head-delete-trace +class RubyFaradayCodeGen { + final String kStringFaradayRequireStatement = """ +require 'uri' +require 'faraday' +"""; + + final String kStringFaradayMultipartRequireStatement = ''' +require 'faraday/multipart' +'''; + + final String kTemplateRequestUrl = """ + +REQUEST_URL = URI("{{ url }}") + + +"""; + + final String kTemplateBody = """ +PAYLOAD = < Faraday::Multipart::ParamPart.new("{{ param.value }}", "text/plain"), +{% elif param.type == "file" %} "{{ param.name }}" => Faraday::Multipart::FilePart.new("{{ param.value }}", "application/octet-stream"),{% endif %}{% endfor %} +} + + +"""; + + final String kTemplateFormParamsWithoutFile = """ +PAYLOAD = URI.encode_www_form({\n{% for param in params %} "{{ param.name }}" => "{{ param.value }}",\n{% endfor %}})\n\n +"""; + + final String kTemplateConnection = """ +conn = Faraday.new do |faraday| + faraday.adapter Faraday.default_adapter{% if hasFile %}\n faraday.request :multipart{% endif %} +end + + +"""; + + final String kTemplateRequestStart = """ +response = conn.{{ method|lower }}(REQUEST_URL{% if doesMethodAcceptBody and containsBody %}, PAYLOAD{% endif %}) do |req| + +"""; + + final String kTemplateRequestParams = """ + req.params = { +{% for key, val in params %} "{{ key }}" => "{{ val }}",\n{% endfor %} } + +"""; + + final String kTemplateRequestHeaders = """ + req.headers = { +{% for key, val in headers %} "{{ key }}" => "{{ val }}",\n{% endfor %} } + +"""; + + final String kStringDeleteRequestBody = """ + req.body = PAYLOAD +"""; + + final String kStringRequestEnd = """ +end + +"""; + + final String kStringResponse = """ +puts "Status Code: #{response.status}" +puts "Response Body: #{response.body}" +"""; + + String? getCode( + RequestModel requestModel, + ) { + try { + String result = ""; + + var rec = getValidRequestUri( + requestModel.url, + requestModel.enabledRequestParams, + ); + + Uri? uri = rec.$1; + + if (uri == null) { + return ""; + } + + var url = stripUriParams(uri); + + result += kStringFaradayRequireStatement; + if (requestModel.hasFormDataContentType && + requestModel.hasFileInFormData) { + result += kStringFaradayMultipartRequireStatement; + } + + var templateRequestUrl = jj.Template(kTemplateRequestUrl); + result += templateRequestUrl.render({"url": url}); + + if (requestModel.hasFormData) { + jj.Template payload; + if (requestModel.hasFileInFormData) { + payload = jj.Template(kTemplateFormParamsWithFile); + } else { + payload = jj.Template(kTemplateFormParamsWithoutFile); + } + result += payload.render({"params": requestModel.formDataMapList}); + } else if (requestModel.hasJsonData || requestModel.hasTextData) { + var templateBody = jj.Template(kTemplateBody); + result += templateBody.render({ + "body": requestModel.requestBody, + }); + } + + // creating faraday connection for request + var templateConnection = jj.Template(kTemplateConnection); + result += templateConnection.render({ + "hasFile": requestModel.hasFormDataContentType && + requestModel.hasFileInFormData + }); + + // start of the request sending + var templateRequestStart = jj.Template(kTemplateRequestStart); + result += templateRequestStart.render({ + "method": requestModel.method.name, + "doesMethodAcceptBody": + kMethodsWithBody.contains(requestModel.method) && + requestModel.method != HTTPVerb.delete, + "containsBody": requestModel.hasBody, + }); + + var headers = requestModel.enabledHeadersMap; + if (requestModel.hasBody && !requestModel.hasContentTypeHeader) { + if (requestModel.hasJsonData || requestModel.hasTextData) { + headers[kHeaderContentType] = + requestModel.requestBodyContentType.header; + } + } + + if (headers.isNotEmpty) { + var templateRequestHeaders = jj.Template(kTemplateRequestHeaders); + result += templateRequestHeaders.render({"headers": headers}); + } + + if (uri.hasQuery) { + var params = uri.queryParameters; + if (params.isNotEmpty) { + var templateRequestParams = jj.Template(kTemplateRequestParams); + result += templateRequestParams.render({"params": params}); + } + } + + if (requestModel.hasBody && requestModel.method == HTTPVerb.delete) { + result += kStringDeleteRequestBody; + } + + result += kStringRequestEnd; + result += kStringResponse; + return result; + } catch (e) { + return null; + } + } +} diff --git a/lib/codegen/ruby/net_http.dart b/lib/codegen/ruby/net_http.dart new file mode 100644 index 00000000..b64e5196 --- /dev/null +++ b/lib/codegen/ruby/net_http.dart @@ -0,0 +1,117 @@ +import 'package:jinja/jinja.dart' as jj; +import 'package:apidash/utils/utils.dart' + show getValidRequestUri, stripUriParams; +import 'package:apidash/models/models.dart' show RequestModel; +import '../../extensions/extensions.dart'; +import 'package:apidash/consts.dart'; + +class RubyNetHttpCodeGen { + String kTemplateStart = """require "uri" +require "net/http" + +url = URI("{{url}}") +https = Net::HTTP.new(url.host, url.port) +{% if check == "https" %}https.use_ssl = true{% endif %} +request = Net::HTTP::{{method}}.new(url) +"""; + + String kTemplateHeader = """ +{% for key, value in headers %} +request["{{key}}"] = "{{value}}"{% endfor %} +"""; + + String kTemplateBody = """ + +request.body = < requestModel.requestBodyContentType.header); + } + if (headers.isNotEmpty) { + var templateHeader = jj.Template(kTemplateHeader); + result += templateHeader.render({ + "headers": headers, + }); + } + } + + result += kTemplateEnd; + } + + return result; + } catch (e) { + return null; + } + } +} diff --git a/lib/consts.dart b/lib/consts.dart index 06ee28c3..e2de6b47 100644 --- a/lib/consts.dart +++ b/lib/consts.dart @@ -3,7 +3,6 @@ import 'dart:convert'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:google_fonts/google_fonts.dart'; -import 'package:davi/davi.dart'; const kDiscordUrl = "https://bit.ly/heyfoss"; const kGitUrl = "https://github.com/foss42/apidash"; @@ -21,7 +20,7 @@ final kIsLinux = !kIsWeb && Platform.isLinux; final kIsApple = !kIsWeb && (Platform.isIOS || Platform.isMacOS); final kIsDesktop = !kIsWeb && (Platform.isMacOS || Platform.isWindows || Platform.isLinux); - +final kIsRunningTests = Platform.environment.containsKey('FLUTTER_TEST'); final kIsIOS = !kIsWeb && Platform.isIOS; final kIsAndroid = !kIsWeb && Platform.isAndroid; final kIsMobile = !kIsWeb && (Platform.isIOS || Platform.isAndroid); @@ -56,6 +55,7 @@ const kForegroundOpacity = 0.05; const kOverlayBackgroundOpacity = 0.5; const kTextStyleButton = TextStyle(fontWeight: FontWeight.bold); +const kTextStyleTab = TextStyle(fontSize: 14); const kTextStyleButtonSmall = TextStyle(fontSize: 12); const kFormDataButtonLabelTextStyle = TextStyle( fontSize: 12, @@ -71,12 +71,18 @@ const kP5 = EdgeInsets.all(5); const kP8 = EdgeInsets.all(8); const kPs8 = EdgeInsets.only(left: 8); const kPs2 = EdgeInsets.only(left: 2); +const kPe8 = EdgeInsets.only(right: 8.0); const kPh20v5 = EdgeInsets.symmetric(horizontal: 20, vertical: 5); const kPh20v10 = EdgeInsets.symmetric(horizontal: 20, vertical: 10); const kP10 = EdgeInsets.all(10); +const kPv8 = EdgeInsets.symmetric(vertical: 8); +const kPv2 = EdgeInsets.symmetric(vertical: 2); +const kPh2 = EdgeInsets.symmetric(horizontal: 2); const kPt24o8 = EdgeInsets.only(top: 24, left: 8.0, right: 8.0, bottom: 8.0); const kPt5o10 = EdgeInsets.only(left: 10.0, right: 10.0, top: 5.0, bottom: 10.0); +const kPh4 = EdgeInsets.symmetric(horizontal: 4); +const kPh8 = EdgeInsets.symmetric(horizontal: 8); const kPh20 = EdgeInsets.symmetric( horizontal: 20, ); @@ -102,8 +108,9 @@ const kP8CollectionPane = EdgeInsets.only( const kPb10 = EdgeInsets.only( bottom: 10, ); -const kPr8CollectionPane = EdgeInsets.only(right: 8.0); -const kpsV5 = EdgeInsets.symmetric(vertical: 2); +const kPb15 = EdgeInsets.only( + bottom: 15, +); const kHSpacer4 = SizedBox(width: 4); const kHSpacer5 = SizedBox(width: 5); const kHSpacer10 = SizedBox(width: 10); @@ -112,28 +119,21 @@ const kVSpacer5 = SizedBox(height: 5); const kVSpacer8 = SizedBox(height: 8); const kVSpacer10 = SizedBox(height: 10); const kVSpacer20 = SizedBox(height: 20); +const kVSpacer40 = SizedBox(height: 40); const kTabAnimationDuration = Duration(milliseconds: 200); -const kTabHeight = 45.0; +const kTabHeight = 32.0; const kHeaderHeight = 32.0; const kSegmentHeight = 24.0; const kTextButtonMinWidth = 44.0; const kRandMax = 100000; -const kTableThemeData = DaviThemeData( - columnDividerThickness: 1, - columnDividerColor: kColorTransparent, - row: RowThemeData( - dividerColor: kColorTransparent, - ), - decoration: BoxDecoration( - border: Border(), - ), - header: HeaderThemeData( - visible: false, - ), +const kDataTableScrollbarTheme = ScrollbarThemeData( + crossAxisMargin: -4, ); +const kDataTableBottomPadding = 12.0; +const kDataTableRowHeight = 36.0; const kIconRemoveDark = Icon( Icons.remove_circle, @@ -272,6 +272,8 @@ const kDefaultContentType = ContentType.json; enum CodegenLanguage { curl("cURL", "bash", "curl"), har("HAR", "json", "har"), + cCurlCodeGen("C (Curl)", "C", "c"), + cSharpRestSharp("C# (Rest Sharp)", "cs", "cs"), dartHttp("Dart (http)", "dart", "dart"), dartDio("Dart (dio)", "dart", "dart"), goHttp("Go (http)", "go", "go"), @@ -282,14 +284,18 @@ enum CodegenLanguage { kotlinOkHttp("Kotlin (okhttp3)", "java", "kt"), pythonRequests("Python (requests)", "python", "py"), pythonHttpClient("Python (http.client)", "python", "py"), + rubyFaraday("Ruby (Faraday)", "ruby", "rb"), + rubyNetHttp("Ruby (Net::Http)", "Ruby", "rb"), rustActix("Rust (Actix Client)", "rust", "rs"), rustReqwest("Rust (reqwest)", "rust", "rs"), + rustCurl("Rust (curl-rust)", "rust", "rs"), rustUreq("Rust (ureq)", "rust", "rs"), javaOkHttp("Java (okhttp3)", "java", 'java'), javaAsyncHttpClient("Java (asynchttpclient)", "java", "java"), javaHttpClient("Java (HttpClient)", "java", "java"), javaUnirest("Java (Unirest)", "java", "java"), juliaHttp("Julia (HTTP)", "julia", "jl"), + phpCurl("PHP (cURL)", "php", "php"), phpGuzzle("PHP (guzzle)", "php", "php"); const CodegenLanguage(this.label, this.codeHighlightLang, this.ext); @@ -398,7 +404,7 @@ const Map>> kSubTypeDefaultViewOptions: kPreviewBodyViewOptions, }, kTypeVideo: { - kSubTypeDefaultViewOptions: kNoBodyViewOptions, + kSubTypeDefaultViewOptions: kPreviewBodyViewOptions, }, kTypeText: { kSubTypeDefaultViewOptions: kRawBodyViewOptions, @@ -507,6 +513,9 @@ const kMimeTypeRaiseIssue = const kUnexpectedRaiseIssue = "\nIf the behaviour is unexpected, please raise an issue in API Dash GitHub repo so that we can resolve it."; +const kVideoError = + "There seems to be an issue playing this video. Please raise an issue in API Dash GitHub repo so that we can resolve it."; + const kImageError = "There seems to be an issue rendering this image. Please raise an issue in API Dash GitHub repo so that we can resolve it."; @@ -535,3 +544,36 @@ const kLabelSave = "Save"; const kLabelDownload = "Download"; const kLabelSaving = "Saving"; const kLabelSaved = "Saved"; +// Request Pane +const kLabelRequest = "Request"; +const kLabelHideCode = "Hide Code"; +const kLabelViewCode = "View Code"; +const kLabelURLParams = "URL Params"; +const kLabelHeaders = "Headers"; +const kLabelBody = "Body"; +const kNameCheckbox = "Checkbox"; +const kNameURLParam = "URL Parameter"; +const kNameHeader = "Header Name"; +const kNameValue = "Value"; +const kNameField = "Field"; +const kHintAddURLParam = "Add URL Parameter"; +const kHintAddValue = "Add Value"; +const kHintAddName = "Add Name"; +const kHintAddFieldName = "Add Field Name"; +const kLabelAddParam = "Add Param"; +const kLabelAddHeader = "Add Header"; +const kLabelSelectFile = "Select File"; +const kLabelAddFormField = "Add Form Field"; +// Response Pane +const kLabelNotSent = "Not Sent"; +const kLabelResponse = "Response"; +const kLabelResponseBody = "Response Body"; +const kTooltipClearResponse = "Clear Response"; +const kHeaderRow = ["Header Name", "Header Value"]; +const kLabelRequestHeaders = "Request Headers"; +const kLabelResponseHeaders = "Response Headers"; +const kLabelItems = "items"; +const kMsgError = "Error: Response data does not exist."; +const kMsgNullBody = "Response body is missing (null)."; +const kMsgNoContent = "No content"; +const kMsgUnknowContentType = "Unknown Response Content-Type"; diff --git a/lib/extensions/extensions.dart b/lib/extensions/extensions.dart new file mode 100644 index 00000000..d8c9fa84 --- /dev/null +++ b/lib/extensions/extensions.dart @@ -0,0 +1 @@ +export 'string_extensions.dart'; diff --git a/lib/extensions/string_extensions.dart b/lib/extensions/string_extensions.dart new file mode 100644 index 00000000..5d929489 --- /dev/null +++ b/lib/extensions/string_extensions.dart @@ -0,0 +1,5 @@ +extension StringExtension on String { + String capitalize() { + return "${this[0].toUpperCase()}${substring(1).toLowerCase()}"; + } +} diff --git a/lib/models/request_model.dart b/lib/models/request_model.dart index 0ea6d735..d8b9d6af 100644 --- a/lib/models/request_model.dart +++ b/lib/models/request_model.dart @@ -31,6 +31,7 @@ class RequestModel { this.message, this.responseModel, this.isWorking = false, + this.sendingTime, }); final String id; @@ -50,6 +51,7 @@ class RequestModel { final String? message; final ResponseModel? responseModel; final bool isWorking; + final DateTime? sendingTime; List? get enabledRequestHeaders => getEnabledRows(requestHeaders, isHeaderEnabledList); @@ -95,6 +97,7 @@ class RequestModel { RequestModel duplicate({ required String id, String? name, + int? requestTabIndex, }) { return RequestModel( id: id, @@ -102,6 +105,7 @@ class RequestModel { url: url, name: name ?? "${this.name} (copy)", description: description, + requestTabIndex: requestTabIndex ?? 0, requestHeaders: requestHeaders != null ? [...requestHeaders!] : null, requestParams: requestParams != null ? [...requestParams!] : null, isHeaderEnabledList: @@ -133,6 +137,7 @@ class RequestModel { String? message, ResponseModel? responseModel, bool? isWorking, + DateTime? sendingTime, }) { var headers = requestHeaders ?? this.requestHeaders; var params = requestParams ?? this.requestParams; @@ -158,6 +163,7 @@ class RequestModel { message: message ?? this.message, responseModel: responseModel ?? this.responseModel, isWorking: isWorking ?? this.isWorking, + sendingTime: sendingTime ?? this.sendingTime, ); } diff --git a/lib/providers/collection_providers.dart b/lib/providers/collection_providers.dart index db6b7cf3..ec4d36f9 100644 --- a/lib/providers/collection_providers.dart +++ b/lib/providers/collection_providers.dart @@ -1,11 +1,12 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'settings_providers.dart'; -import 'ui_providers.dart'; +import 'package:http/http.dart' as http; + +import '../consts.dart'; import '../models/models.dart'; import '../services/services.dart' show hiveHandler, HiveHandler, request; import '../utils/utils.dart' show getNewUuid, collectionToHAR; -import '../consts.dart'; -import 'package:http/http.dart' as http; +import 'settings_providers.dart'; +import 'ui_providers.dart'; final selectedIdStateProvider = StateProvider((ref) => null); @@ -65,6 +66,7 @@ class CollectionStateNotifier .read(requestSequenceProvider.notifier) .update((state) => [id, ...state]); ref.read(selectedIdStateProvider.notifier).state = newRequestModel.id; + ref.read(hasUnsavedChangesProvider.notifier).state = true; } void reorder(int oldIdx, int newIdx) { @@ -72,6 +74,7 @@ class CollectionStateNotifier final itemId = itemIds.removeAt(oldIdx); itemIds.insert(newIdx, itemId); ref.read(requestSequenceProvider.notifier).state = [...itemIds]; + ref.read(hasUnsavedChangesProvider.notifier).state = true; } void remove(String id) { @@ -94,6 +97,7 @@ class CollectionStateNotifier var map = {...state!}; map.remove(id); state = map; + ref.read(hasUnsavedChangesProvider.notifier).state = true; } void clearResponse(String? id) { @@ -102,10 +106,12 @@ class CollectionStateNotifier final newModel = currentModel.duplicate( id: id, name: currentModel.name, + requestTabIndex: currentModel.requestTabIndex, ); var map = {...state!}; map[id] = newModel; state = map; + ref.read(hasUnsavedChangesProvider.notifier).state = true; } void duplicate(String id) { @@ -125,6 +131,7 @@ class CollectionStateNotifier ref.read(requestSequenceProvider.notifier).state = [...itemIds]; ref.read(selectedIdStateProvider.notifier).state = newId; + ref.read(hasUnsavedChangesProvider.notifier).state = true; } void update( @@ -166,6 +173,7 @@ class CollectionStateNotifier var map = {...state!}; map[id] = newModel; state = map; + ref.read(hasUnsavedChangesProvider.notifier).state = true; } Future sendRequest(String id) async { @@ -180,7 +188,10 @@ class CollectionStateNotifier // set current model's isWorking to true and update state var map = {...state!}; - map[id] = requestModel.copyWith(isWorking: true); + map[id] = requestModel.copyWith( + isWorking: true, + sendingTime: DateTime.now(), + ); state = map; (http.Response?, Duration?, String?)? responseRec = await request( @@ -212,6 +223,7 @@ class CollectionStateNotifier map = {...state!}; map[id] = newRequestModel; state = map; + ref.read(hasUnsavedChangesProvider.notifier).state = true; } Future clearData() async { @@ -221,6 +233,7 @@ class CollectionStateNotifier ref.read(clearDataStateProvider.notifier).state = false; ref.read(requestSequenceProvider.notifier).state = []; state = {}; + ref.read(hasUnsavedChangesProvider.notifier).state = true; } bool loadData() { @@ -261,6 +274,7 @@ class CollectionStateNotifier } await hiveHandler.removeUnused(); ref.read(saveDataStateProvider.notifier).state = false; + ref.read(hasUnsavedChangesProvider.notifier).state = false; } Future> exportDataToHAR() async { diff --git a/lib/providers/ui_providers.dart b/lib/providers/ui_providers.dart index 2fddb2ad..e4b10677 100644 --- a/lib/providers/ui_providers.dart +++ b/lib/providers/ui_providers.dart @@ -6,6 +6,8 @@ final selectedIdEditStateProvider = StateProvider((ref) => null); final codePaneVisibleStateProvider = StateProvider((ref) => false); final saveDataStateProvider = StateProvider((ref) => false); final clearDataStateProvider = StateProvider((ref) => false); +final hasUnsavedChangesProvider = StateProvider((ref) => false); + // final nameTextFieldControllerProvider = // StateProvider.autoDispose((ref) { // TextEditingController controller = TextEditingController(text: ""); @@ -23,3 +25,5 @@ final nameTextFieldFocusNodeProvider = }); return focusNode; }); + +final searchQueryProvider = StateProvider((ref) => ''); diff --git a/lib/screens/home_page/collection_pane.dart b/lib/screens/home_page/collection_pane.dart index fd0b518a..934c5b66 100644 --- a/lib/screens/home_page/collection_pane.dart +++ b/lib/screens/home_page/collection_pane.dart @@ -15,6 +15,7 @@ class CollectionPane extends ConsumerWidget { final overlayWidget = OverlayWidgetTemplate(context: context); final collection = ref.watch(collectionStateNotifierProvider); final savingData = ref.watch(saveDataStateProvider); + final hasUnsavedChanges = ref.watch(hasUnsavedChangesProvider); if (collection == null) { return const Center( child: CircularProgressIndicator(), @@ -26,12 +27,12 @@ class CollectionPane extends ConsumerWidget { crossAxisAlignment: CrossAxisAlignment.stretch, children: [ Padding( - padding: kPr8CollectionPane, + padding: kPe8, child: Wrap( alignment: WrapAlignment.spaceBetween, children: [ TextButton.icon( - onPressed: savingData + onPressed: (savingData || !hasUnsavedChanges) ? null : () async { overlayWidget.show( @@ -69,7 +70,39 @@ class CollectionPane extends ConsumerWidget { ], ), ), - kVSpacer8, + kVSpacer10, + Container( + height: 30, + margin: const EdgeInsets.only(right: 8), + decoration: BoxDecoration( + borderRadius: kBorderRadius8, + border: Border.all( + color: Theme.of(context).colorScheme.surfaceVariant, + ), + ), + child: Row( + children: [ + kHSpacer5, + Icon( + Icons.filter_alt, + size: 18, + color: Theme.of(context).colorScheme.secondary, + ), + kHSpacer5, + Expanded( + child: RawTextField( + style: Theme.of(context).textTheme.bodyMedium, + hintText: "Filter by name or URL", + onChanged: (value) { + ref.read(searchQueryProvider.notifier).state = + value.toLowerCase(); + }, + ), + ), + ], + ), + ), + kVSpacer10, const Expanded( child: RequestList(), ), @@ -109,41 +142,61 @@ class _RequestListState extends ConsumerState { final requestItems = ref.watch(collectionStateNotifierProvider)!; final alwaysShowCollectionPaneScrollbar = ref.watch(settingsProvider .select((value) => value.alwaysShowCollectionPaneScrollbar)); + final filterQuery = ref.watch(searchQueryProvider).trim(); return Scrollbar( controller: controller, thumbVisibility: alwaysShowCollectionPaneScrollbar ? true : null, radius: const Radius.circular(12), - child: ReorderableListView.builder( - padding: kPr8CollectionPane, - scrollController: controller, - buildDefaultDragHandles: false, - itemCount: requestSequence.length, - onReorder: (int oldIndex, int newIndex) { - if (oldIndex < newIndex) { - newIndex -= 1; - } - if (oldIndex != newIndex) { - ref - .read(collectionStateNotifierProvider.notifier) - .reorder(oldIndex, newIndex); - } - }, - itemBuilder: (context, index) { - var id = requestSequence[index]; - return ReorderableDragStartListener( - key: ValueKey(id), - index: index, - child: Padding( - padding: kP1, - child: RequestItem( - id: id, - requestModel: requestItems[id]!, - ), + child: filterQuery.isEmpty + ? ReorderableListView.builder( + padding: kPe8, + scrollController: controller, + buildDefaultDragHandles: false, + itemCount: requestSequence.length, + onReorder: (int oldIndex, int newIndex) { + if (oldIndex < newIndex) { + newIndex -= 1; + } + if (oldIndex != newIndex) { + ref + .read(collectionStateNotifierProvider.notifier) + .reorder(oldIndex, newIndex); + } + }, + itemBuilder: (context, index) { + var id = requestSequence[index]; + return ReorderableDragStartListener( + key: ValueKey(id), + index: index, + child: Padding( + padding: kP1, + child: RequestItem( + id: id, + requestModel: requestItems[id]!, + ), + ), + ); + }, + ) + : ListView( + padding: kPe8, + controller: controller, + children: requestSequence.map((id) { + var item = requestItems[id]!; + if (item.url.toLowerCase().contains(filterQuery) || + item.name.toLowerCase().contains(filterQuery)) { + return Padding( + padding: kP1, + child: RequestItem( + id: id, + requestModel: item, + ), + ); + } + return const SizedBox(); + }).toList(), ), - ); - }, - ), ); } } diff --git a/lib/screens/home_page/editor_pane/details_card/request_pane/request_body.dart b/lib/screens/home_page/editor_pane/details_card/request_pane/request_body.dart index f667f6b5..085df3f2 100644 --- a/lib/screens/home_page/editor_pane/details_card/request_pane/request_body.dart +++ b/lib/screens/home_page/editor_pane/details_card/request_pane/request_body.dart @@ -21,7 +21,6 @@ class EditRequestBody extends ConsumerWidget { decoration: BoxDecoration( color: Theme.of(context).colorScheme.background, ), - margin: kPt5o10, child: Column( children: [ const SizedBox( @@ -38,27 +37,34 @@ class EditRequestBody extends ConsumerWidget { ), Expanded( child: switch (contentType) { - ContentType.formdata => const FormDataWidget(), + ContentType.formdata => + const Padding(padding: kPh4, child: FormDataWidget()), // TODO: Fix JsonTextFieldEditor & plug it here - ContentType.json => TextFieldEditor( - key: Key("$selectedId-json-body"), - fieldKey: "$selectedId-json-body-editor", - initialValue: requestModel?.requestBody, - onChanged: (String value) { - ref - .read(collectionStateNotifierProvider.notifier) - .update(selectedId, requestBody: value); - }, + ContentType.json => Padding( + padding: kPt5o10, + child: TextFieldEditor( + key: Key("$selectedId-json-body"), + fieldKey: "$selectedId-json-body-editor", + initialValue: requestModel?.requestBody, + onChanged: (String value) { + ref + .read(collectionStateNotifierProvider.notifier) + .update(selectedId, requestBody: value); + }, + ), ), - _ => TextFieldEditor( - key: Key("$selectedId-body"), - fieldKey: "$selectedId-body-editor", - initialValue: requestModel?.requestBody, - onChanged: (String value) { - ref - .read(collectionStateNotifierProvider.notifier) - .update(selectedId, requestBody: value); - }, + _ => Padding( + padding: kPt5o10, + child: TextFieldEditor( + key: Key("$selectedId-body"), + fieldKey: "$selectedId-body-editor", + initialValue: requestModel?.requestBody, + onChanged: (String value) { + ref + .read(collectionStateNotifierProvider.notifier) + .update(selectedId, requestBody: value); + }, + ), ), }, ) diff --git a/lib/screens/home_page/editor_pane/details_card/request_pane/request_form_data.dart b/lib/screens/home_page/editor_pane/details_card/request_pane/request_form_data.dart index 5d518e22..54f0a73e 100644 --- a/lib/screens/home_page/editor_pane/details_card/request_pane/request_form_data.dart +++ b/lib/screens/home_page/editor_pane/details_card/request_pane/request_form_data.dart @@ -1,7 +1,7 @@ import 'dart:math'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:davi/davi.dart'; +import 'package:data_table_2/data_table_2.dart'; import 'package:apidash/providers/providers.dart'; import 'package:apidash/widgets/widgets.dart'; import 'package:apidash/models/models.dart'; @@ -17,158 +17,186 @@ class FormDataWidget extends ConsumerStatefulWidget { class _FormDataBodyState extends ConsumerState { late int seed; final random = Random.secure(); - late List rows; + late List formRows; + bool isAddingRow = false; + @override void initState() { super.initState(); seed = random.nextInt(kRandMax); } + void _onFieldChange(String selectedId) { + ref.read(collectionStateNotifierProvider.notifier).update( + selectedId, + requestFormDataList: formRows.sublist(0, formRows.length - 1), + ); + } + @override Widget build(BuildContext context) { final selectedId = ref.watch(selectedIdStateProvider); - var formRows = ref.read(selectedRequestModelProvider)?.requestFormDataList; - rows = - formRows == null || formRows.isEmpty ? [kFormDataEmptyModel] : formRows; + ref.watch(selectedRequestModelProvider + .select((value) => value?.requestFormDataList?.length)); + var rF = ref.read(selectedRequestModelProvider)?.requestFormDataList; + bool isFormDataEmpty = rF == null || rF.isEmpty; + formRows = isFormDataEmpty + ? [ + kFormDataEmptyModel, + ] + : rF + + [ + kFormDataEmptyModel, + ]; + isAddingRow = false; - DaviModel daviModelRows = DaviModel( - rows: rows, - columns: [ - DaviColumn( - cellPadding: kpsV5, - name: 'Key', - grow: 4, - cellBuilder: (_, row) { - int idx = row.index; - return Theme( - data: Theme.of(context), - child: FormDataField( - keyId: "$selectedId-$idx-form-v-$seed", - initialValue: rows[idx].name, - hintText: " Add Key", + List columns = const [ + DataColumn2( + label: Text(kNameField), + size: ColumnSize.M, + ), + DataColumn2( + label: Text('='), + fixedWidth: 20, + ), + DataColumn2( + label: Text(''), + fixedWidth: 70, + ), + DataColumn2( + label: Text(kNameValue), + size: ColumnSize.L, + ), + DataColumn2( + label: Text(''), + fixedWidth: 32, + ), + ]; + + List dataRows = List.generate( + formRows.length, + (index) { + bool isLast = index + 1 == formRows.length; + return DataRow( + key: ValueKey("$selectedId-$index-form-row-$seed"), + cells: [ + DataCell( + CellField( + keyId: "$selectedId-$index-form-k-$seed", + initialValue: formRows[index].name, + hintText: kHintAddFieldName, onChanged: (value) { - rows[idx] = rows[idx].copyWith( - name: value, - ); + formRows[index] = formRows[index].copyWith(name: value); + if (isLast && !isAddingRow) { + isAddingRow = true; + formRows.add(kFormDataEmptyModel); + } _onFieldChange(selectedId!); }, colorScheme: Theme.of(context).colorScheme, - formDataType: rows[idx].type, - onFormDataTypeChanged: (value) { - rows[idx] = rows[idx].copyWith( + ), + ), + DataCell( + Center( + child: Text( + "=", + style: kCodeStyle, + ), + ), + ), + DataCell( + DropdownButtonFormData( + formDataType: formRows[index].type, + onChanged: (value) { + bool hasChanged = formRows[index].type != value; + formRows[index] = formRows[index].copyWith( type: value ?? FormDataType.text, ); - rows[idx] = rows[idx].copyWith(value: ""); + formRows[index] = formRows[index].copyWith(value: ""); + if (isLast && hasChanged) { + formRows.add(kFormDataEmptyModel); + } setState(() {}); _onFieldChange(selectedId!); }, ), - ); - }, - sortable: false, - ), - DaviColumn( - width: 40, - cellPadding: kpsV5, - cellAlignment: Alignment.center, - cellBuilder: (_, row) { - return Text( - "=", - style: kCodeStyle, - ); - }, - ), - DaviColumn( - name: 'Value', - grow: 4, - cellPadding: kpsV5, - cellBuilder: (_, row) { - int idx = row.index; - return rows[idx].type == FormDataType.file - ? Align( - alignment: Alignment.centerLeft, - child: Row( - children: [ - Expanded( - child: Theme( - data: Theme.of(context), - child: ElevatedButton.icon( - icon: const Icon( - Icons.snippet_folder_rounded, - size: 20, - ), - style: ButtonStyle( - shape: MaterialStatePropertyAll( - RoundedRectangleBorder( - borderRadius: BorderRadius.circular(6), - ), - ), - ), - onPressed: () async { - var pickedResult = await pickFile(); - if (pickedResult != null && - pickedResult.files.isNotEmpty && - pickedResult.files.first.path != null) { - rows[idx] = rows[idx].copyWith( - value: pickedResult.files.first.path!, - ); - setState(() {}); - _onFieldChange(selectedId!); - } - }, - label: Text( - (rows[idx].type == FormDataType.file && - rows[idx].value.isNotEmpty) - ? rows[idx].value.toString() - : "Select File", - textAlign: TextAlign.center, - overflow: TextOverflow.ellipsis, - style: kFormDataButtonLabelTextStyle, - ), - ), - ), + ), + DataCell( + formRows[index].type == FormDataType.file + ? ElevatedButton.icon( + icon: const Icon( + Icons.snippet_folder_rounded, + size: 20, + ), + style: ElevatedButton.styleFrom( + minimumSize: const Size.fromHeight(kDataTableRowHeight), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(6), ), - ], + ), + onPressed: () async { + var pickedResult = await pickFile(); + if (pickedResult != null && + pickedResult.path.isNotEmpty) { + formRows[index] = formRows[index].copyWith( + value: pickedResult.path, + ); + setState(() {}); + _onFieldChange(selectedId!); + } + }, + label: Text( + (formRows[index].type == FormDataType.file && + formRows[index].value.isNotEmpty) + ? formRows[index].value.toString() + : kLabelSelectFile, + overflow: TextOverflow.ellipsis, + style: kFormDataButtonLabelTextStyle, + ), + ) + : CellField( + keyId: "$selectedId-$index-form-v-$seed", + initialValue: formRows[index].value, + hintText: kHintAddValue, + onChanged: (value) { + formRows[index] = + formRows[index].copyWith(value: value); + if (isLast && !isAddingRow) { + isAddingRow = true; + formRows.add(kFormDataEmptyModel); + } + _onFieldChange(selectedId!); + }, + colorScheme: Theme.of(context).colorScheme, ), - ) - : CellField( - keyId: "$selectedId-$idx-form-v-$seed", - initialValue: rows[idx].value, - hintText: " Add Value", - onChanged: (value) { - rows[idx] = rows[idx].copyWith(value: value); - _onFieldChange(selectedId!); - }, - colorScheme: Theme.of(context).colorScheme, - ); - }, - sortable: false, - ), - DaviColumn( - pinStatus: PinStatus.none, - width: 30, - cellBuilder: (_, row) { - return InkWell( - child: Theme.of(context).brightness == Brightness.dark - ? kIconRemoveDark - : kIconRemoveLight, - onTap: () { - seed = random.nextInt(kRandMax); - if (rows.length == 1) { - setState(() { - rows = [kFormDataEmptyModel]; - }); - } else { - rows.removeAt(row.index); - } - _onFieldChange(selectedId!); - setState(() {}); - }, - ); - }, - ), - ], + ), + DataCell( + InkWell( + onTap: isLast + ? null + : () { + seed = random.nextInt(kRandMax); + if (formRows.length == 2) { + setState(() { + formRows = [ + kFormDataEmptyModel, + ]; + }); + } else { + formRows.removeAt(index); + } + _onFieldChange(selectedId!); + }, + child: Theme.of(context).brightness == Brightness.dark + ? kIconRemoveDark + : kIconRemoveLight, + ), + ), + ], + ); + }, ); + return Stack( children: [ Container( @@ -180,28 +208,38 @@ class _FormDataBodyState extends ConsumerState { child: Column( children: [ Expanded( - child: DaviTheme( - data: kTableThemeData, - child: Davi(daviModelRows), + child: Theme( + data: Theme.of(context) + .copyWith(scrollbarTheme: kDataTableScrollbarTheme), + child: DataTable2( + columnSpacing: 12, + dividerThickness: 0, + horizontalMargin: 0, + headingRowHeight: 0, + dataRowHeight: kDataTableRowHeight, + bottomMargin: kDataTableBottomPadding, + isVerticalScrollBarVisible: true, + columns: columns, + rows: dataRows, + ), ), ), + kVSpacer40, ], ), ), Align( alignment: Alignment.bottomCenter, child: Padding( - padding: const EdgeInsets.only(bottom: 30), + padding: kPb15, child: ElevatedButton.icon( onPressed: () { - setState(() { - rows.add(kFormDataEmptyModel); - }); + formRows.add(kFormDataEmptyModel); _onFieldChange(selectedId!); }, icon: const Icon(Icons.add), label: const Text( - "Add Form Data", + kLabelAddFormField, style: kTextStyleButton, ), ), @@ -210,11 +248,4 @@ class _FormDataBodyState extends ConsumerState { ], ); } - - void _onFieldChange(String selectedId) { - ref.read(collectionStateNotifierProvider.notifier).update( - selectedId, - requestFormDataList: rows, - ); - } } diff --git a/lib/screens/home_page/editor_pane/details_card/request_pane/request_headers.dart b/lib/screens/home_page/editor_pane/details_card/request_pane/request_headers.dart index 503355f8..ab8efec3 100644 --- a/lib/screens/home_page/editor_pane/details_card/request_pane/request_headers.dart +++ b/lib/screens/home_page/editor_pane/details_card/request_pane/request_headers.dart @@ -1,7 +1,7 @@ import 'dart:math'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:davi/davi.dart'; +import 'package:data_table_2/data_table_2.dart'; import 'package:apidash/providers/providers.dart'; import 'package:apidash/widgets/widgets.dart'; import 'package:apidash/models/models.dart'; @@ -15,10 +15,11 @@ class EditRequestHeaders extends ConsumerStatefulWidget { } class EditRequestHeadersState extends ConsumerState { - final random = Random.secure(); - late List rows; - late List isRowEnabledList; late int seed; + final random = Random.secure(); + late List headerRows; + late List isRowEnabledList; + bool isAddingRow = false; @override void initState() { @@ -29,8 +30,9 @@ class EditRequestHeadersState extends ConsumerState { void _onFieldChange(String selectedId) { ref.read(collectionStateNotifierProvider.notifier).update( selectedId, - requestHeaders: rows, - isHeaderEnabledList: isRowEnabledList, + requestHeaders: headerRows.sublist(0, headerRows.length - 1), + isHeaderEnabledList: + isRowEnabledList.sublist(0, headerRows.length - 1), ); } @@ -40,110 +42,134 @@ class EditRequestHeadersState extends ConsumerState { ref.watch(selectedRequestModelProvider .select((value) => value?.requestHeaders?.length)); var rH = ref.read(selectedRequestModelProvider)?.requestHeaders; - rows = (rH == null || rH.isEmpty) + bool isHeadersEmpty = rH == null || rH.isEmpty; + headerRows = isHeadersEmpty ? [ kNameValueEmptyModel, ] - : rH; + : rH + [kNameValueEmptyModel]; isRowEnabledList = ref.read(selectedRequestModelProvider)?.isHeaderEnabledList ?? - List.filled(rows.length, true, growable: true); + List.filled(rH?.length ?? 0, true, growable: true); + isRowEnabledList.add(false); + isAddingRow = false; - DaviModel model = DaviModel( - rows: rows, - columns: [ - DaviColumn( - name: 'Checkbox', - width: 30, - cellBuilder: (_, row) { - int idx = row.index; - return CheckBox( - keyId: "$selectedId-$idx-headers-c-$seed", - value: isRowEnabledList[idx], - onChanged: (value) { - setState(() { - isRowEnabledList[idx] = value!; - }); - _onFieldChange(selectedId!); - }, - colorScheme: Theme.of(context).colorScheme, - ); - }, - ), - DaviColumn( - name: 'Header Name', - width: 70, - grow: 1, - cellBuilder: (_, row) { - int idx = row.index; - return HeaderField( - keyId: "$selectedId-$idx-headers-k-$seed", - initialValue: rows[idx].name, - hintText: "Add Header Name", - onChanged: (value) { - rows[idx] = rows[idx].copyWith(name: value); - _onFieldChange(selectedId!); - }, - colorScheme: Theme.of(context).colorScheme, - ); - }, - sortable: false, - ), - DaviColumn( - width: 30, - cellBuilder: (_, row) { - return Text( - "=", - style: kCodeStyle, - ); - }, - ), - DaviColumn( - name: 'Header Value', - grow: 1, - cellBuilder: (_, row) { - int idx = row.index; - return CellField( - keyId: "$selectedId-$idx-headers-v-$seed", - initialValue: rows[idx].value, - hintText: " Add Header Value", - onChanged: (value) { - rows[idx] = rows[idx].copyWith(value: value); - _onFieldChange(selectedId!); - }, - colorScheme: Theme.of(context).colorScheme, - ); - }, - sortable: false, - ), - DaviColumn( - pinStatus: PinStatus.none, - width: 30, - cellBuilder: (_, row) { - return InkWell( - child: Theme.of(context).brightness == Brightness.dark - ? kIconRemoveDark - : kIconRemoveLight, - onTap: () { - seed = random.nextInt(kRandMax); - if (rows.length == 1) { - setState(() { - rows = [ - kNameValueEmptyModel, - ]; - isRowEnabledList = [true]; - }); - } else { - rows.removeAt(row.index); - isRowEnabledList.removeAt(row.index); - } - _onFieldChange(selectedId!); - }, - ); - }, - ), - ], + List columns = const [ + DataColumn2( + label: Text(kNameCheckbox), + fixedWidth: 30, + ), + DataColumn2( + label: Text(kNameHeader), + ), + DataColumn2( + label: Text('='), + fixedWidth: 30, + ), + DataColumn2( + label: Text(kNameValue), + ), + DataColumn2( + label: Text(''), + fixedWidth: 32, + ), + ]; + + List dataRows = List.generate( + headerRows.length, + (index) { + bool isLast = index + 1 == headerRows.length; + return DataRow( + key: ValueKey("$selectedId-$index-headers-row-$seed"), + cells: [ + DataCell( + CheckBox( + keyId: "$selectedId-$index-headers-c-$seed", + value: isRowEnabledList[index], + onChanged: isLast + ? null + : (value) { + setState(() { + isRowEnabledList[index] = value!; + }); + _onFieldChange(selectedId!); + }, + colorScheme: Theme.of(context).colorScheme, + ), + ), + DataCell( + HeaderField( + keyId: "$selectedId-$index-headers-k-$seed", + initialValue: headerRows[index].name, + hintText: kHintAddName, + onChanged: (value) { + headerRows[index] = headerRows[index].copyWith(name: value); + if (isLast && !isAddingRow) { + isAddingRow = true; + isRowEnabledList[index] = true; + headerRows.add(kNameValueEmptyModel); + isRowEnabledList.add(false); + } + _onFieldChange(selectedId!); + }, + colorScheme: Theme.of(context).colorScheme, + ), + ), + DataCell( + Center( + child: Text( + "=", + style: kCodeStyle, + ), + ), + ), + DataCell( + CellField( + keyId: "$selectedId-$index-headers-v-$seed", + initialValue: headerRows[index].value, + hintText: kHintAddValue, + onChanged: (value) { + headerRows[index] = headerRows[index].copyWith(value: value); + if (isLast && !isAddingRow) { + isAddingRow = true; + isRowEnabledList[index] = true; + headerRows.add(kNameValueEmptyModel); + isRowEnabledList.add(false); + } + _onFieldChange(selectedId!); + }, + colorScheme: Theme.of(context).colorScheme, + ), + ), + DataCell( + InkWell( + onTap: isLast + ? null + : () { + seed = random.nextInt(kRandMax); + if (headerRows.length == 2) { + setState(() { + headerRows = [ + kNameValueEmptyModel, + ]; + isRowEnabledList = [false]; + }); + } else { + headerRows.removeAt(index); + isRowEnabledList.removeAt(index); + } + _onFieldChange(selectedId!); + }, + child: Theme.of(context).brightness == Brightness.dark + ? kIconRemoveDark + : kIconRemoveLight, + ), + ), + ], + ); + }, ); + return Stack( children: [ Container( @@ -155,27 +181,39 @@ class EditRequestHeadersState extends ConsumerState { child: Column( children: [ Expanded( - child: DaviTheme( - data: kTableThemeData, - child: Davi(model), + child: Theme( + data: Theme.of(context) + .copyWith(scrollbarTheme: kDataTableScrollbarTheme), + child: DataTable2( + columnSpacing: 12, + dividerThickness: 0, + horizontalMargin: 0, + headingRowHeight: 0, + dataRowHeight: kDataTableRowHeight, + bottomMargin: kDataTableBottomPadding, + isVerticalScrollBarVisible: true, + columns: columns, + rows: dataRows, + ), ), ), + kVSpacer40, ], ), ), Align( alignment: Alignment.bottomCenter, child: Padding( - padding: const EdgeInsets.only(bottom: 30), + padding: kPb15, child: ElevatedButton.icon( onPressed: () { - rows.add(kNameValueEmptyModel); - isRowEnabledList.add(true); + headerRows.add(kNameValueEmptyModel); + isRowEnabledList.add(false); _onFieldChange(selectedId!); }, icon: const Icon(Icons.add), label: const Text( - "Add Header", + kLabelAddHeader, style: kTextStyleButton, ), ), diff --git a/lib/screens/home_page/editor_pane/details_card/request_pane/request_params.dart b/lib/screens/home_page/editor_pane/details_card/request_pane/request_params.dart index 6e3aca4b..4b048c0a 100644 --- a/lib/screens/home_page/editor_pane/details_card/request_pane/request_params.dart +++ b/lib/screens/home_page/editor_pane/details_card/request_pane/request_params.dart @@ -1,11 +1,11 @@ import 'dart:math'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:davi/davi.dart'; import 'package:apidash/providers/providers.dart'; import 'package:apidash/widgets/widgets.dart'; import 'package:apidash/models/models.dart'; import 'package:apidash/consts.dart'; +import 'package:data_table_2/data_table_2.dart'; class EditRequestURLParams extends ConsumerStatefulWidget { const EditRequestURLParams({super.key}); @@ -16,10 +16,11 @@ class EditRequestURLParams extends ConsumerStatefulWidget { } class EditRequestURLParamsState extends ConsumerState { - final random = Random.secure(); - late List rows; - late List isRowEnabledList; late int seed; + final random = Random.secure(); + late List paramRows; + late List isRowEnabledList; + bool isAddingRow = false; @override void initState() { @@ -30,8 +31,8 @@ class EditRequestURLParamsState extends ConsumerState { void _onFieldChange(String selectedId) { ref.read(collectionStateNotifierProvider.notifier).update( selectedId, - requestParams: rows, - isParamEnabledList: isRowEnabledList, + requestParams: paramRows.sublist(0, paramRows.length - 1), + isParamEnabledList: isRowEnabledList.sublist(0, paramRows.length - 1), ); } @@ -41,110 +42,134 @@ class EditRequestURLParamsState extends ConsumerState { ref.watch(selectedRequestModelProvider .select((value) => value?.requestParams?.length)); var rP = ref.read(selectedRequestModelProvider)?.requestParams; - rows = (rP == null || rP.isEmpty) + bool isParamsEmpty = rP == null || rP.isEmpty; + paramRows = isParamsEmpty ? [ kNameValueEmptyModel, ] - : rP; + : rP + [kNameValueEmptyModel]; isRowEnabledList = ref.read(selectedRequestModelProvider)?.isParamEnabledList ?? - List.filled(rows.length, true, growable: true); + List.filled(rP?.length ?? 0, true, growable: true); + isRowEnabledList.add(false); + isAddingRow = false; - DaviModel model = DaviModel( - rows: rows, - columns: [ - DaviColumn( - name: 'Checkbox', - width: 30, - cellBuilder: (_, row) { - int idx = row.index; - return CheckBox( - keyId: "$selectedId-$idx-params-c-$seed", - value: isRowEnabledList[idx], - onChanged: (value) { - setState(() { - isRowEnabledList[idx] = value!; - }); - _onFieldChange(selectedId!); - }, - colorScheme: Theme.of(context).colorScheme, - ); - }, - ), - DaviColumn( - name: 'URL Parameter', - width: 70, - grow: 1, - cellBuilder: (_, row) { - int idx = row.index; - return CellField( - keyId: "$selectedId-$idx-params-k-$seed", - initialValue: rows[idx].name, - hintText: "Add URL Parameter", - onChanged: (value) { - rows[idx] = rows[idx].copyWith(name: value); - _onFieldChange(selectedId!); - }, - colorScheme: Theme.of(context).colorScheme, - ); - }, - sortable: false, - ), - DaviColumn( - width: 30, - cellBuilder: (_, row) { - return Text( - "=", - style: kCodeStyle, - ); - }, - ), - DaviColumn( - name: 'Value', - grow: 1, - cellBuilder: (_, row) { - int idx = row.index; - return CellField( - keyId: "$selectedId-$idx-params-v-$seed", - initialValue: rows[idx].value, - hintText: "Add Value", - onChanged: (value) { - rows[idx] = rows[idx].copyWith(value: value); - _onFieldChange(selectedId!); - }, - colorScheme: Theme.of(context).colorScheme, - ); - }, - sortable: false, - ), - DaviColumn( - pinStatus: PinStatus.none, - width: 30, - cellBuilder: (_, row) { - return InkWell( - child: Theme.of(context).brightness == Brightness.dark - ? kIconRemoveDark - : kIconRemoveLight, - onTap: () { - seed = random.nextInt(kRandMax); - if (rows.length == 1) { - setState(() { - rows = [ - kNameValueEmptyModel, - ]; - isRowEnabledList = [true]; - }); - } else { - rows.removeAt(row.index); - isRowEnabledList.removeAt(row.index); - } - _onFieldChange(selectedId!); - }, - ); - }, - ), - ], + List columns = const [ + DataColumn2( + label: Text(kNameCheckbox), + fixedWidth: 30, + ), + DataColumn2( + label: Text(kNameURLParam), + ), + DataColumn2( + label: Text('='), + fixedWidth: 30, + ), + DataColumn2( + label: Text(kNameValue), + ), + DataColumn2( + label: Text(''), + fixedWidth: 32, + ), + ]; + + List dataRows = List.generate( + paramRows.length, + (index) { + bool isLast = index + 1 == paramRows.length; + return DataRow( + key: ValueKey("$selectedId-$index-params-row-$seed"), + cells: [ + DataCell( + CheckBox( + keyId: "$selectedId-$index-params-c-$seed", + value: isRowEnabledList[index], + onChanged: isLast + ? null + : (value) { + setState(() { + isRowEnabledList[index] = value!; + }); + _onFieldChange(selectedId!); + }, + colorScheme: Theme.of(context).colorScheme, + ), + ), + DataCell( + CellField( + keyId: "$selectedId-$index-params-k-$seed", + initialValue: paramRows[index].name, + hintText: kHintAddURLParam, + onChanged: (value) { + paramRows[index] = paramRows[index].copyWith(name: value); + if (isLast && !isAddingRow) { + isAddingRow = true; + isRowEnabledList[index] = true; + paramRows.add(kNameValueEmptyModel); + isRowEnabledList.add(false); + } + _onFieldChange(selectedId!); + }, + colorScheme: Theme.of(context).colorScheme, + ), + ), + DataCell( + Center( + child: Text( + "=", + style: kCodeStyle, + ), + ), + ), + DataCell( + CellField( + keyId: "$selectedId-$index-params-v-$seed", + initialValue: paramRows[index].value, + hintText: kHintAddValue, + onChanged: (value) { + paramRows[index] = paramRows[index].copyWith(value: value); + if (isLast && !isAddingRow) { + isAddingRow = true; + isRowEnabledList[index] = true; + paramRows.add(kNameValueEmptyModel); + isRowEnabledList.add(false); + } + _onFieldChange(selectedId!); + }, + colorScheme: Theme.of(context).colorScheme, + ), + ), + DataCell( + InkWell( + onTap: isLast + ? null + : () { + seed = random.nextInt(kRandMax); + if (paramRows.length == 2) { + setState(() { + paramRows = [ + kNameValueEmptyModel, + ]; + isRowEnabledList = [false]; + }); + } else { + paramRows.removeAt(index); + isRowEnabledList.removeAt(index); + } + _onFieldChange(selectedId!); + }, + child: Theme.of(context).brightness == Brightness.dark + ? kIconRemoveDark + : kIconRemoveLight, + ), + ), + ], + ); + }, ); + return Stack( children: [ Container( @@ -154,29 +179,42 @@ class EditRequestURLParamsState extends ConsumerState { ), margin: kP10, child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, children: [ Expanded( - child: DaviTheme( - data: kTableThemeData, - child: Davi(model), + child: Theme( + data: Theme.of(context) + .copyWith(scrollbarTheme: kDataTableScrollbarTheme), + child: DataTable2( + columnSpacing: 12, + dividerThickness: 0, + horizontalMargin: 0, + headingRowHeight: 0, + dataRowHeight: kDataTableRowHeight, + bottomMargin: kDataTableBottomPadding, + isVerticalScrollBarVisible: true, + columns: columns, + rows: dataRows, + ), ), ), + kVSpacer40, ], ), ), Align( alignment: Alignment.bottomCenter, child: Padding( - padding: const EdgeInsets.only(bottom: 30), + padding: kPb15, child: ElevatedButton.icon( onPressed: () { - rows.add(kNameValueEmptyModel); - isRowEnabledList.add(true); + paramRows.add(kNameValueEmptyModel); + isRowEnabledList.add(false); _onFieldChange(selectedId!); }, icon: const Icon(Icons.add), label: const Text( - "Add Param", + kLabelAddParam, style: kTextStyleButton, ), ), diff --git a/lib/screens/home_page/editor_pane/details_card/response_pane.dart b/lib/screens/home_page/editor_pane/details_card/response_pane.dart index 703b873d..17a03ea7 100644 --- a/lib/screens/home_page/editor_pane/details_card/response_pane.dart +++ b/lib/screens/home_page/editor_pane/details_card/response_pane.dart @@ -12,12 +12,17 @@ class ResponsePane extends ConsumerWidget { final isWorking = ref.watch( selectedRequestModelProvider.select((value) => value?.isWorking)) ?? false; + final startSendingTime = ref.watch( + selectedRequestModelProvider.select((value) => value?.sendingTime)); final responseStatus = ref.watch( selectedRequestModelProvider.select((value) => value?.responseStatus)); final message = ref .watch(selectedRequestModelProvider.select((value) => value?.message)); + if (isWorking) { - return const SendingWidget(); + return SendingWidget( + startSendingTime: startSendingTime, + ); } if (responseStatus == null) { return const NotSentWidget(); @@ -34,7 +39,6 @@ class ResponseDetails extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { - var sm = ScaffoldMessenger.of(context); final responseStatus = ref.watch( selectedRequestModelProvider.select((value) => value?.responseStatus)); final message = ref @@ -52,8 +56,6 @@ class ResponseDetails extends ConsumerWidget { ref .read(collectionStateNotifierProvider.notifier) .clearResponse(selectedRequest?.id); - sm.hideCurrentSnackBar(); - sm.showSnackBar(getSnackBar('Response cleared')); }, ), const Expanded( diff --git a/lib/screens/home_page/editor_pane/editor_request.dart b/lib/screens/home_page/editor_pane/editor_request.dart index 90a60349..ce264454 100644 --- a/lib/screens/home_page/editor_pane/editor_request.dart +++ b/lib/screens/home_page/editor_pane/editor_request.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:apidash/providers/collection_providers.dart'; +import 'package:apidash/providers/providers.dart'; import 'package:apidash/consts.dart'; import 'details_card/details_card.dart'; import 'url_card.dart'; diff --git a/lib/utils/file_utils.dart b/lib/utils/file_utils.dart index 58d69513..8f7c6a72 100644 --- a/lib/utils/file_utils.dart +++ b/lib/utils/file_utils.dart @@ -1,10 +1,10 @@ import 'dart:io'; import 'dart:typed_data'; +import 'package:file_selector/file_selector.dart'; import 'package:path/path.dart' as p; import 'package:mime_dart/mime_dart.dart'; import 'package:uuid/uuid.dart'; import 'package:path_provider/path_provider.dart'; -import 'package:file_picker/file_picker.dart'; const uuid = Uuid(); @@ -57,7 +57,7 @@ String getTempFileName() { return getNewUuid(); } -Future pickFile() async { - FilePickerResult? pickedResult = await FilePicker.platform.pickFiles(); +Future pickFile() async { + XFile? pickedResult = await openFile(); return pickedResult; } diff --git a/lib/widgets/buttons.dart b/lib/widgets/buttons.dart index f4280380..41bcddb9 100644 --- a/lib/widgets/buttons.dart +++ b/lib/widgets/buttons.dart @@ -246,15 +246,12 @@ class ClearResponseButton extends StatelessWidget { @override Widget build(BuildContext context) { - return Tooltip( - message: 'Clear response', - child: TextButton( - style: TextButton.styleFrom(minimumSize: const Size(40, 40)), - onPressed: onPressed, - child: const Icon( - Icons.delete, - size: 20, - ), + return IconButton( + tooltip: kTooltipClearResponse, + onPressed: onPressed, + icon: const Icon( + Icons.delete, + size: 16, ), ); } diff --git a/lib/widgets/checkbox.dart b/lib/widgets/checkbox.dart index 22c3869f..53adf496 100644 --- a/lib/widgets/checkbox.dart +++ b/lib/widgets/checkbox.dart @@ -3,7 +3,7 @@ import 'package:flutter/material.dart'; class CheckBox extends StatelessWidget { final String keyId; final bool value; - final ValueChanged onChanged; + final ValueChanged? onChanged; final ColorScheme? colorScheme; const CheckBox({ super.key, diff --git a/lib/widgets/dropdowns.dart b/lib/widgets/dropdowns.dart index 69008a6b..1be902e9 100644 --- a/lib/widgets/dropdowns.dart +++ b/lib/widgets/dropdowns.dart @@ -157,6 +157,7 @@ class DropdownButtonCodegenLanguage extends StatelessWidget { Widget build(BuildContext context) { final surfaceColor = Theme.of(context).colorScheme.surface; return DropdownButton( + isExpanded: true, focusColor: surfaceColor, value: codegenLanguage, icon: const Icon( @@ -181,6 +182,8 @@ class DropdownButtonCodegenLanguage extends StatelessWidget { child: Text( value.label, style: kTextStyleButton, + overflow: TextOverflow.ellipsis, + maxLines: 1, ), ), ); diff --git a/lib/widgets/form_data_field.dart b/lib/widgets/form_data_field.dart deleted file mode 100644 index 29f210c4..00000000 --- a/lib/widgets/form_data_field.dart +++ /dev/null @@ -1,83 +0,0 @@ -import 'package:apidash/consts.dart'; -import 'package:flutter/material.dart'; -import 'dropdowns.dart'; - -class FormDataField extends StatefulWidget { - const FormDataField({ - super.key, - required this.keyId, - this.initialValue, - this.hintText, - this.onChanged, - this.colorScheme, - this.formDataType, - this.onFormDataTypeChanged, - }); - - final String keyId; - final String? initialValue; - final String? hintText; - final void Function(String)? onChanged; - final ColorScheme? colorScheme; - final FormDataType? formDataType; - final void Function(FormDataType?)? onFormDataTypeChanged; - - @override - State createState() => _FormDataFieldState(); -} - -class _FormDataFieldState extends State { - @override - void initState() { - super.initState(); - } - - @override - Widget build(BuildContext context) { - var colorScheme = widget.colorScheme ?? Theme.of(context).colorScheme; - return Row( - children: [ - Expanded( - flex: 1, - child: TextFormField( - initialValue: widget.initialValue, - key: Key(widget.keyId), - style: kCodeStyle.copyWith( - color: colorScheme.onSurface, - ), - decoration: InputDecoration( - hintStyle: kCodeStyle.copyWith( - color: colorScheme.outline.withOpacity( - kHintOpacity, - ), - ), - hintText: widget.hintText, - contentPadding: const EdgeInsets.only(bottom: 16), - focusedBorder: UnderlineInputBorder( - borderSide: BorderSide( - color: colorScheme.primary.withOpacity( - kHintOpacity, - ), - ), - ), - enabledBorder: UnderlineInputBorder( - borderSide: BorderSide( - color: colorScheme.surfaceVariant, - ), - ), - suffixIcon: DropdownButtonFormData( - formDataType: widget.formDataType, - onChanged: (p0) { - if (widget.onFormDataTypeChanged != null) { - widget.onFormDataTypeChanged!(p0); - } - }, - ), - ), - onChanged: widget.onChanged, - ), - ), - ], - ); - } -} diff --git a/lib/widgets/headerfield.dart b/lib/widgets/headerfield.dart index 5bce6c8f..3d60caac 100644 --- a/lib/widgets/headerfield.dart +++ b/lib/widgets/headerfield.dart @@ -76,11 +76,14 @@ class _HeaderFieldState extends State { onChanged: widget.onChanged, controller: controller, focusNode: focusNode, - style: kCodeStyle.copyWith(color: colorScheme.onSurface), + style: kCodeStyle.copyWith( + color: colorScheme.onSurface, + ), decoration: InputDecoration( hintStyle: kCodeStyle.copyWith( color: colorScheme.outline.withOpacity(kHintOpacity)), hintText: widget.hintText, + contentPadding: const EdgeInsets.only(bottom: 12), focusedBorder: UnderlineInputBorder( borderSide: BorderSide( color: colorScheme.primary.withOpacity( diff --git a/lib/widgets/previewer.dart b/lib/widgets/previewer.dart index dd2f5186..ac213b50 100644 --- a/lib/widgets/previewer.dart +++ b/lib/widgets/previewer.dart @@ -8,6 +8,7 @@ import 'error_message.dart'; import 'uint8_audio_player.dart'; import 'json_previewer.dart'; import 'csv_previewer.dart'; +import 'video_previewer.dart'; import '../consts.dart'; class Previewer extends StatefulWidget { @@ -86,7 +87,12 @@ class _PreviewerState extends State { return CsvPreviewer(body: widget.body); } if (widget.type == kTypeVideo) { - // TODO: Video Player + try { + var preview = VideoPreviewer(videoBytes: widget.bytes); + return preview; + } catch (e) { + return const ErrorMessage(message: kVideoError); + } } String message = widget.hasRaw ? "$kMimeTypeRawRaiseIssueStart${widget.type}/${widget.subtype}$kMimeTypeRaiseIssue" diff --git a/lib/widgets/request_widgets.dart b/lib/widgets/request_widgets.dart index ffac504e..747cc8f4 100644 --- a/lib/widgets/request_widgets.dart +++ b/lib/widgets/request_widgets.dart @@ -48,16 +48,12 @@ class _RequestPaneState extends State return Column( children: [ Padding( - padding: kPh20v10, + padding: kP8, child: SizedBox( height: kHeaderHeight, child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, + mainAxisAlignment: MainAxisAlignment.end, children: [ - Text( - "Request", - style: Theme.of(context).textTheme.titleMedium, - ), FilledButton.tonalIcon( onPressed: widget.onPressedCodeButton, icon: Icon( @@ -68,7 +64,8 @@ class _RequestPaneState extends State label: SizedBox( width: 75, child: Text( - widget.codePaneVisible ? "Hide Code" : "View Code"), + widget.codePaneVisible ? kLabelHideCode : kLabelViewCode, + ), ), ), ], @@ -79,22 +76,24 @@ class _RequestPaneState extends State key: Key(widget.selectedId!), controller: _controller, overlayColor: kColorTransparentState, + labelPadding: kPh2, onTap: widget.onTapTabBar, tabs: [ TabLabel( - text: 'URL Params', + text: kLabelURLParams, showIndicator: widget.showIndicators[0], ), TabLabel( - text: 'Headers', + text: kLabelHeaders, showIndicator: widget.showIndicators[1], ), TabLabel( - text: 'Body', + text: kLabelBody, showIndicator: widget.showIndicators[2], ), ], ), + kVSpacer5, Expanded( child: TabBarView( controller: _controller, diff --git a/lib/widgets/response_widgets.dart b/lib/widgets/response_widgets.dart index e641b03d..a3d9f20b 100644 --- a/lib/widgets/response_widgets.dart +++ b/lib/widgets/response_widgets.dart @@ -1,3 +1,4 @@ +import 'dart:async'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:http_parser/http_parser.dart'; @@ -23,7 +24,7 @@ class NotSentWidget extends StatelessWidget { color: color, ), Text( - 'Not Sent', + kLabelNotSent, style: Theme.of(context).textTheme.titleMedium?.copyWith(color: color), ), @@ -33,18 +34,80 @@ class NotSentWidget extends StatelessWidget { } } -class SendingWidget extends StatelessWidget { - const SendingWidget({super.key}); +class SendingWidget extends StatefulWidget { + final DateTime? startSendingTime; + const SendingWidget({ + super.key, + required this.startSendingTime, + }); + + @override + State createState() => _SendingWidgetState(); +} + +class _SendingWidgetState extends State { + int _millisecondsElapsed = 0; + Timer? _timer; + + @override + void initState() { + super.initState(); + if (widget.startSendingTime != null) { + _millisecondsElapsed = + (DateTime.now().difference(widget.startSendingTime!).inMilliseconds ~/ + 100) * + 100; + _timer = Timer.periodic(const Duration(milliseconds: 100), _updateTimer); + } + } + + void _updateTimer(Timer timer) { + setState(() { + _millisecondsElapsed += 100; + }); + } + + @override + void dispose() { + if (_timer != null && _timer!.isActive) _timer?.cancel(); + super.dispose(); + } @override Widget build(BuildContext context) { - return Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Lottie.asset(kAssetSendingLottie), - ], - ), + return Stack( + children: [ + Center( + child: Lottie.asset(kAssetSendingLottie), + ), + Padding( + padding: kPh20t40, + child: Visibility( + visible: _millisecondsElapsed >= 0, + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon( + Icons.alarm, + color: Theme.of(context).colorScheme.onSurfaceVariant, + ), + const SizedBox( + width: 10, + ), + Text( + 'Time elapsed: ${humanizeDuration(Duration(milliseconds: _millisecondsElapsed))}', + textAlign: TextAlign.center, + overflow: TextOverflow.fade, + softWrap: false, + style: kTextStyleButton.copyWith( + color: Theme.of(context).colorScheme.onSurfaceVariant, + ), + ), + ], + ), + ), + ), + ], ); } } @@ -66,42 +129,19 @@ class ResponsePaneHeader extends StatelessWidget { @override Widget build(BuildContext context) { return Padding( - padding: kPh20v10, + padding: kPv8, child: SizedBox( height: kHeaderHeight, child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Text.rich( - TextSpan( - children: [ - const TextSpan( - text: "Response (", - ), - TextSpan( - text: "$responseStatus", - style: TextStyle( - color: getResponseStatusCodeColor( - responseStatus, - brightness: Theme.of(context).brightness, - ), - fontFamily: kCodeStyle.fontFamily, - ), - ), - const TextSpan( - text: ")", - ), - ], - style: Theme.of(context).textTheme.titleMedium, - ), - ), - kHSpacer20, + kHSpacer10, Expanded( child: Text( - message ?? "", + "$responseStatus: ${message ?? '-'}", softWrap: false, overflow: TextOverflow.ellipsis, - style: Theme.of(context).textTheme.titleMedium!.copyWith( + style: Theme.of(context).textTheme.bodyMedium?.copyWith( fontFamily: kCodeStyle.fontFamily, color: getResponseStatusCodeColor( responseStatus, @@ -110,10 +150,10 @@ class ResponsePaneHeader extends StatelessWidget { ), ), ), - kHSpacer20, + kHSpacer10, Text( humanizeDuration(time), - style: Theme.of(context).textTheme.titleMedium!.copyWith( + style: Theme.of(context).textTheme.bodyMedium?.copyWith( fontFamily: kCodeStyle.fontFamily, color: Theme.of(context).colorScheme.secondary, ), @@ -163,31 +203,15 @@ class _ResponseTabViewState extends State TabBar( key: Key(widget.selectedId!), controller: _controller, + labelPadding: kPh2, overlayColor: kColorTransparentState, onTap: (index) {}, tabs: const [ - SizedBox( - height: kTabHeight, - child: Center( - child: Text( - 'Body', - textAlign: TextAlign.center, - overflow: TextOverflow.fade, - softWrap: false, - style: kTextStyleButton, - ), - ), + TabLabel( + text: kLabelResponseBody, ), - SizedBox( - height: kTabHeight, - child: Center( - child: Text( - 'Headers', - textAlign: TextAlign.center, - overflow: TextOverflow.fade, - style: kTextStyleButton, - ), - ), + TabLabel( + text: kLabelHeaders, ), ], ), @@ -227,8 +251,8 @@ class ResponseHeadersHeader extends StatelessWidget { children: [ Expanded( child: Text( - "$name (${map.length} items)", - style: Theme.of(context).textTheme.labelLarge!.copyWith( + "$name (${map.length} $kLabelItems)", + style: Theme.of(context).textTheme.labelMedium?.copyWith( fontWeight: FontWeight.bold, ), ), @@ -243,8 +267,6 @@ class ResponseHeadersHeader extends StatelessWidget { } } -const kHeaderRow = ["Header Name", "Header Value"]; - class ResponseHeaders extends StatelessWidget { const ResponseHeaders({ super.key, @@ -263,7 +285,7 @@ class ResponseHeaders extends StatelessWidget { children: [ ResponseHeadersHeader( map: responseHeaders, - name: "Response Headers", + name: kLabelResponseHeaders, ), if (responseHeaders.isNotEmpty) kVSpacer5, if (responseHeaders.isNotEmpty) @@ -275,7 +297,7 @@ class ResponseHeaders extends StatelessWidget { kVSpacer10, ResponseHeadersHeader( map: requestHeaders, - name: "Request Headers", + name: kLabelRequestHeaders, ), if (requestHeaders.isNotEmpty) kVSpacer5, if (requestHeaders.isNotEmpty) @@ -302,20 +324,18 @@ class ResponseBody extends StatelessWidget { Widget build(BuildContext context) { final responseModel = selectedRequestModel?.responseModel; if (responseModel == null) { - return const ErrorMessage( - message: - 'Error: Response data does not exist. $kUnexpectedRaiseIssue'); + return const ErrorMessage(message: '$kMsgError $kUnexpectedRaiseIssue'); } var body = responseModel.body; var formattedBody = responseModel.formattedBody; if (body == null) { return const ErrorMessage( - message: 'Response body is missing (null). $kUnexpectedRaiseIssue'); + message: '$kMsgNullBody $kUnexpectedRaiseIssue'); } if (body.isEmpty) { return const ErrorMessage( - message: 'No content', + message: kMsgNoContent, showIcon: false, showIssueButton: false, ); @@ -325,7 +345,7 @@ class ResponseBody extends StatelessWidget { if (mediaType == null) { return ErrorMessage( message: - 'Unknown Response Content-Type - ${responseModel.contentType}. $kUnexpectedRaiseIssue'); + '$kMsgUnknowContentType - ${responseModel.contentType}. $kUnexpectedRaiseIssue'); } var responseBodyView = getResponseBodyViewOptions(mediaType); diff --git a/lib/widgets/tabs.dart b/lib/widgets/tabs.dart index eabf36c8..c2542a26 100644 --- a/lib/widgets/tabs.dart +++ b/lib/widgets/tabs.dart @@ -2,7 +2,11 @@ import 'package:flutter/material.dart'; import 'package:apidash/consts.dart'; class TabLabel extends StatelessWidget { - const TabLabel({super.key, required this.text, this.showIndicator = false}); + const TabLabel({ + super.key, + required this.text, + this.showIndicator = false, + }); final String text; final bool showIndicator; @@ -18,14 +22,14 @@ class TabLabel extends StatelessWidget { textAlign: TextAlign.center, overflow: TextOverflow.fade, softWrap: false, - style: kTextStyleButton, + style: kTextStyleTab, ), ), if (showIndicator) const Align( alignment: Alignment.topCenter, child: Padding( - padding: EdgeInsets.only(top: 6), + padding: EdgeInsets.only(top: 1), child: Icon( Icons.circle, size: 6, diff --git a/lib/widgets/textfields.dart b/lib/widgets/textfields.dart index da68f9e2..671be6ba 100644 --- a/lib/widgets/textfields.dart +++ b/lib/widgets/textfields.dart @@ -68,6 +68,7 @@ class CellField extends StatelessWidget { ), ), hintText: hintText, + contentPadding: const EdgeInsets.only(bottom: 12), focusedBorder: UnderlineInputBorder( borderSide: BorderSide( color: clrScheme.primary.withOpacity( @@ -94,14 +95,39 @@ class JsonSearchField extends StatelessWidget { @override Widget build(BuildContext context) { - return TextField( + return RawTextField( controller: controller, onChanged: onChanged, style: kCodeStyle, - decoration: const InputDecoration( + hintText: 'Search..', + ); + } +} + +class RawTextField extends StatelessWidget { + const RawTextField({ + super.key, + this.onChanged, + this.controller, + this.hintText, + this.style, + }); + + final void Function(String)? onChanged; + final TextEditingController? controller; + final String? hintText; + final TextStyle? style; + + @override + Widget build(BuildContext context) { + return TextField( + controller: controller, + onChanged: onChanged, + style: style, + decoration: InputDecoration( isDense: true, border: InputBorder.none, - hintText: 'Search..', + hintText: hintText, ), ); } diff --git a/lib/widgets/video_previewer.dart b/lib/widgets/video_previewer.dart new file mode 100644 index 00000000..c077e569 --- /dev/null +++ b/lib/widgets/video_previewer.dart @@ -0,0 +1,147 @@ +import 'dart:io'; +import 'dart:typed_data'; +import 'package:apidash/consts.dart'; +import 'package:fvp/fvp.dart' as fvp; +import 'package:flutter/material.dart'; +import 'package:flutter/foundation.dart'; +import 'package:video_player/video_player.dart'; +import 'package:path_provider/path_provider.dart'; + +class VideoPreviewer extends StatefulWidget { + const VideoPreviewer({ + super.key, + required this.videoBytes, + }); + + final Uint8List videoBytes; + + @override + State createState() => _VideoPreviewerState(); +} + +class _VideoPreviewerState extends State { + VideoPlayerController? _videoController; + bool _isPlaying = false; + File? _tempVideoFile; + bool _showControls = false; + + @override + void initState() { + super.initState(); + registerWithAllPlatforms(); + _initializeVideoPlayer(); + } + + void registerWithAllPlatforms() { + try { + fvp.registerWith(); + } catch (e) { + // pass + } + } + + void _initializeVideoPlayer() async { + final tempDir = await getTemporaryDirectory(); + _tempVideoFile = File( + '${tempDir.path}/temp_video_${DateTime.now().millisecondsSinceEpoch}'); + try { + await _tempVideoFile?.writeAsBytes(widget.videoBytes); + _videoController = VideoPlayerController.file(_tempVideoFile!) + ..initialize().then((_) { + if (mounted) { + setState(() { + _videoController!.play(); + _videoController!.setLooping(true); + }); + } + }); + } catch (e) { + return; + } + } + + @override + Widget build(BuildContext context) { + final iconColor = Theme.of(context).iconTheme.color; + final progressBarColors = VideoProgressColors( + playedColor: iconColor!, + bufferedColor: iconColor.withOpacity(0.5), + backgroundColor: iconColor.withOpacity(0.3), + ); + return Scaffold( + body: MouseRegion( + onEnter: (_) => setState(() => _showControls = true), + onExit: (_) => setState(() => _showControls = false), + child: Stack( + children: [ + Center( + child: _videoController?.value.isInitialized == true + ? AspectRatio( + aspectRatio: _videoController!.value.aspectRatio, + child: VideoPlayer(_videoController!), + ) + : const CircularProgressIndicator(), + ), + Positioned( + left: 0, + right: 0, + bottom: 0, + child: _videoController?.value.isInitialized == true + ? SizedBox( + height: 50.0, + child: VideoProgressIndicator( + _videoController!, + allowScrubbing: true, + padding: const EdgeInsets.all(20), + colors: progressBarColors, + ), + ) + : Container(height: 0), + ), + if (_showControls) + Center( + child: GestureDetector( + onTap: () { + if (_videoController!.value.isPlaying) { + _videoController!.pause(); + } else { + _videoController!.play(); + } + setState(() { + _isPlaying = !_isPlaying; + }); + }, + child: Container( + color: Colors.transparent, + child: Icon( + _isPlaying ? Icons.play_arrow : Icons.pause, + size: 64, + color: iconColor, + ), + ), + ), + ), + ], + ), + ), + ); + } + + @override + void dispose() { + _videoController?.pause(); + _videoController?.dispose(); + if (!kIsRunningTests) { + Future.delayed(const Duration(seconds: 1), () async { + try { + if (_tempVideoFile != null) { + await _tempVideoFile!.delete(); + } + } catch (e) { + return; + } + }); + } + super.dispose(); + } +} diff --git a/lib/widgets/widgets.dart b/lib/widgets/widgets.dart index e4e842fb..4d249939 100644 --- a/lib/widgets/widgets.dart +++ b/lib/widgets/widgets.dart @@ -7,7 +7,6 @@ export 'dropdowns.dart'; export 'editor_json.dart'; export 'editor.dart'; export 'error_message.dart'; -export 'form_data_field.dart'; export 'headerfield.dart'; export 'intro_message.dart'; export 'json_previewer.dart'; diff --git a/pubspec.lock b/pubspec.lock index a4e54dfb..d6235dec 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -49,14 +49,6 @@ packages: url: "https://pub.dev" source: hosted version: "0.1.18" - axis_layout: - dependency: transitive - description: - name: axis_layout - sha256: "9ba44f279f39121065d811e72da892de86f5613d68eb0b295f60d021ea8f2a59" - url: "https://pub.dev" - source: hosted - version: "1.0.1" barcode: dependency: transitive description: @@ -209,6 +201,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.7.2" + cross_file: + dependency: transitive + description: + name: cross_file + sha256: "55d7b444feb71301ef6b8838dbc1ae02e63dd48c8773f3810ff53bb1e2945b32" + url: "https://pub.dev" + source: hosted + version: "0.3.4+1" crypto: dependency: transitive description: @@ -217,6 +217,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.0.3" + csslib: + dependency: transitive + description: + name: csslib + sha256: "706b5707578e0c1b4b7550f64078f0a0f19dec3f50a178ffae7006b0a9ca58fb" + url: "https://pub.dev" + source: hosted + version: "1.0.0" csv: dependency: "direct main" description: @@ -233,14 +241,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.3.6" - davi: + data_table_2: dependency: "direct main" description: - name: davi - sha256: "4105870281c4c33e8e017e21e212b96fd2637b4c1a35b2a56f14aaa4acdf6f0d" + name: data_table_2 + sha256: fdb0551f103f1daf837bddfde14619fd9e683408833a618c9afabeb533fce88c url: "https://pub.dev" source: hosted - version: "3.4.1" + version: "2.5.11" eventify: dependency: transitive description: @@ -289,14 +297,70 @@ packages: url: "https://pub.dev" source: hosted version: "7.0.0" - file_picker: + file_selector: dependency: "direct main" description: - name: file_picker - sha256: caa6bc229eab3e32eb2f37b53a5f9d22a6981474afd210c512a7546c1e1a04f6 + name: file_selector + sha256: "5019692b593455127794d5718304ff1ae15447dea286cdda9f0db2a796a1b828" url: "https://pub.dev" source: hosted - version: "6.2.0" + version: "1.0.3" + file_selector_android: + dependency: transitive + description: + name: file_selector_android + sha256: "1cd66575f063b689e041aec836905ba7be18d76c9f0634d0d75daec825f67095" + url: "https://pub.dev" + source: hosted + version: "0.5.0+7" + file_selector_ios: + dependency: transitive + description: + name: file_selector_ios + sha256: b015154e6d9fddbc4d08916794df170b44531798c8dd709a026df162d07ad81d + url: "https://pub.dev" + source: hosted + version: "0.5.1+8" + file_selector_linux: + dependency: transitive + description: + name: file_selector_linux + sha256: "045d372bf19b02aeb69cacf8b4009555fb5f6f0b7ad8016e5f46dd1387ddd492" + url: "https://pub.dev" + source: hosted + version: "0.9.2+1" + file_selector_macos: + dependency: transitive + description: + name: file_selector_macos + sha256: b15c3da8bd4908b9918111fa486903f5808e388b8d1c559949f584725a6594d6 + url: "https://pub.dev" + source: hosted + version: "0.9.3+3" + file_selector_platform_interface: + dependency: transitive + description: + name: file_selector_platform_interface + sha256: a3994c26f10378a039faa11de174d7b78eb8f79e4dd0af2a451410c1a5c3f66b + url: "https://pub.dev" + source: hosted + version: "2.6.2" + file_selector_web: + dependency: transitive + description: + name: file_selector_web + sha256: "619e431b224711a3869e30dbd7d516f5f5a4f04b265013a50912f39e1abc88c8" + url: "https://pub.dev" + source: hosted + version: "0.9.4+1" + file_selector_windows: + dependency: transitive + description: + name: file_selector_windows + sha256: d3547240c20cabf205c7c7f01a50ecdbc413755814d6677f3cb366f04abcead0 + url: "https://pub.dev" + source: hosted + version: "0.9.3+1" fixnum: dependency: transitive description: @@ -382,14 +446,6 @@ packages: url: "https://pub.dev" source: hosted version: "0.6.21" - flutter_plugin_android_lifecycle: - dependency: transitive - description: - name: flutter_plugin_android_lifecycle - sha256: b068ffc46f82a55844acfa4fdbb61fad72fa2aef0905548419d97f0f95c456da - url: "https://pub.dev" - source: hosted - version: "2.0.17" flutter_riverpod: dependency: "direct main" description: @@ -448,6 +504,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.2.0" + fvp: + dependency: "direct main" + description: + name: fvp + sha256: "995328479ba4641da6760ddc84a168db157a3b9db4f0417fa68713d99344a146" + url: "https://pub.dev" + source: hosted + version: "0.14.0" glob: dependency: transitive description: @@ -496,6 +560,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.1.0" + html: + dependency: transitive + description: + name: html + sha256: "3a7812d5bcd2894edf53dfaf8cd640876cf6cef50a8f238745c8b8120ea74d3a" + url: "https://pub.dev" + source: hosted + version: "0.15.4" html_unescape: dependency: transitive description: @@ -1294,6 +1366,46 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.4" + video_player: + dependency: "direct main" + description: + name: video_player + sha256: afc65f4b8bcb2c188f64a591f84fb471f4f2e19fc607c65fd8d2f8fedb3dec23 + url: "https://pub.dev" + source: hosted + version: "2.8.3" + video_player_android: + dependency: transitive + description: + name: video_player_android + sha256: "4dd9b8b86d70d65eecf3dcabfcdfbb9c9115d244d022654aba49a00336d540c2" + url: "https://pub.dev" + source: hosted + version: "2.4.12" + video_player_avfoundation: + dependency: transitive + description: + name: video_player_avfoundation + sha256: "309e3962795e761be010869bae65c0b0e45b5230c5cee1bec72197ca7db040ed" + url: "https://pub.dev" + source: hosted + version: "2.5.6" + video_player_platform_interface: + dependency: "direct main" + description: + name: video_player_platform_interface + sha256: "236454725fafcacf98f0f39af0d7c7ab2ce84762e3b63f2cbb3ef9a7e0550bc6" + url: "https://pub.dev" + source: hosted + version: "6.2.2" + video_player_web: + dependency: transitive + description: + name: video_player_web + sha256: "41245cef5ef29c4585dbabcbcbe9b209e34376642c7576cabf11b4ad9289d6e4" + url: "https://pub.dev" + source: hosted + version: "2.3.0" vm_service: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 6f78ae1e..528cda82 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -13,9 +13,8 @@ dependencies: multi_split_view: ^2.4.0 url_launcher: ^6.2.5 flutter_riverpod: ^2.5.1 - riverpod: ^2.5.1 + riverpod: ^2.5.1 uuid: ^4.3.3 - davi: ^3.4.1 http: ^1.2.1 http_parser: ^4.0.2 collection: ^1.17.2 @@ -44,18 +43,22 @@ dependencies: package_info_plus: ^5.0.1 flutter_typeahead: ^5.2.0 provider: ^6.1.2 + fvp: ^0.14.0 + video_player: ^2.3.2 + video_player_platform_interface: ^6.2.2 json_data_explorer: git: url: https://github.com/foss42/json_data_explorer.git ref: b7dde2f85dff4f482eed7eda4ef2a71344ef8b3a scrollable_positioned_list: ^0.3.8 - file_picker: ^6.2.0 flutter_svg: ^2.0.10+1 vector_graphics_compiler: ^1.1.9+1 code_builder: ^4.10.0 dart_style: ^2.3.6 json_text_field: ^1.1.0 csv: ^6.0.0 + data_table_2: ^2.5.11 + file_selector: ^1.0.3 dependency_overrides: web: ^0.5.0 diff --git a/test/codegen/c_curl_codegen_test.dart b/test/codegen/c_curl_codegen_test.dart new file mode 100644 index 00000000..20023220 --- /dev/null +++ b/test/codegen/c_curl_codegen_test.dart @@ -0,0 +1,1602 @@ +import 'package:apidash/codegen/codegen.dart'; +import 'package:apidash/consts.dart'; +import 'package:test/test.dart'; +import '../request_models.dart'; + +void main() { + final codeGen = Codegen(); + + group('GET Request', () { + test('GET 1', () { + const expectedCode = r"""#include +#include +#include +#include +struct ResponseData { + char *data; + size_t size; +}; + +size_t write_callback(char *ptr, size_t size, size_t nmemb, void *userdata) { + struct ResponseData *response_data = (struct ResponseData *)userdata; + size_t real_size = size * nmemb; + + response_data->data = realloc(response_data->data, response_data->size + real_size + 1); + if (response_data->data == NULL) { + fprintf(stderr, "Memory allocation failed\n"); + return 0; + } + + memcpy(&(response_data->data[response_data->size]), ptr, real_size); + response_data->size += real_size; + response_data->data[response_data->size] = 0; + + return real_size; +} +int main() { + CURL *curl; + CURLcode res; + curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "https://api.apidash.dev"); + struct ResponseData response_data = {0}; + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response_data); + res = curl_easy_perform(curl); + long response_code; + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code); + printf("Response code: %ld\n", response_code); + printf("Response body: %s\n", response_data.data); + free(response_data.data); + } + curl_easy_cleanup(curl); + return 0; +}"""; + expect( + codeGen.getCode( + CodegenLanguage.cCurlCodeGen, requestModelGet1, "https"), + expectedCode); + }); + + test('GET 2', () { + const expectedCode = r"""#include +#include +#include +#include +struct ResponseData { + char *data; + size_t size; +}; + +size_t write_callback(char *ptr, size_t size, size_t nmemb, void *userdata) { + struct ResponseData *response_data = (struct ResponseData *)userdata; + size_t real_size = size * nmemb; + + response_data->data = realloc(response_data->data, response_data->size + real_size + 1); + if (response_data->data == NULL) { + fprintf(stderr, "Memory allocation failed\n"); + return 0; + } + + memcpy(&(response_data->data[response_data->size]), ptr, real_size); + response_data->size += real_size; + response_data->data[response_data->size] = 0; + + return real_size; +} +int main() { + CURL *curl; + CURLcode res; + curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "https://api.apidash.dev/country/data?code=US"); + struct ResponseData response_data = {0}; + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response_data); + res = curl_easy_perform(curl); + long response_code; + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code); + printf("Response code: %ld\n", response_code); + printf("Response body: %s\n", response_data.data); + free(response_data.data); + } + curl_easy_cleanup(curl); + return 0; +}"""; + expect( + codeGen.getCode( + CodegenLanguage.cCurlCodeGen, requestModelGet2, "https"), + expectedCode); + }); + + test('GET 3', () { + const expectedCode = r"""#include +#include +#include +#include +struct ResponseData { + char *data; + size_t size; +}; + +size_t write_callback(char *ptr, size_t size, size_t nmemb, void *userdata) { + struct ResponseData *response_data = (struct ResponseData *)userdata; + size_t real_size = size * nmemb; + + response_data->data = realloc(response_data->data, response_data->size + real_size + 1); + if (response_data->data == NULL) { + fprintf(stderr, "Memory allocation failed\n"); + return 0; + } + + memcpy(&(response_data->data[response_data->size]), ptr, real_size); + response_data->size += real_size; + response_data->data[response_data->size] = 0; + + return real_size; +} +int main() { + CURL *curl; + CURLcode res; + curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "https://api.apidash.dev/country/data?code=IND"); + struct ResponseData response_data = {0}; + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response_data); + res = curl_easy_perform(curl); + long response_code; + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code); + printf("Response code: %ld\n", response_code); + printf("Response body: %s\n", response_data.data); + free(response_data.data); + } + curl_easy_cleanup(curl); + return 0; +}"""; + expect( + codeGen.getCode( + CodegenLanguage.cCurlCodeGen, requestModelGet3, "https"), + expectedCode); + }); + + test('GET 4', () { + const expectedCode = r"""#include +#include +#include +#include +struct ResponseData { + char *data; + size_t size; +}; + +size_t write_callback(char *ptr, size_t size, size_t nmemb, void *userdata) { + struct ResponseData *response_data = (struct ResponseData *)userdata; + size_t real_size = size * nmemb; + + response_data->data = realloc(response_data->data, response_data->size + real_size + 1); + if (response_data->data == NULL) { + fprintf(stderr, "Memory allocation failed\n"); + return 0; + } + + memcpy(&(response_data->data[response_data->size]), ptr, real_size); + response_data->size += real_size; + response_data->data[response_data->size] = 0; + + return real_size; +} +int main() { + CURL *curl; + CURLcode res; + curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "https://api.apidash.dev/humanize/social?num=8700000&digits=3&system=SS&add_space=true&trailing_zeros=true"); + struct ResponseData response_data = {0}; + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response_data); + res = curl_easy_perform(curl); + long response_code; + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code); + printf("Response code: %ld\n", response_code); + printf("Response body: %s\n", response_data.data); + free(response_data.data); + } + curl_easy_cleanup(curl); + return 0; +}"""; + expect( + codeGen.getCode( + CodegenLanguage.cCurlCodeGen, requestModelGet4, "https"), + expectedCode); + }); + + test('GET 5', () { + const expectedCode = r"""#include +#include +#include +#include +struct ResponseData { + char *data; + size_t size; +}; + +size_t write_callback(char *ptr, size_t size, size_t nmemb, void *userdata) { + struct ResponseData *response_data = (struct ResponseData *)userdata; + size_t real_size = size * nmemb; + + response_data->data = realloc(response_data->data, response_data->size + real_size + 1); + if (response_data->data == NULL) { + fprintf(stderr, "Memory allocation failed\n"); + return 0; + } + + memcpy(&(response_data->data[response_data->size]), ptr, real_size); + response_data->size += real_size; + response_data->data[response_data->size] = 0; + + return real_size; +} +int main() { + CURL *curl; + CURLcode res; + curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "https://api.github.com/repos/foss42/apidash"); + struct curl_slist *headers = NULL; + headers = curl_slist_append(headers,"User-Agent: Test Agent"); + + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); + struct ResponseData response_data = {0}; + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response_data); + res = curl_easy_perform(curl); + long response_code; + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code); + printf("Response code: %ld\n", response_code); + printf("Response body: %s\n", response_data.data); + free(response_data.data); + curl_slist_free_all(headers); + } + curl_easy_cleanup(curl); + return 0; +}"""; + expect( + codeGen.getCode( + CodegenLanguage.cCurlCodeGen, requestModelGet5, "https"), + expectedCode); + }); + + test('GET 6', () { + const expectedCode = r"""#include +#include +#include +#include +struct ResponseData { + char *data; + size_t size; +}; + +size_t write_callback(char *ptr, size_t size, size_t nmemb, void *userdata) { + struct ResponseData *response_data = (struct ResponseData *)userdata; + size_t real_size = size * nmemb; + + response_data->data = realloc(response_data->data, response_data->size + real_size + 1); + if (response_data->data == NULL) { + fprintf(stderr, "Memory allocation failed\n"); + return 0; + } + + memcpy(&(response_data->data[response_data->size]), ptr, real_size); + response_data->size += real_size; + response_data->data[response_data->size] = 0; + + return real_size; +} +int main() { + CURL *curl; + CURLcode res; + curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "https://api.github.com/repos/foss42/apidash?raw=true"); + struct curl_slist *headers = NULL; + headers = curl_slist_append(headers,"User-Agent: Test Agent"); + + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); + struct ResponseData response_data = {0}; + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response_data); + res = curl_easy_perform(curl); + long response_code; + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code); + printf("Response code: %ld\n", response_code); + printf("Response body: %s\n", response_data.data); + free(response_data.data); + curl_slist_free_all(headers); + } + curl_easy_cleanup(curl); + return 0; +}"""; + expect( + codeGen.getCode( + CodegenLanguage.cCurlCodeGen, requestModelGet6, "https"), + expectedCode); + }); + + test('GET 7', () { + const expectedCode = r"""#include +#include +#include +#include +struct ResponseData { + char *data; + size_t size; +}; + +size_t write_callback(char *ptr, size_t size, size_t nmemb, void *userdata) { + struct ResponseData *response_data = (struct ResponseData *)userdata; + size_t real_size = size * nmemb; + + response_data->data = realloc(response_data->data, response_data->size + real_size + 1); + if (response_data->data == NULL) { + fprintf(stderr, "Memory allocation failed\n"); + return 0; + } + + memcpy(&(response_data->data[response_data->size]), ptr, real_size); + response_data->size += real_size; + response_data->data[response_data->size] = 0; + + return real_size; +} +int main() { + CURL *curl; + CURLcode res; + curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "https://api.apidash.dev"); + struct ResponseData response_data = {0}; + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response_data); + res = curl_easy_perform(curl); + long response_code; + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code); + printf("Response code: %ld\n", response_code); + printf("Response body: %s\n", response_data.data); + free(response_data.data); + } + curl_easy_cleanup(curl); + return 0; +}"""; + expect( + codeGen.getCode( + CodegenLanguage.cCurlCodeGen, requestModelGet7, "https"), + expectedCode); + }); + + test('GET 8', () { + const expectedCode = r"""#include +#include +#include +#include +struct ResponseData { + char *data; + size_t size; +}; + +size_t write_callback(char *ptr, size_t size, size_t nmemb, void *userdata) { + struct ResponseData *response_data = (struct ResponseData *)userdata; + size_t real_size = size * nmemb; + + response_data->data = realloc(response_data->data, response_data->size + real_size + 1); + if (response_data->data == NULL) { + fprintf(stderr, "Memory allocation failed\n"); + return 0; + } + + memcpy(&(response_data->data[response_data->size]), ptr, real_size); + response_data->size += real_size; + response_data->data[response_data->size] = 0; + + return real_size; +} +int main() { + CURL *curl; + CURLcode res; + curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "https://api.github.com/repos/foss42/apidash?raw=true"); + struct curl_slist *headers = NULL; + headers = curl_slist_append(headers,"User-Agent: Test Agent"); + + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); + struct ResponseData response_data = {0}; + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response_data); + res = curl_easy_perform(curl); + long response_code; + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code); + printf("Response code: %ld\n", response_code); + printf("Response body: %s\n", response_data.data); + free(response_data.data); + curl_slist_free_all(headers); + } + curl_easy_cleanup(curl); + return 0; +}"""; + expect( + codeGen.getCode( + CodegenLanguage.cCurlCodeGen, requestModelGet8, "https"), + expectedCode); + }); + + test('GET 9', () { + const expectedCode = r"""#include +#include +#include +#include +struct ResponseData { + char *data; + size_t size; +}; + +size_t write_callback(char *ptr, size_t size, size_t nmemb, void *userdata) { + struct ResponseData *response_data = (struct ResponseData *)userdata; + size_t real_size = size * nmemb; + + response_data->data = realloc(response_data->data, response_data->size + real_size + 1); + if (response_data->data == NULL) { + fprintf(stderr, "Memory allocation failed\n"); + return 0; + } + + memcpy(&(response_data->data[response_data->size]), ptr, real_size); + response_data->size += real_size; + response_data->data[response_data->size] = 0; + + return real_size; +} +int main() { + CURL *curl; + CURLcode res; + curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "https://api.apidash.dev/humanize/social?num=8700000&add_space=true"); + struct ResponseData response_data = {0}; + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response_data); + res = curl_easy_perform(curl); + long response_code; + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code); + printf("Response code: %ld\n", response_code); + printf("Response body: %s\n", response_data.data); + free(response_data.data); + } + curl_easy_cleanup(curl); + return 0; +}"""; + expect( + codeGen.getCode( + CodegenLanguage.cCurlCodeGen, requestModelGet9, "https"), + expectedCode); + }); + + test('GET 10', () { + const expectedCode = r"""#include +#include +#include +#include +struct ResponseData { + char *data; + size_t size; +}; + +size_t write_callback(char *ptr, size_t size, size_t nmemb, void *userdata) { + struct ResponseData *response_data = (struct ResponseData *)userdata; + size_t real_size = size * nmemb; + + response_data->data = realloc(response_data->data, response_data->size + real_size + 1); + if (response_data->data == NULL) { + fprintf(stderr, "Memory allocation failed\n"); + return 0; + } + + memcpy(&(response_data->data[response_data->size]), ptr, real_size); + response_data->size += real_size; + response_data->data[response_data->size] = 0; + + return real_size; +} +int main() { + CURL *curl; + CURLcode res; + curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "https://api.apidash.dev/humanize/social"); + struct curl_slist *headers = NULL; + headers = curl_slist_append(headers,"User-Agent: Test Agent"); + + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); + struct ResponseData response_data = {0}; + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response_data); + res = curl_easy_perform(curl); + long response_code; + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code); + printf("Response code: %ld\n", response_code); + printf("Response body: %s\n", response_data.data); + free(response_data.data); + curl_slist_free_all(headers); + } + curl_easy_cleanup(curl); + return 0; +}"""; + expect( + codeGen.getCode( + CodegenLanguage.cCurlCodeGen, + requestModelGet10, + "https", + ), + expectedCode); + }); + + test('GET 11', () { + const expectedCode = r"""#include +#include +#include +#include +struct ResponseData { + char *data; + size_t size; +}; + +size_t write_callback(char *ptr, size_t size, size_t nmemb, void *userdata) { + struct ResponseData *response_data = (struct ResponseData *)userdata; + size_t real_size = size * nmemb; + + response_data->data = realloc(response_data->data, response_data->size + real_size + 1); + if (response_data->data == NULL) { + fprintf(stderr, "Memory allocation failed\n"); + return 0; + } + + memcpy(&(response_data->data[response_data->size]), ptr, real_size); + response_data->size += real_size; + response_data->data[response_data->size] = 0; + + return real_size; +} +int main() { + CURL *curl; + CURLcode res; + curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "https://api.apidash.dev/humanize/social?num=8700000&digits=3"); + struct curl_slist *headers = NULL; + headers = curl_slist_append(headers,"User-Agent: Test Agent"); + + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); + struct ResponseData response_data = {0}; + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response_data); + res = curl_easy_perform(curl); + long response_code; + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code); + printf("Response code: %ld\n", response_code); + printf("Response body: %s\n", response_data.data); + free(response_data.data); + curl_slist_free_all(headers); + } + curl_easy_cleanup(curl); + return 0; +}"""; + expect( + codeGen.getCode( + CodegenLanguage.cCurlCodeGen, requestModelGet11, "https"), + expectedCode); + }); + + test('GET 12', () { + const expectedCode = r"""#include +#include +#include +#include +struct ResponseData { + char *data; + size_t size; +}; + +size_t write_callback(char *ptr, size_t size, size_t nmemb, void *userdata) { + struct ResponseData *response_data = (struct ResponseData *)userdata; + size_t real_size = size * nmemb; + + response_data->data = realloc(response_data->data, response_data->size + real_size + 1); + if (response_data->data == NULL) { + fprintf(stderr, "Memory allocation failed\n"); + return 0; + } + + memcpy(&(response_data->data[response_data->size]), ptr, real_size); + response_data->size += real_size; + response_data->data[response_data->size] = 0; + + return real_size; +} +int main() { + CURL *curl; + CURLcode res; + curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "https://api.apidash.dev/humanize/social"); + struct ResponseData response_data = {0}; + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response_data); + res = curl_easy_perform(curl); + long response_code; + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code); + printf("Response code: %ld\n", response_code); + printf("Response body: %s\n", response_data.data); + free(response_data.data); + } + curl_easy_cleanup(curl); + return 0; +}"""; + expect( + codeGen.getCode( + CodegenLanguage.cCurlCodeGen, requestModelGet12, "https"), + expectedCode); + }); + }); + + group('HEAD Request', () { + test('HEAD 1', () { + const expectedCode = r"""#include +#include +#include +#include +struct ResponseData { + char *data; + size_t size; +}; + +size_t write_callback(char *ptr, size_t size, size_t nmemb, void *userdata) { + struct ResponseData *response_data = (struct ResponseData *)userdata; + size_t real_size = size * nmemb; + + response_data->data = realloc(response_data->data, response_data->size + real_size + 1); + if (response_data->data == NULL) { + fprintf(stderr, "Memory allocation failed\n"); + return 0; + } + + memcpy(&(response_data->data[response_data->size]), ptr, real_size); + response_data->size += real_size; + response_data->data[response_data->size] = 0; + + return real_size; +} +int main() { + CURL *curl; + CURLcode res; + curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "HEAD"); + curl_easy_setopt(curl, CURLOPT_URL, "https://api.apidash.dev"); + struct ResponseData response_data = {0}; + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response_data); + res = curl_easy_perform(curl); + long response_code; + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code); + printf("Response code: %ld\n", response_code); + printf("Response body: %s\n", response_data.data); + free(response_data.data); + } + curl_easy_cleanup(curl); + return 0; +}"""; + expect( + codeGen.getCode( + CodegenLanguage.cCurlCodeGen, requestModelHead1, "https"), + expectedCode); + }); + + test('HEAD 2', () { + const expectedCode = r"""#include +#include +#include +#include +struct ResponseData { + char *data; + size_t size; +}; + +size_t write_callback(char *ptr, size_t size, size_t nmemb, void *userdata) { + struct ResponseData *response_data = (struct ResponseData *)userdata; + size_t real_size = size * nmemb; + + response_data->data = realloc(response_data->data, response_data->size + real_size + 1); + if (response_data->data == NULL) { + fprintf(stderr, "Memory allocation failed\n"); + return 0; + } + + memcpy(&(response_data->data[response_data->size]), ptr, real_size); + response_data->size += real_size; + response_data->data[response_data->size] = 0; + + return real_size; +} +int main() { + CURL *curl; + CURLcode res; + curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "HEAD"); + curl_easy_setopt(curl, CURLOPT_URL, "http://api.apidash.dev"); + struct ResponseData response_data = {0}; + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response_data); + res = curl_easy_perform(curl); + long response_code; + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code); + printf("Response code: %ld\n", response_code); + printf("Response body: %s\n", response_data.data); + free(response_data.data); + } + curl_easy_cleanup(curl); + return 0; +}"""; + expect( + codeGen.getCode( + CodegenLanguage.cCurlCodeGen, requestModelHead2, "http"), + expectedCode); + }); + }); + + group('POST Request', () { + test('POST 1', () { + const expectedCode = r"""#include +#include +#include +#include +struct ResponseData { + char *data; + size_t size; +}; + +size_t write_callback(char *ptr, size_t size, size_t nmemb, void *userdata) { + struct ResponseData *response_data = (struct ResponseData *)userdata; + size_t real_size = size * nmemb; + + response_data->data = realloc(response_data->data, response_data->size + real_size + 1); + if (response_data->data == NULL) { + fprintf(stderr, "Memory allocation failed\n"); + return 0; + } + + memcpy(&(response_data->data[response_data->size]), ptr, real_size); + response_data->size += real_size; + response_data->data[response_data->size] = 0; + + return real_size; +} +int main() { + CURL *curl; + CURLcode res; + curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "https://api.apidash.dev/case/lower"); + struct curl_slist *headers = NULL; + headers = curl_slist_append(headers,"Content-Type: text/plain"); + + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); + const char *data = "{\n\"text\": \"I LOVE Flutter\"\n}"; + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data); + + + struct ResponseData response_data = {0}; + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response_data); + res = curl_easy_perform(curl); + long response_code; + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code); + printf("Response code: %ld\n", response_code); + printf("Response body: %s\n", response_data.data); + free(response_data.data); + curl_slist_free_all(headers); + } + curl_easy_cleanup(curl); + return 0; +}"""; + expect( + codeGen.getCode( + CodegenLanguage.cCurlCodeGen, requestModelPost1, "https"), + expectedCode); + }); + + test('POST 2', () { + const expectedCode = r"""#include +#include +#include +#include +struct ResponseData { + char *data; + size_t size; +}; + +size_t write_callback(char *ptr, size_t size, size_t nmemb, void *userdata) { + struct ResponseData *response_data = (struct ResponseData *)userdata; + size_t real_size = size * nmemb; + + response_data->data = realloc(response_data->data, response_data->size + real_size + 1); + if (response_data->data == NULL) { + fprintf(stderr, "Memory allocation failed\n"); + return 0; + } + + memcpy(&(response_data->data[response_data->size]), ptr, real_size); + response_data->size += real_size; + response_data->data[response_data->size] = 0; + + return real_size; +} +int main() { + CURL *curl; + CURLcode res; + curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "https://api.apidash.dev/case/lower"); + struct curl_slist *headers = NULL; + headers = curl_slist_append(headers,"Content-Type: application/json"); + + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); + const char *data = "{\n\"text\": \"I LOVE Flutter\",\n\"flag\": null,\n\"male\": true,\n\"female\": false,\n\"no\": 1.2,\n\"arr\": [\"null\", \"true\", \"false\", null]\n}"; + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data); + + + struct ResponseData response_data = {0}; + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response_data); + res = curl_easy_perform(curl); + long response_code; + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code); + printf("Response code: %ld\n", response_code); + printf("Response body: %s\n", response_data.data); + free(response_data.data); + curl_slist_free_all(headers); + } + curl_easy_cleanup(curl); + return 0; +}"""; + expect( + codeGen.getCode( + CodegenLanguage.cCurlCodeGen, requestModelPost2, "https"), + expectedCode); + }); + + test('POST 3', () { + const expectedCode = r"""#include +#include +#include +#include +struct ResponseData { + char *data; + size_t size; +}; + +size_t write_callback(char *ptr, size_t size, size_t nmemb, void *userdata) { + struct ResponseData *response_data = (struct ResponseData *)userdata; + size_t real_size = size * nmemb; + + response_data->data = realloc(response_data->data, response_data->size + real_size + 1); + if (response_data->data == NULL) { + fprintf(stderr, "Memory allocation failed\n"); + return 0; + } + + memcpy(&(response_data->data[response_data->size]), ptr, real_size); + response_data->size += real_size; + response_data->data[response_data->size] = 0; + + return real_size; +} +int main() { + CURL *curl; + CURLcode res; + curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "https://api.apidash.dev/case/lower"); + struct curl_slist *headers = NULL; + headers = curl_slist_append(headers,"User-Agent: Test Agent"); + headers = curl_slist_append(headers,"Content-Type: application/json"); + + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); + const char *data = "{\n\"text\": \"I LOVE Flutter\"\n}"; + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data); + + + struct ResponseData response_data = {0}; + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response_data); + res = curl_easy_perform(curl); + long response_code; + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code); + printf("Response code: %ld\n", response_code); + printf("Response body: %s\n", response_data.data); + free(response_data.data); + curl_slist_free_all(headers); + } + curl_easy_cleanup(curl); + return 0; +}"""; + expect( + codeGen.getCode( + CodegenLanguage.cCurlCodeGen, requestModelPost3, "https"), + expectedCode); + }); + + test('POST 4', () { + const expectedCode = r"""#include +#include +#include +#include +struct ResponseData { + char *data; + size_t size; +}; + +size_t write_callback(char *ptr, size_t size, size_t nmemb, void *userdata) { + struct ResponseData *response_data = (struct ResponseData *)userdata; + size_t real_size = size * nmemb; + + response_data->data = realloc(response_data->data, response_data->size + real_size + 1); + if (response_data->data == NULL) { + fprintf(stderr, "Memory allocation failed\n"); + return 0; + } + + memcpy(&(response_data->data[response_data->size]), ptr, real_size); + response_data->size += real_size; + response_data->data[response_data->size] = 0; + + return real_size; +} +int main() { + CURL *curl; + CURLcode res; + curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "https://api.apidash.dev/io/form"); + curl_mime *mime; + curl_mimepart *part; + mime = curl_mime_init(curl); + + part = curl_mime_addpart(mime); + curl_mime_name(part, "text"); + curl_mime_data(part, "API", CURL_ZERO_TERMINATED); + + + part = curl_mime_addpart(mime); + curl_mime_name(part, "sep"); + curl_mime_data(part, "|", CURL_ZERO_TERMINATED); + + + part = curl_mime_addpart(mime); + curl_mime_name(part, "times"); + curl_mime_data(part, "3", CURL_ZERO_TERMINATED); + + curl_easy_setopt(curl, CURLOPT_MIMEPOST, mime); + struct ResponseData response_data = {0}; + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response_data); + res = curl_easy_perform(curl); + long response_code; + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code); + printf("Response code: %ld\n", response_code); + printf("Response body: %s\n", response_data.data); + free(response_data.data); + curl_mime_free(mime); + } + curl_easy_cleanup(curl); + return 0; +}"""; + expect( + codeGen.getCode( + CodegenLanguage.cCurlCodeGen, requestModelPost4, "https"), + expectedCode); + }); + + test('POST 5', () { + const expectedCode = r"""#include +#include +#include +#include +struct ResponseData { + char *data; + size_t size; +}; + +size_t write_callback(char *ptr, size_t size, size_t nmemb, void *userdata) { + struct ResponseData *response_data = (struct ResponseData *)userdata; + size_t real_size = size * nmemb; + + response_data->data = realloc(response_data->data, response_data->size + real_size + 1); + if (response_data->data == NULL) { + fprintf(stderr, "Memory allocation failed\n"); + return 0; + } + + memcpy(&(response_data->data[response_data->size]), ptr, real_size); + response_data->size += real_size; + response_data->data[response_data->size] = 0; + + return real_size; +} +int main() { + CURL *curl; + CURLcode res; + curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "https://api.apidash.dev/io/form"); + struct curl_slist *headers = NULL; + headers = curl_slist_append(headers,"User-Agent: Test Agent"); + + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); + curl_mime *mime; + curl_mimepart *part; + mime = curl_mime_init(curl); + + part = curl_mime_addpart(mime); + curl_mime_name(part, "text"); + curl_mime_data(part, "API", CURL_ZERO_TERMINATED); + + + part = curl_mime_addpart(mime); + curl_mime_name(part, "sep"); + curl_mime_data(part, "|", CURL_ZERO_TERMINATED); + + + part = curl_mime_addpart(mime); + curl_mime_name(part, "times"); + curl_mime_data(part, "3", CURL_ZERO_TERMINATED); + + curl_easy_setopt(curl, CURLOPT_MIMEPOST, mime); + struct ResponseData response_data = {0}; + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response_data); + res = curl_easy_perform(curl); + long response_code; + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code); + printf("Response code: %ld\n", response_code); + printf("Response body: %s\n", response_data.data); + free(response_data.data); + curl_mime_free(mime); + curl_slist_free_all(headers); + } + curl_easy_cleanup(curl); + return 0; +}"""; + expect( + codeGen.getCode( + CodegenLanguage.cCurlCodeGen, requestModelPost5, "https"), + expectedCode); + }); + + test('POST 6', () { + const expectedCode = r"""#include +#include +#include +#include +struct ResponseData { + char *data; + size_t size; +}; + +size_t write_callback(char *ptr, size_t size, size_t nmemb, void *userdata) { + struct ResponseData *response_data = (struct ResponseData *)userdata; + size_t real_size = size * nmemb; + + response_data->data = realloc(response_data->data, response_data->size + real_size + 1); + if (response_data->data == NULL) { + fprintf(stderr, "Memory allocation failed\n"); + return 0; + } + + memcpy(&(response_data->data[response_data->size]), ptr, real_size); + response_data->size += real_size; + response_data->data[response_data->size] = 0; + + return real_size; +} +int main() { + CURL *curl; + CURLcode res; + curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "https://api.apidash.dev/io/img"); + curl_mime *mime; + curl_mimepart *part; + mime = curl_mime_init(curl); + + part = curl_mime_addpart(mime); + curl_mime_name(part, "token"); + curl_mime_data(part, "xyz", CURL_ZERO_TERMINATED); + + + part = curl_mime_addpart(mime); + curl_mime_name(part, "imfile"); + curl_mime_filedata(part, "/Documents/up/1.png"); + + curl_easy_setopt(curl, CURLOPT_MIMEPOST, mime); + struct ResponseData response_data = {0}; + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response_data); + res = curl_easy_perform(curl); + long response_code; + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code); + printf("Response code: %ld\n", response_code); + printf("Response body: %s\n", response_data.data); + free(response_data.data); + curl_mime_free(mime); + } + curl_easy_cleanup(curl); + return 0; +}"""; + expect( + codeGen.getCode( + CodegenLanguage.cCurlCodeGen, requestModelPost6, "https"), + expectedCode); + }); + + test('POST 7', () { + const expectedCode = r"""#include +#include +#include +#include +struct ResponseData { + char *data; + size_t size; +}; + +size_t write_callback(char *ptr, size_t size, size_t nmemb, void *userdata) { + struct ResponseData *response_data = (struct ResponseData *)userdata; + size_t real_size = size * nmemb; + + response_data->data = realloc(response_data->data, response_data->size + real_size + 1); + if (response_data->data == NULL) { + fprintf(stderr, "Memory allocation failed\n"); + return 0; + } + + memcpy(&(response_data->data[response_data->size]), ptr, real_size); + response_data->size += real_size; + response_data->data[response_data->size] = 0; + + return real_size; +} +int main() { + CURL *curl; + CURLcode res; + curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "https://api.apidash.dev/io/img"); + curl_mime *mime; + curl_mimepart *part; + mime = curl_mime_init(curl); + + part = curl_mime_addpart(mime); + curl_mime_name(part, "token"); + curl_mime_data(part, "xyz", CURL_ZERO_TERMINATED); + + + part = curl_mime_addpart(mime); + curl_mime_name(part, "imfile"); + curl_mime_filedata(part, "/Documents/up/1.png"); + + curl_easy_setopt(curl, CURLOPT_MIMEPOST, mime); + struct ResponseData response_data = {0}; + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response_data); + res = curl_easy_perform(curl); + long response_code; + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code); + printf("Response code: %ld\n", response_code); + printf("Response body: %s\n", response_data.data); + free(response_data.data); + curl_mime_free(mime); + } + curl_easy_cleanup(curl); + return 0; +}"""; + expect( + codeGen.getCode( + CodegenLanguage.cCurlCodeGen, requestModelPost7, "https"), + expectedCode); + }); + + test('POST 8', () { + const expectedCode = r"""#include +#include +#include +#include +struct ResponseData { + char *data; + size_t size; +}; + +size_t write_callback(char *ptr, size_t size, size_t nmemb, void *userdata) { + struct ResponseData *response_data = (struct ResponseData *)userdata; + size_t real_size = size * nmemb; + + response_data->data = realloc(response_data->data, response_data->size + real_size + 1); + if (response_data->data == NULL) { + fprintf(stderr, "Memory allocation failed\n"); + return 0; + } + + memcpy(&(response_data->data[response_data->size]), ptr, real_size); + response_data->size += real_size; + response_data->data[response_data->size] = 0; + + return real_size; +} +int main() { + CURL *curl; + CURLcode res; + curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "https://api.apidash.dev/io/form?size=2&len=3"); + curl_mime *mime; + curl_mimepart *part; + mime = curl_mime_init(curl); + + part = curl_mime_addpart(mime); + curl_mime_name(part, "text"); + curl_mime_data(part, "API", CURL_ZERO_TERMINATED); + + + part = curl_mime_addpart(mime); + curl_mime_name(part, "sep"); + curl_mime_data(part, "|", CURL_ZERO_TERMINATED); + + + part = curl_mime_addpart(mime); + curl_mime_name(part, "times"); + curl_mime_data(part, "3", CURL_ZERO_TERMINATED); + + curl_easy_setopt(curl, CURLOPT_MIMEPOST, mime); + struct ResponseData response_data = {0}; + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response_data); + res = curl_easy_perform(curl); + long response_code; + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code); + printf("Response code: %ld\n", response_code); + printf("Response body: %s\n", response_data.data); + free(response_data.data); + curl_mime_free(mime); + } + curl_easy_cleanup(curl); + return 0; +}"""; + expect( + codeGen.getCode( + CodegenLanguage.cCurlCodeGen, requestModelPost8, "https"), + expectedCode); + }); + + test('POST 9', () { + const expectedCode = r"""#include +#include +#include +#include +struct ResponseData { + char *data; + size_t size; +}; + +size_t write_callback(char *ptr, size_t size, size_t nmemb, void *userdata) { + struct ResponseData *response_data = (struct ResponseData *)userdata; + size_t real_size = size * nmemb; + + response_data->data = realloc(response_data->data, response_data->size + real_size + 1); + if (response_data->data == NULL) { + fprintf(stderr, "Memory allocation failed\n"); + return 0; + } + + memcpy(&(response_data->data[response_data->size]), ptr, real_size); + response_data->size += real_size; + response_data->data[response_data->size] = 0; + + return real_size; +} +int main() { + CURL *curl; + CURLcode res; + curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "https://api.apidash.dev/io/img?size=2&len=3"); + struct curl_slist *headers = NULL; + headers = curl_slist_append(headers,"User-Agent: Test Agent"); + headers = curl_slist_append(headers,"Keep-Alive: true"); + + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); + curl_mime *mime; + curl_mimepart *part; + mime = curl_mime_init(curl); + + part = curl_mime_addpart(mime); + curl_mime_name(part, "token"); + curl_mime_data(part, "xyz", CURL_ZERO_TERMINATED); + + + part = curl_mime_addpart(mime); + curl_mime_name(part, "imfile"); + curl_mime_filedata(part, "/Documents/up/1.png"); + + curl_easy_setopt(curl, CURLOPT_MIMEPOST, mime); + struct ResponseData response_data = {0}; + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response_data); + res = curl_easy_perform(curl); + long response_code; + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code); + printf("Response code: %ld\n", response_code); + printf("Response body: %s\n", response_data.data); + free(response_data.data); + curl_mime_free(mime); + curl_slist_free_all(headers); + } + curl_easy_cleanup(curl); + return 0; +}"""; + expect( + codeGen.getCode( + CodegenLanguage.cCurlCodeGen, requestModelPost9, "https"), + expectedCode); + }); + }); + + group('PUT Request', () { + test('PUT 1', () { + const expectedCode = r"""#include +#include +#include +#include +struct ResponseData { + char *data; + size_t size; +}; + +size_t write_callback(char *ptr, size_t size, size_t nmemb, void *userdata) { + struct ResponseData *response_data = (struct ResponseData *)userdata; + size_t real_size = size * nmemb; + + response_data->data = realloc(response_data->data, response_data->size + real_size + 1); + if (response_data->data == NULL) { + fprintf(stderr, "Memory allocation failed\n"); + return 0; + } + + memcpy(&(response_data->data[response_data->size]), ptr, real_size); + response_data->size += real_size; + response_data->data[response_data->size] = 0; + + return real_size; +} +int main() { + CURL *curl; + CURLcode res; + curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PUT"); + curl_easy_setopt(curl, CURLOPT_URL, "https://reqres.in/api/users/2"); + struct curl_slist *headers = NULL; + headers = curl_slist_append(headers,"Content-Type: application/json"); + + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); + const char *data = "{\n\"name\": \"morpheus\",\n\"job\": \"zion resident\"\n}"; + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data); + + + struct ResponseData response_data = {0}; + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response_data); + res = curl_easy_perform(curl); + long response_code; + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code); + printf("Response code: %ld\n", response_code); + printf("Response body: %s\n", response_data.data); + free(response_data.data); + curl_slist_free_all(headers); + } + curl_easy_cleanup(curl); + return 0; +}"""; + expect( + codeGen.getCode( + CodegenLanguage.cCurlCodeGen, requestModelPut1, "https"), + expectedCode); + }); + }); + + group('PATCH Request', () { + test('PATCH 1', () { + const expectedCode = r"""#include +#include +#include +#include +struct ResponseData { + char *data; + size_t size; +}; + +size_t write_callback(char *ptr, size_t size, size_t nmemb, void *userdata) { + struct ResponseData *response_data = (struct ResponseData *)userdata; + size_t real_size = size * nmemb; + + response_data->data = realloc(response_data->data, response_data->size + real_size + 1); + if (response_data->data == NULL) { + fprintf(stderr, "Memory allocation failed\n"); + return 0; + } + + memcpy(&(response_data->data[response_data->size]), ptr, real_size); + response_data->size += real_size; + response_data->data[response_data->size] = 0; + + return real_size; +} +int main() { + CURL *curl; + CURLcode res; + curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PATCH"); + curl_easy_setopt(curl, CURLOPT_URL, "https://reqres.in/api/users/2"); + struct curl_slist *headers = NULL; + headers = curl_slist_append(headers,"Content-Type: application/json"); + + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); + const char *data = "{\n\"name\": \"marfeus\",\n\"job\": \"accountant\"\n}"; + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data); + + + struct ResponseData response_data = {0}; + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response_data); + res = curl_easy_perform(curl); + long response_code; + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code); + printf("Response code: %ld\n", response_code); + printf("Response body: %s\n", response_data.data); + free(response_data.data); + curl_slist_free_all(headers); + } + curl_easy_cleanup(curl); + return 0; +}"""; + expect( + codeGen.getCode( + CodegenLanguage.cCurlCodeGen, requestModelPatch1, "https"), + expectedCode); + }); + }); + + group('DELETE Request', () { + test('DELETE 1', () { + const expectedCode = r"""#include +#include +#include +#include +struct ResponseData { + char *data; + size_t size; +}; + +size_t write_callback(char *ptr, size_t size, size_t nmemb, void *userdata) { + struct ResponseData *response_data = (struct ResponseData *)userdata; + size_t real_size = size * nmemb; + + response_data->data = realloc(response_data->data, response_data->size + real_size + 1); + if (response_data->data == NULL) { + fprintf(stderr, "Memory allocation failed\n"); + return 0; + } + + memcpy(&(response_data->data[response_data->size]), ptr, real_size); + response_data->size += real_size; + response_data->data[response_data->size] = 0; + + return real_size; +} +int main() { + CURL *curl; + CURLcode res; + curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "DELETE"); + curl_easy_setopt(curl, CURLOPT_URL, "https://reqres.in/api/users/2"); + struct ResponseData response_data = {0}; + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response_data); + res = curl_easy_perform(curl); + long response_code; + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code); + printf("Response code: %ld\n", response_code); + printf("Response body: %s\n", response_data.data); + free(response_data.data); + } + curl_easy_cleanup(curl); + return 0; +}"""; + expect( + codeGen.getCode( + CodegenLanguage.cCurlCodeGen, requestModelDelete1, "https"), + expectedCode); + }); + + test('DELETE 2', () { + const expectedCode = r"""#include +#include +#include +#include +struct ResponseData { + char *data; + size_t size; +}; + +size_t write_callback(char *ptr, size_t size, size_t nmemb, void *userdata) { + struct ResponseData *response_data = (struct ResponseData *)userdata; + size_t real_size = size * nmemb; + + response_data->data = realloc(response_data->data, response_data->size + real_size + 1); + if (response_data->data == NULL) { + fprintf(stderr, "Memory allocation failed\n"); + return 0; + } + + memcpy(&(response_data->data[response_data->size]), ptr, real_size); + response_data->size += real_size; + response_data->data[response_data->size] = 0; + + return real_size; +} +int main() { + CURL *curl; + CURLcode res; + curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "DELETE"); + curl_easy_setopt(curl, CURLOPT_URL, "https://reqres.in/api/users/2"); + struct curl_slist *headers = NULL; + headers = curl_slist_append(headers,"Content-Type: application/json"); + + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); + const char *data = "{\n\"name\": \"marfeus\",\n\"job\": \"accountant\"\n}"; + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data); + + + struct ResponseData response_data = {0}; + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response_data); + res = curl_easy_perform(curl); + long response_code; + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code); + printf("Response code: %ld\n", response_code); + printf("Response body: %s\n", response_data.data); + free(response_data.data); + curl_slist_free_all(headers); + } + curl_easy_cleanup(curl); + return 0; +}"""; + expect( + codeGen.getCode( + CodegenLanguage.cCurlCodeGen, requestModelDelete2, "https"), + expectedCode); + }); + }); +} diff --git a/test/codegen/csharp_rest_sharp_codgen_test.dart b/test/codegen/csharp_rest_sharp_codgen_test.dart new file mode 100644 index 00000000..7f35beeb --- /dev/null +++ b/test/codegen/csharp_rest_sharp_codgen_test.dart @@ -0,0 +1,982 @@ +import 'package:apidash/consts.dart'; +import 'package:apidash/screens/home_page/editor_pane/details_card/code_pane.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import '../request_models.dart'; + +void main() { + group("Get Request Test", () { + test("Get 1", () { + const expectedCode = r""" +using System; +using RestSharp; +using System.Threading.Tasks; + +class Program +{ + static async Task Main(){ + try{ + const String _baseUrl = "https://api.apidash.dev"; + var client = new RestClient(_baseUrl); + + var request = new RestRequest("", Method.Get); + + var response = await client.ExecuteAsync(request); + Console.WriteLine("Status Code: " + (int)response.StatusCode); + Console.WriteLine("Response Content: " + response.Content); + } + catch(Exception ex){ + Console.WriteLine("Error: " + ex); + } + } +} +"""; + expect( + codegen.getCode( + CodegenLanguage.cSharpRestSharp, requestModelGet1, "https"), + expectedCode); + }); + + test("Get 2", () { + const expectedCode = r""" +using System; +using RestSharp; +using System.Threading.Tasks; + +class Program +{ + static async Task Main(){ + try{ + const String _baseUrl = "https://api.apidash.dev"; + var client = new RestClient(_baseUrl); + + var request = new RestRequest("/country/data", Method.Get); + + request.AddQueryParameter("code", "US"); + + var response = await client.ExecuteAsync(request); + Console.WriteLine("Status Code: " + (int)response.StatusCode); + Console.WriteLine("Response Content: " + response.Content); + } + catch(Exception ex){ + Console.WriteLine("Error: " + ex); + } + } +} +"""; + + expect( + codegen.getCode( + CodegenLanguage.cSharpRestSharp, requestModelGet2, "https"), + expectedCode); + }); + + test("Get 3", () { + const expectedCode = r""" +using System; +using RestSharp; +using System.Threading.Tasks; + +class Program +{ + static async Task Main(){ + try{ + const String _baseUrl = "https://api.apidash.dev"; + var client = new RestClient(_baseUrl); + + var request = new RestRequest("/country/data", Method.Get); + + request.AddQueryParameter("code", "IND"); + + var response = await client.ExecuteAsync(request); + Console.WriteLine("Status Code: " + (int)response.StatusCode); + Console.WriteLine("Response Content: " + response.Content); + } + catch(Exception ex){ + Console.WriteLine("Error: " + ex); + } + } +} +"""; + + expect( + codegen.getCode( + CodegenLanguage.cSharpRestSharp, requestModelGet3, "https"), + expectedCode); + }); + + test("Get 4", () { + const expectedCode = r""" +using System; +using RestSharp; +using System.Threading.Tasks; + +class Program +{ + static async Task Main(){ + try{ + const String _baseUrl = "https://api.apidash.dev"; + var client = new RestClient(_baseUrl); + + var request = new RestRequest("/humanize/social", Method.Get); + + request.AddQueryParameter("num", "8700000"); + request.AddQueryParameter("digits", "3"); + request.AddQueryParameter("system", "SS"); + request.AddQueryParameter("add_space", "true"); + request.AddQueryParameter("trailing_zeros", "true"); + + var response = await client.ExecuteAsync(request); + Console.WriteLine("Status Code: " + (int)response.StatusCode); + Console.WriteLine("Response Content: " + response.Content); + } + catch(Exception ex){ + Console.WriteLine("Error: " + ex); + } + } +} +"""; + + expect( + codegen.getCode( + CodegenLanguage.cSharpRestSharp, requestModelGet4, "https"), + expectedCode); + }); + + test("Get 5", () { + const expectedCode = r""" +using System; +using RestSharp; +using System.Threading.Tasks; + +class Program +{ + static async Task Main(){ + try{ + const String _baseUrl = "https://api.github.com"; + var client = new RestClient(_baseUrl); + + var request = new RestRequest("/repos/foss42/apidash", Method.Get); + + request.AddHeader("User-Agent", "Test Agent"); + + var response = await client.ExecuteAsync(request); + Console.WriteLine("Status Code: " + (int)response.StatusCode); + Console.WriteLine("Response Content: " + response.Content); + } + catch(Exception ex){ + Console.WriteLine("Error: " + ex); + } + } +} +"""; + + expect( + codegen.getCode( + CodegenLanguage.cSharpRestSharp, requestModelGet5, "https"), + expectedCode); + }); + + test("Get 6", () { + const expectedCode = r""" +using System; +using RestSharp; +using System.Threading.Tasks; + +class Program +{ + static async Task Main(){ + try{ + const String _baseUrl = "https://api.github.com"; + var client = new RestClient(_baseUrl); + + var request = new RestRequest("/repos/foss42/apidash", Method.Get); + + request.AddQueryParameter("raw", "true"); + + request.AddHeader("User-Agent", "Test Agent"); + + var response = await client.ExecuteAsync(request); + Console.WriteLine("Status Code: " + (int)response.StatusCode); + Console.WriteLine("Response Content: " + response.Content); + } + catch(Exception ex){ + Console.WriteLine("Error: " + ex); + } + } +} +"""; + + expect( + codegen.getCode( + CodegenLanguage.cSharpRestSharp, requestModelGet6, "https"), + expectedCode); + }); + + test("Get 7", () { + const expectedCode = r""" +using System; +using RestSharp; +using System.Threading.Tasks; + +class Program +{ + static async Task Main(){ + try{ + const String _baseUrl = "https://api.apidash.dev"; + var client = new RestClient(_baseUrl); + + var request = new RestRequest("", Method.Get); + + var response = await client.ExecuteAsync(request); + Console.WriteLine("Status Code: " + (int)response.StatusCode); + Console.WriteLine("Response Content: " + response.Content); + } + catch(Exception ex){ + Console.WriteLine("Error: " + ex); + } + } +} +"""; + + expect( + codegen.getCode( + CodegenLanguage.cSharpRestSharp, requestModelGet7, "https"), + expectedCode); + }); + + test("Get 8", () { + const expectedCode = r""" +using System; +using RestSharp; +using System.Threading.Tasks; + +class Program +{ + static async Task Main(){ + try{ + const String _baseUrl = "https://api.github.com"; + var client = new RestClient(_baseUrl); + + var request = new RestRequest("/repos/foss42/apidash", Method.Get); + + request.AddQueryParameter("raw", "true"); + + request.AddHeader("User-Agent", "Test Agent"); + + var response = await client.ExecuteAsync(request); + Console.WriteLine("Status Code: " + (int)response.StatusCode); + Console.WriteLine("Response Content: " + response.Content); + } + catch(Exception ex){ + Console.WriteLine("Error: " + ex); + } + } +} +"""; + expect( + codegen.getCode( + CodegenLanguage.cSharpRestSharp, requestModelGet8, "https"), + expectedCode); + }); + + test("Get 9", () { + const expectedCode = r""" +using System; +using RestSharp; +using System.Threading.Tasks; + +class Program +{ + static async Task Main(){ + try{ + const String _baseUrl = "https://api.apidash.dev"; + var client = new RestClient(_baseUrl); + + var request = new RestRequest("/humanize/social", Method.Get); + + request.AddQueryParameter("num", "8700000"); + request.AddQueryParameter("add_space", "true"); + + var response = await client.ExecuteAsync(request); + Console.WriteLine("Status Code: " + (int)response.StatusCode); + Console.WriteLine("Response Content: " + response.Content); + } + catch(Exception ex){ + Console.WriteLine("Error: " + ex); + } + } +} +"""; + expect( + codegen.getCode( + CodegenLanguage.cSharpRestSharp, requestModelGet9, "https"), + expectedCode); + }); + + test("Get 10", () { + const expectedCode = r""" +using System; +using RestSharp; +using System.Threading.Tasks; + +class Program +{ + static async Task Main(){ + try{ + const String _baseUrl = "https://api.apidash.dev"; + var client = new RestClient(_baseUrl); + + var request = new RestRequest("/humanize/social", Method.Get); + + request.AddHeader("User-Agent", "Test Agent"); + + var response = await client.ExecuteAsync(request); + Console.WriteLine("Status Code: " + (int)response.StatusCode); + Console.WriteLine("Response Content: " + response.Content); + } + catch(Exception ex){ + Console.WriteLine("Error: " + ex); + } + } +} +"""; + expect( + codegen.getCode( + CodegenLanguage.cSharpRestSharp, requestModelGet10, "https"), + expectedCode); + }); + + test("Get 11", () { + const expectedCode = r""" +using System; +using RestSharp; +using System.Threading.Tasks; + +class Program +{ + static async Task Main(){ + try{ + const String _baseUrl = "https://api.apidash.dev"; + var client = new RestClient(_baseUrl); + + var request = new RestRequest("/humanize/social", Method.Get); + + request.AddQueryParameter("num", "8700000"); + request.AddQueryParameter("digits", "3"); + + request.AddHeader("User-Agent", "Test Agent"); + + var response = await client.ExecuteAsync(request); + Console.WriteLine("Status Code: " + (int)response.StatusCode); + Console.WriteLine("Response Content: " + response.Content); + } + catch(Exception ex){ + Console.WriteLine("Error: " + ex); + } + } +} +"""; + expect( + codegen.getCode( + CodegenLanguage.cSharpRestSharp, requestModelGet11, "https"), + expectedCode); + }); + + test("Get 12", () { + const expectedCode = r""" +using System; +using RestSharp; +using System.Threading.Tasks; + +class Program +{ + static async Task Main(){ + try{ + const String _baseUrl = "https://api.apidash.dev"; + var client = new RestClient(_baseUrl); + + var request = new RestRequest("/humanize/social", Method.Get); + + var response = await client.ExecuteAsync(request); + Console.WriteLine("Status Code: " + (int)response.StatusCode); + Console.WriteLine("Response Content: " + response.Content); + } + catch(Exception ex){ + Console.WriteLine("Error: " + ex); + } + } +} +"""; + expect( + codegen.getCode( + CodegenLanguage.cSharpRestSharp, requestModelGet12, "https"), + expectedCode); + }); + }); + + group("Head Request Test", () { + test("Head 1", () { + const expectedCode = r""" +using System; +using RestSharp; +using System.Threading.Tasks; + +class Program +{ + static async Task Main(){ + try{ + const String _baseUrl = "https://api.apidash.dev"; + var client = new RestClient(_baseUrl); + + var request = new RestRequest("", Method.Head); + + var response = await client.ExecuteAsync(request); + Console.WriteLine("Status Code: " + (int)response.StatusCode); + Console.WriteLine("Response Content: " + response.Content); + } + catch(Exception ex){ + Console.WriteLine("Error: " + ex); + } + } +} +"""; + expect( + codegen.getCode( + CodegenLanguage.cSharpRestSharp, requestModelHead1, "https"), + expectedCode); + }); + + test("Head 2", () { + const expectedCode = r""" +using System; +using RestSharp; +using System.Threading.Tasks; + +class Program +{ + static async Task Main(){ + try{ + const String _baseUrl = "http://api.apidash.dev"; + var client = new RestClient(_baseUrl); + + var request = new RestRequest("", Method.Head); + + var response = await client.ExecuteAsync(request); + Console.WriteLine("Status Code: " + (int)response.StatusCode); + Console.WriteLine("Response Content: " + response.Content); + } + catch(Exception ex){ + Console.WriteLine("Error: " + ex); + } + } +} +"""; + expect( + codegen.getCode( + CodegenLanguage.cSharpRestSharp, requestModelHead2, "http"), + expectedCode); + }); + }); + + group("Post Request Test", () { + test("Post 1", () { + const expectedCode = r""" +using System; +using RestSharp; +using System.Threading.Tasks; + +class Program +{ + static async Task Main(){ + try{ + const String _baseUrl = "https://api.apidash.dev"; + var client = new RestClient(_baseUrl); + + var request = new RestRequest("/case/lower", Method.Post); + + request.AddHeader("Content-Type", "text/plain"); + + var textBody = "{\n\"text\": \"I LOVE Flutter\"\n}"; + request.AddStringBody(textBody, ContentType.Plain); + + var response = await client.ExecuteAsync(request); + Console.WriteLine("Status Code: " + (int)response.StatusCode); + Console.WriteLine("Response Content: " + response.Content); + } + catch(Exception ex){ + Console.WriteLine("Error: " + ex); + } + } +} +"""; + expect( + codegen.getCode( + CodegenLanguage.cSharpRestSharp, requestModelPost1, "https"), + expectedCode); + }); + test("Post 2", () { + const expectedCode = """ +using System; +using RestSharp; +using System.Threading.Tasks; + +class Program +{ + static async Task Main(){ + try{ + const String _baseUrl = "https://api.apidash.dev"; + var client = new RestClient(_baseUrl); + + var request = new RestRequest("/case/lower", Method.Post); + + request.AddHeader("Content-Type", "application/json"); + + var jsonBody = new { +text = "I LOVE Flutter", +flag = "null", +male = "true", +female = "false", +no = "1.2", +arr = "[null, true, false, null]" +}; + request.AddJsonBody(jsonBody); + + var response = await client.ExecuteAsync(request); + Console.WriteLine("Status Code: " + (int)response.StatusCode); + Console.WriteLine("Response Content: " + response.Content); + } + catch(Exception ex){ + Console.WriteLine("Error: " + ex); + } + } +} +"""; + expect( + codegen.getCode( + CodegenLanguage.cSharpRestSharp, requestModelPost2, "https"), + expectedCode); + }); + test("Post 3", () { + const expectedCode = """ +using System; +using RestSharp; +using System.Threading.Tasks; + +class Program +{ + static async Task Main(){ + try{ + const String _baseUrl = "https://api.apidash.dev"; + var client = new RestClient(_baseUrl); + + var request = new RestRequest("/case/lower", Method.Post); + + request.AddHeader("User-Agent", "Test Agent"); + request.AddHeader("Content-Type", "application/json"); + + var jsonBody = new { +text = "I LOVE Flutter" +}; + request.AddJsonBody(jsonBody); + + var response = await client.ExecuteAsync(request); + Console.WriteLine("Status Code: " + (int)response.StatusCode); + Console.WriteLine("Response Content: " + response.Content); + } + catch(Exception ex){ + Console.WriteLine("Error: " + ex); + } + } +} +"""; + expect( + codegen.getCode( + CodegenLanguage.cSharpRestSharp, requestModelPost3, "https"), + expectedCode); + }); + test("Post 4", () { + const expectedCode = r""" +using System; +using RestSharp; +using System.Threading.Tasks; + +class Program +{ + static async Task Main(){ + try{ + const String _baseUrl = "https://api.apidash.dev"; + var client = new RestClient(_baseUrl); + + var request = new RestRequest("/io/form", Method.Post); + + request.AlwaysMultipartFormData = true; + request.AddParameter("text", "API", ParameterType.GetOrPost); + request.AddParameter("sep", "|", ParameterType.GetOrPost); + request.AddParameter("times", "3", ParameterType.GetOrPost); + + var response = await client.ExecuteAsync(request); + Console.WriteLine("Status Code: " + (int)response.StatusCode); + Console.WriteLine("Response Content: " + response.Content); + } + catch(Exception ex){ + Console.WriteLine("Error: " + ex); + } + } +} +"""; + expect( + codegen.getCode( + CodegenLanguage.cSharpRestSharp, requestModelPost4, "https"), + expectedCode); + }); + test("Post 5", () { + const expectedCode = r""" +using System; +using RestSharp; +using System.Threading.Tasks; + +class Program +{ + static async Task Main(){ + try{ + const String _baseUrl = "https://api.apidash.dev"; + var client = new RestClient(_baseUrl); + + var request = new RestRequest("/io/form", Method.Post); + + request.AddHeader("User-Agent", "Test Agent"); + + request.AlwaysMultipartFormData = true; + request.AddParameter("text", "API", ParameterType.GetOrPost); + request.AddParameter("sep", "|", ParameterType.GetOrPost); + request.AddParameter("times", "3", ParameterType.GetOrPost); + + var response = await client.ExecuteAsync(request); + Console.WriteLine("Status Code: " + (int)response.StatusCode); + Console.WriteLine("Response Content: " + response.Content); + } + catch(Exception ex){ + Console.WriteLine("Error: " + ex); + } + } +} +"""; + expect( + codegen.getCode( + CodegenLanguage.cSharpRestSharp, requestModelPost5, "https"), + expectedCode); + }); + test("Post 6", () { + const expectedCode = r""" +using System; +using RestSharp; +using System.Threading.Tasks; + +class Program +{ + static async Task Main(){ + try{ + const String _baseUrl = "https://api.apidash.dev"; + var client = new RestClient(_baseUrl); + + var request = new RestRequest("/io/img", Method.Post); + + request.AlwaysMultipartFormData = true; + var options = new FileParameterOptions + { + DisableFilenameEncoding = true + }; + request.AddParameter("token", "xyz", ParameterType.GetOrPost); + request.AddFile("imfile", "/Documents/up/1.png", options: options); + + var response = await client.ExecuteAsync(request); + Console.WriteLine("Status Code: " + (int)response.StatusCode); + Console.WriteLine("Response Content: " + response.Content); + } + catch(Exception ex){ + Console.WriteLine("Error: " + ex); + } + } +} +"""; + expect( + codegen.getCode( + CodegenLanguage.cSharpRestSharp, requestModelPost6, "https"), + expectedCode); + }); + test("Post 7", () { + const expectedCode = r""" +using System; +using RestSharp; +using System.Threading.Tasks; + +class Program +{ + static async Task Main(){ + try{ + const String _baseUrl = "https://api.apidash.dev"; + var client = new RestClient(_baseUrl); + + var request = new RestRequest("/io/img", Method.Post); + + request.AlwaysMultipartFormData = true; + var options = new FileParameterOptions + { + DisableFilenameEncoding = true + }; + request.AddParameter("token", "xyz", ParameterType.GetOrPost); + request.AddFile("imfile", "/Documents/up/1.png", options: options); + + var response = await client.ExecuteAsync(request); + Console.WriteLine("Status Code: " + (int)response.StatusCode); + Console.WriteLine("Response Content: " + response.Content); + } + catch(Exception ex){ + Console.WriteLine("Error: " + ex); + } + } +} +"""; + expect( + codegen.getCode( + CodegenLanguage.cSharpRestSharp, requestModelPost7, "https"), + expectedCode); + }); + test("Post 8", () { + const expectedCode = r""" +using System; +using RestSharp; +using System.Threading.Tasks; + +class Program +{ + static async Task Main(){ + try{ + const String _baseUrl = "https://api.apidash.dev"; + var client = new RestClient(_baseUrl); + + var request = new RestRequest("/io/form", Method.Post); + + request.AddQueryParameter("size", "2"); + request.AddQueryParameter("len", "3"); + + request.AlwaysMultipartFormData = true; + request.AddParameter("text", "API", ParameterType.GetOrPost); + request.AddParameter("sep", "|", ParameterType.GetOrPost); + request.AddParameter("times", "3", ParameterType.GetOrPost); + + var response = await client.ExecuteAsync(request); + Console.WriteLine("Status Code: " + (int)response.StatusCode); + Console.WriteLine("Response Content: " + response.Content); + } + catch(Exception ex){ + Console.WriteLine("Error: " + ex); + } + } +} +"""; + expect( + codegen.getCode( + CodegenLanguage.cSharpRestSharp, requestModelPost8, "https"), + expectedCode); + }); + test("Post 9", () { + const expectedCode = r""" +using System; +using RestSharp; +using System.Threading.Tasks; + +class Program +{ + static async Task Main(){ + try{ + const String _baseUrl = "https://api.apidash.dev"; + var client = new RestClient(_baseUrl); + + var request = new RestRequest("/io/img", Method.Post); + + request.AddQueryParameter("size", "2"); + request.AddQueryParameter("len", "3"); + + request.AddHeader("User-Agent", "Test Agent"); + request.AddHeader("Keep-Alive", "true"); + + request.AlwaysMultipartFormData = true; + var options = new FileParameterOptions + { + DisableFilenameEncoding = true + }; + request.AddParameter("token", "xyz", ParameterType.GetOrPost); + request.AddFile("imfile", "/Documents/up/1.png", options: options); + + var response = await client.ExecuteAsync(request); + Console.WriteLine("Status Code: " + (int)response.StatusCode); + Console.WriteLine("Response Content: " + response.Content); + } + catch(Exception ex){ + Console.WriteLine("Error: " + ex); + } + } +} +"""; + expect( + codegen.getCode( + CodegenLanguage.cSharpRestSharp, requestModelPost9, "https"), + expectedCode); + }); + }); + + group("Put Request Test", () { + test("Put 1", () { + const expectedCode = """ +using System; +using RestSharp; +using System.Threading.Tasks; + +class Program +{ + static async Task Main(){ + try{ + const String _baseUrl = "https://reqres.in"; + var client = new RestClient(_baseUrl); + + var request = new RestRequest("/api/users/2", Method.Put); + + request.AddHeader("Content-Type", "application/json"); + + var jsonBody = new { +name = "morpheus", +job = "zion resident" +}; + request.AddJsonBody(jsonBody); + + var response = await client.ExecuteAsync(request); + Console.WriteLine("Status Code: " + (int)response.StatusCode); + Console.WriteLine("Response Content: " + response.Content); + } + catch(Exception ex){ + Console.WriteLine("Error: " + ex); + } + } +} +"""; + expect( + codegen.getCode( + CodegenLanguage.cSharpRestSharp, requestModelPut1, "https"), + expectedCode); + }); + }); + + group("Patch Request Test", () { + test("Patch 1", () { + const expectedCode = """ +using System; +using RestSharp; +using System.Threading.Tasks; + +class Program +{ + static async Task Main(){ + try{ + const String _baseUrl = "https://reqres.in"; + var client = new RestClient(_baseUrl); + + var request = new RestRequest("/api/users/2", Method.Patch); + + request.AddHeader("Content-Type", "application/json"); + + var jsonBody = new { +name = "marfeus", +job = "accountant" +}; + request.AddJsonBody(jsonBody); + + var response = await client.ExecuteAsync(request); + Console.WriteLine("Status Code: " + (int)response.StatusCode); + Console.WriteLine("Response Content: " + response.Content); + } + catch(Exception ex){ + Console.WriteLine("Error: " + ex); + } + } +} +"""; + expect( + codegen.getCode( + CodegenLanguage.cSharpRestSharp, requestModelPatch1, "https"), + expectedCode); + }); + }); + + group("Delete Request Test", () { + test("Delete 1", () { + const expectedCode = """ +using System; +using RestSharp; +using System.Threading.Tasks; + +class Program +{ + static async Task Main(){ + try{ + const String _baseUrl = "https://reqres.in"; + var client = new RestClient(_baseUrl); + + var request = new RestRequest("/api/users/2", Method.Delete); + + var response = await client.ExecuteAsync(request); + Console.WriteLine("Status Code: " + (int)response.StatusCode); + Console.WriteLine("Response Content: " + response.Content); + } + catch(Exception ex){ + Console.WriteLine("Error: " + ex); + } + } +} +"""; + expect( + codegen.getCode( + CodegenLanguage.cSharpRestSharp, requestModelDelete1, "https"), + expectedCode); + }); + test("Delete 2", () { + const expectedCode = """ +using System; +using RestSharp; +using System.Threading.Tasks; + +class Program +{ + static async Task Main(){ + try{ + const String _baseUrl = "https://reqres.in"; + var client = new RestClient(_baseUrl); + + var request = new RestRequest("/api/users/2", Method.Delete); + + request.AddHeader("Content-Type", "application/json"); + + var jsonBody = new { +name = "marfeus", +job = "accountant" +}; + request.AddJsonBody(jsonBody); + + var response = await client.ExecuteAsync(request); + Console.WriteLine("Status Code: " + (int)response.StatusCode); + Console.WriteLine("Response Content: " + response.Content); + } + catch(Exception ex){ + Console.WriteLine("Error: " + ex); + } + } +} +"""; + expect( + codegen.getCode( + CodegenLanguage.cSharpRestSharp, requestModelDelete2, "https"), + expectedCode); + }); + }); +} diff --git a/test/codegen/java_httpclient_codegen_test.dart b/test/codegen/java_httpclient_codegen_test.dart new file mode 100644 index 00000000..d279f5ab --- /dev/null +++ b/test/codegen/java_httpclient_codegen_test.dart @@ -0,0 +1,1109 @@ +import 'package:apidash/codegen/codegen.dart'; +import 'package:apidash/consts.dart'; +import 'package:test/test.dart'; +import '../request_models.dart'; + +void main() { + final codeGen = Codegen(); + + group('GET Request', () { + test('GET1', () { + const expectedCode = r''' +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.io.IOException; + +public class Main { + public static void main(String[] args) { + try { + HttpClient client = HttpClient.newHttpClient(); + URI uri = URI.create("https://api.apidash.dev"); + + HttpRequest.Builder requestBuilder = HttpRequest.newBuilder(uri).GET(); + HttpResponse response = client.send(requestBuilder.build(), HttpResponse.BodyHandlers.ofString()); + System.out.println("Response body: " + response.body()); + System.out.println("Response code: " + response.statusCode()); + } catch (IOException | InterruptedException e) { + System.out.println("An error occurred: " + e.getMessage()); + } + } + +}'''; + expect( + codeGen.getCode( + CodegenLanguage.javaHttpClient, requestModelGet1, "https"), + expectedCode); + }); + test('GET2', () { + const expectedCode = r''' +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.io.IOException; + +public class Main { + public static void main(String[] args) { + try { + HttpClient client = HttpClient.newHttpClient(); + URI uri = URI.create("https://api.apidash.dev/country/data?code=US"); + + HttpRequest.Builder requestBuilder = HttpRequest.newBuilder(uri).GET(); + HttpResponse response = client.send(requestBuilder.build(), HttpResponse.BodyHandlers.ofString()); + System.out.println("Response body: " + response.body()); + System.out.println("Response code: " + response.statusCode()); + } catch (IOException | InterruptedException e) { + System.out.println("An error occurred: " + e.getMessage()); + } + } + +}'''; + expect( + codeGen.getCode( + CodegenLanguage.javaHttpClient, requestModelGet2, "https"), + expectedCode); + }); + test('GET3', () { + const expectedCode = r''' +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.io.IOException; + +public class Main { + public static void main(String[] args) { + try { + HttpClient client = HttpClient.newHttpClient(); + URI uri = URI.create("https://api.apidash.dev/country/data?code=IND"); + + HttpRequest.Builder requestBuilder = HttpRequest.newBuilder(uri).GET(); + HttpResponse response = client.send(requestBuilder.build(), HttpResponse.BodyHandlers.ofString()); + System.out.println("Response body: " + response.body()); + System.out.println("Response code: " + response.statusCode()); + } catch (IOException | InterruptedException e) { + System.out.println("An error occurred: " + e.getMessage()); + } + } + +}'''; + expect( + codeGen.getCode( + CodegenLanguage.javaHttpClient, requestModelGet3, "https"), + expectedCode); + }); + test('GET4', () { + const expectedCode = r''' +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.io.IOException; + +public class Main { + public static void main(String[] args) { + try { + HttpClient client = HttpClient.newHttpClient(); + URI uri = URI.create("https://api.apidash.dev/humanize/social?num=8700000&digits=3&system=SS&add_space=true&trailing_zeros=true"); + + HttpRequest.Builder requestBuilder = HttpRequest.newBuilder(uri).GET(); + HttpResponse response = client.send(requestBuilder.build(), HttpResponse.BodyHandlers.ofString()); + System.out.println("Response body: " + response.body()); + System.out.println("Response code: " + response.statusCode()); + } catch (IOException | InterruptedException e) { + System.out.println("An error occurred: " + e.getMessage()); + } + } + +}'''; + expect( + codeGen.getCode( + CodegenLanguage.javaHttpClient, requestModelGet4, "https"), + expectedCode); + }); + test('GET5', () { + const expectedCode = r''' +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.io.IOException; + +public class Main { + public static void main(String[] args) { + try { + HttpClient client = HttpClient.newHttpClient(); + URI uri = URI.create("https://api.github.com/repos/foss42/apidash"); + + HttpRequest.Builder requestBuilder = HttpRequest.newBuilder(uri).GET(); + requestBuilder = requestBuilder.headers( + "User-Agent", "Test Agent" + ); + HttpResponse response = client.send(requestBuilder.build(), HttpResponse.BodyHandlers.ofString()); + System.out.println("Response body: " + response.body()); + System.out.println("Response code: " + response.statusCode()); + } catch (IOException | InterruptedException e) { + System.out.println("An error occurred: " + e.getMessage()); + } + } + +}'''; + expect( + codeGen.getCode( + CodegenLanguage.javaHttpClient, requestModelGet5, "https"), + expectedCode); + }); + test('GET6', () { + const expectedCode = r''' +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.io.IOException; + +public class Main { + public static void main(String[] args) { + try { + HttpClient client = HttpClient.newHttpClient(); + URI uri = URI.create("https://api.github.com/repos/foss42/apidash?raw=true"); + + HttpRequest.Builder requestBuilder = HttpRequest.newBuilder(uri).GET(); + requestBuilder = requestBuilder.headers( + "User-Agent", "Test Agent" + ); + HttpResponse response = client.send(requestBuilder.build(), HttpResponse.BodyHandlers.ofString()); + System.out.println("Response body: " + response.body()); + System.out.println("Response code: " + response.statusCode()); + } catch (IOException | InterruptedException e) { + System.out.println("An error occurred: " + e.getMessage()); + } + } + +}'''; + expect( + codeGen.getCode( + CodegenLanguage.javaHttpClient, requestModelGet6, "https"), + expectedCode); + }); + test('GET7', () { + const expectedCode = r''' +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.io.IOException; + +public class Main { + public static void main(String[] args) { + try { + HttpClient client = HttpClient.newHttpClient(); + URI uri = URI.create("https://api.apidash.dev"); + + HttpRequest.Builder requestBuilder = HttpRequest.newBuilder(uri).GET(); + HttpResponse response = client.send(requestBuilder.build(), HttpResponse.BodyHandlers.ofString()); + System.out.println("Response body: " + response.body()); + System.out.println("Response code: " + response.statusCode()); + } catch (IOException | InterruptedException e) { + System.out.println("An error occurred: " + e.getMessage()); + } + } + +}'''; + expect( + codeGen.getCode( + CodegenLanguage.javaHttpClient, requestModelGet7, "https"), + expectedCode); + }); + test('GET8', () { + const expectedCode = r''' +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.io.IOException; + +public class Main { + public static void main(String[] args) { + try { + HttpClient client = HttpClient.newHttpClient(); + URI uri = URI.create("https://api.github.com/repos/foss42/apidash?raw=true"); + + HttpRequest.Builder requestBuilder = HttpRequest.newBuilder(uri).GET(); + requestBuilder = requestBuilder.headers( + "User-Agent", "Test Agent" + ); + HttpResponse response = client.send(requestBuilder.build(), HttpResponse.BodyHandlers.ofString()); + System.out.println("Response body: " + response.body()); + System.out.println("Response code: " + response.statusCode()); + } catch (IOException | InterruptedException e) { + System.out.println("An error occurred: " + e.getMessage()); + } + } + +}'''; + expect( + codeGen.getCode( + CodegenLanguage.javaHttpClient, requestModelGet8, "https"), + expectedCode); + }); + test('GET9', () { + const expectedCode = r''' +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.io.IOException; + +public class Main { + public static void main(String[] args) { + try { + HttpClient client = HttpClient.newHttpClient(); + URI uri = URI.create("https://api.apidash.dev/humanize/social?num=8700000&add_space=true"); + + HttpRequest.Builder requestBuilder = HttpRequest.newBuilder(uri).GET(); + HttpResponse response = client.send(requestBuilder.build(), HttpResponse.BodyHandlers.ofString()); + System.out.println("Response body: " + response.body()); + System.out.println("Response code: " + response.statusCode()); + } catch (IOException | InterruptedException e) { + System.out.println("An error occurred: " + e.getMessage()); + } + } + +}'''; + expect( + codeGen.getCode( + CodegenLanguage.javaHttpClient, requestModelGet9, "https"), + expectedCode); + }); + test('GET10', () { + const expectedCode = r''' +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.io.IOException; + +public class Main { + public static void main(String[] args) { + try { + HttpClient client = HttpClient.newHttpClient(); + URI uri = URI.create("https://api.apidash.dev/humanize/social"); + + HttpRequest.Builder requestBuilder = HttpRequest.newBuilder(uri).GET(); + requestBuilder = requestBuilder.headers( + "User-Agent", "Test Agent" + ); + HttpResponse response = client.send(requestBuilder.build(), HttpResponse.BodyHandlers.ofString()); + System.out.println("Response body: " + response.body()); + System.out.println("Response code: " + response.statusCode()); + } catch (IOException | InterruptedException e) { + System.out.println("An error occurred: " + e.getMessage()); + } + } + +}'''; + expect( + codeGen.getCode( + CodegenLanguage.javaHttpClient, requestModelGet10, "https"), + expectedCode); + }); + test('GET11', () { + const expectedCode = r''' +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.io.IOException; + +public class Main { + public static void main(String[] args) { + try { + HttpClient client = HttpClient.newHttpClient(); + URI uri = URI.create("https://api.apidash.dev/humanize/social?num=8700000&digits=3"); + + HttpRequest.Builder requestBuilder = HttpRequest.newBuilder(uri).GET(); + requestBuilder = requestBuilder.headers( + "User-Agent", "Test Agent" + ); + HttpResponse response = client.send(requestBuilder.build(), HttpResponse.BodyHandlers.ofString()); + System.out.println("Response body: " + response.body()); + System.out.println("Response code: " + response.statusCode()); + } catch (IOException | InterruptedException e) { + System.out.println("An error occurred: " + e.getMessage()); + } + } + +}'''; + expect( + codeGen.getCode( + CodegenLanguage.javaHttpClient, requestModelGet11, "https"), + expectedCode); + }); + test('GET12', () { + const expectedCode = r''' +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.io.IOException; + +public class Main { + public static void main(String[] args) { + try { + HttpClient client = HttpClient.newHttpClient(); + URI uri = URI.create("https://api.apidash.dev/humanize/social"); + + HttpRequest.Builder requestBuilder = HttpRequest.newBuilder(uri).GET(); + HttpResponse response = client.send(requestBuilder.build(), HttpResponse.BodyHandlers.ofString()); + System.out.println("Response body: " + response.body()); + System.out.println("Response code: " + response.statusCode()); + } catch (IOException | InterruptedException e) { + System.out.println("An error occurred: " + e.getMessage()); + } + } + +}'''; + expect( + codeGen.getCode( + CodegenLanguage.javaHttpClient, requestModelGet12, "https"), + expectedCode); + }); + }); + + group('HEAD Request', () { + test('HEAD1', () { + const expectedCode = r''' +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.io.IOException; + +public class Main { + public static void main(String[] args) { + try { + HttpClient client = HttpClient.newHttpClient(); + URI uri = URI.create("https://api.apidash.dev"); + + HttpRequest.Builder requestBuilder = HttpRequest.newBuilder(uri).method("HEAD", HttpRequest.BodyPublishers.noBody()); + HttpResponse response = client.send(requestBuilder.build(), HttpResponse.BodyHandlers.ofString()); + System.out.println("Response body: " + response.body()); + System.out.println("Response code: " + response.statusCode()); + } catch (IOException | InterruptedException e) { + System.out.println("An error occurred: " + e.getMessage()); + } + } + +}'''; + expect( + codeGen.getCode( + CodegenLanguage.javaHttpClient, requestModelHead1, "https"), + expectedCode); + }); + test('HEAD2', () { + const expectedCode = r''' +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.io.IOException; + +public class Main { + public static void main(String[] args) { + try { + HttpClient client = HttpClient.newHttpClient(); + URI uri = URI.create("http://api.apidash.dev"); + + HttpRequest.Builder requestBuilder = HttpRequest.newBuilder(uri).method("HEAD", HttpRequest.BodyPublishers.noBody()); + HttpResponse response = client.send(requestBuilder.build(), HttpResponse.BodyHandlers.ofString()); + System.out.println("Response body: " + response.body()); + System.out.println("Response code: " + response.statusCode()); + } catch (IOException | InterruptedException e) { + System.out.println("An error occurred: " + e.getMessage()); + } + } + +}'''; + expect( + codeGen.getCode( + CodegenLanguage.javaHttpClient, requestModelHead2, "http"), + expectedCode); + }); + }); + + group('POST Request', () { + test('POST1', () { + const expectedCode = r''' +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.io.IOException; + +public class Main { + public static void main(String[] args) { + try { + HttpClient client = HttpClient.newHttpClient(); + URI uri = URI.create("https://api.apidash.dev/case/lower"); + HttpRequest.BodyPublisher bodyPublisher = HttpRequest.BodyPublishers.ofString(""" + { +"text": "I LOVE Flutter" +}"""); + HttpRequest.Builder requestBuilder = HttpRequest.newBuilder(uri).POST(bodyPublisher); + requestBuilder = requestBuilder.headers( + "Content-Type", "text/plain" + ); + HttpResponse response = client.send(requestBuilder.build(), HttpResponse.BodyHandlers.ofString()); + System.out.println("Response body: " + response.body()); + System.out.println("Response code: " + response.statusCode()); + } catch (IOException | InterruptedException e) { + System.out.println("An error occurred: " + e.getMessage()); + } + } + +}'''; + expect( + codeGen.getCode( + CodegenLanguage.javaHttpClient, requestModelPost1, "https"), + expectedCode); + }); + test('POST2', () { + const expectedCode = r''' +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.io.IOException; + +public class Main { + public static void main(String[] args) { + try { + HttpClient client = HttpClient.newHttpClient(); + URI uri = URI.create("https://api.apidash.dev/case/lower"); + HttpRequest.BodyPublisher bodyPublisher = HttpRequest.BodyPublishers.ofString(""" +{ +"text": "I LOVE Flutter", +"flag": null, +"male": true, +"female": false, +"no": 1.2, +"arr": ["null", "true", "false", null] +}"""); + HttpRequest.Builder requestBuilder = HttpRequest.newBuilder(uri).POST(bodyPublisher); + requestBuilder = requestBuilder.headers( + "Content-Type", "application/json" + ); + HttpResponse response = client.send(requestBuilder.build(), HttpResponse.BodyHandlers.ofString()); + System.out.println("Response body: " + response.body()); + System.out.println("Response code: " + response.statusCode()); + } catch (IOException | InterruptedException e) { + System.out.println("An error occurred: " + e.getMessage()); + } + } + +}'''; + expect( + codeGen.getCode( + CodegenLanguage.javaHttpClient, requestModelPost2, "https"), + expectedCode); + }); + test('POST3', () { + const expectedCode = r''' +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.io.IOException; + +public class Main { + public static void main(String[] args) { + try { + HttpClient client = HttpClient.newHttpClient(); + URI uri = URI.create("https://api.apidash.dev/case/lower"); + HttpRequest.BodyPublisher bodyPublisher = HttpRequest.BodyPublishers.ofString(""" +{ +"text": "I LOVE Flutter" +}"""); + HttpRequest.Builder requestBuilder = HttpRequest.newBuilder(uri).POST(bodyPublisher); + requestBuilder = requestBuilder.headers( + "User-Agent", "Test Agent", + "Content-Type", "application/json" + ); + HttpResponse response = client.send(requestBuilder.build(), HttpResponse.BodyHandlers.ofString()); + System.out.println("Response body: " + response.body()); + System.out.println("Response code: " + response.statusCode()); + } catch (IOException | InterruptedException e) { + System.out.println("An error occurred: " + e.getMessage()); + } + } + +}'''; + expect( + codeGen.getCode( + CodegenLanguage.javaHttpClient, requestModelPost3, "https"), + expectedCode); + }); + test('POST4', () { + const expectedCode = r''' +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; + +public class Main { + public static void main(String[] args) { + try { + HttpClient client = HttpClient.newHttpClient(); + URI uri = URI.create("https://api.apidash.dev/io/form"); + String boundary = "b9826c20-773c-1f0c-814d-a1b3d90cd6b3"; + Map data = new HashMap<>(); + + data.put("text", "API"); + data.put("sep", "|"); + data.put("times", "3"); + HttpRequest.BodyPublisher bodyPublisher = buildMultipartFormData(data, boundary); + HttpRequest.Builder requestBuilder = HttpRequest.newBuilder(uri).POST(bodyPublisher); + requestBuilder = requestBuilder.headers( + "Content-Type", "multipart/form-data; boundary=b9826c20-773c-1f0c-814d-a1b3d90cd6b3" + ); + HttpResponse response = client.send(requestBuilder.build(), HttpResponse.BodyHandlers.ofString()); + System.out.println("Response body: " + response.body()); + System.out.println("Response code: " + response.statusCode()); + } catch (IOException | InterruptedException e) { + System.out.println("An error occurred: " + e.getMessage()); + } + } + + private static HttpRequest.BodyPublisher buildMultipartFormData(Map data, String boundary) throws IOException { + var byteArrays = new ArrayList(); + var CRLF = "\r\n".getBytes(StandardCharsets.UTF_8); + + for (Map.Entry entry : data.entrySet()) { + byteArrays.add(("--" + boundary + "\r\n").getBytes(StandardCharsets.UTF_8)); + if (entry.getValue() instanceof Path) { + var file = (Path) entry.getValue(); + var fileName = file.getFileName().toString(); + byteArrays.add(("Content-Disposition: form-data; name=\"" + entry.getKey() + "\"; filename=\"" + fileName + "\"\r\n").getBytes(StandardCharsets.UTF_8)); + byteArrays.add(("Content-Type: " + Files.probeContentType(file) + "\r\n\r\n").getBytes(StandardCharsets.UTF_8)); + byteArrays.add(Files.readAllBytes(file)); + byteArrays.add(CRLF); + } else { + byteArrays.add(("Content-Disposition: form-data; name=\"" + entry.getKey() + "\"\r\n\r\n").getBytes(StandardCharsets.UTF_8)); + byteArrays.add(entry.getValue().toString().getBytes(StandardCharsets.UTF_8)); + byteArrays.add(CRLF); + } + } + byteArrays.add(("--" + boundary + "--\r\n").getBytes(StandardCharsets.UTF_8)); + + return HttpRequest.BodyPublishers.ofByteArrays(byteArrays); + } +}'''; + expect( + codeGen.getCode( + CodegenLanguage.javaHttpClient, requestModelPost4, "https", + boundary: "b9826c20-773c-1f0c-814d-a1b3d90cd6b3"), + expectedCode); + }); + test('POST5', () { + const expectedCode = r''' +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; + +public class Main { + public static void main(String[] args) { + try { + HttpClient client = HttpClient.newHttpClient(); + URI uri = URI.create("https://api.apidash.dev/io/form"); + String boundary = "b9826c20-773c-1f0c-814d-a1b3d90cd6b3"; + Map data = new HashMap<>(); + + data.put("text", "API"); + data.put("sep", "|"); + data.put("times", "3"); + HttpRequest.BodyPublisher bodyPublisher = buildMultipartFormData(data, boundary); + HttpRequest.Builder requestBuilder = HttpRequest.newBuilder(uri).POST(bodyPublisher); + requestBuilder = requestBuilder.headers( + "User-Agent", "Test Agent", + "Content-Type", "multipart/form-data; boundary=b9826c20-773c-1f0c-814d-a1b3d90cd6b3" + ); + HttpResponse response = client.send(requestBuilder.build(), HttpResponse.BodyHandlers.ofString()); + System.out.println("Response body: " + response.body()); + System.out.println("Response code: " + response.statusCode()); + } catch (IOException | InterruptedException e) { + System.out.println("An error occurred: " + e.getMessage()); + } + } + + private static HttpRequest.BodyPublisher buildMultipartFormData(Map data, String boundary) throws IOException { + var byteArrays = new ArrayList(); + var CRLF = "\r\n".getBytes(StandardCharsets.UTF_8); + + for (Map.Entry entry : data.entrySet()) { + byteArrays.add(("--" + boundary + "\r\n").getBytes(StandardCharsets.UTF_8)); + if (entry.getValue() instanceof Path) { + var file = (Path) entry.getValue(); + var fileName = file.getFileName().toString(); + byteArrays.add(("Content-Disposition: form-data; name=\"" + entry.getKey() + "\"; filename=\"" + fileName + "\"\r\n").getBytes(StandardCharsets.UTF_8)); + byteArrays.add(("Content-Type: " + Files.probeContentType(file) + "\r\n\r\n").getBytes(StandardCharsets.UTF_8)); + byteArrays.add(Files.readAllBytes(file)); + byteArrays.add(CRLF); + } else { + byteArrays.add(("Content-Disposition: form-data; name=\"" + entry.getKey() + "\"\r\n\r\n").getBytes(StandardCharsets.UTF_8)); + byteArrays.add(entry.getValue().toString().getBytes(StandardCharsets.UTF_8)); + byteArrays.add(CRLF); + } + } + byteArrays.add(("--" + boundary + "--\r\n").getBytes(StandardCharsets.UTF_8)); + + return HttpRequest.BodyPublishers.ofByteArrays(byteArrays); + } +}'''; + expect( + codeGen.getCode( + CodegenLanguage.javaHttpClient, requestModelPost5, "https", + boundary: "b9826c20-773c-1f0c-814d-a1b3d90cd6b3"), + expectedCode); + }); + test('POST6', () { + const expectedCode = r''' +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; + +public class Main { + public static void main(String[] args) { + try { + HttpClient client = HttpClient.newHttpClient(); + URI uri = URI.create("https://api.apidash.dev/io/img"); + String boundary = "b9826c20-773c-1f0c-814d-a1b3d90cd6b3"; + Map data = new HashMap<>(); + + data.put("token", "xyz"); + data.put("imfile", Paths.get("/Documents/up/1.png")); + HttpRequest.BodyPublisher bodyPublisher = buildMultipartFormData(data, boundary); + HttpRequest.Builder requestBuilder = HttpRequest.newBuilder(uri).POST(bodyPublisher); + requestBuilder = requestBuilder.headers( + "Content-Type", "multipart/form-data; boundary=b9826c20-773c-1f0c-814d-a1b3d90cd6b3" + ); + HttpResponse response = client.send(requestBuilder.build(), HttpResponse.BodyHandlers.ofString()); + System.out.println("Response body: " + response.body()); + System.out.println("Response code: " + response.statusCode()); + } catch (IOException | InterruptedException e) { + System.out.println("An error occurred: " + e.getMessage()); + } + } + + private static HttpRequest.BodyPublisher buildMultipartFormData(Map data, String boundary) throws IOException { + var byteArrays = new ArrayList(); + var CRLF = "\r\n".getBytes(StandardCharsets.UTF_8); + + for (Map.Entry entry : data.entrySet()) { + byteArrays.add(("--" + boundary + "\r\n").getBytes(StandardCharsets.UTF_8)); + if (entry.getValue() instanceof Path) { + var file = (Path) entry.getValue(); + var fileName = file.getFileName().toString(); + byteArrays.add(("Content-Disposition: form-data; name=\"" + entry.getKey() + "\"; filename=\"" + fileName + "\"\r\n").getBytes(StandardCharsets.UTF_8)); + byteArrays.add(("Content-Type: " + Files.probeContentType(file) + "\r\n\r\n").getBytes(StandardCharsets.UTF_8)); + byteArrays.add(Files.readAllBytes(file)); + byteArrays.add(CRLF); + } else { + byteArrays.add(("Content-Disposition: form-data; name=\"" + entry.getKey() + "\"\r\n\r\n").getBytes(StandardCharsets.UTF_8)); + byteArrays.add(entry.getValue().toString().getBytes(StandardCharsets.UTF_8)); + byteArrays.add(CRLF); + } + } + byteArrays.add(("--" + boundary + "--\r\n").getBytes(StandardCharsets.UTF_8)); + + return HttpRequest.BodyPublishers.ofByteArrays(byteArrays); + } +}'''; + expect( + codeGen.getCode( + CodegenLanguage.javaHttpClient, requestModelPost6, "https", + boundary: "b9826c20-773c-1f0c-814d-a1b3d90cd6b3"), + expectedCode); + }); + test('POST7', () { + const expectedCode = r''' +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; + +public class Main { + public static void main(String[] args) { + try { + HttpClient client = HttpClient.newHttpClient(); + URI uri = URI.create("https://api.apidash.dev/io/img"); + String boundary = "b9826c20-773c-1f0c-814d-a1b3d90cd6b3"; + Map data = new HashMap<>(); + + data.put("token", "xyz"); + data.put("imfile", Paths.get("/Documents/up/1.png")); + HttpRequest.BodyPublisher bodyPublisher = buildMultipartFormData(data, boundary); + HttpRequest.Builder requestBuilder = HttpRequest.newBuilder(uri).POST(bodyPublisher); + requestBuilder = requestBuilder.headers( + "Content-Type", "multipart/form-data; boundary=b9826c20-773c-1f0c-814d-a1b3d90cd6b3" + ); + HttpResponse response = client.send(requestBuilder.build(), HttpResponse.BodyHandlers.ofString()); + System.out.println("Response body: " + response.body()); + System.out.println("Response code: " + response.statusCode()); + } catch (IOException | InterruptedException e) { + System.out.println("An error occurred: " + e.getMessage()); + } + } + + private static HttpRequest.BodyPublisher buildMultipartFormData(Map data, String boundary) throws IOException { + var byteArrays = new ArrayList(); + var CRLF = "\r\n".getBytes(StandardCharsets.UTF_8); + + for (Map.Entry entry : data.entrySet()) { + byteArrays.add(("--" + boundary + "\r\n").getBytes(StandardCharsets.UTF_8)); + if (entry.getValue() instanceof Path) { + var file = (Path) entry.getValue(); + var fileName = file.getFileName().toString(); + byteArrays.add(("Content-Disposition: form-data; name=\"" + entry.getKey() + "\"; filename=\"" + fileName + "\"\r\n").getBytes(StandardCharsets.UTF_8)); + byteArrays.add(("Content-Type: " + Files.probeContentType(file) + "\r\n\r\n").getBytes(StandardCharsets.UTF_8)); + byteArrays.add(Files.readAllBytes(file)); + byteArrays.add(CRLF); + } else { + byteArrays.add(("Content-Disposition: form-data; name=\"" + entry.getKey() + "\"\r\n\r\n").getBytes(StandardCharsets.UTF_8)); + byteArrays.add(entry.getValue().toString().getBytes(StandardCharsets.UTF_8)); + byteArrays.add(CRLF); + } + } + byteArrays.add(("--" + boundary + "--\r\n").getBytes(StandardCharsets.UTF_8)); + + return HttpRequest.BodyPublishers.ofByteArrays(byteArrays); + } +}'''; + expect( + codeGen.getCode( + CodegenLanguage.javaHttpClient, requestModelPost7, "https", + boundary: "b9826c20-773c-1f0c-814d-a1b3d90cd6b3"), + expectedCode); + }); + test('POST8', () { + const expectedCode = r''' +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; + +public class Main { + public static void main(String[] args) { + try { + HttpClient client = HttpClient.newHttpClient(); + URI uri = URI.create("https://api.apidash.dev/io/form?size=2&len=3"); + String boundary = "b9826c20-773c-1f0c-814d-a1b3d90cd6b3"; + Map data = new HashMap<>(); + + data.put("text", "API"); + data.put("sep", "|"); + data.put("times", "3"); + HttpRequest.BodyPublisher bodyPublisher = buildMultipartFormData(data, boundary); + HttpRequest.Builder requestBuilder = HttpRequest.newBuilder(uri).POST(bodyPublisher); + requestBuilder = requestBuilder.headers( + "Content-Type", "multipart/form-data; boundary=b9826c20-773c-1f0c-814d-a1b3d90cd6b3" + ); + HttpResponse response = client.send(requestBuilder.build(), HttpResponse.BodyHandlers.ofString()); + System.out.println("Response body: " + response.body()); + System.out.println("Response code: " + response.statusCode()); + } catch (IOException | InterruptedException e) { + System.out.println("An error occurred: " + e.getMessage()); + } + } + + private static HttpRequest.BodyPublisher buildMultipartFormData(Map data, String boundary) throws IOException { + var byteArrays = new ArrayList(); + var CRLF = "\r\n".getBytes(StandardCharsets.UTF_8); + + for (Map.Entry entry : data.entrySet()) { + byteArrays.add(("--" + boundary + "\r\n").getBytes(StandardCharsets.UTF_8)); + if (entry.getValue() instanceof Path) { + var file = (Path) entry.getValue(); + var fileName = file.getFileName().toString(); + byteArrays.add(("Content-Disposition: form-data; name=\"" + entry.getKey() + "\"; filename=\"" + fileName + "\"\r\n").getBytes(StandardCharsets.UTF_8)); + byteArrays.add(("Content-Type: " + Files.probeContentType(file) + "\r\n\r\n").getBytes(StandardCharsets.UTF_8)); + byteArrays.add(Files.readAllBytes(file)); + byteArrays.add(CRLF); + } else { + byteArrays.add(("Content-Disposition: form-data; name=\"" + entry.getKey() + "\"\r\n\r\n").getBytes(StandardCharsets.UTF_8)); + byteArrays.add(entry.getValue().toString().getBytes(StandardCharsets.UTF_8)); + byteArrays.add(CRLF); + } + } + byteArrays.add(("--" + boundary + "--\r\n").getBytes(StandardCharsets.UTF_8)); + + return HttpRequest.BodyPublishers.ofByteArrays(byteArrays); + } +}'''; + expect( + codeGen.getCode( + CodegenLanguage.javaHttpClient, requestModelPost8, "https", + boundary: "b9826c20-773c-1f0c-814d-a1b3d90cd6b3"), + expectedCode); + }); + test('POST9', () { + const expectedCode = r''' +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; + +public class Main { + public static void main(String[] args) { + try { + HttpClient client = HttpClient.newHttpClient(); + URI uri = URI.create("https://api.apidash.dev/io/img?size=2&len=3"); + String boundary = "b9826c20-773c-1f0c-814d-a1b3d90cd6b3"; + Map data = new HashMap<>(); + + data.put("token", "xyz"); + data.put("imfile", Paths.get("/Documents/up/1.png")); + HttpRequest.BodyPublisher bodyPublisher = buildMultipartFormData(data, boundary); + HttpRequest.Builder requestBuilder = HttpRequest.newBuilder(uri).POST(bodyPublisher); + requestBuilder = requestBuilder.headers( + "User-Agent", "Test Agent", + "Keep-Alive", "true", + "Content-Type", "multipart/form-data; boundary=b9826c20-773c-1f0c-814d-a1b3d90cd6b3" + ); + HttpResponse response = client.send(requestBuilder.build(), HttpResponse.BodyHandlers.ofString()); + System.out.println("Response body: " + response.body()); + System.out.println("Response code: " + response.statusCode()); + } catch (IOException | InterruptedException e) { + System.out.println("An error occurred: " + e.getMessage()); + } + } + + private static HttpRequest.BodyPublisher buildMultipartFormData(Map data, String boundary) throws IOException { + var byteArrays = new ArrayList(); + var CRLF = "\r\n".getBytes(StandardCharsets.UTF_8); + + for (Map.Entry entry : data.entrySet()) { + byteArrays.add(("--" + boundary + "\r\n").getBytes(StandardCharsets.UTF_8)); + if (entry.getValue() instanceof Path) { + var file = (Path) entry.getValue(); + var fileName = file.getFileName().toString(); + byteArrays.add(("Content-Disposition: form-data; name=\"" + entry.getKey() + "\"; filename=\"" + fileName + "\"\r\n").getBytes(StandardCharsets.UTF_8)); + byteArrays.add(("Content-Type: " + Files.probeContentType(file) + "\r\n\r\n").getBytes(StandardCharsets.UTF_8)); + byteArrays.add(Files.readAllBytes(file)); + byteArrays.add(CRLF); + } else { + byteArrays.add(("Content-Disposition: form-data; name=\"" + entry.getKey() + "\"\r\n\r\n").getBytes(StandardCharsets.UTF_8)); + byteArrays.add(entry.getValue().toString().getBytes(StandardCharsets.UTF_8)); + byteArrays.add(CRLF); + } + } + byteArrays.add(("--" + boundary + "--\r\n").getBytes(StandardCharsets.UTF_8)); + + return HttpRequest.BodyPublishers.ofByteArrays(byteArrays); + } +}'''; + expect( + codeGen.getCode( + CodegenLanguage.javaHttpClient, requestModelPost9, "https", + boundary: "b9826c20-773c-1f0c-814d-a1b3d90cd6b3"), + expectedCode); + }); + }); + + group('PUT Request', () { + test('PUT1', () { + const expectedCode = r''' +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.io.IOException; + +public class Main { + public static void main(String[] args) { + try { + HttpClient client = HttpClient.newHttpClient(); + URI uri = URI.create("https://reqres.in/api/users/2"); + HttpRequest.BodyPublisher bodyPublisher = HttpRequest.BodyPublishers.ofString(""" +{ +"name": "morpheus", +"job": "zion resident" +}"""); + HttpRequest.Builder requestBuilder = HttpRequest.newBuilder(uri).PUT(bodyPublisher); + requestBuilder = requestBuilder.headers( + "Content-Type", "application/json" + ); + HttpResponse response = client.send(requestBuilder.build(), HttpResponse.BodyHandlers.ofString()); + System.out.println("Response body: " + response.body()); + System.out.println("Response code: " + response.statusCode()); + } catch (IOException | InterruptedException e) { + System.out.println("An error occurred: " + e.getMessage()); + } + } + +}'''; + expect( + codeGen.getCode( + CodegenLanguage.javaHttpClient, requestModelPut1, "https"), + expectedCode); + }); + }); + + group('PATCH Request', () { + test('PATCH1', () { + const expectedCode = r''' +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.io.IOException; + +public class Main { + public static void main(String[] args) { + try { + HttpClient client = HttpClient.newHttpClient(); + URI uri = URI.create("https://reqres.in/api/users/2"); + HttpRequest.BodyPublisher bodyPublisher = HttpRequest.BodyPublishers.ofString(""" +{ +"name": "marfeus", +"job": "accountant" +}"""); + HttpRequest.Builder requestBuilder = HttpRequest.newBuilder(uri).method("PATCH", bodyPublisher); + requestBuilder = requestBuilder.headers( + "Content-Type", "application/json" + ); + HttpResponse response = client.send(requestBuilder.build(), HttpResponse.BodyHandlers.ofString()); + System.out.println("Response body: " + response.body()); + System.out.println("Response code: " + response.statusCode()); + } catch (IOException | InterruptedException e) { + System.out.println("An error occurred: " + e.getMessage()); + } + } + +}'''; + expect( + codeGen.getCode( + CodegenLanguage.javaHttpClient, requestModelPatch1, "https"), + expectedCode); + }); + }); + + group('DELETE Request', () { + test('DELETE1', () { + const expectedCode = r''' +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.io.IOException; + +public class Main { + public static void main(String[] args) { + try { + HttpClient client = HttpClient.newHttpClient(); + URI uri = URI.create("https://reqres.in/api/users/2"); + + HttpRequest.Builder requestBuilder = HttpRequest.newBuilder(uri).method("DELETE", HttpRequest.BodyPublishers.noBody()); + HttpResponse response = client.send(requestBuilder.build(), HttpResponse.BodyHandlers.ofString()); + System.out.println("Response body: " + response.body()); + System.out.println("Response code: " + response.statusCode()); + } catch (IOException | InterruptedException e) { + System.out.println("An error occurred: " + e.getMessage()); + } + } + +}'''; + expect( + codeGen.getCode( + CodegenLanguage.javaHttpClient, requestModelDelete1, "https"), + expectedCode); + }); + test('DELETE2', () { + const expectedCode = r''' +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.io.IOException; + +public class Main { + public static void main(String[] args) { + try { + HttpClient client = HttpClient.newHttpClient(); + URI uri = URI.create("https://reqres.in/api/users/2"); + HttpRequest.BodyPublisher bodyPublisher = HttpRequest.BodyPublishers.ofString(""" +{ +"name": "marfeus", +"job": "accountant" +}"""); + HttpRequest.Builder requestBuilder = HttpRequest.newBuilder(uri).method("DELETE", bodyPublisher); + requestBuilder = requestBuilder.headers( + "Content-Type", "application/json" + ); + HttpResponse response = client.send(requestBuilder.build(), HttpResponse.BodyHandlers.ofString()); + System.out.println("Response body: " + response.body()); + System.out.println("Response code: " + response.statusCode()); + } catch (IOException | InterruptedException e) { + System.out.println("An error occurred: " + e.getMessage()); + } + } + +}'''; + expect( + codeGen.getCode( + CodegenLanguage.javaHttpClient, requestModelDelete2, "https"), + expectedCode); + }); + }); +} diff --git a/test/codegen/julia_http_codegen_test.dart b/test/codegen/julia_http_codegen_test.dart index 2b5161eb..eb78e63b 100644 --- a/test/codegen/julia_http_codegen_test.dart +++ b/test/codegen/julia_http_codegen_test.dart @@ -8,76 +8,72 @@ void main() { group('GET Request', () { test('GET 1', () { - const expectedCode = r"""using HTTP,JSON + const expectedCode = r"""using HTTP url = "https://api.apidash.dev" +response = HTTP.request("GET", url, status_exception=false) -response = HTTP.get(url) - -println("Status Code:", response.status) -println("Response Body:", String(response.body)) +println("Status Code: $(response.status) $(HTTP.StatusCodes.statustext(response.status))") +println("Response Body: \n$(String(response.body))") """; expect( codeGen.getCode(CodegenLanguage.juliaHttp, requestModelGet1, "https"), expectedCode); }); test('GET 2', () { - const expectedCode = r"""using HTTP,JSON + const expectedCode = r"""using HTTP url = "https://api.apidash.dev/country/data" - params = Dict( - "code"=> "US" - ) + "code" => "US", +) -response = HTTP.get(url, query=params) +response = HTTP.request("GET", url, query=params, status_exception=false) -println("Status Code:", response.status) -println("Response Body:", String(response.body)) +println("Status Code: $(response.status) $(HTTP.StatusCodes.statustext(response.status))") +println("Response Body: \n$(String(response.body))") """; expect( codeGen.getCode(CodegenLanguage.juliaHttp, requestModelGet2, "https"), expectedCode); }); test('GET 3', () { - const expectedCode = r"""using HTTP,JSON + const expectedCode = r"""using HTTP url = "https://api.apidash.dev/country/data" - params = Dict( - "code"=> "IND" - ) + "code" => "IND", +) -response = HTTP.get(url, query=params) +response = HTTP.request("GET", url, query=params, status_exception=false) -println("Status Code:", response.status) -println("Response Body:", String(response.body)) +println("Status Code: $(response.status) $(HTTP.StatusCodes.statustext(response.status))") +println("Response Body: \n$(String(response.body))") """; expect( codeGen.getCode(CodegenLanguage.juliaHttp, requestModelGet3, "https"), expectedCode); }); test('GET 4', () { - const expectedCode = r"""using HTTP,JSON + const expectedCode = r"""using HTTP url = "https://api.apidash.dev/humanize/social" - params = Dict( - "num"=> "8700000", - "digits"=> "3", - "system"=> "SS", - "add_space"=> "true", - "trailing_zeros"=> "true" - ) + "num" => "8700000", + "digits" => "3", + "system" => "SS", + "add_space" => "true", + "trailing_zeros" => "true", +) -response = HTTP.get(url, query=params) +response = HTTP.request("GET", url, query=params, status_exception=false) -println("Status Code:", response.status) -println("Response Body:", String(response.body)) +println("Status Code: $(response.status) $(HTTP.StatusCodes.statustext(response.status))") +println("Response Body: \n$(String(response.body))") """; expect( codeGen.getCode(CodegenLanguage.juliaHttp, requestModelGet4, "https"), @@ -85,19 +81,18 @@ println("Response Body:", String(response.body)) }); test('GET 5', () { - const expectedCode = r"""using HTTP,JSON + const expectedCode = r"""using HTTP url = "https://api.github.com/repos/foss42/apidash" - headers = Dict( - "User-Agent"=> "Test Agent" - ) + "User-Agent" => "Test Agent", +) -response = HTTP.get(url, headers=headers) +response = HTTP.request("GET", url, headers=headers, status_exception=false) -println("Status Code:", response.status) -println("Response Body:", String(response.body)) +println("Status Code: $(response.status) $(HTTP.StatusCodes.statustext(response.status))") +println("Response Body: \n$(String(response.body))") """; expect( codeGen.getCode(CodegenLanguage.juliaHttp, requestModelGet5, "https"), @@ -105,23 +100,22 @@ println("Response Body:", String(response.body)) }); test('GET 6', () { - const expectedCode = r"""using HTTP,JSON + const expectedCode = r"""using HTTP url = "https://api.github.com/repos/foss42/apidash" - params = Dict( - "raw"=> "true" - ) + "raw" => "true", +) headers = Dict( - "User-Agent"=> "Test Agent" - ) + "User-Agent" => "Test Agent", +) -response = HTTP.get(url, query=params, headers=headers) +response = HTTP.request("GET", url, headers=headers, query=params, status_exception=false) -println("Status Code:", response.status) -println("Response Body:", String(response.body)) +println("Status Code: $(response.status) $(HTTP.StatusCodes.statustext(response.status))") +println("Response Body: \n$(String(response.body))") """; expect( codeGen.getCode(CodegenLanguage.juliaHttp, requestModelGet6, "https"), @@ -129,15 +123,14 @@ println("Response Body:", String(response.body)) }); test('GET 7', () { - const expectedCode = r"""using HTTP,JSON + const expectedCode = r"""using HTTP url = "https://api.apidash.dev" +response = HTTP.request("GET", url, status_exception=false) -response = HTTP.get(url) - -println("Status Code:", response.status) -println("Response Body:", String(response.body)) +println("Status Code: $(response.status) $(HTTP.StatusCodes.statustext(response.status))") +println("Response Body: \n$(String(response.body))") """; expect( codeGen.getCode(CodegenLanguage.juliaHttp, requestModelGet7, "https"), @@ -145,23 +138,22 @@ println("Response Body:", String(response.body)) }); test('GET 8', () { - const expectedCode = r"""using HTTP,JSON + const expectedCode = r"""using HTTP url = "https://api.github.com/repos/foss42/apidash" - params = Dict( - "raw"=> "true" - ) + "raw" => "true", +) headers = Dict( - "User-Agent"=> "Test Agent" - ) + "User-Agent" => "Test Agent", +) -response = HTTP.get(url, query=params, headers=headers) +response = HTTP.request("GET", url, headers=headers, query=params, status_exception=false) -println("Status Code:", response.status) -println("Response Body:", String(response.body)) +println("Status Code: $(response.status) $(HTTP.StatusCodes.statustext(response.status))") +println("Response Body: \n$(String(response.body))") """; expect( codeGen.getCode(CodegenLanguage.juliaHttp, requestModelGet8, "https"), @@ -169,20 +161,19 @@ println("Response Body:", String(response.body)) }); test('GET 9', () { - const expectedCode = r"""using HTTP,JSON + const expectedCode = r"""using HTTP url = "https://api.apidash.dev/humanize/social" - params = Dict( - "num"=> "8700000", - "add_space"=> "true" - ) + "num" => "8700000", + "add_space" => "true", +) -response = HTTP.get(url, query=params) +response = HTTP.request("GET", url, query=params, status_exception=false) -println("Status Code:", response.status) -println("Response Body:", String(response.body)) +println("Status Code: $(response.status) $(HTTP.StatusCodes.statustext(response.status))") +println("Response Body: \n$(String(response.body))") """; expect( codeGen.getCode(CodegenLanguage.juliaHttp, requestModelGet9, "https"), @@ -190,19 +181,18 @@ println("Response Body:", String(response.body)) }); test('GET 10', () { - const expectedCode = r"""using HTTP,JSON + const expectedCode = r"""using HTTP url = "https://api.apidash.dev/humanize/social" - headers = Dict( - "User-Agent"=> "Test Agent" - ) + "User-Agent" => "Test Agent", +) -response = HTTP.get(url, headers=headers) +response = HTTP.request("GET", url, headers=headers, status_exception=false) -println("Status Code:", response.status) -println("Response Body:", String(response.body)) +println("Status Code: $(response.status) $(HTTP.StatusCodes.statustext(response.status))") +println("Response Body: \n$(String(response.body))") """; expect( codeGen.getCode( @@ -211,24 +201,23 @@ println("Response Body:", String(response.body)) }); test('GET 11', () { - const expectedCode = r"""using HTTP,JSON + const expectedCode = r"""using HTTP url = "https://api.apidash.dev/humanize/social" - params = Dict( - "num"=> "8700000", - "digits"=> "3" - ) + "num" => "8700000", + "digits" => "3", +) headers = Dict( - "User-Agent"=> "Test Agent" - ) + "User-Agent" => "Test Agent", +) -response = HTTP.get(url, query=params, headers=headers) +response = HTTP.request("GET", url, headers=headers, query=params, status_exception=false) -println("Status Code:", response.status) -println("Response Body:", String(response.body)) +println("Status Code: $(response.status) $(HTTP.StatusCodes.statustext(response.status))") +println("Response Body: \n$(String(response.body))") """; expect( codeGen.getCode( @@ -237,15 +226,14 @@ println("Response Body:", String(response.body)) }); test('GET 12', () { - const expectedCode = r"""using HTTP,JSON + const expectedCode = r"""using HTTP url = "https://api.apidash.dev/humanize/social" +response = HTTP.request("GET", url, status_exception=false) -response = HTTP.get(url) - -println("Status Code:", response.status) -println("Response Body:", String(response.body)) +println("Status Code: $(response.status) $(HTTP.StatusCodes.statustext(response.status))") +println("Response Body: \n$(String(response.body))") """; expect( codeGen.getCode( @@ -256,15 +244,14 @@ println("Response Body:", String(response.body)) group('HEAD Request', () { test('HEAD 1', () { - const expectedCode = r"""using HTTP,JSON + const expectedCode = r"""using HTTP url = "https://api.apidash.dev" +response = HTTP.request("HEAD", url, status_exception=false) -response = HTTP.head(url) - -println("Status Code:", response.status) -println("Response Body:", String(response.body)) +println("Status Code: $(response.status) $(HTTP.StatusCodes.statustext(response.status))") +println("Response Body: \n$(String(response.body))") """; expect( codeGen.getCode( @@ -273,43 +260,40 @@ println("Response Body:", String(response.body)) }); test('HEAD 2', () { - const expectedCode = r"""using HTTP,JSON + const expectedCode = r"""using HTTP -url = "https://api.apidash.dev" +url = "http://api.apidash.dev" +response = HTTP.request("HEAD", url, status_exception=false) -response = HTTP.head(url) - -println("Status Code:", response.status) -println("Response Body:", String(response.body)) +println("Status Code: $(response.status) $(HTTP.StatusCodes.statustext(response.status))") +println("Response Body: \n$(String(response.body))") """; expect( - codeGen.getCode( - CodegenLanguage.juliaHttp, requestModelHead2, "https"), + codeGen.getCode(CodegenLanguage.juliaHttp, requestModelHead2, "http"), expectedCode); }); }); group('POST Request', () { test('POST 1', () { - const expectedCode = r"""using HTTP,JSON + const expectedCode = r'''using HTTP url = "https://api.apidash.dev/case/lower" - -payload = Dict( -"text"=> "I LOVE Flutter" -) +payload = """{ +"text": "I LOVE Flutter" +}""" headers = Dict( - "content-type"=> "text/plain" - ) + "content-type" => "text/plain", +) -response = HTTP.post(url, payload=payload, headers=headers) +response = HTTP.request("POST", url, headers=headers, body=payload, status_exception=false) -println("Status Code:", response.status) -println("Response Body:", String(response.body)) -"""; +println("Status Code: $(response.status) $(HTTP.StatusCodes.statustext(response.status))") +println("Response Body: \n$(String(response.body))") +'''; expect( codeGen.getCode( CodegenLanguage.juliaHttp, requestModelPost1, "https"), @@ -317,72 +301,234 @@ println("Response Body:", String(response.body)) }); test('POST 2', () { - const expectedCode = r"""using HTTP,JSON + const expectedCode = r'''using HTTP url = "https://api.apidash.dev/case/lower" +payload = """{ +"text": "I LOVE Flutter", +"flag": null, +"male": true, +"female": false, +"no": 1.2, +"arr": ["null", "true", "false", null] +}""" -payload = Dict( -"text"=> "I LOVE Flutter", -"flag"=> null, -"male"=> true, -"female"=> false, -"no"=> 1.2, -"arr"=> ["null", "true", "false", null] +headers = Dict( + "content-type" => "application/json", ) -response = HTTP.post(url, JSON.json(payload)) +response = HTTP.request("POST", url, headers=headers, body=payload, status_exception=false) -println("Status Code:", response.status) -println("Response Body:", String(response.body)) -"""; +println("Status Code: $(response.status) $(HTTP.StatusCodes.statustext(response.status))") +println("Response Body: \n$(String(response.body))") +'''; expect( codeGen.getCode( CodegenLanguage.juliaHttp, requestModelPost2, "https"), expectedCode); }); test('POST 3', () { - const expectedCode = r"""using HTTP,JSON + const expectedCode = r'''using HTTP url = "https://api.apidash.dev/case/lower" - -payload = Dict( -"text"=> "I LOVE Flutter" -) +payload = """{ +"text": "I LOVE Flutter" +}""" headers = Dict( - "User-Agent"=> "Test Agent" - ) + "User-Agent" => "Test Agent", + "content-type" => "application/json", +) -response = HTTP.post(url, JSON.json(payload), headers=headers) +response = HTTP.request("POST", url, headers=headers, body=payload, status_exception=false) -println("Status Code:", response.status) -println("Response Body:", String(response.body)) -"""; +println("Status Code: $(response.status) $(HTTP.StatusCodes.statustext(response.status))") +println("Response Body: \n$(String(response.body))") +'''; expect( codeGen.getCode( CodegenLanguage.juliaHttp, requestModelPost3, "https"), expectedCode); }); + + test('POST 4', () { + const expectedCode = r"""using HTTP + +url = "https://api.apidash.dev/io/form" + +data = Dict( + "text" => "API", + "sep" => "|", + "times" => "3", +) + +payload = HTTP.Form(data) + +response = HTTP.request("POST", url, body=payload, status_exception=false) + +println("Status Code: $(response.status) $(HTTP.StatusCodes.statustext(response.status))") +println("Response Body: \n$(String(response.body))") +"""; + expect( + codeGen.getCode( + CodegenLanguage.juliaHttp, requestModelPost4, "https"), + expectedCode); + }); + + test('POST 5', () { + const expectedCode = r"""using HTTP + +url = "https://api.apidash.dev/io/form" + +data = Dict( + "text" => "API", + "sep" => "|", + "times" => "3", +) + +payload = HTTP.Form(data) + +headers = Dict( + "User-Agent" => "Test Agent", +) + +response = HTTP.request("POST", url, headers=headers, body=payload, status_exception=false) + +println("Status Code: $(response.status) $(HTTP.StatusCodes.statustext(response.status))") +println("Response Body: \n$(String(response.body))") +"""; + expect( + codeGen.getCode( + CodegenLanguage.juliaHttp, requestModelPost5, "https"), + expectedCode); + }); + test('POST 6', () { + const expectedCode = r"""using HTTP + +url = "https://api.apidash.dev/io/img" + +data = Dict( + "token" => "xyz", + "imfile" => open("/Documents/up/1.png"), +) + +payload = HTTP.Form(data) + +response = HTTP.request("POST", url, body=payload, status_exception=false) + +println("Status Code: $(response.status) $(HTTP.StatusCodes.statustext(response.status))") +println("Response Body: \n$(String(response.body))") +"""; + expect( + codeGen.getCode( + CodegenLanguage.juliaHttp, requestModelPost6, "https"), + expectedCode); + }); + test('POST 7', () { + const expectedCode = r"""using HTTP + +url = "https://api.apidash.dev/io/img" + +data = Dict( + "token" => "xyz", + "imfile" => open("/Documents/up/1.png"), +) + +payload = HTTP.Form(data) + +response = HTTP.request("POST", url, body=payload, status_exception=false) + +println("Status Code: $(response.status) $(HTTP.StatusCodes.statustext(response.status))") +println("Response Body: \n$(String(response.body))") +"""; + expect( + codeGen.getCode( + CodegenLanguage.juliaHttp, requestModelPost7, "https"), + expectedCode); + }); + test('POST 8', () { + const expectedCode = r"""using HTTP + +url = "https://api.apidash.dev/io/form" + +params = Dict( + "size" => "2", + "len" => "3", +) + +data = Dict( + "text" => "API", + "sep" => "|", + "times" => "3", +) + +payload = HTTP.Form(data) + +response = HTTP.request("POST", url, body=payload, query=params, status_exception=false) + +println("Status Code: $(response.status) $(HTTP.StatusCodes.statustext(response.status))") +println("Response Body: \n$(String(response.body))") +"""; + expect( + codeGen.getCode( + CodegenLanguage.juliaHttp, requestModelPost8, "https"), + expectedCode); + }); + test('POST 9', () { + const expectedCode = r"""using HTTP + +url = "https://api.apidash.dev/io/img" + +params = Dict( + "size" => "2", + "len" => "3", +) + +data = Dict( + "token" => "xyz", + "imfile" => open("/Documents/up/1.png"), +) + +payload = HTTP.Form(data) + +headers = Dict( + "User-Agent" => "Test Agent", + "Keep-Alive" => "true", +) + +response = HTTP.request("POST", url, headers=headers, body=payload, query=params, status_exception=false) + +println("Status Code: $(response.status) $(HTTP.StatusCodes.statustext(response.status))") +println("Response Body: \n$(String(response.body))") +"""; + expect( + codeGen.getCode( + CodegenLanguage.juliaHttp, requestModelPost9, "https"), + expectedCode); + }); }); group('PUT Request', () { test('PUT 1', () { - const expectedCode = r"""using HTTP,JSON + const expectedCode = r'''using HTTP url = "https://reqres.in/api/users/2" +payload = """{ +"name": "morpheus", +"job": "zion resident" +}""" -payload = Dict( -"name"=> "morpheus", -"job"=> "zion resident" +headers = Dict( + "content-type" => "application/json", ) -response = HTTP.put(url, JSON.json(payload)) +response = HTTP.request("PUT", url, headers=headers, body=payload, status_exception=false) -println("Status Code:", response.status) -println("Response Body:", String(response.body)) -"""; +println("Status Code: $(response.status) $(HTTP.StatusCodes.statustext(response.status))") +println("Response Body: \n$(String(response.body))") +'''; expect( codeGen.getCode(CodegenLanguage.juliaHttp, requestModelPut1, "https"), expectedCode); @@ -390,21 +536,24 @@ println("Response Body:", String(response.body)) }); group('PATCH Request', () { test('PATCH 1', () { - const expectedCode = r"""using HTTP,JSON + const expectedCode = r'''using HTTP url = "https://reqres.in/api/users/2" +payload = """{ +"name": "marfeus", +"job": "accountant" +}""" -payload = Dict( -"name"=> "marfeus", -"job"=> "accountant" +headers = Dict( + "content-type" => "application/json", ) -response = HTTP.patch(url, JSON.json(payload)) +response = HTTP.request("PATCH", url, headers=headers, body=payload, status_exception=false) -println("Status Code:", response.status) -println("Response Body:", String(response.body)) -"""; +println("Status Code: $(response.status) $(HTTP.StatusCodes.statustext(response.status))") +println("Response Body: \n$(String(response.body))") +'''; expect( codeGen.getCode( CodegenLanguage.juliaHttp, requestModelPatch1, "https"), @@ -413,15 +562,14 @@ println("Response Body:", String(response.body)) }); group('DELETE Request', () { test('DELETE 1', () { - const expectedCode = r"""using HTTP,JSON + const expectedCode = r"""using HTTP url = "https://reqres.in/api/users/2" +response = HTTP.request("DELETE", url, status_exception=false) -response = HTTP.delete(url) - -println("Status Code:", response.status) -println("Response Body:", String(response.body)) +println("Status Code: $(response.status) $(HTTP.StatusCodes.statustext(response.status))") +println("Response Body: \n$(String(response.body))") """; expect( codeGen.getCode( @@ -429,21 +577,24 @@ println("Response Body:", String(response.body)) expectedCode); }); test('DELETE 2', () { - const expectedCode = r"""using HTTP,JSON + const expectedCode = r'''using HTTP url = "https://reqres.in/api/users/2" +payload = """{ +"name": "marfeus", +"job": "accountant" +}""" -payload = Dict( -"name"=> "marfeus", -"job"=> "accountant" +headers = Dict( + "content-type" => "application/json", ) -response = HTTP.delete(url, JSON.json(payload)) +response = HTTP.request("DELETE", url, headers=headers, body=payload, status_exception=false) -println("Status Code:", response.status) -println("Response Body:", String(response.body)) -"""; +println("Status Code: $(response.status) $(HTTP.StatusCodes.statustext(response.status))") +println("Response Body: \n$(String(response.body))") +'''; expect( codeGen.getCode( CodegenLanguage.juliaHttp, requestModelDelete2, "https"), diff --git a/test/codegen/php_curl_codegen_test.dart b/test/codegen/php_curl_codegen_test.dart new file mode 100644 index 00000000..afcb8e3e --- /dev/null +++ b/test/codegen/php_curl_codegen_test.dart @@ -0,0 +1,909 @@ +import 'package:apidash/codegen/codegen.dart'; +import 'package:apidash/consts.dart'; +import 'package:test/test.dart'; +import '../request_models.dart'; + +void main() { + final codeGen = Codegen(); + + group('GET Request', () { + test('GET 1', () { + const expectedCode = r''' 1, + CURLOPT_CUSTOMREQUEST => 'GET', + CURLOPT_FOLLOWLOCATION => true, +]); + +$response = curl_exec($request); + +curl_close($request); + +$httpCode = curl_getinfo($request, CURLINFO_HTTP_CODE); +echo "Status Code: " . $httpCode . "\n"; +echo $response . "\n"; +'''; + expect( + codeGen.getCode(CodegenLanguage.phpCurl, requestModelGet1, 'https'), + expectedCode); + }); + test('GET 2', () { + const expectedCode = r''' 'US', +]; +$uri .= '?' . http_build_query($queryParams); + +$request = curl_init($uri); + +curl_setopt_array($request, [ + CURLOPT_RETURNTRANSFER => 1, + CURLOPT_CUSTOMREQUEST => 'GET', + CURLOPT_FOLLOWLOCATION => true, +]); + +$response = curl_exec($request); + +curl_close($request); + +$httpCode = curl_getinfo($request, CURLINFO_HTTP_CODE); +echo "Status Code: " . $httpCode . "\n"; +echo $response . "\n"; +'''; + expect( + codeGen.getCode(CodegenLanguage.phpCurl, requestModelGet2, 'https'), + expectedCode); + }); + test('GET 3', () { + const expectedCode = r''' 'IND', +]; +$uri .= '?' . http_build_query($queryParams); + +$request = curl_init($uri); + +curl_setopt_array($request, [ + CURLOPT_RETURNTRANSFER => 1, + CURLOPT_CUSTOMREQUEST => 'GET', + CURLOPT_FOLLOWLOCATION => true, +]); + +$response = curl_exec($request); + +curl_close($request); + +$httpCode = curl_getinfo($request, CURLINFO_HTTP_CODE); +echo "Status Code: " . $httpCode . "\n"; +echo $response . "\n"; +'''; + expect( + codeGen.getCode(CodegenLanguage.phpCurl, requestModelGet3, "https"), + expectedCode); + }); + test('GET 4', () { + const expectedCode = r''' '8700000', + 'digits' => '3', + 'system' => 'SS', + 'add_space' => 'true', + 'trailing_zeros' => 'true', +]; +$uri .= '?' . http_build_query($queryParams); + +$request = curl_init($uri); + +curl_setopt_array($request, [ + CURLOPT_RETURNTRANSFER => 1, + CURLOPT_CUSTOMREQUEST => 'GET', + CURLOPT_FOLLOWLOCATION => true, +]); + +$response = curl_exec($request); + +curl_close($request); + +$httpCode = curl_getinfo($request, CURLINFO_HTTP_CODE); +echo "Status Code: " . $httpCode . "\n"; +echo $response . "\n"; +'''; + expect( + codeGen.getCode(CodegenLanguage.phpCurl, requestModelGet4, "https"), + expectedCode); + }); + + test('GET 5', () { + const expectedCode = r''' 1, + CURLOPT_CUSTOMREQUEST => 'GET', + CURLOPT_HTTPHEADER => $headers, + CURLOPT_FOLLOWLOCATION => true, +]); + +$response = curl_exec($request); + +curl_close($request); + +$httpCode = curl_getinfo($request, CURLINFO_HTTP_CODE); +echo "Status Code: " . $httpCode . "\n"; +echo $response . "\n"; +'''; + expect( + codeGen.getCode(CodegenLanguage.phpCurl, requestModelGet5, 'https'), + expectedCode); + }); + + test('GET 6', () { + const expectedCode = r''' 'true', +]; +$uri .= '?' . http_build_query($queryParams); + +$headers = [ + 'User-Agent: Test Agent', +]; + +$request = curl_init($uri); + +curl_setopt_array($request, [ + CURLOPT_RETURNTRANSFER => 1, + CURLOPT_CUSTOMREQUEST => 'GET', + CURLOPT_HTTPHEADER => $headers, + CURLOPT_FOLLOWLOCATION => true, +]); + +$response = curl_exec($request); + +curl_close($request); + +$httpCode = curl_getinfo($request, CURLINFO_HTTP_CODE); +echo "Status Code: " . $httpCode . "\n"; +echo $response . "\n"; +'''; + expect( + codeGen.getCode(CodegenLanguage.phpCurl, requestModelGet6, "https"), + expectedCode); + }); + + test('GET 7', () { + const expectedCode = r''' 1, + CURLOPT_CUSTOMREQUEST => 'GET', + CURLOPT_FOLLOWLOCATION => true, +]); + +$response = curl_exec($request); + +curl_close($request); + +$httpCode = curl_getinfo($request, CURLINFO_HTTP_CODE); +echo "Status Code: " . $httpCode . "\n"; +echo $response . "\n"; +'''; + expect( + codeGen.getCode(CodegenLanguage.phpCurl, requestModelGet7, "https"), + expectedCode); + }); + + test('GET 8', () { + const expectedCode = r''' 'true', +]; +$uri .= '?' . http_build_query($queryParams); + +$headers = [ + 'User-Agent: Test Agent', +]; + +$request = curl_init($uri); + +curl_setopt_array($request, [ + CURLOPT_RETURNTRANSFER => 1, + CURLOPT_CUSTOMREQUEST => 'GET', + CURLOPT_HTTPHEADER => $headers, + CURLOPT_FOLLOWLOCATION => true, +]); + +$response = curl_exec($request); + +curl_close($request); + +$httpCode = curl_getinfo($request, CURLINFO_HTTP_CODE); +echo "Status Code: " . $httpCode . "\n"; +echo $response . "\n"; +'''; + expect( + codeGen.getCode(CodegenLanguage.phpCurl, requestModelGet8, "https"), + expectedCode); + }); + + test('GET 9', () { + const expectedCode = r''' '8700000', + 'add_space' => 'true', +]; +$uri .= '?' . http_build_query($queryParams); + +$request = curl_init($uri); + +curl_setopt_array($request, [ + CURLOPT_RETURNTRANSFER => 1, + CURLOPT_CUSTOMREQUEST => 'GET', + CURLOPT_FOLLOWLOCATION => true, +]); + +$response = curl_exec($request); + +curl_close($request); + +$httpCode = curl_getinfo($request, CURLINFO_HTTP_CODE); +echo "Status Code: " . $httpCode . "\n"; +echo $response . "\n"; +'''; + expect( + codeGen.getCode(CodegenLanguage.phpCurl, requestModelGet9, "https"), + expectedCode); + }); + + test('GET 10', () { + const expectedCode = r''' 1, + CURLOPT_CUSTOMREQUEST => 'GET', + CURLOPT_HTTPHEADER => $headers, + CURLOPT_FOLLOWLOCATION => true, +]); + +$response = curl_exec($request); + +curl_close($request); + +$httpCode = curl_getinfo($request, CURLINFO_HTTP_CODE); +echo "Status Code: " . $httpCode . "\n"; +echo $response . "\n"; +'''; + expect( + codeGen.getCode(CodegenLanguage.phpCurl, requestModelGet10, "https"), + expectedCode); + }); + + test('GET 11', () { + const expectedCode = r''' '8700000', + 'digits' => '3', +]; +$uri .= '?' . http_build_query($queryParams); + +$headers = [ + 'User-Agent: Test Agent', +]; + +$request = curl_init($uri); + +curl_setopt_array($request, [ + CURLOPT_RETURNTRANSFER => 1, + CURLOPT_CUSTOMREQUEST => 'GET', + CURLOPT_HTTPHEADER => $headers, + CURLOPT_FOLLOWLOCATION => true, +]); + +$response = curl_exec($request); + +curl_close($request); + +$httpCode = curl_getinfo($request, CURLINFO_HTTP_CODE); +echo "Status Code: " . $httpCode . "\n"; +echo $response . "\n"; +'''; + expect( + codeGen.getCode(CodegenLanguage.phpCurl, requestModelGet11, "https"), + expectedCode); + }); + + test('GET 12', () { + const expectedCode = r''' 1, + CURLOPT_CUSTOMREQUEST => 'GET', + CURLOPT_FOLLOWLOCATION => true, +]); + +$response = curl_exec($request); + +curl_close($request); + +$httpCode = curl_getinfo($request, CURLINFO_HTTP_CODE); +echo "Status Code: " . $httpCode . "\n"; +echo $response . "\n"; +'''; + expect( + codeGen.getCode(CodegenLanguage.phpCurl, requestModelGet12, "https"), + expectedCode); + }); + }); + + group('HEAD Request', () { + test('HEAD 1', () { + const expectedCode = r''' 1, + CURLOPT_CUSTOMREQUEST => 'HEAD', + CURLOPT_FOLLOWLOCATION => true, +]); + +$response = curl_exec($request); + +curl_close($request); + +$httpCode = curl_getinfo($request, CURLINFO_HTTP_CODE); +echo "Status Code: " . $httpCode . "\n"; +echo $response . "\n"; +'''; + expect( + codeGen.getCode(CodegenLanguage.phpCurl, requestModelHead1, "https"), + expectedCode); + }); + + test('HEAD 2', () { + const expectedCode = r''' 1, + CURLOPT_CUSTOMREQUEST => 'HEAD', + CURLOPT_FOLLOWLOCATION => true, +]); + +$response = curl_exec($request); + +curl_close($request); + +$httpCode = curl_getinfo($request, CURLINFO_HTTP_CODE); +echo "Status Code: " . $httpCode . "\n"; +echo $response . "\n"; +'''; + expect( + codeGen.getCode(CodegenLanguage.phpCurl, requestModelHead2, "http"), + expectedCode); + }); + }); + + group('POST Request', () { + test('POST 1', () { + const expectedCode = r''' 1, + CURLOPT_CUSTOMREQUEST => 'POST', + CURLOPT_HTTPHEADER => $headers, + CURLOPT_POSTFIELDS => $request_body, + CURLOPT_FOLLOWLOCATION => true, +]); + +$response = curl_exec($request); + +curl_close($request); + +$httpCode = curl_getinfo($request, CURLINFO_HTTP_CODE); +echo "Status Code: " . $httpCode . "\n"; +echo $response . "\n"; +'''; + expect( + codeGen.getCode(CodegenLanguage.phpCurl, requestModelPost1, "https"), + expectedCode); + }); + + test('POST 2', () { + const expectedCode = r''' 1, + CURLOPT_CUSTOMREQUEST => 'POST', + CURLOPT_HTTPHEADER => $headers, + CURLOPT_POSTFIELDS => $request_body, + CURLOPT_FOLLOWLOCATION => true, +]); + +$response = curl_exec($request); + +curl_close($request); + +$httpCode = curl_getinfo($request, CURLINFO_HTTP_CODE); +echo "Status Code: " . $httpCode . "\n"; +echo $response . "\n"; +'''; + expect( + codeGen.getCode(CodegenLanguage.phpCurl, requestModelPost2, "https"), + expectedCode); + }); + test('POST 3', () { + const expectedCode = r''' 1, + CURLOPT_CUSTOMREQUEST => 'POST', + CURLOPT_HTTPHEADER => $headers, + CURLOPT_POSTFIELDS => $request_body, + CURLOPT_FOLLOWLOCATION => true, +]); + +$response = curl_exec($request); + +curl_close($request); + +$httpCode = curl_getinfo($request, CURLINFO_HTTP_CODE); +echo "Status Code: " . $httpCode . "\n"; +echo $response . "\n"; +'''; + expect( + codeGen.getCode(CodegenLanguage.phpCurl, requestModelPost3, "https"), + expectedCode); + }); + + test('POST 4', () { + const expectedCode = r''' 'API', + 'sep' => '|', + 'times' => '3', +]; + +$request = curl_init($uri); + +curl_setopt_array($request, [ + CURLOPT_RETURNTRANSFER => 1, + CURLOPT_CUSTOMREQUEST => 'POST', + CURLOPT_POSTFIELDS => $request_body, + CURLOPT_FOLLOWLOCATION => true, +]); + +$response = curl_exec($request); + +curl_close($request); + +$httpCode = curl_getinfo($request, CURLINFO_HTTP_CODE); +echo "Status Code: " . $httpCode . "\n"; +echo $response . "\n"; +'''; + expect( + codeGen.getCode(CodegenLanguage.phpCurl, requestModelPost4, "https"), + expectedCode); + }); + + test('POST 5', () { + const expectedCode = r''' 'API', + 'sep' => '|', + 'times' => '3', +]; + +$headers = [ + 'User-Agent: Test Agent', +]; + +$request = curl_init($uri); + +curl_setopt_array($request, [ + CURLOPT_RETURNTRANSFER => 1, + CURLOPT_CUSTOMREQUEST => 'POST', + CURLOPT_HTTPHEADER => $headers, + CURLOPT_POSTFIELDS => $request_body, + CURLOPT_FOLLOWLOCATION => true, +]); + +$response = curl_exec($request); + +curl_close($request); + +$httpCode = curl_getinfo($request, CURLINFO_HTTP_CODE); +echo "Status Code: " . $httpCode . "\n"; +echo $response . "\n"; +'''; + expect( + codeGen.getCode(CodegenLanguage.phpCurl, requestModelPost5, "https"), + expectedCode); + }); + test('POST 6', () { + const expectedCode = r''' 'xyz', + 'imfile' => new CURLFILE('/Documents/up/1.png'), +]; + +$request = curl_init($uri); + +curl_setopt_array($request, [ + CURLOPT_RETURNTRANSFER => 1, + CURLOPT_CUSTOMREQUEST => 'POST', + CURLOPT_POSTFIELDS => $request_body, + CURLOPT_FOLLOWLOCATION => true, +]); + +$response = curl_exec($request); + +curl_close($request); + +$httpCode = curl_getinfo($request, CURLINFO_HTTP_CODE); +echo "Status Code: " . $httpCode . "\n"; +echo $response . "\n"; +'''; + expect( + codeGen.getCode(CodegenLanguage.phpCurl, requestModelPost6, "https"), + expectedCode); + }); + test('POST 7', () { + const expectedCode = r''' 'xyz', + 'imfile' => new CURLFILE('/Documents/up/1.png'), +]; + +$request = curl_init($uri); + +curl_setopt_array($request, [ + CURLOPT_RETURNTRANSFER => 1, + CURLOPT_CUSTOMREQUEST => 'POST', + CURLOPT_POSTFIELDS => $request_body, + CURLOPT_FOLLOWLOCATION => true, +]); + +$response = curl_exec($request); + +curl_close($request); + +$httpCode = curl_getinfo($request, CURLINFO_HTTP_CODE); +echo "Status Code: " . $httpCode . "\n"; +echo $response . "\n"; +'''; + expect( + codeGen.getCode(CodegenLanguage.phpCurl, requestModelPost7, "https"), + expectedCode); + }); + test('POST 8', () { + const expectedCode = r''' 'API', + 'sep' => '|', + 'times' => '3', +]; + +$queryParams = [ + 'size' => '2', + 'len' => '3', +]; +$uri .= '?' . http_build_query($queryParams); + +$request = curl_init($uri); + +curl_setopt_array($request, [ + CURLOPT_RETURNTRANSFER => 1, + CURLOPT_CUSTOMREQUEST => 'POST', + CURLOPT_POSTFIELDS => $request_body, + CURLOPT_FOLLOWLOCATION => true, +]); + +$response = curl_exec($request); + +curl_close($request); + +$httpCode = curl_getinfo($request, CURLINFO_HTTP_CODE); +echo "Status Code: " . $httpCode . "\n"; +echo $response . "\n"; +'''; + expect( + codeGen.getCode(CodegenLanguage.phpCurl, requestModelPost8, "https"), + expectedCode); + }); + test('POST 9', () { + const expectedCode = r''' 'xyz', + 'imfile' => new CURLFILE('/Documents/up/1.png'), +]; + +$queryParams = [ + 'size' => '2', + 'len' => '3', +]; +$uri .= '?' . http_build_query($queryParams); + +$headers = [ + 'User-Agent: Test Agent', + 'Keep-Alive: true', +]; + +$request = curl_init($uri); + +curl_setopt_array($request, [ + CURLOPT_RETURNTRANSFER => 1, + CURLOPT_CUSTOMREQUEST => 'POST', + CURLOPT_HTTPHEADER => $headers, + CURLOPT_POSTFIELDS => $request_body, + CURLOPT_FOLLOWLOCATION => true, +]); + +$response = curl_exec($request); + +curl_close($request); + +$httpCode = curl_getinfo($request, CURLINFO_HTTP_CODE); +echo "Status Code: " . $httpCode . "\n"; +echo $response . "\n"; +'''; + expect( + codeGen.getCode(CodegenLanguage.phpCurl, requestModelPost9, "https"), + expectedCode); + }); + }); + group('PUT Request', () { + test('PUT 1', () { + const expectedCode = r''' 1, + CURLOPT_CUSTOMREQUEST => 'PUT', + CURLOPT_HTTPHEADER => $headers, + CURLOPT_POSTFIELDS => $request_body, + CURLOPT_FOLLOWLOCATION => true, +]); + +$response = curl_exec($request); + +curl_close($request); + +$httpCode = curl_getinfo($request, CURLINFO_HTTP_CODE); +echo "Status Code: " . $httpCode . "\n"; +echo $response . "\n"; +'''; + expect( + codeGen.getCode(CodegenLanguage.phpCurl, requestModelPut1, "https"), + expectedCode); + }); + }); + group('PATCH Request', () { + test('PATCH 1', () { + const expectedCode = r''' 1, + CURLOPT_CUSTOMREQUEST => 'PATCH', + CURLOPT_HTTPHEADER => $headers, + CURLOPT_POSTFIELDS => $request_body, + CURLOPT_FOLLOWLOCATION => true, +]); + +$response = curl_exec($request); + +curl_close($request); + +$httpCode = curl_getinfo($request, CURLINFO_HTTP_CODE); +echo "Status Code: " . $httpCode . "\n"; +echo $response . "\n"; +'''; + expect( + codeGen.getCode(CodegenLanguage.phpCurl, requestModelPatch1, "https"), + expectedCode); + }); + }); + group('DELETE Request', () { + test('DELETE 1', () { + const expectedCode = r''' 1, + CURLOPT_CUSTOMREQUEST => 'DELETE', + CURLOPT_FOLLOWLOCATION => true, +]); + +$response = curl_exec($request); + +curl_close($request); + +$httpCode = curl_getinfo($request, CURLINFO_HTTP_CODE); +echo "Status Code: " . $httpCode . "\n"; +echo $response . "\n"; +'''; + expect( + codeGen.getCode( + CodegenLanguage.phpCurl, requestModelDelete1, "https"), + expectedCode); + }); + test('DELETE 2', () { + const expectedCode = r''' 1, + CURLOPT_CUSTOMREQUEST => 'DELETE', + CURLOPT_HTTPHEADER => $headers, + CURLOPT_POSTFIELDS => $request_body, + CURLOPT_FOLLOWLOCATION => true, +]); + +$response = curl_exec($request); + +curl_close($request); + +$httpCode = curl_getinfo($request, CURLINFO_HTTP_CODE); +echo "Status Code: " . $httpCode . "\n"; +echo $response . "\n"; +'''; + expect( + codeGen.getCode( + CodegenLanguage.phpCurl, requestModelDelete2, "https"), + expectedCode); + }); + }); +} diff --git a/test/codegen/ruby_faraday_codegen_test.dart b/test/codegen/ruby_faraday_codegen_test.dart new file mode 100644 index 00000000..e7cf604e --- /dev/null +++ b/test/codegen/ruby_faraday_codegen_test.dart @@ -0,0 +1,775 @@ +import 'package:apidash/codegen/codegen.dart'; +import 'package:apidash/consts.dart'; +import 'package:test/test.dart'; +import '../request_models.dart'; + +void main() { + final codeGen = Codegen(); + + group('GET Request', () { + test('GET 1', () { + const expectedCode = r"""require 'uri' +require 'faraday' + +REQUEST_URL = URI("https://api.apidash.dev") + +conn = Faraday.new do |faraday| + faraday.adapter Faraday.default_adapter +end + +response = conn.get(REQUEST_URL) do |req| +end + +puts "Status Code: #{response.status}" +puts "Response Body: #{response.body}" +"""; + expect( + codeGen.getCode( + CodegenLanguage.rubyFaraday, requestModelGet1, "https"), + expectedCode); + }); + + test('GET 2', () { + const expectedCode = r"""require 'uri' +require 'faraday' + +REQUEST_URL = URI("https://api.apidash.dev/country/data") + +conn = Faraday.new do |faraday| + faraday.adapter Faraday.default_adapter +end + +response = conn.get(REQUEST_URL) do |req| + req.params = { + "code" => "US", + } +end + +puts "Status Code: #{response.status}" +puts "Response Body: #{response.body}" +"""; + expect( + codeGen.getCode( + CodegenLanguage.rubyFaraday, requestModelGet2, "https"), + expectedCode); + }); + + test('GET 3', () { + const expectedCode = r"""require 'uri' +require 'faraday' + +REQUEST_URL = URI("https://api.apidash.dev/country/data") + +conn = Faraday.new do |faraday| + faraday.adapter Faraday.default_adapter +end + +response = conn.get(REQUEST_URL) do |req| + req.params = { + "code" => "IND", + } +end + +puts "Status Code: #{response.status}" +puts "Response Body: #{response.body}" +"""; + expect( + codeGen.getCode( + CodegenLanguage.rubyFaraday, requestModelGet3, "https"), + expectedCode); + }); + + test('GET 4', () { + const expectedCode = r"""require 'uri' +require 'faraday' + +REQUEST_URL = URI("https://api.apidash.dev/humanize/social") + +conn = Faraday.new do |faraday| + faraday.adapter Faraday.default_adapter +end + +response = conn.get(REQUEST_URL) do |req| + req.params = { + "num" => "8700000", + "digits" => "3", + "system" => "SS", + "add_space" => "true", + "trailing_zeros" => "true", + } +end + +puts "Status Code: #{response.status}" +puts "Response Body: #{response.body}" +"""; + expect( + codeGen.getCode( + CodegenLanguage.rubyFaraday, requestModelGet4, "https"), + expectedCode); + }); + + test('GET 5', () { + const expectedCode = r"""require 'uri' +require 'faraday' + +REQUEST_URL = URI("https://api.github.com/repos/foss42/apidash") + +conn = Faraday.new do |faraday| + faraday.adapter Faraday.default_adapter +end + +response = conn.get(REQUEST_URL) do |req| + req.headers = { + "User-Agent" => "Test Agent", + } +end + +puts "Status Code: #{response.status}" +puts "Response Body: #{response.body}" +"""; + expect( + codeGen.getCode( + CodegenLanguage.rubyFaraday, requestModelGet5, "https"), + expectedCode); + }); + + test('GET 6', () { + const expectedCode = r"""require 'uri' +require 'faraday' + +REQUEST_URL = URI("https://api.github.com/repos/foss42/apidash") + +conn = Faraday.new do |faraday| + faraday.adapter Faraday.default_adapter +end + +response = conn.get(REQUEST_URL) do |req| + req.headers = { + "User-Agent" => "Test Agent", + } + req.params = { + "raw" => "true", + } +end + +puts "Status Code: #{response.status}" +puts "Response Body: #{response.body}" +"""; + expect( + codeGen.getCode( + CodegenLanguage.rubyFaraday, requestModelGet6, "https"), + expectedCode); + }); + + test('GET 7', () { + const expectedCode = r"""require 'uri' +require 'faraday' + +REQUEST_URL = URI("https://api.apidash.dev") + +conn = Faraday.new do |faraday| + faraday.adapter Faraday.default_adapter +end + +response = conn.get(REQUEST_URL) do |req| +end + +puts "Status Code: #{response.status}" +puts "Response Body: #{response.body}" +"""; + expect( + codeGen.getCode( + CodegenLanguage.rubyFaraday, requestModelGet7, "https"), + expectedCode); + }); + + test('GET 8', () { + const expectedCode = r"""require 'uri' +require 'faraday' + +REQUEST_URL = URI("https://api.github.com/repos/foss42/apidash") + +conn = Faraday.new do |faraday| + faraday.adapter Faraday.default_adapter +end + +response = conn.get(REQUEST_URL) do |req| + req.headers = { + "User-Agent" => "Test Agent", + } + req.params = { + "raw" => "true", + } +end + +puts "Status Code: #{response.status}" +puts "Response Body: #{response.body}" +"""; + expect( + codeGen.getCode( + CodegenLanguage.rubyFaraday, requestModelGet8, "https"), + expectedCode); + }); + + test('GET 9', () { + const expectedCode = r"""require 'uri' +require 'faraday' + +REQUEST_URL = URI("https://api.apidash.dev/humanize/social") + +conn = Faraday.new do |faraday| + faraday.adapter Faraday.default_adapter +end + +response = conn.get(REQUEST_URL) do |req| + req.params = { + "num" => "8700000", + "add_space" => "true", + } +end + +puts "Status Code: #{response.status}" +puts "Response Body: #{response.body}" +"""; + expect( + codeGen.getCode( + CodegenLanguage.rubyFaraday, requestModelGet9, "https"), + expectedCode); + }); + + test('GET 10', () { + const expectedCode = r"""require 'uri' +require 'faraday' + +REQUEST_URL = URI("https://api.apidash.dev/humanize/social") + +conn = Faraday.new do |faraday| + faraday.adapter Faraday.default_adapter +end + +response = conn.get(REQUEST_URL) do |req| + req.headers = { + "User-Agent" => "Test Agent", + } +end + +puts "Status Code: #{response.status}" +puts "Response Body: #{response.body}" +"""; + expect( + codeGen.getCode( + CodegenLanguage.rubyFaraday, + requestModelGet10, + "https", + ), + expectedCode); + }); + + test('GET 11', () { + const expectedCode = r"""require 'uri' +require 'faraday' + +REQUEST_URL = URI("https://api.apidash.dev/humanize/social") + +conn = Faraday.new do |faraday| + faraday.adapter Faraday.default_adapter +end + +response = conn.get(REQUEST_URL) do |req| + req.headers = { + "User-Agent" => "Test Agent", + } + req.params = { + "num" => "8700000", + "digits" => "3", + } +end + +puts "Status Code: #{response.status}" +puts "Response Body: #{response.body}" +"""; + expect( + codeGen.getCode( + CodegenLanguage.rubyFaraday, requestModelGet11, "https"), + expectedCode); + }); + + test('GET 12', () { + const expectedCode = r"""require 'uri' +require 'faraday' + +REQUEST_URL = URI("https://api.apidash.dev/humanize/social") + +conn = Faraday.new do |faraday| + faraday.adapter Faraday.default_adapter +end + +response = conn.get(REQUEST_URL) do |req| +end + +puts "Status Code: #{response.status}" +puts "Response Body: #{response.body}" +"""; + expect( + codeGen.getCode( + CodegenLanguage.rubyFaraday, requestModelGet12, "https"), + expectedCode); + }); + }); + + group('HEAD Request', () { + test('HEAD 1', () { + const expectedCode = r"""require 'uri' +require 'faraday' + +REQUEST_URL = URI("https://api.apidash.dev") + +conn = Faraday.new do |faraday| + faraday.adapter Faraday.default_adapter +end + +response = conn.head(REQUEST_URL) do |req| +end + +puts "Status Code: #{response.status}" +puts "Response Body: #{response.body}" +"""; + expect( + codeGen.getCode( + CodegenLanguage.rubyFaraday, requestModelHead1, "https"), + expectedCode); + }); + + test('HEAD 2', () { + const expectedCode = r"""require 'uri' +require 'faraday' + +REQUEST_URL = URI("http://api.apidash.dev") + +conn = Faraday.new do |faraday| + faraday.adapter Faraday.default_adapter +end + +response = conn.head(REQUEST_URL) do |req| +end + +puts "Status Code: #{response.status}" +puts "Response Body: #{response.body}" +"""; + expect( + codeGen.getCode( + CodegenLanguage.rubyFaraday, requestModelHead2, "http"), + expectedCode); + }); + }); + + group('POST Request', () { + test('POST 1', () { + const expectedCode = r"""require 'uri' +require 'faraday' + +REQUEST_URL = URI("https://api.apidash.dev/case/lower") + +PAYLOAD = < "text/plain", + } +end + +puts "Status Code: #{response.status}" +puts "Response Body: #{response.body}" +"""; + expect( + codeGen.getCode( + CodegenLanguage.rubyFaraday, requestModelPost1, "https"), + expectedCode); + }); + + test('POST 2', () { + const expectedCode = r"""require 'uri' +require 'faraday' + +REQUEST_URL = URI("https://api.apidash.dev/case/lower") + +PAYLOAD = < "application/json", + } +end + +puts "Status Code: #{response.status}" +puts "Response Body: #{response.body}" +"""; + expect( + codeGen.getCode( + CodegenLanguage.rubyFaraday, requestModelPost2, "https"), + expectedCode); + }); + + test('POST 3', () { + const expectedCode = r"""require 'uri' +require 'faraday' + +REQUEST_URL = URI("https://api.apidash.dev/case/lower") + +PAYLOAD = < "Test Agent", + "Content-Type" => "application/json", + } +end + +puts "Status Code: #{response.status}" +puts "Response Body: #{response.body}" +"""; + expect( + codeGen.getCode( + CodegenLanguage.rubyFaraday, requestModelPost3, "https"), + expectedCode); + }); + + test('POST 4', () { + const expectedCode = r"""require 'uri' +require 'faraday' + +REQUEST_URL = URI("https://api.apidash.dev/io/form") + +PAYLOAD = URI.encode_www_form({ + "text" => "API", + "sep" => "|", + "times" => "3", +}) + +conn = Faraday.new do |faraday| + faraday.adapter Faraday.default_adapter +end + +response = conn.post(REQUEST_URL, PAYLOAD) do |req| +end + +puts "Status Code: #{response.status}" +puts "Response Body: #{response.body}" +"""; + expect( + codeGen.getCode( + CodegenLanguage.rubyFaraday, + requestModelPost4, + "https", + ), + expectedCode); + }); + test('POST 5', () { + const expectedCode = r"""require 'uri' +require 'faraday' + +REQUEST_URL = URI("https://api.apidash.dev/io/form") + +PAYLOAD = URI.encode_www_form({ + "text" => "API", + "sep" => "|", + "times" => "3", +}) + +conn = Faraday.new do |faraday| + faraday.adapter Faraday.default_adapter +end + +response = conn.post(REQUEST_URL, PAYLOAD) do |req| + req.headers = { + "User-Agent" => "Test Agent", + } +end + +puts "Status Code: #{response.status}" +puts "Response Body: #{response.body}" +"""; + expect( + codeGen.getCode( + CodegenLanguage.rubyFaraday, requestModelPost5, "https"), + expectedCode); + }); + test('POST 6', () { + const expectedCode = r"""require 'uri' +require 'faraday' +require 'faraday/multipart' + +REQUEST_URL = URI("https://api.apidash.dev/io/img") + +PAYLOAD = { + "token" => Faraday::Multipart::ParamPart.new("xyz", "text/plain"), + "imfile" => Faraday::Multipart::FilePart.new("/Documents/up/1.png", "application/octet-stream"), +} + +conn = Faraday.new do |faraday| + faraday.adapter Faraday.default_adapter + faraday.request :multipart +end + +response = conn.post(REQUEST_URL, PAYLOAD) do |req| +end + +puts "Status Code: #{response.status}" +puts "Response Body: #{response.body}" +"""; + expect( + codeGen.getCode( + CodegenLanguage.rubyFaraday, requestModelPost6, "https"), + expectedCode); + }); + test('POST 7', () { + const expectedCode = r"""require 'uri' +require 'faraday' +require 'faraday/multipart' + +REQUEST_URL = URI("https://api.apidash.dev/io/img") + +PAYLOAD = { + "token" => Faraday::Multipart::ParamPart.new("xyz", "text/plain"), + "imfile" => Faraday::Multipart::FilePart.new("/Documents/up/1.png", "application/octet-stream"), +} + +conn = Faraday.new do |faraday| + faraday.adapter Faraday.default_adapter + faraday.request :multipart +end + +response = conn.post(REQUEST_URL, PAYLOAD) do |req| +end + +puts "Status Code: #{response.status}" +puts "Response Body: #{response.body}" +"""; + expect( + codeGen.getCode( + CodegenLanguage.rubyFaraday, requestModelPost7, "https"), + expectedCode); + }); + test('POST 8', () { + const expectedCode = r"""require 'uri' +require 'faraday' + +REQUEST_URL = URI("https://api.apidash.dev/io/form") + +PAYLOAD = URI.encode_www_form({ + "text" => "API", + "sep" => "|", + "times" => "3", +}) + +conn = Faraday.new do |faraday| + faraday.adapter Faraday.default_adapter +end + +response = conn.post(REQUEST_URL, PAYLOAD) do |req| + req.params = { + "size" => "2", + "len" => "3", + } +end + +puts "Status Code: #{response.status}" +puts "Response Body: #{response.body}" +"""; + expect( + codeGen.getCode( + CodegenLanguage.rubyFaraday, requestModelPost8, "https"), + expectedCode); + }); + test('POST 9', () { + const expectedCode = r"""require 'uri' +require 'faraday' +require 'faraday/multipart' + +REQUEST_URL = URI("https://api.apidash.dev/io/img") + +PAYLOAD = { + "token" => Faraday::Multipart::ParamPart.new("xyz", "text/plain"), + "imfile" => Faraday::Multipart::FilePart.new("/Documents/up/1.png", "application/octet-stream"), +} + +conn = Faraday.new do |faraday| + faraday.adapter Faraday.default_adapter + faraday.request :multipart +end + +response = conn.post(REQUEST_URL, PAYLOAD) do |req| + req.headers = { + "User-Agent" => "Test Agent", + "Keep-Alive" => "true", + } + req.params = { + "size" => "2", + "len" => "3", + } +end + +puts "Status Code: #{response.status}" +puts "Response Body: #{response.body}" +"""; + expect( + codeGen.getCode( + CodegenLanguage.rubyFaraday, requestModelPost9, "https"), + expectedCode); + }); + }); + + group('PUT Request', () { + test('PUT 1', () { + const expectedCode = r"""require 'uri' +require 'faraday' + +REQUEST_URL = URI("https://reqres.in/api/users/2") + +PAYLOAD = < "application/json", + } +end + +puts "Status Code: #{response.status}" +puts "Response Body: #{response.body}" +"""; + expect( + codeGen.getCode( + CodegenLanguage.rubyFaraday, requestModelPut1, "https"), + expectedCode); + }); + }); + + group('PATCH Request', () { + test('PATCH 1', () { + const expectedCode = r"""require 'uri' +require 'faraday' + +REQUEST_URL = URI("https://reqres.in/api/users/2") + +PAYLOAD = < "application/json", + } +end + +puts "Status Code: #{response.status}" +puts "Response Body: #{response.body}" +"""; + expect( + codeGen.getCode( + CodegenLanguage.rubyFaraday, requestModelPatch1, "https"), + expectedCode); + }); + }); + + group('DELETE Request', () { + test('DELETE 1', () { + const expectedCode = r"""require 'uri' +require 'faraday' + +REQUEST_URL = URI("https://reqres.in/api/users/2") + +conn = Faraday.new do |faraday| + faraday.adapter Faraday.default_adapter +end + +response = conn.delete(REQUEST_URL) do |req| +end + +puts "Status Code: #{response.status}" +puts "Response Body: #{response.body}" +"""; + expect( + codeGen.getCode( + CodegenLanguage.rubyFaraday, requestModelDelete1, "https"), + expectedCode); + }); + + test('DELETE 2', () { + const expectedCode = r"""require 'uri' +require 'faraday' + +REQUEST_URL = URI("https://reqres.in/api/users/2") + +PAYLOAD = < "application/json", + } + req.body = PAYLOAD +end + +puts "Status Code: #{response.status}" +puts "Response Body: #{response.body}" +"""; + expect( + codeGen.getCode( + CodegenLanguage.rubyFaraday, requestModelDelete2, "https"), + expectedCode); + }); + }); +} diff --git a/test/codegen/ruby_net_http_codegen_test.dart b/test/codegen/ruby_net_http_codegen_test.dart new file mode 100644 index 00000000..6ac3b09b --- /dev/null +++ b/test/codegen/ruby_net_http_codegen_test.dart @@ -0,0 +1,620 @@ +import 'package:apidash/codegen/codegen.dart'; +import 'package:apidash/consts.dart'; +import 'package:test/test.dart'; +import '../request_models.dart'; + +void main() { + final codeGen = Codegen(); + + group('GET Request', () { + test('GET 1', () { + const expectedCode = r"""require "uri" +require "net/http" + +url = URI("https://api.apidash.dev") +https = Net::HTTP.new(url.host, url.port) +https.use_ssl = true +request = Net::HTTP::Get.new(url) +response = https.request(request) + +puts "Response Code: #{response.code}" +puts "Response Body: #{response.body}" +"""; + expect( + codeGen.getCode( + CodegenLanguage.rubyNetHttp, requestModelGet1, "https"), + expectedCode); + }); + + test('GET 2', () { + const expectedCode = r"""require "uri" +require "net/http" + +url = URI("https://api.apidash.dev/country/data?code=US") +https = Net::HTTP.new(url.host, url.port) +https.use_ssl = true +request = Net::HTTP::Get.new(url) +response = https.request(request) + +puts "Response Code: #{response.code}" +puts "Response Body: #{response.body}" +"""; + expect( + codeGen.getCode( + CodegenLanguage.rubyNetHttp, requestModelGet2, "https"), + expectedCode); + }); + + test('GET 3', () { + const expectedCode = r"""require "uri" +require "net/http" + +url = URI("https://api.apidash.dev/country/data?code=IND") +https = Net::HTTP.new(url.host, url.port) +https.use_ssl = true +request = Net::HTTP::Get.new(url) +response = https.request(request) + +puts "Response Code: #{response.code}" +puts "Response Body: #{response.body}" +"""; + expect( + codeGen.getCode( + CodegenLanguage.rubyNetHttp, requestModelGet3, "https"), + expectedCode); + }); + + test('GET 4', () { + const expectedCode = r"""require "uri" +require "net/http" + +url = URI("https://api.apidash.dev/humanize/social?num=8700000&digits=3&system=SS&add_space=true&trailing_zeros=true") +https = Net::HTTP.new(url.host, url.port) +https.use_ssl = true +request = Net::HTTP::Get.new(url) +response = https.request(request) + +puts "Response Code: #{response.code}" +puts "Response Body: #{response.body}" +"""; + expect( + codeGen.getCode( + CodegenLanguage.rubyNetHttp, requestModelGet4, "https"), + expectedCode); + }); + + test('GET 5', () { + const expectedCode = r"""require "uri" +require "net/http" + +url = URI("https://api.github.com/repos/foss42/apidash") +https = Net::HTTP.new(url.host, url.port) +https.use_ssl = true +request = Net::HTTP::Get.new(url) +request["User-Agent"] = "Test Agent" +response = https.request(request) + +puts "Response Code: #{response.code}" +puts "Response Body: #{response.body}" +"""; + expect( + codeGen.getCode( + CodegenLanguage.rubyNetHttp, requestModelGet5, "https"), + expectedCode); + }); + + test('GET 6', () { + const expectedCode = r"""require "uri" +require "net/http" + +url = URI("https://api.github.com/repos/foss42/apidash?raw=true") +https = Net::HTTP.new(url.host, url.port) +https.use_ssl = true +request = Net::HTTP::Get.new(url) +request["User-Agent"] = "Test Agent" +response = https.request(request) + +puts "Response Code: #{response.code}" +puts "Response Body: #{response.body}" +"""; + expect( + codeGen.getCode( + CodegenLanguage.rubyNetHttp, requestModelGet6, "https"), + expectedCode); + }); + + test('GET 7', () { + const expectedCode = r"""require "uri" +require "net/http" + +url = URI("https://api.apidash.dev") +https = Net::HTTP.new(url.host, url.port) +https.use_ssl = true +request = Net::HTTP::Get.new(url) +response = https.request(request) + +puts "Response Code: #{response.code}" +puts "Response Body: #{response.body}" +"""; + expect( + codeGen.getCode( + CodegenLanguage.rubyNetHttp, requestModelGet7, "https"), + expectedCode); + }); + + test('GET 8', () { + const expectedCode = r"""require "uri" +require "net/http" + +url = URI("https://api.github.com/repos/foss42/apidash?raw=true") +https = Net::HTTP.new(url.host, url.port) +https.use_ssl = true +request = Net::HTTP::Get.new(url) +request["User-Agent"] = "Test Agent" +response = https.request(request) + +puts "Response Code: #{response.code}" +puts "Response Body: #{response.body}" +"""; + expect( + codeGen.getCode( + CodegenLanguage.rubyNetHttp, requestModelGet8, "https"), + expectedCode); + }); + + test('GET 9', () { + const expectedCode = r"""require "uri" +require "net/http" + +url = URI("https://api.apidash.dev/humanize/social?num=8700000&add_space=true") +https = Net::HTTP.new(url.host, url.port) +https.use_ssl = true +request = Net::HTTP::Get.new(url) +response = https.request(request) + +puts "Response Code: #{response.code}" +puts "Response Body: #{response.body}" +"""; + expect( + codeGen.getCode( + CodegenLanguage.rubyNetHttp, requestModelGet9, "https"), + expectedCode); + }); + + test('GET 10', () { + const expectedCode = r"""require "uri" +require "net/http" + +url = URI("https://api.apidash.dev/humanize/social") +https = Net::HTTP.new(url.host, url.port) +https.use_ssl = true +request = Net::HTTP::Get.new(url) +request["User-Agent"] = "Test Agent" +response = https.request(request) + +puts "Response Code: #{response.code}" +puts "Response Body: #{response.body}" +"""; + expect( + codeGen.getCode( + CodegenLanguage.rubyNetHttp, + requestModelGet10, + "https", + ), + expectedCode); + }); + + test('GET 11', () { + const expectedCode = r"""require "uri" +require "net/http" + +url = URI("https://api.apidash.dev/humanize/social?num=8700000&digits=3") +https = Net::HTTP.new(url.host, url.port) +https.use_ssl = true +request = Net::HTTP::Get.new(url) +request["User-Agent"] = "Test Agent" +response = https.request(request) + +puts "Response Code: #{response.code}" +puts "Response Body: #{response.body}" +"""; + expect( + codeGen.getCode( + CodegenLanguage.rubyNetHttp, requestModelGet11, "https"), + expectedCode); + }); + + test('GET 12', () { + const expectedCode = r"""require "uri" +require "net/http" + +url = URI("https://api.apidash.dev/humanize/social") +https = Net::HTTP.new(url.host, url.port) +https.use_ssl = true +request = Net::HTTP::Get.new(url) +response = https.request(request) + +puts "Response Code: #{response.code}" +puts "Response Body: #{response.body}" +"""; + expect( + codeGen.getCode( + CodegenLanguage.rubyNetHttp, requestModelGet12, "https"), + expectedCode); + }); + }); + + group('HEAD Request', () { + test('HEAD 1', () { + const expectedCode = r"""require "uri" +require "net/http" + +url = URI("https://api.apidash.dev") +https = Net::HTTP.new(url.host, url.port) +https.use_ssl = true +request = Net::HTTP::Head.new(url) +response = https.request(request) + +puts "Response Code: #{response.code}" +puts "Response Body: #{response.to_hash}" +"""; + expect( + codeGen.getCode( + CodegenLanguage.rubyNetHttp, requestModelHead1, "https"), + expectedCode); + }); + + test('HEAD 2', () { + const expectedCode = r"""require "uri" +require "net/http" + +url = URI("http://api.apidash.dev") +https = Net::HTTP.new(url.host, url.port) + +request = Net::HTTP::Head.new(url) +response = https.request(request) + +puts "Response Code: #{response.code}" +puts "Response Body: #{response.to_hash}" +"""; + expect( + codeGen.getCode( + CodegenLanguage.rubyNetHttp, requestModelHead2, "http"), + expectedCode); + }); + }); + + group('POST Request', () { + test('POST 1', () { + const expectedCode = r"""require "uri" +require "net/http" + +url = URI("https://api.apidash.dev/case/lower") +https = Net::HTTP.new(url.host, url.port) +https.use_ssl = true +request = Net::HTTP::Post.new(url) +request["Content-Type"] = "text/plain" +request.body = < 1), + ], + child: const MaterialApp( + home: Dashboard(), + ), + ), + ); + + // Verify that the IntroPage is displayed + expect(find.byType(IntroPage), findsOneWidget); + expect(find.byType(HomePage), findsNothing); + expect(find.byType(SettingsPage), findsNothing); + }); + + testWidgets( + "Dashboard should display SettingsPage when navRailIndexStateProvider is 2", + (WidgetTester tester) async { + await tester.pumpWidget( + ProviderScope( + overrides: [ + navRailIndexStateProvider.overrideWith((ref) => 2), + ], + child: const MaterialApp( + home: Dashboard(), + ), + ), + ); + + // Verify that the SettingsPage is displayed + expect(find.byType(SettingsPage), findsOneWidget); + expect(find.byType(IntroPage), findsNothing); + expect(find.byType(HomePage), findsNothing); + }); + + testWidgets( + 'navRailIndexStateProvider should update when icon button is pressed', + (tester) async { + await tester.pumpWidget( + const ProviderScope( + child: MaterialApp( + home: Dashboard(), + ), + ), + ); + + // Tap on the Intro icon + await tester.tap(find.byIcon(Icons.help_outline)); + await tester.pump(); + + // Verify that the navRailIndexStateProvider is updated + final dashboard = tester.element(find.byType(Dashboard)); + final container = ProviderScope.containerOf(dashboard); + expect(container.read(navRailIndexStateProvider), 1); + }); + + testWidgets( + 'navRailIndexStateProvider should persist across widget rebuilds', + (tester) async { + // Pump the initial widget tree + await tester.pumpWidget( + const ProviderScope( + child: MaterialApp( + home: Dashboard(), + ), + ), + ); + + // Tap on the Settings icon to change the index to 2 + await tester.tap(find.byIcon(Icons.settings_outlined)); + await tester.pump(); + + // Rebuild the widget tree with the same ProviderScope + await tester.pumpWidget( + const ProviderScope( + child: MaterialApp( + home: Dashboard(), + ), + ), + ); + + // Verify that the navRailIndexStateProvider still has the updated value + final dashboard = tester.element(find.byType(Dashboard)); + final container = ProviderScope.containerOf(dashboard); + expect(container.read(navRailIndexStateProvider), 2); + + // Verify that the SettingsPage is still displayed after the rebuild + expect(find.byType(SettingsPage), findsOneWidget); + expect(find.byType(IntroPage), findsNothing); + expect(find.byType(HomePage), findsNothing); + }); + + testWidgets( + 'UI should update correctly when navRailIndexStateProvider changes', + (tester) async { + await tester.pumpWidget( + const ProviderScope( + child: MaterialApp( + home: Dashboard(), + ), + ), + ); + + // Grab the Dashboard widget and its ProviderContainer + final dashboard = tester.element(find.byType(Dashboard)); + final container = ProviderScope.containerOf(dashboard); + + // Go to IntroPage + container.read(navRailIndexStateProvider.notifier).state = 1; + await tester.pump(); + + // Verify that the IntroPage is displayed + expect(find.byType(IntroPage), findsOneWidget); + // Verify that the selected icon is the filled version (selectedIcon) + expect(find.byIcon(Icons.help), findsOneWidget); + + // Go to SettingsPage + container.read(navRailIndexStateProvider.notifier).state = 2; + await tester.pump(); + + // Verify that the SettingsPage is displayed + expect(find.byType(SettingsPage), findsOneWidget); + // Verify that the selected icon is the filled version (selectedIcon) + expect(find.byIcon(Icons.settings), findsOneWidget); + }); + + testWidgets( + 'navRailIndexStateProvider should be disposed when Dashboard is removed', + (tester) async { + await tester.pumpWidget( + const ProviderScope( + child: MaterialApp( + home: Dashboard(), + ), + ), + ); + + // Grab the Dashboard widget and its ProviderContainer + final dashboard = tester.element(find.byType(Dashboard)); + final container = ProviderScope.containerOf(dashboard); + + // Pumping a different widget to remove the Dashboard from the widget tree + await tester.pumpWidget( + const MaterialApp( + home: Scaffold(body: Text('Different Widget')), + ), + ); + + // Verify that the ProviderContainer has been disposed + // by trying to read from disposed container + bool isDisposed = false; + try { + container.read(navRailIndexStateProvider); + } catch (e) { + isDisposed = true; + } + expect(isDisposed, true); + }); + }); + + group("Testing selectedIdEditStateProvider", () { + testWidgets('It should have an initial value of null', (tester) async { + await tester.pumpWidget( + const ProviderScope( + child: MaterialApp( + home: Scaffold( + body: CollectionPane(), + ), + ), + ), + ); + + // Verify that the initial value is null + final collectionPane = tester.element(find.byType(CollectionPane)); + final container = ProviderScope.containerOf(collectionPane); + expect(container.read(selectedIdEditStateProvider), null); + }); + + testWidgets( + 'selectedIdEditStateProvider should not be null after rename button has been tapped', + (tester) async { + await tester.pumpWidget( + const ProviderScope( + child: MaterialApp( + home: Scaffold( + body: CollectionPane(), + ), + ), + ), + ); + + // Tap on the three dots to open the request card menu + await tester.tap(find.byType(RequestList)); + await tester.pump(); + await tester.tap(find.byType(RequestItem)); + await tester.pump(); + await tester.tap(find.byIcon(Icons.more_vert).first); + await tester.pumpAndSettle(); + + // Tap on the "Rename" option in the menu + await tester.tap(find.text('Rename')); + await tester.pumpAndSettle(); + + // Verify that the selectedIdEditStateProvider is not null + final collectionPane = tester.element(find.byType(CollectionPane)); + final container = ProviderScope.containerOf(collectionPane); + expect(container.read(selectedIdEditStateProvider), isNotNull); + expect((container.read(selectedIdEditStateProvider)).runtimeType, String); + }); + + testWidgets( + 'It should be set back to null when user taps outside name editor', + (tester) async { + await tester.pumpWidget( + const ProviderScope( + child: MaterialApp( + home: Scaffold( + body: CollectionPane(), + ), + ), + ), + ); + + // Grab the CollectionPane widget and its ProviderContainer + final collectionPane = tester.element(find.byType(CollectionPane)); + final container = ProviderScope.containerOf(collectionPane); + + // Tap on the three dots to open the request card menu + await tester.tap(find.byType(RequestList)); + await tester.pump(); + await tester.tap(find.byType(RequestItem)); + await tester.pump(); + await tester.tap(find.byIcon(Icons.more_vert).first); + await tester.pumpAndSettle(); + + // Tap on the "Rename" option in the menu + await tester.tap(find.text('Rename')); + await tester.pumpAndSettle(); + + // Verify that the selectedIdEditStateProvider is not null + expect(container.read(selectedIdEditStateProvider), isNotNull); + expect((container.read(selectedIdEditStateProvider)).runtimeType, String); + + // Tap on the screen to simulate tapping outside the name editor + await tester.tap(find.byType(CollectionPane)); + await tester.pumpAndSettle(); + + // Verify that the selectedIdEditStateProvider is null + expect(container.read(selectedIdEditStateProvider), null); + }); + testWidgets("It should be properly disposed", (tester) async { + await tester.pumpWidget( + const ProviderScope( + child: MaterialApp( + home: Scaffold( + body: CollectionPane(), + ), + ), + ), + ); + + // Grab the Dashboard widget and its ProviderContainer + final collectionPane = tester.element(find.byType(CollectionPane)); + final container = ProviderScope.containerOf(collectionPane); + + // Pumping a different widget to remove the CollectionPane from the widget tree + await tester.pumpWidget( + const MaterialApp( + home: Scaffold(body: Text('Foo')), + ), + ); + + // Verify that the ProviderContainer has been disposed + // by trying to read from disposed container + bool isDisposed = false; + try { + container.read(selectedIdEditStateProvider); + } catch (e) { + isDisposed = true; + } + expect(isDisposed, true); + }); + }); + + group('Testing codePaneVisibleStateProvider', () { + testWidgets("It should have have an initial value of false", + (tester) async { + await tester.pumpWidget( + const ProviderScope( + child: MaterialApp( + home: RequestEditorPane(), + ), + ), + ); + + // Verify that the initial value is false + final editorPane = tester.element(find.byType(RequestEditorPane)); + final container = ProviderScope.containerOf(editorPane); + expect(container.read(codePaneVisibleStateProvider), false); + }); + + testWidgets("When state is false ResponsePane should be visible", + (tester) async { + await tester.pumpWidget( + const ProviderScope( + child: MaterialApp( + home: RequestEditorPane(), + ), + ), + ); + + expect(find.byType(RequestEditorDefault), findsOneWidget); + + // Tap on the "Plus New" button + Finder plusNewButton = find.descendant( + of: find.byType(RequestEditorDefault), + matching: find.byType(ElevatedButton), + ); + await tester.tap(plusNewButton); + await tester.pump(); + + // Verify that NotSentWidget is visible + expect(find.byType(NotSentWidget), findsOneWidget); + + // Add some data in URLTextField + Finder field = find.descendant( + of: find.byType(URLField), + matching: find.byType(TextFormField), + ); + await tester.enterText(field, kTestUrl); + await tester.pump(); + + // Tap on the "Send" button + Finder sendButton = find.byType(SendButton); + await tester.tap(sendButton); + await tester.pump(); + + final editorPane = tester.element(find.byType(RequestEditorPane)); + final container = ProviderScope.containerOf(editorPane); + expect(container.read(codePaneVisibleStateProvider), false); + expect(find.byType(ResponsePane), findsOneWidget); + }); + + testWidgets("When state is true CodePane should be visible", + (tester) async { + await tester.pumpWidget( + const ProviderScope( + child: MaterialApp( + home: Scaffold( + body: RequestEditorPane(), + ), + ), + ), + ); + + expect(find.byType(RequestEditorDefault), findsOneWidget); + + // Tap on the "Plus New" button + Finder plusNewButton = find.descendant( + of: find.byType(RequestEditorDefault), + matching: find.byType(ElevatedButton), + ); + await tester.tap(plusNewButton); + await tester.pump(); + + // Verify that NotSentWidget is visible + expect(find.byType(NotSentWidget), findsOneWidget); + + // Add some data in URLTextField + Finder field = find.descendant( + of: find.byType(URLField), + matching: find.byType(TextFormField), + ); + await tester.enterText(field, kTestUrl); + await tester.pump(); + + // Tap on the "Send" button + Finder sendButton = find.byType(SendButton); + await tester.tap(sendButton); + await tester.pump(); + + final editorPane = tester.element(find.byType(RequestEditorPane)); + final container = ProviderScope.containerOf(editorPane); + // Change codePaneVisibleStateProvider state to true + container.read(codePaneVisibleStateProvider.notifier).state = true; + await tester.pump(); + + // Verify that the CodePane is visible + expect(container.read(codePaneVisibleStateProvider), true); + expect(find.byType(CodePane), findsOneWidget); + }); + + testWidgets("Hide/View Code button toggles the state", (tester) async { + await tester.pumpWidget( + const ProviderScope( + child: MaterialApp( + home: Scaffold( + body: RequestEditorPane(), + ), + ), + ), + ); + + expect(find.byType(RequestEditorDefault), findsOneWidget); + + // Tap on the "Plus New" button + Finder plusNewButton = find.descendant( + of: find.byType(RequestEditorDefault), + matching: find.byType(ElevatedButton), + ); + await tester.tap(plusNewButton); + await tester.pump(); + + // Verify that NotSentWidget is visible + expect(find.byType(NotSentWidget), findsOneWidget); + + // Add some data in URLTextField + Finder field = find.descendant( + of: find.byType(URLField), + matching: find.byType(TextFormField), + ); + await tester.enterText(field, kTestUrl); + await tester.pump(); + + // Tap on the "Send" button + Finder sendButton = find.byType(SendButton); + await tester.tap(sendButton); + await tester.pump(); + + final editorPane = tester.element(find.byType(RequestEditorPane)); + final container = ProviderScope.containerOf(editorPane); + final bool currentValue = container.read(codePaneVisibleStateProvider); + + // Click on View Code button + await tester.tap(find.byIcon(Icons.code_rounded)); + await tester.pump(); + + // Verify that the state value has changed + expect(container.read(codePaneVisibleStateProvider), !currentValue); + final bool newValue = container.read(codePaneVisibleStateProvider); + + // Click on Hide Code button + await tester.tap(find.byIcon(Icons.code_off_rounded)); + await tester.pump(); + + // Verify that the state value has changed + expect(container.read(codePaneVisibleStateProvider), !newValue); + }); + + testWidgets("That state persists across widget rebuilds", (tester) async { + await tester.pumpWidget( + const ProviderScope( + child: MaterialApp( + home: Scaffold( + body: RequestEditorPane(), + ), + ), + ), + ); + + expect(find.byType(RequestEditorDefault), findsOneWidget); + + // Tap on the "Plus New" button + Finder plusNewButton = find.descendant( + of: find.byType(RequestEditorDefault), + matching: find.byType(ElevatedButton), + ); + await tester.tap(plusNewButton); + await tester.pump(); + + // Verify that NotSentWidget is visible + expect(find.byType(NotSentWidget), findsOneWidget); + + // Add some data in URLTextField + Finder field = find.descendant( + of: find.byType(URLField), + matching: find.byType(TextFormField), + ); + await tester.enterText(field, kTestUrl); + await tester.pump(); + + // Tap on the "Send" button + Finder sendButton = find.byType(SendButton); + await tester.tap(sendButton); + await tester.pump(); + + final editorPane = tester.element(find.byType(RequestEditorPane)); + final container = ProviderScope.containerOf(editorPane); + final bool currentValue = container.read(codePaneVisibleStateProvider); + + // Click on View Code button + await tester.tap(find.byIcon(Icons.code_rounded)); + await tester.pump(); + + // Verify that the state value has changed + expect(container.read(codePaneVisibleStateProvider), !currentValue); + bool matcher = !currentValue; + + // Rebuild the widget tree + await tester.pumpWidget( + const ProviderScope( + child: MaterialApp( + home: Scaffold( + body: RequestEditorPane(), + ), + ), + ), + ); + + // Verify that the value of codePaneVisibleStateProvider is still true + final containerAfterRebuild = ProviderScope.containerOf(editorPane); + bool actual = containerAfterRebuild.read(codePaneVisibleStateProvider); + expect(actual, matcher); + }); + + testWidgets("That it is properly disposed", (tester) async { + await tester.pumpWidget( + const ProviderScope( + child: MaterialApp( + home: Scaffold( + body: RequestEditorPane(), + ), + ), + ), + ); + + // Verify that codePaneVisibleStateProvider is present + final editorPane = tester.element(find.byType(RequestEditorPane)); + final container = ProviderScope.containerOf(editorPane); + expect(container.read(codePaneVisibleStateProvider).runtimeType, bool); + + // Update the widget tree to dispose the provider + await tester.pumpWidget(const MaterialApp()); + + // Verify that the provider was disposed + expect(() => container.read(codePaneVisibleStateProvider), + throwsA(isA())); + expect( + () => container.read(codePaneVisibleStateProvider), + throwsA( + isA().having( + (e) => e.message, + 'message', + contains('was already disposed'), + ), + ), + ); + }); + }); +} diff --git a/test/test_consts.dart b/test/test_consts.dart index f0a9b779..6ef47887 100644 --- a/test/test_consts.dart +++ b/test/test_consts.dart @@ -1,5 +1,5 @@ -import 'package:flutter/material.dart'; import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; final kThemeDataDark = ThemeData( useMaterial3: true, @@ -13,6 +13,8 @@ final kThemeDataLight = ThemeData( brightness: Brightness.light, ); +const kTestUrl = 'https://api.apidash.dev'; + Uint8List kBodyBytesJpeg = Uint8List.fromList([ 255, 216, diff --git a/test/widgets/form_data_field_test.dart b/test/widgets/form_data_field_test.dart deleted file mode 100644 index b5748370..00000000 --- a/test/widgets/form_data_field_test.dart +++ /dev/null @@ -1,21 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:apidash/widgets/form_data_field.dart'; - -void main() { - testWidgets('Testing for Form Data Widget', (tester) async { - await tester.pumpWidget( - const MaterialApp( - title: 'Form Data Field Widget', - home: Scaffold( - body: FormDataField( - keyId: "1", - initialValue: "Test Field", - ), - ), - ), - ); - - expect(find.text("Test Field"), findsOneWidget); - }); -} diff --git a/test/widgets/previewer_test.dart b/test/widgets/previewer_test.dart index c26793bb..c8a33f62 100644 --- a/test/widgets/previewer_test.dart +++ b/test/widgets/previewer_test.dart @@ -5,6 +5,7 @@ import 'package:apidash/consts.dart'; import 'package:flutter/foundation.dart'; import 'package:printing/printing.dart' show PdfPreview; import 'package:flutter_svg/flutter_svg.dart' show SvgPicture; +import 'package:apidash/widgets/video_previewer.dart'; import '../test_consts.dart'; void main() { @@ -63,10 +64,7 @@ void main() { ), ), ); - - expect( - find.text("${kMimeTypeRaiseIssueStart}video/H264$kMimeTypeRaiseIssue"), - findsOneWidget); + expect(find.byType(VideoPreviewer), findsOneWidget); }); testWidgets('Testing when type/subtype is model/step+xml', (tester) async { diff --git a/test/widgets/request_widgets_test.dart b/test/widgets/request_widgets_test.dart index b50a033f..b47114b8 100644 --- a/test/widgets/request_widgets_test.dart +++ b/test/widgets/request_widgets_test.dart @@ -21,7 +21,6 @@ void main() { ); expect(find.byType(Center), findsAtLeastNWidgets(1)); - expect(find.text('Request'), findsOneWidget); expect(find.text('Hide Code'), findsOneWidget); expect(find.text('View Code'), findsNothing); expect(find.text('URL Params'), findsOneWidget); @@ -52,7 +51,6 @@ void main() { ); expect(find.byType(Center), findsAtLeastNWidgets(1)); - expect(find.text('Request'), findsOneWidget); expect(find.text('Hide Code'), findsOneWidget); expect(find.text('View Code'), findsNothing); expect(find.text('URL Params'), findsOneWidget); @@ -83,7 +81,6 @@ void main() { ); expect(find.byType(Center), findsAtLeastNWidgets(1)); - expect(find.text('Request'), findsOneWidget); expect(find.text('Hide Code'), findsNothing); expect(find.text('View Code'), findsOneWidget); expect(find.text('URL Params'), findsOneWidget); @@ -117,7 +114,6 @@ void main() { ); expect(find.byType(Center), findsAtLeastNWidgets(1)); - expect(find.text('Request'), findsOneWidget); expect(find.text('URL Params'), findsOneWidget); expect(find.text('Headers'), findsOneWidget); expect(find.text('Body'), findsOneWidget); diff --git a/test/widgets/response_widgets_test.dart b/test/widgets/response_widgets_test.dart index 7877a285..c5617035 100644 --- a/test/widgets/response_widgets_test.dart +++ b/test/widgets/response_widgets_test.dart @@ -10,13 +10,15 @@ import 'package:apidash/models/models.dart'; import '../test_consts.dart'; void main() { - testWidgets('Testing Sending Widget', (tester) async { + testWidgets('Testing Sending Widget Without Timer', (tester) async { await tester.pumpWidget( MaterialApp( title: 'Send', theme: kThemeDataDark, home: const Scaffold( - body: SendingWidget(), + body: SendingWidget( + startSendingTime: null, + ), ), ), ); @@ -24,6 +26,26 @@ void main() { expect(find.byType(Lottie), findsOneWidget); }); + testWidgets('Testing Sending Widget With Timer', (tester) async { + await tester.pumpWidget( + MaterialApp( + title: 'Send', + theme: kThemeDataDark, + home: Scaffold( + body: SendingWidget( + startSendingTime: DateTime.now(), + ), + ), + ), + ); + expect(find.text('Time elapsed: 0 ms'), findsOneWidget); + expect(find.byType(Lottie), findsOneWidget); + + await tester.pump(const Duration(seconds: 1)); + + expect(find.text('Time elapsed: 1.00 s'), findsOneWidget); + }); + testWidgets('Testing Not Sent Widget', (tester) async { await tester.pumpWidget( const MaterialApp( @@ -52,11 +74,8 @@ void main() { ), ); - expect(find.byType(RichText), findsAtLeastNWidgets(1)); - expect( - find.textContaining("Response (", findRichText: true), findsOneWidget); - expect(find.text('Hi'), findsOneWidget); expect(find.textContaining("200", findRichText: true), findsOneWidget); + expect(find.textContaining("Hi", findRichText: true), findsOneWidget); expect(find.text(humanizeDuration(const Duration(microseconds: 23))), findsOneWidget); }); @@ -73,7 +92,7 @@ void main() { ), ); - expect(find.text('Body'), findsOneWidget); + expect(find.text('Response Body'), findsOneWidget); expect(find.text('Headers'), findsOneWidget); await tester.tap(find.text('Headers')); @@ -81,7 +100,7 @@ void main() { expect(find.text('first'), findsNothing); expect(find.text('second'), findsOneWidget); - await tester.tap(find.text('Body')); + await tester.tap(find.text('Response Body')); await tester.pumpAndSettle(); expect(find.text('first'), findsOneWidget);