<commit_before>#[macro_use] extern crate log;
#[macro_use] extern crate p_macro;
#[macro_use] extern crate maplit;
#[macro_use] extern crate lazy_static;
extern crate libc;
#[macro_use] extern crate libpact_v1_matching;
extern crate rustc_serialize;
extern crate env_logger;
#[macro_use] extern crate hyper;
extern crate uuid;

use libc::{c_char, int32_t};
use std::ffi::CStr;
use std::str;
use libpact_v1_matching::models::{Pact, Interaction, Request, Response, OptionalBody};
use libpact_v1_matching::models::parse_query_string;
use libpact_v1_matching::Mismatch;
use rustc_serialize::json;
use rustc_serialize::json::Json;
use std::collections::{BTreeMap, HashMap};
use std::cell::Cell;
use std::thread;
use std::sync::Mutex;
use std::sync::mpsc::channel;
use std::io::{Read, Write};
use hyper::server::Server;
use hyper::status::StatusCode;
use hyper::header::{Headers, ContentType, AccessControlAllowOrigin, ContentLength};
use hyper::mime::{Mime, TopLevel, SubLevel, Attr, Value};
use hyper::uri::RequestUri;
use uuid::Uuid;

#[derive(Debug, Clone, PartialEq)]
pub enum MatchResult {
    RequestMatch(Response),
    RequestMismatch(Vec<(Interaction, Vec<Mismatch>)>),
    RequestNotFound(Request)
}

impl MatchResult {
    pub fn match_key(&self) -> String {
        match self {
            &MatchResult::RequestMatch(_) => s!("Request-Matched"),
            &MatchResult::RequestMismatch(_) => s!("Request-Mismatch"),
            &MatchResult::RequestNotFound(_) => s!("Unexpected-Request")
        }
    }

    pub fn matched(&self) -> bool {
        match self {
            &MatchResult::RequestMatch(_) => true,
            _ => false
        }
    }
}

#[derive(Debug, Clone, PartialEq)]
pub struct MockServer {
    pub id: String,
    pub port: i32,
    pub matches: Vec<MatchResult>
}

impl MockServer {
    pub fn new(id: String) -> MockServer {
        MockServer { id: id.clone(), port: -1, matches: vec![] }
    }

    pub fn port(&mut self, port: i32) {
        self.port = port;
    }
}

lazy_static! {
    static ref MOCK_SERVERS: Mutex<BTreeMap<String, Box<MockServer>>> = Mutex::new(BTreeMap::new());
}

fn match_request(req: &Request, interactions: &Vec<Interaction>) -> MatchResult {
    let list = interactions.clone();
    let list: Vec<Interaction> = list.iter().filter(|i| {
        i.request.method == req.method && i.request.path == req.path
    }).map(|i| i.clone() ).collect();
    if list.is_empty() {
        MatchResult::RequestNotFound(req.clone())
    } else {
        let matches: Vec<(Interaction, Vec<Mismatch>)> = list.iter().map(|i| {
            let mismatches = libpact_v1_matching::match_request(i.request.clone(), req.clone());
            (i.clone(), mismatches)
        }).collect();
        match matches.iter().find(|i| i.1.is_empty()) {
            Some(i) => MatchResult::RequestMatch(i.clone().0.response),
            None => MatchResult::RequestMismatch(matches.clone())
        }
    }
}

fn extract_path(uri: &RequestUri) -> String {
    match uri {
        &RequestUri::AbsolutePath(ref s) => s!(s.splitn(2, "?").next().unwrap_or("/")),
        &RequestUri::AbsoluteUri(ref url) => url.path().unwrap_or(&[s!("")]).join("/"),
        _ => uri.to_string()
    }
}

fn extract_query_string(uri: &RequestUri) -> Option<HashMap<String, Vec<String>>> {
    match uri {
        &RequestUri::AbsolutePath(ref s) => match s.splitn(2, "?").last() {
            Some(q) => parse_query_string(&s!(q)),
            None => None
        },
        &RequestUri::AbsoluteUri(ref url) => match url.query {
            Some(ref q) => parse_query_string(q),
            None => None
        },
        _ => None<commit_msg>fix the query parsing when there is no query<commit_after>#[macro_use] extern crate log;
#[macro_use] extern crate p_macro;
#[macro_use] extern crate maplit;
#[macro_use] extern crate lazy_static;
extern crate libc;
#[macro_use] extern crate libpact_v1_matching;
extern crate rustc_serialize;
extern crate env_logger;
#[macro_use] extern crate hyper;
extern crate uuid;

use libc::{c_char, int32_t};
use std::ffi::CStr;
use std::str;
use libpact_v1_matching::models::{Pact, Interaction, Request, Response, OptionalBody};
use libpact_v1_matching::models::parse_query_string;
use libpact_v1_matching::Mismatch;
use rustc_serialize::json;
use rustc_serialize::json::Json;
use std::collections::{BTreeMap, HashMap};
use std::cell::Cell;
use std::thread;
use std::sync::Mutex;
use std::sync::mpsc::channel;
use std::io::{Read, Write};
use hyper::server::Server;
use hyper::status::StatusCode;
use hyper::header::{Headers, ContentType, AccessControlAllowOrigin, ContentLength};
use hyper::mime::{Mime, TopLevel, SubLevel, Attr, Value};
use hyper::uri::RequestUri;
use uuid::Uuid;

#[derive(Debug, Clone, PartialEq)]
pub enum MatchResult {
    RequestMatch(Response),
    RequestMismatch(Vec<(Interaction, Vec<Mismatch>)>),
    RequestNotFound(Request)
}

impl MatchResult {
    pub fn match_key(&self) -> String {
        match self {
            &MatchResult::RequestMatch(_) => s!("Request-Matched"),
            &MatchResult::RequestMismatch(_) => s!("Request-Mismatch"),
            &MatchResult::RequestNotFound(_) => s!("Unexpected-Request")
        }
    }

    pub fn matched(&self) -> bool {
        match self {
            &MatchResult::RequestMatch(_) => true,
            _ => false
        }
    }
}

#[derive(Debug, Clone, PartialEq)]
pub struct MockServer {
    pub id: String,
    pub port: i32,
    pub matches: Vec<MatchResult>
}

impl MockServer {
    pub fn new(id: String) -> MockServer {
        MockServer { id: id.clone(), port: -1, matches: vec![] }
    }

    pub fn port(&mut self, port: i32) {
        self.port = port;
    }
}

lazy_static! {
    static ref MOCK_SERVERS: Mutex<BTreeMap<String, Box<MockServer>>> = Mutex::new(BTreeMap::new());
}

fn match_request(req: &Request, interactions: &Vec<Interaction>) -> MatchResult {
    let list = interactions.clone();
    let list: Vec<Interaction> = list.iter().filter(|i| {
        i.request.method == req.method && i.request.path == req.path
    }).map(|i| i.clone() ).collect();
    if list.is_empty() {
        MatchResult::RequestNotFound(req.clone())
    } else {
        let matches: Vec<(Interaction, Vec<Mismatch>)> = list.iter().map(|i| {
            let mismatches = libpact_v1_matching::match_request(i.request.clone(), req.clone());
            (i.clone(), mismatches)
        }).collect();
        match matches.iter().find(|i| i.1.is_empty()) {
            Some(i) => MatchResult::RequestMatch(i.clone().0.response),
            None => MatchResult::RequestMismatch(matches.clone())
        }
    }
}

fn extract_path(uri: &RequestUri) -> String {
    match uri {
        &RequestUri::AbsolutePath(ref s) => s!(s.splitn(2, "?").next().unwrap_or("/")),
        &RequestUri::AbsoluteUri(ref url) => url.path().unwrap_or(&[s!("")]).join("/"),
        _ => uri.to_string()
    }
}

fn extract_query_string(uri: &RequestUri) -> Option<HashMap<String, Vec<String>>> {
    match uri {
        &RequestUri::AbsolutePath(ref s) => {
            if s.contains("?") {
                match s.splitn(2, "?").last() {
                    Some(q) => parse_query_string(&s!(q)),
                    None => None
                }
            } else {
                None
            }
        },
        &RequestUri::AbsoluteUri(ref url) => match url.query {
            Some(ref q) => parse_query_string(q),
            None => None
        },
        _ => None
{'fraction_non_alphanumeric': 0.16213333333333332, 'fraction_numerical': 0.004266666666666667, 'mean_word_length': 3.3408564814814814, 'pattern_counts': {'":': 0, '<': 29, '<?xml version=': 0, '>': 75, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7237176', 'n_tokens_mistral': 2438, 'n_tokens_neox': 2431, 'n_words': 511}