Some checks failed
API and SemVer surface / api-surface (push) Failing after 1m34s
Native code generation / deterministic (push) Has been cancelled
Concurrency and resource soak audit / soak (push) Has been cancelled
Documentation / documentation (push) Has been cancelled
performance evidence / audit (push) Has been cancelled
First release candidate / non-fuzz-release-gate (push) Has been cancelled
Release platform and feature matrix / audit (push) Has been cancelled
Release platform and feature matrix / matrix (false, linux-stable-minimal, x86_64-unknown-linux-gnu, stable) (push) Has been cancelled
Release platform and feature matrix / matrix (false, macos-stable-portable, x86_64-apple-darwin, stable) (push) Has been cancelled
Release platform and feature matrix / matrix (false, windows-stable-portable, x86_64-pc-windows-gnu, stable) (push) Has been cancelled
Release platform and feature matrix / matrix (true, linux-msrv-portable, x86_64-unknown-linux-gnu, 1.96.0) (push) Has been cancelled
Release platform and feature matrix / matrix (true, linux-stable-default, x86_64-unknown-linux-gnu, stable) (push) Has been cancelled
Release platform and feature matrix / matrix (true, linux-stable-features, x86_64-unknown-linux-gnu, stable) (push) Has been cancelled
Release platform and feature matrix / matrix (true, linux-stable-release-surface, x86_64-unknown-linux-gnu, stable) (push) Has been cancelled
Dependency and supply-chain audit / audit (push) Has been cancelled
Native release artifact audit / audit (push) Has been cancelled
Imaging and meshing gate / native (push) Failing after 53s
JPEG 2000 feature / linux (push) Successful in 2m49s
Native Rust workspace compile / compile (push) Failing after 59s
Skia feature / linux (push) Has been cancelled
485 lines
18 KiB
Rust
485 lines
18 KiB
Rust
// Exact Rust translations of world capability tests owned by milestone issue #23.
|
|
// Source SHA-256: f83be0075683edda91f8e345661b2f753d81c134585f38ddd52b8b9b9e406089
|
|
// Source SHA-256: 79483c67d93295f09d281ec577f642d4967e281f88e531b2b43ee14c1444a440
|
|
// Source SHA-256: 1ef332ad434b9bdc468282eae99150393950db352a98f5f822517fa48021222f
|
|
// Source SHA-256: e49de5d4d588aa944bc27eeecd9921891b851eaecb76270abcec91f649579f7b
|
|
|
|
use libremetaverse::messages::linden::{EnvironmentData, SimConsoleResponseMessage};
|
|
use libremetaverse::{
|
|
GridClient, HttpCapsClient, RegionRestartDays, RegionRestartSchedule, Simulator,
|
|
};
|
|
use libremetaverse_compat_tests::block_on;
|
|
use libremetaverse_structured_data::{OSD, OSDParser};
|
|
use libremetaverse_types::UUID;
|
|
use libremetaverse_types::compat::{HttpMessageHandler, HttpRequest, HttpResponse, Uri};
|
|
use std::collections::BTreeMap;
|
|
use std::sync::{Arc, Mutex};
|
|
use std::time::Duration;
|
|
|
|
const CAP: &str = "http://test.invalid/capability";
|
|
const SEED: &str = "http://test.invalid/seed";
|
|
|
|
#[derive(Clone)]
|
|
struct Recording(Arc<Mutex<Vec<HttpRequest>>>);
|
|
|
|
impl Recording {
|
|
fn requests(&self) -> Vec<HttpRequest> {
|
|
self.0.lock().unwrap().clone()
|
|
}
|
|
}
|
|
|
|
fn response(status: u16, content_type: &str, body: &str) -> HttpResponse {
|
|
HttpResponse {
|
|
status_code: status,
|
|
headers: BTreeMap::new(),
|
|
content_type: Some(content_type.into()),
|
|
body: body.as_bytes().to_vec(),
|
|
}
|
|
}
|
|
|
|
fn client_with_cap(
|
|
cap_name: &str,
|
|
expose_capability: bool,
|
|
cap_response: HttpResponse,
|
|
) -> (GridClient, Recording) {
|
|
let requests = Arc::new(Mutex::new(Vec::new()));
|
|
let captured = Arc::clone(&requests);
|
|
let cap_reply = Mutex::new(Some(cap_response));
|
|
let seed = if expose_capability {
|
|
format!("<llsd><map><key>{cap_name}</key><uri>{CAP}</uri></map></llsd>")
|
|
} else {
|
|
"<llsd><map></map></llsd>".into()
|
|
};
|
|
let handler = HttpMessageHandler::new(move |request, _| {
|
|
let reply = if request.uri.0 == SEED {
|
|
response(200, "application/llsd+xml", &seed)
|
|
} else {
|
|
captured.lock().unwrap().push(request);
|
|
cap_reply
|
|
.lock()
|
|
.unwrap()
|
|
.take()
|
|
.unwrap_or_else(|| response(404, "application/octet-stream", ""))
|
|
};
|
|
async move { reply }
|
|
});
|
|
let mut client = GridClient::new().expect("GridClient constructor");
|
|
client.set_http_caps_client(HttpCapsClient::new(handler.clone()).unwrap());
|
|
let mut simulator_client = GridClient::new().expect("simulator GridClient constructor");
|
|
simulator_client.set_http_caps_client(HttpCapsClient::new(handler).unwrap());
|
|
let simulator = Simulator::new(
|
|
simulator_client,
|
|
"127.0.0.1:13".parse().unwrap(),
|
|
0,
|
|
None,
|
|
None,
|
|
)
|
|
.unwrap();
|
|
simulator
|
|
.set_seed_caps(Some(Uri(SEED.into())), Some(true))
|
|
.unwrap();
|
|
let mut network = client.network();
|
|
network.set_current_sim(Some(simulator));
|
|
client.set_network(network);
|
|
(client, Recording(requests))
|
|
}
|
|
|
|
fn only_request(recording: &Recording) -> HttpRequest {
|
|
let requests = recording.requests();
|
|
assert_eq!(requests.len(), 1);
|
|
requests.into_iter().next().unwrap()
|
|
}
|
|
|
|
fn uuid() -> UUID {
|
|
UUID::random().expect("UUID Random")
|
|
}
|
|
|
|
// parity-case: LibreMetaverse.Tests/EnvironmentManagerTests.cs::EnvironmentManagerTests.GetParcelEnvironment_UsesParcelidQueryParameter::test 5c2f2b0fa2a86955975c621b2415a92ff3da283215e669956e14bf5ee2a4c1f4 translated
|
|
#[test]
|
|
fn get_parcel_environment_uses_parcelid_query_parameter() {
|
|
let (client, recording) = client_with_cap(
|
|
"ExtEnvironment",
|
|
true,
|
|
response(
|
|
200,
|
|
"application/llsd+xml",
|
|
"<llsd><map><key>success</key><boolean>true</boolean></map></llsd>",
|
|
),
|
|
);
|
|
block_on(client.environment().get_parcel_environment(42, None)).unwrap();
|
|
let request = only_request(&recording);
|
|
assert_eq!(request.method, "GET");
|
|
assert!(request.uri.0.contains("parcelid=42"));
|
|
assert!(!request.uri.0.contains("parcel_id"));
|
|
}
|
|
|
|
// parity-case: LibreMetaverse.Tests/EnvironmentManagerTests.cs::EnvironmentManagerTests.SetParcelEnvironment_SendsParcelidInQueryStringNotBody::test f633e2d78e4c6a0fff42917ccfe8de68e4f6133a11e7eef7f9b757c3d1622f0f translated
|
|
#[test]
|
|
fn set_parcel_environment_sends_parcelid_in_query_not_body() {
|
|
let (client, recording) = client_with_cap(
|
|
"ExtEnvironment",
|
|
true,
|
|
response(
|
|
200,
|
|
"application/llsd+xml",
|
|
"<llsd><map><key>success</key><boolean>true</boolean></map></llsd>",
|
|
),
|
|
);
|
|
let mut environment = EnvironmentData::new().expect("EnvironmentData constructor");
|
|
environment.set_day_length(7200);
|
|
block_on(
|
|
client
|
|
.environment()
|
|
.set_parcel_environment(7, environment, None),
|
|
)
|
|
.unwrap();
|
|
let request = only_request(&recording);
|
|
assert_eq!(request.method, "POST");
|
|
assert!(request.uri.0.contains("parcelid=7"));
|
|
let OSD::Map(body) = OSDParser::deserialize_with_bytes(request.body).unwrap() else {
|
|
panic!("ExtEnvironment POST body is not an LLSD map")
|
|
};
|
|
assert!(!body.contains_key("parcel_id"));
|
|
let Some(OSD::Map(environment)) = body.get("environment") else {
|
|
panic!("environment map missing")
|
|
};
|
|
assert_eq!(
|
|
environment.get("day_length").unwrap().as_integer().unwrap(),
|
|
7200
|
|
);
|
|
assert!(!environment.contains_key("sky_track"));
|
|
}
|
|
|
|
// parity-case: LibreMetaverse.Tests/EnvironmentManagerTests.cs::EnvironmentManagerTests.SetRegionEnvironment_OmitsQueryStringEntirely::test bade6e06765506ad7e500ac3e5c9f168605ce25fef86647819d285a68b39f109 translated
|
|
#[test]
|
|
fn set_region_environment_omits_query_string_entirely() {
|
|
let (client, recording) = client_with_cap(
|
|
"ExtEnvironment",
|
|
true,
|
|
response(
|
|
200,
|
|
"application/llsd+xml",
|
|
"<llsd><map><key>success</key><boolean>true</boolean></map></llsd>",
|
|
),
|
|
);
|
|
let environment = EnvironmentData::new().expect("EnvironmentData constructor");
|
|
block_on(
|
|
client
|
|
.environment()
|
|
.set_region_environment_with_environment_data_cancellation_token(environment, None),
|
|
)
|
|
.unwrap();
|
|
let request = only_request(&recording);
|
|
assert_eq!(request.method, "POST");
|
|
assert_eq!(request.uri.0, CAP);
|
|
}
|
|
|
|
// parity-case: LibreMetaverse.Tests/EnvironmentManagerTests.cs::EnvironmentManagerTests.ResetParcelEnvironment_SendsHttpDeleteNotPost::test 4360439192c137f5d7a2ceb83b8664f3917b4b261798050cb855d596f483f082 translated
|
|
#[test]
|
|
fn reset_parcel_environment_sends_delete_not_post() {
|
|
let (client, recording) = client_with_cap(
|
|
"ExtEnvironment",
|
|
true,
|
|
response(
|
|
200,
|
|
"application/llsd+xml",
|
|
"<llsd><map><key>success</key><boolean>true</boolean></map></llsd>",
|
|
),
|
|
);
|
|
assert!(block_on(client.environment().reset_parcel_environment(3, None)).unwrap());
|
|
let request = only_request(&recording);
|
|
assert_eq!(request.method, "DELETE");
|
|
assert!(request.uri.0.contains("parcelid=3"));
|
|
}
|
|
|
|
// parity-case: LibreMetaverse.Tests/QueryExperiencesOnParcelTests.cs::QueryExperiencesOnParcelTests.QueryExperiencesOnParcelAsync_HappyPath_ParsesAllowedMapAndBuildsExpectedQuery::test 2571d3a4100face21268d7ca2401cc8468e711c03c808704aacc7a50006125d5 translated
|
|
#[test]
|
|
fn query_experiences_on_parcel_happy_path() {
|
|
let first = uuid();
|
|
let second = uuid();
|
|
let first_text = first.to_string();
|
|
let second_text = second.to_string();
|
|
let body = format!(r#"{{"experiences":{{"{first_text}":true,"{second_text}":false}}}}"#);
|
|
let (mut client, recording) = client_with_cap(
|
|
"ExperienceQuery",
|
|
true,
|
|
response(200, "application/json", &body),
|
|
);
|
|
let result = block_on(client.self_().query_experiences_on_parcel(
|
|
42,
|
|
Box::new([first, second].into_iter()),
|
|
None,
|
|
))
|
|
.unwrap()
|
|
.expect("experience result");
|
|
assert_eq!(result.get(&first), Some(&true));
|
|
assert_eq!(result.get(&second), Some(&false));
|
|
let request = only_request(&recording);
|
|
assert!(request.uri.0.contains("parcelid=42"));
|
|
assert!(
|
|
request
|
|
.uri
|
|
.0
|
|
.contains(&format!("experiences={first_text},{second_text}"))
|
|
);
|
|
}
|
|
|
|
// parity-case: LibreMetaverse.Tests/QueryExperiencesOnParcelTests.cs::QueryExperiencesOnParcelTests.QueryExperiencesOnParcelAsync_NoExperienceIds_OmitsExperiencesParam::test ddbaa53aa8c63262c2241588b4281c42bbb66efdecac95e297deb0fb81797455 translated
|
|
#[test]
|
|
fn query_experiences_on_parcel_no_ids_omits_parameter() {
|
|
let (mut client, recording) = client_with_cap(
|
|
"ExperienceQuery",
|
|
true,
|
|
response(200, "application/json", r#"{"experiences":{}}"#),
|
|
);
|
|
let result = block_on(client.self_().query_experiences_on_parcel(
|
|
7,
|
|
Box::new(std::iter::empty()),
|
|
None,
|
|
))
|
|
.unwrap()
|
|
.expect("experience result");
|
|
assert!(result.is_empty());
|
|
let request = only_request(&recording);
|
|
assert!(request.uri.0.contains("parcelid=7"));
|
|
assert!(!request.uri.0.contains("experiences"));
|
|
}
|
|
|
|
// parity-case: LibreMetaverse.Tests/QueryExperiencesOnParcelTests.cs::QueryExperiencesOnParcelTests.QueryExperiencesOnParcelAsync_NoCapability_ReturnsNullWithoutRequest::test 5c6a6584fba8ddc66200367217f658d342fb2c26d6be9e49ccf3892bea420095 translated
|
|
#[test]
|
|
fn query_experiences_on_parcel_no_capability_returns_none_without_request() {
|
|
let (mut client, recording) = client_with_cap(
|
|
"ExperienceQuery",
|
|
false,
|
|
response(404, "application/json", ""),
|
|
);
|
|
let result = block_on(client.self_().query_experiences_on_parcel(
|
|
1,
|
|
Box::new([uuid()].into_iter()),
|
|
None,
|
|
))
|
|
.unwrap();
|
|
assert!(result.is_none());
|
|
assert!(recording.requests().is_empty());
|
|
}
|
|
|
|
// parity-case: LibreMetaverse.Tests/QueryExperiencesOnParcelTests.cs::QueryExperiencesOnParcelTests.QueryExperiencesOnParcelAsync_NonSuccessStatus_ReturnsNull::test 977fe55acd5aeb5735cc718f705a2742ae0dfab12dc1211c03a64cc6d1f3bbf5 translated
|
|
#[test]
|
|
fn query_experiences_on_parcel_non_success_returns_none() {
|
|
let (mut client, _) = client_with_cap(
|
|
"ExperienceQuery",
|
|
true,
|
|
response(500, "application/json", ""),
|
|
);
|
|
assert!(
|
|
block_on(client.self_().query_experiences_on_parcel(
|
|
1,
|
|
Box::new([uuid()].into_iter()),
|
|
None
|
|
))
|
|
.unwrap()
|
|
.is_none()
|
|
);
|
|
}
|
|
|
|
// parity-case: LibreMetaverse.Tests/RegionScheduleTests.cs::RegionScheduleTests.GetRegionRestartScheduleAsync_WeeklySchedule_ParsesDaysAndTime::test 0f64aab66c6a6d807b3d2bbc46b636a85900e4f76e35d5e3dd8cd0d8b295618b translated
|
|
#[test]
|
|
fn get_region_restart_schedule_weekly_parses_days_and_time() {
|
|
let (client, _) = client_with_cap(
|
|
"RegionSchedule",
|
|
true,
|
|
response(
|
|
200,
|
|
"application/json",
|
|
r#"{"restart":{"type":"W","days":"TR","time":7200}}"#,
|
|
),
|
|
);
|
|
let schedule = block_on(client.estate().get_region_restart_schedule(None))
|
|
.unwrap()
|
|
.expect("restart schedule");
|
|
assert!(!schedule.is_daily());
|
|
assert_eq!(
|
|
schedule.days(),
|
|
RegionRestartDays(RegionRestartDays::TUESDAY.0 | RegionRestartDays::THURSDAY.0)
|
|
);
|
|
assert_eq!(schedule.time(), Duration::from_hours(2));
|
|
}
|
|
|
|
// parity-case: LibreMetaverse.Tests/RegionScheduleTests.cs::RegionScheduleTests.GetRegionRestartScheduleAsync_DailySchedule_ReturnsAllDays::test cd966b6e3ba470c91ac958bf6c71aeb34f4dab060ad5334cb6060e1954b5c6d0 translated
|
|
#[test]
|
|
fn get_region_restart_schedule_daily_returns_all_days() {
|
|
let (client, _) = client_with_cap(
|
|
"RegionSchedule",
|
|
true,
|
|
response(
|
|
200,
|
|
"application/json",
|
|
r#"{"restart":{"type":"D","time":3600}}"#,
|
|
),
|
|
);
|
|
let schedule = block_on(client.estate().get_region_restart_schedule(None))
|
|
.unwrap()
|
|
.expect("restart schedule");
|
|
assert!(schedule.is_daily());
|
|
assert_eq!(schedule.days(), RegionRestartDays::ALL);
|
|
assert_eq!(schedule.time(), Duration::from_hours(1));
|
|
}
|
|
|
|
// parity-case: LibreMetaverse.Tests/RegionScheduleTests.cs::RegionScheduleTests.GetRegionRestartScheduleAsync_NoRestartConfigured_ReturnsNull::test 59a4b050a79659ccaf0fff13b750d634d803ed7b9e4940cbad676c1bdc04a5fc translated
|
|
#[test]
|
|
fn get_region_restart_schedule_no_restart_returns_none() {
|
|
let (client, _) = client_with_cap(
|
|
"RegionSchedule",
|
|
true,
|
|
response(200, "application/json", "{}"),
|
|
);
|
|
assert!(
|
|
block_on(client.estate().get_region_restart_schedule(None))
|
|
.unwrap()
|
|
.is_none()
|
|
);
|
|
}
|
|
|
|
// parity-case: LibreMetaverse.Tests/RegionScheduleTests.cs::RegionScheduleTests.GetRegionRestartScheduleAsync_NoCapability_ReturnsNullWithoutRequest::test e169e7846874ed4309a50cb25b03c2e722a8d758a787654a5906610ab3b655f1 translated
|
|
#[test]
|
|
fn get_region_restart_schedule_no_capability_returns_none_without_request() {
|
|
let (client, recording) = client_with_cap(
|
|
"RegionSchedule",
|
|
false,
|
|
response(404, "application/json", ""),
|
|
);
|
|
assert!(
|
|
block_on(client.estate().get_region_restart_schedule(None))
|
|
.unwrap()
|
|
.is_none()
|
|
);
|
|
assert!(recording.requests().is_empty());
|
|
}
|
|
|
|
fn schedule(daily: bool, days: RegionRestartDays, time: Duration) -> RegionRestartSchedule {
|
|
let mut schedule = RegionRestartSchedule::new().expect("RegionRestartSchedule constructor");
|
|
schedule.set_is_daily(daily);
|
|
schedule.set_days(days);
|
|
schedule.set_time(time);
|
|
schedule
|
|
}
|
|
|
|
// parity-case: LibreMetaverse.Tests/RegionScheduleTests.cs::RegionScheduleTests.SetRegionRestartScheduleAsync_Weekly_PostsUppercaseDaysAndSeconds::test 153fc0ac84af549c1381d0814a356bf2d9e0ead2c879e503981193366943546c translated
|
|
#[test]
|
|
fn set_region_restart_schedule_weekly_posts_uppercase_days_and_seconds() {
|
|
let (client, recording) = client_with_cap(
|
|
"RegionSchedule",
|
|
true,
|
|
response(200, "application/json", ""),
|
|
);
|
|
let days = RegionRestartDays(
|
|
RegionRestartDays::MONDAY.0 | RegionRestartDays::WEDNESDAY.0 | RegionRestartDays::FRIDAY.0,
|
|
);
|
|
assert!(
|
|
block_on(
|
|
client
|
|
.estate()
|
|
.set_region_restart_schedule(schedule(false, days, Duration::from_mins(90)), None)
|
|
)
|
|
.unwrap()
|
|
);
|
|
let body = String::from_utf8(only_request(&recording).body).unwrap();
|
|
assert!(body.contains("<key>type</key>"));
|
|
assert!(body.contains('W'));
|
|
assert!(body.contains("MWF"));
|
|
assert!(body.contains("5400"));
|
|
}
|
|
|
|
// parity-case: LibreMetaverse.Tests/RegionScheduleTests.cs::RegionScheduleTests.SetRegionRestartScheduleAsync_DailyIgnoresDays_DoesNotPostDaysKey::test b51a1272465c3316194542eb346b2aa15c43fdc8474163ddd851b3f2204d1c2b translated
|
|
#[test]
|
|
fn set_region_restart_schedule_daily_omits_days() {
|
|
let (client, recording) = client_with_cap(
|
|
"RegionSchedule",
|
|
true,
|
|
response(200, "application/json", ""),
|
|
);
|
|
assert!(
|
|
block_on(client.estate().set_region_restart_schedule(
|
|
schedule(true, RegionRestartDays::NONE, Duration::from_hours(3)),
|
|
None
|
|
))
|
|
.unwrap()
|
|
);
|
|
assert!(
|
|
!String::from_utf8(only_request(&recording).body)
|
|
.unwrap()
|
|
.contains("<key>days</key>")
|
|
);
|
|
}
|
|
|
|
// parity-case: LibreMetaverse.Tests/RegionScheduleTests.cs::RegionScheduleTests.SetRegionRestartScheduleAsync_EmptyDaysClearsSchedule::test 57ef3c0f8d9eeac58a7d1b3e7dbc44413016f39303d304cacd3071bd2c55f320 translated
|
|
#[test]
|
|
fn set_region_restart_schedule_empty_days_clears_schedule() {
|
|
let (client, recording) = client_with_cap(
|
|
"RegionSchedule",
|
|
true,
|
|
response(200, "application/json", ""),
|
|
);
|
|
assert!(
|
|
block_on(client.estate().set_region_restart_schedule(
|
|
schedule(false, RegionRestartDays::NONE, Duration::ZERO),
|
|
None
|
|
))
|
|
.unwrap()
|
|
);
|
|
let body = String::from_utf8(only_request(&recording).body).unwrap();
|
|
assert!(body.contains("<key>days</key>"));
|
|
assert!(body.contains("<string />") || body.contains("<string></string>"));
|
|
}
|
|
|
|
// parity-case: LibreMetaverse.Tests/RegionScheduleTests.cs::RegionScheduleTests.SetRegionRestartScheduleAsync_NoCapability_ReturnsFalseWithoutRequest::test be03507fe574b9f7c7174c39af44b7b693e1b7a496845db46451ef09bf9db206 translated
|
|
#[test]
|
|
fn set_region_restart_schedule_no_capability_returns_false_without_request() {
|
|
let (client, recording) = client_with_cap(
|
|
"RegionSchedule",
|
|
false,
|
|
response(404, "application/json", ""),
|
|
);
|
|
assert!(
|
|
!block_on(client.estate().set_region_restart_schedule(
|
|
schedule(true, RegionRestartDays::NONE, Duration::ZERO),
|
|
None
|
|
))
|
|
.unwrap()
|
|
);
|
|
assert!(recording.requests().is_empty());
|
|
}
|
|
|
|
// parity-case: LibreMetaverse.Tests/RegionScheduleTests.cs::RegionScheduleTests.SetRegionRestartScheduleAsync_NonSuccessStatus_ReturnsFalse::test 16c8988d7aa15ea9f58deaa2e3f416b6115978e23073fd99749843f4f410dca4 translated
|
|
#[test]
|
|
fn set_region_restart_schedule_non_success_returns_false() {
|
|
let (client, _) = client_with_cap(
|
|
"RegionSchedule",
|
|
true,
|
|
response(500, "application/json", ""),
|
|
);
|
|
assert!(
|
|
!block_on(client.estate().set_region_restart_schedule(
|
|
schedule(true, RegionRestartDays::NONE, Duration::ZERO),
|
|
None
|
|
))
|
|
.unwrap()
|
|
);
|
|
}
|
|
|
|
// parity-case: LibreMetaverse.Tests/SimConsoleTests.cs::SimConsoleTests.SimConsoleResponseMessage_Deserialize_ReadsBodyField::test 4d367bc3fd012d1579847fd9837bf883c5ea95452776a086bbf856899d7c2099 translated
|
|
#[test]
|
|
fn sim_console_response_message_deserialize_reads_body_field() {
|
|
let map = libremetaverse_structured_data::OSDMap::new_with_dictionary(
|
|
std::collections::HashMap::from([(
|
|
"body".into(),
|
|
OSD::String("console output text".into()),
|
|
)]),
|
|
)
|
|
.unwrap();
|
|
let mut message =
|
|
SimConsoleResponseMessage::new().expect("SimConsoleResponseMessage constructor");
|
|
message.deserialize(map).unwrap();
|
|
assert_eq!(message.body, "console output text");
|
|
}
|