829 lines
33 KiB
Rust
829 lines
33 KiB
Rust
#![allow(
|
|
clippy::float_cmp,
|
|
clippy::needless_pass_by_value,
|
|
clippy::too_many_lines
|
|
)]
|
|
|
|
// Exact BSD-3-Clause fixture provenance at LibreMetaverse
|
|
// 2aa70bb68513b39795da5d13c88f31b86e85a3ba (see LICENSE.md):
|
|
// GLTFMaterialOverrideCapTests.cs 4d717ded7cc7bd4e68210417f722a1ceec6391b19dc3b1dfeb558ae16e6f115b
|
|
// GLTFMaterialUploadTests.cs 0602d1504e405868d7bcb608eb7c0db9f47e9ec6636846f34d48669aa5a27025
|
|
// TerrainMaterialOverrideTests.cs b9409ba65906e2b9d30d42b350b4b3e9c1655d4a503c4ff87bd548dd229dad88
|
|
// SendPostcardTests.cs 56691373dfa8f817f0b1079b8ec40f16e0186d6cfb13f772da0ffe3935188b4d
|
|
// UploadThumbnailTests.cs 8a88c5e4d45e7e1d4f8a41092528eefee347c7bd5f5e6f3af171ac19455e894b
|
|
// ConstructorNullArgumentTests.cs 28deea0bf4d9353a2424842c6184abab8fe82746ceb12e093912728a247f21bc
|
|
|
|
use libremetaverse::assets::AssetMaterial;
|
|
use libremetaverse::{
|
|
AssetManager, GLTFMaterialUpdate, GridClient, HttpCapsClient, InventoryFolder, Simulator,
|
|
};
|
|
use libremetaverse_compat_tests::block_on;
|
|
use libremetaverse_types::compat::{HttpMessageHandler, HttpRequest, HttpResponse, Uri};
|
|
use libremetaverse_types::{Color4, Error, UUID, Vector3};
|
|
use std::collections::{BTreeMap, HashMap, VecDeque};
|
|
use std::fmt::Write as _;
|
|
use std::sync::{Arc, Mutex};
|
|
|
|
const MODIFY_MATERIAL: &str = "http://test.invalid/modify-material-params";
|
|
const MATERIAL_AGENT: &str = "http://test.invalid/update-material-agent-inventory";
|
|
const MATERIAL_TASK: &str = "http://test.invalid/update-material-task-inventory";
|
|
const MATERIAL_UPLOADER: &str = "http://test.invalid/update-material/upload/abc123";
|
|
const MODIFY_REGION: &str = "http://test.invalid/modify-region";
|
|
const POSTCARD: &str = "http://test.invalid/send-postcard";
|
|
const POSTCARD_UPLOADER: &str = "http://test.invalid/send-postcard/upload/abc123";
|
|
const THUMBNAIL: &str = "http://test.invalid/inventory-thumbnail-upload";
|
|
const THUMBNAIL_UPLOADER: &str = "http://test.invalid/inventory-thumbnail-upload/upload/abc123";
|
|
const SEED_CAPS: &str = "http://test.invalid/seed";
|
|
const OTHER_CAP: &str = "http://test.invalid/other";
|
|
|
|
#[derive(Clone)]
|
|
struct RecordingHttp {
|
|
requests: Arc<Mutex<Vec<HttpRequest>>>,
|
|
}
|
|
|
|
impl RecordingHttp {
|
|
fn new(
|
|
capabilities: &[(&str, &str)],
|
|
responses: &[(&str, &str)],
|
|
) -> (Self, HttpMessageHandler) {
|
|
let requests = Arc::new(Mutex::new(Vec::new()));
|
|
let recorded = Arc::clone(&requests);
|
|
let mut queued = HashMap::<String, VecDeque<HttpResponse>>::new();
|
|
for (uri, body) in responses {
|
|
queued
|
|
.entry((*uri).into())
|
|
.or_default()
|
|
.push_back(response(body));
|
|
}
|
|
let queued = Mutex::new(queued);
|
|
let mut seed_body = "<llsd><map>".to_owned();
|
|
for (name, uri) in capabilities {
|
|
write!(seed_body, "<key>{name}</key><uri>{uri}</uri>")
|
|
.expect("writing to a String cannot fail");
|
|
}
|
|
seed_body.push_str("</map></llsd>");
|
|
let handler = HttpMessageHandler::new(move |request, _| {
|
|
let uri = request.uri.0.clone();
|
|
let response = if uri == SEED_CAPS {
|
|
HttpResponse {
|
|
status_code: 200,
|
|
headers: BTreeMap::new(),
|
|
content_type: Some("application/llsd+xml".into()),
|
|
body: seed_body.as_bytes().to_vec(),
|
|
}
|
|
} else {
|
|
recorded.lock().expect("request recording").push(request);
|
|
queued
|
|
.lock()
|
|
.expect("response queue")
|
|
.get_mut(&uri)
|
|
.and_then(VecDeque::pop_front)
|
|
.unwrap_or_else(|| HttpResponse {
|
|
status_code: 404,
|
|
headers: BTreeMap::new(),
|
|
content_type: None,
|
|
body: Vec::new(),
|
|
})
|
|
};
|
|
async move { response }
|
|
});
|
|
(Self { requests }, handler)
|
|
}
|
|
|
|
fn requests(&self) -> Vec<HttpRequest> {
|
|
self.requests.lock().expect("request recording").clone()
|
|
}
|
|
}
|
|
|
|
fn response(body: &str) -> HttpResponse {
|
|
HttpResponse {
|
|
status_code: 200,
|
|
headers: BTreeMap::from([("Content-Length".into(), body.len().to_string())]),
|
|
content_type: Some("application/json".into()),
|
|
body: body.as_bytes().to_vec(),
|
|
}
|
|
}
|
|
|
|
fn client_with_fixture(
|
|
capabilities: &[(&str, &str)],
|
|
responses: &[(&str, &str)],
|
|
) -> (GridClient, RecordingHttp) {
|
|
let (recording, handler) = RecordingHttp::new(capabilities, responses);
|
|
let mut client = GridClient::new().expect("GridClient constructor");
|
|
client.set_http_caps_client(
|
|
HttpCapsClient::new(handler.clone()).expect("HttpCapsClient constructor"),
|
|
);
|
|
if !capabilities.is_empty() {
|
|
let mut simulator_client = GridClient::new().expect("simulator GridClient constructor");
|
|
simulator_client.set_http_caps_client(
|
|
HttpCapsClient::new(handler).expect("simulator HttpCapsClient constructor"),
|
|
);
|
|
let simulator = Simulator::new(
|
|
simulator_client,
|
|
"127.0.0.1:0".parse().expect("loopback endpoint"),
|
|
0,
|
|
None,
|
|
None,
|
|
)
|
|
.expect("fixture simulator");
|
|
simulator
|
|
.set_seed_caps(Some(Uri(SEED_CAPS.into())), Some(true))
|
|
.expect("seed fixture capabilities");
|
|
let mut network = client.network();
|
|
network.set_current_sim(Some(simulator));
|
|
client.set_network(network);
|
|
}
|
|
(client, recording)
|
|
}
|
|
|
|
fn body(request: &HttpRequest) -> String {
|
|
String::from_utf8(request.body.clone()).expect("UTF-8 request body")
|
|
}
|
|
|
|
fn uuid_eq(actual: &UUID, expected: &UUID) {
|
|
assert_eq!(
|
|
actual.get_bytes().expect("actual UUID bytes"),
|
|
expected.get_bytes().expect("expected UUID bytes")
|
|
);
|
|
}
|
|
|
|
fn happy_upload_responses<'a>(
|
|
capability: &'a str,
|
|
uploader: &'a str,
|
|
new_asset: &UUID,
|
|
) -> [(&'a str, String); 2] {
|
|
[
|
|
(
|
|
capability,
|
|
format!(r#"{{"state":"upload","uploader":"{uploader}"}}"#),
|
|
),
|
|
(
|
|
uploader,
|
|
format!(
|
|
r#"{{"state":"complete","new_asset":"{}"}}"#,
|
|
new_asset.to_string()
|
|
),
|
|
),
|
|
]
|
|
}
|
|
|
|
fn response_refs<'a, const N: usize>(
|
|
responses: &'a [(&'a str, String); N],
|
|
) -> Vec<(&'a str, &'a str)> {
|
|
responses
|
|
.iter()
|
|
.map(|(uri, body)| (*uri, body.as_str()))
|
|
.collect()
|
|
}
|
|
|
|
// parity-case: LibreMetaverse.Tests/GLTFMaterialOverrideCapTests.cs::GLTFMaterialOverrideCapTests.SetMaterialOverrideAsync_HappyPath_PostsBareArrayWithGltfJson::test 0c51b7b793111f5433e52057f26fa5a98d983e7230fefeb61a7b3408e97f28ee translated
|
|
#[test]
|
|
fn set_material_override_posts_bare_array_with_gltf_json() {
|
|
let (client, recording) = client_with_fixture(
|
|
&[("ModifyMaterialParams", MODIFY_MATERIAL)],
|
|
&[(MODIFY_MATERIAL, r#"{"success":true}"#)],
|
|
);
|
|
let object_id = UUID::random().expect("UUID Random");
|
|
let expected_id = object_id.to_string();
|
|
let mut material = AssetMaterial::new_with_constructor().expect("AssetMaterial constructor");
|
|
material
|
|
.set_base_color_factor_with_color4_boolean(
|
|
Color4::new_with_single_single_single_single(0.1, 0.2, 0.3, 1.0)
|
|
.expect("Color4 constructor"),
|
|
Some(true),
|
|
)
|
|
.expect("SetBaseColorFactor");
|
|
let result = block_on(client.objects().set_material_override(
|
|
client.network().current_sim().expect("current simulator"),
|
|
object_id,
|
|
3,
|
|
material,
|
|
None,
|
|
))
|
|
.expect("SetMaterialOverrideAsync");
|
|
assert!(result);
|
|
let requests = recording.requests();
|
|
assert_eq!(requests.len(), 1);
|
|
let body = body(&requests[0]);
|
|
assert!(body.contains("<key>object_id</key>"));
|
|
assert!(body.contains(&expected_id));
|
|
assert!(body.contains("<key>side</key>"));
|
|
assert!(body.contains("<key>gltf_json</key>"));
|
|
assert!(!body.contains("<key>asset_id</key>"));
|
|
}
|
|
|
|
// parity-case: LibreMetaverse.Tests/GLTFMaterialOverrideCapTests.cs::GLTFMaterialOverrideCapTests.ClearMaterialOverrideAsync_SendsEmptyGltfJson::test 8394d063ea71447d9ce2b76fd00be1d10967f9193e1eb909c5b9f2da56eec812 translated
|
|
#[test]
|
|
fn clear_material_override_sends_empty_gltf_json() {
|
|
let (client, recording) = client_with_fixture(
|
|
&[("ModifyMaterialParams", MODIFY_MATERIAL)],
|
|
&[(MODIFY_MATERIAL, r#"{"success":true}"#)],
|
|
);
|
|
assert!(
|
|
block_on(client.objects().clear_material_override(
|
|
client.network().current_sim().expect("current simulator"),
|
|
UUID::random().expect("UUID Random"),
|
|
0,
|
|
None,
|
|
))
|
|
.expect("ClearMaterialOverrideAsync")
|
|
);
|
|
let body = body(&recording.requests()[0]);
|
|
assert!(body.contains("<key>gltf_json</key>"));
|
|
assert!(body.contains("<string />") || body.contains("<string></string>"));
|
|
assert!(!body.contains("<key>asset_id</key>"));
|
|
}
|
|
|
|
// parity-case: LibreMetaverse.Tests/GLTFMaterialOverrideCapTests.cs::GLTFMaterialOverrideCapTests.ApplyMaterialAsync_WithoutOverride_SendsAssetIdOnly::test 1db03ab6710ecf532644398d1fef5e82520e1206058d66fb15c8885fdc8f8363 translated
|
|
#[test]
|
|
fn apply_material_without_override_sends_asset_id_only() {
|
|
let (client, recording) = client_with_fixture(
|
|
&[("ModifyMaterialParams", MODIFY_MATERIAL)],
|
|
&[(MODIFY_MATERIAL, r#"{"success":true}"#)],
|
|
);
|
|
let asset_id = UUID::random().expect("UUID Random");
|
|
let expected_id = asset_id.to_string();
|
|
assert!(
|
|
block_on(client.objects().apply_material(
|
|
client.network().current_sim().expect("current simulator"),
|
|
UUID::random().expect("UUID Random"),
|
|
1,
|
|
asset_id,
|
|
None,
|
|
None,
|
|
))
|
|
.expect("ApplyMaterialAsync")
|
|
);
|
|
let body = body(&recording.requests()[0]);
|
|
assert!(body.contains("<key>asset_id</key>"));
|
|
assert!(body.contains(&expected_id));
|
|
assert!(!body.contains("<key>gltf_json</key>"));
|
|
}
|
|
|
|
// parity-case: LibreMetaverse.Tests/GLTFMaterialOverrideCapTests.cs::GLTFMaterialOverrideCapTests.SendMaterialUpdatesAsync_MultipleEntries_SendsSingleArrayBody::test 621dca88e7f1c9e024563204ca05c3c8d9a03c4b5a7b31ec1c006abe6732b47b translated
|
|
#[test]
|
|
fn material_updates_send_one_array_body() {
|
|
let (client, recording) = client_with_fixture(
|
|
&[("ModifyMaterialParams", MODIFY_MATERIAL)],
|
|
&[(MODIFY_MATERIAL, r#"{"success":true}"#)],
|
|
);
|
|
let mut first = GLTFMaterialUpdate::new().expect("GLTFMaterialUpdate constructor");
|
|
first.set_object_id(UUID::random().expect("UUID Random"));
|
|
first.set_side(0);
|
|
let mut second = GLTFMaterialUpdate::new().expect("GLTFMaterialUpdate constructor");
|
|
second.set_object_id(UUID::random().expect("UUID Random"));
|
|
second.set_side(1);
|
|
second.set_asset_id(Some(Some(UUID::random().expect("UUID Random"))));
|
|
assert!(
|
|
block_on(client.objects().send_material_updates(
|
|
client.network().current_sim().expect("current simulator"),
|
|
Box::new(vec![first, second].into_iter()),
|
|
None,
|
|
))
|
|
.expect("SendMaterialUpdatesAsync")
|
|
);
|
|
assert_eq!(recording.requests().len(), 1);
|
|
}
|
|
|
|
// parity-case: LibreMetaverse.Tests/GLTFMaterialOverrideCapTests.cs::GLTFMaterialOverrideCapTests.SendMaterialUpdatesAsync_ServerRejects_ReturnsFalse::test e9fbd95fff84695e2cb1a35943bda768f00cf9015b25e0ae1505dce4dde603a4 translated
|
|
#[test]
|
|
fn material_updates_server_rejection_returns_false() {
|
|
let (client, _) = client_with_fixture(
|
|
&[("ModifyMaterialParams", MODIFY_MATERIAL)],
|
|
&[(
|
|
MODIFY_MATERIAL,
|
|
r#"{"success":false,"message":"no rez rights"}"#,
|
|
)],
|
|
);
|
|
assert!(
|
|
!block_on(client.objects().clear_material_override(
|
|
client.network().current_sim().expect("current simulator"),
|
|
UUID::random().expect("UUID Random"),
|
|
0,
|
|
None,
|
|
))
|
|
.expect("ClearMaterialOverrideAsync")
|
|
);
|
|
}
|
|
|
|
// parity-case: LibreMetaverse.Tests/GLTFMaterialOverrideCapTests.cs::GLTFMaterialOverrideCapTests.SendMaterialUpdatesAsync_NoCapability_ReturnsFalseWithoutRequest::test fdceb6bf865cb23386a6b82a9741f230e5c22b0ec6d37bc2ac8478f29292a49f translated
|
|
#[test]
|
|
fn material_updates_without_capability_make_no_request() {
|
|
let (client, recording) = client_with_fixture(&[("SomeOtherCap", OTHER_CAP)], &[]);
|
|
assert!(
|
|
!block_on(client.objects().clear_material_override(
|
|
client.network().current_sim().expect("current simulator"),
|
|
UUID::random().expect("UUID Random"),
|
|
0,
|
|
None,
|
|
))
|
|
.expect("ClearMaterialOverrideAsync")
|
|
);
|
|
assert!(recording.requests().is_empty());
|
|
}
|
|
|
|
// parity-case: LibreMetaverse.Tests/GLTFMaterialUploadTests.cs::GLTFMaterialUploadTests.RequestUpdateMaterialAgentInventoryAsync_HappyPath_PostsMetadataThenJsonAndReturnsNewAsset::test 5ac0e3c27fa6ebfddc9d7582aefb0684a676413948b055382c43b1b0b1cd7e7e translated
|
|
#[test]
|
|
fn material_agent_upload_posts_metadata_then_json() {
|
|
let item_id = UUID::random().expect("UUID Random");
|
|
let new_asset = UUID::random().expect("UUID Random");
|
|
let responses = happy_upload_responses(MATERIAL_AGENT, MATERIAL_UPLOADER, &new_asset);
|
|
let refs = response_refs(&responses);
|
|
let (client, recording) = client_with_fixture(
|
|
&[
|
|
("UpdateMaterialAgentInventory", MATERIAL_AGENT),
|
|
("UpdateMaterialTaskInventory", MATERIAL_TASK),
|
|
],
|
|
&refs,
|
|
);
|
|
let result = block_on(client.inventory().request_update_material_agent_inventory(
|
|
AssetMaterial::new_with_constructor().expect("AssetMaterial constructor"),
|
|
item_id,
|
|
None,
|
|
None,
|
|
))
|
|
.expect("RequestUpdateMaterialAgentInventoryAsync");
|
|
assert!(result.0);
|
|
uuid_eq(&result.2, &new_asset);
|
|
let requests = recording.requests();
|
|
assert_eq!(requests.len(), 2);
|
|
let metadata = body(&requests[0]);
|
|
assert!(metadata.contains("<key>item_id</key>"));
|
|
assert!(!metadata.contains("<key>task_id</key>"));
|
|
assert_eq!(requests[1].uri, Uri(MATERIAL_UPLOADER.into()));
|
|
}
|
|
|
|
// parity-case: LibreMetaverse.Tests/GLTFMaterialUploadTests.cs::GLTFMaterialUploadTests.RequestUpdateMaterialTaskInventoryAsync_HappyPath_PostsItemIdAndTaskId::test 7ac0e7d210b1aefa795e479f4da0d2dd4caae0b3bbe84ca124707c3ae005bbbd translated
|
|
#[test]
|
|
fn material_task_upload_posts_item_and_task_ids() {
|
|
let new_asset = UUID::random().expect("UUID Random");
|
|
let responses = happy_upload_responses(MATERIAL_TASK, MATERIAL_UPLOADER, &new_asset);
|
|
let refs = response_refs(&responses);
|
|
let (client, recording) = client_with_fixture(
|
|
&[
|
|
("UpdateMaterialAgentInventory", MATERIAL_AGENT),
|
|
("UpdateMaterialTaskInventory", MATERIAL_TASK),
|
|
],
|
|
&refs,
|
|
);
|
|
let result = block_on(client.inventory().request_update_material_task_inventory(
|
|
AssetMaterial::new_with_constructor().expect("AssetMaterial constructor"),
|
|
UUID::random().expect("UUID Random"),
|
|
UUID::random().expect("UUID Random"),
|
|
None,
|
|
None,
|
|
))
|
|
.expect("RequestUpdateMaterialTaskInventoryAsync");
|
|
assert!(result.0);
|
|
uuid_eq(&result.2, &new_asset);
|
|
let metadata = body(&recording.requests()[0]);
|
|
assert!(metadata.contains("<key>item_id</key>"));
|
|
assert!(metadata.contains("<key>task_id</key>"));
|
|
}
|
|
|
|
// parity-case: LibreMetaverse.Tests/GLTFMaterialUploadTests.cs::GLTFMaterialUploadTests.RequestUpdateMaterialAgentInventoryAsync_NoCapability_Throws::test 325269807d778264e571d1518ca9a2ca69a27ba67ad689e580f2636ab595f335 translated
|
|
#[test]
|
|
fn material_agent_upload_without_capability_is_invalid_operation() {
|
|
let (client, _) = client_with_fixture(&[], &[]);
|
|
let result = block_on(client.inventory().request_update_material_agent_inventory(
|
|
AssetMaterial::new_with_constructor().expect("AssetMaterial constructor"),
|
|
UUID::random().expect("UUID Random"),
|
|
None,
|
|
None,
|
|
));
|
|
match result {
|
|
Err(error) => assert_eq!(error, Error::InvalidOperation),
|
|
Ok(_) => panic!("expected InvalidOperation, got success"),
|
|
}
|
|
}
|
|
|
|
// parity-case: LibreMetaverse.Tests/GLTFMaterialUploadTests.cs::GLTFMaterialUploadTests.RequestUpdateMaterialAgentInventoryAsync_UploadedJsonRoundTripsMaterial::test fd059dfc8c9299c3b6583b3b47ba18ae9c92e3ad923f88634019b0ab9f34d401 translated
|
|
#[test]
|
|
fn uploaded_material_json_round_trips() {
|
|
let new_asset = UUID::random().expect("UUID Random");
|
|
let responses = happy_upload_responses(MATERIAL_AGENT, MATERIAL_UPLOADER, &new_asset);
|
|
let refs = response_refs(&responses);
|
|
let (client, recording) = client_with_fixture(
|
|
&[
|
|
("UpdateMaterialAgentInventory", MATERIAL_AGENT),
|
|
("UpdateMaterialTaskInventory", MATERIAL_TASK),
|
|
],
|
|
&refs,
|
|
);
|
|
let mut material = AssetMaterial::new_with_constructor().expect("AssetMaterial constructor");
|
|
material.set_name("My Material".into());
|
|
material
|
|
.set_base_color_factor_with_color4_boolean(
|
|
Color4::new_with_single_single_single_single(0.2, 0.4, 0.6, 1.0)
|
|
.expect("Color4 constructor"),
|
|
None,
|
|
)
|
|
.expect("SetBaseColorFactor");
|
|
block_on(client.inventory().request_update_material_agent_inventory(
|
|
material,
|
|
UUID::random().expect("UUID Random"),
|
|
None,
|
|
None,
|
|
))
|
|
.expect("RequestUpdateMaterialAgentInventoryAsync");
|
|
let uploaded = recording.requests()[1].body.clone();
|
|
let round_trip =
|
|
AssetMaterial::new_with_uuid_bytes(UUID::random().expect("UUID Random"), uploaded)
|
|
.expect("AssetMaterial JSON constructor");
|
|
assert_eq!(round_trip.name(), "My Material");
|
|
assert_eq!(
|
|
[
|
|
round_trip.base_color_factor().r,
|
|
round_trip.base_color_factor().g,
|
|
round_trip.base_color_factor().b,
|
|
round_trip.base_color_factor().a,
|
|
],
|
|
[0.2, 0.4, 0.6, 1.0]
|
|
);
|
|
}
|
|
|
|
// parity-case: LibreMetaverse.Tests/TerrainMaterialOverrideTests.cs::TerrainMaterialOverrideTests.GetTerrainMaterialOverridesAsync_ParsesFourSlotsWithSomeEmpty::test 0b7f2b5a7a95c70f4ed97b9b028f3ec16f1cd427a9d4d1b133523bd331f6b9f2 translated
|
|
#[test]
|
|
fn terrain_get_parses_four_slots_with_empty_entries() {
|
|
let (client, _) = client_with_fixture(
|
|
&[("ModifyRegion", MODIFY_REGION)],
|
|
&[(
|
|
MODIFY_REGION,
|
|
r#"{"success":true,"overrides":[{},{"mf":0.25},{},{}]}"#,
|
|
)],
|
|
);
|
|
let overrides = block_on(client.terrain().get_terrain_material_overrides(None))
|
|
.expect("GetTerrainMaterialOverridesAsync")
|
|
.expect("successful override response");
|
|
assert_eq!(overrides.len(), 4);
|
|
assert!(overrides[0].is_none());
|
|
assert_eq!(
|
|
overrides[1].as_ref().expect("slot one").metallic_factor(),
|
|
0.25
|
|
);
|
|
assert!(overrides[2].is_none());
|
|
assert!(overrides[3].is_none());
|
|
}
|
|
|
|
// parity-case: LibreMetaverse.Tests/TerrainMaterialOverrideTests.cs::TerrainMaterialOverrideTests.GetTerrainMaterialOverridesAsync_ServerReportsFailure_ReturnsNull::test c66b84662333288b7328822d1f9fa79450075d44a1178a9b0b661671072efe5b translated
|
|
#[test]
|
|
fn terrain_get_server_failure_returns_none() {
|
|
let (client, _) = client_with_fixture(
|
|
&[("ModifyRegion", MODIFY_REGION)],
|
|
&[(MODIFY_REGION, r#"{"success":false,"message":"nope"}"#)],
|
|
);
|
|
assert!(
|
|
block_on(client.terrain().get_terrain_material_overrides(None))
|
|
.expect("GetTerrainMaterialOverridesAsync")
|
|
.is_none()
|
|
);
|
|
}
|
|
|
|
// parity-case: LibreMetaverse.Tests/TerrainMaterialOverrideTests.cs::TerrainMaterialOverrideTests.GetTerrainMaterialOverridesAsync_NoCapability_ReturnsNullWithoutRequest::test 677f80689e1b6a67893d100e1116805fb9f63c5b6ec33e64a4dc9a4cf24c1237 translated
|
|
#[test]
|
|
fn terrain_get_without_capability_makes_no_request() {
|
|
let (client, recording) = client_with_fixture(&[("SomeOtherCap", OTHER_CAP)], &[]);
|
|
assert!(
|
|
block_on(client.terrain().get_terrain_material_overrides(None))
|
|
.expect("GetTerrainMaterialOverridesAsync")
|
|
.is_none()
|
|
);
|
|
assert!(recording.requests().is_empty());
|
|
}
|
|
|
|
// parity-case: LibreMetaverse.Tests/TerrainMaterialOverrideTests.cs::TerrainMaterialOverrideTests.SetTerrainMaterialOverridesAsync_MixOfNullAndSet_PostsFourEntries::test a4ce031e565ca7eb1864064d299dbf0c7b715581ce330a57be9c3aa93987e67c translated
|
|
#[test]
|
|
fn terrain_set_posts_four_mixed_entries() {
|
|
let (client, recording) = client_with_fixture(
|
|
&[("ModifyRegion", MODIFY_REGION)],
|
|
&[(MODIFY_REGION, r#"{"success":true}"#)],
|
|
);
|
|
let mut material = AssetMaterial::new_with_constructor().expect("AssetMaterial constructor");
|
|
material
|
|
.set_roughness_factor_with_single_boolean(0.1, Some(true))
|
|
.expect("SetRoughnessFactor");
|
|
assert!(
|
|
block_on(
|
|
client
|
|
.terrain()
|
|
.set_terrain_material_overrides(vec![None, Some(material), None, None], None,)
|
|
)
|
|
.expect("SetTerrainMaterialOverridesAsync")
|
|
);
|
|
let body = body(&recording.requests()[0]);
|
|
assert!(body.contains("<key>overrides</key>"));
|
|
assert!(body.contains("<key>rf</key>"));
|
|
}
|
|
|
|
// parity-case: LibreMetaverse.Tests/TerrainMaterialOverrideTests.cs::TerrainMaterialOverrideTests.SetTerrainMaterialOverridesAsync_WrongLength_Throws::test 836099a369b37555049b1c1ddfb9562c57cdef88381b7a79e8b80fe62b169a44 translated
|
|
#[test]
|
|
fn terrain_set_wrong_length_is_argument_error() {
|
|
let (client, _) = client_with_fixture(&[("ModifyRegion", MODIFY_REGION)], &[]);
|
|
let result = block_on(
|
|
client
|
|
.terrain()
|
|
.set_terrain_material_overrides(vec![None, None], None),
|
|
);
|
|
match result {
|
|
Err(error) => assert_eq!(error, Error::Argument),
|
|
Ok(_) => panic!("expected Argument, got success"),
|
|
}
|
|
}
|
|
|
|
// parity-case: LibreMetaverse.Tests/TerrainMaterialOverrideTests.cs::TerrainMaterialOverrideTests.SetTerrainMaterialOverridesAsync_NoCapability_ReturnsFalseWithoutRequest::test 37948cbc0240910d63782d88c0fb9f1d239215cea34a5aa84ac68a10d0555e87 translated
|
|
#[test]
|
|
fn terrain_set_without_capability_makes_no_request() {
|
|
let (client, recording) = client_with_fixture(&[("SomeOtherCap", OTHER_CAP)], &[]);
|
|
assert!(
|
|
!block_on(
|
|
client
|
|
.terrain()
|
|
.set_terrain_material_overrides(vec![None, None, None, None], None,)
|
|
)
|
|
.expect("SetTerrainMaterialOverridesAsync")
|
|
);
|
|
assert!(recording.requests().is_empty());
|
|
}
|
|
|
|
// parity-case: LibreMetaverse.Tests/SendPostcardTests.cs::SendPostcardTests.SendPostcardAsync_HappyPath_PostsMetadataThenImageAndReturnsTrue::test 2e02bd16ef1431c2ca82d7804dffc764be0175cff5daff8c38d0a61641439e06 translated
|
|
#[test]
|
|
fn postcard_posts_metadata_then_image() {
|
|
let (mut client, recording) = client_with_fixture(
|
|
&[("SendPostcard", POSTCARD)],
|
|
&[
|
|
(
|
|
POSTCARD,
|
|
r#"{"state":"upload","uploader":"http://test.invalid/send-postcard/upload/abc123"}"#,
|
|
),
|
|
(POSTCARD_UPLOADER, r#"{"state":"complete"}"#),
|
|
],
|
|
);
|
|
assert!(
|
|
block_on(client.self_().send_postcard(
|
|
vec![0xff, 0xd8, 0xff, 0xd9],
|
|
"friend@example.com".into(),
|
|
"Jim Radford".into(),
|
|
"Postcard from the edge".into(),
|
|
"Hello, how are you today?".into(),
|
|
Vector3::one(),
|
|
None,
|
|
))
|
|
.expect("SendPostcardAsync")
|
|
);
|
|
let requests = recording.requests();
|
|
assert_eq!(requests.len(), 2);
|
|
assert_eq!(requests[0].method, "POST");
|
|
assert_eq!(requests[0].uri, Uri(POSTCARD.into()));
|
|
let metadata = body(&requests[0]);
|
|
assert!(!metadata.contains("<key>from</key>"));
|
|
for field in ["to", "name", "subject", "msg", "pos-global"] {
|
|
assert!(metadata.contains(field));
|
|
}
|
|
assert_eq!(requests[1].method, "POST");
|
|
assert_eq!(requests[1].uri, Uri(POSTCARD_UPLOADER.into()));
|
|
}
|
|
|
|
// parity-case: LibreMetaverse.Tests/SendPostcardTests.cs::SendPostcardTests.SendPostcardAsync_UploaderMissingFromResponse_ReturnsFalseWithoutSecondRequest::test 2f9498d57d7a512399f9b108765e6e8da8e4c937402f9671d580c66332630432 translated
|
|
#[test]
|
|
fn postcard_missing_uploader_returns_false_after_one_request() {
|
|
let (mut client, recording) = client_with_fixture(
|
|
&[("SendPostcard", POSTCARD)],
|
|
&[(POSTCARD, r#"{"state":"upload"}"#)],
|
|
);
|
|
assert!(
|
|
!block_on(client.self_().send_postcard(
|
|
vec![1, 2, 3],
|
|
"friend@example.com".into(),
|
|
"Jim Radford".into(),
|
|
"Subject".into(),
|
|
"Message".into(),
|
|
Vector3::zero(),
|
|
None,
|
|
))
|
|
.expect("SendPostcardAsync")
|
|
);
|
|
assert_eq!(recording.requests().len(), 1);
|
|
}
|
|
|
|
// parity-case: LibreMetaverse.Tests/SendPostcardTests.cs::SendPostcardTests.SendPostcardAsync_UploadDoesNotComplete_ReturnsFalse::test 937b682b406506ec9fba9570852bbf8689450a11cbecb85979af97609b1794f9 translated
|
|
#[test]
|
|
fn postcard_incomplete_upload_returns_false() {
|
|
let (mut client, _) = client_with_fixture(
|
|
&[("SendPostcard", POSTCARD)],
|
|
&[
|
|
(
|
|
POSTCARD,
|
|
r#"{"state":"upload","uploader":"http://test.invalid/send-postcard/upload/abc123"}"#,
|
|
),
|
|
(POSTCARD_UPLOADER, r#"{"state":"failed"}"#),
|
|
],
|
|
);
|
|
assert!(
|
|
!block_on(client.self_().send_postcard(
|
|
vec![1, 2, 3],
|
|
"friend@example.com".into(),
|
|
"Jim Radford".into(),
|
|
"Subject".into(),
|
|
"Message".into(),
|
|
Vector3::zero(),
|
|
None,
|
|
))
|
|
.expect("SendPostcardAsync")
|
|
);
|
|
}
|
|
|
|
// parity-case: LibreMetaverse.Tests/SendPostcardTests.cs::SendPostcardTests.SendPostcardAsync_NoCapability_ReturnsFalseWithoutRequest::test 8d3ef84e873096d9388bb7db3eaeeb79c661fd9951e338f71bbf3251ae6580e8 translated
|
|
#[test]
|
|
fn postcard_without_capability_makes_no_request() {
|
|
let (mut client, recording) = client_with_fixture(&[], &[]);
|
|
assert!(
|
|
!block_on(client.self_().send_postcard(
|
|
vec![1, 2, 3],
|
|
"friend@example.com".into(),
|
|
"Jim Radford".into(),
|
|
"Subject".into(),
|
|
"Message".into(),
|
|
Vector3::zero(),
|
|
None,
|
|
))
|
|
.expect("SendPostcardAsync")
|
|
);
|
|
assert!(recording.requests().is_empty());
|
|
}
|
|
|
|
fn thumbnail_responses(new_asset: &UUID) -> [(&str, String); 2] {
|
|
[
|
|
(
|
|
THUMBNAIL,
|
|
format!(r#"{{"uploader":"{THUMBNAIL_UPLOADER}"}}"#),
|
|
),
|
|
(
|
|
THUMBNAIL_UPLOADER,
|
|
format!(
|
|
r#"{{"state":"complete","new_asset":"{}"}}"#,
|
|
new_asset.to_string()
|
|
),
|
|
),
|
|
]
|
|
}
|
|
|
|
// parity-case: LibreMetaverse.Tests/UploadThumbnailTests.cs::UploadThumbnailTests.UploadThumbnailAsync_AgentInventoryItem_SendsBareItemIdAndReturnsNewAsset::test 40ca874a37dade3bfbb391a2b4a75c684cfd7509b269286ccc14d747340d095d translated
|
|
#[test]
|
|
fn thumbnail_agent_item_sends_bare_item_id() {
|
|
let new_asset = UUID::random().expect("UUID Random");
|
|
let responses = thumbnail_responses(&new_asset);
|
|
let refs = response_refs(&responses);
|
|
let (client, recording) =
|
|
client_with_fixture(&[("InventoryThumbnailUpload", THUMBNAIL)], &refs);
|
|
let item_id = UUID::random().expect("UUID Random");
|
|
let result = block_on(client.inventory().upload_thumbnail(
|
|
item_id,
|
|
UUID::zero(),
|
|
vec![1, 2, 3],
|
|
None,
|
|
None,
|
|
))
|
|
.expect("UploadThumbnailAsync")
|
|
.flatten()
|
|
.expect("new thumbnail asset");
|
|
uuid_eq(&result, &new_asset);
|
|
let requests = recording.requests();
|
|
assert_eq!(requests.len(), 2);
|
|
let metadata = body(&requests[0]);
|
|
assert!(metadata.contains("<key>item_id</key>"));
|
|
assert!(!metadata.contains("<key>task_id</key>"));
|
|
assert!(!metadata.contains("<key>category_id</key>"));
|
|
assert_eq!(requests[1].uri, Uri(THUMBNAIL_UPLOADER.into()));
|
|
}
|
|
|
|
// parity-case: LibreMetaverse.Tests/UploadThumbnailTests.cs::UploadThumbnailTests.UploadThumbnailAsync_TaskInventoryItem_SendsItemIdAndTaskId::test dae80f9a7ba6222a651165f779c123d8472f88a17490e69a1112acc3cec6d108 translated
|
|
#[test]
|
|
fn thumbnail_task_item_sends_item_and_task_ids() {
|
|
let new_asset = UUID::random().expect("UUID Random");
|
|
let responses = thumbnail_responses(&new_asset);
|
|
let refs = response_refs(&responses);
|
|
let (client, recording) =
|
|
client_with_fixture(&[("InventoryThumbnailUpload", THUMBNAIL)], &refs);
|
|
let item_id = UUID::random().expect("UUID Random");
|
|
let task_id = UUID::random().expect("UUID Random");
|
|
let result =
|
|
block_on(
|
|
client
|
|
.inventory()
|
|
.upload_thumbnail(item_id, task_id, vec![1, 2, 3], None, None),
|
|
)
|
|
.expect("UploadThumbnailAsync")
|
|
.flatten()
|
|
.expect("new thumbnail asset");
|
|
uuid_eq(&result, &new_asset);
|
|
let metadata = body(&recording.requests()[0]);
|
|
assert!(metadata.contains("<key>item_id</key>"));
|
|
assert!(metadata.contains("<key>task_id</key>"));
|
|
assert!(!metadata.contains("<key>category_id</key>"));
|
|
}
|
|
|
|
// parity-case: LibreMetaverse.Tests/UploadThumbnailTests.cs::UploadThumbnailTests.UploadThumbnailAsync_KnownLocalFolder_SendsCategoryId::test 1ccca44bbead54fd5041c41fc6560478ba17f9e5d9bacff21096b254d2f526db translated
|
|
#[test]
|
|
fn thumbnail_known_local_folder_sends_category_id() {
|
|
let folder_id = UUID::random().expect("UUID Random");
|
|
let new_asset = UUID::random().expect("UUID Random");
|
|
let responses = thumbnail_responses(&new_asset);
|
|
let refs = response_refs(&responses);
|
|
let (client, recording) =
|
|
client_with_fixture(&[("InventoryThumbnailUpload", THUMBNAIL)], &refs);
|
|
let mut folder = InventoryFolder::new(folder_id).expect("InventoryFolder constructor");
|
|
folder.base.set_name("Test Folder".into());
|
|
folder.base.set_parent_uuid(UUID::zero());
|
|
let mut store = client.inventory().store().expect("fixture inventory store");
|
|
store.set_item(folder_id, folder.base);
|
|
let result = block_on(client.inventory().upload_thumbnail(
|
|
folder_id,
|
|
UUID::zero(),
|
|
vec![1, 2, 3],
|
|
None,
|
|
None,
|
|
))
|
|
.expect("UploadThumbnailAsync")
|
|
.flatten()
|
|
.expect("new thumbnail asset");
|
|
uuid_eq(&result, &new_asset);
|
|
let metadata = body(&recording.requests()[0]);
|
|
assert!(metadata.contains("<key>category_id</key>"));
|
|
assert!(!metadata.contains("<key>item_id</key>"));
|
|
assert!(!metadata.contains("<key>task_id</key>"));
|
|
}
|
|
|
|
// parity-case: LibreMetaverse.Tests/UploadThumbnailTests.cs::UploadThumbnailTests.UploadThumbnailAsync_NoCapability_ReturnsNullWithoutRequest::test 2bc1ad18b159c5d62a18d2208ed3cf3c88d3f666a0e0dad8730778cd22b59eda translated
|
|
#[test]
|
|
fn thumbnail_without_capability_makes_no_request() {
|
|
let (client, recording) = client_with_fixture(&[], &[]);
|
|
let result = block_on(client.inventory().upload_thumbnail(
|
|
UUID::random().expect("UUID Random"),
|
|
UUID::zero(),
|
|
vec![1],
|
|
None,
|
|
None,
|
|
))
|
|
.expect("UploadThumbnailAsync")
|
|
.flatten();
|
|
assert!(result.is_none());
|
|
assert!(recording.requests().is_empty());
|
|
}
|
|
|
|
// parity-case: LibreMetaverse.Tests/UploadThumbnailTests.cs::UploadThumbnailTests.UploadThumbnailAsync_MetadataResponseMissingUploader_ReturnsNullWithoutSecondRequest::test 8db3eddf1204ad795e9d5ef15365f422f96191a8b4c24ef3393b03c10d92d662 translated
|
|
#[test]
|
|
fn thumbnail_missing_uploader_returns_none_after_one_request() {
|
|
let (client, recording) = client_with_fixture(
|
|
&[("InventoryThumbnailUpload", THUMBNAIL)],
|
|
&[(THUMBNAIL, r#"{"state":"upload"}"#)],
|
|
);
|
|
let result = block_on(client.inventory().upload_thumbnail(
|
|
UUID::random().expect("UUID Random"),
|
|
UUID::zero(),
|
|
vec![1],
|
|
None,
|
|
None,
|
|
))
|
|
.expect("UploadThumbnailAsync")
|
|
.flatten();
|
|
assert!(result.is_none());
|
|
assert_eq!(recording.requests().len(), 1);
|
|
}
|
|
|
|
// parity-case: LibreMetaverse.Tests/UploadThumbnailTests.cs::UploadThumbnailTests.UploadThumbnailAsync_UploadDoesNotComplete_ReturnsNull::test e870f6913e3f45676ce490069930427e6c625072fc1d6ebbf16f503be51df4ae translated
|
|
#[test]
|
|
fn thumbnail_incomplete_upload_returns_none() {
|
|
let (client, _) = client_with_fixture(
|
|
&[("InventoryThumbnailUpload", THUMBNAIL)],
|
|
&[
|
|
(
|
|
THUMBNAIL,
|
|
r#"{"uploader":"http://test.invalid/inventory-thumbnail-upload/upload/abc123"}"#,
|
|
),
|
|
(
|
|
THUMBNAIL_UPLOADER,
|
|
r#"{"state":"failed","message":"bad image"}"#,
|
|
),
|
|
],
|
|
);
|
|
let result = block_on(client.inventory().upload_thumbnail(
|
|
UUID::random().expect("UUID Random"),
|
|
UUID::zero(),
|
|
vec![1],
|
|
None,
|
|
None,
|
|
))
|
|
.expect("UploadThumbnailAsync")
|
|
.flatten();
|
|
assert!(result.is_none());
|
|
}
|
|
|
|
// parity-case: LibreMetaverse.Tests/ConstructorNullArgumentTests.cs::ConstructorNullArgumentTests.AssetManager_Null_Throws::test 4fa1be8b233dacf6a5955359f2197ff77ae85ffbf2c3c68fcd8cbe672c2c5f91 translated
|
|
#[test]
|
|
fn asset_manager_none_client_is_argument_null() {
|
|
match AssetManager::new(None) {
|
|
Err(error) => assert_eq!(error, Error::ArgumentNull),
|
|
Ok(_) => panic!("expected ArgumentNull, got success"),
|
|
}
|
|
}
|