use std::fmt::{self, Debug, Display, Formatter};
use std::panic::RefUnwindSafe;
use std::sync::{Arc, Mutex};
use serde_json::Value;
use crate::bodies::OptionalBody;
use crate::content_types::ContentType;
use crate::matchingrules::MatchingRules;
use crate::message::Message;
use crate::PactSpecification;
use crate::provider_states::ProviderState;
use crate::sync_interaction::RequestResponseInteraction;
use crate::v4::async_message::AsynchronousMessage;
use crate::v4::interaction::{interaction_from_json, V4Interaction};
use crate::v4::sync_message::SynchronousMessage;
use crate::v4::synch_http::SynchronousHttp;
#[derive(Debug, Clone)]
pub struct PactConflict {
pub interaction: String,
pub description: String
}
pub trait Interaction: Debug {
fn type_of(&self) -> String;
fn is_request_response(&self) -> bool;
fn as_request_response(&self) -> Option<RequestResponseInteraction>;
fn is_message(&self) -> bool;
fn as_message(&self) -> Option<Message>;
fn id(&self) -> Option<String>;
fn description(&self) -> String;
fn set_id(&mut self, id: Option<String>);
fn set_description(&mut self, description: &str);
fn provider_states(&self) -> Vec<ProviderState>;
fn provider_states_mut(&mut self) -> &mut Vec<ProviderState>;
#[deprecated(
since = "0.1.0",
note = "Some interactions have multiple contents (like request/response), so it is impossible \
to know which to return for this method"
)]
fn contents(&self) -> OptionalBody;
fn contents_for_verification(&self) -> OptionalBody;
#[deprecated(
since = "0.1.0",
note = "Some interactions have multiple contents (like request/response), so it is impossible \
to know which to return for this method"
)]
fn content_type(&self) -> Option<ContentType>;
fn is_v4(&self) -> bool;
fn as_v4(&self) -> Option<Box<dyn V4Interaction + Send + Sync + RefUnwindSafe>>;
fn as_v4_mut(&mut self) -> Option<&mut dyn V4Interaction>;
fn is_v4_http(&self) -> bool { false }
fn as_v4_http(&self) -> Option<SynchronousHttp>;
fn as_v4_async_message(&self) -> Option<AsynchronousMessage>;
fn is_v4_async_message(&self) -> bool { false }
fn as_v4_sync_message(&self) -> Option<SynchronousMessage>;
fn as_v4_http_mut(&mut self) -> Option<&mut SynchronousHttp>;
fn is_v4_sync_message(&self) -> bool { false }
fn as_v4_async_message_mut(&mut self) -> Option<&mut AsynchronousMessage>;
fn as_v4_sync_message_mut(&mut self) -> Option<&mut SynchronousMessage>;
fn boxed(&self) -> Box<dyn Interaction + Send + Sync + RefUnwindSafe>;
fn arced(&self) -> Arc<dyn Interaction + Send + Sync + RefUnwindSafe>;
fn thread_safe(&self) -> Arc<Mutex<dyn Interaction + Send + Sync + RefUnwindSafe>>;
#[deprecated(
since = "0.2.1",
note = "Some interactions have multiple contents (like request/response), so it is impossible \
to know which to return for this method"
)]
fn matching_rules(&self) -> Option<MatchingRules>;
fn pending(&self) -> bool { false }
}
impl Display for dyn Interaction {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
if let Some(req_res) = self.as_request_response() {
std::fmt::Display::fmt(&req_res, f)
} else if let Some(mp) = self.as_message() {
std::fmt::Display::fmt(&mp, f)
} else if let Some(mp) = self.as_v4_http() {
std::fmt::Display::fmt(&mp, f)
} else if let Some(mp) = self.as_v4_async_message() {
std::fmt::Display::fmt(&mp, f)
} else {
Err(fmt::Error)
}
}
}
impl Clone for Box<dyn Interaction> {
fn clone(&self) -> Self {
if self.is_v4() {
if let Some(http) = self.as_v4_http() {
Box::new(http)
} else if let Some(message) = self.as_v4_async_message() {
Box::new(message)
} else {
panic!("Internal Error - Tried to clone an interaction that was not valid")
}
} else if let Some(req_res) = self.as_request_response() {
Box::new(req_res)
} else if let Some(mp) = self.as_message() {
Box::new(mp)
} else {
panic!("Internal Error - Tried to clone an interaction that was not valid")
}
}
}
pub fn http_interaction_from_json(source: &str, json: &Value, spec: &PactSpecification) -> anyhow::Result<Box<dyn Interaction + Send + Sync + RefUnwindSafe>> {
match spec {
PactSpecification::V4 => interaction_from_json(source, 0, json)
.map(|i| i.boxed()),
_ => Ok(Box::new(RequestResponseInteraction::from_json(0, json, spec)?))
}
}
pub fn message_interaction_from_json(source: &str, json: &Value, spec: &PactSpecification) -> anyhow::Result<Box<dyn Interaction + Send + Sync + RefUnwindSafe>> {
match spec {
PactSpecification::V4 => interaction_from_json(source, 0, json)
.map(|i| i.boxed()),
_ => Message::from_json(0, json, spec).map(|i| i.boxed())
}
}
pub(crate) fn parse_interactions(pact_json: &Value, spec_version: PactSpecification
) -> anyhow::Result<Vec<RequestResponseInteraction>> {
if let Some(&Value::Array(ref array)) = pact_json.get("interactions") {
array.iter().enumerate().map(|(index, ijson)| {
RequestResponseInteraction::from_json(index, ijson, &spec_version)
}).collect()
}
else {
Ok(vec![])
}
}