From f6440ec7d593aa3194a0a2df054d84e16a7a7a4a Mon Sep 17 00:00:00 2001
From: kirbylife <kirbylife@protonmail.com>
Date: Sat, 3 Apr 2021 18:36:30 -0600
Subject: [PATCH] add support to add args url-encoded to the requests

---
 src/request.rs      | 43 ++++++++++++++++++++++++++++++++++++++-----
 tests/unit_tests.rs | 33 ++++++++++++++++++++++-----------
 2 files changed, 60 insertions(+), 16 deletions(-)

diff --git a/src/request.rs b/src/request.rs
index c836efc..c153633 100644
--- a/src/request.rs
+++ b/src/request.rs
@@ -1,10 +1,17 @@
 use http::Method;
-use serde::Serialize;
 use url::ParseError;
 
 use crate::into_url::IntoUrl;
 use crate::response;
 
+#[derive(Clone)]
+pub enum ParameterType {
+    Number(isize),
+    Decimal(f64),
+    Boolean(bool),
+    Text(String),
+}
+
 pub trait RequestBase {
     fn new<T: IntoUrl>(url: T) -> Result<Self, ParseError>
     where
@@ -16,6 +23,7 @@ pub trait RequestBase {
 pub struct Request {
     pub url: url::Url,
     method: Method,
+    params: Vec<(String, String)>,
 }
 
 impl RequestBase for Request {
@@ -23,11 +31,16 @@ impl RequestBase for Request {
         url.into_url().map(|url_parsed| Request {
             url: url_parsed,
             method: Method::GET,
+            params: Vec::new(),
         })
     }
 
-    fn launch(self) -> response::Response {
+    fn launch(mut self) -> response::Response {
         let client = reqwest::blocking::Client::new();
+        for (key, value) in &self.params {
+            self.url.query_pairs_mut().append_pair(key, value);
+        }
+
         let resp = (match self.method {
             Method::GET => client.get(self.url.as_str()),
             Method::POST => client.post(self.url.as_str()),
@@ -42,7 +55,7 @@ impl RequestBase for Request {
         let status = resp.status();
         let text = resp.text().unwrap();
 
-        let url = self.url.clone();
+        let url = self.url;
 
         response::Response {
             text: text,
@@ -52,13 +65,33 @@ impl RequestBase for Request {
     }
 }
 
+impl std::string::ToString for ParameterType {
+    fn to_string(&self) -> String {
+        match self {
+            ParameterType::Number(n) => n.to_string(),
+            ParameterType::Decimal(n) => n.to_string(),
+            ParameterType::Boolean(n) => n.to_string(),
+            ParameterType::Text(t) => t.clone(),
+        }
+    }
+}
+
 impl Request {
     pub fn method(mut self, method: Method) -> Self {
         self.method = method;
         self
     }
 
-    pub fn add_attrs<T: Serialize + Sized>(self, _attrs: T) -> Self {
-        unimplemented!();
+    pub fn add_params<S: AsRef<str>, T: ToString>(mut self, params: Vec<(S, T)>) -> Self {
+        self.params = params
+            .iter()
+            .map(|item| (item.0.as_ref().to_string(), item.1.to_string()))
+            .collect();
+        self
+    }
+
+    pub fn add_param<S: AsRef<str>, T: ToString>(&mut self, key: S, value: T) {
+        self.params
+            .push((key.as_ref().to_string(), value.to_string()));
     }
 }
diff --git a/tests/unit_tests.rs b/tests/unit_tests.rs
index f4a98e7..2e111cc 100644
--- a/tests/unit_tests.rs
+++ b/tests/unit_tests.rs
@@ -1,6 +1,6 @@
 use http::Method;
 use http::StatusCode;
-use raspa::request::{Request, RequestBase};
+use raspa::request::{ParameterType, Request, RequestBase};
 use raspa::selector::{Selector, SelectorBase};
 use serde_json::Value;
 // use std::collections::HashMap;
@@ -124,13 +124,24 @@ fn simple_post_request() {
     assert_eq!(resp["url"].as_str().unwrap(), "https://httpbin.org/post");
 }
 
-// #[test]
-// fn complex_post_request() {
-//     let form = HashMap::new();
-//     let attrs = HashMap::new();
-//
-//     let resp = Request::new("https://httpbin.org/post")
-//         .unwrap()
-//         .method(Method::POST)
-//         .add_attrs()
-// }
+#[test]
+fn parameter_get_request() {
+    use ParameterType::*;
+
+    let mut req = Request::new("https://httpbin.org/get").unwrap().add_params(
+        [
+            ("param_str", Text("hello".to_string())),
+            ("param_num", Number(42)),
+            ("param_bool", Boolean(true)),
+        ]
+        .to_vec(),
+    );
+    req.add_param("param_float", 3.14159);
+    let resp: Value = req.launch().to_json().expect("cannot parse json");
+    println!("{}", resp);
+
+    assert_eq!(resp["args"]["param_str"].as_str(), Some("hello"));
+    assert_eq!(resp["args"]["param_num"].as_str(), Some("42"));
+    assert_eq!(resp["args"]["param_bool"].as_str(), Some("true"));
+    assert_eq!(resp["args"]["param_float"].as_str(), Some("3.14159"));
+}