#![allow(clippy::unwrap_used, clippy::expect_used, clippy::panic)]
mod support;
use std::sync::Arc;
use support::{Harness, narrating, token_for};
use turnframe_core::ids::TurnId;
use turnframe_core::locale::Locale;
use turnframe_core::response::{AssistantTurn, ResponseBlock};
use turnframe_core::understanding::Understanding;
use turnframe_test::providers::UnderstandingBuilder;
use turnframe_test::workflows::trip::{
awaiting_rebooking_confirmation, incomplete_case, operations, with_offer,
};
fn turn_one() -> TurnId {
TurnId::from(uuid::Uuid::from_u128(1))
}
fn artifacts(turn: &AssistantTurn) -> Vec<(String, String)> {
turn.blocks
.iter()
.filter_map(|block| match block {
ResponseBlock::Artifact(view) => Some((
view.artifact.kind.clone(),
view.artifact
.label
.resolve(&Locale::from("en-GB"))
.to_owned(),
)),
_ => None,
})
.collect()
}
fn artifact_ids(turn: &AssistantTurn) -> Vec<String> {
turn.blocks
.iter()
.filter_map(|block| match block {
ResponseBlock::Artifact(view) => Some(view.block_id.to_string()),
_ => None,
})
.collect()
}
const REVIEW: &str = "show me the rebooking card";
fn review() -> Understanding {
UnderstandingBuilder::of(REVIEW)
.apply(
operations::REQUEST_REBOOKING,
token_for(turn_one(), "trip", "trip-1"),
serde_json::json!({"leg": 1}),
REVIEW,
)
.build()
.unwrap()
}
async fn reviewing(state: turnframe_test::workflows::trip::TripState) -> AssistantTurn {
let harness = Harness::builder()
.trip("trip-1", "Trip 1", 3, state)
.understands(review())
.provider(narrating().build_shared())
.build()
.await;
harness
.handle(harness.turn(turn_one(), REVIEW))
.await
.unwrap()
}
#[tokio::test]
async fn a_case_with_a_document_puts_it_in_front_of_the_user() {
let found = artifacts(&reviewing(with_offer(1)).await);
assert_eq!(
found,
vec![("itinerary_pdf".to_owned(), "Itinerary preview".to_owned())],
"the point of a confirmation step is seeing what is being authorised"
);
}
#[tokio::test]
async fn the_block_names_the_revision_the_document_is_at() {
let answered = reviewing(with_offer(1)).await;
let case_ref = answered
.blocks
.iter()
.find_map(|block| match block {
ResponseBlock::Interaction(card) => Some(card.view.case_ref.clone()),
_ => None,
})
.expect("the rebooking card names the case it is bound to");
assert_eq!(
artifact_ids(&answered),
vec![format!(
"artifact:trip:trip-1:{}:itinerary:trip-1",
case_ref.expected_revision
)],
"same document, same revision, same block"
);
}
#[tokio::test]
async fn a_case_with_no_document_adds_no_block() {
let found = artifacts(&reviewing(incomplete_case()).await);
assert!(found.is_empty(), "{found:?}");
}
#[tokio::test]
async fn a_document_that_has_not_changed_is_announced_once() {
let second = UnderstandingBuilder::of("e allora?")
.ask("e allora?")
.build()
.unwrap();
let provider = narrating().answering("Nothing has changed.").build_shared();
let harness = Harness::builder()
.trip("trip-1", "Trip 1", 3, with_offer(1))
.understands(review())
.understands(second)
.provider(Arc::clone(&provider))
.build()
.await;
let first = harness
.handle(harness.turn(turn_one(), REVIEW))
.await
.unwrap();
assert_eq!(
artifacts(&first).len(),
1,
"the document is announced when the phase it belongs to is reached"
);
let again = harness
.handle(harness.turn(TurnId::from(uuid::Uuid::from_u128(2)), "e allora?"))
.await
.unwrap();
assert!(
artifacts(&again).is_empty(),
"and not again while it is the same document at the same revision: {:?}",
artifacts(&again)
);
}
#[tokio::test]
async fn a_document_is_not_re_announced_by_a_turn_that_answers_a_card() {
let provider = narrating()
.acknowledging("All right.")
.build_shared();
let harness = Harness::builder()
.trip("trip-1", "Trip 1", 3, with_offer(1))
.understands(review())
.provider(Arc::clone(&provider))
.build()
.await;
let first = harness
.handle(harness.turn(turn_one(), REVIEW))
.await
.unwrap();
assert_eq!(artifacts(&first).len(), 1);
let card = harness.blocking_card("trip", "trip-1").await;
let revision = harness.trip_revision("trip-1");
let answered = harness
.handle(harness.click(
TurnId::from(uuid::Uuid::from_u128(2)),
card.id,
turnframe_test::workflows::trip::REBOOK_DECLINE_OPTION,
revision.0,
))
.await
.unwrap();
assert!(
artifacts(&answered).is_empty(),
"the same document at the same revision, and a turn with no \
model call: {:?}",
artifacts(&answered)
);
}
#[tokio::test]
async fn a_document_of_a_case_the_turn_ignored_stays_out() {
let turn = turn_one();
let text = "Set the name to Lisbon";
let understood = UnderstandingBuilder::of(text)
.apply(
operations::SET_NAME,
token_for(turn, "trip", "trip-1"),
serde_json::json!({"value": "Lisbon"}),
text,
)
.build()
.unwrap();
let harness = Harness::builder()
.trip("trip-1", "Trip 1", 3, incomplete_case())
.trip("trip-2", "Trip 2", 3, awaiting_rebooking_confirmation())
.understands(understood)
.provider(narrating().build_shared())
.build()
.await;
let answered = harness.handle(harness.turn(turn, text)).await.unwrap();
assert!(
artifacts(&answered).is_empty(),
"{:?}",
artifacts(&answered)
);
}