Translate complete RLV test suite

This commit is contained in:
2026-08-08 23:21:40 +02:00
parent 1604822689
commit 3140e65dc7
31 changed files with 14434 additions and 4938 deletions

View File

@@ -1,5 +1,7 @@
//! Shared deterministic fixtures used by translated compatibility tests.
pub mod rlv_support;
use std::collections::BTreeMap;
use std::future::Future;
use std::io;

View File

@@ -0,0 +1,491 @@
//! Recording callbacks shared by the RLV translations.
use libremetaverse_rlv::{
AttachmentRequest, CameraSettings, IRlvActionCallbacks, IRlvQueryCallbacks, InventoryMap,
RlvAttachmentPoint, RlvInventoryItem, RlvService, RlvSharedFolder,
};
use libremetaverse_types::Error;
use libremetaverse_types::compat::{CancellationToken, Guid};
use std::collections::{BTreeMap, HashMap};
use std::future::Future;
use std::pin::Pin;
use std::sync::{Arc, Mutex};
pub const SENDER_NAME: &str = "Sender 1";
pub const SENDER_ID: &str = "ffffffff-ffff-4fff-8fff-ffffffffffff";
/// Parses a UUID literal used by the pinned RLV fixtures.
///
/// # Panics
///
/// Panics when `value` is not a 32-digit hexadecimal UUID, ignoring hyphens.
#[must_use]
pub fn guid(value: &str) -> Guid {
let digits: Vec<_> = value.bytes().filter(|byte| *byte != b'-').collect();
assert_eq!(digits.len(), 32, "valid RLV test UUID");
let mut bytes = [0; 16];
for (index, pair) in digits.chunks_exact(2).enumerate() {
let digit = |byte| match byte {
b'0'..=b'9' => byte - b'0',
b'a'..=b'f' => byte - b'a' + 10,
b'A'..=b'F' => byte - b'A' + 10,
_ => panic!("valid RLV test UUID"),
};
bytes[index] = digit(pair[0]) << 4 | digit(pair[1]);
}
Guid(bytes)
}
#[derive(Clone, Debug, PartialEq)]
pub struct AttachmentCall {
pub item_id: Guid,
pub point: RlvAttachmentPoint,
pub replace: bool,
}
#[derive(Clone, Debug, PartialEq)]
pub struct TeleportCall {
pub x: f32,
pub y: f32,
pub z: f32,
pub region: Option<String>,
pub look_at: Option<Option<f32>>,
}
#[derive(Clone, Debug, Default, PartialEq)]
pub struct ActionLog {
pub adjusted_heights: Vec<(f32, f32, f32)>,
pub attachments: Vec<Vec<AttachmentCall>>,
pub detachments: Vec<Vec<Guid>>,
pub removed_outfits: Vec<Vec<Guid>>,
pub instant_messages: Vec<(Guid, String)>,
pub replies: Vec<(i32, String)>,
pub camera_fovs: Vec<f32>,
pub debug_settings: Vec<(String, String)>,
pub environment_settings: Vec<(String, String)>,
pub group_ids: Vec<(Guid, Option<String>)>,
pub group_names: Vec<(String, Option<String>)>,
pub rotations: Vec<f32>,
pub sits: Vec<Guid>,
pub sit_ground_count: usize,
pub teleports: Vec<TeleportCall>,
pub unsit_count: usize,
}
#[derive(Clone, Default)]
pub struct RecordingActions(pub Arc<Mutex<ActionLog>>);
type ActionFuture<'a> = Pin<Box<dyn Future<Output = Result<(), Error>> + Send + 'a>>;
impl IRlvActionCallbacks for RecordingActions {
fn adjust_height(
&self,
distance: f32,
factor: f32,
delta: f32,
_: CancellationToken,
) -> ActionFuture<'_> {
self.0
.lock()
.unwrap()
.adjusted_heights
.push((distance, factor, delta));
Box::pin(async { Ok(()) })
}
fn attach(&self, requests: Vec<AttachmentRequest>, _: CancellationToken) -> ActionFuture<'_> {
let calls = requests
.iter()
.map(|request| AttachmentCall {
item_id: request.item_id(),
point: request.attachment_point(),
replace: request.replace_existing_attachments(),
})
.collect();
self.0.lock().unwrap().attachments.push(calls);
Box::pin(async { Ok(()) })
}
fn detach(&self, item_ids: Vec<Guid>, _: CancellationToken) -> ActionFuture<'_> {
self.0.lock().unwrap().detachments.push(item_ids);
Box::pin(async { Ok(()) })
}
fn rem_outfit(&self, item_ids: Vec<Guid>, _: CancellationToken) -> ActionFuture<'_> {
self.0.lock().unwrap().removed_outfits.push(item_ids);
Box::pin(async { Ok(()) })
}
fn send_instant_message(
&self,
target: Guid,
message: String,
_: CancellationToken,
) -> ActionFuture<'_> {
self.0
.lock()
.unwrap()
.instant_messages
.push((target, message));
Box::pin(async { Ok(()) })
}
fn send_reply(&self, channel: i32, message: String, _: CancellationToken) -> ActionFuture<'_> {
self.0.lock().unwrap().replies.push((channel, message));
Box::pin(async { Ok(()) })
}
fn set_cam_fov(&self, value: f32, _: CancellationToken) -> ActionFuture<'_> {
self.0.lock().unwrap().camera_fovs.push(value);
Box::pin(async { Ok(()) })
}
fn set_debug(&self, name: String, value: String, _: CancellationToken) -> ActionFuture<'_> {
self.0.lock().unwrap().debug_settings.push((name, value));
Box::pin(async { Ok(()) })
}
fn set_env(&self, name: String, value: String, _: CancellationToken) -> ActionFuture<'_> {
self.0
.lock()
.unwrap()
.environment_settings
.push((name, value));
Box::pin(async { Ok(()) })
}
fn set_group_with_guid_string_cancellation_token(
&self,
id: Guid,
role: Option<String>,
_: CancellationToken,
) -> ActionFuture<'_> {
self.0.lock().unwrap().group_ids.push((id, role));
Box::pin(async { Ok(()) })
}
fn set_group_with_string_string_cancellation_token(
&self,
name: String,
role: Option<String>,
_: CancellationToken,
) -> ActionFuture<'_> {
self.0.lock().unwrap().group_names.push((name, role));
Box::pin(async { Ok(()) })
}
fn set_rot(&self, angle: f32, _: CancellationToken) -> ActionFuture<'_> {
self.0.lock().unwrap().rotations.push(angle);
Box::pin(async { Ok(()) })
}
fn sit(&self, target: Guid, _: CancellationToken) -> ActionFuture<'_> {
self.0.lock().unwrap().sits.push(target);
Box::pin(async { Ok(()) })
}
fn sit_ground(&self, _: CancellationToken) -> ActionFuture<'_> {
self.0.lock().unwrap().sit_ground_count += 1;
Box::pin(async { Ok(()) })
}
fn tp_to(
&self,
x: f32,
y: f32,
z: f32,
region: Option<String>,
look_at: Option<Option<f32>>,
_: CancellationToken,
) -> ActionFuture<'_> {
self.0.lock().unwrap().teleports.push(TeleportCall {
x,
y,
z,
region,
look_at,
});
Box::pin(async { Ok(()) })
}
fn unsit(&self, _: CancellationToken) -> ActionFuture<'_> {
self.0.lock().unwrap().unsit_count += 1;
Box::pin(async { Ok(()) })
}
}
#[derive(Default)]
pub struct QueryState {
pub is_sitting: bool,
pub object_exists: HashMap<Guid, bool>,
pub active_group: Option<String>,
pub camera_settings: Option<[f32; 6]>,
pub debug_settings: BTreeMap<String, String>,
pub environment_settings: BTreeMap<String, String>,
pub inventory_map: Option<InventoryMap>,
pub sit_id: Option<Guid>,
}
#[derive(Clone, Default)]
pub struct RecordingQueries(pub Arc<Mutex<QueryState>>);
type QueryFuture<'a, T> = Pin<Box<dyn Future<Output = Result<T, Error>> + Send + 'a>>;
impl IRlvQueryCallbacks for RecordingQueries {
fn is_sitting(&self, _: CancellationToken) -> QueryFuture<'_, bool> {
let value = self.0.lock().unwrap().is_sitting;
Box::pin(async move { Ok(value) })
}
fn object_exists(&self, id: Guid, _: CancellationToken) -> QueryFuture<'_, bool> {
let value = self
.0
.lock()
.unwrap()
.object_exists
.get(&id)
.copied()
.unwrap_or(false);
Box::pin(async move { Ok(value) })
}
fn try_get_active_group_name(&self, _: CancellationToken) -> QueryFuture<'_, (bool, String)> {
let value = self.0.lock().unwrap().active_group.clone();
Box::pin(async move { Ok(value.map_or((false, String::new()), |name| (true, name))) })
}
fn try_get_camera_settings(
&self,
_: CancellationToken,
) -> QueryFuture<'_, (bool, Option<CameraSettings>)> {
let values = self.0.lock().unwrap().camera_settings;
Box::pin(async move {
let Some([av_min, av_max, fov_min, fov_max, zoom_min, current_fov]) = values else {
return Ok((false, None));
};
Ok((
true,
Some(CameraSettings::new(
av_min,
av_max,
fov_min,
fov_max,
zoom_min,
current_fov,
)?),
))
})
}
fn try_get_debug_setting_value(
&self,
name: String,
_: CancellationToken,
) -> QueryFuture<'_, (bool, String)> {
let value = self.0.lock().unwrap().debug_settings.get(&name).cloned();
Box::pin(async move { Ok(value.map_or((false, String::new()), |value| (true, value))) })
}
fn try_get_environment_setting_value(
&self,
name: String,
_: CancellationToken,
) -> QueryFuture<'_, (bool, String)> {
let value = self
.0
.lock()
.unwrap()
.environment_settings
.get(&name)
.cloned();
Box::pin(async move { Ok(value.map_or((false, String::new()), |value| (true, value))) })
}
fn try_get_inventory_map(
&self,
_: CancellationToken,
) -> QueryFuture<'_, (bool, Option<InventoryMap>)> {
let value = self.0.lock().unwrap().inventory_map.take();
Box::pin(async move { Ok((value.is_some(), value)) })
}
fn try_get_sit_id(&self, _: CancellationToken) -> QueryFuture<'_, (bool, Guid)> {
let value = self.0.lock().unwrap().sit_id;
Box::pin(async move { Ok(value.map_or((false, Guid([0; 16])), |id| (true, id))) })
}
}
pub struct RlvHarness {
pub service: RlvService,
pub actions: Arc<Mutex<ActionLog>>,
pub queries: Arc<Mutex<QueryState>>,
}
impl RlvHarness {
/// Builds the same enabled service and two narrow callback fakes as the C# base fixture.
///
/// # Errors
///
/// Returns the standardized constructor error while the public RLV service is a shim.
pub fn new() -> Result<Self, Error> {
let action_callbacks = RecordingActions::default();
let query_callbacks = RecordingQueries::default();
let actions = Arc::clone(&action_callbacks.0);
let queries = Arc::clone(&query_callbacks.0);
let service = RlvService::new(Box::new(query_callbacks), Box::new(action_callbacks), true)?;
Ok(Self {
service,
actions,
queries,
})
}
/// Processes a command using the base fixture sender identity.
///
/// # Errors
///
/// Returns the public RLV service error for the command.
pub async fn process(&self, command: &str) -> Result<bool, Error> {
self.service
.process_message(command.into(), guid(SENDER_ID), SENDER_NAME.into(), None)
.await
}
/// Processes a command using an explicit sender identity.
///
/// # Errors
///
/// Returns the public RLV service error for the command.
pub async fn process_from(
&self,
command: &str,
sender_id: &str,
sender_name: &str,
) -> Result<bool, Error> {
self.service
.process_message(command.into(), guid(sender_id), sender_name.into(), None)
.await
}
}
pub struct SampleInventoryTree {
pub root: RlvSharedFolder,
pub clothing: RlvSharedFolder,
pub hats: RlvSharedFolder,
pub sub_hats: RlvSharedFolder,
pub accessories: RlvSharedFolder,
pub fancy_hat: RlvInventoryItem,
pub party_hat: RlvInventoryItem,
pub business_pants: RlvInventoryItem,
pub retro_pants: RlvInventoryItem,
pub happy_shirt: RlvInventoryItem,
pub glasses: RlvInventoryItem,
pub watch: RlvInventoryItem,
}
impl SampleInventoryTree {
/// Builds the exact `#RLV` hierarchy shared by the upstream fixtures.
///
/// # Errors
///
/// Returns a mapped constructor or collection error.
pub fn build() -> Result<Self, Error> {
let root =
RlvSharedFolder::new(guid("aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa"), "#RLV".into())?;
let clothing = root.add_child(
guid("bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb"),
"Clothing".into(),
)?;
let hats =
clothing.add_child(guid("dddddddd-dddd-4ddd-8ddd-dddddddddddd"), "Hats".into())?;
let sub_hats = hats.add_child(
guid("ffffffff-0000-4000-8000-000000000000"),
"Sub Hats".into(),
)?;
root.add_child(
guid("eeeeeeee-eeee-4eee-8eee-eeeeeeeeeeee"),
".private".into(),
)?;
let accessories = root.add_child(
guid("cccccccc-cccc-4ccc-8ccc-cccccccccccc"),
"Accessories".into(),
)?;
let watch = accessories.add_item(
guid("c0000000-cccc-4ccc-8ccc-cccccccccccc"),
"Watch".into(),
false,
None,
None,
None,
None,
)?;
let glasses = accessories.add_item(
guid("c1111111-cccc-4ccc-8ccc-cccccccccccc"),
"Glasses".into(),
false,
None,
None,
None,
None,
)?;
let business_pants = clothing.add_item(
guid("b0000000-bbbb-4bbb-8bbb-bbbbbbbbbbbb"),
"Business Pants (Pelvis)".into(),
false,
None,
None,
None,
None,
)?;
let happy_shirt = clothing.add_item(
guid("b1111111-bbbb-4bbb-8bbb-bbbbbbbbbbbb"),
"Happy Shirt".into(),
false,
None,
None,
None,
None,
)?;
let retro_pants = clothing.add_item(
guid("b2222222-bbbb-4bbb-8bbb-bbbbbbbbbbbb"),
"Retro Pants".into(),
false,
None,
None,
None,
None,
)?;
let party_hat = hats.add_item(
guid("d0000000-dddd-4ddd-8ddd-dddddddddddd"),
"Party Hat (Spine)".into(),
false,
None,
None,
None,
None,
)?;
let fancy_hat = hats.add_item(
guid("d1111111-dddd-4ddd-8ddd-dddddddddddd"),
"Fancy Hat (chin)".into(),
false,
None,
None,
None,
None,
)?;
Ok(Self {
root,
clothing,
hats,
sub_hats,
accessories,
fancy_hat,
party_hat,
business_pants,
retro_pants,
happy_shirt,
glasses,
watch,
})
}
}

View File

@@ -1,620 +1,3 @@
// @generated by tools/generate_surface.py; do not edit by hand.
// Source: LibreMetaverse 2aa70bb68513b39795da5d13c88f31b86e85a3ba
// Pending cases are catalog entries, not fake executable Rust tests.
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AdjustHeightCommandTests.cs::AdjustHeightCommandTests.AdjustHeight::test fb3adb86988b10b2d3fe9223324f8a3c1ba7b8c2ea909ee6b57b38c590fed372
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AdjustHeightCommandTests.cs::AdjustHeightCommandTests.AdjustHeight_WithDelta::test 1f37a125fd9df8585740d37c711888dfcd92460d86c19077f771d7f3fab54264
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachAllCommandTests.cs::AttachAllCommandTests.AttachForce_Recursive::case:eee2b1b757fc196e 17a84542635b76f4f806126ab170d43441ad00b9b91650aa1164909de9692671
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachAllCommandTests.cs::AttachAllCommandTests.AttachForce_Recursive::case:e6bc1820d9335b07 17a84542635b76f4f806126ab170d43441ad00b9b91650aa1164909de9692671
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachAllCommandTests.cs::AttachAllCommandTests.AttachForce_Recursive::case:fb63a8c8c9b75b99 17a84542635b76f4f806126ab170d43441ad00b9b91650aa1164909de9692671
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachAllCommandTests.cs::AttachAllCommandTests.AttachForce_Recursive_WithHiddenSubfolder::case:eee2b1b757fc196e f2e3209b5a1a655a846e7f19801ed118a6dd303edeab705480aaf03959a383e4
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachAllCommandTests.cs::AttachAllCommandTests.AttachForce_Recursive_WithHiddenSubfolder::case:e6bc1820d9335b07 f2e3209b5a1a655a846e7f19801ed118a6dd303edeab705480aaf03959a383e4
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachAllCommandTests.cs::AttachAllCommandTests.AttachForce_Recursive_WithHiddenSubfolder::case:fb63a8c8c9b75b99 f2e3209b5a1a655a846e7f19801ed118a6dd303edeab705480aaf03959a383e4
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachAllCommandTests.cs::AttachAllCommandTests.AttachForce_Recursive_FolderNameSpecifiesToAddInsteadOfReplace::case:eee2b1b757fc196e 6164ae5589e5a684637e9c85dd04e5e4c439c541be45b5ae2228e5c5edb2b79d
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachAllCommandTests.cs::AttachAllCommandTests.AttachForce_Recursive_FolderNameSpecifiesToAddInsteadOfReplace::case:e6bc1820d9335b07 6164ae5589e5a684637e9c85dd04e5e4c439c541be45b5ae2228e5c5edb2b79d
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachAllCommandTests.cs::AttachAllCommandTests.AttachForce_Recursive_FolderNameSpecifiesToAddInsteadOfReplace::case:fb63a8c8c9b75b99 6164ae5589e5a684637e9c85dd04e5e4c439c541be45b5ae2228e5c5edb2b79d
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachAllCommandTests.cs::AttachAllCommandTests.AttachForce_Recursive_SourceFolderPrivate::case:eee2b1b757fc196e cdab3dc2313a5fec377f6fa0d49ac51b7ef58ede741d8c886f298b47efb508ae
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachAllCommandTests.cs::AttachAllCommandTests.AttachForce_Recursive_SourceFolderPrivate::case:e6bc1820d9335b07 cdab3dc2313a5fec377f6fa0d49ac51b7ef58ede741d8c886f298b47efb508ae
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachAllCommandTests.cs::AttachAllCommandTests.AttachForce_Recursive_SourceFolderPrivate::case:fb63a8c8c9b75b99 cdab3dc2313a5fec377f6fa0d49ac51b7ef58ede741d8c886f298b47efb508ae
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachAllThisCommandTests.cs::AttachAllThisCommandTests.AttachAllThisForce_Recursive::case:bc5a9cb6a299a551 be84d92abe19975bbf7a680f077d36956f33873a2b65bfebff8eddf6458b77c9
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachAllThisCommandTests.cs::AttachAllThisCommandTests.AttachAllThisForce_Recursive::case:0f04a34ae77465d3 be84d92abe19975bbf7a680f077d36956f33873a2b65bfebff8eddf6458b77c9
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachAllThisCommandTests.cs::AttachAllThisCommandTests.AttachAllThisForce_Recursive::case:1560d5268a46ddf1 be84d92abe19975bbf7a680f077d36956f33873a2b65bfebff8eddf6458b77c9
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachAllThisCommandTests.cs::AttachAllThisCommandTests.AttachAllThisForce_Recursive_ById::case:bc5a9cb6a299a551 dfc11c1f68841153e34d37f98884c041366bd89d754b0f3421a166f09436daa7
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachAllThisCommandTests.cs::AttachAllThisCommandTests.AttachAllThisForce_Recursive_ById::case:0f04a34ae77465d3 dfc11c1f68841153e34d37f98884c041366bd89d754b0f3421a166f09436daa7
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachAllThisCommandTests.cs::AttachAllThisCommandTests.AttachAllThisForce_Recursive_ById::case:1560d5268a46ddf1 dfc11c1f68841153e34d37f98884c041366bd89d754b0f3421a166f09436daa7
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachAllThisCommandTests.cs::AttachAllThisCommandTests.AttachAllThisForce_Recursive_WithHiddenSubfolder::case:bc5a9cb6a299a551 cfdb334a613f22babdc58f2fb96a884ed7e7a2fd339ec396a71f4decc02a3747
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachAllThisCommandTests.cs::AttachAllThisCommandTests.AttachAllThisForce_Recursive_WithHiddenSubfolder::case:0f04a34ae77465d3 cfdb334a613f22babdc58f2fb96a884ed7e7a2fd339ec396a71f4decc02a3747
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachAllThisCommandTests.cs::AttachAllThisCommandTests.AttachAllThisForce_Recursive_WithHiddenSubfolder::case:1560d5268a46ddf1 cfdb334a613f22babdc58f2fb96a884ed7e7a2fd339ec396a71f4decc02a3747
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachAllThisCommandTests.cs::AttachAllThisCommandTests.AttachAllThisForce_Recursive_FolderNameSpecifiesToAddInsteadOfReplace::case:bc5a9cb6a299a551 780e7212749cb332abbf1a1cef33ed8938584b817476d39424b4628d34c3f4ea
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachAllThisCommandTests.cs::AttachAllThisCommandTests.AttachAllThisForce_Recursive_FolderNameSpecifiesToAddInsteadOfReplace::case:0f04a34ae77465d3 780e7212749cb332abbf1a1cef33ed8938584b817476d39424b4628d34c3f4ea
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachAllThisCommandTests.cs::AttachAllThisCommandTests.AttachAllThisForce_Recursive_FolderNameSpecifiesToAddInsteadOfReplace::case:1560d5268a46ddf1 780e7212749cb332abbf1a1cef33ed8938584b817476d39424b4628d34c3f4ea
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachAllThisCommandTests.cs::AttachAllThisCommandTests.AttachAllThisForce_AttachPoint::case:bc5a9cb6a299a551 4115d8f4e18acc9992e84f30962536c4cd15db2e4c8c54aa840f5ee397ba8613
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachAllThisCommandTests.cs::AttachAllThisCommandTests.AttachAllThisForce_AttachPoint::case:0f04a34ae77465d3 4115d8f4e18acc9992e84f30962536c4cd15db2e4c8c54aa840f5ee397ba8613
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachAllThisCommandTests.cs::AttachAllThisCommandTests.AttachAllThisForce_AttachPoint::case:1560d5268a46ddf1 4115d8f4e18acc9992e84f30962536c4cd15db2e4c8c54aa840f5ee397ba8613
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachAllThisCommandTests.cs::AttachAllThisCommandTests.AttachAllThisForce_RlvWearableType::case:bc5a9cb6a299a551 91d47986c684dfb289df7f867f847d270324cbc6754a24aaa009b3a96226661d
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachAllThisCommandTests.cs::AttachAllThisCommandTests.AttachAllThisForce_RlvWearableType::case:0f04a34ae77465d3 91d47986c684dfb289df7f867f847d270324cbc6754a24aaa009b3a96226661d
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachAllThisCommandTests.cs::AttachAllThisCommandTests.AttachAllThisForce_RlvWearableType::case:1560d5268a46ddf1 91d47986c684dfb289df7f867f847d270324cbc6754a24aaa009b3a96226661d
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachCommandTests.cs::AttachCommandTests.AttachForce::case:5e4fd9176ccab2f0 2ecd1c4e8f6238ac0e1274053bcc512d08767c61a0532bbd321d1c8b15c94d6d
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachCommandTests.cs::AttachCommandTests.AttachForce::case:1112c98c6420210d 2ecd1c4e8f6238ac0e1274053bcc512d08767c61a0532bbd321d1c8b15c94d6d
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachCommandTests.cs::AttachCommandTests.AttachForce::case:0dd9d8fadf48e313 2ecd1c4e8f6238ac0e1274053bcc512d08767c61a0532bbd321d1c8b15c94d6d
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachCommandTests.cs::AttachCommandTests.AttachForce_WithClothing::case:5e4fd9176ccab2f0 1bbd8cf1f00311fc656ca6c05d60ed033c6a69d59d4ff69d876f50f9d48645a3
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachCommandTests.cs::AttachCommandTests.AttachForce_WithClothing::case:1112c98c6420210d 1bbd8cf1f00311fc656ca6c05d60ed033c6a69d59d4ff69d876f50f9d48645a3
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachCommandTests.cs::AttachCommandTests.AttachForce_WithClothing::case:0dd9d8fadf48e313 1bbd8cf1f00311fc656ca6c05d60ed033c6a69d59d4ff69d876f50f9d48645a3
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachCommandTests.cs::AttachCommandTests.AttachForce_AlreadyAttached::case:2a7ad8f0a57b741d 751483b13ff87bf258c3aec671ff6a8c9b34e8126f7e877982065d28ef426385
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachCommandTests.cs::AttachCommandTests.AttachForce_AlreadyAttached::case:da775b6e5cf13e70 751483b13ff87bf258c3aec671ff6a8c9b34e8126f7e877982065d28ef426385
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachCommandTests.cs::AttachCommandTests.AttachForce_AlreadyAttached::case:e59967ec103647cc 751483b13ff87bf258c3aec671ff6a8c9b34e8126f7e877982065d28ef426385
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachCommandTests.cs::AttachCommandTests.AttachForce_PositionFromFolderName::case:5e4fd9176ccab2f0 6a34c794669e596b982f5050071502e43061053677b44536f60847d4c3798634
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachCommandTests.cs::AttachCommandTests.AttachForce_PositionFromFolderName::case:1112c98c6420210d 6a34c794669e596b982f5050071502e43061053677b44536f60847d4c3798634
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachCommandTests.cs::AttachCommandTests.AttachForce_PositionFromFolderName::case:0dd9d8fadf48e313 6a34c794669e596b982f5050071502e43061053677b44536f60847d4c3798634
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachCommandTests.cs::AttachCommandTests.AttachForce_FolderNameSpecifiesToAddInsteadOfReplace::case:2a7ad8f0a57b741d 5c09150744493c62b8b5c0ec139b6580bb74fe618b1a111b7a1ce583e8fa82e1
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachCommandTests.cs::AttachCommandTests.AttachForce_FolderNameSpecifiesToAddInsteadOfReplace::case:da775b6e5cf13e70 5c09150744493c62b8b5c0ec139b6580bb74fe618b1a111b7a1ce583e8fa82e1
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachCommandTests.cs::AttachCommandTests.AttachForce_FolderNameSpecifiesToAddInsteadOfReplace::case:e59967ec103647cc 5c09150744493c62b8b5c0ec139b6580bb74fe618b1a111b7a1ce583e8fa82e1
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachCommandTests.cs::AttachCommandTests.AttachForce_AttachPrivateParentFolder::case:5e4fd9176ccab2f0 268a375256333f2986ac68c5a357042b424f867585ef5a954328f9333b62007c
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachCommandTests.cs::AttachCommandTests.AttachForce_AttachPrivateParentFolder::case:1112c98c6420210d 268a375256333f2986ac68c5a357042b424f867585ef5a954328f9333b62007c
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachCommandTests.cs::AttachCommandTests.AttachForce_AttachPrivateParentFolder::case:0dd9d8fadf48e313 268a375256333f2986ac68c5a357042b424f867585ef5a954328f9333b62007c
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachThisCommandTests.cs::AttachThisCommandTests.AttachThis_Default::case:6882162efd904e15 3bd216683e650e5727244882dd61b16c58192e48438d8a8a831d60782d409fb2
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachThisCommandTests.cs::AttachThisCommandTests.AttachThis_Default::case:45b5361aae1131d0 3bd216683e650e5727244882dd61b16c58192e48438d8a8a831d60782d409fb2
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachThisCommandTests.cs::AttachThisCommandTests.AttachThis_Default::case:f66e403049f440cf 3bd216683e650e5727244882dd61b16c58192e48438d8a8a831d60782d409fb2
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachThisCommandTests.cs::AttachThisCommandTests.AttachThis_ById::case:6882162efd904e15 3f6cc1241679d7746e58925c3c17aabf88a5c8694bbfda0fceb4b054d8b90392
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachThisCommandTests.cs::AttachThisCommandTests.AttachThis_ById::case:45b5361aae1131d0 3f6cc1241679d7746e58925c3c17aabf88a5c8694bbfda0fceb4b054d8b90392
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachThisCommandTests.cs::AttachThisCommandTests.AttachThis_ById::case:f66e403049f440cf 3f6cc1241679d7746e58925c3c17aabf88a5c8694bbfda0fceb4b054d8b90392
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachThisCommandTests.cs::AttachThisCommandTests.AttachThis_FolderNameSpecifiesToAddInsteadOfReplace::case:a2681d046a6f6fef 67d84750193300b9445aa33d47d78f8fc5161b9456b7755d305568c695737a4b
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachThisCommandTests.cs::AttachThisCommandTests.AttachThis_FolderNameSpecifiesToAddInsteadOfReplace::case:34172d9d6ebbcf53 67d84750193300b9445aa33d47d78f8fc5161b9456b7755d305568c695737a4b
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachThisCommandTests.cs::AttachThisCommandTests.AttachThis_FolderNameSpecifiesToAddInsteadOfReplace::case:30379630ffa50e68 67d84750193300b9445aa33d47d78f8fc5161b9456b7755d305568c695737a4b
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachThisCommandTests.cs::AttachThisCommandTests.AttachThis_FolderNameSpecifiesRlvAttachmentPoint::case:6882162efd904e15 c45b9e08563acaf523fc8bddf5953e970bc773749d6f52b59f0806f104c24d27
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachThisCommandTests.cs::AttachThisCommandTests.AttachThis_FolderNameSpecifiesRlvAttachmentPoint::case:45b5361aae1131d0 c45b9e08563acaf523fc8bddf5953e970bc773749d6f52b59f0806f104c24d27
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachThisCommandTests.cs::AttachThisCommandTests.AttachThis_FolderNameSpecifiesRlvAttachmentPoint::case:f66e403049f440cf c45b9e08563acaf523fc8bddf5953e970bc773749d6f52b59f0806f104c24d27
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachThisCommandTests.cs::AttachThisCommandTests.AttachThis_FromHiddenSubfolder::case:6882162efd904e15 059d647777a2d65d5a14f77aa6914449d1a9c0cbc876d3acccfa3a0de30988e8
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachThisCommandTests.cs::AttachThisCommandTests.AttachThis_FromHiddenSubfolder::case:45b5361aae1131d0 059d647777a2d65d5a14f77aa6914449d1a9c0cbc876d3acccfa3a0de30988e8
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachThisCommandTests.cs::AttachThisCommandTests.AttachThis_FromHiddenSubfolder::case:f66e403049f440cf 059d647777a2d65d5a14f77aa6914449d1a9c0cbc876d3acccfa3a0de30988e8
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachThisCommandTests.cs::AttachThisCommandTests.AttachThis_AttachPoint::case:6882162efd904e15 9e004ad47add2d97565c14c2d70bff08d1bea46d997140ad17ca5ffe04ee41a9
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachThisCommandTests.cs::AttachThisCommandTests.AttachThis_AttachPoint::case:45b5361aae1131d0 9e004ad47add2d97565c14c2d70bff08d1bea46d997140ad17ca5ffe04ee41a9
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachThisCommandTests.cs::AttachThisCommandTests.AttachThis_AttachPoint::case:f66e403049f440cf 9e004ad47add2d97565c14c2d70bff08d1bea46d997140ad17ca5ffe04ee41a9
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachThisCommandTests.cs::AttachThisCommandTests.AttachThis_RlvWearableType::case:6882162efd904e15 1c0adf85cffdece3b2576998e7c73921e8b842daf2e14ef1319e71c1f64797b3
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachThisCommandTests.cs::AttachThisCommandTests.AttachThis_RlvWearableType::case:45b5361aae1131d0 1c0adf85cffdece3b2576998e7c73921e8b842daf2e14ef1319e71c1f64797b3
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/AttachThisCommandTests.cs::AttachThisCommandTests.AttachThis_RlvWearableType::case:f66e403049f440cf 1c0adf85cffdece3b2576998e7c73921e8b842daf2e14ef1319e71c1f64797b3
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/ClearCommandTests.cs::ClearCommandTests.Clear::test 865d022233930e9582fec5b0e99063f15506a339c430755aba83706b594182ad
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/ClearCommandTests.cs::ClearCommandTests.Clear_CaseInSensitive::test b70296f9d2b6c9eb8c6dd6e560056ab8320d746a991fafec858812fc2ebb3141
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/ClearCommandTests.cs::ClearCommandTests.Clear_SenderBased::test 1ae70737411e18626227c0b15181572c1c623eefce0a8fa1a874b2229c44c38e
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/ClearCommandTests.cs::ClearCommandTests.Clear_Filtered::test e0f0b5a42c3baf92fef6a8d4fc2c60dbd6963db6f844fed55b06968f0c9e543f
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/DetachAllCommandTests.cs::DetachAllCommandTests.DetachAllForce_Recursive::test 45405dbca6c2b8bb9f439736d53c2ff60056252f4cdf6296bedcc14d2be9248e
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/DetachAllCommandTests.cs::DetachAllCommandTests.DetachAllForce_Recursive_EnforceRestrictions::test 6186f5923009fb984daef726e8df44aff7cb65f74c2e381dd8cc9968f5534e43
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/DetachAllCommandTests.cs::DetachAllCommandTests.DetachAllForce_Recursive_PrivateTargetDir::test 300a323967b6258d1202190bbd3de7b91699231f7a5afa86204ba627cb61215f
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/DetachAllCommandTests.cs::DetachAllCommandTests.DetachAllForce_Recursive_PrivateSubFolders::test e688b64d13f0a07f4bfeae0715fbfbf98c1d1fa64b0aefbd0e4e3d3d4dd98eee
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/DetachAllCommandTests.cs::DetachAllCommandTests.DetachAllForce_Recursive_NostripSubFolders::test 22cf1a159861c98c8a0f14ac63bafcbef21466c2ac01e615fe9ca4630d16f956
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/DetachAllCommandTests.cs::DetachAllCommandTests.DetachAllForce_Recursive_NostripSubFolders_LinkException::test cbe38368a6d4c59d72291195688d0c70898be5c3cceb02f09c5d386c3668fb07
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/DetachAllCommandTests.cs::DetachAllCommandTests.DetachAllForce_Recursive_NostripItemName::test ea0fab47cb1829338948f605919fcf1dca4f88d7965cdca4c7f457e399e4fbfc
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/DetachAllThisCommandTests.cs::DetachAllThisCommandTests.DetachAllThisForce_Default::test 8fe4eacf8cc5841e638d69540e2ab080efc3e64534346ece854429d0476f8a84
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/DetachAllThisCommandTests.cs::DetachAllThisCommandTests.DetachAllThisForce_Nostrip::test 754bd01f2f0b77c05ee5d1548f76337da93d980a48ad0922d80f34707c4fe68b
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/DetachAllThisCommandTests.cs::DetachAllThisCommandTests.DetachAllThisForce_Nostrip_LinkException::test 0cce15f7cfda160733c305b0867be31875e1814b38e2e980525d960e0214ad51
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/DetachAllThisCommandTests.cs::DetachAllThisCommandTests.DetachAllThisForce_ById::test 2f657ffed317d4d7f97f6111942ea8214996872da6294f7c66d07890647f7f63
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/DetachAllThisCommandTests.cs::DetachAllThisCommandTests.DetachAllThisForce_ById_Nostrip::test 48ab7aec02efd652478ca3110dd39011fd9b79a1e0a1336f53e9f77b2f56e635
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/DetachAllThisCommandTests.cs::DetachAllThisCommandTests.DetachAllThisForce_ById_Nostrip_LinkException::test 5d882f00bfe73cecfc3e96c26ff18a20c00481619996b25ed2ce851eff9a86ce
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/DetachAllThisCommandTests.cs::DetachAllThisCommandTests.DetachThisAllForce_ByRlvAttachmentPoint::test 30e6806d5c484bf2a2f9a3b1fcdb5e88272874b0e755462c3b0bfa97326d180c
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/DetachAllThisCommandTests.cs::DetachAllThisCommandTests.DetachThisAllForce_ByRlvAttachmentPoint_NoStrip::test 657125be7aec668f72e744cc87cae38f022c8ccf9e8980c8ef4bea7e0557fdd1
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/DetachAllThisCommandTests.cs::DetachAllThisCommandTests.DetachThisAllForce_ByRlvAttachmentPoint_NoStrip_LinkException::test fe019191a9a3df9a43fd500db775ba5f874f4b767096365cba390480b2b2189f
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/DetachAllThisCommandTests.cs::DetachAllThisCommandTests.DetachAllThisForce_ByRlvWearableType::test ccf302d870f323790af63873fcbb172f084c4e7400a728e480378706b5fb9947
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/DetachAllThisCommandTests.cs::DetachAllThisCommandTests.DetachAllThisForce_ByRlvWearableType_NoStrip::test 1947e7c9cfe8bb931ee7ad50c6f505515feeb9d30b236702a2d68fb4734a30f0
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/DetachAllThisCommandTests.cs::DetachAllThisCommandTests.DetachAllThisForce_ByRlvWearableType_NoStrip_LinkException::test 50ec101ab557e78d947ac7f9878acd4df4957482f358a7ce02371df8754add94
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/DetachAllThisCommandTests.cs::DetachAllThisCommandTests.DetachAllThisForce_ByRlvWearableType_PrivateFolder::test 2ba745b093f0348d8754f74073c6a6a0f18383b5ce4a73721b39b01f0306a994
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/DetachMeCommandTests.cs::DetachMeCommandTests.DetachMeForce::test fde065233689ec75c12e9607acf06c5859a91efea58e143ecc508ebec784a567
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/DetachMeCommandTests.cs::DetachMeCommandTests.DetachMeForce_WithNoStripItemName_SpecialException::test ee511230131312be9b788033aac8766ea3cb3c1f8d7c5b9b26a4bd6a83cd695c
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/DetachMeCommandTests.cs::DetachMeCommandTests.DetachMeForce_WithLockedFolderRestriction::test 05fefae0563306af0c491006f18915ff1b250b7972c82c160f20f06e07335887
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/DetachMeCommandTests.cs::DetachMeCommandTests.DetachMeForce_MultipleLinksSameItem::test 1ae8a318762625819371fb109fd673e0d31a2c0354add1e65802eb54cb71e303
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/DetachThisCommandTests.cs::DetachThisCommandTests.DetachThisForce_Default::test ae8c0fd737f869ef3e2dbd97ae28974b35c6bbc5327151c0074d531efdaaf54e
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/DetachThisCommandTests.cs::DetachThisCommandTests.DetachThisForce_NoStrip::test 3aa17222f7539814f8329e07de548cca4bb702f4b0409e793ea551327b0c57d0
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/DetachThisCommandTests.cs::DetachThisCommandTests.DetachThisForce_NoStripFolder::test 16b74c3bf8312ccb885e61f933ec9d292988d2e1fad05e0188006df5630681f8
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/DetachThisCommandTests.cs::DetachThisCommandTests.DetachThisForce_NoStripFolder_LinkException::test b86b22a0ab30d0ded0cd6fbc7d34fae77e521861f5672b44a25a77325e594ab4
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/DetachThisCommandTests.cs::DetachThisCommandTests.DetachThisForce_ById::test 3c4a211e5fefb44b42f50f6e6e58f8f852c8cf2d732bb6c3f737c3d6a592fa22
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/DetachThisCommandTests.cs::DetachThisCommandTests.DetachThisForce_ById_NostripItemName::test f32926ca6f4328afdd3ddeb9f7bec8ff2ee01e9563555921ac8c663d20005551
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/DetachThisCommandTests.cs::DetachThisCommandTests.DetachThisForce_ById_NostripFolderName::test bec3216bf016c2543a3410b069abd786167e04a7527253887f158127644656a8
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/DetachThisCommandTests.cs::DetachThisCommandTests.DetachThisForce_ById_NostripFolderName_LinkException::test 1b5eb3a0bdef8ea65b800533ab3153dc6b3ea21d2f4f27e4820d0a0df48891a2
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/DetachThisCommandTests.cs::DetachThisCommandTests.DetachThisForce_ByRlvAttachmentPoint::test 7e8f3a4d8b2cbdb5cc81eea598da6ef6395834b1cb7a629dc8d7ee2bfd80fab5
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/DetachThisCommandTests.cs::DetachThisCommandTests.DetachThisForce_ByRlvAttachmentPoint_NoStrip::test f6ff482bdb8d28414e01952201e37e49316b3e2345b0ff85dd4cb059193d1816
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/DetachThisCommandTests.cs::DetachThisCommandTests.DetachThisForce_ByRlvAttachmentPoint_NoStrip_LinkException::test 289f8cc48f0e6a412d58258876e4aca08d8116d549642a0011bbdaf9b2223e83
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/DetachThisCommandTests.cs::DetachThisCommandTests.DetachThisForce_ByRlvWearableType::test 51607294f12279974c2b44b47ba2eadca9846180a39bcde6a28c020dc4466254
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/DetachThisCommandTests.cs::DetachThisCommandTests.DetachThisForce_ByRlvWearableType_NoStrip::test 30dec183993b2a644c2812ffc1c863e1714df134942f7827df818d9200e47c38
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/DetachThisCommandTests.cs::DetachThisCommandTests.DetachThisForce_ByRlvWearableType_NoStrip_LinkException::test 62f59cf66f21dcac15cf3166dcec2183181c0b434e9eacba796eb7025c4f1ab3
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/DetachThisCommandTests.cs::DetachThisCommandTests.DetachThisForce_ByRlvWearableType_PrivateFolder::test dd40588598bd081189e7c4f284af3851a140155e2ede0ae2121dd59a156dc988
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach::case:bb1d34dc76ade75f 16420d56c60229e8d8b6a2a0d63b1f500112c23cef451d69bb0ed97fe9b63bae
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach::case:c9faa5be8fef55e8 16420d56c60229e8d8b6a2a0d63b1f500112c23cef451d69bb0ed97fe9b63bae
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_NoStrip::case:bb1d34dc76ade75f 5b3f1cbe99833e16c6f10ef568618627445babbcdfc9be555b48257bfdffeea7
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_NoStrip::case:c9faa5be8fef55e8 5b3f1cbe99833e16c6f10ef568618627445babbcdfc9be555b48257bfdffeea7
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_NoStrip_LinkException::case:bb1d34dc76ade75f 96a4b53d9e55dcd656c25af6619a3d0d67f5bc2517a759d722559a4ffb225472
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_NoStrip_LinkException::case:c9faa5be8fef55e8 96a4b53d9e55dcd656c25af6619a3d0d67f5bc2517a759d722559a4ffb225472
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ExternalItems::case:bb1d34dc76ade75f 7545f36532fcb7974a9e009e567b2342754a11da95eb3f17ee04089dcec42664
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ExternalItems::case:c9faa5be8fef55e8 7545f36532fcb7974a9e009e567b2342754a11da95eb3f17ee04089dcec42664
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ByFolder::case:97eb7af1f9c3c62c 583d3f596c80411d950038e3ec64032bee75150b8c819741fe89a4ca40eb2553
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ByFolder::case:1a04fd408fddaac0 583d3f596c80411d950038e3ec64032bee75150b8c819741fe89a4ca40eb2553
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ByFolder_NoStrip::case:2117c838922f5ba4 3a21b8ae807126d6f93ac95e16c47330b4146ace9781e9c9665ad493ee8c48b1
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ByFolder_NoStrip::case:11d4ca4fd3e35db1 3a21b8ae807126d6f93ac95e16c47330b4146ace9781e9c9665ad493ee8c48b1
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ByFolder_NoStrip_LinkException::case:2117c838922f5ba4 7c00e7dc70b3078d75009cf78a9fece889eee85f237c1a3c79c6249ae5e5327f
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ByFolder_NoStrip_LinkException::case:11d4ca4fd3e35db1 7c00e7dc70b3078d75009cf78a9fece889eee85f237c1a3c79c6249ae5e5327f
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ByAttachmentPoint::case:644d3f75f3570ac3 e09627228c1cf8311e56ac6660389bc1b268db8fd4f883dc40aaf3d2ec00916b
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ByAttachmentPoint::case:53be219b37533fa6 e09627228c1cf8311e56ac6660389bc1b268db8fd4f883dc40aaf3d2ec00916b
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ByAttachmentPoint_NoStrip::case:644d3f75f3570ac3 ffaaad92700d5d606154abdddd05c24c7584c5c3e55290df61e2b2a71d8148d7
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ByAttachmentPoint_NoStrip::case:53be219b37533fa6 ffaaad92700d5d606154abdddd05c24c7584c5c3e55290df61e2b2a71d8148d7
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ByAttachmentPoint_NoStrip_LinkException::case:644d3f75f3570ac3 af1b1caf070a186bc2b02b598919b52d47c289d708fde3713e48ce1a40d7c025
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ByAttachmentPoint_NoStrip_LinkException::case:53be219b37533fa6 af1b1caf070a186bc2b02b598919b52d47c289d708fde3713e48ce1a40d7c025
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ByAttachmentPoint_None::case:9a124e69f33b279f afed603254ad6048a46e157254f16253063e6c76c9ea16f46a69d8455bc0e6fb
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ByAttachmentPoint_None::case:800d7d8ba57071b1 afed603254ad6048a46e157254f16253063e6c76c9ea16f46a69d8455bc0e6fb
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ByUUID::case:e5bdbdba9613b46a 4b1a8acea7f1bb100bf11e9329672c64b53aba4974558f1c693460eef7f56c2d
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ByUUID::case:7cb3f81460bd8e9f 4b1a8acea7f1bb100bf11e9329672c64b53aba4974558f1c693460eef7f56c2d
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ByUUID_NostripInItemName::case:e5bdbdba9613b46a 6857733912b45ef9153b0f58cd74ae6c9dc0034fa10933d153cae88a2c7d9423
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ByUUID_NostripInItemName::case:7cb3f81460bd8e9f 6857733912b45ef9153b0f58cd74ae6c9dc0034fa10933d153cae88a2c7d9423
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ByUUID_NostripInFolderName::case:e5bdbdba9613b46a 1a3189f931e086ab3d2d3e99c53dba2e9d39dce75a52fd02400c6892aef5d0c4
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ByUUID_NostripInFolderName::case:7cb3f81460bd8e9f 1a3189f931e086ab3d2d3e99c53dba2e9d39dce75a52fd02400c6892aef5d0c4
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ByUUID_NostripInFolderName_LinkException::case:e5bdbdba9613b46a bd7bc72a107b4a21b00977e13b086da192bef2c2e6f0fdb73b8e332016c6ef23
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ByUUID_NostripInFolderName_LinkException::case:7cb3f81460bd8e9f bd7bc72a107b4a21b00977e13b086da192bef2c2e6f0fdb73b8e332016c6ef23
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ByUUID_WithRestrictions::case:e5bdbdba9613b46a 2ecf40d1d338117ddac4cfd6c7a030e96b7adf72cd90e0d8327787317e1f38d7
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ByUUID_WithRestrictions::case:7cb3f81460bd8e9f 2ecf40d1d338117ddac4cfd6c7a030e96b7adf72cd90e0d8327787317e1f38d7
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ByUUID_External::case:e5bdbdba9613b46a e0bdc682df3416bdc01855e6e63974e64c21951aac629807352220baf572dded
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ByUUID_External::case:7cb3f81460bd8e9f e0bdc682df3416bdc01855e6e63974e64c21951aac629807352220baf572dded
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/RemOutfitCommandTests.cs::RemOutfitCommandTests.RemOutfit::test 60bd0e62bbd4613c4d2d1a65705644dc25fd7327408adfc0bb7e95c45d79cdcb
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/RemOutfitCommandTests.cs::RemOutfitCommandTests.RemOutfit_PrivateFolders::test d79ac3806f50915390edd0a24b756ef398c1334017f69d16f4cb887dcdd41fb1
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/RemOutfitCommandTests.cs::RemOutfitCommandTests.RemOutfit_ExternalItems::test 0265a9fee1070cbcc458bfcb05fe267991cbdb5480500c1b32aace1eb4935217
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/RemOutfitCommandTests.cs::RemOutfitCommandTests.RemOutfit_ExternalItems_NoStrip::test b93d39d919fb70b02ccdb724969f7b983c726c707bca96e1b1ddc6ee248a734f
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/RemOutfitCommandTests.cs::RemOutfitCommandTests.RemOutfit_ExternalItems_NoStrip_LinkException::test 5ecc44228573645e0a0c78d100dab54b793c6ce8dc50a02d79a919fe6d7c1678
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/RemOutfitCommandTests.cs::RemOutfitCommandTests.RemOutfit_ExternalItems_ByType::test 8ba106f071f8768af1d6213c04f67dd0aec846ae47552686eba86c489bdb0292
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/RemOutfitCommandTests.cs::RemOutfitCommandTests.RemOutfit_Folder::test 45f9e7a9d0ef99ec7d58b59f1c1db7b6065994939717842bb02486b470b357b5
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/RemOutfitCommandTests.cs::RemOutfitCommandTests.RemOutfit_Folder_PrivateFolder::test 68f3050a1b667304ff2b252690cc7d1994964dbd2c7633d54e5c6654714c0aed
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/RemOutfitCommandTests.cs::RemOutfitCommandTests.RemOutfit_Folder_NoStrip::test d56b83a72d6d3529af0390674550ce40733c14de6210cf71e277f0e195d1e330
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/RemOutfitCommandTests.cs::RemOutfitCommandTests.RemOutfit_Folder_NoStripFolderName::test a28f5517a9d05085627d5acaf33441d598912301962f6e99aaff49ef5114af53
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/RemOutfitCommandTests.cs::RemOutfitCommandTests.RemOutfit_Folder_NoStripFolderName_LinkException::test 80efc201f976365e68d32ae1b30db0f10a17cbc65aedc82895ffa679700008da
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/RemOutfitCommandTests.cs::RemOutfitCommandTests.RemOutfit_Specific::test 7235143679739442ec942d294a8a68f69b7fb5678ed4e3ca03be35c74e9c71a9
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/RemOutfitCommandTests.cs::RemOutfitCommandTests.RemOutfit_Specific_PrivateFolder::test 3feea26f000dc7eb86b1413f1a5bdd5f109c5f9f969918cd1ce2e7f926f26c12
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/RemOutfitCommandTests.cs::RemOutfitCommandTests.RemOutfit_Specific_NoStrip::test 6e4b8bc53933a889df1cf553ca7e0601e5061bb87013a4075c2ff357cc9d987f
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/RemOutfitCommandTests.cs::RemOutfitCommandTests.RemOutfit_Specific_NoStrip_LinkException::test 72b1409f70531d859f15a012cb1fb03d795d2065c5d03b7a263d352ca4b80e98
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/RemOutfitCommandTests.cs::RemOutfitCommandTests.RemOutfit_BodyPart_Specific::test 13804c96395db86821371dc8f2cacd2cb182338f8ea88034afcc5da19e3f0691
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/SetDebugCommandTests.cs::SetDebugCommandTests.SetDebug_Default::case:fa77559e30768d15 abcee425068df326a3258ab4d881218e6eee52523fa5d306b191308e85dfff3d
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/SetDebugCommandTests.cs::SetDebugCommandTests.SetDebug_Default::case:55694f25ed879d95 abcee425068df326a3258ab4d881218e6eee52523fa5d306b191308e85dfff3d
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/SetDebugCommandTests.cs::SetDebugCommandTests.SetDebug_Invalid::test 2e0595319ba8e2c9a8280c5b034363ad7998eb740cb6b7fff3d75bb0167c6464
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/SetEnvCommandTests.cs::SetEnvCommandTests.SetEnv_Default::case:f656b648d00a6d91 836c1332ca9c4f645e5c9dca8b4a2b967d55fd8148901b05ce5d741e665ab7e1
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/SetEnvCommandTests.cs::SetEnvCommandTests.SetEnv_Default::case:55694f25ed879d95 836c1332ca9c4f645e5c9dca8b4a2b967d55fd8148901b05ce5d741e665ab7e1
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/SetGroupCommandTests.cs::SetGroupCommandTests.SetGroup_ByName::test fae27e58cd981f5471f4c2b8356bb07aa5e76a57aaf0882d0dbfb86360e077e3
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/SetGroupCommandTests.cs::SetGroupCommandTests.SetGroup_ByNameAndRole::test 408442b86bb8259eb9bbb4cf8a5d3b0830c7ba9357fa04cb6e851511a7a24df1
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/SetGroupCommandTests.cs::SetGroupCommandTests.SetGroup_ById::test 27f13c52c8c5e2e4298fee3f4322f9906d5f82e900aa5f46c9a8ffac3a6dfae7
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/SetGroupCommandTests.cs::SetGroupCommandTests.SetGroup_ByIdAndRole::test e18fd0c318ebd4f9a189418449568b3a34b8f7d3a0097f100a7253c4d5a31bde
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/SetRotCommandTests.cs::SetRotCommandTests.SetRot::test c3302d63cdda9d72b85dad2749e2684cc26d51c72ddc6ace8275911f8ba67ef4
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/SitCommandTests.cs::SitCommandTests.ForceSit_Default::test 24e45ba898cb8ed0919369d07a39d0b21982fa4fc4c41eb4835ba765c05e2469
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/SitCommandTests.cs::SitCommandTests.ForceSit_RestrictedUnsit_WhileStanding::test 8d179277f6a7f98ead813de7bd02ab5146b46ce240d1d5e4a69037885e5f626a
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/SitCommandTests.cs::SitCommandTests.ForceSit_RestrictedUnsit_WhileSeated::test 1f2debd6e644c86698577e1c04db96d6aac43267ceae8de9f28435b62ff92817
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/SitCommandTests.cs::SitCommandTests.ForceSit_RestrictedSit::test 8ac0964fc07bb5e860123ce8de1102c2254ffde28f246896d81f7524c3c87021
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/SitCommandTests.cs::SitCommandTests.ForceSit_RestrictedStandTp::test bc0c259477ef5f1e5a76b1081f604ba421c82340f738e37fd52b91a421037cf6
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/SitCommandTests.cs::SitCommandTests.ForceSit_InvalidObject::test 787bfe6fefe3895b4bcb5da027ffeac70bf67c3c7a295dbbf7e1526156290040
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/SitGroundCommandTests.cs::SitGroundCommandTests.ForceSitGround::test 2319cd49aaae5ac824bc5ffd4f33a5e4f3f684ebec1dc1f1732071eb44ee1cb8
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/SitGroundCommandTests.cs::SitGroundCommandTests.ForceSitGround_RestrictedSit::test 5ac661e9f7fa93cf6ca76aa69f6d84ac61ebd22f26620203f084777010b6de4d
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/TpToCommandTests.cs::TpToCommandTests.TpTo_Default::test 1613e723da60f84dfb54a7345b96566a055a9b7a017e66b0929d6f37c04b62a3
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/TpToCommandTests.cs::TpToCommandTests.TpTo_WithRegion::test 50c5f63c5cb0da221846fd7c0c7f2d471bef2aa2ab203a9b5bdb4eceeb3d97bf
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/TpToCommandTests.cs::TpToCommandTests.TpTo_WithRegionAndLookAt::test c9030189de7acdad0db5c8f83e49ee0433ec0588a35436ab39cdcf40a4fd4d36
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/TpToCommandTests.cs::TpToCommandTests.TpTo_RestrictedUnsit::test 4dc00a1048593f7468271a4262cf311a3516ea4a53e288eeca69d1297dafc9f2
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/TpToCommandTests.cs::TpToCommandTests.TpTo_RestrictedTpLoc::test 3e1ecc1d04973a496edf9d156e52ba76a93ff431181a3ece93c0e4f82884895a
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/UnsitCommandTests.cs::UnsitCommandTests.ForceUnSit::test 2f91e1112e1c4e97b79a4dc7bcd4d4a85f13125bd636f81147ce5b396366ebed
// pending-parity-case: LibreMetaverse.Tests/RLV/Commands/UnsitCommandTests.cs::UnsitCommandTests.ForceUnSit_RestrictedUnsit::test 2ecf210dc83b06018cdcf44cb44bdf43f1040133e7523542a2e1126d6d98004f
// pending-parity-case: LibreMetaverse.Tests/RLV/Exceptions/AcceptPermissionExceptionTests.cs::AcceptPermissionExceptionTests.AcceptPermission::test a5ffc51718e89fb872c6df8b8667f6d231618d47a2ffc71d596e8e10e15cb02e
// pending-parity-case: LibreMetaverse.Tests/RLV/Exceptions/AcceptTpExceptionTests.cs::AcceptTpExceptionTests.CanAutoAcceptTp_User::test e988496e81a717eae1a96c5501e748a441fa64f637aaa47a6ae7a8d571c30f6e
// pending-parity-case: LibreMetaverse.Tests/RLV/Exceptions/AcceptTpExceptionTests.cs::AcceptTpExceptionTests.CanAutoAcceptTp_All::test 428ec184c9d09f6ec57ac3429180f327ed1b79e9d9dea9815df3bb6f0f6244fd
// pending-parity-case: LibreMetaverse.Tests/RLV/Exceptions/AcceptTpRequestExceptionTests.cs::AcceptTpRequestExceptionTests.CanAutoAcceptTpRequest_User::test 3a5af1a55e74b5e75a04abc11826ded17c327ac2ed99ab2a423674fbb0e61f31
// pending-parity-case: LibreMetaverse.Tests/RLV/Exceptions/AcceptTpRequestExceptionTests.cs::AcceptTpRequestExceptionTests.CanAutoAcceptTpRequest_All::test 8e2cf7c4d17dcec4d7855fc430092699416108966fb5d97c170c13f0bcd04cfe
// pending-parity-case: LibreMetaverse.Tests/RLV/Exceptions/AttachAllThisExceptExceptionTests.cs::AttachAllThisExceptExceptionTests.AttachAllThis_Recursive_ExceptAll::test 1daa414beb2a767518f335f6ae59e711395375ed9d7912fbbc139fa0998dfdb1
// pending-parity-case: LibreMetaverse.Tests/RLV/Exceptions/AttachAllThisExceptExceptionTests.cs::AttachAllThisExceptExceptionTests.AttachAllThis_Recursive_ExceptAll_Recursive::test 6e0c78d6ed78bedca9a8c6a9a83fd9f90f7123da433eb4c560e6f5c0b6fe6d94
// pending-parity-case: LibreMetaverse.Tests/RLV/Exceptions/AttachAllThisExceptExceptionTests.cs::AttachAllThisExceptExceptionTests.AttachAllThis_Recursive_ExceptAll_Recursive_AddRem::test 9423ed205501604501d31909414ecf6ef99a0d56d4efae100f5576b31b71a858
// pending-parity-case: LibreMetaverse.Tests/RLV/Exceptions/AttachThisExceptExceptionTests.cs::AttachThisExceptExceptionTests.AttachThisExcept_Default::test b8e6e55d8f2654429c9826e38ffc8522eec44ab2521891b68616db61ac662db0
// pending-parity-case: LibreMetaverse.Tests/RLV/Exceptions/AttachThisExceptExceptionTests.cs::AttachThisExceptExceptionTests.AttachThisExcept_AddRem::test 05bc7eab5dd02a0a3e60f85eb51b374623aaa29c9ce2b522748a3478b8ee44ea
// pending-parity-case: LibreMetaverse.Tests/RLV/Exceptions/DenyPermissionExceptionTests.cs::DenyPermissionExceptionTests.DenyPermission::test c2284b63e7b4a93f8613a3afe34466d14e1c6ed8528656d54ae64ca6d081cdd5
// pending-parity-case: LibreMetaverse.Tests/RLV/Exceptions/DetachAllThisExceptExceptionTests.cs::DetachAllThisExceptExceptionTests.DetachAllThis_Recursive_ExceptAll::test 75e7ab22f6d9d058580fd83741d65f7e5babb7ad54805eaeb16bec8cd65370ed
// pending-parity-case: LibreMetaverse.Tests/RLV/Exceptions/DetachAllThisExceptExceptionTests.cs::DetachAllThisExceptExceptionTests.DetachAllThis_Recursive_ExceptAll_Recursive::test 3fb8bb13d6a917d9be18265d90767488cde66746badc6584025bbbaf84f020ad
// pending-parity-case: LibreMetaverse.Tests/RLV/Exceptions/DetachAllThisExceptExceptionTests.cs::DetachAllThisExceptExceptionTests.DetachAllThis_Recursive_ExceptAll_Recursive_AddRem::test fb5fd8a4eda181d22d1756ec0cae700c4b90895a74dc79c24c67c1705cfd37c8
// pending-parity-case: LibreMetaverse.Tests/RLV/Exceptions/DetachThisExceptExceptionTests.cs::DetachThisExceptExceptionTests.DetachAllThis_Recursive_Except::test 3222d97d73d8b54bd11212f8cd3de26279040321f0bc330e061ff93880053f3e
// pending-parity-case: LibreMetaverse.Tests/RLV/Exceptions/DetachThisExceptExceptionTests.cs::DetachThisExceptExceptionTests.DetachAllThis_Recursive_Except_AddRem::test d25b2c533b9b51428c0c2414d687c466a3c80c4a573dd36763504de19e8dc6f8
// pending-parity-case: LibreMetaverse.Tests/RLV/Exceptions/EditExceptionTests.cs::EditExceptionTests.CanEdit_Exception::test e435b03faef04dfe06d0cbec76e94cbf30e61ad7bc08502728f9239cf47292f8
// pending-parity-case: LibreMetaverse.Tests/RLV/Exceptions/EditExceptionTests.cs::EditExceptionTests.CanEdit_Specific::test db097167497bc650c6729f0687924adedda7097b4089107fc5ea03716c1cb4e5
// pending-parity-case: LibreMetaverse.Tests/RLV/Exceptions/EmoteExceptionTests.cs::EmoteExceptionTests.CanEmote::test a643401539d7258ae04ddebaf9c82876f59c4433b11ee61bfe8b416058c9fe38
// pending-parity-case: LibreMetaverse.Tests/RLV/Exceptions/RecvChatExceptionTests.cs::RecvChatExceptionTests.CanRecvChat_Except::test b34881785cf2df3d8f4e5ba971adcf2144d8de4db00acfbe136c79457742ec33
// pending-parity-case: LibreMetaverse.Tests/RLV/Exceptions/RecvEmoteExceptionTests.cs::RecvEmoteExceptionTests.CanRecvChat_RecvEmote_Except::test d4647d71c02e05405ae2acf7b58522aae559b1c90a4f7a1521c9a9a383220f8a
// pending-parity-case: LibreMetaverse.Tests/RLV/Exceptions/RecvImExceptionTests.cs::RecvImExceptionTests.CanReceiveIM_Exception::test 2e1afba517b29e8e7f2e0605340eb6e87443282857400eba259f0ebdf4874e23
// pending-parity-case: LibreMetaverse.Tests/RLV/Exceptions/RecvImExceptionTests.cs::RecvImExceptionTests.CanReceiveIM_Exception_SingleGroup::test 9ec57daeed225caf960d00f0c83378d1836e86b1896063703ee1c3a38c7b582a
// pending-parity-case: LibreMetaverse.Tests/RLV/Exceptions/RecvImExceptionTests.cs::RecvImExceptionTests.CanReceiveIM_Exception_AllGroups::test 633b8c680b583a6f8d80335c26f4ebcec77f9d8d5231e49bea562dcb66f00267
// pending-parity-case: LibreMetaverse.Tests/RLV/Exceptions/RedirChatExceptionTests.cs::RedirChatExceptionTests.IsRedirChat::test 1eb25c5579789db22ee242c4b52c65989bd26dce6d7577021c329c6c49be9414
// pending-parity-case: LibreMetaverse.Tests/RLV/Exceptions/RedirChatExceptionTests.cs::RedirChatExceptionTests.IsRedirChat_Removed::test 62e03ff1db1e790d8bc1e38ac1495fc12723ba2eb5c9d6035d73c9fdb91a44ad
// pending-parity-case: LibreMetaverse.Tests/RLV/Exceptions/RedirChatExceptionTests.cs::RedirChatExceptionTests.IsRedirChat_MultipleChannels::test c7d0c428d121ab80eee9b6b5855cbe50e7a4cd74e81c369da09df04d55c7554f
// pending-parity-case: LibreMetaverse.Tests/RLV/Exceptions/RedirChatExceptionTests.cs::RedirChatExceptionTests.IsRedirChat_RedirectChat::test c4a083e495a578c1ed0855c43680d5b05144bf627f06df48c82e089e6f0699bf
// pending-parity-case: LibreMetaverse.Tests/RLV/Exceptions/RedirChatExceptionTests.cs::RedirChatExceptionTests.IsRedirChat_RedirectChatMultiple::test 5ff8665440d8d02e0aa900121e591034d51e2b48ca62fdec2fbc9135f8c83428
// pending-parity-case: LibreMetaverse.Tests/RLV/Exceptions/RedirChatExceptionTests.cs::RedirChatExceptionTests.IsRedirChat_RedirectChatEmote::test 5d88009e3e8d365c52315a9b189f6cffdc9d04fdb70aa26bcc03d6bc16227189
// pending-parity-case: LibreMetaverse.Tests/RLV/Exceptions/RedirEmoteExceptionTests.cs::RedirEmoteExceptionTests.IsRedirEmote::test 02170a2b3eb0cbb88921517c9742d2fc0baaea7a621e5a3c3264a7a17d5efb61
// pending-parity-case: LibreMetaverse.Tests/RLV/Exceptions/RedirEmoteExceptionTests.cs::RedirEmoteExceptionTests.IsRedirEmote_Removed::test 6ee89cedfd1e2d79d2447f2f48d1e2d1ac96295485b7509fe09f98e3bfcd9766
// pending-parity-case: LibreMetaverse.Tests/RLV/Exceptions/RedirEmoteExceptionTests.cs::RedirEmoteExceptionTests.IsRedirEmote_MultipleChannels::test 1a95f4cc5db96cf033fed0c1a4e573b1cb1ac17ef72b76e0ce115c051f10528a
// pending-parity-case: LibreMetaverse.Tests/RLV/Exceptions/RedirEmoteExceptionTests.cs::RedirEmoteExceptionTests.IsRedirEmote_RedirectEmote::test 525297be5b5ff466fc9a61f2bc87af38bd637cbef8e0c794e897e021d0cca464
// pending-parity-case: LibreMetaverse.Tests/RLV/Exceptions/RedirEmoteExceptionTests.cs::RedirEmoteExceptionTests.IsRedirEmote_RedirectEmoteMultiple::test fd6af49a90e111ed6424c85565242e1205e13604b529909f7be0260e93f0b1c6
// pending-parity-case: LibreMetaverse.Tests/RLV/Exceptions/RedirEmoteExceptionTests.cs::RedirEmoteExceptionTests.IsRedirEmote_RedirectEmoteChat::test e8b78a6a34e3d3acdfc6d454b46a939d341260362ae5327dc4b70164d41431aa
// pending-parity-case: LibreMetaverse.Tests/RLV/Exceptions/SendChannelExceptExceptionTests.cs::SendChannelExceptExceptionTests.CanSendChannelExcept::test 08c309d08681fe067f67315a72014d0a05c87d6e14632fa04f6f2fb617d61be3
// pending-parity-case: LibreMetaverse.Tests/RLV/Exceptions/SendChannelExceptionTests.cs::SendChannelExceptionTests.CanSendChannel_Exception::test 49bcacb6fb31d596ce9afc73099f8aaf645156ee222262174e1d7fed08393cf9
// pending-parity-case: LibreMetaverse.Tests/RLV/Exceptions/SendImExceptionTests.cs::SendImExceptionTests.CanSendIM_Exception::test 8124011921e8d4caf6840e960bd9f98d21df9db476e1726e0d54550cb8527ceb
// pending-parity-case: LibreMetaverse.Tests/RLV/Exceptions/SendImExceptionTests.cs::SendImExceptionTests.CanSendIM_Exception_SingleGroup::test b55a4bdba1d33652f3809c3478047afc65757fbe1dec6c5292e17b71a04b206c
// pending-parity-case: LibreMetaverse.Tests/RLV/Exceptions/SendImExceptionTests.cs::SendImExceptionTests.CanSendIM_Exception_AllGroups::test 4190ff51848f63dce5682317db79da23fa19ad9e53004534382f3eb6e8544788
// pending-parity-case: LibreMetaverse.Tests/RLV/Exceptions/ShareExceptionTests.cs::ShareExceptionTests.CanShare_Except::test 37297059a814bfde94c466e263a429258cce11ae258afd7953d26f65f9178f1d
// pending-parity-case: LibreMetaverse.Tests/RLV/Exceptions/ShowNameTagsExceptionTests.cs::ShowNameTagsExceptionTests.CanShowNameTags_Except::test 5d1fe4ec1fa289623d473ffae1682ed725735cbdf48bdf5b7fed086237e32a1a
// pending-parity-case: LibreMetaverse.Tests/RLV/Exceptions/ShowNamesExceptionTests.cs::ShowNamesExceptionTests.CanShowNames_Except::test b11578e758631037440dd56a683a3ffc25b576eaa25e7388c950d8d647eb2a75
// pending-parity-case: LibreMetaverse.Tests/RLV/Exceptions/StartImExceptionTests.cs::StartImExceptionTests.CanStartIM_Exception::test e0001ffc665f0f39833cf2376ea1fcb7559bdb87a48ea60bb348e14b078880e4
// pending-parity-case: LibreMetaverse.Tests/RLV/Exceptions/TouchMeExceptionTests.cs::TouchMeExceptionTests.TouchMe_default::test a0f3ffd3c70263738c074e258d9271e0a825f163c40d9c7ee8d20865873eb304
// pending-parity-case: LibreMetaverse.Tests/RLV/Exceptions/TouchThisExceptionTests.cs::TouchThisExceptionTests.TouchThis_default::test e7e6c9e14badb0159f81adc96e17fcf3ebe2cf5351ec6465f03c430de06d85d2
// pending-parity-case: LibreMetaverse.Tests/RLV/Exceptions/TouchWorldExceptionTests.cs::TouchWorldExceptionTests.TouchWorld_Exception::test ffef2f112b5718bab7b01fc1b624e588c181dadc5c50fd85de4404a501ee6f37
// pending-parity-case: LibreMetaverse.Tests/RLV/Exceptions/TpLureExceptionTests.cs::TpLureExceptionTests.CanTpLure_Except::test a32f4cdda5b48ffcaced683b2e77fc129c1c321951aa2e16623eea022f2aa0b9
// pending-parity-case: LibreMetaverse.Tests/RLV/InventoryMapTests.cs::InventoryMapTests.TryGetFolderFromPath_Normal::test 97787ac6b51198e317ed391e91125724ce1b580924c40500f81186812b45f625
// pending-parity-case: LibreMetaverse.Tests/RLV/InventoryMapTests.cs::InventoryMapTests.TryGetFolderFromPath_EmptyPath::test 0ffd4f32e285ba94e94f63ac312d3be20bf144b769e8d18af32e15f481042ed7
// pending-parity-case: LibreMetaverse.Tests/RLV/InventoryMapTests.cs::InventoryMapTests.TryGetFolderFromPath_FolderNameContainsForwardSlash::test 90ae520739ea1a2612f491bb110b0870ed4dcb8a983aad9526ed25d8c5cbe687
// pending-parity-case: LibreMetaverse.Tests/RLV/InventoryMapTests.cs::InventoryMapTests.TryGetFolderFromPath_FolderNameContainsForwardSlashes::test 8c0ed3c6cc16b916f9df8d25d55618e82299fd1bcd66983f682219c338853028
// pending-parity-case: LibreMetaverse.Tests/RLV/InventoryMapTests.cs::InventoryMapTests.TryGetFolderFromPath_FolderNameWithSlashPrefix::test 8a86081d6b25ae50b3cf8cdcb1c58c8539264931ab74f395dfc7345ee7f4f861
// pending-parity-case: LibreMetaverse.Tests/RLV/InventoryMapTests.cs::InventoryMapTests.TryGetFolderFromPath_FolderNameWithSlashSuffix::test 04afafa569b7a10d6add8c1e9d8f26ac502791f1da2dbdb3e37407e945c87872
// pending-parity-case: LibreMetaverse.Tests/RLV/InventoryMapTests.cs::InventoryMapTests.TryGetFolderFromPath_FolderNameWithSlashAffix::test 7eaec38fa6b545f133748b502169fab575308c9c4e60548cfbfd704452bd9761
// pending-parity-case: LibreMetaverse.Tests/RLV/InventoryMapTests.cs::InventoryMapTests.TryGetFolderFromPath_ContendingFoldersWithSlashes::test 96a8189266746a564072122342f36b3321998f3e0cbe0094f3e4c83d29bc53d5
// pending-parity-case: LibreMetaverse.Tests/RLV/InventoryMapTests.cs::InventoryMapTests.TryGetFolderFromPath_InvalidPath::test 547def910ded67bc7950b211ad929f775d4eff26e351d11612f146b3e863510e
// pending-parity-case: LibreMetaverse.Tests/RLV/InventoryMapTests.cs::InventoryMapTests.TryGetFolderFromPath_IgnoreFolderPrefix::test 5039b79496d215d3921427ab6f65867ba7a4ea5239864f1f5a1e38ea3e5bb426
// pending-parity-case: LibreMetaverse.Tests/RLV/InventoryMapTests.cs::InventoryMapTests.TryGetFolderFromPath_FailOnHiddenFolder::test bb0c7e531584128d251b06a4ac23b8cfad16ec4b117be79a53dea3c54aed4510
// pending-parity-case: LibreMetaverse.Tests/RLV/InventoryMapTests.cs::InventoryMapTests.TryGetFolderFromPath_AllowHiddenFolder::test 9217cb5bd9c325fc792303e5ab53cefd71e95a5acf9e5a1601957ba8bf807346
// pending-parity-case: LibreMetaverse.Tests/RLV/InventoryMapTests.cs::InventoryMapTests.FindFoldersContaining_ById::test fc89036c3472dcc2ea4d3fcb55636238e3d2c75b490f46d328b5f91f28301ed0
// pending-parity-case: LibreMetaverse.Tests/RLV/InventoryMapTests.cs::InventoryMapTests.FindFoldersContaining_ByAttachmentType::test 90b36c29312b87c824c158987e551ca31522cf53a68f5f6bd3eae8fe03e914ed
// pending-parity-case: LibreMetaverse.Tests/RLV/InventoryMapTests.cs::InventoryMapTests.FindFoldersContaining_ByAttachmentType_SingleResult::test a973bf8087abb0c68cd80d76949fac2735474bf6ccbe743933051f60527d93ce
// pending-parity-case: LibreMetaverse.Tests/RLV/InventoryMapTests.cs::InventoryMapTests.FindFoldersContaining_ByWearType::test d6712cbeacd6ddf25a1f76dc1eeb10f4c0d8967a7591c249127f9b6387f0df8a
// pending-parity-case: LibreMetaverse.Tests/RLV/PermissionsTests.cs::PermissionsTests.CamZoomMin_Default::test 662b332d66c72caecc1a179730bc2524b9da16aa85f7289bebd31842610ceccc
// pending-parity-case: LibreMetaverse.Tests/RLV/PermissionsTests.cs::PermissionsTests.CanShowHoverTextWorld_Default::test 380d1e30bd9ded04329bfd6d65ba447a8dd45a934cfa875628253719bb0e69ce
// pending-parity-case: LibreMetaverse.Tests/RLV/PermissionsTests.cs::PermissionsTests.CanShowHoverTextHud_Default::test a0af1f72f417cfa451284b7a3dbbb26d378e7eb9896dde3b6df0d0a2e4773f38
// pending-parity-case: LibreMetaverse.Tests/RLV/PermissionsTests.cs::PermissionsTests.CanShowHoverText_Default::test c4122dbf650f51bde55dfda412a884347a78d3cd09dd2bb0fcbe4a7e74a1fff6
// pending-parity-case: LibreMetaverse.Tests/RLV/PermissionsTests.cs::PermissionsTests.CanShowHoverTextAll_Default::test 0ed67c5566d038f770eb9f5df6aa0b5394d7d94cf7c397fa8089b419f872c681
// pending-parity-case: LibreMetaverse.Tests/RLV/PermissionsTests.cs::PermissionsTests.CanShowNameTags_Default::test 0781be94eb099d9aed1be2ff313856770d1ec24047d04c81c69219c743b4c8cb
// pending-parity-case: LibreMetaverse.Tests/RLV/PermissionsTests.cs::PermissionsTests.CanShare_Default::test e827d549d1d9329b63db159446937735ead13eed5d3eaa59440d3c686182f517
// pending-parity-case: LibreMetaverse.Tests/RLV/PermissionsTests.cs::PermissionsTests.CanShowNames_Default::test 56492cdd0802c5f8ed2a0f6d56abaf8186e37dd7b888904db52be97f9137279a
// pending-parity-case: LibreMetaverse.Tests/RLV/PermissionsTests.cs::PermissionsTests.CanEdit_Default::test 417fb9f3eb3e70f3bd33710d11fb25eacd0db0a365b0ed2dec6778d09968f44b
// pending-parity-case: LibreMetaverse.Tests/RLV/PermissionsTests.cs::PermissionsTests.CanRecvChat_Default::test b1ec48da83249b1141c3af926cd494373c47214d6a145916a8833d49edd155e2
// pending-parity-case: LibreMetaverse.Tests/RLV/PermissionsTests.cs::PermissionsTests.CanAutoAcceptTpRequest_Default::test abbcccb4415afdb6558f40a6d4030704f64442f019d065fef8a7a56a407e8642
// pending-parity-case: LibreMetaverse.Tests/RLV/PermissionsTests.cs::PermissionsTests.CanTpRequest_Default::test aefc51023a5274d402dae0e8111a0776622dc431754c3d1f0ce240a50dfd405d
// pending-parity-case: LibreMetaverse.Tests/RLV/PermissionsTests.cs::PermissionsTests.CanAutoAcceptTp_Default::test 553245a5381689a7f1c6398cb0ca50510f9089b9bdc797672ae35fb5822fdf8e
// pending-parity-case: LibreMetaverse.Tests/RLV/PermissionsTests.cs::PermissionsTests.CanChat_Default::test a9b0e4f8713991ce8b9b61d750c086d56da432dbddd533ec63dc0604238831a1
// pending-parity-case: LibreMetaverse.Tests/RLV/PermissionsTests.cs::PermissionsTests.CanSendIM_Default::test 6cc5238ded59b80408c59c9e77ded1162e370c295b846903dbcc87f74175cd55
// pending-parity-case: LibreMetaverse.Tests/RLV/PermissionsTests.cs::PermissionsTests.CanStartIM_Default::test c6d6db79b0939b33eb5fd29490474575e062f796160f4a69aab34ccefc1842cb
// pending-parity-case: LibreMetaverse.Tests/RLV/PermissionsTests.cs::PermissionsTests.CanReceiveIM_Default::test 23c1c79ae9eba016a48f3e9097fc26283223c9e120308d93fe53ce591ee5691c
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/FindFolderQueryTests.cs::FindFolderQueryTests.FindFolder_MultipleTerms::test a1f04e5ab064772c25feefc21ea57d65b1044f0fa3254aeb2a3bfedf68d8e0ca
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/FindFolderQueryTests.cs::FindFolderQueryTests.FindFolder_SearchOrder::test 4cba32dd316f49713c18a71bf5a932e1c28c94944add38c25852e8611ef0f987
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/FindFolderQueryTests.cs::FindFolderQueryTests.FindFolder_IgnorePrivate::test 54c5ec1f6a6ae5611221e3afdc47db0c2d0ecb0da460dd8f2c506ed34c221ff8
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/FindFolderQueryTests.cs::FindFolderQueryTests.FindFolder_IgnoreTildePrefix::test 9f6635f5e14dbc14d1592a19b62d67748a60201128a75893e47ea1751c83b6d7
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/FindFoldersQueryTests.cs::FindFoldersQueryTests.FindFolders::test 09dbc17be4b28cc4a63d0f837960586ba7cd03e184f0013b26ed27db15703d84
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/FindFoldersQueryTests.cs::FindFoldersQueryTests.FindFolders_Separator::test 51caa783dded41b99c878066618a10a7fe32c681ef4385c9a72f154870312b1f
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/GetAttachQueryTests.cs::GetAttachQueryTests.GetAttach_WearingNothing::test 41fc967c6c174ac39ce3f6de7e273e6db1845bc2ad6acd393f27a6705a3555df
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/GetAttachQueryTests.cs::GetAttachQueryTests.GetAttach_ExternalItems::test 3f8e640aad5deeaf00b07af2d12c33b0a93257260d057d7b5dd5488f846f467a
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/GetAttachQueryTests.cs::GetAttachQueryTests.GetAttach_WearingSomeItems::test c209cd826958306f1350a685b29985cb8335a55ebcb9c0bec5c5a21279bb0a1a
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/GetAttachQueryTests.cs::GetAttachQueryTests.GetAttach_WearingEverything::test 4adb25030cd3c125242a4b1f770bfd3afdcabd85c23d37c34df9c8f273489e5b
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/GetAttachQueryTests.cs::GetAttachQueryTests.GetAttach_Specific_Exists::test 7d8ccf26629911b6b20dc26c5c549975827d7378b4d85259a8b9724a3622892b
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/GetAttachQueryTests.cs::GetAttachQueryTests.GetAttach_Specific_NotExists::test 08d9852205987a266608ad17c12fa498894d7c3216e873cffb9db4584cfd100d
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/GetBlacklistQueryTests.cs::GetBlacklistQueryTests.GetBlacklist::case:8e1b820c1f2bd3cd 3faf1c80c07da463d139f13d4ed9deba67b160a29d3001437f2e2794940a7765
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/GetBlacklistQueryTests.cs::GetBlacklistQueryTests.GetBlacklist::case:64136cd82156035a 3faf1c80c07da463d139f13d4ed9deba67b160a29d3001437f2e2794940a7765
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/GetBlacklistQueryTests.cs::GetBlacklistQueryTests.GetBlacklist::case:2068bf7f0a131fe8 3faf1c80c07da463d139f13d4ed9deba67b160a29d3001437f2e2794940a7765
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/GetBlacklistQueryTests.cs::GetBlacklistQueryTests.GetBlacklist::case:b86b0c5e67f981c2 3faf1c80c07da463d139f13d4ed9deba67b160a29d3001437f2e2794940a7765
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/GetBlacklistQueryTests.cs::GetBlacklistQueryTests.GetBlacklist::case:123b930bb970a1f1 3faf1c80c07da463d139f13d4ed9deba67b160a29d3001437f2e2794940a7765
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/GetBlacklistQueryTests.cs::GetBlacklistQueryTests.ManualBlacklist::case:f14641dea0f1de93 4ef9ab9bc3165b99ef6b9cf6ae563210660e83fccf946376217c300a752c724e
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/GetBlacklistQueryTests.cs::GetBlacklistQueryTests.ManualBlacklist::case:d25c660357f6ccff 4ef9ab9bc3165b99ef6b9cf6ae563210660e83fccf946376217c300a752c724e
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/GetDebugQueryTests.cs::GetDebugQueryTests.GetDebug_Default::case:fa77559e30768d15 6554db3b0455887c0224a6f91c7830d6cbf38d5520a65a9b17e26280fcc291f7
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/GetDebugQueryTests.cs::GetDebugQueryTests.GetDebug_Default::case:55694f25ed879d95 6554db3b0455887c0224a6f91c7830d6cbf38d5520a65a9b17e26280fcc291f7
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/GetEnvQueryTests.cs::GetEnvQueryTests.GetEnv_Default::case:f656b648d00a6d91 cf4270c6c3417690afcf43982c3bdcf815f46ce81f9b6ccaf59377c633a64881
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/GetEnvQueryTests.cs::GetEnvQueryTests.GetEnv_Default::case:55694f25ed879d95 cf4270c6c3417690afcf43982c3bdcf815f46ce81f9b6ccaf59377c633a64881
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/GetGroupQueryTests.cs::GetGroupQueryTests.GetGroup_Default::test da65b184d0ef1380274e8e4dfa199c125a1a192b9e76f8fec1d406df18186169
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/GetGroupQueryTests.cs::GetGroupQueryTests.GetGroup_NoGroup::test d1da37ae52bd94dac9cd6e031525b57f31ca7e9dc00a69a6e0c4e753741dc9e8
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/GetInvQueryTests.cs::GetInvQueryTests.GetInv::test 7476602b4103b47ed7dff44146a7ba90a1d62dc0d502f7b9e37b7863d9441ceb
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/GetInvQueryTests.cs::GetInvQueryTests.GetInv_Outfits::test d60a78bb35cc8fcdbdc2465889333b25567ea5e1c9279a8fb7b4162f4a35eae2
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/GetInvQueryTests.cs::GetInvQueryTests.GetInv_Outfits_IgnoreLeadingSlash::test add33ed33e1940f26362332b89486253c6af1a56e601bafab49511b6607ed50a
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/GetInvQueryTests.cs::GetInvQueryTests.GetInv_Outfits_IgnoreTrailingSlash::test 8f89302126be19f89d075d87d5194cc000fb7819f92ea7d54e6a63c1df9ca1ee
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/GetInvQueryTests.cs::GetInvQueryTests.GetInv_Outfits_IgnoreLeadingAndTrailingSlash::test c660447f93fb8508dbe4c874c92fd776a6e13596bbe3036bfb4664e35ee22306
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/GetInvQueryTests.cs::GetInvQueryTests.GetInv_Outfits_Inventory::test 7db6f75e2f109d0e8d852d181ddd721f688e27144ad8a5604384b37de9f8c3eb
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/GetInvQueryTests.cs::GetInvQueryTests.GetInv_Subfolder::test 6a5effe8012e9a446021b83f9b5314f6f9b66587222b447fa79028582830b3a1
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/GetInvQueryTests.cs::GetInvQueryTests.GetInv_Empty::test 2dd9f242eb71826066482ff4faa80b952ef89f855723cdc0c01cc4714abf8751
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/GetInvQueryTests.cs::GetInvQueryTests.GetInv_Invalid::test 92595df155e79568e70bceb1538c23f10de99a6a138a0a5d9b8a2626588fdae9
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/GetInvWornQueryTests.cs::GetInvWornQueryTests.GetInvWorn::test 472d70fb14f393d43f8698bb81d1855426f570d85c9e592fa86607eb79ce366e
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/GetInvWornQueryTests.cs::GetInvWornQueryTests.GetInvWorn_PartialRoot::test ce4c640a901a6684a27b2b259c4fc3b25f2d6b870107babff3b930ced64a150b
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/GetInvWornQueryTests.cs::GetInvWornQueryTests.GetInvWorn_Naked::test fa8994189c5d9cda7d613dfb8f6ffbb1808c8bae54a3647530fb872d47c43dd5
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/GetInvWornQueryTests.cs::GetInvWornQueryTests.GetInvWorn_EmptyFolder::test ab6fc753f4d4170e17f49b708d7e62816f197e83234feda1fdcf63dcdc0bc6c4
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/GetInvWornQueryTests.cs::GetInvWornQueryTests.GetInvWorn_PartialWorn::test ceb446f2aa6eaa5232a99147d5d993386ee9e2e5fefd93ef582f27a6b8ece948
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/GetOutfitQueryTests.cs::GetOutfitQueryTests.GetOutfit_WearingNothing::test 27befef9fdef993d82a641980f2b1ad7f458f07a50c7d008b6d311aeedfb4939
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/GetOutfitQueryTests.cs::GetOutfitQueryTests.GetOutfit_ExternalItems::test f88d149572ae35e880f16a5a92b4a9db73a3f26c5e8e61e4b1c01440151bd64b
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/GetOutfitQueryTests.cs::GetOutfitQueryTests.GetOutfit_WearingSomeItems::test 4e9ef77ab72f1fd16c4fad69f00eb80ab46421597d41b61df80b1f87370f42d3
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/GetOutfitQueryTests.cs::GetOutfitQueryTests.GetOutfit_WearingEverything::test a840b239174cdb5dee4beb875bf9129209af3ba310564319528ad5b19764aae0
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/GetOutfitQueryTests.cs::GetOutfitQueryTests.GetOutfit_Specific_Exists::test a402fd67ed8ddfc12d09863f08f9b15b34262ffa12b4b5aa965826eac89abae5
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/GetOutfitQueryTests.cs::GetOutfitQueryTests.GetOutfit_Specific_NotExists::test d7e891a620b5e5407fe337f507874b63eb5a21589767a01362bd8bc43d19ba4a
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/GetPathNewQueryTests.cs::GetPathNewQueryTests.GetPathNew_BySender::test e7e87c01e83967a7160509d76f49d2a4b18d34b9b3fbed370c174d64ddb2c2b5
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/GetPathNewQueryTests.cs::GetPathNewQueryTests.GetPathNew_ByUUID::test 3a7d242966286258ed075c8e5c69eaf54ba0e71b8607432615a1199f5aeb6dcf
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/GetPathNewQueryTests.cs::GetPathNewQueryTests.GetPathNew_ByUUID_Unknown::test c3c206661594026c36dfcfea110631548cd362d824db268c170e4d04b24b674a
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/GetPathNewQueryTests.cs::GetPathNewQueryTests.GetPathNew_ByAttach::test f8858e6141b660cec8a09c016891f2275dd9364157b1aa614b63fca5abb7620c
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/GetPathNewQueryTests.cs::GetPathNewQueryTests.GetPathNew_ByWorn::test eed31d9aaf34578368cc4f590de1da7f47e3f6c5e663215866f7f8e6946f974b
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/GetSitIdQueryTests.cs::GetSitIdQueryTests.GetSitID::test bfbf6d62c09c4878504aa529805a29fe9689d1e29e7ca3d44bf2346d6b3fbe6b
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/GetSitIdQueryTests.cs::GetSitIdQueryTests.GetSitID_Default::test 456f8f22b1d2917c3729ed600bdf0b693c0189bd100b9863f4b42b07259110b0
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/GetStatusAllQueryTests.cs::GetStatusAllQueryTests.GetStatusAll::test ee8fac8485db2b5c01abf8664364ca1e13214243f1e661a04d93df680422d596
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/GetStatusQueryTests.cs::GetStatusQueryTests.GetStatus::test c538e68277e93b40374dfd86bde9be00e0b82dfad7f4573cc4b0660f15fa5fe4
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/GetStatusQueryTests.cs::GetStatusQueryTests.GetStatus_filtered::test 574b7f7c37b4e09e4257e5b02d50b222054216e34b6d1dd3fe6b26127c89b562
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/GetStatusQueryTests.cs::GetStatusQueryTests.GetStatus_customSeparator::test 3bec2e53ea88857d4a1ae8cd6bc6f235f24e00d0773c24ca75a1892adb803527
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.Notify::test 082ff4cd00faf29a73aca158d4e24ed9fd3e7844ed6cefbf962d8727846a3c27
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifyFiltered::test e00e51aeadd0d7a107105684129a6ae74fbf918be4c563d92d7cdaa223d2c03c
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifyMultiCommand::test 77f3950214a1bd1e3816fa6f7b0ca69727e9e18be5fb7b37f19490408ca023dc
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifyMultiChannels::test 12a0a6e0a0a6632960de98236670e063f2c1aa16cf6b6c8d718bde0e0abfd9b9
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifyMultiChannelsFiltered::test bff8ca8465c2299d0d2ef60adfa4164270d08cee7223361bb27b86a7e4daeec9
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifySynonyms::case:9e893d263294d04d 6cf84f004648f8b5304bf7fc7fab7ac8b1f8f7da8c605c06daa68d3a1280cd67
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifySynonyms::case:fc6b17eb4e9e7a00 6cf84f004648f8b5304bf7fc7fab7ac8b1f8f7da8c605c06daa68d3a1280cd67
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifySynonyms::case:b37376c5865a6fe8 6cf84f004648f8b5304bf7fc7fab7ac8b1f8f7da8c605c06daa68d3a1280cd67
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifySynonyms::case:5d497faea315b624 6cf84f004648f8b5304bf7fc7fab7ac8b1f8f7da8c605c06daa68d3a1280cd67
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifySynonyms::case:282fa0139ccbba29 6cf84f004648f8b5304bf7fc7fab7ac8b1f8f7da8c605c06daa68d3a1280cd67
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifySynonyms::case:f08c6eb7b4d12fac 6cf84f004648f8b5304bf7fc7fab7ac8b1f8f7da8c605c06daa68d3a1280cd67
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifySynonyms::case:37f0f73ed7492dd0 6cf84f004648f8b5304bf7fc7fab7ac8b1f8f7da8c605c06daa68d3a1280cd67
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifySynonyms::case:d75917941e63732c 6cf84f004648f8b5304bf7fc7fab7ac8b1f8f7da8c605c06daa68d3a1280cd67
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifySynonyms::case:2f72da33fdbcd8be 6cf84f004648f8b5304bf7fc7fab7ac8b1f8f7da8c605c06daa68d3a1280cd67
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifyClear_Filtered::test f3e0550a53faca13679421318eee85f010c1b8668e3edfae6e2548d39dbcafd7
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifyClear::test 61d7419956a83be04eeb13557c6a2120419b2f0f1c529149c4fb57871bb6506e
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifyInventoryOffer::test 2bbac63ab86ec77f6d0a4558a14ee913a7f44930364476a89e02cd5ec80191b9
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifySitStandLegal::test 83a07a88a0386982c854a0223b64dd5c417f1a55a038e4ceba8f487983daadaf
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifySitStandWithRestrictions::test 166e2087aa0652bdd427e1908bc338659ec1d4dc8065c016612696d1f5dfd000
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifyWear::test 9529acb9f3e1c335a50f8de6d63cc5711921de962546ff868811279d05826399
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifyWear_Illegal::test 65bfc1db698470cf56dd8c6811e85ae373d1fca95cdbf82be66b7e32da311a2f
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifyUnWear::test 340b60b8038dcd55320dc9aedc16beb9193e731ba7b659ca3cb2951a2d19b7ac
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifyUnWear_illegal::test e7056e6e145430eb2180edb92593f59c07bcbdfa21629b1ca29ac93b2fca975e
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifyAttached::test dc5239c77b9169cf3833c5a1dc765b381efe833f15b34ac7e57173c0a640942a
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifyAttached_Illegal::test b56de057dece9cb8ece795d13d6bc42e7825d62f09f967f37a4dbf262d2b4456
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifyDetached::test a741cec23a985028b3dc2b09195255276a96e4f07fc4fe5f8cca6c1e3c940d71
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifyDetached_Illegal::test 1a4c9475a3b91a975b9861685dcaf899505b4f6727257618f9add9cecd3df54d
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/VersionNumBlQueryTests.cs::VersionNumBlQueryTests.VersionNumBL::case:478968a5d14830de 0dbc89f77a6f293efcca217febb2f6b8d224f9ac5e1d6532a56a7df64a7be6e9
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/VersionNumBlQueryTests.cs::VersionNumBlQueryTests.VersionNumBL::case:8c124ee42e9ab944 0dbc89f77a6f293efcca217febb2f6b8d224f9ac5e1d6532a56a7df64a7be6e9
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/VersionQueryTests.cs::VersionQueryTests.ManualVersion::test 6f8493b201d69e1449d8311e434736f6f6b2bad04c9fe9c6adf94a94d9cbe597
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/VersionQueryTests.cs::VersionQueryTests.CheckVersions::case:442bdc765ad34e20 f8118590cf64832f30e5e3c927bf8cee42c90d82a3e275554e9c36adb7ad5d30
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/VersionQueryTests.cs::VersionQueryTests.CheckVersions::case:968af293ea2a53a1 f8118590cf64832f30e5e3c927bf8cee42c90d82a3e275554e9c36adb7ad5d30
// pending-parity-case: LibreMetaverse.Tests/RLV/Queries/VersionQueryTests.cs::VersionQueryTests.CheckVersions::case:ae9a221915e6e1bb f8118590cf64832f30e5e3c927bf8cee42c90d82a3e275554e9c36adb7ad5d30
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/AddAttachRestrictionTests.cs::AddAttachRestrictionTests.AddAttach::test bb2c3495d7b6862fabe1007bcfccc2850d29eef1d9aa4eac6d13d6004dcc4e6b
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/AddAttachRestrictionTests.cs::AddAttachRestrictionTests.AddAttach_Specific::test 0201965931ebba1c13a23bbb43a8787c1639b0b98851141faffd963173c51035
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/AddOutfitRestrictionTests.cs::AddOutfitRestrictionTests.AddOutfit::test d4902b4dda0a640d240c88af30431f6d247aae2a74a81126fd91ba1d930de3fb
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/AddOutfitRestrictionTests.cs::AddOutfitRestrictionTests.AddOutfit_part::test e7e5467b36484fb54b0336abccf682905fbe5bff9e04195645981815e2ffadeb
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/AllowIdleRestrictionTests.cs::AllowIdleRestrictionTests.CanAllowIdle::test 6278bb1a70f024f687080cb8e8a56bbc923f679fb4adb61c6c91c3397a3de7fc
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/AlwaysRunRestrictionTests.cs::AlwaysRunRestrictionTests.CanAlwaysRun::test 9c0a34e0960e3e2a834ccfc1c129a1f5a8f8c6cfd30b322671b4e5c4cd25a24c
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/AttachAllThisRestrictionTests.cs::AttachAllThisRestrictionTests.AttachAllThis::test 39bc0c4581f8277f4d5c90ec715c40f4715b5ae7007a28a04fe762f2f6adfbfd
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/AttachAllThisRestrictionTests.cs::AttachAllThisRestrictionTests.AttachAllThis_Recursive::test d051e7783e79bf91a8092cd2d29cf1aacec3b0af86ecf0c7ca590ce25bc8393c
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/AttachAllThisRestrictionTests.cs::AttachAllThisRestrictionTests.AttachAllThis_Recursive_Path::test b4db2b29ad376777b382f8c6f4f7b62643bb2dd43858de4be69ac2252f18c963
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/AttachAllThisRestrictionTests.cs::AttachAllThisRestrictionTests.AttachAllThis_Recursive_Worn::test 6ecfc6ffe71896979a37dac6dd8149a015b8d3e7e952247954333c053da4961e
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/AttachAllThisRestrictionTests.cs::AttachAllThisRestrictionTests.AttachAllThis_Recursive_Attached::test 8ac38c77c6bdb03e4cbaa96600bead9a760eb5eec098504b05cfb3a1bdfb8557
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/AttachAllThisRestrictionTests.cs::AttachAllThisRestrictionTests.AttachAllThis_Recursive_Attached_AddRem::test 495f288e0fa86059d13a027075700ba6308e9c9d585fa56e3d1adf4a71df912b
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/AttachThisRestrictionTests.cs::AttachThisRestrictionTests.AttachThis::test 3a8a5acc4ad5cbec76737239ea23330a34f54146a4ff9d5d25082c220527a3e4
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/AttachThisRestrictionTests.cs::AttachThisRestrictionTests.AttachThis_NotRecursive::test a5818b4e30d04aba7d6427b2b94e025d34e82eb3bdcb7ac80a23e55f2382ec29
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/AttachThisRestrictionTests.cs::AttachThisRestrictionTests.AttachThis_ByPath::test 93e1721f171e24e540160e738f731b895ebd868d840bcdf7c16ba92f6eb4c49a
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/AttachThisRestrictionTests.cs::AttachThisRestrictionTests.AttachThis_ByRlvAttachmentPoint::test 90a562b2c120daa0ea2612befe9e09649bc2ffac59c2cd360fe4a37dedf85ae3
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/AttachThisRestrictionTests.cs::AttachThisRestrictionTests.AttachThis_ByWornLayer::test a444d51c2091fa36f1a010e98ad896042aa0262153ea8a833a14dfcbf02de85e
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/AttachThisRestrictionTests.cs::AttachThisRestrictionTests.AttachThis_ByWornLayer_AddRem::test dd3d9a0d9b56f08f6be7a6200e1f50e834ecc7613de0cdf44ee89262b3abdb30
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/ChatNormalTests.cs::ChatNormalTests.CanChatNormal::test 9a23c49327636e769c7ff2688a0649d441f3531406e8f51e152ec7186a312287
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/ChatShoutRestrictionTests.cs::ChatShoutRestrictionTests.CanChatShout::test 493e1dd87afaaa7f8183e677df5c32d00f150ffcdd53f9afad8684672837aa28
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/ChatWhisperRestrictionTests.cs::ChatWhisperRestrictionTests.CanChatWhisper::test 67c5d2cb8b3e9424fbcf08378c2a28368fe07aa83ec028df7cf88b91576d3e9f
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/DefaultWearRestrictionTests.cs::DefaultWearRestrictionTests.CanDefaultWear::test 64eef4c82d1c5a21bc923cfd44616ddc1a5e6403a9a1c5ad6bd2e5ee06e9704c
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/DetachAllThisRestrictionTests.cs::DetachAllThisRestrictionTests.DetachAllThis::test ee74f952bd602bd23cfc7b203940a902e1b30e02cff60c1abc1f74da964c1f7d
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/DetachAllThisRestrictionTests.cs::DetachAllThisRestrictionTests.DetachAllThis_Recursive::test 2b6a646ee82484a6d1901ea4425b0e32fe553827f5bea37b506ffe29d1aec192
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/DetachAllThisRestrictionTests.cs::DetachAllThisRestrictionTests.DetachAllThis_Recursive_Path::test 731244b623f23a8870d011280a062add751607ce2c58be3261485bb61d488297
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/DetachAllThisRestrictionTests.cs::DetachAllThisRestrictionTests.DetachAllThis_Recursive_Worn::test d8424a48e64346edd683b7a68652dd5a0be615658f085b0390699ac7b4db5d2c
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/DetachAllThisRestrictionTests.cs::DetachAllThisRestrictionTests.DetachAllThis_Recursive_Attached::test f399592217e7a4638ea25d469681ab9cc58bf8a937af2bfff8895996f7bbc493
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/DetachAllThisRestrictionTests.cs::DetachAllThisRestrictionTests.DetachAllThis_Recursive_Attached_AddRem::test 507273250b932ff93fa34f87190ad1ab289edeed275be6d2259bab05c5b055d1
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/DetachRestrictionTests.cs::DetachRestrictionTests.Detach_Default::test 8c5b165329ab6b46eb3ec7c9a07383e8ea1e54edf0882b43b14166d67cc45617
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/DetachRestrictionTests.cs::DetachRestrictionTests.Detach::test 50f5419aea3ea41aa9ebedd29202a549deb4ae6089c38965300a46fd5abf94bf
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/DetachRestrictionTests.cs::DetachRestrictionTests.Detach_AttachPoint::test a75fea134b92bca704b2e140135076d699d645c0d2854022d5b20d14be372589
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/DetachThisRestrictionTests.cs::DetachThisRestrictionTests.DetachThis::test bf6cdb48a5271d5116db4d0cbf12dbf63fc3cc93862bf718cf849d4abf9eb7cc
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/DetachThisRestrictionTests.cs::DetachThisRestrictionTests.DetachThis_NotRecursive::test a8452e2b0abcf82447394bae981a1d25677147fad17828d8f6d0705264efa429
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/DetachThisRestrictionTests.cs::DetachThisRestrictionTests.DetachThis_ByPath::test e6378e0db310005b8426cabd25969818ed36252e1995de97c6b29d5ab155ee58
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/DetachThisRestrictionTests.cs::DetachThisRestrictionTests.DetachThis_ByRlvAttachmentPoint::test 278e4cbf0f9999efec04fcabade19da97439cca732e0e7e3e3c004e232c27224
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/DetachThisRestrictionTests.cs::DetachThisRestrictionTests.DetachThis_ByWornLayer::test 66b7eba54e34ed58c59d594cdcb85d874c4db9bbbd871e5438c40fd3d47ad3f6
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/DetachThisRestrictionTests.cs::DetachThisRestrictionTests.DetachThis_ByWornLayer_AddRem::test 7424bf38db1abd74132618ee3bcf95a79c32942da26086760dc82355a815d37e
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/EditAttachRestrictionTests.cs::EditAttachRestrictionTests.CanEdit_Attachment::test 22bc9e267e270c2c762561851249af4ef64c0b5bd288950a95b1b636b2975b6e
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/EditRestrictionTests.cs::EditRestrictionTests.CanEditFolderNameSpecifiesToAddInsteadOfReplace::test 6d82d0869826bbc935d89967445dfc991619bdaf3fa631550c5d3f91a13c4935
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/EditWorldRestrictionTests.cs::EditWorldRestrictionTests.CanEdit_World::test 1f335a2c81735bf58294b97ceedfd85192113e69c78a38804f0db923ce7a0241
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/FarTouchRestrictionTests.cs::FarTouchRestrictionTests.CanFarTouch::case:ccd63fc5b9c064fb a5568e0040a3c0ac8875a11596b7d0799ac5169b919e4fc65587555b2d3edd52
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/FarTouchRestrictionTests.cs::FarTouchRestrictionTests.CanFarTouch::case:ae3d093c6c7267ac a5568e0040a3c0ac8875a11596b7d0799ac5169b919e4fc65587555b2d3edd52
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/FarTouchRestrictionTests.cs::FarTouchRestrictionTests.CanFarTouch_Synonym::case:ccd63fc5b9c064fb c7aff866d539ceb26cc028532a901f18b58bb020f34da56444f08c9f4df1eb52
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/FarTouchRestrictionTests.cs::FarTouchRestrictionTests.CanFarTouch_Synonym::case:ae3d093c6c7267ac c7aff866d539ceb26cc028532a901f18b58bb020f34da56444f08c9f4df1eb52
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/FarTouchRestrictionTests.cs::FarTouchRestrictionTests.CanFarTouch_Default::case:ccd63fc5b9c064fb e894c744ea780a0a46cd2387157077c1a62c3c6b982303f3b7bff0b5d950816a
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/FarTouchRestrictionTests.cs::FarTouchRestrictionTests.CanFarTouch_Default::case:ae3d093c6c7267ac e894c744ea780a0a46cd2387157077c1a62c3c6b982303f3b7bff0b5d950816a
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/FarTouchRestrictionTests.cs::FarTouchRestrictionTests.CanFarTouch_Multiple_Synonyms::case:5788809ef8877342 423a8781a2de94943fa028ac64d61532509c90375cf1ca80edf1d0ef8edd9905
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/FarTouchRestrictionTests.cs::FarTouchRestrictionTests.CanFarTouch_Multiple_Synonyms::case:b3ebeae1885ed5db 423a8781a2de94943fa028ac64d61532509c90375cf1ca80edf1d0ef8edd9905
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/FarTouchRestrictionTests.cs::FarTouchRestrictionTests.CanFarTouch_Multiple_Synonyms::case:07cf5c5cabecfebf 423a8781a2de94943fa028ac64d61532509c90375cf1ca80edf1d0ef8edd9905
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/FarTouchRestrictionTests.cs::FarTouchRestrictionTests.CanFarTouch_Multiple_Synonyms::case:8008f95bc76b47e9 423a8781a2de94943fa028ac64d61532509c90375cf1ca80edf1d0ef8edd9905
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/FlyRestrictionTests.cs::FlyRestrictionTests.CanFly::test 5f60149edccece6b8a6827bbdc6f593ffd863961c13b506f1171aa0cf37fd5b7
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/InteractRestrictionTests.cs::InteractRestrictionTests.CanInteract::test 935d319e07b613ba39b06db30cfd18306670f7dc97186db38c0374c3aac6901e
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/InteractRestrictionTests.cs::InteractRestrictionTests.CanInteract_default::test 53b9d7f7cfd63a10538060624f81b7a6b1754a7462c230671ed909698dd18923
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/JumpRestrictionTests.cs::JumpRestrictionTests.CanJump::test 104374c66e6748d101b69ed5343d9972f29e937305cb17f90244ffa74fc7ed35
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/PermissiveRestrictionTests.cs::PermissiveRestrictionTests.Permissive_On::test 923519a1220e5b3007321fb9ee8cc9db27bc0bbc38bed69df0659e4365c610e8
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/PermissiveRestrictionTests.cs::PermissiveRestrictionTests.Permissive_Off::test b995698351bf04e00ab5aed459c8ee08292897545b8684338a90eaf42cd6c4aa
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/RecvChatExceptionTests.cs::RecvChatExceptionTests.CanRecvChat::test 017906038e211352d7d2751fafbcab5028cd8b189e7aa29a6202ff578976a23c
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/RecvChatFromRestrictionTests.cs::RecvChatFromRestrictionTests.CanRecvChatFrom::test aaf24dc0b8533a7e93cc567fecbb866067b72da1837207869f879647840bfa21
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/RecvChatSecExceptionTests.cs::RecvChatSecExceptionTests.CanRecvChat_Secure::test cba089ebe607088e37be285918a1d2c674f1acc4cad075733108afea3ad0279b
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/RecvEmoteFromRestrictionTests.cs::RecvEmoteFromRestrictionTests.CanRecvChat_RecvEmoteFrom::test d07ded724315cf135603d4dc5a684e5a59a5cf8415963acc30d402ad81916ac1
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/RecvEmoteRestrictionTests.cs::RecvEmoteRestrictionTests.CanRecvChat_RecvEmote::test 438b72e6c44570580bf41aa7b8ed00afb800eff8836ee971eab9fc6a00fecc19
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/RecvEmoteSecRestrictionTests.cs::RecvEmoteSecRestrictionTests.CanRecvChat_RecvEmote_Secure::test 9e1f72426762569b1c650fdf80c53e4a590b6476f8539fff6e110101e48459e8
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/RecvImFromRestrictionTests.cs::RecvImFromRestrictionTests.CanReceiveIMFrom::test ebe072c7e1c8ba440b560c2e4a0aa5151ba546f5b6cd5505012958e901c58201
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/RecvImFromRestrictionTests.cs::RecvImFromRestrictionTests.CanReceiveIMFrom_Group::test d3d155240723ca2d379f00111a3b27acb41786615a2f5b0ad2c968040d7f4447
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/RecvImFromRestrictionTests.cs::RecvImFromRestrictionTests.CanReceiveIMTo_AllGroups::test dd1050e7ef3e9805b88964822485856d6b2e5e98ee647ee08251cbc5bd452208
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/RecvImRestrictionTests.cs::RecvImRestrictionTests.CanReceiveIM::test 9c88e79ed2686e571e32ccecbc93c130423b966ff4e65e72f228f1713e5047cd
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/RecvImSecRestrictionTests.cs::RecvImSecRestrictionTests.CanReceiveIM_Secure::test e549fe9719efd180f8ab8c80b989701cd23ebf07cd004d9a5a18a0cc7db12e64
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/RecvImSecRestrictionTests.cs::RecvImSecRestrictionTests.CanReceiveIM_Secure_Group::test 13653ee7443d2eca88f2940d0c3804de3685dcf6c9277a4717a42dad4c01fca4
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/RecvImSecRestrictionTests.cs::RecvImSecRestrictionTests.CanReceiveIM_Secure_AllGroups::test d99435b52a3b774ab5d2bb6911824fa45803fe82cfe0b2c192a05473b72463c8
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/RemAttachRestrictionTests.cs::RemAttachRestrictionTests.RemAttach::test 7005409bfff88f7fb75e5cf87f6f52f4c6f048de32f651b844cf62a1cc16f55c
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/RemAttachRestrictionTests.cs::RemAttachRestrictionTests.RemAttach_Specific::test 407cb5627753c42af2b469644ddc2857416fb4b181bfbb742b199ad7239d5e6f
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/RemOutfitRestrictionTests.cs::RemOutfitRestrictionTests.RemOutfit::test 2aa5056c8aec09fb28d0da37bf6861220595cacb3190542d865f99034fc1c488
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/RemOutfitRestrictionTests.cs::RemOutfitRestrictionTests.RemOutfit_part::test f0c36209e33c9961b10ff685c8d4a32e279b4852e1c16a0e724f3cd481089576
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/RezRestrictionTests.cs::RezRestrictionTests.CanRez::test 5cae348cc241a884803692031c0af4f33fb3a2ce8331129a9866c5364599eccb
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/SendChannelRestrictionTests.cs::SendChannelRestrictionTests.CanSendChannel::test 8496734391f57cf2f2d8156f3b5a9ad9147c959e3bf99f9e76a4072e971a5b42
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/SendChannelSecRestrictionTests.cs::SendChannelSecRestrictionTests.CanSendChannel_Secure::test 5bd9096e9af488d5cdb08ed78120ef46f81f9be1eaf132c49a955eb07ae904eb
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/SendChannelSecRestrictionTests.cs::SendChannelSecRestrictionTests.CanSendChannel_Secure_Exception::test e675121ba9f6ab8f6e4484e66d76d0dd14f8ef39122c8fff2878ba5e6b3a7409
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/SendChatRestrictionTests.cs::SendChatRestrictionTests.CanSendChat::test 36cfbe5123b4b37ee43f0b4ba6453ebbe2754960825b1a8481e77e4f3a0e8015
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/SendChatRestrictionTests.cs::SendChatRestrictionTests.CanChat_SendChatRestriction::test 793a31da070038e90c41e4bdb1161daaf51376617a7444867f19c7125ad34313
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/SendGestureRestrictionTests.cs::SendGestureRestrictionTests.CanSendGesture::test 91367110c04e3c6ad173f56f209a166d828560850d3d084893e899bcc756428a
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/SendImRestrictionTests.cs::SendImRestrictionTests.CanSendIM::test c63ab3a41b6b302e7c84c54374c7193335840bafc40f2d0f2b1c3a2787b26203
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/SendImSecRestrictionTests.cs::SendImSecRestrictionTests.CanSendIM_Secure::test 65422234501bcbf151f27e0d45c74726e670665f39d90df23396f79450ba2b91
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/SendImSecRestrictionTests.cs::SendImSecRestrictionTests.CanSendIM_Secure_Group::test 4ed2e6416a86eb2406e20bbb7e60a380de25577ad034ba613530ed28f6001df9
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/SendImSecRestrictionTests.cs::SendImSecRestrictionTests.CanSendIM_Secure_AllGroups::test a4b699c9ada01ca4ce4d535739178e5310affa938d02dfaede6d034488d24f5f
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/SendImToRestrictionTests.cs::SendImToRestrictionTests.CanSendIMTo::test 38258cda1081160b6b34f8e909adbc683a0f08efce8c63066bcac09835e5cdcc
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/SendImToRestrictionTests.cs::SendImToRestrictionTests.CanSendIMTo_Group::test 1e12f7e3dbbee7d8dfb757fc8797644a353dfaa995e343e59124aa85126d70aa
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/SendImToRestrictionTests.cs::SendImToRestrictionTests.CanSendIMTo_AllGroups::test bc9b87ab7b171c76987ddaf94f05c0ac2ad8dc0c1f24f5dfce2f4125e7b28df5
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/SetDebugRestrictionTests.cs::SetDebugRestrictionTests.CanSetDebug::test d4fb9da4879ef8d1be115e00b7a8de959fd58e32722bc9e2985bca8e97dd2ce3
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/SetEnvRestrictionTests.cs::SetEnvRestrictionTests.CanSetEnv::test bb4c82afd643d267264467282cdfe09095c804079e73dd15179e1aa0b063c08f
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/SetGroupRestrictionTests.cs::SetGroupRestrictionTests.CanSetGroup::test 9d89210cbc5c188985a535ae045e44d296c796f700d4a1e2b7b4d75345cc4a6d
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/ShareRestrictionTests.cs::ShareRestrictionTests.CanShare::test 23052e5792ff72624d45b54ccfd02fa5d8025d977010f1e8d34a90d27a4d0e29
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/ShareSecRestrictionTests.cs::ShareSecRestrictionTests.CanShare_Secure_Default::test 6d61bafb190791ceaccb6c46cde3adf5b5479e6b5e76bafeadd0942400389248
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/ShareSecRestrictionTests.cs::ShareSecRestrictionTests.CanShare_Secure::test e1aed5b3b8efccef47094788c3221e20240c671c1004d6d6bd899e5d9ddd51fa
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/ShowHoverTextAllRestrictionTests.cs::ShowHoverTextAllRestrictionTests.CanShowHoverTextAll::test 6a855738e87477d31dc7867d0c75ba1bf563e2b1e180f54759657a58b7da9793
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/ShowHoverTextHudRestrictionTests.cs::ShowHoverTextHudRestrictionTests.CanShowHoverTextHud::test 9d08e2a3eb303b14c4b222cae5d52537e81a7d9cfc9fcfe9625d513b6311a6ed
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/ShowHoverTextRestrictionTests.cs::ShowHoverTextRestrictionTests.CanShowHoverText::test 5642102d6832b227c37c14d0fbfc30921022c5789b811021805db6f3a2120f36
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/ShowHoverTextWorldRestrictionTests.cs::ShowHoverTextWorldRestrictionTests.CanShowHoverTextWorld::test 1be82408fbc87f1525dc7652e01fbbc17a993b70a2268f0b742d035b37cbf70c
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/ShowInvRestrictionTests.cs::ShowInvRestrictionTests.CanShowInv::test b7c8bb7ad9d2c02c1c0168531c8ac0636885817a40b13bc006f4f5b20d28591c
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/ShowLocRestrictionTests.cs::ShowLocRestrictionTests.CanShowLoc::test a8b154f2db967ab72781f31dcd7701d204f66ece1ef95a30cc67d788c78da617
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/ShowMiniMapRestrictionTests.cs::ShowMiniMapRestrictionTests.CanShowMiniMap::test da901135b533aee1b025cf5dd925e857b4734ea00770ced4518f501453ea9736
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/ShowNameTagsRestrictionTests.cs::ShowNameTagsRestrictionTests.CanShowNameTags::test 74e8a6aefdefb9eb41509f6b4438e6854e5ad0ace38ab663f445aae484e94e22
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/ShowNamesRestrictionTests.cs::ShowNamesRestrictionTests.CanShowNames::test c44fe98d881a89af5db856e98f7bd7480d9bfb4378730002e518a7d1da412812
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/ShowNamesSecRestrictionTests.cs::ShowNamesSecRestrictionTests.CanShowNames_Secure_Default::test 98d2c84d2f226fbb4b03c365f3ab007142d87b1980dda3666ce5ec36909fc599
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/ShowNamesSecRestrictionTests.cs::ShowNamesSecRestrictionTests.CanShowNames_Secure::test 90ae29916dc2b60cd3de336e4a37683de8967f448fef26af360e3d24278773d3
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/ShowNamesSecRestrictionTests.cs::ShowNamesSecRestrictionTests.CanShowNames_Secure_Except::test 457772321f7fd1ea88a279e99a4b0a955e462652bac1fb7953b8455f3d67a155
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/ShowNearbyRestrictionTests.cs::ShowNearbyRestrictionTests.CanShowNearby::test 4faa79795b1143934efbd8ebea7a926b270dd5d1e69f8a64f496063d570d868d
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/ShowWorldMapRestrictionTests.cs::ShowWorldMapRestrictionTests.CanShowWorldMap::test da16f247df929f83ed21377869790c00cb5922fa6086da3787e90570f5684f67
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/SitRestrictionTests.cs::SitRestrictionTests.CanSit::test 813906dbfd09bb02c129a794f40a2f5dcda6e73d232e167359a6360a350fa4b4
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/SitTpRestrictionTests.cs::SitTpRestrictionTests.CanSitTp_Default::test ddcdba94af060ede43f0d585688966ccd923238a2365164b32a301b04d83cdfc
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/SitTpRestrictionTests.cs::SitTpRestrictionTests.CanSitTp_Single::test 041c57829ab1032eed79e6f47c8b9026124b681fb6ffa4b3c5ac16b16d0b354b
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/SitTpRestrictionTests.cs::SitTpRestrictionTests.CanSitTp_Multiple_SingleSender::test feed9f3cca3395e1eb5a8d831304a4171e79f6e1d93f03a4aca0e27edba5ed6d
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/SitTpRestrictionTests.cs::SitTpRestrictionTests.CanSitTp_Multiple_SingleSender_WithRemoval::test 4b26c525e0a13fbc79b280f0a6c3b0f9e3e0e664241e9f55a88eda3dd80b203a
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/SitTpRestrictionTests.cs::SitTpRestrictionTests.CanSitTp_Multiple_MultipleSenders::test cd9e3508d44e2e008609ac0cc12d3e207ec454a3f5c6e36aa325d33be9b6718f
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/SitTpRestrictionTests.cs::SitTpRestrictionTests.CanSitTp_Off::test e871d15d797e0f8f0b02613c2a421b47b87068c8757bbd0104cd15d406137854
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/StandTpRestrictionTests.cs::StandTpRestrictionTests.CanStandTp::test 0f694e59d32c3c97fbee072d591b74c89561f4648bd3440002d8f54db0058a94
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/StartImRestrictionTests.cs::StartImRestrictionTests.CanStartIM::test cc8318d5233b947ca96939369de3a2fdc2c21468cc13a87c87908126c6e45500
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/StartImToRestrictionTests.cs::StartImToRestrictionTests.CanStartIMTo::test 0c7e19de2ecf94a6db09ee409ff88ff503e02d8dd8f7f11f427cebc51a3ac09f
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/TempRunRestrictionTests.cs::TempRunRestrictionTests.CanTempRun::test 8893bb24bf10de7e914874c347ac5b73982d33925a1cf29ae8c361c3087be408
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/TouchAllRestrictionTests.cs::TouchAllRestrictionTests.TouchAll::test 06da3251125bf4d3b2d542cfba7fa0a7b0c18dc0f97024a57c0e0ddf6cfc8dd6
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/TouchAllRestrictionTests.cs::TouchAllRestrictionTests.TouchAll_default::test 9526d7bed6473afd41f97fb11ec950caae157865cec8eee719030ca109ab2681
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/TouchAttachOtherRestrictionTests.cs::TouchAttachOtherRestrictionTests.TouchAttachOther_default::test 1f8157f5fd5db8b5a4596d5be6a5d780704cac85370204c77eca08da286adb86
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/TouchAttachOtherRestrictionTests.cs::TouchAttachOtherRestrictionTests.TouchAttachOther_Specific::test add9d393d4aaf03768239611a8a64b2ef73fc4c8561dbbc51950a10c006198e6
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/TouchAttachRestrictionTests.cs::TouchAttachRestrictionTests.TouchAttach_default::test 4c4c65f8ed4b29367c353a02e52c91e9402788ffd35c75e5a6a40a827710e20a
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/TouchAttachSelfRestrictionTests.cs::TouchAttachSelfRestrictionTests.TouchAttachSelf_default::test 09f7d7a45a9899746c1c63608f95db89ef2ae4a875437a2b594bb120da8139ff
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/TouchHudRestrictionTests.cs::TouchHudRestrictionTests.TouchHud_default::test b15afadb1f45b51eb47651a9d890ed2a6b1de8066d986d9b1ccc33da734c0194
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/TouchHudRestrictionTests.cs::TouchHudRestrictionTests.TouchHud_specific::test 4c4e1a9493e5cf34f220ebec54c5373e1b30c81044803deece263dced5f7155d
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/TouchWorldRestrictionTests.cs::TouchWorldRestrictionTests.TouchWorld_default::test 5995288721c44beaa329b266e15d619f2314c9ca74386145294183c7c509b42a
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/TpLmRestrictionTests.cs::TpLmRestrictionTests.CanTpLm::test 847bd3264fd831837d8dab25b235450f19591fef3b3bd0315021727453ad64ee
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/TpLocRestrictionTests.cs::TpLocRestrictionTests.CanTpLoc::test 8e5e2ab1b55b710ecce509b141ccac9bcd9ebbad479868496645ac89574bd089
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/TpLocalRestrictionTests.cs::TpLocalRestrictionTests.CanTpLocal_Default::test 4b251429c6561c1d29f19f8fbc33dd0fb11344fe0d10962e789823ffedb3777b
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/TpLocalRestrictionTests.cs::TpLocalRestrictionTests.CanTpLocal::test f9dd3daf337533beab1f4c2dce488f44dea5d17880e8f61b33e3c17c1a4c776f
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/TpLureRestrictionTests.cs::TpLureRestrictionTests.CanTpLure_Default::test 595e468736aab4136404842adf36a79f37b9900c3ee3993079621a5a6c96dec1
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/TpLureRestrictionTests.cs::TpLureRestrictionTests.CanTpLure::test a57f7803128d75a0f1ba35a1c7489f78ca99d7e5e540f06b84725da8a5cd10da
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/TpLureSecRestrictionTests.cs::TpLureSecRestrictionTests.CanTpLure_Secure_Default::test 577c2c8d22ba1aa8d4426832807ea4ed8cd243836b0d38b0ebc9f32a851c34f4
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/TpLureSecRestrictionTests.cs::TpLureSecRestrictionTests.CanTpLure_Secure::test 38f2894e39bdd7c3c8e1520fa6ed02573be3dfdef0bc5bd1073d9d2240917804
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/TpRequestRestrictionTests.cs::TpRequestRestrictionTests.CanTpRequest::test 08ddf0e6dd1faf1f249bc7f7a9545d9e33efb5a438eacc3606b1495a83cf57db
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/TpRequestRestrictionTests.cs::TpRequestRestrictionTests.CanTpRequest_Except::test 89ccb1dd172928c41079555cb6d7ff3fcbd34594dcff0399670cdebc739ac109
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/TpRequestSecRestrictionTests.cs::TpRequestSecRestrictionTests.CanTpRequest_Secure_Default::test 87cb0ffa95d408d55045ade0966979360c28762e05729893b068801ed3b877ed
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/TpRequestSecRestrictionTests.cs::TpRequestSecRestrictionTests.CanTpRequest_Secure::test 623310f5c9150f6d6527b0db0446e2c33bf873a849a8dc68b78a4173d130da93
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/UnsitRestrictionTests.cs::UnsitRestrictionTests.CanUnsit::test 2341a0d230eace08d612a1ae3f9aac7b5a1d3d914f04b6ada4726523e9bd3a37
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/ViewNoteRestrictionTests.cs::ViewNoteRestrictionTests.CanViewNote::test 954472ccc5e060f987260c7d8f87f09dcb252e832c22810ed48dd316a173cf5e
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/ViewScriptRestrictionTests.cs::ViewScriptRestrictionTests.CanViewScript::test 5e9246991c14d80bc83aad4b5944bd9701dc32b354a701a378def8924f7b5315
// pending-parity-case: LibreMetaverse.Tests/RLV/Restrictions/ViewTextureRestrictionTests.cs::ViewTextureRestrictionTests.CanViewTexture::test d1ee89e12ea9c2d971b4d11c82f3129412fd56fa28d2bd2fb923f082eda62571
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CamZoomMin_Single::test 5f3010d46f3f18ed57ea52916dd9e8bde27d75c707dbcc0c6d68eb9bbe6c3591
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CamZoomMin_Multiple_SingleSender::test 0df818c7a6c90358cb52f59f972e16c769d38f448619dbdfeddd5a602f64d1d9
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CamZoomMin_Multiple_SingleSender_WithRemoval::test ed19a63ef16a600c9367f45d1a704739fd8e20e7811c7055df009676884de7dd
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CamZoomMin_Multiple_MultipleSenders::test c8ce609cf7506ae2df6e17126ebe5174f958245bedea26fe39600fb90195bdda
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CamZoomMin_Off::test 8f8ec9da2b0196a51dfb3fea709de597bdb440196697523824f78ef359a5482a
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CamZoomMax_Default::test 5997b7c86a1b1dac59b7f6c03d38cd09f0fb12619f03f68e1167c85ebe02f7d0
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CamZoomMax_Single::test 75530a051696ffd586b5643f0c9b9f1ae1c05bd30f9c3068f94cb30abbdc6d2d
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CamZoomMax_Multiple_SingleSender::test 44d6a5b2a9462c83047f5b4ec9f4e66bb518f6547ec08df2b5420850129ff7cb
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CamZoomMax_Multiple_SingleSender_WithRemoval::test 4958ce547ff71cf18d31cd557ecaecb8ae0a19b169c2051bd6797769bbcde26e
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CamZoomMax_Multiple_MultipleSenders::test 76346d0c1f4ecf22d09c1950aef99207d28ffe5576b7bc0be1212b91d6518f2c
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CamZoomMax_Off::test 88e2ec791d3f78bb6551b7d37a52cc5dc18c156ddd483bd6ba55288144005e5c
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CamZoomMin::test cf5f8bfbea933b64bc282211f498b01eefab0b31728800e2965a8a489f85b15d
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CamZoomMax::test 7441bff0655432365bb702cce92465ab0ab7b7dd195b732312a4e243f975ba48
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.SetCamFovMin::test b433f776bfa059a889b1a13ebc0841c824715194b6b0634dea1dd5740d5b7bbe
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.SetCamFovMax::test e0f313a03073b283400130e5a91c8c4157c9b83f9001f1ad1badf15f80821663
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.SetCamFov::test 02118d87dfda863c31de56267a31beba94ff124ca225f56d67222b6ffaf0c6f9
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.SetCamFov_Restricted::test 34b9c620b61777ece7ad140fc15dde6d2b77d877af597cf2a1b5d5f768cd5fc7
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.SetCamFov_Restricted_Synonym::test d8824c6f673ea7c101d309643ed4dbacc0fd6b17c0bda13f8cbb16b956529db4
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.SetCamAvDistMax::test 61206ccc9664f63057389d0d9540022ba82da88b1e213387a9a7f0d0cec050b3
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.SetCamAvDistMax_Synonym::test 9742afe1eb83fe3b63f6ce195bb1fb08058a6272e9817b3d1e09c50ca914a66a
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.SetCamAvDistMin::test be661f7ae623eafe2c00a7eb80a716ab832cd56be904725cfa01c16ab219d10e
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.SetCamAvDistMin_Synonym::test da29486a2c8bc2801805774269743566457ca1b9b316dc6846cf499b60aa588d
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CamDrawAlphaMax::test 96e0f72499cdf258062ca0610594137c72f232ddf936c0cc929429368957d3ed
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CamDrawMin::test 53a901a99baeb1f8d45a07d1347a6491d66ad8ca76cdef5304c64738e486e7a9
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CamDrawMin_Small::test 3f531bfcd6e08830912fd4d619a8ffc5e3ab40e9d036769f742ae0d06207400e
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CamDrawMax::test 71ab081b330b9fc4cc73a06b214f52e577ab25c0ff15439e18737dfb220d7aaf
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CamDrawMax_Small::test 72d0752ae72ba5288d2b96fca3e0a29c162406b38588160e6801b211c82fac11
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CamDrawAlphaMin::test 697fafc1837d56255cdf5e2a09634dcc740651d45df04a712c030a224a58d0c2
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CamDrawColor::test b3bc0346dbcf6c6b03d9c2c38b225e7903754fcbc56c74d098dbdcb617d2426d
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CamDrawColor_Default::test fedba7874c0b897309caca0e007cb9fbcbce8cd5155c91ec94bf6d1f391d47a1
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CamDrawColor_Large::test 6d2f0a4a24e71afbca88f3dfe574ff8ee5825e4df9a08552ac4af22a0a6b9f5e
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CamDrawColor_Negative::test 5f7ae954b3f75c5a86da8222a5eadc42ac3fee6ac4134455fb2a7a2e24101081
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CamDrawColor_Removal::test 81322059c2a6e0054c1d2131e0698c614942eec69958f72315545e9b1517fcb5
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CamDrawColor_Multi::test 21b9615f5a7e809ec83442035588414101fdf3862f282f1a501fb15d904f981e
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CanSetCamUnlock::test 3983d83fb0086bc71a585eeda9b561c738ba1eb99365182115a673ab38e166a1
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CanCamUnlock::test b116d0b63222b30c67da7c08d48f10701f5def2bdd3584166939d713a86a8cd4
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CamAvDist::test 4c5641b0e975136e815bfaf8d9821240f0ac2bc615ed105fa5190dfdbcddc158
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.SetCamTextures::case:0fdad12f3bfb0585 4b5058bfacb3e7f282bb83d0068ff9c7c7464b0d4119f879d670ddaf34d469b6
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.SetCamTextures::case:19c11fd923cc347d 4b5058bfacb3e7f282bb83d0068ff9c7c7464b0d4119f879d670ddaf34d469b6
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.SetCamTextures_Single::case:0fdad12f3bfb0585 abe9a6cff61faf1afbd29c4b073d34d67cf5e77058df44b68cbed7e1d9569814
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.SetCamTextures_Single::case:19c11fd923cc347d abe9a6cff61faf1afbd29c4b073d34d67cf5e77058df44b68cbed7e1d9569814
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.SetCamTextures_Multiple_Synonyms::case:1c2423e3f02a5f03 42abc61468c54b5e6e95d27fbadfef6010ce7d4d9b6dba8238f9e863a2ec23c7
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.SetCamTextures_Multiple_Synonyms::case:57689650dc307766 42abc61468c54b5e6e95d27fbadfef6010ce7d4d9b6dba8238f9e863a2ec23c7
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.SetCamTextures_Multiple_Synonyms::case:081becc69dc8e183 42abc61468c54b5e6e95d27fbadfef6010ce7d4d9b6dba8238f9e863a2ec23c7
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.SetCamTextures_Multiple_Synonyms::case:d96d157e365ded15 42abc61468c54b5e6e95d27fbadfef6010ce7d4d9b6dba8238f9e863a2ec23c7
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.GetCamAvDistMin::test 60d28627494c147228930839a18016e3cbfa8eb042167965647794902eb340a6
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.GetCamAvDistMax::test a7cf7887d2934984cc13e10f3afa3248a5e677c9fac680af2a68c3a27d76c3da
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.GetCamFovMin::test 25a040ca69bf4c2a303d45314fec99e70371bf6ac46e1793384e0a626deb4e75
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.GetCamFovMax::test 19153fa188ef6bd763235a03048771d1a1d824c1aeaf64841b7e6e70c35813ae
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.GetCamZoomMin::test 8cd72b3f1922b913c6bde59b928f362fa191574dc1df3cfb4668d4ccf00515a9
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.GetCamFov::test f4031d095b9a7e87d1f1d94e52c15c3c9b2b43aa1ba039c83e391e58ea994c40
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CameraSettings_Default::case:6e89e27b90f28739 4775ab3cf13fcafd3f6177ac11cecc144040d1e5c11293b442591bdfd525c0fe
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CameraSettings_Default::case:82ff323c4cfaad18 4775ab3cf13fcafd3f6177ac11cecc144040d1e5c11293b442591bdfd525c0fe
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CameraSettings_Default::case:c64b136643c55ed8 4775ab3cf13fcafd3f6177ac11cecc144040d1e5c11293b442591bdfd525c0fe
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CameraSettings_Default::case:32ad2cfbbfcf0638 4775ab3cf13fcafd3f6177ac11cecc144040d1e5c11293b442591bdfd525c0fe
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CameraSettings_Default::case:21855f1f68a52025 4775ab3cf13fcafd3f6177ac11cecc144040d1e5c11293b442591bdfd525c0fe
// pending-parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CameraSettings_Default::case:065ec3bc69e3f2b0 4775ab3cf13fcafd3f6177ac11cecc144040d1e5c11293b442591bdfd525c0fe
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.GetBlacklist_EmptyByDefault::test 9bd5c937815547d2d4b9dcfcb5c35d69e224cc4dc256273735c69b8be150c3a8
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.BlacklistBehavior_ValidBehavior_AddsToBlacklist::test dbf7650afeab51abc22fc48881a06e4908f373b6b0077fe58fc4d4e50ea0e0f5
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.BlacklistBehavior_CaseInsensitive_NormalizesToLowercase::test dbc4161b4cd5dd7f3609b11f1c6f4f6e1e243b2ba65a444afa67c70cf649c5d3
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.BlacklistBehavior_DuplicateBehavior_OnlyAddsOnce::test 53644a5123b90e32f162a9106c945a57d05b17de1a8ab0bf1930283deaf28018
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.BlacklistBehavior_NullOrWhitespaceBehavior_ThrowsArgumentException::case:12ae32cb1ec02d01 d9dcd55677740a9a1ffb8b709662060b4c417c10bfc6a361501bb149396dfe17
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.BlacklistBehavior_NullOrWhitespaceBehavior_ThrowsArgumentException::case:52109349dabf6910 d9dcd55677740a9a1ffb8b709662060b4c417c10bfc6a361501bb149396dfe17
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.BlacklistBehavior_NullOrWhitespaceBehavior_ThrowsArgumentException::case:729e2865c247816a d9dcd55677740a9a1ffb8b709662060b4c417c10bfc6a361501bb149396dfe17
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.BlacklistBehavior_NullOrWhitespaceBehavior_ThrowsArgumentException::case:d7a5e915306d21dc d9dcd55677740a9a1ffb8b709662060b4c417c10bfc6a361501bb149396dfe17
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.UnBlacklistBehavior_ExistingBehavior_RemovesFromBlacklist::test 47501ced70145add192d357c6a2647ca4a923bdaab3b1eff1c3857cebc5020db
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.UnBlacklistBehavior_CaseInsensitive_RemovesCorrectBehavior::test b5f4a87e8dc603a08a9f1225a35e44962d4240a3e5b9e605c948d19b268ed1bd
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.UnBlacklistBehavior_NonExistentBehavior_DoesNothing::test 495314ef0e42ec419b804108907c02ffe9520a1657344f391aa491f91129ecc5
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.UnBlacklistBehavior_NullOrWhitespaceBehavior_ThrowsArgumentException::case:12ae32cb1ec02d01 9b1e325139b7cec6e99ab40c5ca0e72faa88b95bce521c4ad25ed9370c2dd89f
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.UnBlacklistBehavior_NullOrWhitespaceBehavior_ThrowsArgumentException::case:52109349dabf6910 9b1e325139b7cec6e99ab40c5ca0e72faa88b95bce521c4ad25ed9370c2dd89f
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.UnBlacklistBehavior_NullOrWhitespaceBehavior_ThrowsArgumentException::case:729e2865c247816a 9b1e325139b7cec6e99ab40c5ca0e72faa88b95bce521c4ad25ed9370c2dd89f
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.UnBlacklistBehavior_NullOrWhitespaceBehavior_ThrowsArgumentException::case:d7a5e915306d21dc 9b1e325139b7cec6e99ab40c5ca0e72faa88b95bce521c4ad25ed9370c2dd89f
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.IsBlacklisted_BlacklistedBehavior_ReturnsTrue::test 2cfeda6f45d63514216d0ffccdee89ee4b7f78e775f43fb12ee78324f9cfde35
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.IsBlacklisted_CaseInsensitive_ReturnsTrue::test 1b4c6ed072b97dd9abcc0f730533691d8a65122d1839d40736e98a0f5c43f07d
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.IsBlacklisted_NonBlacklistedBehavior_ReturnsFalse::test f4cc9018c5d111b06dc8c2ce0d6ed042eb063331f35ef1665e65f4d8606d3cd3
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.IsBlacklisted_NullOrWhitespaceBehavior_ReturnsFalse::case:12ae32cb1ec02d01 ca0126a6bc1cc4ca73fdfe939ad4c9dbf1e35da741c4ea46eb3c16687730a1fa
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.IsBlacklisted_NullOrWhitespaceBehavior_ReturnsFalse::case:52109349dabf6910 ca0126a6bc1cc4ca73fdfe939ad4c9dbf1e35da741c4ea46eb3c16687730a1fa
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.IsBlacklisted_NullOrWhitespaceBehavior_ReturnsFalse::case:729e2865c247816a ca0126a6bc1cc4ca73fdfe939ad4c9dbf1e35da741c4ea46eb3c16687730a1fa
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.IsBlacklisted_NullOrWhitespaceBehavior_ReturnsFalse::case:d7a5e915306d21dc ca0126a6bc1cc4ca73fdfe939ad4c9dbf1e35da741c4ea46eb3c16687730a1fa
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.GetBlacklist_MultipleItems_ReturnsOrderedCollection::test db9bd586b7a4f79ffd2d2c48c8131ccd4bd44d8de444696e9a7c53614ef37ed5
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.GetBlacklist_ReturnsImmutableCopy::test 64db7441c81ea4f0d2e52e79b479cf658fbd2c2d1d23b918edcfa03db1233a3a
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.BlacklistWorkflow_AddMultipleBehaviors_WorksCorrectly::test 75d84bd0b26b16821ba107bef2bbb2ae58a2726496a757092b24dff6170f8872
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.SeedBlacklist_IntegrationWithRestrictionsBase_WorksCorrectly::test f7347786e3a579dc0102dc20fb73823362866ea71658777aa6835a28a58daea9
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.SeedBlacklist_EmptyString_ResultsInEmptyBlacklist::test 63555a93fbcc2b7691fdd2b79fe0db8cb305beef2c153b80f0040ba8f4f7117e
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.SeedBlacklist_WithSpaces_HandlesCorrectly::test ddd764a51e179fa6c349ab2a62bdedde1e62e4ff2ae33aa41a4ebb2359974404
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvCommonTests.cs::RlvCommonTests.TryGetRlvAttachmentPointFromItemName::case:7da68a0c44d86b61 2e932256b5a230d8c8ce814c1c919e4f1ae346f6f7263682661d1b10d4a05a17
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvCommonTests.cs::RlvCommonTests.TryGetRlvAttachmentPointFromItemName::case:d4dfd612ab268dc7 2e932256b5a230d8c8ce814c1c919e4f1ae346f6f7263682661d1b10d4a05a17
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvCommonTests.cs::RlvCommonTests.TryGetRlvAttachmentPointFromItemName::case:58d5bce9d704814b 2e932256b5a230d8c8ce814c1c919e4f1ae346f6f7263682661d1b10d4a05a17
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvCommonTests.cs::RlvCommonTests.TryGetRlvAttachmentPointFromItemName::case:7c453569c08c0a0f 2e932256b5a230d8c8ce814c1c919e4f1ae346f6f7263682661d1b10d4a05a17
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvCommonTests.cs::RlvCommonTests.TryGetRlvAttachmentPointFromItemName::case:ace2eedabcda99e6 2e932256b5a230d8c8ce814c1c919e4f1ae346f6f7263682661d1b10d4a05a17
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvCommonTests.cs::RlvCommonTests.TryGetRlvAttachmentPointFromItemName::case:1a967cd76f5fa058 2e932256b5a230d8c8ce814c1c919e4f1ae346f6f7263682661d1b10d4a05a17
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvCommonTests.cs::RlvCommonTests.TryGetRlvAttachmentPointFromItemName_CaseSensitive::case:f6b796736de6a5d8 cca41435176820c1b26287db1ea697128e5f093f2d91357081c469ba0b90e26c
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvCommonTests.cs::RlvCommonTests.TryGetRlvAttachmentPointFromItemName_CaseSensitive::case:787d37133953ab32 cca41435176820c1b26287db1ea697128e5f093f2d91357081c469ba0b90e26c
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvCommonTests.cs::RlvCommonTests.TryGetRlvAttachmentPointFromItemName_CaseSensitive::case:d2056032186a0a97 cca41435176820c1b26287db1ea697128e5f093f2d91357081c469ba0b90e26c
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvCommonTests.cs::RlvCommonTests.TryGetRlvAttachmentPointFromItemName_CaseSensitive::case:c1f038c1236211aa cca41435176820c1b26287db1ea697128e5f093f2d91357081c469ba0b90e26c
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvCommonTests.cs::RlvCommonTests.TryGetRlvAttachmentPointFromItemNameInvalid::case:564c3e282f3b402f c20289eb110772fb51f82d59b595ebb429f15d6d2a8f93daa8672702dd85ce34
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvCommonTests.cs::RlvCommonTests.TryGetRlvAttachmentPointFromItemNameInvalid::case:1d03935868fa6124 c20289eb110772fb51f82d59b595ebb429f15d6d2a8f93daa8672702dd85ce34
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvCommonTests.cs::RlvCommonTests.TryGetRlvAttachmentPointFromItemNameInvalid::case:12ae32cb1ec02d01 c20289eb110772fb51f82d59b595ebb429f15d6d2a8f93daa8672702dd85ce34
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvRestrictionManagerTests.cs::RlvRestrictionManagerTests.GetTrackedPrimIds_NoRestrictions_ReturnsEmptyCollection::test 327086a5aa514ddf8b2cc40891f7ae5e8039788f5cbfeda86f04bd9161f39ded
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvRestrictionManagerTests.cs::RlvRestrictionManagerTests.GetTrackedPrimIds_SingleRestriction_ReturnsSingleId::test 85a822c9e2e8beb2e70748513a397b8ccbb2977c0581b0519bd8ad43e699ad57
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvRestrictionManagerTests.cs::RlvRestrictionManagerTests.GetTrackedPrimIds_MultipleRestrictionsFromSameObject_ReturnsSingleId::test 933070f933b0a5a39b3d0cd5fd9be9423a538609d0106b352a7d9c339665d6d1
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvRestrictionManagerTests.cs::RlvRestrictionManagerTests.GetTrackedPrimIds_MultipleObjects_ReturnsAllUniqueIds::test 8c2afe66145e4815e73d7849f83cfec50e4a7a49793cc757917cd608c9387419
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvRestrictionManagerTests.cs::RlvRestrictionManagerTests.GetTrackedPrimIds_MixedRestrictionsAndExceptions_ReturnsAllUniqueIds::test 25ea3c36aba93d5183816962bf49bfdbc3e17e6b06d73a41dee5b51407a84746
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvRestrictionManagerTests.cs::RlvRestrictionManagerTests.GetTrackedPrimIds_AfterRemovingRestriction_DoesNotReturnRemovedObjectId::test af3d5328e5c829bd2de2b72c3f4ede6f083efa789ccef1d73d752612a177360f
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvRestrictionManagerTests.cs::RlvRestrictionManagerTests.GetTrackedPrimIds_AfterClearingAllRestrictions_ReturnsEmptyCollection::test 191a8cc3dba7e68155083a6892f1b4a29ab589023e22cffbc8cd69c005884cca
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvRestrictionManagerTests.cs::RlvRestrictionManagerTests.RemoveRestrictionsForObjects_EmptyInput_NoEffect::test 8718e08bb2bf951a94803b4947943b5f7f9eb85e906b4ac6c639cb8cd065cf9d
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvRestrictionManagerTests.cs::RlvRestrictionManagerTests.RemoveRestrictionsForObjects_NonExistentId_NoEffect::test 882d2315f40317cce9c9a026eda498325b6227886652795ed45e87cc4e5697ac
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvRestrictionManagerTests.cs::RlvRestrictionManagerTests.RemoveRestrictionsForObjects_SingleObject_RemovesAllRestrictionsFromObject::test 73ab6ee30a336372f6aef5bc4a99dbb58215b9445daea5d9708d0ea9cabe8bd1
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvRestrictionManagerTests.cs::RlvRestrictionManagerTests.RemoveRestrictionsForObjects_MultipleObjects_RemovesOnlySpecifiedObjects::test 03b6a6a3e02f6a6a5f296ff1d6cca31c9fc53982cbc9c27e73cfb698ed82acf5
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvRestrictionManagerTests.cs::RlvRestrictionManagerTests.RemoveRestrictionsForObjects_PartialMatch_RemovesOnlyMatchingObjects::test 00a26d807882b2bbb375c5ce7cf1074d3227acd891e859602e78abbdc6eefb6a
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvRestrictionManagerTests.cs::RlvRestrictionManagerTests.RemoveRestrictionsForObjects_WithNotificationRestrictions_SendsNotifications::test ba82b183dfdb01b36f9b45520e1808290c360f327d4afa833ba3b8c7a7cecffb
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvRestrictionManagerTests.cs::RlvRestrictionManagerTests.RemoveRestrictionsForObjects_WithComplexRestrictions_RemovesCorrectly::test 631de2d39fa56b29014fae4ce3b57c480f540ad41ce08a0037b7f8bbfcb3c502
// pending-parity-case: LibreMetaverse.Tests/RLV/RlvRestrictionManagerTests.cs::RlvRestrictionManagerTests.RemoveRestrictionsForObjects_TriggersRestrictionUpdatedEvent::test 318f1f4207b04d01076d3498aceea781c4889b05cdbef199cdbea43dde355f4c

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,400 @@
// Exact Rust translations of the direct attachment, outfit, detach, edit, and permissive restrictions.
use libremetaverse_compat_tests::block_on;
use libremetaverse_compat_tests::rlv_support::{RlvHarness, SampleInventoryTree, guid};
use libremetaverse_rlv::{
InventoryMap, RlvAttachmentPoint, RlvPermissionsServiceObjectLocation as ObjectLocation,
RlvWearableType,
};
const PRIM_1: &str = "11111111-0001-4aaa-8aaa-ffffffffffff";
const PRIM_2: &str = "11111111-0002-4aaa-8aaa-ffffffffffff";
const PRIM_3: &str = "11111111-0003-4aaa-8aaa-ffffffffffff";
fn harness() -> RlvHarness {
RlvHarness::new().expect("RlvService constructor")
}
fn provide_inventory(h: &RlvHarness, root: libremetaverse_rlv::RlvSharedFolder) {
h.queries.lock().unwrap().inventory_map = Some(InventoryMap::new(root, vec![]).unwrap());
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/AddAttachRestrictionTests.cs::AddAttachRestrictionTests.AddAttach::test bb2c3495d7b6862fabe1007bcfccc2850d29eef1d9aa4eac6d13d6004dcc4e6b translated
#[test]
fn add_attach_restricts_all_attachment_points() {
let h = harness();
let mut tree = SampleInventoryTree::build().unwrap();
tree.happy_shirt
.set_attached_to(Some(Some(RlvAttachmentPoint::Chin)));
tree.happy_shirt
.set_attached_prim_id(Some(Some(guid(PRIM_1))));
tree.fancy_hat
.set_attached_to(Some(Some(RlvAttachmentPoint::Chin)));
tree.fancy_hat
.set_attached_prim_id(Some(Some(guid(PRIM_3))));
provide_inventory(&h, tree.root);
assert!(block_on(h.process("@addattach=n")).unwrap());
let permissions = h.service.permissions();
assert!(
!permissions
.can_attach_with_rlv_inventory_item_boolean(tree.fancy_hat, true)
.unwrap()
);
assert!(
!permissions
.can_attach_with_rlv_inventory_item_boolean(tree.happy_shirt, true)
.unwrap()
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/AddAttachRestrictionTests.cs::AddAttachRestrictionTests.AddAttach_Specific::test 0201965931ebba1c13a23bbb43a8787c1639b0b98851141faffd963173c51035 translated
#[test]
fn add_attach_restricts_one_attachment_point() {
let h = harness();
let mut tree = SampleInventoryTree::build().unwrap();
tree.happy_shirt
.set_attached_to(Some(Some(RlvAttachmentPoint::Groin)));
tree.happy_shirt
.set_attached_prim_id(Some(Some(guid(PRIM_1))));
tree.fancy_hat
.set_attached_to(Some(Some(RlvAttachmentPoint::Chin)));
tree.fancy_hat
.set_attached_prim_id(Some(Some(guid(PRIM_3))));
provide_inventory(&h, tree.root);
assert!(block_on(h.process("@addattach:groin=n")).unwrap());
let permissions = h.service.permissions();
assert!(
permissions
.can_attach_with_rlv_inventory_item_boolean(tree.fancy_hat, true)
.unwrap()
);
assert!(
!permissions
.can_attach_with_rlv_inventory_item_boolean(tree.happy_shirt, true)
.unwrap()
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/AddOutfitRestrictionTests.cs::AddOutfitRestrictionTests.AddOutfit::test d4902b4dda0a640d240c88af30431f6d247aae2a74a81126fd91ba1d930de3fb translated
#[test]
fn add_outfit_restricts_all_layers() {
let h = harness();
let mut tree = SampleInventoryTree::build().unwrap();
tree.party_hat
.set_attached_to(Some(Some(RlvAttachmentPoint::Skull)));
tree.party_hat
.set_attached_prim_id(Some(Some(guid(PRIM_3))));
tree.happy_shirt
.set_worn_on(Some(Some(RlvWearableType::Shirt)));
tree.fancy_hat
.set_worn_on(Some(Some(RlvWearableType::Hair)));
provide_inventory(&h, tree.root);
assert!(block_on(h.process_from("@addoutfit=n", PRIM_3, "Party Hat (Spine)")).unwrap());
let permissions = h.service.permissions();
assert!(
!permissions
.can_attach_with_rlv_inventory_item_boolean(tree.happy_shirt, true)
.unwrap()
);
assert!(
!permissions
.can_attach_with_rlv_inventory_item_boolean(tree.fancy_hat, true)
.unwrap()
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/AddOutfitRestrictionTests.cs::AddOutfitRestrictionTests.AddOutfit_part::test e7e5467b36484fb54b0336abccf682905fbe5bff9e04195645981815e2ffadeb translated
#[test]
fn add_outfit_restricts_one_layer() {
let h = harness();
let mut tree = SampleInventoryTree::build().unwrap();
tree.happy_shirt
.set_worn_on(Some(Some(RlvWearableType::Shirt)));
tree.fancy_hat
.set_worn_on(Some(Some(RlvWearableType::Hair)));
provide_inventory(&h, tree.root);
assert!(block_on(h.process("@addoutfit:shirt=n")).unwrap());
let permissions = h.service.permissions();
assert!(
!permissions
.can_attach_with_rlv_inventory_item_boolean(tree.happy_shirt, true)
.unwrap()
);
assert!(
permissions
.can_attach_with_rlv_inventory_item_boolean(tree.fancy_hat, true)
.unwrap()
);
}
const OBJECT_1: &str = "00000000-0000-4000-8000-000000000000";
const OBJECT_PRIM_1: &str = "00000000-0000-4000-8000-ffffffffffff";
const OBJECT_2: &str = "11111111-1111-4111-8111-111111111111";
const OBJECT_PRIM_2: &str = "11111111-1111-4111-8111-ffffffffffff";
const FOLDER: &str = "99999999-9999-4999-8999-999999999999";
fn can_detach(
h: &RlvHarness,
item: &str,
prim: Option<&str>,
shared: bool,
point: Option<RlvAttachmentPoint>,
wearable: Option<RlvWearableType>,
) -> bool {
h.service
.permissions()
.can_detach_with_nullable_nullable_nullable_boolean_nullable_nullable(
Some(Some(guid(item))),
prim.map(|value| Some(guid(value))),
Some(Some(guid(FOLDER))),
shared,
point.map(Some),
wearable.map(Some),
)
.unwrap()
}
fn detach_defaults(h: &RlvHarness) -> [bool; 6] {
[
can_detach(h, OBJECT_1, None, false, None, None),
can_detach(
h,
OBJECT_1,
Some(OBJECT_PRIM_1),
false,
Some(RlvAttachmentPoint::Chest),
None,
),
can_detach(h, OBJECT_1, None, false, None, Some(RlvWearableType::Shirt)),
can_detach(h, OBJECT_2, None, true, None, None),
can_detach(
h,
OBJECT_2,
Some(OBJECT_PRIM_2),
true,
Some(RlvAttachmentPoint::Chest),
None,
),
can_detach(h, OBJECT_2, None, true, None, Some(RlvWearableType::Shirt)),
]
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/DetachRestrictionTests.cs::DetachRestrictionTests.Detach_Default::test 8c5b165329ab6b46eb3ec7c9a07383e8ea1e54edf0882b43b14166d67cc45617 translated
#[test]
fn detach_default() {
assert_eq!(detach_defaults(&harness()), [true; 6]);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/DetachRestrictionTests.cs::DetachRestrictionTests.Detach::test 50f5419aea3ea41aa9ebedd29202a549deb4ae6089c38965300a46fd5abf94bf translated
#[test]
fn detach_restricts_sender_prim() {
let h = harness();
assert!(block_on(h.process_from("@detach=n", OBJECT_PRIM_2, "objectPrimId2")).unwrap());
assert_eq!(detach_defaults(&h), [true, true, true, true, false, true]);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/DetachRestrictionTests.cs::DetachRestrictionTests.Detach_AttachPoint::test a75fea134b92bca704b2e140135076d699d645c0d2854022d5b20d14be372589 translated
#[test]
fn detach_restricts_attachment_point() {
let h = harness();
assert!(block_on(h.process("@detach:skull=n")).unwrap());
for shared in [false, true] {
assert!(can_detach(&h, OBJECT_1, None, shared, None, None));
assert!(can_detach(
&h,
OBJECT_1,
Some(if shared { OBJECT_PRIM_2 } else { OBJECT_PRIM_1 }),
shared,
Some(RlvAttachmentPoint::Chest),
None
));
assert!(!can_detach(
&h,
OBJECT_1,
Some(if shared { OBJECT_PRIM_2 } else { OBJECT_PRIM_1 }),
shared,
Some(RlvAttachmentPoint::Skull),
None
));
assert!(can_detach(
&h,
OBJECT_1,
None,
shared,
None,
Some(RlvWearableType::Shirt)
));
}
}
fn edit_matrix(command: &str) -> [[bool; 3]; 2] {
let h = harness();
block_on(h.process(command)).unwrap();
[None, Some(Some(guid(OBJECT_1)))].map(|object| {
[
h.service
.permissions()
.can_edit(ObjectLocation::Hud, object)
.unwrap(),
h.service
.permissions()
.can_edit(ObjectLocation::Attached, object)
.unwrap(),
h.service
.permissions()
.can_edit(ObjectLocation::RezzedInWorld, object)
.unwrap(),
]
})
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/EditAttachRestrictionTests.cs::EditAttachRestrictionTests.CanEdit_Attachment::test 22bc9e267e270c2c762561851249af4ef64c0b5bd288950a95b1b636b2975b6e translated
#[test]
fn edit_attachment_restriction() {
assert_eq!(edit_matrix("@editattach=n"), [[true, false, true]; 2]);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/EditRestrictionTests.cs::EditRestrictionTests.CanEditFolderNameSpecifiesToAddInsteadOfReplace::test 6d82d0869826bbc935d89967445dfc991619bdaf3fa631550c5d3f91a13c4935 translated
#[test]
fn edit_everywhere_restriction() {
assert_eq!(edit_matrix("@edit=n"), [[false, false, false]; 2]);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/EditWorldRestrictionTests.cs::EditWorldRestrictionTests.CanEdit_World::test 1f335a2c81735bf58294b97ceedfd85192113e69c78a38804f0db923ce7a0241 translated
#[test]
fn edit_world_restriction() {
assert_eq!(edit_matrix("@editworld=n"), [[true, true, false]; 2]);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/PermissiveRestrictionTests.cs::PermissiveRestrictionTests.Permissive_On::test 923519a1220e5b3007321fb9ee8cc9db27bc0bbc38bed69df0659e4365c610e8 translated
#[test]
fn permissive_on_command_disables_permissive_mode() {
let h = harness();
block_on(h.process("@permissive=n")).unwrap();
assert!(!h.service.permissions().is_permissive().unwrap());
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/PermissiveRestrictionTests.cs::PermissiveRestrictionTests.Permissive_Off::test b995698351bf04e00ab5aed459c8ee08292897545b8684338a90eaf42cd6c4aa translated
#[test]
fn permissive_off_command_restores_permissive_mode() {
let h = harness();
block_on(h.process("@permissive=n")).unwrap();
block_on(h.process("@permissive=y")).unwrap();
assert!(h.service.permissions().is_permissive().unwrap());
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/RemAttachRestrictionTests.cs::RemAttachRestrictionTests.RemAttach::test 7005409bfff88f7fb75e5cf87f6f52f4c6f048de32f651b844cf62a1cc16f55c translated
#[test]
fn remove_attachment_restriction() {
let h = harness();
let mut tree = SampleInventoryTree::build().unwrap();
tree.fancy_hat
.set_attached_to(Some(Some(RlvAttachmentPoint::Chin)));
tree.fancy_hat
.set_attached_prim_id(Some(Some(guid(PRIM_3))));
tree.watch.set_worn_on(Some(Some(RlvWearableType::Tattoo)));
provide_inventory(&h, tree.root);
assert!(block_on(h.process("@remattach=n")).unwrap());
let permissions = h.service.permissions();
assert!(
!permissions
.can_detach_with_rlv_inventory_item(tree.fancy_hat)
.unwrap()
);
assert!(
permissions
.can_detach_with_rlv_inventory_item(tree.watch)
.unwrap()
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/RemAttachRestrictionTests.cs::RemAttachRestrictionTests.RemAttach_Specific::test 407cb5627753c42af2b469644ddc2857416fb4b181bfbb742b199ad7239d5e6f translated
#[test]
fn remove_specific_attachment_restriction() {
let h = harness();
let mut tree = SampleInventoryTree::build().unwrap();
tree.party_hat
.set_attached_to(Some(Some(RlvAttachmentPoint::Spine)));
tree.party_hat
.set_attached_prim_id(Some(Some(guid(PRIM_3))));
tree.fancy_hat
.set_attached_to(Some(Some(RlvAttachmentPoint::Chin)));
tree.fancy_hat
.set_attached_prim_id(Some(Some(guid(PRIM_2))));
tree.watch.set_worn_on(Some(Some(RlvWearableType::Tattoo)));
provide_inventory(&h, tree.root);
assert!(block_on(h.process("@remattach:spine=n")).unwrap());
let permissions = h.service.permissions();
assert!(
!permissions
.can_detach_with_rlv_inventory_item(tree.party_hat)
.unwrap()
);
assert!(
permissions
.can_detach_with_rlv_inventory_item(tree.fancy_hat)
.unwrap()
);
assert!(
permissions
.can_detach_with_rlv_inventory_item(tree.watch)
.unwrap()
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/RemOutfitRestrictionTests.cs::RemOutfitRestrictionTests.RemOutfit::test 2aa5056c8aec09fb28d0da37bf6861220595cacb3190542d865f99034fc1c488 translated
#[test]
fn remove_outfit_restriction() {
let h = harness();
let mut tree = SampleInventoryTree::build().unwrap();
tree.fancy_hat
.set_attached_to(Some(Some(RlvAttachmentPoint::Chin)));
tree.fancy_hat
.set_attached_prim_id(Some(Some(guid(PRIM_3))));
tree.watch.set_worn_on(Some(Some(RlvWearableType::Tattoo)));
provide_inventory(&h, tree.root);
assert!(block_on(h.process("@remoutfit=n")).unwrap());
let permissions = h.service.permissions();
assert!(
permissions
.can_detach_with_rlv_inventory_item(tree.fancy_hat)
.unwrap()
);
assert!(
!permissions
.can_detach_with_rlv_inventory_item(tree.watch)
.unwrap()
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/RemOutfitRestrictionTests.cs::RemOutfitRestrictionTests.RemOutfit_part::test f0c36209e33c9961b10ff685c8d4a32e279b4852e1c16a0e724f3cd481089576 translated
#[test]
fn remove_specific_outfit_layer_restriction() {
let h = harness();
let mut tree = SampleInventoryTree::build().unwrap();
tree.fancy_hat
.set_attached_to(Some(Some(RlvAttachmentPoint::Chin)));
tree.fancy_hat
.set_attached_prim_id(Some(Some(guid(PRIM_3))));
tree.watch.set_worn_on(Some(Some(RlvWearableType::Tattoo)));
tree.retro_pants
.set_worn_on(Some(Some(RlvWearableType::Pants)));
provide_inventory(&h, tree.root);
assert!(block_on(h.process("@remoutfit:pants=n")).unwrap());
let permissions = h.service.permissions();
assert!(
permissions
.can_detach_with_rlv_inventory_item(tree.fancy_hat)
.unwrap()
);
assert!(
!permissions
.can_detach_with_rlv_inventory_item(tree.retro_pants)
.unwrap()
);
assert!(
permissions
.can_detach_with_rlv_inventory_item(tree.watch)
.unwrap()
);
}

View File

@@ -0,0 +1,335 @@
// Exact Rust translation of LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs.
// Source SHA-256: 01957800d5baff9ab13cf22bc496a5506e26f9be194917a94a3558a8456a761c
use libremetaverse_compat_tests::rlv_support::RlvHarness;
use libremetaverse_types::Error;
fn harness() -> RlvHarness {
RlvHarness::new().expect("RlvService constructor")
}
fn blacklist_behavior(value: &str) -> Result<(), Error> {
harness()
.service
.blacklist()
.blacklist_behavior(value.into())
}
fn unblacklist_behavior(value: &str) -> Result<(), Error> {
harness()
.service
.blacklist()
.un_blacklist_behavior(value.into())
}
fn is_blacklisted(value: &str) -> bool {
harness()
.service
.blacklist()
.is_blacklisted(value.into())
.unwrap()
}
fn seed(h: &RlvHarness, values: &str) {
for value in values
.split(',')
.map(str::trim)
.filter(|value| !value.is_empty())
{
h.service
.blacklist()
.blacklist_behavior(value.into())
.unwrap();
}
}
// parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.GetBlacklist_EmptyByDefault::test 9bd5c937815547d2d4b9dcfcb5c35d69e224cc4dc256273735c69b8be150c3a8 translated
#[test]
fn blacklist_is_empty_by_default() {
assert!(
harness()
.service
.blacklist()
.get_blacklist()
.unwrap()
.is_empty()
);
}
// parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.BlacklistBehavior_ValidBehavior_AddsToBlacklist::test dbf7650afeab51abc22fc48881a06e4908f373b6b0077fe58fc4d4e50ea0e0f5 translated
#[test]
fn blacklist_adds_valid_behavior() {
let h = harness();
h.service
.blacklist()
.blacklist_behavior("testbehavior".into())
.unwrap();
let values = h.service.blacklist().get_blacklist().unwrap();
assert_eq!(values.len(), 1);
assert!(values.contains(&"testbehavior".into()));
}
// parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.BlacklistBehavior_CaseInsensitive_NormalizesToLowercase::test dbc4161b4cd5dd7f3609b11f1c6f4f6e1e243b2ba65a444afa67c70cf649c5d3 translated
#[test]
fn blacklist_normalizes_to_lowercase() {
let h = harness();
h.service
.blacklist()
.blacklist_behavior("TestBehavior".into())
.unwrap();
let values = h.service.blacklist().get_blacklist().unwrap();
assert_eq!(values, vec!["testbehavior"]);
}
// parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.BlacklistBehavior_DuplicateBehavior_OnlyAddsOnce::test 53644a5123b90e32f162a9106c945a57d05b17de1a8ab0bf1930283deaf28018 translated
#[test]
fn blacklist_deduplicates_case_insensitively() {
let h = harness();
for value in ["testbehavior", "testbehavior", "TESTBEHAVIOR"] {
h.service
.blacklist()
.blacklist_behavior(value.into())
.unwrap();
}
assert_eq!(
h.service.blacklist().get_blacklist().unwrap(),
vec!["testbehavior"]
);
}
// parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.BlacklistBehavior_NullOrWhitespaceBehavior_ThrowsArgumentException::case:12ae32cb1ec02d01 d9dcd55677740a9a1ffb8b709662060b4c417c10bfc6a361501bb149396dfe17 translated
#[test]
fn blacklist_rejects_empty_behavior() {
assert_eq!(blacklist_behavior(""), Err(Error::Argument));
}
// parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.BlacklistBehavior_NullOrWhitespaceBehavior_ThrowsArgumentException::case:52109349dabf6910 d9dcd55677740a9a1ffb8b709662060b4c417c10bfc6a361501bb149396dfe17 translated
#[test]
fn blacklist_rejects_spaces_behavior() {
assert_eq!(blacklist_behavior(" "), Err(Error::Argument));
}
// parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.BlacklistBehavior_NullOrWhitespaceBehavior_ThrowsArgumentException::case:729e2865c247816a d9dcd55677740a9a1ffb8b709662060b4c417c10bfc6a361501bb149396dfe17 translated
#[test]
fn blacklist_rejects_tab_behavior() {
assert_eq!(blacklist_behavior("\t"), Err(Error::Argument));
}
// parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.BlacklistBehavior_NullOrWhitespaceBehavior_ThrowsArgumentException::case:d7a5e915306d21dc d9dcd55677740a9a1ffb8b709662060b4c417c10bfc6a361501bb149396dfe17 translated
#[test]
fn blacklist_rejects_newline_behavior() {
assert_eq!(blacklist_behavior("\n"), Err(Error::Argument));
}
// parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.UnBlacklistBehavior_ExistingBehavior_RemovesFromBlacklist::test 47501ced70145add192d357c6a2647ca4a923bdaab3b1eff1c3857cebc5020db translated
#[test]
fn unblacklist_removes_existing_behavior() {
let h = harness();
seed(&h, "testbehavior");
h.service
.blacklist()
.un_blacklist_behavior("testbehavior".into())
.unwrap();
assert!(h.service.blacklist().get_blacklist().unwrap().is_empty());
}
// parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.UnBlacklistBehavior_CaseInsensitive_RemovesCorrectBehavior::test b5f4a87e8dc603a08a9f1225a35e44962d4240a3e5b9e605c948d19b268ed1bd translated
#[test]
fn unblacklist_is_case_insensitive() {
let h = harness();
seed(&h, "TestBehavior");
h.service
.blacklist()
.un_blacklist_behavior("testbehavior".into())
.unwrap();
assert!(h.service.blacklist().get_blacklist().unwrap().is_empty());
}
// parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.UnBlacklistBehavior_NonExistentBehavior_DoesNothing::test 495314ef0e42ec419b804108907c02ffe9520a1657344f391aa491f91129ecc5 translated
#[test]
fn unblacklist_nonexistent_behavior_does_nothing() {
let h = harness();
seed(&h, "existingbehavior");
h.service
.blacklist()
.un_blacklist_behavior("nonexistentbehavior".into())
.unwrap();
assert_eq!(
h.service.blacklist().get_blacklist().unwrap(),
vec!["existingbehavior"]
);
}
// parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.UnBlacklistBehavior_NullOrWhitespaceBehavior_ThrowsArgumentException::case:12ae32cb1ec02d01 9b1e325139b7cec6e99ab40c5ca0e72faa88b95bce521c4ad25ed9370c2dd89f translated
#[test]
fn unblacklist_rejects_empty_behavior() {
assert_eq!(unblacklist_behavior(""), Err(Error::Argument));
}
// parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.UnBlacklistBehavior_NullOrWhitespaceBehavior_ThrowsArgumentException::case:52109349dabf6910 9b1e325139b7cec6e99ab40c5ca0e72faa88b95bce521c4ad25ed9370c2dd89f translated
#[test]
fn unblacklist_rejects_spaces_behavior() {
assert_eq!(unblacklist_behavior(" "), Err(Error::Argument));
}
// parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.UnBlacklistBehavior_NullOrWhitespaceBehavior_ThrowsArgumentException::case:729e2865c247816a 9b1e325139b7cec6e99ab40c5ca0e72faa88b95bce521c4ad25ed9370c2dd89f translated
#[test]
fn unblacklist_rejects_tab_behavior() {
assert_eq!(unblacklist_behavior("\t"), Err(Error::Argument));
}
// parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.UnBlacklistBehavior_NullOrWhitespaceBehavior_ThrowsArgumentException::case:d7a5e915306d21dc 9b1e325139b7cec6e99ab40c5ca0e72faa88b95bce521c4ad25ed9370c2dd89f translated
#[test]
fn unblacklist_rejects_newline_behavior() {
assert_eq!(unblacklist_behavior("\n"), Err(Error::Argument));
}
// parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.IsBlacklisted_BlacklistedBehavior_ReturnsTrue::test 2cfeda6f45d63514216d0ffccdee89ee4b7f78e775f43fb12ee78324f9cfde35 translated
#[test]
fn is_blacklisted_returns_true_for_added_behavior() {
let h = harness();
seed(&h, "testbehavior");
assert!(
h.service
.blacklist()
.is_blacklisted("testbehavior".into())
.unwrap()
);
}
// parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.IsBlacklisted_CaseInsensitive_ReturnsTrue::test 1b4c6ed072b97dd9abcc0f730533691d8a65122d1839d40736e98a0f5c43f07d translated
#[test]
fn is_blacklisted_is_case_insensitive() {
let h = harness();
seed(&h, "TestBehavior");
for value in ["testbehavior", "TESTBEHAVIOR", "TestBehavior"] {
assert!(h.service.blacklist().is_blacklisted(value.into()).unwrap());
}
}
// parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.IsBlacklisted_NonBlacklistedBehavior_ReturnsFalse::test f4cc9018c5d111b06dc8c2ce0d6ed042eb063331f35ef1665e65f4d8606d3cd3 translated
#[test]
fn is_blacklisted_returns_false_for_missing_behavior() {
let h = harness();
seed(&h, "existingbehavior");
assert!(
!h.service
.blacklist()
.is_blacklisted("nonexistentbehavior".into())
.unwrap()
);
}
// parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.IsBlacklisted_NullOrWhitespaceBehavior_ReturnsFalse::case:12ae32cb1ec02d01 ca0126a6bc1cc4ca73fdfe939ad4c9dbf1e35da741c4ea46eb3c16687730a1fa translated
#[test]
fn is_blacklisted_returns_false_for_empty_behavior() {
assert!(!is_blacklisted(""));
}
// parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.IsBlacklisted_NullOrWhitespaceBehavior_ReturnsFalse::case:52109349dabf6910 ca0126a6bc1cc4ca73fdfe939ad4c9dbf1e35da741c4ea46eb3c16687730a1fa translated
#[test]
fn is_blacklisted_returns_false_for_spaces_behavior() {
assert!(!is_blacklisted(" "));
}
// parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.IsBlacklisted_NullOrWhitespaceBehavior_ReturnsFalse::case:729e2865c247816a ca0126a6bc1cc4ca73fdfe939ad4c9dbf1e35da741c4ea46eb3c16687730a1fa translated
#[test]
fn is_blacklisted_returns_false_for_tab_behavior() {
assert!(!is_blacklisted("\t"));
}
// parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.IsBlacklisted_NullOrWhitespaceBehavior_ReturnsFalse::case:d7a5e915306d21dc ca0126a6bc1cc4ca73fdfe939ad4c9dbf1e35da741c4ea46eb3c16687730a1fa translated
#[test]
fn is_blacklisted_returns_false_for_newline_behavior() {
assert!(!is_blacklisted("\n"));
}
// parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.GetBlacklist_MultipleItems_ReturnsOrderedCollection::test db9bd586b7a4f79ffd2d2c48c8131ccd4bd44d8de444696e9a7c53614ef37ed5 translated
#[test]
fn get_blacklist_returns_ordered_collection() {
let h = harness();
seed(&h, "zebra,alpha,beta,charlie");
assert_eq!(
h.service.blacklist().get_blacklist().unwrap(),
vec!["alpha", "beta", "charlie", "zebra"]
);
}
// parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.GetBlacklist_ReturnsImmutableCopy::test 64db7441c81ea4f0d2e52e79b479cf658fbd2c2d1d23b918edcfa03db1233a3a translated
#[test]
fn get_blacklist_returns_independent_copy() {
let h = harness();
seed(&h, "testbehavior");
let first = h.service.blacklist().get_blacklist().unwrap();
seed(&h, "anotherbehavior");
let second = h.service.blacklist().get_blacklist().unwrap();
assert_eq!(first, vec!["testbehavior"]);
assert_eq!(second, vec!["anotherbehavior", "testbehavior"]);
}
// parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.BlacklistWorkflow_AddMultipleBehaviors_WorksCorrectly::test 75d84bd0b26b16821ba107bef2bbb2ae58a2726496a757092b24dff6170f8872 translated
#[test]
fn blacklist_workflow_adds_and_removes_behaviors() {
let h = harness();
seed(&h, "sendim,recvim,tpto,fly");
for value in ["sendim", "recvim", "tpto", "fly"] {
assert!(h.service.blacklist().is_blacklisted(value.into()).unwrap());
}
h.service
.blacklist()
.un_blacklist_behavior("sendim".into())
.unwrap();
h.service
.blacklist()
.un_blacklist_behavior("fly".into())
.unwrap();
assert!(
!h.service
.blacklist()
.is_blacklisted("sendim".into())
.unwrap()
);
assert!(
h.service
.blacklist()
.is_blacklisted("recvim".into())
.unwrap()
);
assert!(h.service.blacklist().is_blacklisted("tpto".into()).unwrap());
assert!(!h.service.blacklist().is_blacklisted("fly".into()).unwrap());
assert_eq!(
h.service.blacklist().get_blacklist().unwrap(),
vec!["recvim", "tpto"]
);
}
// parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.SeedBlacklist_IntegrationWithRestrictionsBase_WorksCorrectly::test f7347786e3a579dc0102dc20fb73823362866ea71658777aa6835a28a58daea9 translated
#[test]
fn seed_blacklist_adds_each_comma_separated_behavior() {
let h = harness();
seed(&h, "sendim,recvim,tpto");
for value in ["sendim", "recvim", "tpto"] {
assert!(h.service.blacklist().is_blacklisted(value.into()).unwrap());
}
assert!(!h.service.blacklist().is_blacklisted("fly".into()).unwrap());
assert_eq!(h.service.blacklist().get_blacklist().unwrap().len(), 3);
}
// parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.SeedBlacklist_EmptyString_ResultsInEmptyBlacklist::test 63555a93fbcc2b7691fdd2b79fe0db8cb305beef2c153b80f0040ba8f4f7117e translated
#[test]
fn seed_blacklist_empty_string_adds_nothing() {
let h = harness();
seed(&h, "");
assert!(h.service.blacklist().get_blacklist().unwrap().is_empty());
}
// parity-case: LibreMetaverse.Tests/RLV/RlvBlacklistTests.cs::RlvBlacklistTests.SeedBlacklist_WithSpaces_HandlesCorrectly::test ddd764a51e179fa6c349ab2a62bdedde1e62e4ff2ae33aa41a4ebb2359974404 translated
#[test]
fn seed_blacklist_trims_spaces() {
let h = harness();
seed(&h, "sendim, recvim , tpto");
for value in ["sendim", "recvim", "tpto"] {
assert!(h.service.blacklist().is_blacklisted(value.into()).unwrap());
}
assert_eq!(h.service.blacklist().get_blacklist().unwrap().len(), 3);
}

View File

@@ -0,0 +1,691 @@
// Exact Rust translation of LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs.
// Source SHA-256: 3bd6f2996fc1948e3f7c3087642ef68e0b959e49100cc70d443c5f110d0e3001
use libremetaverse_compat_tests::assert_close;
use libremetaverse_compat_tests::block_on;
use libremetaverse_compat_tests::rlv_support::{RlvHarness, guid};
use libremetaverse_rlv::CameraRestrictions;
use libremetaverse_types::compat::{Guid, Vector3};
const SENDER_2: &str = "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa";
const SENDER_3: &str = "bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb";
const TEXTURE_1: &str = "00000000-0000-4000-8000-000000000000";
const TEXTURE_2: &str = "11111111-1111-4111-8111-111111111111";
fn harness() -> RlvHarness {
RlvHarness::new().expect("RlvService constructor")
}
fn restrictions(commands: &[(&str, Option<(&str, &str)>)]) -> CameraRestrictions {
let h = harness();
for (command, sender) in commands {
let result = match sender {
Some((id, name)) => block_on(h.process_from(command, id, name)),
None => block_on(h.process(command)),
};
result.unwrap();
}
h.service.permissions().get_camera_restrictions().unwrap()
}
fn scalar_matches(
commands: &[(&str, Option<(&str, &str)>)],
getter: fn(&CameraRestrictions) -> Option<Option<f32>>,
expected: Option<f32>,
) -> bool {
let value = getter(&restrictions(commands)).flatten();
match expected {
Some(expected) => {
value.is_some_and(|actual| (f64::from(actual) - f64::from(expected)).abs() <= 0.00001)
}
None => value.is_none(),
}
}
fn texture(command: &str) -> Option<Guid> {
restrictions(&[(command, None)]).texture().flatten()
}
fn camera_query(command: &str) -> (bool, Vec<(i32, String)>) {
let h = harness();
h.queries.lock().unwrap().camera_settings = Some([1.23, 123.45, 45.60, 130.0, 12.34, 91.34]);
let processed = block_on(h.process(command)).unwrap();
let replies = h.actions.lock().unwrap().replies.clone();
(processed, replies)
}
fn missing_camera_settings(command: &str) -> (bool, Vec<(i32, String)>) {
let h = harness();
let processed = block_on(h.process(command)).unwrap();
let replies = h.actions.lock().unwrap().replies.clone();
(processed, replies)
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CamZoomMin_Single::test 5f3010d46f3f18ed57ea52916dd9e8bde27d75c707dbcc0c6d68eb9bbe6c3591 translated
#[test]
fn cam_zoom_min_single() {
assert!(scalar_matches(
&[("@CamZoomMin:1.5=n", None)],
CameraRestrictions::zoom_min,
Some(1.5),
));
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CamZoomMin_Multiple_SingleSender::test 0df818c7a6c90358cb52f59f972e16c769d38f448619dbdfeddd5a602f64d1d9 translated
#[test]
fn cam_zoom_min_multiple_single_sender() {
assert!(scalar_matches(
&[
("@CamZoomMin:3.5=n", None),
("@CamZoomMin:4.5=n", None),
("@CamZoomMin:1.5=n", None),
],
CameraRestrictions::zoom_min,
Some(4.5),
));
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CamZoomMin_Multiple_SingleSender_WithRemoval::test ed19a63ef16a600c9367f45d1a704739fd8e20e7811c7055df009676884de7dd translated
#[test]
fn cam_zoom_min_removes_matching_value() {
assert!(scalar_matches(
&[
("@CamZoomMin:3.5=n", None),
("@CamZoomMin:4.5=n", None),
("@CamZoomMin:1.5=n", None),
("@CamZoomMin:8.5=n", None),
("@CamZoomMin:8.5=y", None),
],
CameraRestrictions::zoom_min,
Some(4.5),
));
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CamZoomMin_Multiple_MultipleSenders::test c8ce609cf7506ae2df6e17126ebe5174f958245bedea26fe39600fb90195bdda translated
#[test]
fn cam_zoom_min_multiple_senders() {
assert!(scalar_matches(
&[
("@CamZoomMin:3.5=n", None),
("@CamZoomMin:4.5=n", Some((SENDER_2, "Sender 2"))),
("@CamZoomMin:1.5=n", Some((SENDER_3, "Sender 3"))),
],
CameraRestrictions::zoom_min,
Some(4.5),
));
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CamZoomMin_Off::test 8f8ec9da2b0196a51dfb3fea709de597bdb440196697523824f78ef359a5482a translated
#[test]
fn cam_zoom_min_off() {
assert!(scalar_matches(
&[("@CamZoomMin:1.5=n", None), ("@CamZoomMin:1.5=y", None)],
CameraRestrictions::zoom_min,
None,
));
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CamZoomMax_Default::test 5997b7c86a1b1dac59b7f6c03d38cd09f0fb12619f03f68e1167c85ebe02f7d0 translated
#[test]
fn cam_zoom_max_default() {
assert!(scalar_matches(&[], CameraRestrictions::zoom_max, None));
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CamZoomMax_Single::test 75530a051696ffd586b5643f0c9b9f1ae1c05bd30f9c3068f94cb30abbdc6d2d translated
#[test]
fn cam_zoom_max_single() {
assert!(scalar_matches(
&[("@CamZoomMax:1.5=n", None)],
CameraRestrictions::zoom_max,
Some(1.5),
));
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CamZoomMax_Multiple_SingleSender::test 44d6a5b2a9462c83047f5b4ec9f4e66bb518f6547ec08df2b5420850129ff7cb translated
#[test]
fn cam_zoom_max_multiple_single_sender() {
assert!(scalar_matches(
&[
("@CamZoomMax:3.5=n", None),
("@CamZoomMax:4.5=n", None),
("@CamZoomMax:1.5=n", None),
],
CameraRestrictions::zoom_max,
Some(1.5),
));
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CamZoomMax_Multiple_SingleSender_WithRemoval::test 4958ce547ff71cf18d31cd557ecaecb8ae0a19b169c2051bd6797769bbcde26e translated
#[test]
fn cam_zoom_max_removes_matching_value() {
assert!(scalar_matches(
&[
("@CamZoomMax:3.5=n", None),
("@CamZoomMax:4.5=n", None),
("@CamZoomMax:1.5=n", None),
("@CamZoomMax:0.5=n", None),
("@CamZoomMax:0.5=y", None),
],
CameraRestrictions::zoom_max,
Some(1.5),
));
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CamZoomMax_Multiple_MultipleSenders::test 76346d0c1f4ecf22d09c1950aef99207d28ffe5576b7bc0be1212b91d6518f2c translated
#[test]
fn cam_zoom_max_multiple_senders() {
assert!(scalar_matches(
&[
("@CamZoomMax:3.5=n", None),
("@CamZoomMax:4.5=n", Some((SENDER_2, "Sender 2"))),
("@CamZoomMax:1.5=n", Some((SENDER_3, "Sender 3"))),
],
CameraRestrictions::zoom_max,
Some(1.5),
));
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CamZoomMax_Off::test 88e2ec791d3f78bb6551b7d37a52cc5dc18c156ddd483bd6ba55288144005e5c translated
#[test]
fn cam_zoom_max_off() {
assert!(scalar_matches(
&[("@CamZoomMax:1.5=n", None), ("@CamZoomMax:1.5=y", None)],
CameraRestrictions::zoom_max,
None,
));
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CamZoomMin::test cf5f8bfbea933b64bc282211f498b01eefab0b31728800e2965a8a489f85b15d translated
#[test]
fn cam_zoom_min_command() {
assert!(scalar_matches(
&[("@CamZoomMin:0.5=n", None)],
CameraRestrictions::zoom_min,
Some(0.5),
));
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CamZoomMax::test 7441bff0655432365bb702cce92465ab0ab7b7dd195b732312a4e243f975ba48 translated
#[test]
fn cam_zoom_max_command() {
assert!(scalar_matches(
&[("@CamZoomMax:1.5=n", None)],
CameraRestrictions::zoom_max,
Some(1.5),
));
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.SetCamFovMin::test b433f776bfa059a889b1a13ebc0841c824715194b6b0634dea1dd5740d5b7bbe translated
#[test]
fn set_cam_fov_min() {
assert!(scalar_matches(
&[("@setcam_fovmin:15=n", None)],
CameraRestrictions::fov_min,
Some(15.0),
));
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.SetCamFovMax::test e0f313a03073b283400130e5a91c8c4157c9b83f9001f1ad1badf15f80821663 translated
#[test]
fn set_cam_fov_max() {
assert!(scalar_matches(
&[("@setcam_fovmax:45=n", None)],
CameraRestrictions::fov_max,
Some(45.0),
));
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.SetCamFov::test 02118d87dfda863c31de56267a31beba94ff124ca225f56d67222b6ffaf0c6f9 translated
#[test]
fn set_cam_fov_records_exact_value() {
let h = harness();
assert!(block_on(h.process("@setcam_fov:1.75=force")).unwrap());
assert_eq!(h.actions.lock().unwrap().camera_fovs, vec![1.75]);
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.SetCamFov_Restricted::test 34b9c620b61777ece7ad140fc15dde6d2b77d877af597cf2a1b5d5f768cd5fc7 translated
#[test]
fn set_cam_fov_restricted() {
let h = harness();
block_on(h.process("@setcam_unlock=n")).unwrap();
assert!(!block_on(h.process("@setcam_fov:1.75=force")).unwrap());
assert!(h.actions.lock().unwrap().camera_fovs.is_empty());
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.SetCamFov_Restricted_Synonym::test d8824c6f673ea7c101d309643ed4dbacc0fd6b17c0bda13f8cbb16b956529db4 translated
#[test]
fn set_cam_fov_restricted_by_synonym() {
let h = harness();
block_on(h.process("@camunlock=n")).unwrap();
assert!(!block_on(h.process("@setcam_fov:1.75=force")).unwrap());
assert!(h.actions.lock().unwrap().camera_fovs.is_empty());
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.SetCamAvDistMax::test 61206ccc9664f63057389d0d9540022ba82da88b1e213387a9a7f0d0cec050b3 translated
#[test]
fn set_cam_av_dist_max() {
assert!(scalar_matches(
&[("@setcam_avdistmax:30=n", None)],
CameraRestrictions::av_dist_max,
Some(30.0),
));
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.SetCamAvDistMax_Synonym::test 9742afe1eb83fe3b63f6ce195bb1fb08058a6272e9817b3d1e09c50ca914a66a translated
#[test]
fn set_cam_av_dist_max_synonym() {
assert!(scalar_matches(
&[("@camdistmax:30=n", None)],
CameraRestrictions::av_dist_max,
Some(30.0),
));
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.SetCamAvDistMin::test be661f7ae623eafe2c00a7eb80a716ab832cd56be904725cfa01c16ab219d10e translated
#[test]
fn set_cam_av_dist_min() {
assert!(scalar_matches(
&[("@setcam_avdistmin:0.3=n", None)],
CameraRestrictions::av_dist_min,
Some(0.3),
));
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.SetCamAvDistMin_Synonym::test da29486a2c8bc2801805774269743566457ca1b9b316dc6846cf499b60aa588d translated
#[test]
fn set_cam_av_dist_min_synonym() {
assert!(scalar_matches(
&[("@camdistmin:0.3=n", None)],
CameraRestrictions::av_dist_min,
Some(0.3),
));
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CamDrawAlphaMax::test 96e0f72499cdf258062ca0610594137c72f232ddf936c0cc929429368957d3ed translated
#[test]
fn cam_draw_alpha_max() {
assert!(scalar_matches(
&[("@CamDrawAlphaMax:0.9=n", None)],
CameraRestrictions::draw_alpha_max,
Some(0.9),
));
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CamDrawMin::test 53a901a99baeb1f8d45a07d1347a6491d66ad8ca76cdef5304c64738e486e7a9 translated
#[test]
fn cam_draw_min() {
assert!(scalar_matches(
&[("@camdrawmin:1.75=n", None)],
CameraRestrictions::draw_min,
Some(1.75),
));
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CamDrawMin_Small::test 3f531bfcd6e08830912fd4d619a8ffc5e3ab40e9d036769f742ae0d06207400e translated
#[test]
fn cam_draw_min_rejects_too_small_value() {
let h = harness();
assert!(!block_on(h.process("@camdrawmin:0.15=n")).unwrap());
assert!(
h.service
.permissions()
.get_camera_restrictions()
.unwrap()
.draw_min()
.flatten()
.is_none()
);
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CamDrawMax::test 71ab081b330b9fc4cc73a06b214f52e577ab25c0ff15439e18737dfb220d7aaf translated
#[test]
fn cam_draw_max() {
assert!(scalar_matches(
&[("@camdrawmax:1.75=n", None)],
CameraRestrictions::draw_max,
Some(1.75),
));
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CamDrawMax_Small::test 72d0752ae72ba5288d2b96fca3e0a29c162406b38588160e6801b211c82fac11 translated
#[test]
fn cam_draw_max_rejects_too_small_value() {
let h = harness();
assert!(!block_on(h.process("@camdrawmax:0.15=n")).unwrap());
assert!(
h.service
.permissions()
.get_camera_restrictions()
.unwrap()
.draw_max()
.flatten()
.is_none()
);
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CamDrawAlphaMin::test 697fafc1837d56255cdf5e2a09634dcc740651d45df04a712c030a224a58d0c2 translated
#[test]
fn cam_draw_alpha_min() {
assert!(scalar_matches(
&[("@camdrawalphamin:1.75=n", None)],
CameraRestrictions::draw_alpha_min,
Some(1.75),
));
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CamDrawColor::test b3bc0346dbcf6c6b03d9c2c38b225e7903754fcbc56c74d098dbdcb617d2426d translated
#[test]
fn cam_draw_color() {
let Vector3(value) = restrictions(&[("@CamDrawColor:0.1;0.2;0.3=n", None)])
.draw_color()
.flatten()
.unwrap();
for (actual, expected) in value.into_iter().zip([0.1, 0.2, 0.3]) {
assert_close(f64::from(actual), expected, 0.00001);
}
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CamDrawColor_Default::test fedba7874c0b897309caca0e007cb9fbcbce8cd5155c91ec94bf6d1f391d47a1 translated
#[test]
fn cam_draw_color_default() {
assert!(restrictions(&[]).draw_color().flatten().is_none());
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CamDrawColor_Large::test 6d2f0a4a24e71afbca88f3dfe574ff8ee5825e4df9a08552ac4af22a0a6b9f5e translated
#[test]
#[allow(clippy::float_cmp)] // The C# test requires exact clamped endpoint values.
fn cam_draw_color_clamps_large_components() {
let Vector3(value) = restrictions(&[("@CamDrawColor:5;6;7=n", None)])
.draw_color()
.flatten()
.unwrap();
assert_eq!(value, [1.0, 1.0, 1.0]);
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CamDrawColor_Negative::test 5f7ae954b3f75c5a86da8222a5eadc42ac3fee6ac4134455fb2a7a2e24101081 translated
#[test]
#[allow(clippy::float_cmp)] // The C# test requires exact clamped endpoint values.
fn cam_draw_color_clamps_negative_components() {
let Vector3(value) = restrictions(&[("@CamDrawColor:-5;-6;-7=n", None)])
.draw_color()
.flatten()
.unwrap();
assert_eq!(value, [0.0, 0.0, 0.0]);
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CamDrawColor_Removal::test 81322059c2a6e0054c1d2131e0698c614942eec69958f72315545e9b1517fcb5 translated
#[test]
fn cam_draw_color_removal() {
assert!(
restrictions(&[
("@CamDrawColor:0.1;0.2;0.3=n", None),
("@CamDrawColor:0.1;0.2;0.3=y", None),
])
.draw_color()
.flatten()
.is_none()
);
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CamDrawColor_Multi::test 21b9615f5a7e809ec83442035588414101fdf3862f282f1a501fb15d904f981e translated
#[test]
fn cam_draw_color_averages_multiple_values() {
let Vector3(value) = restrictions(&[
("@CamDrawColor:0.1;0.2;0.3=n", None),
("@CamDrawColor:0.2;0.3;0.6=n", None),
])
.draw_color()
.flatten()
.unwrap();
for (actual, expected) in value.into_iter().zip([0.15, 0.25, 0.45]) {
assert_close(f64::from(actual), expected, 0.00001);
}
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CanSetCamUnlock::test 3983d83fb0086bc71a585eeda9b561c738ba1eb99365182115a673ab38e166a1 translated
#[test]
fn set_cam_unlock_toggles_lock() {
let h = harness();
block_on(h.process("@setcam_unlock=n")).unwrap();
assert!(
h.service
.permissions()
.get_camera_restrictions()
.unwrap()
.is_locked()
);
block_on(h.process("@setcam_unlock=y")).unwrap();
assert!(
!h.service
.permissions()
.get_camera_restrictions()
.unwrap()
.is_locked()
);
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CanCamUnlock::test b116d0b63222b30c67da7c08d48f10701f5def2bdd3584166939d713a86a8cd4 translated
#[test]
fn cam_unlock_synonym_toggles_lock() {
let h = harness();
block_on(h.process("@camunlock=n")).unwrap();
assert!(
h.service
.permissions()
.get_camera_restrictions()
.unwrap()
.is_locked()
);
block_on(h.process("@camunlock=y")).unwrap();
assert!(
!h.service
.permissions()
.get_camera_restrictions()
.unwrap()
.is_locked()
);
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CamAvDist::test 4c5641b0e975136e815bfaf8d9821240f0ac2bc615ed105fa5190dfdbcddc158 translated
#[test]
fn cam_av_dist() {
assert!(scalar_matches(
&[("@CamAvDist:5=n", None)],
CameraRestrictions::av_dist,
Some(5.0),
));
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.SetCamTextures::case:0fdad12f3bfb0585 4b5058bfacb3e7f282bb83d0068ff9c7c7464b0d4119f879d670ddaf34d469b6 translated
#[test]
fn set_cam_textures_empty_uuid() {
assert_eq!(texture("@setcam_textures=n"), Some(Guid([0; 16])));
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.SetCamTextures::case:19c11fd923cc347d 4b5058bfacb3e7f282bb83d0068ff9c7c7464b0d4119f879d670ddaf34d469b6 translated
#[test]
fn cam_textures_empty_uuid() {
assert_eq!(texture("@camtextures=n"), Some(Guid([0; 16])));
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.SetCamTextures_Single::case:0fdad12f3bfb0585 abe9a6cff61faf1afbd29c4b073d34d67cf5e77058df44b68cbed7e1d9569814 translated
#[test]
fn set_cam_textures_single() {
assert_eq!(
texture(&format!("@setcam_textures:{TEXTURE_1}=n")),
Some(guid(TEXTURE_1))
);
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.SetCamTextures_Single::case:19c11fd923cc347d abe9a6cff61faf1afbd29c4b073d34d67cf5e77058df44b68cbed7e1d9569814 translated
#[test]
fn cam_textures_single() {
assert_eq!(
texture(&format!("@camtextures:{TEXTURE_1}=n")),
Some(guid(TEXTURE_1))
);
}
fn texture_synonyms(first: &str, second: &str) -> [Option<Guid>; 2] {
let h = harness();
block_on(h.process(&format!("@{first}:{TEXTURE_1}=n"))).unwrap();
block_on(h.process(&format!("@{second}:{TEXTURE_2}=n"))).unwrap();
let second_texture = h
.service
.permissions()
.get_camera_restrictions()
.unwrap()
.texture()
.flatten();
block_on(h.process(&format!("@{first}:{TEXTURE_2}=y"))).unwrap();
[
second_texture,
h.service
.permissions()
.get_camera_restrictions()
.unwrap()
.texture()
.flatten(),
]
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.SetCamTextures_Multiple_Synonyms::case:1c2423e3f02a5f03 42abc61468c54b5e6e95d27fbadfef6010ce7d4d9b6dba8238f9e863a2ec23c7 translated
#[test]
fn set_cam_textures_then_set_cam_textures() {
assert_eq!(
texture_synonyms("setcam_textures", "setcam_textures"),
[Some(guid(TEXTURE_2)), Some(guid(TEXTURE_1))]
);
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.SetCamTextures_Multiple_Synonyms::case:57689650dc307766 42abc61468c54b5e6e95d27fbadfef6010ce7d4d9b6dba8238f9e863a2ec23c7 translated
#[test]
fn set_cam_textures_then_cam_textures() {
assert_eq!(
texture_synonyms("setcam_textures", "camtextures"),
[Some(guid(TEXTURE_2)), Some(guid(TEXTURE_1))]
);
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.SetCamTextures_Multiple_Synonyms::case:081becc69dc8e183 42abc61468c54b5e6e95d27fbadfef6010ce7d4d9b6dba8238f9e863a2ec23c7 translated
#[test]
fn cam_textures_then_cam_textures() {
assert_eq!(
texture_synonyms("camtextures", "camtextures"),
[Some(guid(TEXTURE_2)), Some(guid(TEXTURE_1))]
);
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.SetCamTextures_Multiple_Synonyms::case:d96d157e365ded15 42abc61468c54b5e6e95d27fbadfef6010ce7d4d9b6dba8238f9e863a2ec23c7 translated
#[test]
fn cam_textures_then_set_cam_textures() {
assert_eq!(
texture_synonyms("camtextures", "setcam_textures"),
[Some(guid(TEXTURE_2)), Some(guid(TEXTURE_1))]
);
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.GetCamAvDistMin::test 60d28627494c147228930839a18016e3cbfa8eb042167965647794902eb340a6 translated
#[test]
fn get_cam_av_dist_min() {
assert_eq!(
camera_query("@getcam_avdistmin=1234"),
(true, vec![(1234, "1.23".into())])
);
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.GetCamAvDistMax::test a7cf7887d2934984cc13e10f3afa3248a5e677c9fac680af2a68c3a27d76c3da translated
#[test]
fn get_cam_av_dist_max() {
assert_eq!(
camera_query("@getcam_avdistmax=1234"),
(true, vec![(1234, "123.45".into())])
);
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.GetCamFovMin::test 25a040ca69bf4c2a303d45314fec99e70371bf6ac46e1793384e0a626deb4e75 translated
#[test]
fn get_cam_fov_min() {
assert_eq!(
camera_query("@getcam_fovmin=1234"),
(true, vec![(1234, "45.6".into())])
);
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.GetCamFovMax::test 19153fa188ef6bd763235a03048771d1a1d824c1aeaf64841b7e6e70c35813ae translated
#[test]
fn get_cam_fov_max() {
assert_eq!(
camera_query("@getcam_fovmax=1234"),
(true, vec![(1234, "130".into())])
);
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.GetCamZoomMin::test 8cd72b3f1922b913c6bde59b928f362fa191574dc1df3cfb4668d4ccf00515a9 translated
#[test]
fn get_cam_zoom_min() {
assert_eq!(
camera_query("@getcam_zoommin=1234"),
(true, vec![(1234, "12.34".into())])
);
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.GetCamFov::test f4031d095b9a7e87d1f1d94e52c15c3c9b2b43aa1ba039c83e391e58ea994c40 translated
#[test]
fn get_cam_fov() {
assert_eq!(
camera_query("@getcam_fov=1234"),
(true, vec![(1234, "91.34".into())])
);
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CameraSettings_Default::case:6e89e27b90f28739 4775ab3cf13fcafd3f6177ac11cecc144040d1e5c11293b442591bdfd525c0fe translated
#[test]
fn camera_settings_default_get_zoom_min() {
assert_eq!(
missing_camera_settings("@getcam_zoommin=1234"),
(false, vec![])
);
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CameraSettings_Default::case:82ff323c4cfaad18 4775ab3cf13fcafd3f6177ac11cecc144040d1e5c11293b442591bdfd525c0fe translated
#[test]
fn camera_settings_default_get_fov() {
assert_eq!(missing_camera_settings("@getcam_fov=1234"), (false, vec![]));
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CameraSettings_Default::case:c64b136643c55ed8 4775ab3cf13fcafd3f6177ac11cecc144040d1e5c11293b442591bdfd525c0fe translated
#[test]
fn camera_settings_default_get_fov_max() {
assert_eq!(
missing_camera_settings("@getcam_fovmax=1234"),
(false, vec![])
);
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CameraSettings_Default::case:32ad2cfbbfcf0638 4775ab3cf13fcafd3f6177ac11cecc144040d1e5c11293b442591bdfd525c0fe translated
#[test]
fn camera_settings_default_get_av_dist_min() {
assert_eq!(
missing_camera_settings("@getcam_avdistmin=1234"),
(false, vec![])
);
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CameraSettings_Default::case:21855f1f68a52025 4775ab3cf13fcafd3f6177ac11cecc144040d1e5c11293b442591bdfd525c0fe translated
#[test]
fn camera_settings_default_get_av_dist_max() {
assert_eq!(
missing_camera_settings("@getcam_avdistmax=1234"),
(false, vec![])
);
}
// parity-case: LibreMetaverse.Tests/RLV/RestrictionsCameraTests.cs::RestrictionsCameraTests.CameraSettings_Default::case:065ec3bc69e3f2b0 4775ab3cf13fcafd3f6177ac11cecc144040d1e5c11293b442591bdfd525c0fe translated
#[test]
fn camera_settings_default_get_fov_min() {
assert_eq!(
missing_camera_settings("@getcam_fovmin=1234"),
(false, vec![])
);
}

View File

@@ -0,0 +1,119 @@
// Exact Rust translation of LibreMetaverse.Tests/RLV/RlvCommonTests.cs.
// Source SHA-256: 1e3e097f189cb39e9204a82d881be38847d696870debe7d62e3ddf13b9951a6f
use libremetaverse_rlv::{RlvAttachmentPoint, RlvCommon};
#[allow(clippy::option_option)]
fn point(item_name: &str) -> (bool, Option<Option<RlvAttachmentPoint>>) {
let mut actual = None;
let found = RlvCommon::try_get_attachment_point_from_item_name(item_name.into(), &mut actual);
(found, actual)
}
// parity-case: LibreMetaverse.Tests/RLV/RlvCommonTests.cs::RlvCommonTests.TryGetRlvAttachmentPointFromItemName::case:7da68a0c44d86b61 2e932256b5a230d8c8ce814c1c919e4f1ae346f6f7263682661d1b10d4a05a17 translated
#[test]
fn attachment_point_spine() {
assert_eq!(
point("(spine)"),
(true, Some(Some(RlvAttachmentPoint::Spine)))
);
}
// parity-case: LibreMetaverse.Tests/RLV/RlvCommonTests.cs::RlvCommonTests.TryGetRlvAttachmentPointFromItemName::case:d4dfd612ab268dc7 2e932256b5a230d8c8ce814c1c919e4f1ae346f6f7263682661d1b10d4a05a17 translated
#[test]
fn attachment_point_repeated_spine() {
assert_eq!(
point("(spine)(spine)"),
(true, Some(Some(RlvAttachmentPoint::Spine)))
);
}
// parity-case: LibreMetaverse.Tests/RLV/RlvCommonTests.cs::RlvCommonTests.TryGetRlvAttachmentPointFromItemName::case:58d5bce9d704814b 2e932256b5a230d8c8ce814c1c919e4f1ae346f6f7263682661d1b10d4a05a17 translated
#[test]
fn attachment_point_uses_last_known_tag() {
assert_eq!(
point("My (mouth) item (spine) has a lot of tags"),
(true, Some(Some(RlvAttachmentPoint::Spine)))
);
}
// parity-case: LibreMetaverse.Tests/RLV/RlvCommonTests.cs::RlvCommonTests.TryGetRlvAttachmentPointFromItemName::case:7c453569c08c0a0f 2e932256b5a230d8c8ce814c1c919e4f1ae346f6f7263682661d1b10d4a05a17 translated
#[test]
fn attachment_point_ignores_unknown_tag() {
assert_eq!(
point("My item (l upper leg) and some random unknown tag (unknown)"),
(true, Some(Some(RlvAttachmentPoint::LeftUpperLeg)))
);
}
// parity-case: LibreMetaverse.Tests/RLV/RlvCommonTests.cs::RlvCommonTests.TryGetRlvAttachmentPointFromItemName::case:ace2eedabcda99e6 2e932256b5a230d8c8ce814c1c919e4f1ae346f6f7263682661d1b10d4a05a17 translated
#[test]
fn attachment_point_avatar_center() {
assert_eq!(
point("Central item (avatar center)"),
(true, Some(Some(RlvAttachmentPoint::AvatarCenter)))
);
}
// parity-case: LibreMetaverse.Tests/RLV/RlvCommonTests.cs::RlvCommonTests.TryGetRlvAttachmentPointFromItemName::case:1a967cd76f5fa058 2e932256b5a230d8c8ce814c1c919e4f1ae346f6f7263682661d1b10d4a05a17 translated
#[test]
fn attachment_point_root_alias() {
assert_eq!(
point("Central item (root)"),
(true, Some(Some(RlvAttachmentPoint::AvatarCenter)))
);
}
// parity-case: LibreMetaverse.Tests/RLV/RlvCommonTests.cs::RlvCommonTests.TryGetRlvAttachmentPointFromItemName_CaseSensitive::case:f6b796736de6a5d8 cca41435176820c1b26287db1ea697128e5f093f2d91357081c469ba0b90e26c translated
#[test]
fn attachment_point_uppercase_spine() {
assert_eq!(
point("(SPINE)"),
(true, Some(Some(RlvAttachmentPoint::Spine)))
);
}
// parity-case: LibreMetaverse.Tests/RLV/RlvCommonTests.cs::RlvCommonTests.TryGetRlvAttachmentPointFromItemName_CaseSensitive::case:787d37133953ab32 cca41435176820c1b26287db1ea697128e5f093f2d91357081c469ba0b90e26c translated
#[test]
fn attachment_point_titlecase_spine() {
assert_eq!(
point("(Spine)"),
(true, Some(Some(RlvAttachmentPoint::Spine)))
);
}
// parity-case: LibreMetaverse.Tests/RLV/RlvCommonTests.cs::RlvCommonTests.TryGetRlvAttachmentPointFromItemName_CaseSensitive::case:d2056032186a0a97 cca41435176820c1b26287db1ea697128e5f093f2d91357081c469ba0b90e26c translated
#[test]
fn attachment_point_titlecase_avatar_center() {
assert_eq!(
point("Central item (Avatar center)"),
(true, Some(Some(RlvAttachmentPoint::AvatarCenter)))
);
}
// parity-case: LibreMetaverse.Tests/RLV/RlvCommonTests.cs::RlvCommonTests.TryGetRlvAttachmentPointFromItemName_CaseSensitive::case:c1f038c1236211aa cca41435176820c1b26287db1ea697128e5f093f2d91357081c469ba0b90e26c translated
#[test]
fn attachment_point_lowercase_left_upper_leg() {
assert_eq!(
point("Another item (l upper leg)"),
(true, Some(Some(RlvAttachmentPoint::LeftUpperLeg)))
);
}
// parity-case: LibreMetaverse.Tests/RLV/RlvCommonTests.cs::RlvCommonTests.TryGetRlvAttachmentPointFromItemNameInvalid::case:564c3e282f3b402f c20289eb110772fb51f82d59b595ebb429f15d6d2a8f93daa8672702dd85ce34 translated
#[test]
fn attachment_point_rejects_unknown_tags() {
assert_eq!(point("(unknown)(hand tag)(spine tag)"), (false, None));
}
// parity-case: LibreMetaverse.Tests/RLV/RlvCommonTests.cs::RlvCommonTests.TryGetRlvAttachmentPointFromItemNameInvalid::case:1d03935868fa6124 c20289eb110772fb51f82d59b595ebb429f15d6d2a8f93daa8672702dd85ce34 translated
#[test]
fn attachment_point_rejects_untagged_name() {
assert_eq!(point("Hat"), (false, None));
}
// parity-case: LibreMetaverse.Tests/RLV/RlvCommonTests.cs::RlvCommonTests.TryGetRlvAttachmentPointFromItemNameInvalid::case:12ae32cb1ec02d01 c20289eb110772fb51f82d59b595ebb429f15d6d2a8f93daa8672702dd85ce34 translated
#[test]
fn attachment_point_rejects_empty_name() {
assert_eq!(point(""), (false, None));
}

View File

@@ -0,0 +1,115 @@
//! Exact Rust translations of `DetachAllCommandTests`.
use libremetaverse_compat_tests::block_on;
use libremetaverse_compat_tests::rlv_support::{RlvHarness, SampleInventoryTree, guid};
use libremetaverse_rlv::{InventoryMap, RlvAttachmentPoint, RlvWearableType};
use libremetaverse_types::compat::Guid;
const RETRO: &str = "b2222222-bbbb-4bbb-8bbb-bbbbbbbbbbbb";
const HAPPY: &str = "b1111111-bbbb-4bbb-8bbb-bbbbbbbbbbbb";
const FANCY: &str = "d1111111-dddd-4ddd-8ddd-dddddddddddd";
#[derive(Clone, Copy)]
enum Setup {
Default,
Restricted,
PrivateTarget,
PrivateSubfolder,
NoStripFolder,
NoStripLink,
NoStripItem,
}
fn run(setup: Setup) -> Vec<Guid> {
let h = RlvHarness::new().expect("RlvService constructor");
let mut tree = SampleInventoryTree::build().unwrap();
tree.retro_pants
.set_attached_to(Some(Some(RlvAttachmentPoint::Pelvis)));
tree.retro_pants
.set_attached_prim_id(Some(Some(guid("11111111-0002-4aaa-8aaa-ffffffffffff"))));
tree.glasses.set_worn_on(Some(Some(RlvWearableType::Pants)));
tree.happy_shirt
.set_worn_on(Some(Some(RlvWearableType::Pants)));
if !matches!(setup, Setup::NoStripItem) {
tree.fancy_hat
.set_attached_to(Some(Some(RlvAttachmentPoint::Chin)));
tree.fancy_hat
.set_attached_prim_id(Some(Some(guid("11111111-0003-4aaa-8aaa-ffffffffffff"))));
}
match setup {
Setup::PrivateTarget => tree.clothing.set_name(".clothing".into()),
Setup::PrivateSubfolder => {
tree.clothing.set_name(".clothing".into());
tree.hats.set_name(".hats".into());
}
Setup::NoStripFolder | Setup::NoStripLink => {
tree.clothing.set_name(".clothing".into());
tree.hats.set_name("nostrip hats".into());
}
Setup::NoStripItem => tree.happy_shirt.set_name("nostrip Happy Shirt".into()),
_ => {}
}
if matches!(setup, Setup::NoStripLink) {
tree.party_hat
.set_attached_to(Some(Some(RlvAttachmentPoint::Chin)));
tree.party_hat
.set_attached_prim_id(Some(Some(guid("11111111-0004-4aaa-8aaa-ffffffffffff"))));
tree.fancy_hat.set_is_link(true);
}
h.queries.lock().unwrap().inventory_map = Some(InventoryMap::new(tree.root, vec![]).unwrap());
if matches!(setup, Setup::Restricted) {
block_on(h.process("@detachthis:Clothing=n")).unwrap();
}
let path = if matches!(
setup,
Setup::PrivateTarget | Setup::PrivateSubfolder | Setup::NoStripFolder | Setup::NoStripLink
) {
".clothing"
} else {
"Clothing"
};
block_on(h.process(&format!("@detachall:{path}=force"))).unwrap();
let mut result = h.actions.lock().unwrap().detachments[0].clone();
result.sort_by_key(|id| id.0);
result
}
fn ids(values: &[&str]) -> Vec<Guid> {
let mut v: Vec<_> = values.iter().map(|s| guid(s)).collect();
v.sort_by_key(|id| id.0);
v
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/DetachAllCommandTests.cs::DetachAllCommandTests.DetachAllForce_Recursive::test 45405dbca6c2b8bb9f439736d53c2ff60056252f4cdf6296bedcc14d2be9248e translated
#[test]
fn detach_all_recursive() {
assert_eq!(run(Setup::Default), ids(&[FANCY, HAPPY, RETRO]));
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/DetachAllCommandTests.cs::DetachAllCommandTests.DetachAllForce_Recursive_EnforceRestrictions::test 6186f5923009fb984daef726e8df44aff7cb65f74c2e381dd8cc9968f5534e43 translated
#[test]
fn detach_all_enforces_restrictions() {
assert_eq!(run(Setup::Restricted), ids(&[FANCY]));
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/DetachAllCommandTests.cs::DetachAllCommandTests.DetachAllForce_Recursive_PrivateTargetDir::test 300a323967b6258d1202190bbd3de7b91699231f7a5afa86204ba627cb61215f translated
#[test]
fn detach_all_private_target() {
assert_eq!(run(Setup::PrivateTarget), ids(&[FANCY, HAPPY, RETRO]));
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/DetachAllCommandTests.cs::DetachAllCommandTests.DetachAllForce_Recursive_PrivateSubFolders::test e688b64d13f0a07f4bfeae0715fbfbf98c1d1fa64b0aefbd0e4e3d3d4dd98eee translated
#[test]
fn detach_all_skips_private_subfolders() {
assert_eq!(run(Setup::PrivateSubfolder), ids(&[HAPPY, RETRO]));
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/DetachAllCommandTests.cs::DetachAllCommandTests.DetachAllForce_Recursive_NostripSubFolders::test 22cf1a159861c98c8a0f14ac63bafcbef21466c2ac01e615fe9ca4630d16f956 translated
#[test]
fn detach_all_honors_nostrip_subfolders() {
assert_eq!(run(Setup::NoStripFolder), ids(&[HAPPY, RETRO]));
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/DetachAllCommandTests.cs::DetachAllCommandTests.DetachAllForce_Recursive_NostripSubFolders_LinkException::test cbe38368a6d4c59d72291195688d0c70898be5c3cceb02f09c5d386c3668fb07 translated
#[test]
fn detach_all_honors_link_exception() {
assert_eq!(run(Setup::NoStripLink), ids(&[HAPPY, RETRO, FANCY]));
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/DetachAllCommandTests.cs::DetachAllCommandTests.DetachAllForce_Recursive_NostripItemName::test ea0fab47cb1829338948f605919fcf1dca4f88d7965cdca4c7f457e399e4fbfc translated
#[test]
fn detach_all_honors_nostrip_item() {
assert_eq!(run(Setup::NoStripItem), ids(&[RETRO]));
}

View File

@@ -0,0 +1,226 @@
//! Exact Rust translations of `DetachAllThisCommandTests`.
use libremetaverse_compat_tests::block_on;
use libremetaverse_compat_tests::rlv_support::{RlvHarness, SampleInventoryTree, guid};
use libremetaverse_rlv::{InventoryMap, RlvAttachmentPoint, RlvWearableType};
use libremetaverse_types::compat::Guid;
const HAPPY: &str = "b1111111-bbbb-4bbb-8bbb-bbbbbbbbbbbb";
const RETRO: &str = "b2222222-bbbb-4bbb-8bbb-bbbbbbbbbbbb";
const GLASSES: &str = "c1111111-cccc-4ccc-8ccc-cccccccccccc";
const FANCY: &str = "d1111111-dddd-4ddd-8ddd-dddddddddddd";
const PRIM1: &str = "11111111-0001-4aaa-8aaa-ffffffffffff";
#[derive(Clone, Copy)]
enum Setup {
Normal,
NoStrip,
NoStripLink,
Point,
PointNoStrip,
PointLink,
Wearable,
WearableNoStrip,
WearableLink,
WearablePrivate,
}
fn attach(item: &mut libremetaverse_rlv::RlvInventoryItem, point: RlvAttachmentPoint, prim: &str) {
item.set_attached_to(Some(Some(point)));
item.set_attached_prim_id(Some(Some(guid(prim))));
}
fn run(command: &str, setup: Setup, sender_item: bool) -> Vec<Guid> {
let h = RlvHarness::new().expect("RlvService constructor");
let mut tree = SampleInventoryTree::build().unwrap();
attach(
&mut tree.retro_pants,
RlvAttachmentPoint::Pelvis,
"11111111-0002-4aaa-8aaa-ffffffffffff",
);
attach(
&mut tree.fancy_hat,
RlvAttachmentPoint::Chin,
"11111111-0003-4aaa-8aaa-ffffffffffff",
);
if matches!(
setup,
Setup::Wearable | Setup::WearableNoStrip | Setup::WearableLink | Setup::WearablePrivate
) {
tree.happy_shirt
.set_worn_on(Some(Some(RlvWearableType::Pants)));
tree.glasses.set_worn_on(Some(Some(RlvWearableType::Pants)));
} else {
attach(&mut tree.happy_shirt, RlvAttachmentPoint::Chest, PRIM1);
attach(
&mut tree.glasses,
RlvAttachmentPoint::Chest,
"11111111-0004-4aaa-8aaa-ffffffffffff",
);
}
if matches!(
setup,
Setup::NoStrip
| Setup::NoStripLink
| Setup::PointNoStrip
| Setup::PointLink
| Setup::WearableNoStrip
| Setup::WearableLink
) {
tree.hats.set_name("nostrip Hats".into());
tree.retro_pants.set_name("nostrip Retro Pants".into());
}
if matches!(
setup,
Setup::NoStripLink | Setup::PointLink | Setup::WearableLink
) {
tree.fancy_hat.set_is_link(true);
attach(
&mut tree.party_hat,
RlvAttachmentPoint::Chin,
"11111111-0005-4aaa-8aaa-ffffffffffff",
);
}
if matches!(setup, Setup::WearablePrivate) {
tree.hats.set_name(".hats".into());
}
h.queries.lock().unwrap().inventory_map = Some(InventoryMap::new(tree.root, vec![]).unwrap());
if sender_item {
block_on(h.process_from(command, PRIM1, "Happy Shirt")).unwrap();
} else {
block_on(h.process(command)).unwrap();
}
let mut v = h.actions.lock().unwrap().detachments[0].clone();
v.sort_by_key(|id| id.0);
v
}
fn ids(values: &[&str]) -> Vec<Guid> {
let mut v: Vec<_> = values.iter().map(|s| guid(s)).collect();
v.sort_by_key(|id| id.0);
v
}
fn normal() -> Vec<Guid> {
ids(&[HAPPY, RETRO, FANCY])
}
fn nostrip() -> Vec<Guid> {
ids(&[HAPPY])
}
fn link() -> Vec<Guid> {
ids(&[HAPPY, FANCY])
}
fn selected() -> Vec<Guid> {
ids(&[HAPPY, RETRO, GLASSES, FANCY])
}
fn selected_nostrip() -> Vec<Guid> {
ids(&[HAPPY, GLASSES])
}
fn selected_link() -> Vec<Guid> {
ids(&[HAPPY, GLASSES, FANCY])
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/DetachAllThisCommandTests.cs::DetachAllThisCommandTests.DetachAllThisForce_Default::test 8fe4eacf8cc5841e638d69540e2ab080efc3e64534346ece854429d0476f8a84 translated
#[test]
fn detach_all_this_default() {
assert_eq!(run("@detachallthis=force", Setup::Normal, true), normal());
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/DetachAllThisCommandTests.cs::DetachAllThisCommandTests.DetachAllThisForce_Nostrip::test 754bd01f2f0b77c05ee5d1548f76337da93d980a48ad0922d80f34707c4fe68b translated
#[test]
fn detach_all_this_honors_nostrip() {
assert_eq!(run("@detachallthis=force", Setup::NoStrip, true), nostrip());
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/DetachAllThisCommandTests.cs::DetachAllThisCommandTests.DetachAllThisForce_Nostrip_LinkException::test 0cce15f7cfda160733c305b0867be31875e1814b38e2e980525d960e0214ad51 translated
#[test]
fn detach_all_this_honors_link_exception() {
assert_eq!(
run("@detachallthis=force", Setup::NoStripLink, true),
link()
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/DetachAllThisCommandTests.cs::DetachAllThisCommandTests.DetachAllThisForce_ById::test 2f657ffed317d4d7f97f6111942ea8214996872da6294f7c66d07890647f7f63 translated
#[test]
fn detach_all_this_by_id() {
assert_eq!(
run(
&format!("@detachallthis:{PRIM1}=force"),
Setup::Normal,
false
),
normal()
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/DetachAllThisCommandTests.cs::DetachAllThisCommandTests.DetachAllThisForce_ById_Nostrip::test 48ab7aec02efd652478ca3110dd39011fd9b79a1e0a1336f53e9f77b2f56e635 translated
#[test]
fn detach_all_this_by_id_honors_nostrip() {
assert_eq!(
run(
&format!("@detachallthis:{PRIM1}=force"),
Setup::NoStrip,
false
),
nostrip()
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/DetachAllThisCommandTests.cs::DetachAllThisCommandTests.DetachAllThisForce_ById_Nostrip_LinkException::test 5d882f00bfe73cecfc3e96c26ff18a20c00481619996b25ed2ce851eff9a86ce translated
#[test]
fn detach_all_this_by_id_honors_link_exception() {
assert_eq!(
run(
&format!("@detachallthis:{PRIM1}=force"),
Setup::NoStripLink,
false
),
link()
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/DetachAllThisCommandTests.cs::DetachAllThisCommandTests.DetachThisAllForce_ByRlvAttachmentPoint::test 30e6806d5c484bf2a2f9a3b1fcdb5e88272874b0e755462c3b0bfa97326d180c translated
#[test]
fn detach_all_this_by_attachment_point() {
assert_eq!(
run("@detachallthis:chest=force", Setup::Point, false),
selected()
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/DetachAllThisCommandTests.cs::DetachAllThisCommandTests.DetachThisAllForce_ByRlvAttachmentPoint_NoStrip::test 657125be7aec668f72e744cc87cae38f022c8ccf9e8980c8ef4bea7e0557fdd1 translated
#[test]
fn detach_all_this_by_attachment_point_honors_nostrip() {
assert_eq!(
run("@detachallthis:chest=force", Setup::PointNoStrip, false),
selected_nostrip()
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/DetachAllThisCommandTests.cs::DetachAllThisCommandTests.DetachThisAllForce_ByRlvAttachmentPoint_NoStrip_LinkException::test fe019191a9a3df9a43fd500db775ba5f874f4b767096365cba390480b2b2189f translated
#[test]
fn detach_all_this_by_attachment_point_honors_link_exception() {
assert_eq!(
run("@detachallthis:chest=force", Setup::PointLink, false),
selected_link()
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/DetachAllThisCommandTests.cs::DetachAllThisCommandTests.DetachAllThisForce_ByRlvWearableType::test ccf302d870f323790af63873fcbb172f084c4e7400a728e480378706b5fb9947 translated
#[test]
fn detach_all_this_by_wearable() {
assert_eq!(
run("@detachallthis:pants=force", Setup::Wearable, false),
selected()
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/DetachAllThisCommandTests.cs::DetachAllThisCommandTests.DetachAllThisForce_ByRlvWearableType_NoStrip::test 1947e7c9cfe8bb931ee7ad50c6f505515feeb9d30b236702a2d68fb4734a30f0 translated
#[test]
fn detach_all_this_by_wearable_honors_nostrip() {
assert_eq!(
run("@detachallthis:pants=force", Setup::WearableNoStrip, false),
selected_nostrip()
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/DetachAllThisCommandTests.cs::DetachAllThisCommandTests.DetachAllThisForce_ByRlvWearableType_NoStrip_LinkException::test 50ec101ab557e78d947ac7f9878acd4df4957482f358a7ce02371df8754add94 translated
#[test]
fn detach_all_this_by_wearable_honors_link_exception() {
assert_eq!(
run("@detachallthis:pants=force", Setup::WearableLink, false),
selected_link()
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/DetachAllThisCommandTests.cs::DetachAllThisCommandTests.DetachAllThisForce_ByRlvWearableType_PrivateFolder::test 2ba745b093f0348d8754f74073c6a6a0f18383b5ce4a73721b39b01f0306a994 translated
#[test]
fn detach_all_this_by_wearable_skips_private_folder() {
assert_eq!(
run("@detachallthis:pants=force", Setup::WearablePrivate, false),
ids(&[HAPPY, RETRO, GLASSES])
);
}

View File

@@ -0,0 +1,81 @@
//! Exact Rust translations of `DetachMeCommandTests`.
use libremetaverse_compat_tests::block_on;
use libremetaverse_compat_tests::rlv_support::{RlvHarness, SampleInventoryTree, guid};
use libremetaverse_rlv::{InventoryMap, RlvAttachmentPoint};
use libremetaverse_types::compat::Guid;
const RETRO: &str = "b2222222-bbbb-4bbb-8bbb-bbbbbbbbbbbb";
const PRIM2: &str = "11111111-0002-4aaa-8aaa-ffffffffffff";
const PRIM3: &str = "11111111-0003-4aaa-8aaa-ffffffffffff";
fn run(nostrip: bool, copy: bool, locked: bool) -> Vec<Guid> {
let h = RlvHarness::new().expect("RlvService constructor");
let mut tree = SampleInventoryTree::build().unwrap();
if nostrip {
tree.clothing.set_name("nostrip Clothing".into());
tree.retro_pants.set_name("nostrip Retro Pants".into());
}
tree.retro_pants
.set_attached_to(Some(Some(RlvAttachmentPoint::Pelvis)));
tree.retro_pants
.set_attached_prim_id(Some(Some(guid(PRIM2))));
tree.happy_shirt
.set_attached_to(Some(Some(RlvAttachmentPoint::Spine)));
tree.happy_shirt
.set_attached_prim_id(Some(Some(guid(PRIM3))));
if copy {
tree.hats
.add_item(
guid(RETRO),
if nostrip {
"nostrip Retro Pants"
} else {
"Retro Pants"
}
.into(),
false,
Some(Some(RlvAttachmentPoint::Pelvis)),
Some(Some(guid(PRIM2))),
None,
None,
)
.unwrap();
}
h.queries.lock().unwrap().inventory_map = Some(InventoryMap::new(tree.root, vec![]).unwrap());
if locked {
block_on(h.process("@detachthis:Clothing/Hats=n")).unwrap();
}
block_on(h.process_from(
"@detachme=force",
PRIM2,
if nostrip {
"nostrip Retro Pants"
} else {
"Retro Pants"
},
))
.unwrap();
h.actions.lock().unwrap().detachments[0].clone()
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/DetachMeCommandTests.cs::DetachMeCommandTests.DetachMeForce::test fde065233689ec75c12e9607acf06c5859a91efea58e143ecc508ebec784a567 translated
#[test]
fn detach_me() {
assert_eq!(run(false, false, false), vec![guid(RETRO)]);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/DetachMeCommandTests.cs::DetachMeCommandTests.DetachMeForce_WithNoStripItemName_SpecialException::test ee511230131312be9b788033aac8766ea3cb3c1f8d7c5b9b26a4bd6a83cd695c translated
#[test]
fn detach_me_ignores_nostrip() {
assert_eq!(run(true, false, false), vec![guid(RETRO)]);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/DetachMeCommandTests.cs::DetachMeCommandTests.DetachMeForce_WithLockedFolderRestriction::test 05fefae0563306af0c491006f18915ff1b250b7972c82c160f20f06e07335887 translated
#[test]
fn detach_me_honors_locked_linked_folder() {
assert!(run(false, true, true).is_empty());
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/DetachMeCommandTests.cs::DetachMeCommandTests.DetachMeForce_MultipleLinksSameItem::test 1ae8a318762625819371fb109fd673e0d31a2c0354add1e65802eb54cb71e303 translated
#[test]
fn detach_me_deduplicates_multiple_links() {
assert_eq!(run(false, true, false), vec![guid(RETRO)]);
}

View File

@@ -0,0 +1,229 @@
//! Exact Rust translations of `DetachThisCommandTests`.
use libremetaverse_compat_tests::block_on;
use libremetaverse_compat_tests::rlv_support::{RlvHarness, SampleInventoryTree, guid};
use libremetaverse_rlv::{InventoryMap, RlvAttachmentPoint, RlvWearableType};
use libremetaverse_types::compat::Guid;
const HAPPY: &str = "b1111111-bbbb-4bbb-8bbb-bbbbbbbbbbbb";
const RETRO: &str = "b2222222-bbbb-4bbb-8bbb-bbbbbbbbbbbb";
const GLASSES: &str = "c1111111-cccc-4ccc-8ccc-cccccccccccc";
const PRIM1: &str = "11111111-0001-4aaa-8aaa-ffffffffffff";
#[derive(Clone, Copy)]
enum Setup {
Normal,
NoStripItem,
NoStripFolder,
NoStripLink,
Point,
PointNoStrip,
PointLink,
Wearable,
WearableNoStrip,
WearableLink,
WearablePrivate,
}
fn attach(item: &mut libremetaverse_rlv::RlvInventoryItem, point: RlvAttachmentPoint, prim: &str) {
item.set_attached_to(Some(Some(point)));
item.set_attached_prim_id(Some(Some(guid(prim))));
}
fn run(command: &str, setup: Setup, sender_item: bool) -> Vec<Guid> {
let h = RlvHarness::new().expect("RlvService constructor");
let mut tree = SampleInventoryTree::build().unwrap();
attach(
&mut tree.retro_pants,
RlvAttachmentPoint::Pelvis,
"11111111-0002-4aaa-8aaa-ffffffffffff",
);
attach(
&mut tree.fancy_hat,
RlvAttachmentPoint::Chin,
"11111111-0003-4aaa-8aaa-ffffffffffff",
);
if matches!(
setup,
Setup::Wearable | Setup::WearableNoStrip | Setup::WearableLink | Setup::WearablePrivate
) {
tree.happy_shirt
.set_worn_on(Some(Some(RlvWearableType::Pants)));
tree.glasses.set_worn_on(Some(Some(RlvWearableType::Pants)));
} else {
attach(&mut tree.happy_shirt, RlvAttachmentPoint::Chest, PRIM1);
attach(
&mut tree.glasses,
RlvAttachmentPoint::Chest,
"11111111-0004-4aaa-8aaa-ffffffffffff",
);
}
match setup {
Setup::NoStripItem | Setup::PointNoStrip | Setup::WearableNoStrip => {
tree.happy_shirt.set_name("nostrip Happy Shirt".into());
}
_ => {}
}
if matches!(setup, Setup::NoStripFolder | Setup::NoStripLink) {
tree.clothing.set_name("nostrip Clothing".into());
}
if matches!(
setup,
Setup::PointNoStrip | Setup::PointLink | Setup::WearableNoStrip | Setup::WearableLink
) {
tree.accessories.set_name("nostrip Accessories".into());
}
if matches!(setup, Setup::NoStripLink) {
tree.retro_pants.set_is_link(true);
}
if matches!(setup, Setup::PointLink | Setup::WearableLink) {
tree.glasses.set_is_link(true);
}
if matches!(setup, Setup::WearablePrivate) {
tree.clothing.set_name(".clothing".into());
}
h.queries.lock().unwrap().inventory_map = Some(InventoryMap::new(tree.root, vec![]).unwrap());
if sender_item {
block_on(h.process_from(command, PRIM1, "Happy Shirt")).unwrap();
} else {
block_on(h.process(command)).unwrap();
}
let mut result = h.actions.lock().unwrap().detachments[0].clone();
result.sort_by_key(|id| id.0);
result
}
fn ids(values: &[&str]) -> Vec<Guid> {
let mut v: Vec<_> = values.iter().map(|s| guid(s)).collect();
v.sort_by_key(|id| id.0);
v
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/DetachThisCommandTests.cs::DetachThisCommandTests.DetachThisForce_Default::test ae8c0fd737f869ef3e2dbd97ae28974b35c6bbc5327151c0074d531efdaaf54e translated
#[test]
fn detach_this_default() {
assert_eq!(
run("@detachthis=force", Setup::Normal, true),
ids(&[HAPPY, RETRO])
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/DetachThisCommandTests.cs::DetachThisCommandTests.DetachThisForce_NoStrip::test 3aa17222f7539814f8329e07de548cca4bb702f4b0409e793ea551327b0c57d0 translated
#[test]
fn detach_this_honors_item_nostrip() {
assert_eq!(
run("@detachthis=force", Setup::NoStripItem, true),
ids(&[RETRO])
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/DetachThisCommandTests.cs::DetachThisCommandTests.DetachThisForce_NoStripFolder::test 16b74c3bf8312ccb885e61f933ec9d292988d2e1fad05e0188006df5630681f8 translated
#[test]
fn detach_this_honors_folder_nostrip() {
assert!(run("@detachthis=force", Setup::NoStripFolder, true).is_empty());
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/DetachThisCommandTests.cs::DetachThisCommandTests.DetachThisForce_NoStripFolder_LinkException::test b86b22a0ab30d0ded0cd6fbc7d34fae77e521861f5672b44a25a77325e594ab4 translated
#[test]
fn detach_this_honors_folder_link_exception() {
assert_eq!(
run("@detachthis=force", Setup::NoStripLink, true),
ids(&[RETRO])
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/DetachThisCommandTests.cs::DetachThisCommandTests.DetachThisForce_ById::test 3c4a211e5fefb44b42f50f6e6e58f8f852c8cf2d732bb6c3f737c3d6a592fa22 translated
#[test]
fn detach_this_by_id() {
assert_eq!(
run(&format!("@detachthis:{PRIM1}=force"), Setup::Normal, false),
ids(&[HAPPY, RETRO])
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/DetachThisCommandTests.cs::DetachThisCommandTests.DetachThisForce_ById_NostripItemName::test f32926ca6f4328afdd3ddeb9f7bec8ff2ee01e9563555921ac8c663d20005551 translated
#[test]
fn detach_this_by_id_honors_item_nostrip() {
assert_eq!(
run(
&format!("@detachthis:{PRIM1}=force"),
Setup::NoStripItem,
false
),
ids(&[RETRO])
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/DetachThisCommandTests.cs::DetachThisCommandTests.DetachThisForce_ById_NostripFolderName::test bec3216bf016c2543a3410b069abd786167e04a7527253887f158127644656a8 translated
#[test]
fn detach_this_by_id_honors_folder_nostrip() {
assert!(
run(
&format!("@detachthis:{PRIM1}=force"),
Setup::NoStripFolder,
false
)
.is_empty()
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/DetachThisCommandTests.cs::DetachThisCommandTests.DetachThisForce_ById_NostripFolderName_LinkException::test 1b5eb3a0bdef8ea65b800533ab3153dc6b3ea21d2f4f27e4820d0a0df48891a2 translated
#[test]
fn detach_this_by_id_honors_link_exception() {
assert_eq!(
run(
&format!("@detachthis:{PRIM1}=force"),
Setup::NoStripLink,
false
),
ids(&[RETRO])
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/DetachThisCommandTests.cs::DetachThisCommandTests.DetachThisForce_ByRlvAttachmentPoint::test 7e8f3a4d8b2cbdb5cc81eea598da6ef6395834b1cb7a629dc8d7ee2bfd80fab5 translated
#[test]
fn detach_this_by_attachment_point() {
assert_eq!(
run("@detachthis:chest=force", Setup::Point, false),
ids(&[HAPPY, RETRO, GLASSES])
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/DetachThisCommandTests.cs::DetachThisCommandTests.DetachThisForce_ByRlvAttachmentPoint_NoStrip::test f6ff482bdb8d28414e01952201e37e49316b3e2345b0ff85dd4cb059193d1816 translated
#[test]
fn detach_this_by_attachment_point_honors_nostrip() {
assert_eq!(
run("@detachthis:chest=force", Setup::PointNoStrip, false),
ids(&[RETRO])
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/DetachThisCommandTests.cs::DetachThisCommandTests.DetachThisForce_ByRlvAttachmentPoint_NoStrip_LinkException::test 289f8cc48f0e6a412d58258876e4aca08d8116d549642a0011bbdaf9b2223e83 translated
#[test]
fn detach_this_by_attachment_point_honors_link_exception() {
assert_eq!(
run("@detachthis:chest=force", Setup::PointLink, false),
ids(&[RETRO, GLASSES])
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/DetachThisCommandTests.cs::DetachThisCommandTests.DetachThisForce_ByRlvWearableType::test 51607294f12279974c2b44b47ba2eadca9846180a39bcde6a28c020dc4466254 translated
#[test]
fn detach_this_by_wearable() {
assert_eq!(
run("@detachthis:pants=force", Setup::Wearable, false),
ids(&[HAPPY, RETRO, GLASSES])
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/DetachThisCommandTests.cs::DetachThisCommandTests.DetachThisForce_ByRlvWearableType_NoStrip::test 30dec183993b2a644c2812ffc1c863e1714df134942f7827df818d9200e47c38 translated
#[test]
fn detach_this_by_wearable_honors_nostrip() {
assert_eq!(
run("@detachthis:pants=force", Setup::WearableNoStrip, false),
ids(&[RETRO])
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/DetachThisCommandTests.cs::DetachThisCommandTests.DetachThisForce_ByRlvWearableType_NoStrip_LinkException::test 62f59cf66f21dcac15cf3166dcec2183181c0b434e9eacba796eb7025c4f1ab3 translated
#[test]
fn detach_this_by_wearable_honors_link_exception() {
assert_eq!(
run("@detachthis:pants=force", Setup::WearableLink, false),
ids(&[RETRO, GLASSES])
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/DetachThisCommandTests.cs::DetachThisCommandTests.DetachThisForce_ByRlvWearableType_PrivateFolder::test dd40588598bd081189e7c4f284af3851a140155e2ede0ae2121dd59a156dc988 translated
#[test]
fn detach_this_by_wearable_skips_private_folder() {
assert_eq!(
run("@detachthis:pants=force", Setup::WearablePrivate, false),
ids(&[GLASSES])
);
}

View File

@@ -0,0 +1,743 @@
// Exact Rust translations of the non-folder RLV exception tests.
use libremetaverse_compat_tests::block_on;
use libremetaverse_compat_tests::rlv_support::{RlvHarness, SENDER_ID, guid};
use libremetaverse_rlv::{
RlvPermissionsServiceObjectLocation as ObjectLocation,
RlvPermissionsServiceTouchLocation as TouchLocation,
};
const USER_1: &str = "00000000-0000-4000-8000-000000000000";
const USER_2: &str = "11111111-1111-4111-8111-111111111111";
fn harness() -> RlvHarness {
RlvHarness::new().expect("RlvService constructor")
}
fn process(h: &RlvHarness, commands: &[String]) {
for command in commands {
block_on(h.process(command)).unwrap();
}
}
#[allow(clippy::option_option)]
fn touch_matches(
h: &RlvHarness,
location: TouchLocation,
object: libremetaverse_types::compat::Guid,
user: Option<Option<libremetaverse_types::compat::Guid>>,
distance: Option<Option<f32>>,
expected: bool,
) -> bool {
h.service
.permissions()
.can_touch(location, object, user, distance)
.unwrap()
== expected
}
// parity-case: LibreMetaverse.Tests/RLV/Exceptions/AcceptPermissionExceptionTests.cs::AcceptPermissionExceptionTests.AcceptPermission::test a5ffc51718e89fb872c6df8b8667f6d231618d47a2ffc71d596e8e10e15cb02e translated
#[test]
fn accept_permission_add_and_remove() {
let h = harness();
assert!(block_on(h.process("@acceptpermission=add")).unwrap());
assert!(
h.service
.permissions()
.is_auto_accept_permissions()
.unwrap()
);
assert!(block_on(h.process("@acceptpermission=rem")).unwrap());
assert!(
!h.service
.permissions()
.is_auto_accept_permissions()
.unwrap()
);
}
// parity-case: LibreMetaverse.Tests/RLV/Exceptions/AcceptTpExceptionTests.cs::AcceptTpExceptionTests.CanAutoAcceptTp_User::test e988496e81a717eae1a96c5501e748a441fa64f637aaa47a6ae7a8d571c30f6e translated
#[test]
fn accept_tp_specific_user() {
let h = harness();
block_on(h.process(&format!("@accepttp:{USER_1}=add"))).unwrap();
let permissions = h.service.permissions();
assert!(
permissions
.is_auto_accept_tp(Some(Some(guid(USER_1))))
.unwrap()
);
assert!(
!permissions
.is_auto_accept_tp(Some(Some(guid(USER_2))))
.unwrap()
);
assert!(!permissions.is_auto_accept_tp(None).unwrap());
}
// parity-case: LibreMetaverse.Tests/RLV/Exceptions/AcceptTpExceptionTests.cs::AcceptTpExceptionTests.CanAutoAcceptTp_All::test 428ec184c9d09f6ec57ac3429180f327ed1b79e9d9dea9815df3bb6f0f6244fd translated
#[test]
fn accept_tp_all_users() {
let h = harness();
block_on(h.process("@accepttp=add")).unwrap();
let permissions = h.service.permissions();
assert!(
permissions
.is_auto_accept_tp(Some(Some(guid(USER_1))))
.unwrap()
);
assert!(
permissions
.is_auto_accept_tp(Some(Some(guid(USER_2))))
.unwrap()
);
assert!(permissions.is_auto_accept_tp(None).unwrap());
}
// parity-case: LibreMetaverse.Tests/RLV/Exceptions/AcceptTpRequestExceptionTests.cs::AcceptTpRequestExceptionTests.CanAutoAcceptTpRequest_User::test 3a5af1a55e74b5e75a04abc11826ded17c327ac2ed99ab2a423674fbb0e61f31 translated
#[test]
fn accept_tp_request_specific_user() {
let h = harness();
block_on(h.process(&format!("@accepttprequest:{USER_1}=add"))).unwrap();
let permissions = h.service.permissions();
assert!(
permissions
.is_auto_accept_tp_request(Some(Some(guid(USER_1))))
.unwrap()
);
assert!(
!permissions
.is_auto_accept_tp_request(Some(Some(guid(USER_2))))
.unwrap()
);
assert!(!permissions.is_auto_accept_tp_request(None).unwrap());
}
// parity-case: LibreMetaverse.Tests/RLV/Exceptions/AcceptTpRequestExceptionTests.cs::AcceptTpRequestExceptionTests.CanAutoAcceptTpRequest_All::test 8e2cf7c4d17dcec4d7855fc430092699416108966fb5d97c170c13f0bcd04cfe translated
#[test]
fn accept_tp_request_all_users() {
let h = harness();
block_on(h.process("@accepttprequest=add")).unwrap();
let permissions = h.service.permissions();
assert!(
permissions
.is_auto_accept_tp_request(Some(Some(guid(USER_1))))
.unwrap()
);
assert!(
permissions
.is_auto_accept_tp_request(Some(Some(guid(USER_2))))
.unwrap()
);
assert!(permissions.is_auto_accept_tp_request(None).unwrap());
}
// parity-case: LibreMetaverse.Tests/RLV/Exceptions/DenyPermissionExceptionTests.cs::DenyPermissionExceptionTests.DenyPermission::test c2284b63e7b4a93f8613a3afe34466d14e1c6ed8528656d54ae64ca6d081cdd5 translated
#[test]
fn deny_permission_add_and_remove() {
let h = harness();
assert!(block_on(h.process("@denypermission=add")).unwrap());
assert!(h.service.permissions().is_auto_deny_permissions().unwrap());
assert!(block_on(h.process("@denypermission=rem")).unwrap());
assert!(!h.service.permissions().is_auto_deny_permissions().unwrap());
}
// parity-case: LibreMetaverse.Tests/RLV/Exceptions/EditExceptionTests.cs::EditExceptionTests.CanEdit_Exception::test e435b03faef04dfe06d0cbec76e94cbf30e61ad7bc08502728f9239cf47292f8 translated
#[test]
fn edit_exception_allows_one_object() {
let h = harness();
process(&h, &["@edit=n".into(), format!("@edit:{USER_1}=add")]);
let permissions = h.service.permissions();
for location in [
ObjectLocation::Hud,
ObjectLocation::Attached,
ObjectLocation::RezzedInWorld,
] {
assert!(!permissions.can_edit(location, None).unwrap());
assert!(
permissions
.can_edit(location, Some(Some(guid(USER_1))))
.unwrap()
);
assert!(
!permissions
.can_edit(location, Some(Some(guid(USER_2))))
.unwrap()
);
}
}
// parity-case: LibreMetaverse.Tests/RLV/Exceptions/EditExceptionTests.cs::EditExceptionTests.CanEdit_Specific::test db097167497bc650c6729f0687924adedda7097b4089107fc5ea03716c1cb4e5 translated
#[test]
fn edit_object_restricts_only_one_object() {
let h = harness();
block_on(h.process(&format!("@editobj:{USER_1}=n"))).unwrap();
let permissions = h.service.permissions();
for location in [
ObjectLocation::Hud,
ObjectLocation::Attached,
ObjectLocation::RezzedInWorld,
] {
assert!(permissions.can_edit(location, None).unwrap());
assert!(
!permissions
.can_edit(location, Some(Some(guid(USER_1))))
.unwrap()
);
assert!(
permissions
.can_edit(location, Some(Some(guid(USER_2))))
.unwrap()
);
}
}
// parity-case: LibreMetaverse.Tests/RLV/Exceptions/EmoteExceptionTests.cs::EmoteExceptionTests.CanEmote::test a643401539d7258ae04ddebaf9c82876f59c4433b11ee61bfe8b416058c9fe38 translated
#[test]
fn emote_exception_add_and_remove() {
let h = harness();
block_on(h.process("@emote=n")).unwrap();
assert!(!h.service.permissions().can_emote().unwrap());
block_on(h.process("@emote=y")).unwrap();
assert!(h.service.permissions().can_emote().unwrap());
}
// parity-case: LibreMetaverse.Tests/RLV/Exceptions/RecvChatExceptionTests.cs::RecvChatExceptionTests.CanRecvChat_Except::test b34881785cf2df3d8f4e5ba971adcf2144d8de4db00acfbe136c79457742ec33 translated
#[test]
fn receive_chat_exception_allows_user_chat_and_emote() {
let h = harness();
let user = "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa";
process(&h, &["@recvchat=n".into(), format!("@recvchat:{user}=add")]);
assert!(
h.service
.permissions()
.can_receive_chat("Hello world".into(), guid(user))
.unwrap()
);
assert!(
h.service
.permissions()
.can_receive_chat("/me says Hello world".into(), guid(user))
.unwrap()
);
}
// parity-case: LibreMetaverse.Tests/RLV/Exceptions/RecvEmoteExceptionTests.cs::RecvEmoteExceptionTests.CanRecvChat_RecvEmote_Except::test d4647d71c02e05405ae2acf7b58522aae559b1c90a4f7a1521c9a9a383220f8a translated
#[test]
fn receive_emote_exception_only_allows_selected_user_emotes() {
let h = harness();
process(
&h,
&["@recvemote=n".into(), format!("@recvemote:{USER_1}=add")],
);
let permissions = h.service.permissions();
assert!(
permissions
.can_receive_chat("Hello world".into(), guid(USER_1))
.unwrap()
);
assert!(
permissions
.can_receive_chat("Hello world".into(), guid(USER_2))
.unwrap()
);
assert!(
permissions
.can_receive_chat("/me says Hello world".into(), guid(USER_1))
.unwrap()
);
assert!(
!permissions
.can_receive_chat("/me says Hello world".into(), guid(USER_2))
.unwrap()
);
}
fn im_exception_matches(command: &str, receive: bool, group: Option<&str>) -> bool {
let h = harness();
let behavior = if receive { "recvim" } else { "sendim" };
process(
&h,
&[
format!("@{behavior}=n"),
format!("@{behavior}:{command}=add"),
],
);
let user = Some(Some(guid(USER_1)));
if receive {
h.service
.permissions()
.can_receive_im("Hello world".into(), user, group.map(Into::into))
.unwrap()
} else {
h.service
.permissions()
.can_send_im("Hello world".into(), user, group.map(Into::into))
.unwrap()
}
}
// parity-case: LibreMetaverse.Tests/RLV/Exceptions/RecvImExceptionTests.cs::RecvImExceptionTests.CanReceiveIM_Exception::test 2e1afba517b29e8e7f2e0605340eb6e87443282857400eba259f0ebdf4874e23 translated
#[test]
fn receive_im_exception_for_user() {
assert!(im_exception_matches(USER_1, true, None));
}
// parity-case: LibreMetaverse.Tests/RLV/Exceptions/RecvImExceptionTests.cs::RecvImExceptionTests.CanReceiveIM_Exception_SingleGroup::test 9ec57daeed225caf960d00f0c83378d1836e86b1896063703ee1c3a38c7b582a translated
#[test]
fn receive_im_exception_for_group() {
assert!(im_exception_matches("Group Name", true, Some("Group Name")));
}
// parity-case: LibreMetaverse.Tests/RLV/Exceptions/RecvImExceptionTests.cs::RecvImExceptionTests.CanReceiveIM_Exception_AllGroups::test 633b8c680b583a6f8d80335c26f4ebcec77f9d8d5231e49bea562dcb66f00267 translated
#[test]
fn receive_im_exception_for_all_groups() {
assert!(im_exception_matches("allgroups", true, Some("Group name")));
}
fn redirect_channels_match(command: &str, expected: &[i32], emote: bool) -> bool {
let h = harness();
for channel in expected {
block_on(h.process(&format!("@{command}:{channel}=add"))).unwrap();
}
let mut channels = Vec::new();
let found = if emote {
h.service
.permissions()
.try_get_redir_emote_channels(&mut channels)
} else {
h.service
.permissions()
.try_get_redir_chat_channels(&mut channels)
};
found && channels == expected
}
// parity-case: LibreMetaverse.Tests/RLV/Exceptions/RedirChatExceptionTests.cs::RedirChatExceptionTests.IsRedirChat::test 1eb25c5579789db22ee242c4b52c65989bd26dce6d7577021c329c6c49be9414 translated
#[test]
fn redirect_chat_channel() {
assert!(redirect_channels_match("redirchat", &[1234], false));
}
// parity-case: LibreMetaverse.Tests/RLV/Exceptions/RedirChatExceptionTests.cs::RedirChatExceptionTests.IsRedirChat_Removed::test 62e03ff1db1e790d8bc1e38ac1495fc12723ba2eb5c9d6035d73c9fdb91a44ad translated
#[test]
fn redirect_chat_channel_removed() {
let h = harness();
process(
&h,
&["@redirchat:1234=add".into(), "@redirchat:1234=rem".into()],
);
assert!(
!h.service
.permissions()
.try_get_redir_chat_channels(&mut Vec::new())
);
}
// parity-case: LibreMetaverse.Tests/RLV/Exceptions/RedirChatExceptionTests.cs::RedirChatExceptionTests.IsRedirChat_MultipleChannels::test c7d0c428d121ab80eee9b6b5855cbe50e7a4cd74e81c369da09df04d55c7554f translated
#[test]
fn redirect_chat_multiple_channels() {
assert!(redirect_channels_match("redirchat", &[1234, 12345], false));
}
fn redirected_message_matches(
command: &str,
message: &str,
channels: &[i32],
expected: &[(i32, &str)],
) -> bool {
let h = harness();
for channel in channels {
block_on(h.process(&format!("@{command}:{channel}=add"))).unwrap();
}
block_on(h.service.report_send_public_message(message.into(), None)).unwrap();
let expected: Vec<_> = expected
.iter()
.map(|(channel, text)| (*channel, (*text).into()))
.collect();
h.actions.lock().unwrap().replies == expected
}
// parity-case: LibreMetaverse.Tests/RLV/Exceptions/RedirChatExceptionTests.cs::RedirChatExceptionTests.IsRedirChat_RedirectChat::test c4a083e495a578c1ed0855c43680d5b05144bf627f06df48c82e089e6f0699bf translated
#[test]
fn redirect_chat_sends_public_message() {
assert!(redirected_message_matches(
"redirchat",
"Hello World",
&[1234],
&[(1234, "Hello World")],
));
}
// parity-case: LibreMetaverse.Tests/RLV/Exceptions/RedirChatExceptionTests.cs::RedirChatExceptionTests.IsRedirChat_RedirectChatMultiple::test 5ff8665440d8d02e0aa900121e591034d51e2b48ca62fdec2fbc9135f8c83428 translated
#[test]
fn redirect_chat_sends_to_multiple_channels() {
assert!(redirected_message_matches(
"redirchat",
"Hello World",
&[1234, 5678],
&[(1234, "Hello World"), (5678, "Hello World")],
));
}
// parity-case: LibreMetaverse.Tests/RLV/Exceptions/RedirChatExceptionTests.cs::RedirChatExceptionTests.IsRedirChat_RedirectChatEmote::test 5d88009e3e8d365c52315a9b189f6cffdc9d04fdb70aa26bcc03d6bc16227189 translated
#[test]
fn redirect_chat_does_not_redirect_emote() {
assert!(redirected_message_matches(
"redirchat",
"/me says Hello World",
&[1234],
&[]
));
}
// parity-case: LibreMetaverse.Tests/RLV/Exceptions/RedirEmoteExceptionTests.cs::RedirEmoteExceptionTests.IsRedirEmote::test 02170a2b3eb0cbb88921517c9742d2fc0baaea7a621e5a3c3264a7a17d5efb61 translated
#[test]
fn redirect_emote_channel() {
assert!(redirect_channels_match("rediremote", &[1234], true));
}
// parity-case: LibreMetaverse.Tests/RLV/Exceptions/RedirEmoteExceptionTests.cs::RedirEmoteExceptionTests.IsRedirEmote_Removed::test 6ee89cedfd1e2d79d2447f2f48d1e2d1ac96295485b7509fe09f98e3bfcd9766 translated
#[test]
fn redirect_emote_channel_removed() {
let h = harness();
process(
&h,
&["@rediremote:1234=add".into(), "@rediremote:1234=rem".into()],
);
assert!(
!h.service
.permissions()
.try_get_redir_emote_channels(&mut Vec::new())
);
}
// parity-case: LibreMetaverse.Tests/RLV/Exceptions/RedirEmoteExceptionTests.cs::RedirEmoteExceptionTests.IsRedirEmote_MultipleChannels::test 1a95f4cc5db96cf033fed0c1a4e573b1cb1ac17ef72b76e0ce115c051f10528a translated
#[test]
fn redirect_emote_multiple_channels() {
assert!(redirect_channels_match("rediremote", &[1234, 12345], true));
}
// parity-case: LibreMetaverse.Tests/RLV/Exceptions/RedirEmoteExceptionTests.cs::RedirEmoteExceptionTests.IsRedirEmote_RedirectEmote::test 525297be5b5ff466fc9a61f2bc87af38bd637cbef8e0c794e897e021d0cca464 translated
#[test]
fn redirect_emote_sends_emote() {
assert!(redirected_message_matches(
"rediremote",
"/me says Hello World",
&[1234],
&[(1234, "/me says Hello World")],
));
}
// parity-case: LibreMetaverse.Tests/RLV/Exceptions/RedirEmoteExceptionTests.cs::RedirEmoteExceptionTests.IsRedirEmote_RedirectEmoteMultiple::test fd6af49a90e111ed6424c85565242e1205e13604b529909f7be0260e93f0b1c6 translated
#[test]
fn redirect_emote_sends_to_multiple_channels() {
let h = harness();
process(
&h,
&["@rediremote:1234=add".into(), "@rediremote:5678=n".into()],
);
block_on(
h.service
.report_send_public_message("/me says Hello World".into(), None),
)
.unwrap();
assert_eq!(
h.actions.lock().unwrap().replies,
vec![
(1234, "/me says Hello World".into()),
(5678, "/me says Hello World".into()),
]
);
}
// parity-case: LibreMetaverse.Tests/RLV/Exceptions/RedirEmoteExceptionTests.cs::RedirEmoteExceptionTests.IsRedirEmote_RedirectEmoteChat::test e8b78a6a34e3d3acdfc6d454b46a939d341260362ae5327dc4b70164d41431aa translated
#[test]
fn redirect_emote_does_not_redirect_chat() {
assert!(redirected_message_matches(
"rediremote",
"Hello World",
&[1234],
&[]
));
}
// parity-case: LibreMetaverse.Tests/RLV/Exceptions/SendChannelExceptExceptionTests.cs::SendChannelExceptExceptionTests.CanSendChannelExcept::test 08c309d08681fe067f67315a72014d0a05c87d6e14632fa04f6f2fb617d61be3 translated
#[test]
fn send_channel_exception_blocks_only_selected_channel() {
let h = harness();
block_on(h.process("@sendchannel_except:456=add")).unwrap();
assert!(
h.service
.permissions()
.can_chat(123, "Hello world".into())
.unwrap()
);
assert!(
!h.service
.permissions()
.can_chat(456, "Hello world".into())
.unwrap()
);
}
// parity-case: LibreMetaverse.Tests/RLV/Exceptions/SendChannelExceptionTests.cs::SendChannelExceptionTests.CanSendChannel_Exception::test 49bcacb6fb31d596ce9afc73099f8aaf645156ee222262174e1d7fed08393cf9 translated
#[test]
fn send_channel_adds_allowed_channel() {
let h = harness();
process(&h, &["@sendchannel=n".into(), "@sendchannel:123=n".into()]);
assert!(
h.service
.permissions()
.can_chat(123, "Hello world".into())
.unwrap()
);
}
// parity-case: LibreMetaverse.Tests/RLV/Exceptions/SendImExceptionTests.cs::SendImExceptionTests.CanSendIM_Exception::test 8124011921e8d4caf6840e960bd9f98d21df9db476e1726e0d54550cb8527ceb translated
#[test]
fn send_im_exception_for_user() {
assert!(im_exception_matches(USER_1, false, None));
}
// parity-case: LibreMetaverse.Tests/RLV/Exceptions/SendImExceptionTests.cs::SendImExceptionTests.CanSendIM_Exception_SingleGroup::test b55a4bdba1d33652f3809c3478047afc65757fbe1dec6c5292e17b71a04b206c translated
#[test]
fn send_im_exception_for_group() {
assert!(im_exception_matches(
"Group Name",
false,
Some("Group Name")
));
}
// parity-case: LibreMetaverse.Tests/RLV/Exceptions/SendImExceptionTests.cs::SendImExceptionTests.CanSendIM_Exception_AllGroups::test 4190ff51848f63dce5682317db79da23fa19ad9e53004534382f3eb6e8544788 translated
#[test]
fn send_im_exception_for_all_groups() {
assert!(im_exception_matches("allgroups", false, Some("Group name")));
}
fn nullable_user_exception(
behavior: &str,
permission: fn(
&libremetaverse_rlv::RlvPermissionsService,
Option<Option<libremetaverse_types::compat::Guid>>,
) -> Result<bool, libremetaverse_types::Error>,
) -> [bool; 3] {
let h = harness();
process(
&h,
&[
format!("@{behavior}=n"),
format!("@{behavior}:{USER_1}=add"),
],
);
let permissions = h.service.permissions();
[
permission(&permissions, None).unwrap(),
permission(&permissions, Some(Some(guid(USER_1)))).unwrap(),
permission(&permissions, Some(Some(guid(USER_2)))).unwrap(),
]
}
// parity-case: LibreMetaverse.Tests/RLV/Exceptions/ShareExceptionTests.cs::ShareExceptionTests.CanShare_Except::test 37297059a814bfde94c466e263a429258cce11ae258afd7953d26f65f9178f1d translated
#[test]
fn share_exception_for_user() {
assert_eq!(
nullable_user_exception(
"share",
libremetaverse_rlv::RlvPermissionsService::can_share,
),
[false, true, false]
);
}
// parity-case: LibreMetaverse.Tests/RLV/Exceptions/ShowNameTagsExceptionTests.cs::ShowNameTagsExceptionTests.CanShowNameTags_Except::test 5d1fe4ec1fa289623d473ffae1682ed725735cbdf48bdf5b7fed086237e32a1a translated
#[test]
fn show_name_tags_exception_for_user() {
assert_eq!(
nullable_user_exception(
"shownametags",
libremetaverse_rlv::RlvPermissionsService::can_show_name_tags,
),
[false, true, false]
);
}
// parity-case: LibreMetaverse.Tests/RLV/Exceptions/ShowNamesExceptionTests.cs::ShowNamesExceptionTests.CanShowNames_Except::test b11578e758631037440dd56a683a3ffc25b576eaa25e7388c950d8d647eb2a75 translated
#[test]
fn show_names_exception_for_user() {
assert_eq!(
nullable_user_exception(
"shownames",
libremetaverse_rlv::RlvPermissionsService::can_show_names,
),
[false, true, false]
);
}
// parity-case: LibreMetaverse.Tests/RLV/Exceptions/StartImExceptionTests.cs::StartImExceptionTests.CanStartIM_Exception::test e0001ffc665f0f39833cf2376ea1fcb7559bdb87a48ea60bb348e14b078880e4 translated
#[test]
fn start_im_exception_for_user() {
let h = harness();
process(&h, &["@startim=n".into(), format!("@startim:{USER_1}=add")]);
assert!(h.service.permissions().can_start_im(guid(USER_1)).unwrap());
assert!(!h.service.permissions().can_start_im(guid(USER_2)).unwrap());
}
// parity-case: LibreMetaverse.Tests/RLV/Exceptions/TouchMeExceptionTests.cs::TouchMeExceptionTests.TouchMe_default::test a0f3ffd3c70263738c074e258d9271e0a825f163c40d9c7ee8d20865873eb304 translated
#[test]
fn touch_me_exception_allows_sender_and_hud() {
let h = harness();
process(&h, &["@touchall=n".into(), "@touchme=add".into()]);
let object = guid(USER_1);
let sender = guid(SENDER_ID);
let user = Some(Some(guid("55555555-5555-4555-8555-555555555555")));
assert!(touch_matches(
&h,
TouchLocation::AttachedSelf,
object,
None,
None,
false
));
assert!(touch_matches(
&h,
TouchLocation::AttachedOther,
object,
user,
None,
false
));
assert!(touch_matches(
&h,
TouchLocation::RezzedInWorld,
object,
None,
Some(Some(5.0)),
false,
));
assert!(touch_matches(
&h,
TouchLocation::Hud,
object,
None,
None,
true
));
for (location, callback_user, distance) in [
(TouchLocation::AttachedSelf, None, None),
(TouchLocation::AttachedOther, user, None),
(TouchLocation::RezzedInWorld, None, Some(Some(5.0))),
(TouchLocation::Hud, None, None),
] {
assert!(touch_matches(
&h,
location,
sender,
callback_user,
distance,
true
));
}
}
// parity-case: LibreMetaverse.Tests/RLV/Exceptions/TouchThisExceptionTests.cs::TouchThisExceptionTests.TouchThis_default::test e7e6c9e14badb0159f81adc96e17fcf3ebe2cf5351ec6465f03c430de06d85d2 translated
#[test]
fn touch_this_exception_blocks_only_selected_prim() {
let h = harness();
block_on(h.process(&format!("@touchthis:{USER_1}=add"))).unwrap();
let user = Some(Some(guid("55555555-5555-4555-8555-555555555555")));
for (location, callback_user, distance) in [
(TouchLocation::AttachedSelf, None, None),
(TouchLocation::AttachedOther, user, None),
(TouchLocation::RezzedInWorld, None, Some(Some(5.0))),
(TouchLocation::Hud, None, None),
] {
assert!(touch_matches(
&h,
location,
guid(USER_1),
callback_user,
distance,
false
));
assert!(touch_matches(
&h,
location,
guid(USER_2),
callback_user,
distance,
true
));
}
}
// parity-case: LibreMetaverse.Tests/RLV/Exceptions/TouchWorldExceptionTests.cs::TouchWorldExceptionTests.TouchWorld_Exception::test ffef2f112b5718bab7b01fc1b624e588c181dadc5c50fd85de4404a501ee6f37 translated
#[test]
fn touch_world_exception_allows_selected_world_prim() {
let h = harness();
process(
&h,
&["@touchworld=n".into(), format!("@touchworld:{USER_2}=add")],
);
let user = Some(Some(guid("55555555-5555-4555-8555-555555555555")));
assert!(touch_matches(
&h,
TouchLocation::AttachedSelf,
guid(USER_1),
None,
None,
true,
));
assert!(touch_matches(
&h,
TouchLocation::AttachedOther,
guid(USER_1),
user,
None,
true,
));
assert!(touch_matches(
&h,
TouchLocation::RezzedInWorld,
guid(USER_1),
None,
Some(Some(5.0)),
false,
));
assert!(touch_matches(
&h,
TouchLocation::Hud,
guid(USER_1),
None,
None,
true
));
for (location, callback_user, distance) in [
(TouchLocation::AttachedSelf, None, None),
(TouchLocation::AttachedOther, user, None),
(TouchLocation::RezzedInWorld, None, Some(Some(5.0))),
(TouchLocation::Hud, None, None),
] {
assert!(touch_matches(
&h,
location,
guid(USER_2),
callback_user,
distance,
true
));
}
}
// parity-case: LibreMetaverse.Tests/RLV/Exceptions/TpLureExceptionTests.cs::TpLureExceptionTests.CanTpLure_Except::test a32f4cdda5b48ffcaced683b2e77fc129c1c321951aa2e16623eea022f2aa0b9 translated
#[test]
fn tp_lure_exception_for_user() {
assert_eq!(
nullable_user_exception(
"tplure",
libremetaverse_rlv::RlvPermissionsService::can_tp_lure,
),
[false, true, false]
);
}

View File

@@ -0,0 +1,253 @@
// Exact Rust translations of the recursive folder exception tests.
use libremetaverse_compat_tests::block_on;
use libremetaverse_compat_tests::rlv_support::{RlvHarness, SampleInventoryTree, guid};
use libremetaverse_rlv::{InventoryMap, RlvAttachmentPoint};
const PRIM: &str = "11111111-0003-4aaa-8aaa-ffffffffffff";
const HATS_EXCEPTED: [bool; 7] = [true, true, false, false, false, true, true];
const CLOTHING_EXCEPTED: [bool; 7] = [true; 7];
const NO_EXCEPTIONS: [bool; 7] = [false, false, false, false, false, true, true];
#[derive(Clone, Copy)]
enum Mode {
Attach,
Detach,
}
fn exception_case_matches(
commands: &[&str],
mode: Mode,
expected_items: [bool; 7],
expected_exception_counts: Option<[usize; 3]>,
) -> bool {
let h = RlvHarness::new().expect("RlvService constructor");
let mut tree = SampleInventoryTree::build().expect("sample inventory tree");
tree.business_pants
.set_attached_to(Some(Some(RlvAttachmentPoint::Pelvis)));
tree.business_pants
.set_attached_prim_id(Some(Some(guid(PRIM))));
let folder_ids = [tree.clothing.id(), tree.hats.id(), tree.sub_hats.id()];
h.queries.lock().unwrap().inventory_map = Some(InventoryMap::new(tree.root, vec![]).unwrap());
for command in commands {
if !block_on(h.process_from(command, PRIM, "Business Pants (Pelvis)")).unwrap() {
return false;
}
}
let permissions = h.service.permissions();
let actual = match mode {
Mode::Attach => [
permissions
.can_attach_with_rlv_inventory_item_boolean(tree.party_hat, true)
.unwrap(),
permissions
.can_attach_with_rlv_inventory_item_boolean(tree.fancy_hat, true)
.unwrap(),
permissions
.can_attach_with_rlv_inventory_item_boolean(tree.business_pants, true)
.unwrap(),
permissions
.can_attach_with_rlv_inventory_item_boolean(tree.happy_shirt, true)
.unwrap(),
permissions
.can_attach_with_rlv_inventory_item_boolean(tree.retro_pants, true)
.unwrap(),
permissions
.can_attach_with_rlv_inventory_item_boolean(tree.glasses, true)
.unwrap(),
permissions
.can_attach_with_rlv_inventory_item_boolean(tree.watch, true)
.unwrap(),
],
Mode::Detach => [
permissions
.can_detach_with_rlv_inventory_item(tree.party_hat)
.unwrap(),
permissions
.can_detach_with_rlv_inventory_item(tree.fancy_hat)
.unwrap(),
permissions
.can_detach_with_rlv_inventory_item(tree.business_pants)
.unwrap(),
permissions
.can_detach_with_rlv_inventory_item(tree.happy_shirt)
.unwrap(),
permissions
.can_detach_with_rlv_inventory_item(tree.retro_pants)
.unwrap(),
permissions
.can_detach_with_rlv_inventory_item(tree.glasses)
.unwrap(),
permissions
.can_detach_with_rlv_inventory_item(tree.watch)
.unwrap(),
],
};
if actual != expected_items {
return false;
}
if let Some(expected_counts) = expected_exception_counts {
let locked = h.service.restrictions().get_locked_folders().unwrap();
if locked.len() != 3 {
return false;
}
for (index, id) in folder_ids.iter().enumerate() {
let Some(folder) = locked.get(id) else {
return false;
};
let matches = folder.is_locked()
&& match mode {
Mode::Attach => {
folder.attach_exceptions().len() == expected_counts[index]
&& folder.attach_restrictions().len() == 1
&& folder.detach_exceptions().is_empty()
&& folder.detach_restrictions().is_empty()
}
Mode::Detach => {
folder.attach_exceptions().is_empty()
&& folder.attach_restrictions().is_empty()
&& folder.detach_exceptions().len() == expected_counts[index]
&& folder.detach_restrictions().len() == 1
}
};
if !matches {
return false;
}
}
}
true
}
// parity-case: LibreMetaverse.Tests/RLV/Exceptions/AttachAllThisExceptExceptionTests.cs::AttachAllThisExceptExceptionTests.AttachAllThis_Recursive_ExceptAll::test 1daa414beb2a767518f335f6ae59e711395375ed9d7912fbbc139fa0998dfdb1 translated
#[test]
fn attach_all_this_except_subtree() {
assert!(exception_case_matches(
&[
"@attachallthis=n",
"@attachallthis_except:Clothing/Hats=add",
],
Mode::Attach,
HATS_EXCEPTED,
Some([0, 1, 1]),
));
}
// parity-case: LibreMetaverse.Tests/RLV/Exceptions/AttachAllThisExceptExceptionTests.cs::AttachAllThisExceptExceptionTests.AttachAllThis_Recursive_ExceptAll_Recursive::test 6e0c78d6ed78bedca9a8c6a9a83fd9f90f7123da433eb4c560e6f5c0b6fe6d94 translated
#[test]
fn attach_all_this_except_recursive_subtree() {
assert!(exception_case_matches(
&["@attachallthis=n", "@attachallthis_except:Clothing=add"],
Mode::Attach,
CLOTHING_EXCEPTED,
Some([1, 1, 1]),
));
}
// parity-case: LibreMetaverse.Tests/RLV/Exceptions/AttachAllThisExceptExceptionTests.cs::AttachAllThisExceptExceptionTests.AttachAllThis_Recursive_ExceptAll_Recursive_AddRem::test 9423ed205501604501d31909414ecf6ef99a0d56d4efae100f5576b31b71a858 translated
#[test]
fn attach_all_this_recursive_exception_removed() {
assert!(exception_case_matches(
&[
"@attachallthis=n",
"@attachallthis_except:Clothing=add",
"@attachallthis_except:Clothing=rem",
],
Mode::Attach,
NO_EXCEPTIONS,
Some([0, 0, 0]),
));
}
// parity-case: LibreMetaverse.Tests/RLV/Exceptions/AttachThisExceptExceptionTests.cs::AttachThisExceptExceptionTests.AttachThisExcept_Default::test b8e6e55d8f2654429c9826e38ffc8522eec44ab2521891b68616db61ac662db0 translated
#[test]
fn attach_this_except_folder() {
assert!(exception_case_matches(
&["@attachallthis=n", "@attachthis_except:Clothing/Hats=add"],
Mode::Attach,
HATS_EXCEPTED,
Some([0, 1, 0]),
));
}
// parity-case: LibreMetaverse.Tests/RLV/Exceptions/AttachThisExceptExceptionTests.cs::AttachThisExceptExceptionTests.AttachThisExcept_AddRem::test 05bc7eab5dd02a0a3e60f85eb51b374623aaa29c9ce2b522748a3478b8ee44ea translated
#[test]
fn attach_this_exception_removed() {
assert!(exception_case_matches(
&[
"@attachallthis=n",
"@attachthis_except:Clothing/Hats=add",
"@attachthis_except:Clothing/Hats=rem",
],
Mode::Attach,
NO_EXCEPTIONS,
Some([0, 0, 0]),
));
}
// parity-case: LibreMetaverse.Tests/RLV/Exceptions/DetachAllThisExceptExceptionTests.cs::DetachAllThisExceptExceptionTests.DetachAllThis_Recursive_ExceptAll::test 75e7ab22f6d9d058580fd83741d65f7e5babb7ad54805eaeb16bec8cd65370ed translated
#[test]
fn detach_all_this_except_subtree() {
assert!(exception_case_matches(
&[
"@detachallthis=n",
"@detachallthis_except:Clothing/Hats=add",
],
Mode::Detach,
HATS_EXCEPTED,
None,
));
}
// parity-case: LibreMetaverse.Tests/RLV/Exceptions/DetachAllThisExceptExceptionTests.cs::DetachAllThisExceptExceptionTests.DetachAllThis_Recursive_ExceptAll_Recursive::test 3fb8bb13d6a917d9be18265d90767488cde66746badc6584025bbbaf84f020ad translated
#[test]
fn detach_all_this_except_recursive_subtree() {
assert!(exception_case_matches(
&["@detachallthis=n", "@detachallthis_except:Clothing=add"],
Mode::Detach,
CLOTHING_EXCEPTED,
Some([1, 1, 1]),
));
}
// parity-case: LibreMetaverse.Tests/RLV/Exceptions/DetachAllThisExceptExceptionTests.cs::DetachAllThisExceptExceptionTests.DetachAllThis_Recursive_ExceptAll_Recursive_AddRem::test fb5fd8a4eda181d22d1756ec0cae700c4b90895a74dc79c24c67c1705cfd37c8 translated
#[test]
fn detach_all_this_recursive_exception_removed() {
assert!(exception_case_matches(
&[
"@detachallthis=n",
"@detachallthis_except:Clothing=add",
"@detachallthis_except:Clothing=rem",
],
Mode::Detach,
NO_EXCEPTIONS,
Some([0, 0, 0]),
));
}
// parity-case: LibreMetaverse.Tests/RLV/Exceptions/DetachThisExceptExceptionTests.cs::DetachThisExceptExceptionTests.DetachAllThis_Recursive_Except::test 3222d97d73d8b54bd11212f8cd3de26279040321f0bc330e061ff93880053f3e translated
#[test]
fn detach_this_except_folder() {
assert!(exception_case_matches(
&["@detachallthis=n", "@detachthis_except:Clothing/Hats=add"],
Mode::Detach,
HATS_EXCEPTED,
Some([0, 1, 0]),
));
}
// parity-case: LibreMetaverse.Tests/RLV/Exceptions/DetachThisExceptExceptionTests.cs::DetachThisExceptExceptionTests.DetachAllThis_Recursive_Except_AddRem::test d25b2c533b9b51428c0c2414d687c466a3c80c4a573dd36763504de19e8dc6f8 translated
#[test]
fn detach_this_exception_removed() {
assert!(exception_case_matches(
&[
"@detachallthis=n",
"@detachthis_except:Clothing/Hats=add",
"@detachthis_except:Clothing/Hats=rem",
],
Mode::Detach,
NO_EXCEPTIONS,
Some([0, 0, 0]),
));
}

View File

@@ -0,0 +1,269 @@
// Exact Rust translation of LibreMetaverse.Tests/RLV/InventoryMapTests.cs.
use libremetaverse_compat_tests::rlv_support::{SampleInventoryTree, guid};
use libremetaverse_rlv::{InventoryMap, RlvAttachmentPoint, RlvWearableType};
fn path_matches(
clothing_name: Option<&str>,
hats_name: Option<&str>,
path: &str,
skip_private: bool,
expected: Option<&str>,
) -> bool {
let mut tree = SampleInventoryTree::build().expect("sample inventory tree");
if let Some(name) = clothing_name {
tree.clothing.set_name(name.into());
}
if let Some(name) = hats_name {
tree.hats.set_name(name.into());
}
let expected_id = expected.map(|folder| match folder {
"clothing" => tree.clothing.id(),
"hats" => tree.hats.id(),
_ => unreachable!(),
});
let map = InventoryMap::new(tree.root, vec![]).unwrap();
let mut found = None;
map.try_get_folder_from_path(path.into(), skip_private, &mut found) == expected_id.is_some()
&& found.map(|folder| folder.id()) == expected_id
}
fn folder_ids(
folders: impl Iterator<Item = libremetaverse_rlv::RlvSharedFolder>,
) -> Vec<libremetaverse_types::compat::Guid> {
let mut ids: Vec<_> = folders.map(|folder| folder.id()).collect();
ids.sort_by_key(|id| id.0);
ids
}
// parity-case: LibreMetaverse.Tests/RLV/InventoryMapTests.cs::InventoryMapTests.TryGetFolderFromPath_Normal::test 97787ac6b51198e317ed391e91125724ce1b580924c40500f81186812b45f625 translated
#[test]
fn try_get_folder_from_normal_path() {
assert!(path_matches(
None,
None,
"Clothing/Hats",
true,
Some("hats")
));
}
// parity-case: LibreMetaverse.Tests/RLV/InventoryMapTests.cs::InventoryMapTests.TryGetFolderFromPath_EmptyPath::test 0ffd4f32e285ba94e94f63ac312d3be20bf144b769e8d18af32e15f481042ed7 translated
#[test]
fn try_get_folder_rejects_empty_path() {
assert!(path_matches(None, None, "", true, None));
}
// parity-case: LibreMetaverse.Tests/RLV/InventoryMapTests.cs::InventoryMapTests.TryGetFolderFromPath_FolderNameContainsForwardSlash::test 90ae520739ea1a2612f491bb110b0870ed4dcb8a983aad9526ed25d8c5cbe687 translated
#[test]
fn try_get_folder_when_name_contains_slash() {
assert!(path_matches(
Some("Clo/thing"),
None,
"Clo/thing/Hats",
true,
Some("hats"),
));
}
// parity-case: LibreMetaverse.Tests/RLV/InventoryMapTests.cs::InventoryMapTests.TryGetFolderFromPath_FolderNameContainsForwardSlashes::test 8c0ed3c6cc16b916f9df8d25d55618e82299fd1bcd66983f682219c338853028 translated
#[test]
fn try_get_folder_when_names_contain_multiple_slashes() {
assert!(path_matches(
Some("/Clo//thing//"),
Some("//h/ats/"),
"/Clo//thing/////h/ats/",
true,
Some("hats"),
));
}
// parity-case: LibreMetaverse.Tests/RLV/InventoryMapTests.cs::InventoryMapTests.TryGetFolderFromPath_FolderNameWithSlashPrefix::test 8a86081d6b25ae50b3cf8cdcb1c58c8539264931ab74f395dfc7345ee7f4f861 translated
#[test]
fn try_get_folder_with_slash_prefix() {
assert!(path_matches(
Some("/Clothing"),
None,
"/Clothing",
true,
Some("clothing")
));
}
// parity-case: LibreMetaverse.Tests/RLV/InventoryMapTests.cs::InventoryMapTests.TryGetFolderFromPath_FolderNameWithSlashSuffix::test 04afafa569b7a10d6add8c1e9d8f26ac502791f1da2dbdb3e37407e945c87872 translated
#[test]
fn try_get_folder_with_slash_suffix() {
assert!(path_matches(
Some("Clothing/"),
None,
"Clothing/",
true,
Some("clothing")
));
}
// parity-case: LibreMetaverse.Tests/RLV/InventoryMapTests.cs::InventoryMapTests.TryGetFolderFromPath_FolderNameWithSlashAffix::test 7eaec38fa6b545f133748b502169fab575308c9c4e60548cfbfd704452bd9761 translated
#[test]
fn try_get_folder_with_slash_affix() {
assert!(path_matches(
Some("/Clothing/"),
None,
"/Clothing/",
true,
Some("clothing"),
));
}
// parity-case: LibreMetaverse.Tests/RLV/InventoryMapTests.cs::InventoryMapTests.TryGetFolderFromPath_ContendingFoldersWithSlashes::test 96a8189266746a564072122342f36b3321998f3e0cbe0094f3e4c83d29bc53d5 translated
#[test]
fn try_get_folder_prefers_exact_slash_match() {
let mut tree = SampleInventoryTree::build().unwrap();
tree.root
.add_child(
guid("12345678-0001-4ddd-8ddd-dddddddddddd"),
"Clothing".into(),
)
.unwrap();
tree.root
.add_child(
guid("12345678-0002-4ddd-8ddd-dddddddddddd"),
"+Clothing///".into(),
)
.unwrap();
tree.root
.add_child(
guid("12345678-0003-4ddd-8ddd-dddddddddddd"),
"+Clothing///".into(),
)
.unwrap();
tree.clothing.set_name("Clothing///".into());
tree.hats.set_name("//h/ats/".into());
let expected = tree.hats.id();
let map = InventoryMap::new(tree.root, vec![]).unwrap();
let mut found = None;
assert!(map.try_get_folder_from_path("Clothing//////h/ats/".into(), true, &mut found,));
assert_eq!(found.unwrap().id(), expected);
}
// parity-case: LibreMetaverse.Tests/RLV/InventoryMapTests.cs::InventoryMapTests.TryGetFolderFromPath_InvalidPath::test 547def910ded67bc7950b211ad929f775d4eff26e351d11612f146b3e863510e translated
#[test]
fn try_get_folder_rejects_invalid_path() {
assert!(path_matches(None, None, "Clothing/Hats123", true, None));
}
// parity-case: LibreMetaverse.Tests/RLV/InventoryMapTests.cs::InventoryMapTests.TryGetFolderFromPath_IgnoreFolderPrefix::test 5039b79496d215d3921427ab6f65867ba7a4ea5239864f1f5a1e38ea3e5bb426 translated
#[test]
fn try_get_folder_ignores_tilde_and_plus_prefixes() {
assert!(path_matches(
Some("~Clothing"),
Some("+Hats"),
"Clothing/Hats",
true,
Some("hats"),
));
}
// parity-case: LibreMetaverse.Tests/RLV/InventoryMapTests.cs::InventoryMapTests.TryGetFolderFromPath_FailOnHiddenFolder::test bb0c7e531584128d251b06a4ac23b8cfad16ec4b117be79a53dea3c54aed4510 translated
#[test]
fn try_get_folder_skips_hidden_folder() {
assert!(path_matches(
Some(".Clothing"),
None,
".Clothing",
true,
None
));
}
// parity-case: LibreMetaverse.Tests/RLV/InventoryMapTests.cs::InventoryMapTests.TryGetFolderFromPath_AllowHiddenFolder::test 9217cb5bd9c325fc792303e5ab53cefd71e95a5acf9e5a1601957ba8bf807346 translated
#[test]
fn try_get_folder_allows_hidden_folder() {
assert!(path_matches(
Some(".Clothing"),
None,
".Clothing",
false,
Some("clothing"),
));
}
// parity-case: LibreMetaverse.Tests/RLV/InventoryMapTests.cs::InventoryMapTests.FindFoldersContaining_ById::test fc89036c3472dcc2ea4d3fcb55636238e3d2c75b490f46d328b5f91f28301ed0 translated
#[test]
fn find_folders_containing_by_prim_id() {
let mut tree = SampleInventoryTree::build().unwrap();
let prim = guid("11111111-0002-4aaa-8aaa-ffffffffffff");
tree.party_hat
.set_attached_to(Some(Some(RlvAttachmentPoint::Spine)));
tree.party_hat.set_attached_prim_id(Some(Some(prim)));
let expected = vec![tree.hats.id()];
let map = InventoryMap::new(tree.root, vec![]).unwrap();
assert_eq!(
folder_ids(
map.find_folders_containing(false, Some(Some(prim)), None, None)
.unwrap()
),
expected
);
}
// parity-case: LibreMetaverse.Tests/RLV/InventoryMapTests.cs::InventoryMapTests.FindFoldersContaining_ByAttachmentType::test 90b36c29312b87c824c158987e551ca31522cf53a68f5f6bd3eae8fe03e914ed translated
#[test]
fn find_folders_containing_by_attachment_point() {
let mut tree = SampleInventoryTree::build().unwrap();
tree.happy_shirt
.set_attached_to(Some(Some(RlvAttachmentPoint::Chin)));
tree.happy_shirt
.set_attached_prim_id(Some(Some(guid("11111111-0001-4aaa-8aaa-ffffffffffff"))));
tree.fancy_hat
.set_attached_to(Some(Some(RlvAttachmentPoint::Chin)));
tree.fancy_hat
.set_attached_prim_id(Some(Some(guid("11111111-0003-4aaa-8aaa-ffffffffffff"))));
let mut expected = vec![tree.clothing.id(), tree.hats.id()];
expected.sort_by_key(|id| id.0);
let map = InventoryMap::new(tree.root, vec![]).unwrap();
assert_eq!(
folder_ids(
map.find_folders_containing(false, None, Some(Some(RlvAttachmentPoint::Chin)), None,)
.unwrap()
),
expected
);
}
// parity-case: LibreMetaverse.Tests/RLV/InventoryMapTests.cs::InventoryMapTests.FindFoldersContaining_ByAttachmentType_SingleResult::test a973bf8087abb0c68cd80d76949fac2735474bf6ccbe743933051f60527d93ce translated
#[test]
fn find_folders_containing_by_attachment_point_single_result() {
let mut tree = SampleInventoryTree::build().unwrap();
tree.happy_shirt
.set_attached_to(Some(Some(RlvAttachmentPoint::Chin)));
tree.fancy_hat
.set_attached_to(Some(Some(RlvAttachmentPoint::Chin)));
let expected = vec![tree.hats.id()];
let map = InventoryMap::new(tree.root, vec![]).unwrap();
assert_eq!(
folder_ids(
map.find_folders_containing(true, None, Some(Some(RlvAttachmentPoint::Chin)), None,)
.unwrap()
),
expected
);
}
// parity-case: LibreMetaverse.Tests/RLV/InventoryMapTests.cs::InventoryMapTests.FindFoldersContaining_ByWearType::test d6712cbeacd6ddf25a1f76dc1eeb10f4c0d8967a7591c249127f9b6387f0df8a translated
#[test]
fn find_folders_containing_by_wearable_type() {
let mut tree = SampleInventoryTree::build().unwrap();
tree.happy_shirt
.set_worn_on(Some(Some(RlvWearableType::Pants)));
tree.fancy_hat
.set_worn_on(Some(Some(RlvWearableType::Hair)));
let expected = vec![tree.clothing.id()];
let map = InventoryMap::new(tree.root, vec![]).unwrap();
assert_eq!(
folder_ids(
map.find_folders_containing(false, None, None, Some(Some(RlvWearableType::Pants)),)
.unwrap()
),
expected
);
}

View File

@@ -0,0 +1,782 @@
//! Exact Rust translations of the RLV inventory-query tests.
use libremetaverse_compat_tests::block_on;
use libremetaverse_compat_tests::rlv_support::{RlvHarness, SampleInventoryTree, guid};
use libremetaverse_rlv::{InventoryMap, RlvAttachmentPoint, RlvInventoryItem, RlvWearableType};
const PRIM1: &str = "11111111-0001-4aaa-8aaa-ffffffffffff";
const PRIM2: &str = "11111111-0002-4aaa-8aaa-ffffffffffff";
const PRIM3: &str = "11111111-0003-4aaa-8aaa-ffffffffffff";
const PRIM4: &str = "11111111-0004-4aaa-8aaa-ffffffffffff";
const PRIM5: &str = "11111111-0005-4aaa-8aaa-ffffffffffff";
fn harness() -> RlvHarness {
RlvHarness::new().expect("RlvService constructor")
}
fn install_inventory(h: &RlvHarness, tree: SampleInventoryTree, external: Vec<RlvInventoryItem>) {
h.queries.lock().unwrap().inventory_map = Some(InventoryMap::new(tree.root, external).unwrap());
}
fn query_matches(h: &RlvHarness, command: &str, expected: &str) -> bool {
block_on(h.process(command)).unwrap()
&& h.actions.lock().unwrap().replies == vec![(1234, expected.into())]
}
fn external_item(
id: &str,
name: &str,
folder: &str,
point: Option<RlvAttachmentPoint>,
prim: Option<&str>,
wearable: Option<RlvWearableType>,
) -> RlvInventoryItem {
RlvInventoryItem::new(
guid(id),
name.into(),
false,
Some(Some(guid(folder))),
point.map(Some),
prim.map(|id| Some(guid(id))),
wearable.map(Some),
None,
)
.unwrap()
}
fn empty_tree_query(command: &str, expected: &str) -> bool {
let h = harness();
install_inventory(&h, SampleInventoryTree::build().unwrap(), vec![]);
query_matches(&h, command, expected)
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/FindFolderQueryTests.cs::FindFolderQueryTests.FindFolder_MultipleTerms::test a1f04e5ab064772c25feefc21ea57d65b1044f0fa3254aeb2a3bfedf68d8e0ca translated
#[test]
fn find_folder_multiple_terms() {
assert!(empty_tree_query(
"@findfolder:at&&ub=1234",
"Clothing/Hats/Sub Hats"
));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/FindFolderQueryTests.cs::FindFolderQueryTests.FindFolder_SearchOrder::test 4cba32dd316f49713c18a71bf5a932e1c28c94944add38c25852e8611ef0f987 translated
#[test]
fn find_folder_search_order() {
assert!(empty_tree_query("@findfolder:at=1234", "Clothing/Hats"));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/FindFolderQueryTests.cs::FindFolderQueryTests.FindFolder_IgnorePrivate::test 54c5ec1f6a6ae5611221e3afdc47db0c2d0ecb0da460dd8f2c506ed34c221ff8 translated
#[test]
fn find_folder_ignores_private_folder() {
let h = harness();
let mut tree = SampleInventoryTree::build().unwrap();
tree.hats.set_name(".Hats".into());
install_inventory(&h, tree, vec![]);
assert!(query_matches(&h, "@findfolder:at=1234", ""));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/FindFolderQueryTests.cs::FindFolderQueryTests.FindFolder_IgnoreTildePrefix::test 9f6635f5e14dbc14d1592a19b62d67748a60201128a75893e47ea1751c83b6d7 translated
#[test]
fn find_folder_ignores_tilde_prefixed_folder() {
let h = harness();
let mut tree = SampleInventoryTree::build().unwrap();
tree.hats.set_name("~Hats".into());
install_inventory(&h, tree, vec![]);
assert!(query_matches(&h, "@findfolder:at=1234", ""));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/FindFoldersQueryTests.cs::FindFoldersQueryTests.FindFolders::test 09dbc17be4b28cc4a63d0f837960586ba7cd03e184f0013b26ed27db15703d84 translated
#[test]
fn find_folders() {
assert!(empty_tree_query(
"@findfolders:at=1234",
"Clothing/Hats,Clothing/Hats/Sub Hats",
));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/FindFoldersQueryTests.cs::FindFoldersQueryTests.FindFolders_Separator::test 51caa783dded41b99c878066618a10a7fe32c681ef4385c9a72f154870312b1f translated
#[test]
fn find_folders_with_separator() {
assert!(empty_tree_query(
"@findfolders:at; AND =1234",
"Clothing/Hats AND Clothing/Hats/Sub Hats",
));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/GetAttachQueryTests.cs::GetAttachQueryTests.GetAttach_WearingNothing::test 41fc967c6c174ac39ce3f6de7e273e6db1845bc2ad6acd393f27a6705a3555df translated
#[test]
fn get_attach_wearing_nothing() {
assert!(empty_tree_query(
"@getattach=1234",
"00000000000000000000000000000000000000000000000000000000",
));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/GetAttachQueryTests.cs::GetAttachQueryTests.GetAttach_ExternalItems::test 3f8e640aad5deeaf00b07af2d12c33b0a93257260d057d7b5dd5488f846f467a translated
#[test]
fn get_attach_external_items() {
let h = harness();
let tree = SampleInventoryTree::build().unwrap();
let folder = "12312312-aaaa-4aaa-8aaa-aaaaaaaaaaaa";
install_inventory(
&h,
tree,
vec![
external_item(
"12312312-0001-4aaa-8aaa-aaaaaaaaaaaa",
"External Tattoo",
folder,
None,
None,
Some(RlvWearableType::Tattoo),
),
external_item(
"12312312-0002-4aaa-8aaa-aaaaaaaaaaaa",
"External Jaw Thing",
folder,
Some(RlvAttachmentPoint::Jaw),
Some("12312312-0002-4aaa-8aaa-ffffffffffff"),
None,
),
],
);
assert!(query_matches(
&h,
"@getattach=1234",
"00000000000000000000000000000000000000000000000100000000",
));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/GetAttachQueryTests.cs::GetAttachQueryTests.GetAttach_WearingSomeItems::test c209cd826958306f1350a685b29985cb8335a55ebcb9c0bec5c5a21279bb0a1a translated
#[test]
fn get_attach_wearing_some_items() {
let h = harness();
let tree = SampleInventoryTree::build().unwrap();
let folder = "cccccccc-cccc-4ccc-8ccc-cccccccccccc";
install_inventory(
&h,
tree,
vec![
external_item(
"c0000000-cccc-4ccc-8ccc-cccccccccccc",
"My Socks",
folder,
Some(RlvAttachmentPoint::LeftFoot),
Some("c0000000-cccc-4ccc-8ccc-ffffffffffff"),
None,
),
external_item(
"c0000001-cccc-4ccc-8ccc-cccccccccccc",
"My Hair",
folder,
Some(RlvAttachmentPoint::Skull),
Some("c0000001-cccc-4ccc-8ccc-ffffffffffff"),
None,
),
],
);
assert!(query_matches(
&h,
"@getattach=1234",
"00100001000000000000000000000000000000000000000000000000",
));
}
const ATTACHMENT_POINTS: [RlvAttachmentPoint; 56] = [
RlvAttachmentPoint::Default,
RlvAttachmentPoint::Chest,
RlvAttachmentPoint::Skull,
RlvAttachmentPoint::LeftShoulder,
RlvAttachmentPoint::RightShoulder,
RlvAttachmentPoint::LeftHand,
RlvAttachmentPoint::RightHand,
RlvAttachmentPoint::LeftFoot,
RlvAttachmentPoint::RightFoot,
RlvAttachmentPoint::Spine,
RlvAttachmentPoint::Pelvis,
RlvAttachmentPoint::Mouth,
RlvAttachmentPoint::Chin,
RlvAttachmentPoint::LeftEar,
RlvAttachmentPoint::RightEar,
RlvAttachmentPoint::LeftEyeball,
RlvAttachmentPoint::RightEyeball,
RlvAttachmentPoint::Nose,
RlvAttachmentPoint::RightUpperArm,
RlvAttachmentPoint::RightForearm,
RlvAttachmentPoint::LeftUpperArm,
RlvAttachmentPoint::LeftForearm,
RlvAttachmentPoint::RightHip,
RlvAttachmentPoint::RightUpperLeg,
RlvAttachmentPoint::RightLowerLeg,
RlvAttachmentPoint::LeftHip,
RlvAttachmentPoint::LeftUpperLeg,
RlvAttachmentPoint::LeftLowerLeg,
RlvAttachmentPoint::Stomach,
RlvAttachmentPoint::LeftPec,
RlvAttachmentPoint::RightPec,
RlvAttachmentPoint::HUDCenter2,
RlvAttachmentPoint::HUDTopRight,
RlvAttachmentPoint::HUDTop,
RlvAttachmentPoint::HUDTopLeft,
RlvAttachmentPoint::HUDCenter,
RlvAttachmentPoint::HUDBottomLeft,
RlvAttachmentPoint::HUDBottom,
RlvAttachmentPoint::HUDBottomRight,
RlvAttachmentPoint::Neck,
RlvAttachmentPoint::AvatarCenter,
RlvAttachmentPoint::LeftHandRing,
RlvAttachmentPoint::RightHandRing,
RlvAttachmentPoint::TailBase,
RlvAttachmentPoint::TailTip,
RlvAttachmentPoint::LeftWing,
RlvAttachmentPoint::RightWing,
RlvAttachmentPoint::Jaw,
RlvAttachmentPoint::AltLeftEar,
RlvAttachmentPoint::AltRightEar,
RlvAttachmentPoint::AltLeftEye,
RlvAttachmentPoint::AltRightEye,
RlvAttachmentPoint::Tongue,
RlvAttachmentPoint::Groin,
RlvAttachmentPoint::LeftHindFoot,
RlvAttachmentPoint::RightHindFoot,
];
// parity-case: LibreMetaverse.Tests/RLV/Queries/GetAttachQueryTests.cs::GetAttachQueryTests.GetAttach_WearingEverything::test 4adb25030cd3c125242a4b1f770bfd3afdcabd85c23d37c34df9c8f273489e5b translated
#[test]
fn get_attach_wearing_everything() {
let h = harness();
let tree = SampleInventoryTree::build().unwrap();
let folder = "99999999-9999-4999-8999-999999999999";
let external = ATTACHMENT_POINTS
.into_iter()
.map(|point| {
external_item(
&format!("c{:07}-cccc-4ccc-8ccc-cccccccccccc", point as i32),
&format!("External {point:?}"),
folder,
Some(point),
Some(PRIM1),
None,
)
})
.collect();
install_inventory(&h, tree, external);
assert!(query_matches(
&h,
"@getattach=1234",
"11111111111111111111111111111111111111111111111111111111",
));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/GetAttachQueryTests.cs::GetAttachQueryTests.GetAttach_Specific_Exists::test 7d8ccf26629911b6b20dc26c5c549975827d7378b4d85259a8b9724a3622892b translated
#[test]
fn get_attach_specific_exists() {
let h = harness();
let tree = SampleInventoryTree::build().unwrap();
install_inventory(
&h,
tree,
vec![external_item(
"c0000000-cccc-4ccc-8ccc-cccccccccccc",
"My Socks",
"cccccccc-cccc-4ccc-8ccc-cccccccccccc",
Some(RlvAttachmentPoint::LeftFoot),
Some("c0000000-cccc-4ccc-8ccc-ffffffffffff"),
None,
)],
);
assert!(query_matches(&h, "@getattach:left foot=1234", "1"));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/GetAttachQueryTests.cs::GetAttachQueryTests.GetAttach_Specific_NotExists::test 08d9852205987a266608ad17c12fa498894d7c3216e873cffb9db4584cfd100d translated
#[test]
fn get_attach_specific_not_exists() {
let h = harness();
let tree = SampleInventoryTree::build().unwrap();
install_inventory(
&h,
tree,
vec![external_item(
"c0000001-cccc-4ccc-8ccc-cccccccccccc",
"My Hair",
"cccccccc-cccc-4ccc-8ccc-cccccccccccc",
Some(RlvAttachmentPoint::Skull),
Some("c0000001-cccc-4ccc-8ccc-ffffffffffff"),
None,
)],
);
assert!(query_matches(&h, "@getattach:left foot=1234", "0"));
}
fn get_inv(command: &str, expected: &str) -> bool {
empty_tree_query(command, expected)
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/GetInvQueryTests.cs::GetInvQueryTests.GetInv::test 7476602b4103b47ed7dff44146a7ba90a1d62dc0d502f7b9e37b7863d9441ceb translated
#[test]
fn get_inventory_root() {
assert!(get_inv("@getinv=1234", "Clothing,Accessories"));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/GetInvQueryTests.cs::GetInvQueryTests.GetInv_Outfits::test d60a78bb35cc8fcdbdc2465889333b25567ea5e1c9279a8fb7b4162f4a35eae2 translated
#[test]
fn get_inventory_outfits() {
let h = harness();
let tree = SampleInventoryTree::build().unwrap();
let outfits = tree
.root
.add_child(
guid("12312399-9999-4999-8999-999999999999"),
".outfits".into(),
)
.unwrap();
outfits
.add_child(
guid("12312399-0001-4999-8999-999999999999"),
"First outfit".into(),
)
.unwrap();
outfits
.add_child(
guid("12312399-0002-4999-8999-999999999999"),
"Second outfit".into(),
)
.unwrap();
outfits
.add_item(
guid("12312399-0001-0001-8999-999999999999"),
"First Item".into(),
false,
None,
None,
None,
None,
)
.unwrap();
outfits
.add_item(
guid("12312399-0001-0002-8999-999999999999"),
"Second Item".into(),
false,
None,
None,
None,
None,
)
.unwrap();
install_inventory(&h, tree, vec![]);
assert!(query_matches(
&h,
"@getinv:.outfits=1234",
"First outfit,Second outfit"
));
}
fn get_my_outfits(command: &str) -> bool {
let h = harness();
let tree = SampleInventoryTree::build().unwrap();
let outfits = tree
.root
.add_child(
guid("12312399-9999-4999-8999-999999999999"),
"~MyOutfits".into(),
)
.unwrap();
outfits
.add_child(
guid("12312399-0001-4999-8999-999999999999"),
"First outfit".into(),
)
.unwrap();
install_inventory(&h, tree, vec![]);
query_matches(&h, command, "First outfit")
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/GetInvQueryTests.cs::GetInvQueryTests.GetInv_Outfits_IgnoreLeadingSlash::test add33ed33e1940f26362332b89486253c6af1a56e601bafab49511b6607ed50a translated
#[test]
fn get_inventory_ignores_leading_slash() {
assert!(get_my_outfits("@getinv:/~MyOutfits=1234"));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/GetInvQueryTests.cs::GetInvQueryTests.GetInv_Outfits_IgnoreTrailingSlash::test 8f89302126be19f89d075d87d5194cc000fb7819f92ea7d54e6a63c1df9ca1ee translated
#[test]
fn get_inventory_ignores_trailing_slash() {
assert!(get_my_outfits("@getinv:~MyOutfits/=1234"));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/GetInvQueryTests.cs::GetInvQueryTests.GetInv_Outfits_IgnoreLeadingAndTrailingSlash::test c660447f93fb8508dbe4c874c92fd776a6e13596bbe3036bfb4664e35ee22306 translated
#[test]
fn get_inventory_ignores_leading_and_trailing_slash() {
assert!(get_my_outfits("@getinv:/~MyOutfits/=1234"));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/GetInvQueryTests.cs::GetInvQueryTests.GetInv_Outfits_Inventory::test 7db6f75e2f109d0e8d852d181ddd721f688e27144ad8a5604384b37de9f8c3eb translated
#[test]
fn get_inventory_outfit_items_are_not_folders() {
let h = harness();
let tree = SampleInventoryTree::build().unwrap();
let outfits = tree
.root
.add_child(
guid("12312399-9999-4999-8999-999999999999"),
".outfits".into(),
)
.unwrap();
let first = outfits
.add_child(
guid("12312399-0001-4999-8999-999999999999"),
"First outfit".into(),
)
.unwrap();
first
.add_item(
guid("12312399-0001-0001-8999-999999999999"),
"First Item".into(),
false,
None,
None,
None,
None,
)
.unwrap();
first
.add_item(
guid("12312399-0001-0002-8999-999999999999"),
"Second Item".into(),
false,
None,
None,
None,
None,
)
.unwrap();
install_inventory(&h, tree, vec![]);
assert!(query_matches(&h, "@getinv:.outfits/First outfit=1234", ""));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/GetInvQueryTests.cs::GetInvQueryTests.GetInv_Subfolder::test 6a5effe8012e9a446021b83f9b5314f6f9b66587222b447fa79028582830b3a1 translated
#[test]
fn get_inventory_subfolder() {
assert!(get_inv("@getinv:Clothing/Hats=1234", "Sub Hats"));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/GetInvQueryTests.cs::GetInvQueryTests.GetInv_Empty::test 2dd9f242eb71826066482ff4faa80b952ef89f855723cdc0c01cc4714abf8751 translated
#[test]
fn get_inventory_empty_folder() {
assert!(get_inv("@getinv:Clothing/Hats/Sub Hats=1234", ""));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/GetInvQueryTests.cs::GetInvQueryTests.GetInv_Invalid::test 92595df155e79568e70bceb1538c23f10de99a6a138a0a5d9b8a2626588fdae9 translated
#[test]
fn get_inventory_invalid_folder() {
assert!(get_inv("@getinv:Invalid Folder=1234", ""));
}
fn attach(item: &mut RlvInventoryItem, point: RlvAttachmentPoint, prim: &str) {
item.set_attached_to(Some(Some(point)));
item.set_attached_prim_id(Some(Some(guid(prim))));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/GetInvWornQueryTests.cs::GetInvWornQueryTests.GetInvWorn::test 472d70fb14f393d43f8698bb81d1855426f570d85c9e592fa86607eb79ce366e translated
#[test]
fn get_inventory_worn() {
let h = harness();
let mut tree = SampleInventoryTree::build().unwrap();
attach(&mut tree.business_pants, RlvAttachmentPoint::Pelvis, PRIM1);
attach(&mut tree.happy_shirt, RlvAttachmentPoint::Pelvis, PRIM2);
attach(&mut tree.fancy_hat, RlvAttachmentPoint::Chin, PRIM3);
attach(&mut tree.party_hat, RlvAttachmentPoint::Spine, PRIM4);
attach(&mut tree.glasses, RlvAttachmentPoint::Chin, PRIM5);
tree.retro_pants
.set_worn_on(Some(Some(RlvWearableType::Pants)));
tree.party_hat
.set_worn_on(Some(Some(RlvWearableType::Pants)));
tree.watch.set_worn_on(Some(Some(RlvWearableType::Tattoo)));
install_inventory(&h, tree, vec![]);
assert!(query_matches(
&h,
"@getinvworn=1234",
"|03,Clothing|33,Accessories|33"
));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/GetInvWornQueryTests.cs::GetInvWornQueryTests.GetInvWorn_PartialRoot::test ce4c640a901a6684a27b2b259c4fc3b25f2d6b870107babff3b930ced64a150b translated
#[test]
fn get_inventory_worn_partial_root() {
let h = harness();
let mut tree = SampleInventoryTree::build().unwrap();
attach(&mut tree.business_pants, RlvAttachmentPoint::Pelvis, PRIM1);
tree.watch.set_worn_on(Some(Some(RlvWearableType::Tattoo)));
install_inventory(&h, tree, vec![]);
assert!(query_matches(
&h,
"@getinvworn=1234",
"|02,Clothing|22,Accessories|22"
));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/GetInvWornQueryTests.cs::GetInvWornQueryTests.GetInvWorn_Naked::test fa8994189c5d9cda7d613dfb8f6ffbb1808c8bae54a3647530fb872d47c43dd5 translated
#[test]
fn get_inventory_worn_naked() {
assert!(empty_tree_query(
"@getinvworn=1234",
"|01,Clothing|11,Accessories|11"
));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/GetInvWornQueryTests.cs::GetInvWornQueryTests.GetInvWorn_EmptyFolder::test ab6fc753f4d4170e17f49b708d7e62816f197e83234feda1fdcf63dcdc0bc6c4 translated
#[test]
fn get_inventory_worn_empty_folder() {
assert!(empty_tree_query(
"@getinvworn:Clothing/Hats/Sub Hats=1234",
"|00"
));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/GetInvWornQueryTests.cs::GetInvWornQueryTests.GetInvWorn_PartialWorn::test ceb446f2aa6eaa5232a99147d5d993386ee9e2e5fefd93ef582f27a6b8ece948 translated
#[test]
fn get_inventory_worn_partial_folder() {
let h = harness();
let mut tree = SampleInventoryTree::build().unwrap();
attach(&mut tree.party_hat, RlvAttachmentPoint::Spine, PRIM1);
attach(&mut tree.fancy_hat, RlvAttachmentPoint::Chin, PRIM2);
install_inventory(&h, tree, vec![]);
assert!(query_matches(
&h,
"@getinvworn:Clothing/Hats=1234",
"|33,Sub Hats|00"
));
}
const WEARABLES: [RlvWearableType; 17] = [
RlvWearableType::Shape,
RlvWearableType::Skin,
RlvWearableType::Hair,
RlvWearableType::Eyes,
RlvWearableType::Shirt,
RlvWearableType::Pants,
RlvWearableType::Shoes,
RlvWearableType::Socks,
RlvWearableType::Jacket,
RlvWearableType::Gloves,
RlvWearableType::Undershirt,
RlvWearableType::Underpants,
RlvWearableType::Skirt,
RlvWearableType::Alpha,
RlvWearableType::Tattoo,
RlvWearableType::Physics,
RlvWearableType::Universal,
];
// parity-case: LibreMetaverse.Tests/RLV/Queries/GetOutfitQueryTests.cs::GetOutfitQueryTests.GetOutfit_WearingNothing::test 27befef9fdef993d82a641980f2b1ad7f458f07a50c7d008b6d311aeedfb4939 translated
#[test]
fn get_outfit_wearing_nothing() {
assert!(empty_tree_query("@getoutfit=1234", "0000000000000000"));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/GetOutfitQueryTests.cs::GetOutfitQueryTests.GetOutfit_ExternalItems::test f88d149572ae35e880f16a5a92b4a9db73a3f26c5e8e61e4b1c01440151bd64b translated
#[test]
fn get_outfit_external_items() {
let h = harness();
let tree = SampleInventoryTree::build().unwrap();
let folder = "12312312-aaaa-4aaa-8aaa-aaaaaaaaaaaa";
install_inventory(
&h,
tree,
vec![
external_item(
"12312312-0001-4aaa-8aaa-aaaaaaaaaaaa",
"External Tattoo",
folder,
None,
None,
Some(RlvWearableType::Tattoo),
),
external_item(
"12312312-0002-4aaa-8aaa-aaaaaaaaaaaa",
"External Jaw Thing",
folder,
Some(RlvAttachmentPoint::Jaw),
Some("12312312-0002-4aaa-8aaa-ffffffffffff"),
None,
),
],
);
assert!(query_matches(&h, "@getoutfit=1234", "0000000000000010"));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/GetOutfitQueryTests.cs::GetOutfitQueryTests.GetOutfit_WearingSomeItems::test 4e9ef77ab72f1fd16c4fad69f00eb80ab46421597d41b61df80b1f87370f42d3 translated
#[test]
fn get_outfit_wearing_some_items() {
let h = harness();
let tree = SampleInventoryTree::build().unwrap();
let folder = "cccccccc-cccc-4ccc-8ccc-cccccccccccc";
install_inventory(
&h,
tree,
vec![
external_item(
"c0000000-cccc-4ccc-8ccc-cccccccccccc",
"My Socks",
folder,
None,
None,
Some(RlvWearableType::Socks),
),
external_item(
"c0000001-cccc-4ccc-8ccc-cccccccccccc",
"My Hair",
folder,
None,
None,
Some(RlvWearableType::Hair),
),
],
);
assert!(query_matches(&h, "@getoutfit=1234", "0000001000010000"));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/GetOutfitQueryTests.cs::GetOutfitQueryTests.GetOutfit_WearingEverything::test a840b239174cdb5dee4beb875bf9129209af3ba310564319528ad5b19764aae0 translated
#[test]
fn get_outfit_wearing_everything() {
let h = harness();
let tree = SampleInventoryTree::build().unwrap();
let folder = "99999999-9999-4999-8999-999999999999";
let external = WEARABLES
.into_iter()
.map(|wearable| {
external_item(
&format!("c{:07}-cccc-4ccc-8ccc-cccccccccccc", wearable as i32),
&format!("External {wearable:?}"),
folder,
None,
None,
Some(wearable),
)
})
.collect();
install_inventory(&h, tree, external);
assert!(query_matches(&h, "@getoutfit=1234", "1111111111111111"));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/GetOutfitQueryTests.cs::GetOutfitQueryTests.GetOutfit_Specific_Exists::test a402fd67ed8ddfc12d09863f08f9b15b34262ffa12b4b5aa965826eac89abae5 translated
#[test]
fn get_outfit_specific_exists() {
let h = harness();
let tree = SampleInventoryTree::build().unwrap();
install_inventory(
&h,
tree,
vec![external_item(
"c0000000-cccc-4ccc-8ccc-cccccccccccc",
"My Socks",
"cccccccc-cccc-4ccc-8ccc-cccccccccccc",
None,
None,
Some(RlvWearableType::Socks),
)],
);
assert!(query_matches(&h, "@getoutfit:socks=1234", "1"));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/GetOutfitQueryTests.cs::GetOutfitQueryTests.GetOutfit_Specific_NotExists::test d7e891a620b5e5407fe337f507874b63eb5a21589767a01362bd8bc43d19ba4a translated
#[test]
fn get_outfit_specific_not_exists() {
let h = harness();
let tree = SampleInventoryTree::build().unwrap();
install_inventory(
&h,
tree,
vec![external_item(
"c0000001-cccc-4ccc-8ccc-cccccccccccc",
"My Hair",
"cccccccc-cccc-4ccc-8ccc-cccccccccccc",
None,
None,
Some(RlvWearableType::Hair),
)],
);
assert!(query_matches(&h, "@getoutfit:socks=1234", "0"));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/GetPathNewQueryTests.cs::GetPathNewQueryTests.GetPathNew_BySender::test e7e87c01e83967a7160509d76f49d2a4b18d34b9b3fbed370c174d64ddb2c2b5 translated
#[test]
fn get_path_new_by_sender() {
let h = harness();
let mut tree = SampleInventoryTree::build().unwrap();
attach(&mut tree.party_hat, RlvAttachmentPoint::Spine, PRIM1);
install_inventory(&h, tree, vec![]);
assert!(block_on(h.process_from("@getpathnew=1234", PRIM1, "Party Hat (Spine)")).unwrap());
assert_eq!(
h.actions.lock().unwrap().replies,
vec![(1234, "Clothing/Hats".into())]
);
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/GetPathNewQueryTests.cs::GetPathNewQueryTests.GetPathNew_ByUUID::test 3a7d242966286258ed075c8e5c69eaf54ba0e71b8607432615a1199f5aeb6dcf translated
#[test]
fn get_path_new_by_uuid() {
let h = harness();
let mut tree = SampleInventoryTree::build().unwrap();
attach(&mut tree.party_hat, RlvAttachmentPoint::Spine, PRIM1);
install_inventory(&h, tree, vec![]);
assert!(query_matches(
&h,
&format!("@getpathnew:{PRIM1}=1234"),
"Clothing/Hats"
));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/GetPathNewQueryTests.cs::GetPathNewQueryTests.GetPathNew_ByUUID_Unknown::test c3c206661594026c36dfcfea110631548cd362d824db268c170e4d04b24b674a translated
#[test]
fn get_path_new_by_unknown_uuid() {
let h = harness();
let mut tree = SampleInventoryTree::build().unwrap();
tree.fancy_hat.set_attached_to(None);
tree.party_hat.set_attached_to(None);
tree.business_pants.set_attached_to(None);
tree.happy_shirt.set_attached_to(None);
tree.glasses.set_attached_to(None);
tree.retro_pants.set_worn_on(None);
tree.watch.set_worn_on(None);
install_inventory(&h, tree, vec![]);
assert!(query_matches(
&h,
"@getpathnew:BADBADBA-DBAD-4BAD-8BAD-BADBADBADBAD=1234",
"",
));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/GetPathNewQueryTests.cs::GetPathNewQueryTests.GetPathNew_ByAttach::test f8858e6141b660cec8a09c016891f2275dd9364157b1aa614b63fca5abb7620c translated
#[test]
fn get_path_new_by_attachment_point() {
let h = harness();
let mut tree = SampleInventoryTree::build().unwrap();
attach(&mut tree.business_pants, RlvAttachmentPoint::Pelvis, PRIM1);
attach(&mut tree.fancy_hat, RlvAttachmentPoint::Groin, PRIM2);
attach(&mut tree.glasses, RlvAttachmentPoint::Groin, PRIM3);
install_inventory(&h, tree, vec![]);
assert!(query_matches(
&h,
"@getpathnew:groin=1234",
"Accessories,Clothing/Hats"
));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/GetPathNewQueryTests.cs::GetPathNewQueryTests.GetPathNew_ByWorn::test eed31d9aaf34578368cc4f590de1da7f47e3f6c5e663215866f7f8e6946f974b translated
#[test]
fn get_path_new_by_wearable() {
let h = harness();
let mut tree = SampleInventoryTree::build().unwrap();
tree.retro_pants
.set_worn_on(Some(Some(RlvWearableType::Tattoo)));
tree.fancy_hat
.set_worn_on(Some(Some(RlvWearableType::Pants)));
tree.watch.set_worn_on(Some(Some(RlvWearableType::Pants)));
install_inventory(&h, tree, vec![]);
assert!(query_matches(
&h,
"@getpathnew:pants=1234",
"Accessories,Clothing/Hats"
));
}

View File

@@ -0,0 +1,495 @@
// Exact Rust translations of NotifyQueryTests.
use libremetaverse_compat_tests::block_on;
use libremetaverse_compat_tests::rlv_support::{RlvHarness, guid};
use libremetaverse_rlv::{RlvAttachmentPoint, RlvWearableType};
const ITEM_1: &str = "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa";
const ITEM_2: &str = "bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb";
const ITEM_3: &str = "cccccccc-cccc-4ccc-8ccc-cccccccccccc";
const PRIM: &str = "aaaaaaaa-aaaa-4aaa-8aaa-ffffffffffff";
fn harness() -> RlvHarness {
RlvHarness::new().expect("RlvService constructor")
}
fn process(h: &RlvHarness, commands: &[&str]) {
for command in commands {
block_on(h.process(command)).unwrap();
}
}
fn replies_match(h: &RlvHarness, expected: &[(i32, &str)]) -> bool {
h.actions.lock().unwrap().replies
== expected
.iter()
.map(|(channel, text)| (*channel, (*text).into()))
.collect::<Vec<_>>()
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.Notify::test 082ff4cd00faf29a73aca158d4e24ed9fd3e7844ed6cefbf962d8727846a3c27 translated
#[test]
fn notify_every_restriction() {
let h = harness();
process(
&h,
&[
"@notify:1234=add",
"@sendim=n",
"@alwaysrun=n",
"@sendim:group_name=add",
],
);
assert!(replies_match(
&h,
&[
(1234, "/notify:1234=n"),
(1234, "/sendim=n"),
(1234, "/alwaysrun=n"),
(1234, "/sendim:group_name=n"),
],
));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifyFiltered::test e00e51aeadd0d7a107105684129a6ae74fbf918be4c563d92d7cdaa223d2c03c translated
#[test]
fn notify_filtered() {
let h = harness();
process(
&h,
&[
"@notify:1234;run=add",
"@sendim=n",
"@alwaysrun=n",
"@sendim:group_name=add",
],
);
assert!(replies_match(&h, &[(1234, "/alwaysrun=n")]));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifyMultiCommand::test 77f3950214a1bd1e3816fa6f7b0ca69727e9e18be5fb7b37f19490408ca023dc translated
#[test]
fn notify_multi_command() {
let h = harness();
process(
&h,
&[
"@notify:1234=add",
"@sendim=n,sendim:group_name=add,alwaysrun=n",
],
);
assert!(replies_match(
&h,
&[
(1234, "/notify:1234=n"),
(1234, "/sendim=n"),
(1234, "/sendim:group_name=n"),
(1234, "/alwaysrun=n"),
],
));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifyMultiChannels::test 12a0a6e0a0a6632960de98236670e063f2c1aa16cf6b6c8d718bde0e0abfd9b9 translated
#[test]
fn notify_multiple_channels() {
let h = harness();
process(&h, &["@notify:1234=add", "@notify:12345=add", "@sendim=n"]);
assert!(replies_match(
&h,
&[
(1234, "/notify:1234=n"),
(1234, "/notify:12345=n"),
(12345, "/notify:12345=n"),
(1234, "/sendim=n"),
(12345, "/sendim=n"),
],
));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifyMultiChannelsFiltered::test bff8ca8465c2299d0d2ef60adfa4164270d08cee7223361bb27b86a7e4daeec9 translated
#[test]
fn notify_multiple_channels_filtered() {
let h = harness();
process(
&h,
&["@notify:1234=add", "@notify:12345;im=add", "@sendim=n"],
);
assert!(replies_match(
&h,
&[
(1234, "/notify:1234=n"),
(1234, "/notify:12345;im=n"),
(1234, "/sendim=n"),
(12345, "/sendim=n"),
],
));
}
fn notify_synonym(command: &str, expected_reply: &str) -> bool {
let h = harness();
process(&h, &["@notify:1234=add", command]);
replies_match(&h, &[(1234, "/notify:1234=n"), (1234, expected_reply)])
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifySynonyms::case:9e893d263294d04d 6cf84f004648f8b5304bf7fc7fab7ac8b1f8f7da8c605c06daa68d3a1280cd67 translated
#[test]
fn notify_camdistmax() {
assert!(notify_synonym("@camdistmax:123=n", "/camdistmax:123=n"));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifySynonyms::case:fc6b17eb4e9e7a00 6cf84f004648f8b5304bf7fc7fab7ac8b1f8f7da8c605c06daa68d3a1280cd67 translated
#[test]
fn notify_setcam_avdistmax() {
assert!(notify_synonym(
"@setcam_avdistmax:123=n",
"/setcam_avdistmax:123=n"
));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifySynonyms::case:b37376c5865a6fe8 6cf84f004648f8b5304bf7fc7fab7ac8b1f8f7da8c605c06daa68d3a1280cd67 translated
#[test]
fn notify_camdistmin() {
assert!(notify_synonym("@camdistmin:123=n", "/camdistmin:123=n"));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifySynonyms::case:5d497faea315b624 6cf84f004648f8b5304bf7fc7fab7ac8b1f8f7da8c605c06daa68d3a1280cd67 translated
#[test]
fn notify_setcam_avdistmin() {
assert!(notify_synonym(
"@setcam_avdistmin:123=n",
"/setcam_avdistmin:123=n"
));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifySynonyms::case:282fa0139ccbba29 6cf84f004648f8b5304bf7fc7fab7ac8b1f8f7da8c605c06daa68d3a1280cd67 translated
#[test]
fn notify_camunlock() {
assert!(notify_synonym("@camunlock=n", "/camunlock=n"));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifySynonyms::case:f08c6eb7b4d12fac 6cf84f004648f8b5304bf7fc7fab7ac8b1f8f7da8c605c06daa68d3a1280cd67 translated
#[test]
fn notify_setcam_unlock() {
assert!(notify_synonym("@setcam_unlock=n", "/setcam_unlock=n"));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifySynonyms::case:37f0f73ed7492dd0 6cf84f004648f8b5304bf7fc7fab7ac8b1f8f7da8c605c06daa68d3a1280cd67 translated
#[test]
fn notify_camtextures() {
assert!(notify_synonym(
"@camtextures:1cdbc6a2-ae6b-3130-9348-3d3b1ca84c53=n",
"/camtextures:1cdbc6a2-ae6b-3130-9348-3d3b1ca84c53=n",
));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifySynonyms::case:d75917941e63732c 6cf84f004648f8b5304bf7fc7fab7ac8b1f8f7da8c605c06daa68d3a1280cd67 translated
#[test]
fn notify_touchfar() {
assert!(notify_synonym("@touchfar:5=n", "/touchfar:5=n"));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifySynonyms::case:2f72da33fdbcd8be 6cf84f004648f8b5304bf7fc7fab7ac8b1f8f7da8c605c06daa68d3a1280cd67 translated
#[test]
fn notify_fartouch() {
assert!(notify_synonym("@fartouch:5=n", "/fartouch:5=n"));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifyClear_Filtered::test f3e0550a53faca13679421318eee85f010c1b8668e3edfae6e2548d39dbcafd7 translated
#[test]
fn notify_clear_filtered() {
let h = harness();
process(&h, &["@notify:1234=add", "@fly=n", "@clear=fly"]);
assert!(replies_match(
&h,
&[
(1234, "/notify:1234=n"),
(1234, "/fly=n"),
(1234, "/fly=y"),
(1234, "/clear:fly"),
],
));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifyClear::test 61d7419956a83be04eeb13557c6a2120419b2f0f1c529149c4fb57871bb6506e translated
#[test]
fn notify_clear() {
let h = harness();
block_on(h.process_from("@notify:1234=add", ITEM_3, "Main")).unwrap();
process(&h, &["@fly=n", "@clear"]);
assert!(replies_match(
&h,
&[
(1234, "/notify:1234=n"),
(1234, "/fly=n"),
(1234, "/fly=y"),
(1234, "/clear"),
],
));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifyInventoryOffer::test 2bbac63ab86ec77f6d0a4558a14ee913a7f44930364476a89e02cd5ec80191b9 translated
#[test]
fn notify_inventory_offer() {
let h = harness();
process(&h, &["@notify:1234=add"]);
block_on(
h.service
.report_inventory_offer_accepted("#RLV/~MyCuffs".into(), None),
)
.unwrap();
block_on(
h.service
.report_inventory_offer_accepted("Objects/New Folder (3)".into(), None),
)
.unwrap();
block_on(
h.service
.report_inventory_offer_declined("#RLV/Foo/Bar".into(), None),
)
.unwrap();
assert!(replies_match(
&h,
&[
(1234, "/notify:1234=n"),
(1234, "/accepted_in_rlv inv_offer ~MyCuffs"),
(1234, "/accepted_in_inv inv_offer Objects/New Folder (3)"),
(1234, "/declined inv_offer Foo/Bar"),
],
));
}
fn report_sit_and_unsit(h: &RlvHarness) {
block_on(h.service.report_sit(Some(Some(guid(ITEM_3))), None)).unwrap();
block_on(h.service.report_unsit(Some(Some(guid(ITEM_3))), None)).unwrap();
block_on(h.service.report_sit(None, None)).unwrap();
block_on(h.service.report_unsit(None, None)).unwrap();
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifySitStandLegal::test 83a07a88a0386982c854a0223b64dd5c417f1a55a038e4ceba8f487983daadaf translated
#[test]
fn notify_sit_and_stand_legal() {
let h = harness();
process(&h, &["@notify:1234=add"]);
report_sit_and_unsit(&h);
assert!(replies_match(
&h,
&[
(1234, "/notify:1234=n"),
(
1234,
"/sat object legally 11111111-1111-4111-8111-111111111111",
),
(
1234,
"/unsat object legally 11111111-1111-4111-8111-111111111111",
),
(1234, "/sat ground legally"),
(1234, "/unsat ground legally"),
],
));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifySitStandWithRestrictions::test 166e2087aa0652bdd427e1908bc338659ec1d4dc8065c016612696d1f5dfd000 translated
#[test]
fn notify_sit_and_stand_illegal() {
let h = harness();
process(&h, &["@sit=n", "@unsit=n", "@notify:1234=add"]);
report_sit_and_unsit(&h);
assert!(replies_match(
&h,
&[
(1234, "/notify:1234=n"),
(
1234,
"/sat object illegally 11111111-1111-4111-8111-111111111111",
),
(
1234,
"/unsat object illegally 11111111-1111-4111-8111-111111111111",
),
(1234, "/sat ground illegally"),
(1234, "/unsat ground illegally"),
],
));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifyWear::test 9529acb9f3e1c335a50f8de6d63cc5711921de962546ff868811279d05826399 translated
#[test]
fn notify_wear_legal() {
let h = harness();
process(&h, &["@notify:1234=add"]);
block_on(
h.service
.report_item_worn(guid(ITEM_2), false, RlvWearableType::Skin, None),
)
.unwrap();
block_on(
h.service
.report_item_worn(guid(ITEM_3), true, RlvWearableType::Tattoo, None),
)
.unwrap();
assert!(replies_match(
&h,
&[
(1234, "/notify:1234=n"),
(1234, "/worn legally skin"),
(1234, "/worn legally tattoo"),
],
));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifyWear_Illegal::test 65bfc1db698470cf56dd8c6811e85ae373d1fca95cdbf82be66b7e32da311a2f translated
#[test]
fn notify_wear_illegal() {
let h = harness();
process(&h, &["@addoutfit:skin=n", "@notify:1234=add"]);
block_on(
h.service
.report_item_worn(guid(ITEM_1), false, RlvWearableType::Skin, None),
)
.unwrap();
assert!(replies_match(
&h,
&[(1234, "/notify:1234=n"), (1234, "/worn illegally skin")],
));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifyUnWear::test 340b60b8038dcd55320dc9aedc16beb9193e731ba7b659ca3cb2951a2d19b7ac translated
#[test]
fn notify_unwear_legal() {
let h = harness();
process(&h, &["@notify:1234=add"]);
block_on(h.service.report_item_unworn(
guid(ITEM_1),
guid(ITEM_2),
false,
RlvWearableType::Skin,
None,
))
.unwrap();
block_on(h.service.report_item_unworn(
guid(ITEM_1),
guid(ITEM_3),
true,
RlvWearableType::Tattoo,
None,
))
.unwrap();
assert!(replies_match(
&h,
&[
(1234, "/notify:1234=n"),
(1234, "/unworn legally skin"),
(1234, "/unworn legally tattoo"),
],
));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifyUnWear_illegal::test e7056e6e145430eb2180edb92593f59c07bcbdfa21629b1ca29ac93b2fca975e translated
#[test]
fn notify_unwear_illegal() {
let h = harness();
process(&h, &["@remoutfit:skin=n", "@notify:1234=add"]);
block_on(h.service.report_item_unworn(
guid(ITEM_1),
guid(ITEM_1),
false,
RlvWearableType::Skin,
None,
))
.unwrap();
assert!(replies_match(
&h,
&[(1234, "/notify:1234=n"), (1234, "/unworn illegally skin")],
));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifyAttached::test dc5239c77b9169cf3833c5a1dc765b381efe833f15b34ac7e57173c0a640942a translated
#[test]
fn notify_attached_legal() {
let h = harness();
process(&h, &["@notify:1234=add"]);
block_on(
h.service
.report_item_attached(guid(ITEM_1), false, RlvAttachmentPoint::Chest, None),
)
.unwrap();
block_on(h.service.report_item_attached(
guid(ITEM_2),
true,
RlvAttachmentPoint::AvatarCenter,
None,
))
.unwrap();
assert!(replies_match(
&h,
&[
(1234, "/notify:1234=n"),
(1234, "/attached legally Chest"),
(1234, "/attached legally Avatar Center"),
],
));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifyAttached_Illegal::test b56de057dece9cb8ece795d13d6bc42e7825d62f09f967f37a4dbf262d2b4456 translated
#[test]
fn notify_attached_illegal() {
let h = harness();
process(&h, &["@addattach:chest=n", "@notify:1234=add"]);
block_on(
h.service
.report_item_attached(guid(ITEM_1), false, RlvAttachmentPoint::Chest, None),
)
.unwrap();
assert!(replies_match(
&h,
&[
(1234, "/notify:1234=n"),
(1234, "/attached illegally Chest"),
],
));
}
fn report_detached(h: &RlvHarness, folder: &str, shared: bool, point: RlvAttachmentPoint) {
block_on(h.service.report_item_detached(
guid(ITEM_1),
guid(PRIM),
guid(folder),
shared,
point,
None,
))
.unwrap();
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifyDetached::test a741cec23a985028b3dc2b09195255276a96e4f07fc4fe5f8cca6c1e3c940d71 translated
#[test]
fn notify_detached_legal() {
let h = harness();
process(&h, &["@notify:1234=add"]);
report_detached(&h, ITEM_2, false, RlvAttachmentPoint::Chest);
report_detached(&h, ITEM_3, true, RlvAttachmentPoint::Skull);
assert!(replies_match(
&h,
&[
(1234, "/notify:1234=n"),
(1234, "/detached legally Chest"),
(1234, "/detached legally Skull"),
],
));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/NotifyQueryTests.cs::NotifyQueryTests.NotifyDetached_Illegal::test 1a4c9475a3b91a975b9861685dcaf899505b4f6727257618f9add9cecd3df54d translated
#[test]
fn notify_detached_illegal() {
let h = harness();
process(&h, &["@remattach:chest=n", "@notify:1234=add"]);
report_detached(&h, ITEM_1, false, RlvAttachmentPoint::Chest);
assert!(replies_match(
&h,
&[
(1234, "/notify:1234=n"),
(1234, "/detached illegally Chest"),
],
));
}

View File

@@ -0,0 +1,225 @@
// Exact Rust translation of LibreMetaverse.Tests/RLV/PermissionsTests.cs.
use libremetaverse_compat_tests::rlv_support::{RlvHarness, guid};
use libremetaverse_rlv::{
RlvPermissionsServiceHoverTextLocation as HoverTextLocation,
RlvPermissionsServiceObjectLocation as ObjectLocation,
};
fn harness() -> RlvHarness {
RlvHarness::new().expect("RlvService constructor")
}
fn hover_text_defaults() -> [bool; 2] {
let permissions = harness().service.permissions();
let object = Some(Some(guid("00000000-0000-4000-8000-000000000000")));
[
permissions
.can_show_hover_text(HoverTextLocation::World, object)
.unwrap(),
permissions
.can_show_hover_text(HoverTextLocation::Hud, object)
.unwrap(),
]
}
// parity-case: LibreMetaverse.Tests/RLV/PermissionsTests.cs::PermissionsTests.CamZoomMin_Default::test 662b332d66c72caecc1a179730bc2524b9da16aa85f7289bebd31842610ceccc translated
#[test]
fn camera_zoom_min_defaults_to_none() {
assert!(
harness()
.service
.permissions()
.get_camera_restrictions()
.unwrap()
.zoom_min()
.flatten()
.is_none()
);
}
// parity-case: LibreMetaverse.Tests/RLV/PermissionsTests.cs::PermissionsTests.CanShowHoverTextWorld_Default::test 380d1e30bd9ded04329bfd6d65ba447a8dd45a934cfa875628253719bb0e69ce translated
#[test]
fn can_show_hover_text_world_defaults_true() {
assert_eq!(hover_text_defaults(), [true, true]);
}
// parity-case: LibreMetaverse.Tests/RLV/PermissionsTests.cs::PermissionsTests.CanShowHoverTextHud_Default::test a0af1f72f417cfa451284b7a3dbbb26d378e7eb9896dde3b6df0d0a2e4773f38 translated
#[test]
fn can_show_hover_text_hud_defaults_true() {
assert_eq!(hover_text_defaults(), [true, true]);
}
// parity-case: LibreMetaverse.Tests/RLV/PermissionsTests.cs::PermissionsTests.CanShowHoverText_Default::test c4122dbf650f51bde55dfda412a884347a78d3cd09dd2bb0fcbe4a7e74a1fff6 translated
#[test]
fn can_show_hover_text_defaults_true() {
assert_eq!(hover_text_defaults(), [true, true]);
}
// parity-case: LibreMetaverse.Tests/RLV/PermissionsTests.cs::PermissionsTests.CanShowHoverTextAll_Default::test 0ed67c5566d038f770eb9f5df6aa0b5394d7d94cf7c397fa8089b419f872c681 translated
#[test]
fn can_show_all_hover_text_defaults_true() {
assert_eq!(hover_text_defaults(), [true, true]);
}
// parity-case: LibreMetaverse.Tests/RLV/PermissionsTests.cs::PermissionsTests.CanShowNameTags_Default::test 0781be94eb099d9aed1be2ff313856770d1ec24047d04c81c69219c743b4c8cb translated
#[test]
fn can_show_name_tags_defaults_true() {
let permissions = harness().service.permissions();
assert!(permissions.can_show_name_tags(None).unwrap());
assert!(
permissions
.can_show_name_tags(Some(Some(guid("aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa"))))
.unwrap()
);
}
// parity-case: LibreMetaverse.Tests/RLV/PermissionsTests.cs::PermissionsTests.CanShare_Default::test e827d549d1d9329b63db159446937735ead13eed5d3eaa59440d3c686182f517 translated
#[test]
fn can_share_defaults_true() {
let permissions = harness().service.permissions();
assert!(permissions.can_share(None).unwrap());
assert!(
permissions
.can_share(Some(Some(guid("aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa"))))
.unwrap()
);
}
// parity-case: LibreMetaverse.Tests/RLV/PermissionsTests.cs::PermissionsTests.CanShowNames_Default::test 56492cdd0802c5f8ed2a0f6d56abaf8186e37dd7b888904db52be97f9137279a translated
#[test]
fn can_show_names_defaults_true() {
let permissions = harness().service.permissions();
assert!(permissions.can_show_names(None).unwrap());
assert!(
permissions
.can_show_names(Some(Some(guid("aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa"))))
.unwrap()
);
}
// parity-case: LibreMetaverse.Tests/RLV/PermissionsTests.cs::PermissionsTests.CanEdit_Default::test 417fb9f3eb3e70f3bd33710d11fb25eacd0db0a365b0ed2dec6778d09968f44b translated
#[test]
fn can_edit_defaults_true_for_all_locations_and_ids() {
let permissions = harness().service.permissions();
let object = Some(Some(guid("00000000-0000-4000-8000-000000000000")));
for location in [
ObjectLocation::Hud,
ObjectLocation::Attached,
ObjectLocation::RezzedInWorld,
] {
assert!(permissions.can_edit(location, None).unwrap());
assert!(permissions.can_edit(location, object).unwrap());
}
}
// parity-case: LibreMetaverse.Tests/RLV/PermissionsTests.cs::PermissionsTests.CanRecvChat_Default::test b1ec48da83249b1141c3af926cd494373c47214d6a145916a8833d49edd155e2 translated
#[test]
fn can_receive_chat_defaults_true() {
let permissions = harness().service.permissions();
assert!(
permissions
.can_receive_chat(
"Hello world".into(),
guid("aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa"),
)
.unwrap()
);
assert!(
permissions
.can_receive_chat(
"/me says Hello world".into(),
guid("bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb"),
)
.unwrap()
);
}
// parity-case: LibreMetaverse.Tests/RLV/PermissionsTests.cs::PermissionsTests.CanAutoAcceptTpRequest_Default::test abbcccb4415afdb6558f40a6d4030704f64442f019d065fef8a7a56a407e8642 translated
#[test]
fn auto_accept_tp_request_defaults_false() {
let permissions = harness().service.permissions();
for user in [
Some(Some(guid("00000000-0000-4000-8000-000000000000"))),
Some(Some(guid("11111111-1111-4111-8111-111111111111"))),
None,
] {
assert!(!permissions.is_auto_accept_tp_request(user).unwrap());
}
}
// parity-case: LibreMetaverse.Tests/RLV/PermissionsTests.cs::PermissionsTests.CanTpRequest_Default::test aefc51023a5274d402dae0e8111a0776622dc431754c3d1f0ce240a50dfd405d translated
#[test]
fn can_tp_request_defaults_true() {
let permissions = harness().service.permissions();
assert!(permissions.can_tp_request(None).unwrap());
assert!(
permissions
.can_tp_request(Some(Some(guid("aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa"))))
.unwrap()
);
}
// parity-case: LibreMetaverse.Tests/RLV/PermissionsTests.cs::PermissionsTests.CanAutoAcceptTp_Default::test 553245a5381689a7f1c6398cb0ca50510f9089b9bdc797672ae35fb5822fdf8e translated
#[test]
fn auto_accept_tp_defaults_false() {
let permissions = harness().service.permissions();
for user in [
Some(Some(guid("00000000-0000-4000-8000-000000000000"))),
Some(Some(guid("11111111-1111-4111-8111-111111111111"))),
None,
] {
assert!(!permissions.is_auto_accept_tp(user).unwrap());
}
}
// parity-case: LibreMetaverse.Tests/RLV/PermissionsTests.cs::PermissionsTests.CanChat_Default::test a9b0e4f8713991ce8b9b61d750c086d56da432dbddd533ec63dc0604238831a1 translated
#[test]
fn can_chat_defaults_true() {
let permissions = harness().service.permissions();
for (channel, message) in [(0, "Hello"), (0, "/me says Hello"), (5, "Hello")] {
assert!(permissions.can_chat(channel, message.into()).unwrap());
}
}
// parity-case: LibreMetaverse.Tests/RLV/PermissionsTests.cs::PermissionsTests.CanSendIM_Default::test 6cc5238ded59b80408c59c9e77ded1162e370c295b846903dbcc87f74175cd55 translated
#[test]
fn can_send_im_defaults_true() {
let permissions = harness().service.permissions();
let user = Some(Some(guid("00000000-0000-4000-8000-000000000000")));
assert!(permissions.can_send_im("Hello".into(), user, None).unwrap());
assert!(
permissions
.can_send_im("Hello".into(), user, Some("Group Name".into()))
.unwrap()
);
}
// parity-case: LibreMetaverse.Tests/RLV/PermissionsTests.cs::PermissionsTests.CanStartIM_Default::test c6d6db79b0939b33eb5fd29490474575e062f796160f4a69aab34ccefc1842cb translated
#[test]
fn can_start_im_defaults_true() {
assert!(
harness()
.service
.permissions()
.can_start_im(guid("00000000-0000-4000-8000-000000000000"))
.unwrap()
);
}
// parity-case: LibreMetaverse.Tests/RLV/PermissionsTests.cs::PermissionsTests.CanReceiveIM_Default::test 23c1c79ae9eba016a48f3e9097fc26283223c9e120308d93fe53ce591ee5691c translated
#[test]
fn can_receive_im_defaults_true() {
let permissions = harness().service.permissions();
let user = Some(Some(guid("00000000-0000-4000-8000-000000000000")));
assert!(
permissions
.can_receive_im("Hello".into(), user, None)
.unwrap()
);
assert!(
permissions
.can_receive_im("Hello".into(), user, Some("Group Name".into()))
.unwrap()
);
}

View File

@@ -0,0 +1,315 @@
// Exact Rust translations of the basic RLV query tests.
use libremetaverse_compat_tests::block_on;
use libremetaverse_compat_tests::rlv_support::{RlvHarness, SENDER_ID, guid};
use libremetaverse_rlv::RlvService;
const OTHER_SENDER: &str = "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa";
const SIT_ID: &str = "00000000-0000-4000-8000-000000000000";
const TP_EXCEPTION: &str = "3d6181b0-6a4b-97ef-18d8-722652995cf1";
fn harness() -> RlvHarness {
RlvHarness::new().expect("RlvService constructor")
}
fn seed_blacklist(h: &RlvHarness, seed: &str) {
for behavior in seed.split(',').filter(|behavior| !behavior.is_empty()) {
h.service
.blacklist()
.blacklist_behavior(behavior.into())
.unwrap();
}
}
fn assert_reply(h: &RlvHarness, expected: &str) {
assert_eq!(
h.actions.lock().unwrap().replies,
vec![(1234, expected.into())]
);
}
fn get_blacklist_matches(command: &str, seed: &str, expected: &str) -> bool {
let h = harness();
seed_blacklist(&h, seed);
block_on(h.process(&format!("{command}=1234"))).unwrap();
h.actions.lock().unwrap().replies == vec![(1234, expected.into())]
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/GetBlacklistQueryTests.cs::GetBlacklistQueryTests.GetBlacklist::case:8e1b820c1f2bd3cd 3faf1c80c07da463d139f13d4ed9deba67b160a29d3001437f2e2794940a7765 translated
#[test]
fn get_blacklist_all() {
assert!(get_blacklist_matches(
"@getblacklist",
"sendim,recvim",
"recvim,sendim"
));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/GetBlacklistQueryTests.cs::GetBlacklistQueryTests.GetBlacklist::case:64136cd82156035a 3faf1c80c07da463d139f13d4ed9deba67b160a29d3001437f2e2794940a7765 translated
#[test]
fn get_blacklist_im_filter() {
assert!(get_blacklist_matches(
"@getblacklist:im",
"sendim,recvim",
"recvim,sendim"
));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/GetBlacklistQueryTests.cs::GetBlacklistQueryTests.GetBlacklist::case:2068bf7f0a131fe8 3faf1c80c07da463d139f13d4ed9deba67b160a29d3001437f2e2794940a7765 translated
#[test]
fn get_blacklist_send_filter() {
assert!(get_blacklist_matches(
"@getblacklist:send",
"sendim,recvim",
"sendim"
));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/GetBlacklistQueryTests.cs::GetBlacklistQueryTests.GetBlacklist::case:b86b0c5e67f981c2 3faf1c80c07da463d139f13d4ed9deba67b160a29d3001437f2e2794940a7765 translated
#[test]
fn get_blacklist_unmatched_filter() {
assert!(get_blacklist_matches(
"@getblacklist:tpto",
"sendim,recvim",
""
));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/GetBlacklistQueryTests.cs::GetBlacklistQueryTests.GetBlacklist::case:123b930bb970a1f1 3faf1c80c07da463d139f13d4ed9deba67b160a29d3001437f2e2794940a7765 translated
#[test]
fn get_blacklist_empty() {
assert!(get_blacklist_matches("@getblacklist", "", ""));
}
fn manual_blacklist_matches(seed: &str, expected: &str) -> bool {
let mut h = harness();
h.service.set_enable_instant_message_processing(true);
seed_blacklist(&h, seed);
block_on(
h.service
.process_instant_message("@getblacklist".into(), guid(SENDER_ID), None),
)
.unwrap();
h.actions.lock().unwrap().instant_messages == vec![(guid(SENDER_ID), expected.into())]
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/GetBlacklistQueryTests.cs::GetBlacklistQueryTests.ManualBlacklist::case:f14641dea0f1de93 4ef9ab9bc3165b99ef6b9cf6ae563210660e83fccf946376217c300a752c724e translated
#[test]
fn manual_blacklist_all() {
assert!(manual_blacklist_matches("sendim,recvim", "recvim,sendim"));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/GetBlacklistQueryTests.cs::GetBlacklistQueryTests.ManualBlacklist::case:d25c660357f6ccff 4ef9ab9bc3165b99ef6b9cf6ae563210660e83fccf946376217c300a752c724e translated
#[test]
fn manual_blacklist_empty() {
assert!(manual_blacklist_matches("", ""));
}
fn debug_matches(setting_name: &str, setting_value: &str) -> bool {
let h = harness();
h.queries
.lock()
.unwrap()
.debug_settings
.insert(setting_name.to_lowercase(), setting_value.into());
block_on(h.process(&format!("@getdebug_{setting_name}=1234"))).unwrap()
&& h.actions.lock().unwrap().replies == vec![(1234, setting_value.into())]
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/GetDebugQueryTests.cs::GetDebugQueryTests.GetDebug_Default::case:fa77559e30768d15 6554db3b0455887c0224a6f91c7830d6cbf38d5520a65a9b17e26280fcc291f7 translated
#[test]
fn get_debug_known_setting() {
assert!(debug_matches(
"RenderResolutionDivisor",
"RenderResolutionDivisor Success"
));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/GetDebugQueryTests.cs::GetDebugQueryTests.GetDebug_Default::case:55694f25ed879d95 6554db3b0455887c0224a6f91c7830d6cbf38d5520a65a9b17e26280fcc291f7 translated
#[test]
fn get_debug_unknown_setting() {
assert!(debug_matches("Unknown Setting", "Unknown Setting Success"));
}
fn environment_matches(setting_name: &str, setting_value: &str) -> bool {
let h = harness();
h.queries
.lock()
.unwrap()
.environment_settings
.insert(setting_name.to_lowercase(), setting_value.into());
block_on(h.process(&format!("@getenv_{setting_name}=1234"))).unwrap()
&& h.actions.lock().unwrap().replies == vec![(1234, setting_value.into())]
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/GetEnvQueryTests.cs::GetEnvQueryTests.GetEnv_Default::case:f656b648d00a6d91 cf4270c6c3417690afcf43982c3bdcf815f46ce81f9b6ccaf59377c633a64881 translated
#[test]
fn get_environment_known_setting() {
assert!(environment_matches("Daytime", "Daytime Success"));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/GetEnvQueryTests.cs::GetEnvQueryTests.GetEnv_Default::case:55694f25ed879d95 cf4270c6c3417690afcf43982c3bdcf815f46ce81f9b6ccaf59377c633a64881 translated
#[test]
fn get_environment_unknown_setting() {
assert!(environment_matches(
"Unknown Setting",
"Unknown Setting Success"
));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/GetGroupQueryTests.cs::GetGroupQueryTests.GetGroup_Default::test da65b184d0ef1380274e8e4dfa199c125a1a192b9e76f8fec1d406df18186169 translated
#[test]
fn get_active_group() {
let h = harness();
h.queries.lock().unwrap().active_group = Some("Group Name".into());
assert!(block_on(h.process("@getgroup=1234")).unwrap());
assert_reply(&h, "Group Name");
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/GetGroupQueryTests.cs::GetGroupQueryTests.GetGroup_NoGroup::test d1da37ae52bd94dac9cd6e031525b57f31ca7e9dc00a69a6e0c4e753741dc9e8 translated
#[test]
fn get_group_without_active_group() {
let h = harness();
assert!(block_on(h.process("@getgroup=1234")).unwrap());
assert_reply(&h, "none");
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/GetSitIdQueryTests.cs::GetSitIdQueryTests.GetSitID::test bfbf6d62c09c4878504aa529805a29fe9689d1e29e7ca3d44bf2346d6b3fbe6b translated
#[test]
fn get_sit_id_when_not_sitting() {
let h = harness();
block_on(h.process("@getsitid=1234")).unwrap();
assert_reply(&h, "NULL_KEY");
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/GetSitIdQueryTests.cs::GetSitIdQueryTests.GetSitID_Default::test 456f8f22b1d2917c3729ed600bdf0b693c0189bd100b9863f4b42b07259110b0 translated
#[test]
fn get_current_sit_id() {
let h = harness();
h.queries.lock().unwrap().sit_id = Some(guid(SIT_ID));
block_on(h.process("@getsitid=1234")).unwrap();
assert_reply(&h, SIT_ID);
}
fn seed_status(h: &RlvHarness) {
block_on(h.process("@fly=n")).unwrap();
block_on(h.process("@tplure=n")).unwrap();
block_on(h.process(&format!("@tplure:{TP_EXCEPTION}=add"))).unwrap();
block_on(h.process_from("@tplocal=n", OTHER_SENDER, "Sender 2")).unwrap();
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/GetStatusAllQueryTests.cs::GetStatusAllQueryTests.GetStatusAll::test ee8fac8485db2b5c01abf8664364ca1e13214243f1e661a04d93df680422d596 translated
#[test]
fn get_status_all_senders() {
let h = harness();
seed_status(&h);
block_on(h.process("@getstatusall=1234")).unwrap();
assert_reply(
&h,
"/fly/tplure/tplure:3d6181b0-6a4b-97ef-18d8-722652995cf1/tplocal",
);
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/GetStatusQueryTests.cs::GetStatusQueryTests.GetStatus::test c538e68277e93b40374dfd86bde9be00e0b82dfad7f4573cc4b0660f15fa5fe4 translated
#[test]
fn get_status_for_sender() {
let h = harness();
seed_status(&h);
block_on(h.process("@getstatus=1234")).unwrap();
assert_reply(
&h,
"/fly/tplure/tplure:3d6181b0-6a4b-97ef-18d8-722652995cf1",
);
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/GetStatusQueryTests.cs::GetStatusQueryTests.GetStatus_filtered::test 574b7f7c37b4e09e4257e5b02d50b222054216e34b6d1dd3fe6b26127c89b562 translated
#[test]
fn get_status_filtered() {
let h = harness();
seed_status(&h);
block_on(h.process("@getstatus:tp=1234")).unwrap();
assert_reply(&h, "/tplure/tplure:3d6181b0-6a4b-97ef-18d8-722652995cf1");
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/GetStatusQueryTests.cs::GetStatusQueryTests.GetStatus_customSeparator::test 3bec2e53ea88857d4a1ae8cd6bc6f235f24e00d0773c24ca75a1892adb803527 translated
#[test]
fn get_status_custom_separator() {
let h = harness();
seed_status(&h);
block_on(h.process("@getstatus:; ! =1234")).unwrap();
assert_reply(
&h,
" ! fly ! tplure ! tplure:3d6181b0-6a4b-97ef-18d8-722652995cf1",
);
}
fn version_num_blacklist_matches(seed: &str, expected: &str) -> bool {
let h = harness();
seed_blacklist(&h, seed);
block_on(h.process("@versionnumbl=1234")).unwrap();
h.actions.lock().unwrap().replies == vec![(1234, expected.into())]
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/VersionNumBlQueryTests.cs::VersionNumBlQueryTests.VersionNumBL::case:478968a5d14830de 0dbc89f77a6f293efcca217febb2f6b8d224f9ac5e1d6532a56a7df64a7be6e9 translated
#[test]
fn version_number_without_blacklist() {
assert!(version_num_blacklist_matches(
"",
RlvService::RLV_VERSION_NUM
));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/VersionNumBlQueryTests.cs::VersionNumBlQueryTests.VersionNumBL::case:8c124ee42e9ab944 0dbc89f77a6f293efcca217febb2f6b8d224f9ac5e1d6532a56a7df64a7be6e9 translated
#[test]
fn version_number_with_blacklist() {
assert!(version_num_blacklist_matches(
"sendim,recvim",
"2040213,recvim,sendim"
));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/VersionQueryTests.cs::VersionQueryTests.ManualVersion::test 6f8493b201d69e1449d8311e434736f6f6b2bad04c9fe9c6adf94a94d9cbe597 translated
#[test]
fn manual_version() {
let mut h = harness();
h.service.set_enable_instant_message_processing(true);
block_on(
h.service
.process_instant_message("@version".into(), guid(SENDER_ID), None),
)
.unwrap();
assert_eq!(
h.actions.lock().unwrap().instant_messages,
vec![(guid(SENDER_ID), RlvService::RLV_VERSION.into())]
);
}
fn version_query_matches(command: &str, expected: &str) -> bool {
let h = harness();
block_on(h.process(&format!("{command}=1234"))).unwrap();
h.actions.lock().unwrap().replies == vec![(1234, expected.into())]
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/VersionQueryTests.cs::VersionQueryTests.CheckVersions::case:442bdc765ad34e20 f8118590cf64832f30e5e3c927bf8cee42c90d82a3e275554e9c36adb7ad5d30 translated
#[test]
fn version_query_standard() {
assert!(version_query_matches("@version", RlvService::RLV_VERSION));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/VersionQueryTests.cs::VersionQueryTests.CheckVersions::case:968af293ea2a53a1 f8118590cf64832f30e5e3c927bf8cee42c90d82a3e275554e9c36adb7ad5d30 translated
#[test]
fn version_query_new() {
assert!(version_query_matches(
"@versionnew",
RlvService::RLV_VERSION
));
}
// parity-case: LibreMetaverse.Tests/RLV/Queries/VersionQueryTests.cs::VersionQueryTests.CheckVersions::case:ae9a221915e6e1bb f8118590cf64832f30e5e3c927bf8cee42c90d82a3e275554e9c36adb7ad5d30 translated
#[test]
fn version_query_number() {
assert!(version_query_matches(
"@versionnum",
RlvService::RLV_VERSION_NUM
));
}

View File

@@ -0,0 +1,549 @@
// Exact Rust translations of recursive and folder-targeted attachment restrictions.
use libremetaverse_compat_tests::block_on;
use libremetaverse_compat_tests::rlv_support::{RlvHarness, SampleInventoryTree, guid};
use libremetaverse_rlv::{InventoryMap, RlvAttachmentPoint, RlvWearableType};
use libremetaverse_types::compat::Guid;
const PRIM_1: &str = "11111111-0001-4aaa-8aaa-ffffffffffff";
const PRIM_2: &str = "11111111-0002-4aaa-8aaa-ffffffffffff";
const PRIM_3: &str = "11111111-0003-4aaa-8aaa-ffffffffffff";
#[derive(Clone, Copy)]
enum Setup {
None,
PartySpine,
PartyChin,
BusinessPelvis,
BusinessChin,
BusinessChest,
RetroPants,
WatchTattoo,
PartyAndBusinessPelvis,
PartyAndBusinessPelvisDetach,
}
#[derive(Clone, Copy)]
enum FolderKey {
Clothing,
Hats,
SubHats,
Accessories,
}
#[derive(Clone, Copy)]
enum LockMode {
Attach,
Detach,
}
struct FolderIdentity {
clothing: (Guid, String),
hats: (Guid, String),
sub_hats: (Guid, String),
accessories: (Guid, String),
}
fn apply_setup(tree: &mut SampleInventoryTree, setup: Setup) {
match setup {
Setup::None => {}
Setup::PartySpine => {
tree.party_hat
.set_attached_to(Some(Some(RlvAttachmentPoint::Spine)));
tree.party_hat
.set_attached_prim_id(Some(Some(guid(PRIM_3))));
}
Setup::PartyChin => {
tree.party_hat
.set_attached_to(Some(Some(RlvAttachmentPoint::Chin)));
tree.party_hat
.set_attached_prim_id(Some(Some(guid(PRIM_3))));
}
Setup::BusinessPelvis => {
tree.business_pants
.set_attached_to(Some(Some(RlvAttachmentPoint::Pelvis)));
tree.business_pants
.set_attached_prim_id(Some(Some(guid(PRIM_3))));
}
Setup::BusinessChin => {
tree.business_pants
.set_attached_to(Some(Some(RlvAttachmentPoint::Chin)));
tree.business_pants
.set_attached_prim_id(Some(Some(guid(PRIM_3))));
}
Setup::BusinessChest => {
tree.business_pants
.set_attached_to(Some(Some(RlvAttachmentPoint::Chest)));
tree.business_pants
.set_attached_prim_id(Some(Some(guid(PRIM_3))));
}
Setup::RetroPants => tree
.retro_pants
.set_worn_on(Some(Some(RlvWearableType::Pants))),
Setup::WatchTattoo => tree.watch.set_worn_on(Some(Some(RlvWearableType::Tattoo))),
Setup::PartyAndBusinessPelvis => {
tree.party_hat
.set_attached_to(Some(Some(RlvAttachmentPoint::Pelvis)));
tree.party_hat
.set_attached_prim_id(Some(Some(guid(PRIM_2))));
tree.business_pants
.set_attached_to(Some(Some(RlvAttachmentPoint::Pelvis)));
tree.business_pants
.set_attached_prim_id(Some(Some(guid(PRIM_1))));
}
Setup::PartyAndBusinessPelvisDetach => {
tree.party_hat
.set_attached_to(Some(Some(RlvAttachmentPoint::Pelvis)));
tree.party_hat
.set_attached_prim_id(Some(Some(guid(PRIM_1))));
tree.business_pants
.set_attached_to(Some(Some(RlvAttachmentPoint::Pelvis)));
tree.business_pants
.set_attached_prim_id(Some(Some(guid(PRIM_3))));
}
}
}
fn locked_folders_match(
h: &RlvHarness,
identities: &FolderIdentity,
expected: &[FolderKey],
mode: LockMode,
) -> bool {
let locked = h.service.restrictions().get_locked_folders().unwrap();
if locked.len() != expected.len() {
return false;
}
for key in expected {
let (id, name) = match key {
FolderKey::Clothing => &identities.clothing,
FolderKey::Hats => &identities.hats,
FolderKey::SubHats => &identities.sub_hats,
FolderKey::Accessories => &identities.accessories,
};
let Some(folder) = locked.get(id) else {
return false;
};
let common = folder.id() == *id
&& folder.name() == *name
&& folder.is_locked()
&& folder.attach_exceptions().is_empty()
&& folder.detach_exceptions().is_empty();
let mode_matches = match mode {
LockMode::Attach => {
!folder.can_attach()
&& folder.can_detach()
&& folder.attach_restrictions().len() == 1
&& folder.detach_restrictions().is_empty()
}
LockMode::Detach => {
folder.can_attach()
&& !folder.can_detach()
&& folder.attach_restrictions().is_empty()
&& folder.detach_restrictions().len() == 1
}
};
if !common || !mode_matches {
return false;
}
}
true
}
fn folder_case_matches(
command: &str,
sender: Option<(&str, &str)>,
setup: Setup,
mode: LockMode,
expected_items: [bool; 7],
expected_folders: &[FolderKey],
) -> bool {
let h = RlvHarness::new().expect("RlvService constructor");
let mut tree = SampleInventoryTree::build().expect("sample inventory tree");
apply_setup(&mut tree, setup);
let identities = FolderIdentity {
clothing: (tree.clothing.id(), tree.clothing.name()),
hats: (tree.hats.id(), tree.hats.name()),
sub_hats: (tree.sub_hats.id(), tree.sub_hats.name()),
accessories: (tree.accessories.id(), tree.accessories.name()),
};
h.queries.lock().unwrap().inventory_map = Some(InventoryMap::new(tree.root, vec![]).unwrap());
for command in command.split(',') {
let processed = sender.map_or_else(
|| block_on(h.process(command)),
|(id, name)| block_on(h.process_from(command, id, name)),
);
if !processed.unwrap() {
return false;
}
}
let permissions = h.service.permissions();
let actual = match mode {
LockMode::Attach => [
permissions
.can_attach_with_rlv_inventory_item_boolean(tree.party_hat, true)
.unwrap(),
permissions
.can_attach_with_rlv_inventory_item_boolean(tree.fancy_hat, true)
.unwrap(),
permissions
.can_attach_with_rlv_inventory_item_boolean(tree.business_pants, true)
.unwrap(),
permissions
.can_attach_with_rlv_inventory_item_boolean(tree.happy_shirt, true)
.unwrap(),
permissions
.can_attach_with_rlv_inventory_item_boolean(tree.retro_pants, true)
.unwrap(),
permissions
.can_attach_with_rlv_inventory_item_boolean(tree.glasses, true)
.unwrap(),
permissions
.can_attach_with_rlv_inventory_item_boolean(tree.watch, true)
.unwrap(),
],
LockMode::Detach => [
permissions
.can_detach_with_rlv_inventory_item(tree.party_hat)
.unwrap(),
permissions
.can_detach_with_rlv_inventory_item(tree.fancy_hat)
.unwrap(),
permissions
.can_detach_with_rlv_inventory_item(tree.business_pants)
.unwrap(),
permissions
.can_detach_with_rlv_inventory_item(tree.happy_shirt)
.unwrap(),
permissions
.can_detach_with_rlv_inventory_item(tree.retro_pants)
.unwrap(),
permissions
.can_detach_with_rlv_inventory_item(tree.glasses)
.unwrap(),
permissions
.can_detach_with_rlv_inventory_item(tree.watch)
.unwrap(),
],
};
actual == expected_items && locked_folders_match(&h, &identities, expected_folders, mode)
}
const HATS_LOCKED: [bool; 7] = [false, false, true, true, true, true, true];
const CLOTHING_LOCKED: [bool; 7] = [true, true, false, false, false, true, true];
const CLOTHING_RECURSIVE_LOCKED: [bool; 7] = [false, false, false, false, false, true, true];
const ACCESSORIES_LOCKED: [bool; 7] = [true, true, true, true, true, false, false];
const ALL_ALLOWED: [bool; 7] = [true; 7];
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/AttachAllThisRestrictionTests.cs::AttachAllThisRestrictionTests.AttachAllThis::test 39bc0c4581f8277f4d5c90ec715c40f4715b5ae7007a28a04fe762f2f6adfbfd translated
#[test]
fn attach_all_this() {
assert!(folder_case_matches(
"@attachallthis=n",
Some((PRIM_3, "Party Hat (Spine)")),
Setup::PartyChin,
LockMode::Attach,
HATS_LOCKED,
&[FolderKey::Hats, FolderKey::SubHats],
));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/AttachAllThisRestrictionTests.cs::AttachAllThisRestrictionTests.AttachAllThis_Recursive::test d051e7783e79bf91a8092cd2d29cf1aacec3b0af86ecf0c7ca590ce25bc8393c translated
#[test]
fn attach_all_this_recursive() {
assert!(folder_case_matches(
"@attachallthis=n",
Some((PRIM_3, "Business Pants (Pelvis)")),
Setup::BusinessChin,
LockMode::Attach,
CLOTHING_RECURSIVE_LOCKED,
&[FolderKey::Clothing, FolderKey::Hats, FolderKey::SubHats],
));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/AttachAllThisRestrictionTests.cs::AttachAllThisRestrictionTests.AttachAllThis_Recursive_Path::test b4db2b29ad376777b382f8c6f4f7b62643bb2dd43858de4be69ac2252f18c963 translated
#[test]
fn attach_all_this_recursive_path() {
assert!(folder_case_matches(
"@attachallthis:Clothing=n",
None,
Setup::BusinessChin,
LockMode::Attach,
CLOTHING_RECURSIVE_LOCKED,
&[FolderKey::Clothing, FolderKey::Hats, FolderKey::SubHats],
));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/AttachAllThisRestrictionTests.cs::AttachAllThisRestrictionTests.AttachAllThis_Recursive_Worn::test 6ecfc6ffe71896979a37dac6dd8149a015b8d3e7e952247954333c053da4961e translated
#[test]
fn attach_all_this_recursive_worn() {
assert!(folder_case_matches(
"@attachallthis:pants=n",
None,
Setup::RetroPants,
LockMode::Attach,
CLOTHING_RECURSIVE_LOCKED,
&[FolderKey::Clothing, FolderKey::Hats, FolderKey::SubHats],
));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/AttachAllThisRestrictionTests.cs::AttachAllThisRestrictionTests.AttachAllThis_Recursive_Attached::test 8ac38c77c6bdb03e4cbaa96600bead9a760eb5eec098504b05cfb3a1bdfb8557 translated
#[test]
fn attach_all_this_recursive_attached() {
assert!(folder_case_matches(
"@attachallthis:chest=n",
Some((PRIM_3, "Business Pants (Pelvis)")),
Setup::BusinessChest,
LockMode::Attach,
CLOTHING_RECURSIVE_LOCKED,
&[FolderKey::Clothing, FolderKey::Hats, FolderKey::SubHats],
));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/AttachAllThisRestrictionTests.cs::AttachAllThisRestrictionTests.AttachAllThis_Recursive_Attached_AddRem::test 495f288e0fa86059d13a027075700ba6308e9c9d585fa56e3d1adf4a71df912b translated
#[test]
fn attach_all_this_recursive_attached_removed() {
assert!(folder_case_matches(
"@attachallthis:chest=n,@attachallthis:chest=y",
Some((PRIM_3, "Business Pants (Pelvis)")),
Setup::BusinessChest,
LockMode::Attach,
ALL_ALLOWED,
&[],
));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/AttachThisRestrictionTests.cs::AttachThisRestrictionTests.AttachThis::test 3a8a5acc4ad5cbec76737239ea23330a34f54146a4ff9d5d25082c220527a3e4 translated
#[test]
fn attach_this() {
assert!(folder_case_matches(
"@attachthis=n",
Some((PRIM_3, "Party Hat (Spine)")),
Setup::PartySpine,
LockMode::Attach,
HATS_LOCKED,
&[FolderKey::Hats],
));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/AttachThisRestrictionTests.cs::AttachThisRestrictionTests.AttachThis_NotRecursive::test a5818b4e30d04aba7d6427b2b94e025d34e82eb3bdcb7ac80a23e55f2382ec29 translated
#[test]
fn attach_this_not_recursive() {
assert!(folder_case_matches(
"@attachthis=n",
Some((PRIM_1, "Business Pants (Pelvis)")),
Setup::BusinessPelvis,
LockMode::Attach,
CLOTHING_LOCKED,
&[FolderKey::Clothing],
));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/AttachThisRestrictionTests.cs::AttachThisRestrictionTests.AttachThis_ByPath::test 93e1721f171e24e540160e738f731b895ebd868d840bcdf7c16ba92f6eb4c49a translated
#[test]
fn attach_this_by_path() {
assert!(folder_case_matches(
"@attachthis:Clothing/Hats=n",
None,
Setup::None,
LockMode::Attach,
HATS_LOCKED,
&[FolderKey::Hats],
));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/AttachThisRestrictionTests.cs::AttachThisRestrictionTests.AttachThis_ByRlvAttachmentPoint::test 90a562b2c120daa0ea2612befe9e09649bc2ffac59c2cd360fe4a37dedf85ae3 translated
#[test]
fn attach_this_by_attachment_point() {
assert!(folder_case_matches(
"@attachthis:pelvis=n",
None,
Setup::PartyAndBusinessPelvis,
LockMode::Attach,
CLOTHING_RECURSIVE_LOCKED,
&[FolderKey::Clothing, FolderKey::Hats],
));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/AttachThisRestrictionTests.cs::AttachThisRestrictionTests.AttachThis_ByWornLayer::test a444d51c2091fa36f1a010e98ad896042aa0262153ea8a833a14dfcbf02de85e translated
#[test]
fn attach_this_by_worn_layer() {
assert!(folder_case_matches(
"@attachthis:tattoo=n",
None,
Setup::WatchTattoo,
LockMode::Attach,
ACCESSORIES_LOCKED,
&[FolderKey::Accessories],
));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/AttachThisRestrictionTests.cs::AttachThisRestrictionTests.AttachThis_ByWornLayer_AddRem::test dd3d9a0d9b56f08f6be7a6200e1f50e834ecc7613de0cdf44ee89262b3abdb30 translated
#[test]
fn attach_this_by_worn_layer_removed() {
assert!(folder_case_matches(
"@attachthis:tattoo=n,@attachthis:tattoo=y",
None,
Setup::WatchTattoo,
LockMode::Attach,
ALL_ALLOWED,
&[],
));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/DetachAllThisRestrictionTests.cs::DetachAllThisRestrictionTests.DetachAllThis::test ee74f952bd602bd23cfc7b203940a902e1b30e02cff60c1abc1f74da964c1f7d translated
#[test]
fn detach_all_this() {
assert!(folder_case_matches(
"@detachallthis=n",
Some((PRIM_3, "Party Hat (Spine)")),
Setup::PartySpine,
LockMode::Detach,
HATS_LOCKED,
&[FolderKey::Hats, FolderKey::SubHats],
));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/DetachAllThisRestrictionTests.cs::DetachAllThisRestrictionTests.DetachAllThis_Recursive::test 2b6a646ee82484a6d1901ea4425b0e32fe553827f5bea37b506ffe29d1aec192 translated
#[test]
fn detach_all_this_recursive() {
assert!(folder_case_matches(
"@detachallthis=n",
Some((PRIM_3, "Business Pants (Pelvis)")),
Setup::BusinessPelvis,
LockMode::Detach,
CLOTHING_RECURSIVE_LOCKED,
&[FolderKey::Clothing, FolderKey::Hats, FolderKey::SubHats],
));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/DetachAllThisRestrictionTests.cs::DetachAllThisRestrictionTests.DetachAllThis_Recursive_Path::test 731244b623f23a8870d011280a062add751607ce2c58be3261485bb61d488297 translated
#[test]
fn detach_all_this_recursive_path() {
assert!(folder_case_matches(
"@detachallthis:Clothing=n",
None,
Setup::None,
LockMode::Detach,
CLOTHING_RECURSIVE_LOCKED,
&[FolderKey::Clothing, FolderKey::Hats, FolderKey::SubHats],
));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/DetachAllThisRestrictionTests.cs::DetachAllThisRestrictionTests.DetachAllThis_Recursive_Worn::test d8424a48e64346edd683b7a68652dd5a0be615658f085b0390699ac7b4db5d2c translated
#[test]
fn detach_all_this_recursive_worn() {
assert!(folder_case_matches(
"@detachallthis:pants=n",
None,
Setup::RetroPants,
LockMode::Detach,
CLOTHING_RECURSIVE_LOCKED,
&[FolderKey::Clothing, FolderKey::Hats, FolderKey::SubHats],
));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/DetachAllThisRestrictionTests.cs::DetachAllThisRestrictionTests.DetachAllThis_Recursive_Attached::test f399592217e7a4638ea25d469681ab9cc58bf8a937af2bfff8895996f7bbc493 translated
#[test]
fn detach_all_this_recursive_attached() {
assert!(folder_case_matches(
"@detachallthis:chest=n",
None,
Setup::BusinessChest,
LockMode::Detach,
CLOTHING_RECURSIVE_LOCKED,
&[FolderKey::Clothing, FolderKey::Hats, FolderKey::SubHats],
));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/DetachAllThisRestrictionTests.cs::DetachAllThisRestrictionTests.DetachAllThis_Recursive_Attached_AddRem::test 507273250b932ff93fa34f87190ad1ab289edeed275be6d2259bab05c5b055d1 translated
#[test]
fn detach_all_this_recursive_attached_removed() {
assert!(folder_case_matches(
"@detachallthis:chest=n,@detachallthis:chest=y",
None,
Setup::BusinessChest,
LockMode::Detach,
ALL_ALLOWED,
&[],
));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/DetachThisRestrictionTests.cs::DetachThisRestrictionTests.DetachThis::test bf6cdb48a5271d5116db4d0cbf12dbf63fc3cc93862bf718cf849d4abf9eb7cc translated
#[test]
fn detach_this() {
assert!(folder_case_matches(
"@detachthis=n",
Some((PRIM_3, "Party Hat (Spine)")),
Setup::PartySpine,
LockMode::Detach,
HATS_LOCKED,
&[FolderKey::Hats],
));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/DetachThisRestrictionTests.cs::DetachThisRestrictionTests.DetachThis_NotRecursive::test a8452e2b0abcf82447394bae981a1d25677147fad17828d8f6d0705264efa429 translated
#[test]
fn detach_this_not_recursive() {
assert!(folder_case_matches(
"@detachthis=n",
Some((PRIM_3, "Business Pants (Pelvis)")),
Setup::BusinessPelvis,
LockMode::Detach,
CLOTHING_LOCKED,
&[FolderKey::Clothing],
));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/DetachThisRestrictionTests.cs::DetachThisRestrictionTests.DetachThis_ByPath::test e6378e0db310005b8426cabd25969818ed36252e1995de97c6b29d5ab155ee58 translated
#[test]
fn detach_this_by_path() {
assert!(folder_case_matches(
"@detachthis:Clothing=n",
None,
Setup::None,
LockMode::Detach,
CLOTHING_LOCKED,
&[FolderKey::Clothing],
));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/DetachThisRestrictionTests.cs::DetachThisRestrictionTests.DetachThis_ByRlvAttachmentPoint::test 278e4cbf0f9999efec04fcabade19da97439cca732e0e7e3e3c004e232c27224 translated
#[test]
fn detach_this_by_attachment_point() {
assert!(folder_case_matches(
"@detachthis:pelvis=n",
None,
Setup::PartyAndBusinessPelvisDetach,
LockMode::Detach,
CLOTHING_RECURSIVE_LOCKED,
&[FolderKey::Clothing, FolderKey::Hats],
));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/DetachThisRestrictionTests.cs::DetachThisRestrictionTests.DetachThis_ByWornLayer::test 66b7eba54e34ed58c59d594cdcb85d874c4db9bbbd871e5438c40fd3d47ad3f6 translated
#[test]
fn detach_this_by_worn_layer() {
assert!(folder_case_matches(
"@detachthis:tattoo=n",
None,
Setup::WatchTattoo,
LockMode::Detach,
ACCESSORIES_LOCKED,
&[FolderKey::Accessories],
));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/DetachThisRestrictionTests.cs::DetachThisRestrictionTests.DetachThis_ByWornLayer_AddRem::test 7424bf38db1abd74132618ee3bcf95a79c32942da26086760dc82355a815d37e translated
#[test]
fn detach_this_by_worn_layer_removed() {
assert!(folder_case_matches(
"@detachthis:tattoo=n,@detachthis:tattoo=y",
None,
Setup::WatchTattoo,
LockMode::Detach,
ALL_ALLOWED,
&[],
));
}

View File

@@ -0,0 +1,424 @@
//! Exact Rust translations of every `detach`/`remattach` alias case.
use libremetaverse_compat_tests::block_on;
use libremetaverse_compat_tests::rlv_support::{RlvHarness, SampleInventoryTree, guid};
use libremetaverse_rlv::{InventoryMap, RlvAttachmentPoint, RlvInventoryItem, RlvWearableType};
use libremetaverse_types::compat::Guid;
const HAPPY: &str = "b1111111-bbbb-4bbb-8bbb-bbbbbbbbbbbb";
const RETRO: &str = "b2222222-bbbb-4bbb-8bbb-bbbbbbbbbbbb";
const FANCY: &str = "d1111111-dddd-4ddd-8ddd-dddddddddddd";
const EXTERNAL: &str = "12312312-0002-4aaa-8aaa-aaaaaaaaaaaa";
const PRIM1: &str = "11111111-0001-4aaa-8aaa-ffffffffffff";
const EXTERNAL_PRIM: &str = "12312312-0002-4aaa-8aaa-ffffffffffff";
#[derive(Clone, Copy)]
enum Setup {
Normal,
NoStrip,
NoStripLink,
External,
Folder,
FolderNoStrip,
FolderLink,
Point,
PointNoStrip,
PointLink,
PointNone,
Uuid,
UuidItemNoStrip,
UuidFolderNoStrip,
UuidFolderLink,
UuidRestricted,
UuidExternal,
}
fn attach(item: &mut RlvInventoryItem, point: RlvAttachmentPoint, prim: &str) {
item.set_attached_to(Some(Some(point)));
item.set_attached_prim_id(Some(Some(guid(prim))));
}
fn external(
id: &str,
name: &str,
point: Option<RlvAttachmentPoint>,
prim: Option<&str>,
worn: Option<RlvWearableType>,
) -> RlvInventoryItem {
RlvInventoryItem::new(
guid(id),
name.into(),
false,
Some(Some(guid("12312312-aaaa-4aaa-8aaa-aaaaaaaaaaaa"))),
point.map(Some),
prim.map(|v| Some(guid(v))),
worn.map(Some),
None,
)
.unwrap()
}
fn base(tree: &mut SampleInventoryTree) {
attach(&mut tree.happy_shirt, RlvAttachmentPoint::Chest, PRIM1);
attach(
&mut tree.fancy_hat,
RlvAttachmentPoint::Chin,
"11111111-0003-4aaa-8aaa-ffffffffffff",
);
tree.retro_pants
.set_worn_on(Some(Some(RlvWearableType::Pants)));
}
#[allow(clippy::too_many_lines)]
fn run(command: &str, setup: Setup) -> Vec<Guid> {
let h = RlvHarness::new().expect("RlvService constructor");
let mut tree = SampleInventoryTree::build().unwrap();
let mut external_items = vec![];
base(&mut tree);
match setup {
Setup::NoStrip | Setup::NoStripLink => {
tree.hats.set_name("nostrip Hats".into());
tree.happy_shirt.set_name("nostrip Happy Shirt".into());
attach(
&mut tree.retro_pants,
RlvAttachmentPoint::Groin,
"11111111-0005-4aaa-8aaa-ffffffffffff",
);
if matches!(setup, Setup::NoStripLink) {
tree.fancy_hat.set_is_link(true);
}
}
Setup::External => {
external_items.push(external(
"12312312-0001-4aaa-8aaa-aaaaaaaaaaaa",
"External Tattoo",
None,
None,
Some(RlvWearableType::Tattoo),
));
external_items.push(external(
EXTERNAL,
"External Jaw Thing",
Some(RlvAttachmentPoint::Jaw),
Some(EXTERNAL_PRIM),
None,
));
}
Setup::FolderNoStrip | Setup::FolderLink => {
tree.hats.set_name("nostrip Hats".into());
if matches!(setup, Setup::FolderLink) {
tree.fancy_hat.set_is_link(true);
}
}
Setup::Point => external_items.push(external(
EXTERNAL,
"External Chest Thing",
Some(RlvAttachmentPoint::Chest),
Some(EXTERNAL_PRIM),
None,
)),
Setup::PointNoStrip | Setup::PointLink => {
tree.hats.set_name("nostrip Hats".into());
tree.happy_shirt.set_name("nostrip Happy Shirt".into());
attach(
&mut tree.fancy_hat,
RlvAttachmentPoint::Chest,
"11111111-0003-4aaa-8aaa-ffffffffffff",
);
attach(
&mut tree.retro_pants,
RlvAttachmentPoint::Chest,
"11111111-0005-4aaa-8aaa-ffffffffffff",
);
if matches!(setup, Setup::PointLink) {
tree.fancy_hat.set_is_link(true);
}
external_items.push(external(
EXTERNAL,
"External Chest Thing",
Some(RlvAttachmentPoint::Chest),
Some(EXTERNAL_PRIM),
None,
));
external_items.push(external(
"12312312-0003-4aaa-8aaa-aaaaaaaaaaaa",
"nostrip External Chest Thing",
Some(RlvAttachmentPoint::Chest),
Some("12312312-0003-4aaa-8aaa-ffffffffffff"),
None,
));
}
Setup::UuidItemNoStrip => tree.happy_shirt.set_name("nostrip Happy Shirt".into()),
Setup::UuidFolderNoStrip | Setup::UuidFolderLink => {
tree.clothing.set_name("nostrip Clothing".into());
if matches!(setup, Setup::UuidFolderLink) {
tree.happy_shirt.set_is_link(true);
}
}
Setup::UuidExternal => external_items.push(external(
EXTERNAL,
"External Jaw Thing",
Some(RlvAttachmentPoint::Jaw),
Some(EXTERNAL_PRIM),
None,
)),
_ => {}
}
h.queries.lock().unwrap().inventory_map =
Some(InventoryMap::new(tree.root, external_items).unwrap());
if matches!(setup, Setup::UuidRestricted) {
block_on(h.process("@detachallthis:Clothing=n")).unwrap();
}
block_on(h.process(command)).unwrap();
let mut v = h.actions.lock().unwrap().detachments[0].clone();
v.sort_by_key(|id| id.0);
v
}
fn ids(values: &[&str]) -> Vec<Guid> {
let mut v: Vec<_> = values.iter().map(|s| guid(s)).collect();
v.sort_by_key(|id| id.0);
v
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach::case:bb1d34dc76ade75f 16420d56c60229e8d8b6a2a0d63b1f500112c23cef451d69bb0ed97fe9b63bae translated
#[test]
fn detach_all_attachments() {
assert_eq!(run("@detach=force", Setup::Normal), ids(&[HAPPY, FANCY]));
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach::case:c9faa5be8fef55e8 16420d56c60229e8d8b6a2a0d63b1f500112c23cef451d69bb0ed97fe9b63bae translated
#[test]
fn remattach_all_attachments() {
assert_eq!(run("@remattach=force", Setup::Normal), ids(&[HAPPY, FANCY]));
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_NoStrip::case:bb1d34dc76ade75f 5b3f1cbe99833e16c6f10ef568618627445babbcdfc9be555b48257bfdffeea7 translated
#[test]
fn detach_honors_nostrip() {
assert_eq!(run("@detach=force", Setup::NoStrip), ids(&[RETRO]));
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_NoStrip::case:c9faa5be8fef55e8 5b3f1cbe99833e16c6f10ef568618627445babbcdfc9be555b48257bfdffeea7 translated
#[test]
fn remattach_honors_nostrip() {
assert_eq!(run("@remattach=force", Setup::NoStrip), ids(&[RETRO]));
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_NoStrip_LinkException::case:bb1d34dc76ade75f 96a4b53d9e55dcd656c25af6619a3d0d67f5bc2517a759d722559a4ffb225472 translated
#[test]
fn detach_honors_nostrip_link_exception() {
assert_eq!(
run("@detach=force", Setup::NoStripLink),
ids(&[RETRO, FANCY])
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_NoStrip_LinkException::case:c9faa5be8fef55e8 96a4b53d9e55dcd656c25af6619a3d0d67f5bc2517a759d722559a4ffb225472 translated
#[test]
fn remattach_honors_nostrip_link_exception() {
assert_eq!(
run("@remattach=force", Setup::NoStripLink),
ids(&[RETRO, FANCY])
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ExternalItems::case:bb1d34dc76ade75f 7545f36532fcb7974a9e009e567b2342754a11da95eb3f17ee04089dcec42664 translated
#[test]
fn detach_external_items() {
assert_eq!(
run("@detach=force", Setup::External),
ids(&[HAPPY, FANCY, EXTERNAL])
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ExternalItems::case:c9faa5be8fef55e8 7545f36532fcb7974a9e009e567b2342754a11da95eb3f17ee04089dcec42664 translated
#[test]
fn remattach_external_items() {
assert_eq!(
run("@remattach=force", Setup::External),
ids(&[HAPPY, FANCY, EXTERNAL])
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ByFolder::case:97eb7af1f9c3c62c 583d3f596c80411d950038e3ec64032bee75150b8c819741fe89a4ca40eb2553 translated
#[test]
fn detach_by_folder() {
assert_eq!(
run("@detach:Clothing/Hats=force", Setup::Folder),
ids(&[FANCY])
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ByFolder::case:1a04fd408fddaac0 583d3f596c80411d950038e3ec64032bee75150b8c819741fe89a4ca40eb2553 translated
#[test]
fn remattach_by_folder() {
assert_eq!(
run("@remattach:Clothing/Hats=force", Setup::Folder),
ids(&[FANCY])
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ByFolder_NoStrip::case:2117c838922f5ba4 3a21b8ae807126d6f93ac95e16c47330b4146ace9781e9c9665ad493ee8c48b1 translated
#[test]
fn detach_by_folder_honors_nostrip() {
assert!(run("@detach:Clothing/nostrip Hats=force", Setup::FolderNoStrip).is_empty());
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ByFolder_NoStrip::case:11d4ca4fd3e35db1 3a21b8ae807126d6f93ac95e16c47330b4146ace9781e9c9665ad493ee8c48b1 translated
#[test]
fn remattach_by_folder_honors_nostrip() {
assert!(
run(
"@remattach:Clothing/nostrip Hats=force",
Setup::FolderNoStrip
)
.is_empty()
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ByFolder_NoStrip_LinkException::case:2117c838922f5ba4 7c00e7dc70b3078d75009cf78a9fece889eee85f237c1a3c79c6249ae5e5327f translated
#[test]
fn detach_by_folder_honors_link_exception() {
assert_eq!(
run("@detach:Clothing/nostrip Hats=force", Setup::FolderLink),
ids(&[FANCY])
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ByFolder_NoStrip_LinkException::case:11d4ca4fd3e35db1 7c00e7dc70b3078d75009cf78a9fece889eee85f237c1a3c79c6249ae5e5327f translated
#[test]
fn remattach_by_folder_honors_link_exception() {
assert_eq!(
run("@remattach:Clothing/nostrip Hats=force", Setup::FolderLink),
ids(&[FANCY])
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ByAttachmentPoint::case:644d3f75f3570ac3 e09627228c1cf8311e56ac6660389bc1b268db8fd4f883dc40aaf3d2ec00916b translated
#[test]
fn detach_by_attachment_point() {
assert_eq!(
run("@detach:chest=force", Setup::Point),
ids(&[HAPPY, EXTERNAL])
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ByAttachmentPoint::case:53be219b37533fa6 e09627228c1cf8311e56ac6660389bc1b268db8fd4f883dc40aaf3d2ec00916b translated
#[test]
fn remattach_by_attachment_point() {
assert_eq!(
run("@remattach:chest=force", Setup::Point),
ids(&[HAPPY, EXTERNAL])
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ByAttachmentPoint_NoStrip::case:644d3f75f3570ac3 ffaaad92700d5d606154abdddd05c24c7584c5c3e55290df61e2b2a71d8148d7 translated
#[test]
fn detach_by_attachment_point_honors_nostrip() {
assert_eq!(
run("@detach:chest=force", Setup::PointNoStrip),
ids(&[RETRO, EXTERNAL])
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ByAttachmentPoint_NoStrip::case:53be219b37533fa6 ffaaad92700d5d606154abdddd05c24c7584c5c3e55290df61e2b2a71d8148d7 translated
#[test]
fn remattach_by_attachment_point_honors_nostrip() {
assert_eq!(
run("@remattach:chest=force", Setup::PointNoStrip),
ids(&[RETRO, EXTERNAL])
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ByAttachmentPoint_NoStrip_LinkException::case:644d3f75f3570ac3 af1b1caf070a186bc2b02b598919b52d47c289d708fde3713e48ce1a40d7c025 translated
#[test]
fn detach_by_attachment_point_honors_link_exception() {
assert_eq!(
run("@detach:chest=force", Setup::PointLink),
ids(&[RETRO, FANCY, EXTERNAL])
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ByAttachmentPoint_NoStrip_LinkException::case:53be219b37533fa6 af1b1caf070a186bc2b02b598919b52d47c289d708fde3713e48ce1a40d7c025 translated
#[test]
fn remattach_by_attachment_point_honors_link_exception() {
assert_eq!(
run("@remattach:chest=force", Setup::PointLink),
ids(&[RETRO, FANCY, EXTERNAL])
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ByAttachmentPoint_None::case:9a124e69f33b279f afed603254ad6048a46e157254f16253063e6c76c9ea16f46a69d8455bc0e6fb translated
#[test]
fn detach_by_missing_attachment_point() {
assert!(run("@detach:skull=force", Setup::PointNone).is_empty());
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ByAttachmentPoint_None::case:800d7d8ba57071b1 afed603254ad6048a46e157254f16253063e6c76c9ea16f46a69d8455bc0e6fb translated
#[test]
fn remattach_by_missing_attachment_point() {
assert!(run("@remattach:skull=force", Setup::PointNone).is_empty());
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ByUUID::case:e5bdbdba9613b46a 4b1a8acea7f1bb100bf11e9329672c64b53aba4974558f1c693460eef7f56c2d translated
#[test]
fn detach_by_uuid() {
assert_eq!(
run(&format!("@detach:{PRIM1}=force"), Setup::Uuid),
ids(&[HAPPY])
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ByUUID::case:7cb3f81460bd8e9f 4b1a8acea7f1bb100bf11e9329672c64b53aba4974558f1c693460eef7f56c2d translated
#[test]
fn remattach_by_uuid() {
assert_eq!(
run(&format!("@remattach:{PRIM1}=force"), Setup::Uuid),
ids(&[HAPPY])
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ByUUID_NostripInItemName::case:e5bdbdba9613b46a 6857733912b45ef9153b0f58cd74ae6c9dc0034fa10933d153cae88a2c7d9423 translated
#[test]
fn detach_by_uuid_honors_item_nostrip() {
assert!(run(&format!("@detach:{PRIM1}=force"), Setup::UuidItemNoStrip).is_empty());
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ByUUID_NostripInItemName::case:7cb3f81460bd8e9f 6857733912b45ef9153b0f58cd74ae6c9dc0034fa10933d153cae88a2c7d9423 translated
#[test]
fn remattach_by_uuid_honors_item_nostrip() {
assert!(run(&format!("@remattach:{PRIM1}=force"), Setup::UuidItemNoStrip).is_empty());
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ByUUID_NostripInFolderName::case:e5bdbdba9613b46a 1a3189f931e086ab3d2d3e99c53dba2e9d39dce75a52fd02400c6892aef5d0c4 translated
#[test]
fn detach_by_uuid_honors_folder_nostrip() {
assert!(run(&format!("@detach:{PRIM1}=force"), Setup::UuidFolderNoStrip).is_empty());
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ByUUID_NostripInFolderName::case:7cb3f81460bd8e9f 1a3189f931e086ab3d2d3e99c53dba2e9d39dce75a52fd02400c6892aef5d0c4 translated
#[test]
fn remattach_by_uuid_honors_folder_nostrip() {
assert!(
run(
&format!("@remattach:{PRIM1}=force"),
Setup::UuidFolderNoStrip
)
.is_empty()
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ByUUID_NostripInFolderName_LinkException::case:e5bdbdba9613b46a bd7bc72a107b4a21b00977e13b086da192bef2c2e6f0fdb73b8e332016c6ef23 translated
#[test]
fn detach_by_uuid_honors_folder_link_exception() {
assert_eq!(
run(&format!("@detach:{PRIM1}=force"), Setup::UuidFolderLink),
ids(&[HAPPY])
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ByUUID_NostripInFolderName_LinkException::case:7cb3f81460bd8e9f bd7bc72a107b4a21b00977e13b086da192bef2c2e6f0fdb73b8e332016c6ef23 translated
#[test]
fn remattach_by_uuid_honors_folder_link_exception() {
assert_eq!(
run(&format!("@remattach:{PRIM1}=force"), Setup::UuidFolderLink),
ids(&[HAPPY])
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ByUUID_WithRestrictions::case:e5bdbdba9613b46a 2ecf40d1d338117ddac4cfd6c7a030e96b7adf72cd90e0d8327787317e1f38d7 translated
#[test]
fn detach_by_uuid_honors_restrictions() {
assert!(run(&format!("@detach:{PRIM1}=force"), Setup::UuidRestricted).is_empty());
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ByUUID_WithRestrictions::case:7cb3f81460bd8e9f 2ecf40d1d338117ddac4cfd6c7a030e96b7adf72cd90e0d8327787317e1f38d7 translated
#[test]
fn remattach_by_uuid_honors_restrictions() {
assert!(run(&format!("@remattach:{PRIM1}=force"), Setup::UuidRestricted).is_empty());
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ByUUID_External::case:e5bdbdba9613b46a e0bdc682df3416bdc01855e6e63974e64c21951aac629807352220baf572dded translated
#[test]
fn detach_external_by_uuid() {
assert_eq!(
run(
&format!("@detach:{EXTERNAL_PRIM}=force"),
Setup::UuidExternal
),
ids(&[EXTERNAL])
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/RemAttachCommandTests.cs::RemAttachCommandTests.RemAttach_ByUUID_External::case:7cb3f81460bd8e9f e0bdc682df3416bdc01855e6e63974e64c21951aac629807352220baf572dded translated
#[test]
fn remattach_external_by_uuid() {
assert_eq!(
run(
&format!("@remattach:{EXTERNAL_PRIM}=force"),
Setup::UuidExternal
),
ids(&[EXTERNAL])
);
}

View File

@@ -0,0 +1,257 @@
//! Exact Rust translations of `RemOutfitCommandTests`.
use libremetaverse_compat_tests::block_on;
use libremetaverse_compat_tests::rlv_support::{RlvHarness, SampleInventoryTree, guid};
use libremetaverse_rlv::{InventoryMap, RlvInventoryItem, RlvWearableType};
use libremetaverse_types::compat::Guid;
const RETRO: &str = "b2222222-bbbb-4bbb-8bbb-bbbbbbbbbbbb";
const HAPPY: &str = "b1111111-bbbb-4bbb-8bbb-bbbbbbbbbbbb";
const WATCH: &str = "c0000000-cccc-4ccc-8ccc-cccccccccccc";
const PARTY: &str = "d0000000-dddd-4ddd-8ddd-dddddddddddd";
const FANCY: &str = "d1111111-dddd-4ddd-8ddd-dddddddddddd";
const EXTERNAL1: &str = "12312312-0001-4aaa-8aaa-aaaaaaaaaaaa";
const EXTERNAL2: &str = "12312312-0002-4aaa-8aaa-aaaaaaaaaaaa";
#[derive(Clone, Copy)]
enum Setup {
All,
PrivateClothing,
External,
ExternalNoStrip,
ExternalNoStripLink,
ExternalByType,
Folder,
PrivateFolder,
FolderNoStripItem,
FolderNoStripName,
FolderNoStripNameLink,
Specific,
SpecificPrivate,
SpecificNoStrip,
SpecificNoStripLink,
BodyPart,
}
fn external(id: &str, name: &str) -> RlvInventoryItem {
RlvInventoryItem::new(
guid(id),
name.into(),
false,
Some(Some(guid("12312312-aaaa-4aaa-8aaa-aaaaaaaaaaaa"))),
None,
None,
Some(Some(RlvWearableType::Tattoo)),
None,
)
.unwrap()
}
fn base_worn(tree: &mut SampleInventoryTree) {
tree.retro_pants
.set_worn_on(Some(Some(RlvWearableType::Pants)));
tree.happy_shirt
.set_worn_on(Some(Some(RlvWearableType::Shirt)));
tree.watch.set_worn_on(Some(Some(RlvWearableType::Tattoo)));
tree.fancy_hat
.set_worn_on(Some(Some(RlvWearableType::Tattoo)));
tree.party_hat
.set_worn_on(Some(Some(RlvWearableType::Skin)));
}
fn run(command: &str, setup: Setup) -> Vec<Guid> {
let h = RlvHarness::new().expect("RlvService constructor");
let mut tree = SampleInventoryTree::build().unwrap();
let mut external_items = vec![];
match setup {
Setup::All | Setup::Folder | Setup::Specific | Setup::BodyPart => base_worn(&mut tree),
Setup::PrivateClothing => {
base_worn(&mut tree);
tree.clothing.set_name(".Clothing".into());
}
Setup::External | Setup::ExternalByType => {
base_worn(&mut tree);
external_items.push(external(EXTERNAL1, "External Tattoo"));
}
Setup::ExternalNoStrip | Setup::ExternalNoStripLink => {
base_worn(&mut tree);
tree.hats.set_name("nostrip Hats".into());
tree.happy_shirt.set_name("nostrip Happy Shirt".into());
if matches!(setup, Setup::ExternalNoStripLink) {
tree.fancy_hat.set_is_link(true);
}
external_items.push(external(EXTERNAL1, "External Tattoo"));
external_items.push(external(EXTERNAL2, "nostrip External Tattoo"));
}
Setup::PrivateFolder | Setup::SpecificPrivate => {
base_worn(&mut tree);
tree.hats.set_name(".Hats".into());
}
Setup::FolderNoStripItem => {
base_worn(&mut tree);
tree.fancy_hat.set_name("nostrip Fancy Hat".into());
}
Setup::FolderNoStripName | Setup::FolderNoStripNameLink => {
base_worn(&mut tree);
tree.hats.set_name("nostrip Hats".into());
if matches!(setup, Setup::FolderNoStripNameLink) {
tree.fancy_hat.set_is_link(true);
}
}
Setup::SpecificNoStrip | Setup::SpecificNoStripLink => {
tree.retro_pants
.set_worn_on(Some(Some(RlvWearableType::Pants)));
tree.watch.set_worn_on(Some(Some(RlvWearableType::Pants)));
tree.party_hat
.set_worn_on(Some(Some(RlvWearableType::Pants)));
tree.glasses
.set_worn_on(Some(Some(RlvWearableType::Tattoo)));
tree.watch.set_name("nostrip Watch".into());
tree.clothing.set_name("nostrip clothing".into());
if matches!(setup, Setup::SpecificNoStripLink) {
tree.retro_pants.set_is_link(true);
}
}
}
h.queries.lock().unwrap().inventory_map =
Some(InventoryMap::new(tree.root, external_items).unwrap());
block_on(h.process(command)).unwrap();
let mut ids = h.actions.lock().unwrap().removed_outfits[0].clone();
ids.sort_by_key(|id| id.0);
ids
}
fn ids(values: &[&str]) -> Vec<Guid> {
let mut result: Vec<_> = values.iter().map(|value| guid(value)).collect();
result.sort_by_key(|id| id.0);
result
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/RemOutfitCommandTests.cs::RemOutfitCommandTests.RemOutfit::test 60bd0e62bbd4613c4d2d1a65705644dc25fd7327408adfc0bb7e95c45d79cdcb translated
#[test]
fn remove_outfit() {
assert_eq!(
run("@remoutfit=force", Setup::All),
ids(&[RETRO, HAPPY, WATCH, FANCY])
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/RemOutfitCommandTests.cs::RemOutfitCommandTests.RemOutfit_PrivateFolders::test d79ac3806f50915390edd0a24b756ef398c1334017f69d16f4cb887dcdd41fb1 translated
#[test]
fn remove_outfit_in_private_folders() {
assert_eq!(
run("@remoutfit=force", Setup::PrivateClothing),
ids(&[RETRO, HAPPY, WATCH, FANCY])
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/RemOutfitCommandTests.cs::RemOutfitCommandTests.RemOutfit_ExternalItems::test 0265a9fee1070cbcc458bfcb05fe267991cbdb5480500c1b32aace1eb4935217 translated
#[test]
fn remove_outfit_external_items() {
assert_eq!(
run("@remoutfit=force", Setup::External),
ids(&[RETRO, HAPPY, WATCH, FANCY, EXTERNAL1])
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/RemOutfitCommandTests.cs::RemOutfitCommandTests.RemOutfit_ExternalItems_NoStrip::test b93d39d919fb70b02ccdb724969f7b983c726c707bca96e1b1ddc6ee248a734f translated
#[test]
fn remove_outfit_external_items_honors_nostrip() {
assert_eq!(
run("@remoutfit=force", Setup::ExternalNoStrip),
ids(&[RETRO, WATCH, EXTERNAL1])
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/RemOutfitCommandTests.cs::RemOutfitCommandTests.RemOutfit_ExternalItems_NoStrip_LinkException::test 5ecc44228573645e0a0c78d100dab54b793c6ce8dc50a02d79a919fe6d7c1678 translated
#[test]
fn remove_outfit_external_items_honors_link_exception() {
assert_eq!(
run("@remoutfit=force", Setup::ExternalNoStripLink),
ids(&[RETRO, WATCH, FANCY, EXTERNAL1])
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/RemOutfitCommandTests.cs::RemOutfitCommandTests.RemOutfit_ExternalItems_ByType::test 8ba106f071f8768af1d6213c04f67dd0aec846ae47552686eba86c489bdb0292 translated
#[test]
fn remove_outfit_external_items_by_type() {
assert_eq!(
run("@remoutfit:tattoo=force", Setup::ExternalByType),
ids(&[FANCY, WATCH, EXTERNAL1])
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/RemOutfitCommandTests.cs::RemOutfitCommandTests.RemOutfit_Folder::test 45f9e7a9d0ef99ec7d58b59f1c1db7b6065994939717842bb02486b470b357b5 translated
#[test]
fn remove_outfit_folder() {
assert_eq!(
run("@remoutfit:Clothing/Hats=force", Setup::Folder),
ids(&[FANCY])
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/RemOutfitCommandTests.cs::RemOutfitCommandTests.RemOutfit_Folder_PrivateFolder::test 68f3050a1b667304ff2b252690cc7d1994964dbd2c7633d54e5c6654714c0aed translated
#[test]
fn remove_outfit_private_folder() {
assert_eq!(
run("@remoutfit:Clothing/Hats=force", Setup::PrivateFolder),
ids(&[FANCY])
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/RemOutfitCommandTests.cs::RemOutfitCommandTests.RemOutfit_Folder_NoStrip::test d56b83a72d6d3529af0390674550ce40733c14de6210cf71e277f0e195d1e330 translated
#[test]
fn remove_outfit_folder_honors_item_nostrip() {
assert!(run("@remoutfit:Clothing/Hats=force", Setup::FolderNoStripItem).is_empty());
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/RemOutfitCommandTests.cs::RemOutfitCommandTests.RemOutfit_Folder_NoStripFolderName::test a28f5517a9d05085627d5acaf33441d598912301962f6e99aaff49ef5114af53 translated
#[test]
fn remove_outfit_folder_honors_folder_nostrip() {
assert!(
run(
"@remoutfit:Clothing/nostrip Hats=force",
Setup::FolderNoStripName
)
.is_empty()
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/RemOutfitCommandTests.cs::RemOutfitCommandTests.RemOutfit_Folder_NoStripFolderName_LinkException::test 80efc201f976365e68d32ae1b30db0f10a17cbc65aedc82895ffa679700008da translated
#[test]
fn remove_outfit_folder_honors_link_exception() {
assert_eq!(
run(
"@remoutfit:Clothing/nostrip Hats=force",
Setup::FolderNoStripNameLink
),
ids(&[FANCY])
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/RemOutfitCommandTests.cs::RemOutfitCommandTests.RemOutfit_Specific::test 7235143679739442ec942d294a8a68f69b7fb5678ed4e3ca03be35c74e9c71a9 translated
#[test]
fn remove_outfit_specific() {
assert_eq!(
run("@remoutfit:tattoo=force", Setup::Specific),
ids(&[FANCY, WATCH])
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/RemOutfitCommandTests.cs::RemOutfitCommandTests.RemOutfit_Specific_PrivateFolder::test 3feea26f000dc7eb86b1413f1a5bdd5f109c5f9f969918cd1ce2e7f926f26c12 translated
#[test]
fn remove_outfit_specific_private_folder() {
assert_eq!(
run("@remoutfit:tattoo=force", Setup::SpecificPrivate),
ids(&[FANCY, WATCH])
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/RemOutfitCommandTests.cs::RemOutfitCommandTests.RemOutfit_Specific_NoStrip::test 6e4b8bc53933a889df1cf553ca7e0601e5061bb87013a4075c2ff357cc9d987f translated
#[test]
fn remove_outfit_specific_honors_nostrip() {
assert_eq!(
run("@remoutfit:pants=force", Setup::SpecificNoStrip),
ids(&[PARTY])
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/RemOutfitCommandTests.cs::RemOutfitCommandTests.RemOutfit_Specific_NoStrip_LinkException::test 72b1409f70531d859f15a012cb1fb03d795d2065c5d03b7a263d352ca4b80e98 translated
#[test]
fn remove_outfit_specific_honors_link_exception() {
assert_eq!(
run("@remoutfit:pants=force", Setup::SpecificNoStripLink),
ids(&[PARTY, RETRO])
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/RemOutfitCommandTests.cs::RemOutfitCommandTests.RemOutfit_BodyPart_Specific::test 13804c96395db86821371dc8f2cacd2cb182338f8ea88034afcc5da19e3f0691 translated
#[test]
fn remove_outfit_does_not_remove_body_part() {
assert!(run("@remoutfit:skin=force", Setup::BodyPart).is_empty());
}

View File

@@ -0,0 +1,256 @@
// Exact Rust translations of RlvRestrictionManagerTests.
use libremetaverse_compat_tests::block_on;
use libremetaverse_compat_tests::rlv_support::{RlvHarness, guid};
use libremetaverse_rlv::RlvRestrictionType;
use libremetaverse_types::compat::Guid;
use std::sync::{Arc, Mutex};
const PRIM_1: &str = "11111111-1111-1111-1111-111111111111";
const PRIM_2: &str = "22222222-2222-2222-2222-222222222222";
const PRIM_3: &str = "33333333-3333-3333-3333-333333333333";
const MISSING: &str = "99999999-9999-9999-9999-999999999999";
fn harness() -> RlvHarness {
RlvHarness::new().expect("RlvService constructor")
}
fn process_from(h: &RlvHarness, sender: &str, commands: &[&str]) {
for command in commands {
block_on(h.process_from(command, sender, "TestObject")).unwrap();
}
}
fn tracked(h: &RlvHarness) -> Vec<Guid> {
h.service
.restrictions()
.get_tracked_prim_ids()
.unwrap()
.collect()
}
async fn remove(h: &RlvHarness, ids: Vec<Guid>) {
h.service
.restrictions()
.remove_restrictions_for_objects(Box::new(ids.into_iter()), None)
.await
.unwrap();
}
// parity-case: LibreMetaverse.Tests/RLV/RlvRestrictionManagerTests.cs::RlvRestrictionManagerTests.GetTrackedPrimIds_NoRestrictions_ReturnsEmptyCollection::test 327086a5aa514ddf8b2cc40891f7ae5e8039788f5cbfeda86f04bd9161f39ded translated
#[test]
fn tracked_prim_ids_empty() {
assert!(tracked(&harness()).is_empty());
}
// parity-case: LibreMetaverse.Tests/RLV/RlvRestrictionManagerTests.cs::RlvRestrictionManagerTests.GetTrackedPrimIds_SingleRestriction_ReturnsSingleId::test 85a822c9e2e8beb2e70748513a397b8ccbb2977c0581b0519bd8ad43e699ad57 translated
#[test]
fn tracked_prim_ids_single_restriction() {
let h = harness();
process_from(&h, PRIM_1, &["@fly=n"]);
assert_eq!(tracked(&h), vec![guid(PRIM_1)]);
}
// parity-case: LibreMetaverse.Tests/RLV/RlvRestrictionManagerTests.cs::RlvRestrictionManagerTests.GetTrackedPrimIds_MultipleRestrictionsFromSameObject_ReturnsSingleId::test 933070f933b0a5a39b3d0cd5fd9be9423a538609d0106b352a7d9c339665d6d1 translated
#[test]
fn tracked_prim_ids_deduplicates_one_object() {
let h = harness();
process_from(&h, PRIM_1, &["@fly=n", "@jump=n", "@sit=n"]);
assert_eq!(tracked(&h), vec![guid(PRIM_1)]);
}
// parity-case: LibreMetaverse.Tests/RLV/RlvRestrictionManagerTests.cs::RlvRestrictionManagerTests.GetTrackedPrimIds_MultipleObjects_ReturnsAllUniqueIds::test 8c2afe66145e4815e73d7849f83cfec50e4a7a49793cc757917cd608c9387419 translated
#[test]
fn tracked_prim_ids_multiple_objects() {
let h = harness();
process_from(&h, PRIM_1, &["@fly=n"]);
process_from(&h, PRIM_2, &["@jump=n"]);
process_from(&h, PRIM_3, &["@sit=n"]);
let ids = tracked(&h);
assert_eq!(ids.len(), 3);
assert!(ids.contains(&guid(PRIM_1)));
assert!(ids.contains(&guid(PRIM_2)));
assert!(ids.contains(&guid(PRIM_3)));
}
// parity-case: LibreMetaverse.Tests/RLV/RlvRestrictionManagerTests.cs::RlvRestrictionManagerTests.GetTrackedPrimIds_MixedRestrictionsAndExceptions_ReturnsAllUniqueIds::test 25ea3c36aba93d5183816962bf49bfdbc3e17e6b06d73a41dee5b51407a84746 translated
#[test]
fn tracked_prim_ids_include_restrictions_and_exceptions() {
let h = harness();
process_from(&h, PRIM_1, &["@detachthis=n"]);
process_from(&h, PRIM_2, &["@detachthis_except:folder=n"]);
let ids = tracked(&h);
assert_eq!(ids.len(), 2);
assert!(ids.contains(&guid(PRIM_1)));
assert!(ids.contains(&guid(PRIM_2)));
}
// parity-case: LibreMetaverse.Tests/RLV/RlvRestrictionManagerTests.cs::RlvRestrictionManagerTests.GetTrackedPrimIds_AfterRemovingRestriction_DoesNotReturnRemovedObjectId::test af3d5328e5c829bd2de2b72c3f4ede6f083efa789ccef1d73d752612a177360f translated
#[test]
fn tracked_prim_ids_after_removing_restriction() {
let h = harness();
process_from(&h, PRIM_1, &["@fly=n"]);
process_from(&h, PRIM_2, &["@jump=n"]);
process_from(&h, PRIM_1, &["@fly=y"]);
let ids = tracked(&h);
assert_eq!(ids, vec![guid(PRIM_2)]);
assert!(!ids.contains(&guid(PRIM_1)));
}
// parity-case: LibreMetaverse.Tests/RLV/RlvRestrictionManagerTests.cs::RlvRestrictionManagerTests.GetTrackedPrimIds_AfterClearingAllRestrictions_ReturnsEmptyCollection::test 191a8cc3dba7e68155083a6892f1b4a29ab589023e22cffbc8cd69c005884cca translated
#[test]
fn tracked_prim_ids_after_clear() {
let h = harness();
process_from(&h, PRIM_1, &["@fly=n", "@jump=n", "@clear"]);
assert!(tracked(&h).is_empty());
}
// parity-case: LibreMetaverse.Tests/RLV/RlvRestrictionManagerTests.cs::RlvRestrictionManagerTests.RemoveRestrictionsForObjects_EmptyInput_NoEffect::test 8718e08bb2bf951a94803b4947943b5f7f9eb85e906b4ac6c639cb8cd065cf9d translated
#[test]
fn remove_restrictions_empty_input() {
let h = harness();
process_from(&h, PRIM_1, &["@fly=n"]);
block_on(remove(&h, vec![]));
assert!(!h.service.permissions().can_fly().unwrap());
assert_eq!(tracked(&h).len(), 1);
}
// parity-case: LibreMetaverse.Tests/RLV/RlvRestrictionManagerTests.cs::RlvRestrictionManagerTests.RemoveRestrictionsForObjects_NonExistentId_NoEffect::test 882d2315f40317cce9c9a026eda498325b6227886652795ed45e87cc4e5697ac translated
#[test]
fn remove_restrictions_missing_id() {
let h = harness();
process_from(&h, PRIM_1, &["@fly=n"]);
block_on(remove(&h, vec![guid(MISSING)]));
assert!(!h.service.permissions().can_fly().unwrap());
assert_eq!(tracked(&h), vec![guid(PRIM_1)]);
}
// parity-case: LibreMetaverse.Tests/RLV/RlvRestrictionManagerTests.cs::RlvRestrictionManagerTests.RemoveRestrictionsForObjects_SingleObject_RemovesAllRestrictionsFromObject::test 73ab6ee30a336372f6aef5bc4a99dbb58215b9445daea5d9708d0ea9cabe8bd1 translated
#[test]
fn remove_restrictions_single_object() {
let h = harness();
process_from(&h, PRIM_1, &["@fly=n", "@jump=n", "@sit=n"]);
assert!(!h.service.permissions().can_fly().unwrap());
assert!(!h.service.permissions().can_jump().unwrap());
block_on(remove(&h, vec![guid(PRIM_1)]));
assert!(h.service.permissions().can_fly().unwrap());
assert!(h.service.permissions().can_jump().unwrap());
assert!(tracked(&h).is_empty());
}
// parity-case: LibreMetaverse.Tests/RLV/RlvRestrictionManagerTests.cs::RlvRestrictionManagerTests.RemoveRestrictionsForObjects_MultipleObjects_RemovesOnlySpecifiedObjects::test 03b6a6a3e02f6a6a5f296ff1d6cca31c9fc53982cbc9c27e73cfb698ed82acf5 translated
#[test]
fn remove_restrictions_multiple_objects() {
let h = harness();
process_from(&h, PRIM_1, &["@fly=n"]);
process_from(&h, PRIM_2, &["@jump=n"]);
process_from(&h, PRIM_3, &["@sit=n"]);
assert!(!h.service.permissions().can_fly().unwrap());
assert!(!h.service.permissions().can_jump().unwrap());
block_on(remove(&h, vec![guid(PRIM_1), guid(PRIM_3)]));
assert!(h.service.permissions().can_fly().unwrap());
assert!(!h.service.permissions().can_jump().unwrap());
assert_eq!(tracked(&h), vec![guid(PRIM_2)]);
}
// parity-case: LibreMetaverse.Tests/RLV/RlvRestrictionManagerTests.cs::RlvRestrictionManagerTests.RemoveRestrictionsForObjects_PartialMatch_RemovesOnlyMatchingObjects::test 00a26d807882b2bbb375c5ce7cf1074d3227acd891e859602e78abbdc6eefb6a translated
#[test]
fn remove_restrictions_partial_match() {
let h = harness();
process_from(&h, PRIM_1, &["@fly=n"]);
process_from(&h, PRIM_2, &["@jump=n"]);
block_on(remove(&h, vec![guid(PRIM_1), guid(MISSING)]));
assert!(h.service.permissions().can_fly().unwrap());
assert!(!h.service.permissions().can_jump().unwrap());
assert_eq!(tracked(&h), vec![guid(PRIM_2)]);
}
// parity-case: LibreMetaverse.Tests/RLV/RlvRestrictionManagerTests.cs::RlvRestrictionManagerTests.RemoveRestrictionsForObjects_WithNotificationRestrictions_SendsNotifications::test ba82b183dfdb01b36f9b45520e1808290c360f327d4afa833ba3b8c7a7cecffb translated
#[test]
fn remove_restrictions_sends_notification() {
let h = harness();
process_from(&h, PRIM_2, &["@notify:123=n"]);
process_from(&h, PRIM_1, &["@fly=n"]);
block_on(remove(&h, vec![guid(PRIM_1)]));
assert_eq!(
h.actions
.lock()
.unwrap()
.replies
.iter()
.filter(|reply| **reply == (123, "/fly=y".into()))
.count(),
1
);
}
// parity-case: LibreMetaverse.Tests/RLV/RlvRestrictionManagerTests.cs::RlvRestrictionManagerTests.RemoveRestrictionsForObjects_WithComplexRestrictions_RemovesCorrectly::test 631de2d39fa56b29014fae4ce3b57c480f540ad41ce08a0037b7f8bbfcb3c502 translated
#[test]
fn remove_restrictions_complex_types() {
let h = harness();
process_from(
&h,
PRIM_1,
&[
"@detachthis=n",
"@detachthis_except:folder=n",
"@touchfar:1.5=n",
],
);
process_from(&h, PRIM_2, &["@fly=n"]);
assert_eq!(
h.service
.restrictions()
.find_restrictions(None, Some(Some(guid(PRIM_1))))
.unwrap()
.len(),
3
);
assert_eq!(
h.service
.restrictions()
.find_restrictions(None, Some(Some(guid(PRIM_2))))
.unwrap()
.len(),
1
);
block_on(remove(&h, vec![guid(PRIM_1)]));
assert!(
h.service
.restrictions()
.find_restrictions(None, Some(Some(guid(PRIM_1))))
.unwrap()
.is_empty()
);
assert_eq!(
h.service
.restrictions()
.find_restrictions(None, Some(Some(guid(PRIM_2))))
.unwrap()
.len(),
1
);
}
// parity-case: LibreMetaverse.Tests/RLV/RlvRestrictionManagerTests.cs::RlvRestrictionManagerTests.RemoveRestrictionsForObjects_TriggersRestrictionUpdatedEvent::test 318f1f4207b04d01076d3498aceea781c4889b05cdbef199cdbea43dde355f4c translated
#[test]
fn remove_restrictions_triggers_update_event() {
let h = harness();
process_from(&h, PRIM_1, &["@fly=n"]);
let removed = Arc::new(Mutex::new(None));
let captured = Arc::clone(&removed);
let _subscription = h
.service
.restrictions()
.subscribe_restriction_updated(Some(Arc::new(move |args| {
if !args.is_new() && args.is_deleted() {
let restriction = args.restriction();
*captured.lock().unwrap() = Some((restriction.behavior(), restriction.sender()));
}
})));
block_on(remove(&h, vec![guid(PRIM_1)]));
assert_eq!(
*removed.lock().unwrap(),
Some((RlvRestrictionType::Fly, guid(PRIM_1)))
);
}

View File

@@ -0,0 +1,383 @@
//! Exact Rust translations of the non-inventory RLV command tests.
use libremetaverse_compat_tests::block_on;
use libremetaverse_compat_tests::rlv_support::{RlvHarness, TeleportCall, guid};
const OBJECT: &str = "00000000-0000-4000-8000-000000000000";
const OTHER_SENDER: &str = "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa";
fn harness() -> RlvHarness {
RlvHarness::new().expect("RlvService constructor")
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/AdjustHeightCommandTests.cs::AdjustHeightCommandTests.AdjustHeight::test fb3adb86988b10b2d3fe9223324f8a3c1ba7b8c2ea909ee6b57b38c590fed372 translated
#[test]
fn adjust_height() {
let h = harness();
block_on(h.process("@adjustheight:4.3;1.25=force")).unwrap();
assert_eq!(
h.actions.lock().unwrap().adjusted_heights,
vec![(4.3, 1.25, 0.0)]
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/AdjustHeightCommandTests.cs::AdjustHeightCommandTests.AdjustHeight_WithDelta::test 1f37a125fd9df8585740d37c711888dfcd92460d86c19077f771d7f3fab54264 translated
#[test]
fn adjust_height_with_delta() {
let h = harness();
block_on(h.process("@adjustheight:4.3;1.25;12.34=force")).unwrap();
assert_eq!(
h.actions.lock().unwrap().adjusted_heights,
vec![(4.3, 1.25, 12.34)]
);
}
fn seed_clear(h: &RlvHarness) {
block_on(h.process("@tploc=n")).unwrap();
block_on(h.process("@tplm=n")).unwrap();
block_on(h.process("@unsit=n")).unwrap();
block_on(h.process("@fly=n")).unwrap();
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/ClearCommandTests.cs::ClearCommandTests.Clear::test 865d022233930e9582fec5b0e99063f15506a339c430755aba83706b594182ad translated
#[test]
fn clear() {
let h = harness();
seed_clear(&h);
block_on(h.process("@clear")).unwrap();
assert!(
h.service
.restrictions()
.find_restrictions(None, None)
.unwrap()
.is_empty()
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/ClearCommandTests.cs::ClearCommandTests.Clear_CaseInSensitive::test b70296f9d2b6c9eb8c6dd6e560056ab8320d746a991fafec858812fc2ebb3141 translated
#[test]
fn clear_is_case_insensitive() {
let h = harness();
seed_clear(&h);
block_on(h.process("@cLEaR")).unwrap();
assert!(
h.service
.restrictions()
.find_restrictions(None, None)
.unwrap()
.is_empty()
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/ClearCommandTests.cs::ClearCommandTests.Clear_SenderBased::test 1ae70737411e18626227c0b15181572c1c623eefce0a8fa1a874b2229c44c38e translated
#[test]
fn clear_is_sender_based() {
let h = harness();
block_on(h.process("@tploc=n")).unwrap();
block_on(h.process("@tplm=n")).unwrap();
block_on(h.process_from("@unsit=n", OTHER_SENDER, "Sender 2")).unwrap();
block_on(h.process_from("@fly=n", OTHER_SENDER, "Sender 2")).unwrap();
block_on(h.process_from("@clear", OTHER_SENDER, "Sender 2")).unwrap();
let permissions = h.service.permissions();
assert_eq!(
[
permissions.can_tp_loc().unwrap(),
permissions.can_tp_lm().unwrap(),
permissions.can_unsit().unwrap(),
permissions.can_fly().unwrap()
],
[false, false, true, true]
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/ClearCommandTests.cs::ClearCommandTests.Clear_Filtered::test e0f0b5a42c3baf92fef6a8d4fc2c60dbd6963db6f844fed55b06968f0c9e543f translated
#[test]
fn clear_is_filtered() {
let h = harness();
seed_clear(&h);
block_on(h.process("@clear=tp")).unwrap();
let permissions = h.service.permissions();
assert_eq!(
[
permissions.can_tp_loc().unwrap(),
permissions.can_tp_lm().unwrap(),
permissions.can_unsit().unwrap(),
permissions.can_fly().unwrap()
],
[true, true, false, false]
);
}
fn set_debug(setting: &str, value: &str) -> Vec<(String, String)> {
let h = harness();
block_on(h.process(&format!("@setdebug_{setting}:{value}=force"))).unwrap();
h.actions.lock().unwrap().debug_settings.clone()
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/SetDebugCommandTests.cs::SetDebugCommandTests.SetDebug_Default::case:fa77559e30768d15 abcee425068df326a3258ab4d881218e6eee52523fa5d306b191308e85dfff3d translated
#[test]
fn set_debug_known_setting() {
assert_eq!(
set_debug("RenderResolutionDivisor", "RenderResolutionDivisor Success"),
vec![(
"renderresolutiondivisor".into(),
"RenderResolutionDivisor Success".into()
)]
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/SetDebugCommandTests.cs::SetDebugCommandTests.SetDebug_Default::case:55694f25ed879d95 abcee425068df326a3258ab4d881218e6eee52523fa5d306b191308e85dfff3d translated
#[test]
fn set_debug_unknown_setting() {
assert_eq!(
set_debug("Unknown Setting", "Unknown Setting Success"),
vec![("unknown setting".into(), "Unknown Setting Success".into())]
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/SetDebugCommandTests.cs::SetDebugCommandTests.SetDebug_Invalid::test 2e0595319ba8e2c9a8280c5b034363ad7998eb740cb6b7fff3d75bb0167c6464 translated
#[test]
fn set_debug_rejects_empty_name() {
let h = harness();
assert!(!block_on(h.process("@setdebug_:42=force")).unwrap());
assert!(h.actions.lock().unwrap().debug_settings.is_empty());
}
fn set_env(setting: &str, value: &str) -> Vec<(String, String)> {
let h = harness();
block_on(h.process(&format!("@setenv_{setting}:{value}=force"))).unwrap();
h.actions.lock().unwrap().environment_settings.clone()
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/SetEnvCommandTests.cs::SetEnvCommandTests.SetEnv_Default::case:f656b648d00a6d91 836c1332ca9c4f645e5c9dca8b4a2b967d55fd8148901b05ce5d741e665ab7e1 translated
#[test]
fn set_environment_known_setting() {
assert_eq!(
set_env("Daytime", "Daytime Success"),
vec![("daytime".into(), "Daytime Success".into())]
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/SetEnvCommandTests.cs::SetEnvCommandTests.SetEnv_Default::case:55694f25ed879d95 836c1332ca9c4f645e5c9dca8b4a2b967d55fd8148901b05ce5d741e665ab7e1 translated
#[test]
fn set_environment_unknown_setting() {
assert_eq!(
set_env("Unknown Setting", "Unknown Setting Success"),
vec![("unknown setting".into(), "Unknown Setting Success".into())]
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/SetGroupCommandTests.cs::SetGroupCommandTests.SetGroup_ByName::test fae27e58cd981f5471f4c2b8356bb07aa5e76a57aaf0882d0dbfb86360e077e3 translated
#[test]
fn set_group_by_name() {
let h = harness();
block_on(h.process("@setgroup:Group Name=force")).unwrap();
assert_eq!(
h.actions.lock().unwrap().group_names,
vec![("Group Name".into(), None)]
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/SetGroupCommandTests.cs::SetGroupCommandTests.SetGroup_ByNameAndRole::test 408442b86bb8259eb9bbb4cf8a5d3b0830c7ba9357fa04cb6e851511a7a24df1 translated
#[test]
fn set_group_by_name_and_role() {
let h = harness();
block_on(h.process("@setgroup:Group Name;Admin Role=force")).unwrap();
assert_eq!(
h.actions.lock().unwrap().group_names,
vec![("Group Name".into(), Some("Admin Role".into()))]
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/SetGroupCommandTests.cs::SetGroupCommandTests.SetGroup_ById::test 27f13c52c8c5e2e4298fee3f4322f9906d5f82e900aa5f46c9a8ffac3a6dfae7 translated
#[test]
fn set_group_by_id() {
let h = harness();
block_on(h.process(&format!("@setgroup:{OBJECT}=force"))).unwrap();
assert_eq!(
h.actions.lock().unwrap().group_ids,
vec![(guid(OBJECT), None)]
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/SetGroupCommandTests.cs::SetGroupCommandTests.SetGroup_ByIdAndRole::test e18fd0c318ebd4f9a189418449568b3a34b8f7d3a0097f100a7253c4d5a31bde translated
#[test]
fn set_group_by_id_and_role() {
let h = harness();
block_on(h.process(&format!("@setgroup:{OBJECT};Admin Role=force"))).unwrap();
assert_eq!(
h.actions.lock().unwrap().group_ids,
vec![(guid(OBJECT), Some("Admin Role".into()))]
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/SetRotCommandTests.cs::SetRotCommandTests.SetRot::test c3302d63cdda9d72b85dad2749e2684cc26d51c72ddc6ace8275911f8ba67ef4 translated
#[test]
fn set_rotation() {
let h = harness();
block_on(h.process("@setrot:1.5=force")).unwrap();
assert_eq!(h.actions.lock().unwrap().rotations, vec![1.5]);
}
fn sit_harness(is_sitting: bool, exists: bool) -> RlvHarness {
let h = harness();
h.queries.lock().unwrap().is_sitting = is_sitting;
h.queries
.lock()
.unwrap()
.object_exists
.insert(guid(OBJECT), exists);
h
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/SitCommandTests.cs::SitCommandTests.ForceSit_Default::test 24e45ba898cb8ed0919369d07a39d0b21982fa4fc4c41eb4835ba765c05e2469 translated
#[test]
fn force_sit() {
let h = sit_harness(false, true);
block_on(h.process(&format!("@sit:{OBJECT}=force"))).unwrap();
assert_eq!(h.actions.lock().unwrap().sits, vec![guid(OBJECT)]);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/SitCommandTests.cs::SitCommandTests.ForceSit_RestrictedUnsit_WhileStanding::test 8d179277f6a7f98ead813de7bd02ab5146b46ce240d1d5e4a69037885e5f626a translated
#[test]
fn force_sit_with_unsit_restricted_while_standing() {
let h = sit_harness(false, true);
block_on(h.process("@unsit=n")).unwrap();
block_on(h.process(&format!("@sit:{OBJECT}=force"))).unwrap();
assert_eq!(h.actions.lock().unwrap().sits, vec![guid(OBJECT)]);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/SitCommandTests.cs::SitCommandTests.ForceSit_RestrictedUnsit_WhileSeated::test 1f2debd6e644c86698577e1c04db96d6aac43267ceae8de9f28435b62ff92817 translated
#[test]
fn force_sit_rejects_unsit_restriction_while_seated() {
let h = sit_harness(true, true);
block_on(h.process("@unsit=n")).unwrap();
assert!(!block_on(h.process(&format!("@sit:{OBJECT}=force"))).unwrap());
assert!(h.actions.lock().unwrap().sits.is_empty());
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/SitCommandTests.cs::SitCommandTests.ForceSit_RestrictedSit::test 8ac0964fc07bb5e860123ce8de1102c2254ffde28f246896d81f7524c3c87021 translated
#[test]
fn force_sit_rejects_sit_restriction() {
let h = sit_harness(true, true);
block_on(h.process("@sit=n")).unwrap();
assert!(!block_on(h.process(&format!("@sit:{OBJECT}=force"))).unwrap());
assert!(h.actions.lock().unwrap().sits.is_empty());
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/SitCommandTests.cs::SitCommandTests.ForceSit_RestrictedStandTp::test bc0c259477ef5f1e5a76b1081f604ba421c82340f738e37fd52b91a421037cf6 translated
#[test]
fn force_sit_rejects_standtp_restriction() {
let h = sit_harness(true, true);
block_on(h.process("@standtp=n")).unwrap();
assert!(!block_on(h.process(&format!("@sit:{OBJECT}=force"))).unwrap());
assert!(h.actions.lock().unwrap().sits.is_empty());
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/SitCommandTests.cs::SitCommandTests.ForceSit_InvalidObject::test 787bfe6fefe3895b4bcb5da027ffeac70bf67c3c7a295dbbf7e1526156290040 translated
#[test]
fn force_sit_rejects_invalid_object() {
let h = sit_harness(false, false);
assert!(!block_on(h.process(&format!("@sit:{OBJECT}=force"))).unwrap());
assert!(h.actions.lock().unwrap().sits.is_empty());
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/SitGroundCommandTests.cs::SitGroundCommandTests.ForceSitGround::test 2319cd49aaae5ac824bc5ffd4f33a5e4f3f684ebec1dc1f1732071eb44ee1cb8 translated
#[test]
fn force_sit_ground() {
let h = harness();
assert!(block_on(h.process("@sitground=force")).unwrap());
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/SitGroundCommandTests.cs::SitGroundCommandTests.ForceSitGround_RestrictedSit::test 5ac661e9f7fa93cf6ca76aa69f6d84ac61ebd22f26620203f084777010b6de4d translated
#[test]
fn force_sit_ground_rejects_sit_restriction() {
let h = harness();
block_on(h.process("@sit=n")).unwrap();
assert!(!block_on(h.process("@sitground=force")).unwrap());
}
fn teleport(command: &str) -> Vec<TeleportCall> {
let h = harness();
block_on(h.process(command)).unwrap();
h.actions.lock().unwrap().teleports.clone()
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/TpToCommandTests.cs::TpToCommandTests.TpTo_Default::test 1613e723da60f84dfb54a7345b96566a055a9b7a017e66b0929d6f37c04b62a3 translated
#[test]
fn teleport_default() {
assert_eq!(
teleport("@tpto:1.5/2.5/3.5=force"),
vec![TeleportCall {
x: 1.5,
y: 2.5,
z: 3.5,
region: None,
look_at: None
}]
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/TpToCommandTests.cs::TpToCommandTests.TpTo_WithRegion::test 50c5f63c5cb0da221846fd7c0c7f2d471bef2aa2ab203a9b5bdb4eceeb3d97bf translated
#[test]
fn teleport_with_region() {
assert_eq!(
teleport("@tpto:Region Name/1.5/2.5/3.5=force"),
vec![TeleportCall {
x: 1.5,
y: 2.5,
z: 3.5,
region: Some("Region Name".into()),
look_at: None
}]
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/TpToCommandTests.cs::TpToCommandTests.TpTo_WithRegionAndLookAt::test c9030189de7acdad0db5c8f83e49ee0433ec0588a35436ab39cdcf40a4fd4d36 translated
#[test]
#[allow(clippy::approx_constant)] // Exact C# fixture literal, not a PI approximation.
fn teleport_with_region_and_look_at() {
assert_eq!(
teleport("@tpto:Region Name/1.5/2.5/3.5;3.1415=force"),
vec![TeleportCall {
x: 1.5,
y: 2.5,
z: 3.5,
region: Some("Region Name".into()),
look_at: Some(Some(3.1415))
}]
);
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/TpToCommandTests.cs::TpToCommandTests.TpTo_RestrictedUnsit::test 4dc00a1048593f7468271a4262cf311a3516ea4a53e288eeca69d1297dafc9f2 translated
#[test]
fn teleport_rejects_unsit_restriction() {
let h = harness();
block_on(h.process("@unsit=n")).unwrap();
assert!(!block_on(h.process("@tpto:1.5/2.5/3.5=force")).unwrap());
assert!(h.actions.lock().unwrap().teleports.is_empty());
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/TpToCommandTests.cs::TpToCommandTests.TpTo_RestrictedTpLoc::test 3e1ecc1d04973a496edf9d156e52ba76a93ff431181a3ece93c0e4f82884895a translated
#[test]
fn teleport_rejects_tploc_restriction() {
let h = harness();
block_on(h.process("@tploc=n")).unwrap();
assert!(!block_on(h.process("@tpto:1.5/2.5/3.5=force")).unwrap());
assert!(h.actions.lock().unwrap().teleports.is_empty());
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/UnsitCommandTests.cs::UnsitCommandTests.ForceUnSit::test 2f91e1112e1c4e97b79a4dc7bcd4d4a85f13125bd636f81147ce5b396366ebed translated
#[test]
fn force_unsit() {
let h = harness();
assert!(block_on(h.process("@unsit=force")).unwrap());
}
// parity-case: LibreMetaverse.Tests/RLV/Commands/UnsitCommandTests.cs::UnsitCommandTests.ForceUnSit_RestrictedUnsit::test 2ecf210dc83b06018cdcf44cb44bdf43f1040133e7523542a2e1126d6d98004f translated
#[test]
fn force_unsit_rejects_unsit_restriction() {
let h = harness();
block_on(h.process("@unsit=n")).unwrap();
assert!(!block_on(h.process("@unsit=force")).unwrap());
}

View File

@@ -0,0 +1,329 @@
// Exact Rust translations of the simple RLV permission restrictions.
use libremetaverse_compat_tests::block_on;
use libremetaverse_compat_tests::rlv_support::{RlvHarness, guid};
use libremetaverse_rlv::{
RlvPermissionsService, RlvPermissionsServiceObjectLocation as ObjectLocation,
RlvPermissionsServiceTouchLocation as TouchLocation,
};
use libremetaverse_types::Error;
fn check_simple(
command: &str,
permission: fn(&RlvPermissionsService) -> Result<bool, Error>,
) -> [bool; 2] {
let h = RlvHarness::new().expect("RlvService constructor");
block_on(h.process(&format!("@{command}=n"))).unwrap();
let restricted = permission(&h.service.permissions()).unwrap();
block_on(h.process(&format!("@{command}=y"))).unwrap();
[restricted, permission(&h.service.permissions()).unwrap()]
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/AllowIdleRestrictionTests.cs::AllowIdleRestrictionTests.CanAllowIdle::test 6278bb1a70f024f687080cb8e8a56bbc923f679fb4adb61c6c91c3397a3de7fc translated
#[test]
fn allow_idle_restriction() {
assert_eq!(
check_simple("allowIdle", RlvPermissionsService::can_allow_idle),
[false, true]
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/AlwaysRunRestrictionTests.cs::AlwaysRunRestrictionTests.CanAlwaysRun::test 9c0a34e0960e3e2a834ccfc1c129a1f5a8f8c6cfd30b322671b4e5c4cd25a24c translated
#[test]
fn always_run_restriction() {
assert_eq!(
check_simple("alwaysRun", RlvPermissionsService::can_always_run),
[false, true]
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/ChatNormalTests.cs::ChatNormalTests.CanChatNormal::test 9a23c49327636e769c7ff2688a0649d441f3531406e8f51e152ec7186a312287 translated
#[test]
fn chat_normal_restriction() {
assert_eq!(
check_simple("chatNormal", RlvPermissionsService::can_chat_normal),
[false, true]
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/ChatShoutRestrictionTests.cs::ChatShoutRestrictionTests.CanChatShout::test 493e1dd87afaaa7f8183e677df5c32d00f150ffcdd53f9afad8684672837aa28 translated
#[test]
fn chat_shout_restriction() {
assert_eq!(
check_simple("chatShout", RlvPermissionsService::can_chat_shout),
[false, true]
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/ChatWhisperRestrictionTests.cs::ChatWhisperRestrictionTests.CanChatWhisper::test 67c5d2cb8b3e9424fbcf08378c2a28368fe07aa83ec028df7cf88b91576d3e9f translated
#[test]
fn chat_whisper_restriction() {
assert_eq!(
check_simple("chatWhisper", RlvPermissionsService::can_chat_whisper),
[false, true]
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/DefaultWearRestrictionTests.cs::DefaultWearRestrictionTests.CanDefaultWear::test 64eef4c82d1c5a21bc923cfd44616ddc1a5e6403a9a1c5ad6bd2e5ee06e9704c translated
#[test]
fn default_wear_restriction() {
assert_eq!(
check_simple("defaultWear", RlvPermissionsService::can_default_wear),
[false, true]
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/FlyRestrictionTests.cs::FlyRestrictionTests.CanFly::test 5f60149edccece6b8a6827bbdc6f593ffd863961c13b506f1171aa0cf37fd5b7 translated
#[test]
fn fly_restriction() {
assert_eq!(
check_simple("fly", RlvPermissionsService::can_fly),
[false, true]
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/InteractRestrictionTests.cs::InteractRestrictionTests.CanInteract::test 935d319e07b613ba39b06db30cfd18306670f7dc97186db38c0374c3aac6901e translated
#[test]
fn interact_restriction() {
assert_eq!(
check_simple("interact", RlvPermissionsService::can_interact),
[false, true]
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/InteractRestrictionTests.cs::InteractRestrictionTests.CanInteract_default::test 53b9d7f7cfd63a10538060624f81b7a6b1754a7462c230671ed909698dd18923 translated
#[test]
fn interact_restriction_blocks_touch_edit_rez_and_sit() {
let h = RlvHarness::new().unwrap();
block_on(h.process("@interact=n")).unwrap();
let permissions = h.service.permissions();
let object = guid("00000000-0000-4000-8000-000000000000");
let user = Some(Some(guid("55555555-5555-4555-8555-555555555555")));
for (location, user, distance) in [
(TouchLocation::AttachedSelf, None, None),
(TouchLocation::AttachedOther, user, None),
(TouchLocation::RezzedInWorld, None, Some(Some(5.0))),
(TouchLocation::Hud, None, None),
] {
assert!(
!permissions
.can_touch(location, object, user, distance)
.unwrap()
);
}
for location in [
ObjectLocation::Attached,
ObjectLocation::RezzedInWorld,
ObjectLocation::Hud,
] {
assert!(!permissions.can_edit(location, Some(Some(object))).unwrap());
}
assert!(!permissions.can_rez().unwrap());
assert!(!permissions.can_sit().unwrap());
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/JumpRestrictionTests.cs::JumpRestrictionTests.CanJump::test 104374c66e6748d101b69ed5343d9972f29e937305cb17f90244ffa74fc7ed35 translated
#[test]
fn jump_restriction() {
assert_eq!(
check_simple("jump", RlvPermissionsService::can_jump),
[false, true]
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/RezRestrictionTests.cs::RezRestrictionTests.CanRez::test 5cae348cc241a884803692031c0af4f33fb3a2ce8331129a9866c5364599eccb translated
#[test]
fn rez_restriction() {
assert_eq!(
check_simple("rez", RlvPermissionsService::can_rez),
[false, true]
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/SendChatRestrictionTests.cs::SendChatRestrictionTests.CanSendChat::test 36cfbe5123b4b37ee43f0b4ba6453ebbe2754960825b1a8481e77e4f3a0e8015 translated
#[test]
fn send_chat_restriction() {
assert_eq!(
check_simple("sendChat", RlvPermissionsService::can_send_chat),
[false, true]
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/SendChatRestrictionTests.cs::SendChatRestrictionTests.CanChat_SendChatRestriction::test 793a31da070038e90c41e4bdb1161daaf51376617a7444867f19c7125ad34313 translated
#[test]
fn send_chat_restriction_preserves_slash_messages_and_private_channels() {
let h = RlvHarness::new().unwrap();
block_on(h.process("@sendchat=n")).unwrap();
let permissions = h.service.permissions();
assert!(!permissions.can_chat(0, "Hello".into()).unwrap());
assert!(permissions.can_chat(0, "/me says Hello".into()).unwrap());
assert!(permissions.can_chat(0, "/ something?".into()).unwrap());
assert!(
!permissions
.can_chat(0, "/me says Hello ^_^".into())
.unwrap()
);
assert!(permissions.can_chat(5, "Hello".into()).unwrap());
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/SendGestureRestrictionTests.cs::SendGestureRestrictionTests.CanSendGesture::test 91367110c04e3c6ad173f56f209a166d828560850d3d084893e899bcc756428a translated
#[test]
fn send_gesture_restriction() {
assert_eq!(
check_simple("sendGesture", RlvPermissionsService::can_send_gesture),
[false, true]
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/SetDebugRestrictionTests.cs::SetDebugRestrictionTests.CanSetDebug::test d4fb9da4879ef8d1be115e00b7a8de959fd58e32722bc9e2985bca8e97dd2ce3 translated
#[test]
fn set_debug_restriction() {
assert_eq!(
check_simple("setDebug", RlvPermissionsService::can_set_debug),
[false, true]
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/SetEnvRestrictionTests.cs::SetEnvRestrictionTests.CanSetEnv::test bb4c82afd643d267264467282cdfe09095c804079e73dd15179e1aa0b063c08f translated
#[test]
fn set_env_restriction() {
assert_eq!(
check_simple("setEnv", RlvPermissionsService::can_set_env),
[false, true]
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/SetGroupRestrictionTests.cs::SetGroupRestrictionTests.CanSetGroup::test 9d89210cbc5c188985a535ae045e44d296c796f700d4a1e2b7b4d75345cc4a6d translated
#[test]
fn set_group_restriction() {
assert_eq!(
check_simple("setGroup", RlvPermissionsService::can_set_group),
[false, true]
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/ShowInvRestrictionTests.cs::ShowInvRestrictionTests.CanShowInv::test b7c8bb7ad9d2c02c1c0168531c8ac0636885817a40b13bc006f4f5b20d28591c translated
#[test]
fn show_inventory_restriction() {
assert_eq!(
check_simple("showInv", RlvPermissionsService::can_show_inv),
[false, true]
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/ShowLocRestrictionTests.cs::ShowLocRestrictionTests.CanShowLoc::test a8b154f2db967ab72781f31dcd7701d204f66ece1ef95a30cc67d788c78da617 translated
#[test]
fn show_location_restriction() {
assert_eq!(
check_simple("showLoc", RlvPermissionsService::can_show_loc),
[false, true]
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/ShowMiniMapRestrictionTests.cs::ShowMiniMapRestrictionTests.CanShowMiniMap::test da901135b533aee1b025cf5dd925e857b4734ea00770ced4518f501453ea9736 translated
#[test]
fn show_mini_map_restriction() {
assert_eq!(
check_simple("showMiniMap", RlvPermissionsService::can_show_mini_map),
[false, true]
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/ShowNearbyRestrictionTests.cs::ShowNearbyRestrictionTests.CanShowNearby::test 4faa79795b1143934efbd8ebea7a926b270dd5d1e69f8a64f496063d570d868d translated
#[test]
fn show_nearby_restriction() {
assert_eq!(
check_simple("showNearby", RlvPermissionsService::can_show_nearby),
[false, true]
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/ShowWorldMapRestrictionTests.cs::ShowWorldMapRestrictionTests.CanShowWorldMap::test da16f247df929f83ed21377869790c00cb5922fa6086da3787e90570f5684f67 translated
#[test]
fn show_world_map_restriction() {
assert_eq!(
check_simple("showWorldMap", RlvPermissionsService::can_show_world_map),
[false, true]
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/SitRestrictionTests.cs::SitRestrictionTests.CanSit::test 813906dbfd09bb02c129a794f40a2f5dcda6e73d232e167359a6360a350fa4b4 translated
#[test]
fn sit_restriction() {
assert_eq!(
check_simple("sit", RlvPermissionsService::can_sit),
[false, true]
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/StandTpRestrictionTests.cs::StandTpRestrictionTests.CanStandTp::test 0f694e59d32c3c97fbee072d591b74c89561f4648bd3440002d8f54db0058a94 translated
#[test]
fn stand_tp_restriction() {
assert_eq!(
check_simple("standTp", RlvPermissionsService::can_stand_tp),
[false, true]
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/TempRunRestrictionTests.cs::TempRunRestrictionTests.CanTempRun::test 8893bb24bf10de7e914874c347ac5b73982d33925a1cf29ae8c361c3087be408 translated
#[test]
fn temp_run_restriction() {
assert_eq!(
check_simple("tempRun", RlvPermissionsService::can_temp_run),
[false, true]
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/TpLmRestrictionTests.cs::TpLmRestrictionTests.CanTpLm::test 847bd3264fd831837d8dab25b235450f19591fef3b3bd0315021727453ad64ee translated
#[test]
fn tp_landmark_restriction() {
assert_eq!(
check_simple("tpLm", RlvPermissionsService::can_tp_lm),
[false, true]
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/TpLocRestrictionTests.cs::TpLocRestrictionTests.CanTpLoc::test 8e5e2ab1b55b710ecce509b141ccac9bcd9ebbad479868496645ac89574bd089 translated
#[test]
fn tp_location_restriction() {
assert_eq!(
check_simple("tpLoc", RlvPermissionsService::can_tp_loc),
[false, true]
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/UnsitRestrictionTests.cs::UnsitRestrictionTests.CanUnsit::test 2341a0d230eace08d612a1ae3f9aac7b5a1d3d914f04b6ada4726523e9bd3a37 translated
#[test]
fn unsit_restriction() {
assert_eq!(
check_simple("unsit", RlvPermissionsService::can_unsit),
[false, true]
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/ViewNoteRestrictionTests.cs::ViewNoteRestrictionTests.CanViewNote::test 954472ccc5e060f987260c7d8f87f09dcb252e832c22810ed48dd316a173cf5e translated
#[test]
fn view_note_restriction() {
assert_eq!(
check_simple("viewNote", RlvPermissionsService::can_view_note),
[false, true]
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/ViewScriptRestrictionTests.cs::ViewScriptRestrictionTests.CanViewScript::test 5e9246991c14d80bc83aad4b5944bd9701dc32b354a701a378def8924f7b5315 translated
#[test]
fn view_script_restriction() {
assert_eq!(
check_simple("viewScript", RlvPermissionsService::can_view_script),
[false, true]
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/ViewTextureRestrictionTests.cs::ViewTextureRestrictionTests.CanViewTexture::test d1ee89e12ea9c2d971b4d11c82f3129412fd56fa28d2bd2fb923f082eda62571 translated
#[test]
fn view_texture_restriction() {
assert_eq!(
check_simple("viewTexture", RlvPermissionsService::can_view_texture),
[false, true]
);
}

View File

@@ -0,0 +1,605 @@
// Exact Rust translations of the message, sharing, and name restriction tests.
use libremetaverse_compat_tests::block_on;
use libremetaverse_compat_tests::rlv_support::{RlvHarness, guid};
use libremetaverse_rlv::RlvPermissionsServiceHoverTextLocation as HoverTextLocation;
const USER_1: &str = "00000000-0000-4000-8000-000000000000";
const USER_2: &str = "11111111-1111-4111-8111-111111111111";
const SENDER_2: &str = "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa";
const SENDER_3: &str = "22222222-2222-4222-8222-222222222222";
fn harness() -> RlvHarness {
RlvHarness::new().expect("RlvService constructor")
}
fn process(h: &RlvHarness, commands: &[&str]) {
for command in commands {
block_on(h.process(command)).unwrap();
}
}
fn receive_im(h: &RlvHarness, user: &str, group: Option<&str>) -> bool {
h.service
.permissions()
.can_receive_im(
"Hello world".into(),
Some(Some(guid(user))),
group.map(Into::into),
)
.unwrap()
}
fn send_im(h: &RlvHarness, user: &str, group: Option<&str>) -> bool {
h.service
.permissions()
.can_send_im(
"Hello world".into(),
Some(Some(guid(user))),
group.map(Into::into),
)
.unwrap()
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/RecvChatExceptionTests.cs::RecvChatExceptionTests.CanRecvChat::test 017906038e211352d7d2751fafbcab5028cd8b189e7aa29a6202ff578976a23c translated
#[test]
fn receive_chat_blocks_chat_but_not_emote() {
let h = harness();
process(&h, &["@recvchat=n"]);
let permissions = h.service.permissions();
assert!(
!permissions
.can_receive_chat("Hello world".into(), guid(SENDER_2))
.unwrap()
);
assert!(
permissions
.can_receive_chat("/me says Hello world".into(), guid(SENDER_2))
.unwrap()
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/RecvChatFromRestrictionTests.cs::RecvChatFromRestrictionTests.CanRecvChatFrom::test aaf24dc0b8533a7e93cc567fecbb866067b72da1837207869f879647840bfa21 translated
#[test]
fn receive_chat_from_one_user() {
let h = harness();
process(&h, &[&format!("@recvchatfrom:{USER_1}=add")]);
let permissions = h.service.permissions();
assert!(
!permissions
.can_receive_chat("Hello world".into(), guid(USER_1))
.unwrap()
);
assert!(
permissions
.can_receive_chat("/me says Hello world".into(), guid(USER_1))
.unwrap()
);
assert!(
permissions
.can_receive_chat("Hello world".into(), guid(USER_2))
.unwrap()
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/RecvChatSecExceptionTests.cs::RecvChatSecExceptionTests.CanRecvChat_Secure::test cba089ebe607088e37be285918a1d2c674f1acc4cad075733108afea3ad0279b translated
#[test]
fn secure_receive_chat_exceptions_are_sender_scoped() {
let h = harness();
process(&h, &["@recvchat_sec=n"]);
block_on(h.process_from(&format!("@recvchat:{USER_1}=add"), SENDER_2, "Sender 2")).unwrap();
process(&h, &[&format!("@recvchat:{USER_2}=add")]);
let permissions = h.service.permissions();
assert!(
!permissions
.can_receive_chat("Hello world".into(), guid(USER_1))
.unwrap()
);
assert!(
permissions
.can_receive_chat("Hello world".into(), guid(USER_2))
.unwrap()
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/RecvEmoteFromRestrictionTests.cs::RecvEmoteFromRestrictionTests.CanRecvChat_RecvEmoteFrom::test d07ded724315cf135603d4dc5a684e5a59a5cf8415963acc30d402ad81916ac1 translated
#[test]
fn receive_emote_from_one_user() {
let h = harness();
process(&h, &[&format!("@recvemotefrom:{USER_1}=n")]);
let permissions = h.service.permissions();
assert!(
permissions
.can_receive_chat("Hello world".into(), guid(USER_1))
.unwrap()
);
assert!(
permissions
.can_receive_chat("Hello world".into(), guid(USER_2))
.unwrap()
);
assert!(
!permissions
.can_receive_chat("/me says Hello world".into(), guid(USER_1))
.unwrap()
);
assert!(
permissions
.can_receive_chat("/me says Hello world".into(), guid(USER_2))
.unwrap()
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/RecvEmoteRestrictionTests.cs::RecvEmoteRestrictionTests.CanRecvChat_RecvEmote::test 438b72e6c44570580bf41aa7b8ed00afb800eff8836ee971eab9fc6a00fecc19 translated
#[test]
fn receive_emote_restriction() {
let h = harness();
process(&h, &["@recvemote=n"]);
let permissions = h.service.permissions();
assert!(
permissions
.can_receive_chat("Hello world".into(), guid(SENDER_2))
.unwrap()
);
assert!(
!permissions
.can_receive_chat("/me says Hello world".into(), guid(SENDER_2))
.unwrap()
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/RecvEmoteSecRestrictionTests.cs::RecvEmoteSecRestrictionTests.CanRecvChat_RecvEmote_Secure::test 9e1f72426762569b1c650fdf80c53e4a590b6476f8539fff6e110101e48459e8 translated
#[test]
fn secure_receive_emote_exceptions_are_sender_scoped() {
let h = harness();
process(&h, &["@recvemote_sec=n"]);
block_on(h.process_from(&format!("@recvemote:{USER_1}=add"), SENDER_2, "Sender 2")).unwrap();
process(&h, &[&format!("@recvemote:{USER_2}=add")]);
let permissions = h.service.permissions();
assert!(
permissions
.can_receive_chat("Hello world".into(), guid(USER_1))
.unwrap()
);
assert!(
permissions
.can_receive_chat("Hello world".into(), guid(USER_2))
.unwrap()
);
assert!(
!permissions
.can_receive_chat("/me says Hello world".into(), guid(USER_1))
.unwrap()
);
assert!(
permissions
.can_receive_chat("/me says Hello world".into(), guid(USER_2))
.unwrap()
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/RecvImFromRestrictionTests.cs::RecvImFromRestrictionTests.CanReceiveIMFrom::test ebe072c7e1c8ba440b560c2e4a0aa5151ba546f5b6cd5505012958e901c58201 translated
#[test]
fn receive_im_from_one_user() {
let h = harness();
process(&h, &[&format!("@recvimfrom:{USER_1}=n")]);
assert!(!receive_im(&h, USER_1, None));
assert!(receive_im(&h, USER_2, None));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/RecvImFromRestrictionTests.cs::RecvImFromRestrictionTests.CanReceiveIMFrom_Group::test d3d155240723ca2d379f00111a3b27acb41786615a2f5b0ad2c968040d7f4447 translated
#[test]
fn receive_im_from_one_group() {
let h = harness();
process(&h, &["@recvimfrom:First Group=n"]);
assert!(!receive_im(&h, USER_1, Some("First Group")));
assert!(receive_im(&h, USER_2, Some("Second Group")));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/RecvImFromRestrictionTests.cs::RecvImFromRestrictionTests.CanReceiveIMTo_AllGroups::test dd1050e7ef3e9805b88964822485856d6b2e5e98ee647ee08251cbc5bd452208 translated
#[test]
fn receive_im_from_all_groups() {
let h = harness();
process(&h, &["@recvimfrom:allgroups=n"]);
assert!(!receive_im(&h, USER_1, Some("First Group")));
assert!(!receive_im(&h, USER_2, Some("Second Group")));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/RecvImRestrictionTests.cs::RecvImRestrictionTests.CanReceiveIM::test 9c88e79ed2686e571e32ccecbc93c130423b966ff4e65e72f228f1713e5047cd translated
#[test]
fn receive_im_restriction() {
let h = harness();
process(&h, &["@recvim=n"]);
assert!(
!h.service
.permissions()
.can_receive_im("Hello".into(), Some(Some(guid(USER_1))), None)
.unwrap()
);
assert!(
!h.service
.permissions()
.can_receive_im(
"Hello".into(),
Some(Some(guid(USER_1))),
Some("Group Name".into())
)
.unwrap()
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/RecvImSecRestrictionTests.cs::RecvImSecRestrictionTests.CanReceiveIM_Secure::test e549fe9719efd180f8ab8c80b989701cd23ebf07cd004d9a5a18a0cc7db12e64 translated
#[test]
fn secure_receive_im_user_exceptions_are_sender_scoped() {
let h = harness();
process(&h, &["@recvim_sec=n", &format!("@recvim:{USER_1}=add")]);
block_on(h.process_from(&format!("@recvim:{USER_2}=add"), SENDER_2, "Sender 2")).unwrap();
assert!(receive_im(&h, USER_1, None));
assert!(!receive_im(&h, USER_2, None));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/RecvImSecRestrictionTests.cs::RecvImSecRestrictionTests.CanReceiveIM_Secure_Group::test 13653ee7443d2eca88f2940d0c3804de3685dcf6c9277a4717a42dad4c01fca4 translated
#[test]
fn secure_receive_im_group_exception() {
let h = harness();
process(&h, &["@recvim_sec=n", "@recvim:Group Name=add"]);
block_on(h.process_from("@recvim:allgroups=add", SENDER_2, "Sender 2")).unwrap();
assert!(receive_im(&h, USER_1, Some("Group Name")));
assert!(!receive_im(&h, USER_1, Some("Another Group")));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/RecvImSecRestrictionTests.cs::RecvImSecRestrictionTests.CanReceiveIM_Secure_AllGroups::test d99435b52a3b774ab5d2bb6911824fa45803fe82cfe0b2c192a05473b72463c8 translated
#[test]
fn secure_receive_im_all_groups_exception() {
let h = harness();
process(&h, &["@recvim_sec=n", "@recvim:allgroups=add"]);
assert!(receive_im(&h, USER_1, Some("Group Name")));
assert!(receive_im(&h, USER_1, Some("Another Group")));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/SendChannelRestrictionTests.cs::SendChannelRestrictionTests.CanSendChannel::test 8496734391f57cf2f2d8156f3b5a9ad9147c959e3bf99f9e76a4072e971a5b42 translated
#[test]
fn send_channel_restriction() {
let h = harness();
process(&h, &["@sendchannel=n"]);
assert!(
!h.service
.permissions()
.can_chat(123, "Hello world".into())
.unwrap()
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/SendChannelSecRestrictionTests.cs::SendChannelSecRestrictionTests.CanSendChannel_Secure::test 5bd9096e9af488d5cdb08ed78120ef46f81f9be1eaf132c49a955eb07ae904eb translated
#[test]
fn secure_send_channel_restrictions_are_sender_scoped() {
let h = harness();
process(&h, &["@sendchannel_sec=n", "@sendchannel:123=n"]);
block_on(h.process_from("@sendchannel:456=n", SENDER_2, "Sender 2")).unwrap();
assert!(
h.service
.permissions()
.can_chat(123, "Hello world".into())
.unwrap()
);
assert!(
!h.service
.permissions()
.can_chat(456, "Hello world".into())
.unwrap()
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/SendChannelSecRestrictionTests.cs::SendChannelSecRestrictionTests.CanSendChannel_Secure_Exception::test e675121ba9f6ab8f6e4484e66d76d0dd14f8ef39122c8fff2878ba5e6b3a7409 translated
#[test]
fn secure_send_channel_exception() {
let h = harness();
process(&h, &["@sendchannel_sec=n", "@sendchannel_sec:123=n"]);
assert!(
h.service
.permissions()
.can_chat(123, "Hello world".into())
.unwrap()
);
assert!(
!h.service
.permissions()
.can_chat(456, "Hello world".into())
.unwrap()
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/SendImRestrictionTests.cs::SendImRestrictionTests.CanSendIM::test c63ab3a41b6b302e7c84c54374c7193335840bafc40f2d0f2b1c3a2787b26203 translated
#[test]
fn send_im_restriction() {
let h = harness();
process(&h, &["@sendim=n"]);
assert!(
!h.service
.permissions()
.can_send_im("Hello".into(), Some(Some(guid(USER_1))), None)
.unwrap()
);
assert!(
!h.service
.permissions()
.can_send_im(
"Hello".into(),
Some(Some(guid(USER_1))),
Some("Group Name".into())
)
.unwrap()
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/SendImSecRestrictionTests.cs::SendImSecRestrictionTests.CanSendIM_Secure::test 65422234501bcbf151f27e0d45c74726e670665f39d90df23396f79450ba2b91 translated
#[test]
fn secure_send_im_user_exceptions_are_sender_scoped() {
let h = harness();
process(&h, &["@sendim_sec=n", &format!("@sendim:{USER_1}=add")]);
block_on(h.process_from(&format!("@sendim:{USER_2}=add"), SENDER_2, "Sender 2")).unwrap();
assert!(send_im(&h, USER_1, None));
assert!(!send_im(&h, USER_2, None));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/SendImSecRestrictionTests.cs::SendImSecRestrictionTests.CanSendIM_Secure_Group::test 4ed2e6416a86eb2406e20bbb7e60a380de25577ad034ba613530ed28f6001df9 translated
#[test]
fn secure_send_im_group_exception() {
let h = harness();
process(&h, &["@sendim_sec=n", "@sendim:Group Name=add"]);
block_on(h.process_from("@sendim:allgroups=add", SENDER_2, "Sender 2")).unwrap();
assert!(send_im(&h, USER_1, Some("Group Name")));
assert!(!send_im(&h, USER_1, Some("Another Group")));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/SendImSecRestrictionTests.cs::SendImSecRestrictionTests.CanSendIM_Secure_AllGroups::test a4b699c9ada01ca4ce4d535739178e5310affa938d02dfaede6d034488d24f5f translated
#[test]
fn secure_send_im_all_groups_exception() {
let h = harness();
process(&h, &["@sendim_sec=n", "@sendim:allgroups=add"]);
assert!(send_im(&h, USER_1, Some("Group Name")));
assert!(send_im(&h, USER_1, Some("Another Group")));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/SendImToRestrictionTests.cs::SendImToRestrictionTests.CanSendIMTo::test 38258cda1081160b6b34f8e909adbc683a0f08efce8c63066bcac09835e5cdcc translated
#[test]
fn send_im_to_one_user() {
let h = harness();
process(&h, &[&format!("@sendimto:{USER_1}=n")]);
assert!(!send_im(&h, USER_1, None));
assert!(send_im(&h, USER_2, None));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/SendImToRestrictionTests.cs::SendImToRestrictionTests.CanSendIMTo_Group::test 1e12f7e3dbbee7d8dfb757fc8797644a353dfaa995e343e59124aa85126d70aa translated
#[test]
fn send_im_to_one_group() {
let h = harness();
process(&h, &["@sendimto:First Group=n"]);
assert!(!send_im(&h, USER_1, Some("First Group")));
assert!(send_im(&h, USER_2, Some("Second Group")));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/SendImToRestrictionTests.cs::SendImToRestrictionTests.CanSendIMTo_AllGroups::test bc9b87ab7b171c76987ddaf94f05c0ac2ad8dc0c1f24f5dfce2f4125e7b28df5 translated
#[test]
fn send_im_to_all_groups() {
let h = harness();
process(&h, &["@sendimto:allgroups=n"]);
assert!(!send_im(&h, USER_1, Some("First Group")));
assert!(!send_im(&h, USER_2, Some("Second Group")));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/ShareRestrictionTests.cs::ShareRestrictionTests.CanShare::test 23052e5792ff72624d45b54ccfd02fa5d8025d977010f1e8d34a90d27a4d0e29 translated
#[test]
fn share_restriction() {
let h = harness();
process(&h, &["@share=n"]);
assert!(!h.service.permissions().can_share(None).unwrap());
assert!(
!h.service
.permissions()
.can_share(Some(Some(guid(SENDER_2))))
.unwrap()
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/ShareSecRestrictionTests.cs::ShareSecRestrictionTests.CanShare_Secure_Default::test 6d61bafb190791ceaccb6c46cde3adf5b5479e6b5e76bafeadd0942400389248 translated
#[test]
fn secure_share_default() {
let h = harness();
process(&h, &["@share_sec=n"]);
assert!(!h.service.permissions().can_share(None).unwrap());
assert!(
!h.service
.permissions()
.can_share(Some(Some(guid(USER_1))))
.unwrap()
);
assert!(
!h.service
.permissions()
.can_share(Some(Some(guid(USER_2))))
.unwrap()
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/ShareSecRestrictionTests.cs::ShareSecRestrictionTests.CanShare_Secure::test e1aed5b3b8efccef47094788c3221e20240c671c1004d6d6bd899e5d9ddd51fa translated
#[test]
fn secure_share_exceptions_are_sender_scoped() {
let h = harness();
process(&h, &["@share_sec=n", &format!("@share:{USER_1}=add")]);
block_on(h.process_from(&format!("@share:{USER_2}=add"), SENDER_2, "Sender 2")).unwrap();
assert!(!h.service.permissions().can_share(None).unwrap());
assert!(
h.service
.permissions()
.can_share(Some(Some(guid(USER_1))))
.unwrap()
);
assert!(
!h.service
.permissions()
.can_share(Some(Some(guid(USER_2))))
.unwrap()
);
}
fn hover(h: &RlvHarness, location: HoverTextLocation, object: &str) -> bool {
h.service
.permissions()
.can_show_hover_text(location, Some(Some(guid(object))))
.unwrap()
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/ShowHoverTextAllRestrictionTests.cs::ShowHoverTextAllRestrictionTests.CanShowHoverTextAll::test 6a855738e87477d31dc7867d0c75ba1bf563e2b1e180f54759657a58b7da9793 translated
#[test]
fn show_hover_text_all_restriction() {
let h = harness();
process(&h, &["@showhovertextall=n"]);
assert!(!hover(&h, HoverTextLocation::World, USER_1));
assert!(!hover(&h, HoverTextLocation::Hud, USER_1));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/ShowHoverTextHudRestrictionTests.cs::ShowHoverTextHudRestrictionTests.CanShowHoverTextHud::test 9d08e2a3eb303b14c4b222cae5d52537e81a7d9cfc9fcfe9625d513b6311a6ed translated
#[test]
fn show_hover_text_hud_restriction() {
let h = harness();
process(&h, &["@showhovertexthud=n"]);
for object in [USER_1, USER_2] {
assert!(hover(&h, HoverTextLocation::World, object));
assert!(!hover(&h, HoverTextLocation::Hud, object));
}
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/ShowHoverTextRestrictionTests.cs::ShowHoverTextRestrictionTests.CanShowHoverText::test 5642102d6832b227c37c14d0fbfc30921022c5789b811021805db6f3a2120f36 translated
#[test]
fn show_hover_text_one_object_restriction() {
let h = harness();
process(&h, &[&format!("@showhovertext:{USER_1}=n")]);
assert!(!hover(&h, HoverTextLocation::World, USER_1));
assert!(!hover(&h, HoverTextLocation::Hud, USER_1));
assert!(hover(&h, HoverTextLocation::World, USER_2));
assert!(hover(&h, HoverTextLocation::Hud, USER_2));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/ShowHoverTextWorldRestrictionTests.cs::ShowHoverTextWorldRestrictionTests.CanShowHoverTextWorld::test 1be82408fbc87f1525dc7652e01fbbc17a993b70a2268f0b742d035b37cbf70c translated
#[test]
fn show_hover_text_world_restriction() {
let h = harness();
process(&h, &["@showhovertextworld=n"]);
for object in [USER_1, USER_2] {
assert!(!hover(&h, HoverTextLocation::World, object));
assert!(hover(&h, HoverTextLocation::Hud, object));
}
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/ShowNameTagsRestrictionTests.cs::ShowNameTagsRestrictionTests.CanShowNameTags::test 74e8a6aefdefb9eb41509f6b4438e6854e5ad0ace38ab663f445aae484e94e22 translated
#[test]
fn show_name_tags_restriction() {
let h = harness();
process(&h, &["@shownametags=n"]);
assert!(!h.service.permissions().can_show_name_tags(None).unwrap());
assert!(
!h.service
.permissions()
.can_show_name_tags(Some(Some(guid(SENDER_2))))
.unwrap()
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/ShowNamesRestrictionTests.cs::ShowNamesRestrictionTests.CanShowNames::test c44fe98d881a89af5db856e98f7bd7480d9bfb4378730002e518a7d1da412812 translated
#[test]
fn show_names_restriction() {
let h = harness();
process(&h, &["@shownames=n"]);
assert!(!h.service.permissions().can_show_names(None).unwrap());
assert!(
!h.service
.permissions()
.can_show_names(Some(Some(guid(SENDER_2))))
.unwrap()
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/ShowNamesSecRestrictionTests.cs::ShowNamesSecRestrictionTests.CanShowNames_Secure_Default::test 98d2c84d2f226fbb4b03c365f3ab007142d87b1980dda3666ce5ec36909fc599 translated
#[test]
fn secure_show_names_default() {
let h = harness();
process(&h, &["@shownames_sec=n"]);
assert!(!h.service.permissions().can_show_names(None).unwrap());
assert!(
!h.service
.permissions()
.can_show_names(Some(Some(guid(USER_1))))
.unwrap()
);
assert!(
!h.service
.permissions()
.can_show_names(Some(Some(guid(USER_2))))
.unwrap()
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/ShowNamesSecRestrictionTests.cs::ShowNamesSecRestrictionTests.CanShowNames_Secure::test 90ae29916dc2b60cd3de336e4a37683de8967f448fef26af360e3d24278773d3 translated
#[test]
fn secure_show_names_exceptions_are_sender_scoped() {
let h = harness();
process(
&h,
&["@shownames_sec=n", &format!("@shownames:{USER_1}=add")],
);
block_on(h.process_from(&format!("@shownames:{USER_2}=add"), SENDER_3, "Sender 2")).unwrap();
assert!(!h.service.permissions().can_show_names(None).unwrap());
assert!(
h.service
.permissions()
.can_show_names(Some(Some(guid(USER_1))))
.unwrap()
);
assert!(
!h.service
.permissions()
.can_show_names(Some(Some(guid(USER_2))))
.unwrap()
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/ShowNamesSecRestrictionTests.cs::ShowNamesSecRestrictionTests.CanShowNames_Secure_Except::test 457772321f7fd1ea88a279e99a4b0a955e462652bac1fb7953b8455f3d67a155 translated
#[test]
fn secure_show_names_direct_exception() {
let h = harness();
process(
&h,
&["@shownames_sec=n", &format!("@shownames_sec:{USER_1}=n")],
);
assert!(!h.service.permissions().can_show_names(None).unwrap());
assert!(
h.service
.permissions()
.can_show_names(Some(Some(guid(USER_1))))
.unwrap()
);
assert!(
!h.service
.permissions()
.can_show_names(Some(Some(guid(USER_2))))
.unwrap()
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/StartImRestrictionTests.cs::StartImRestrictionTests.CanStartIM::test cc8318d5233b947ca96939369de3a2fdc2c21468cc13a87c87908126c6e45500 translated
#[test]
fn start_im_restriction() {
let h = harness();
process(&h, &["@startim=n"]);
assert!(!h.service.permissions().can_start_im(guid(USER_1)).unwrap());
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/StartImToRestrictionTests.cs::StartImToRestrictionTests.CanStartIMTo::test 0c7e19de2ecf94a6db09ee409ff88ff503e02d8dd8f7f11f427cebc51a3ac09f translated
#[test]
fn start_im_to_one_user() {
let h = harness();
process(&h, &[&format!("@startimto:{USER_2}=n")]);
assert!(h.service.permissions().can_start_im(guid(USER_1)).unwrap());
assert!(!h.service.permissions().can_start_im(guid(USER_2)).unwrap());
}

View File

@@ -0,0 +1,441 @@
// Exact Rust translations of far-touch, touch, sit-teleport, and teleport restrictions.
use libremetaverse_compat_tests::block_on;
use libremetaverse_compat_tests::rlv_support::{RlvHarness, guid};
use libremetaverse_rlv::RlvPermissionsServiceTouchLocation as TouchLocation;
const OBJECT_1: &str = "00000000-0000-4000-8000-000000000000";
const OBJECT_2: &str = "11111111-1111-4111-8111-111111111111";
const USER_1: &str = "55555555-5555-4555-8555-555555555555";
const USER_2: &str = "66666666-6666-4666-8666-666666666666";
const SENDER_2: &str = "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa";
const SENDER_3: &str = "bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb";
fn harness() -> RlvHarness {
RlvHarness::new().expect("RlvService constructor")
}
fn process(h: &RlvHarness, commands: &[&str]) {
for command in commands {
block_on(h.process(command)).unwrap();
}
}
fn far_touch(command: &str) -> (bool, f32) {
let h = harness();
process(&h, &[command]);
let mut distance = 0.0;
let found = h
.service
.permissions()
.try_get_max_far_touch_distance(&mut distance);
(found, distance)
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/FarTouchRestrictionTests.cs::FarTouchRestrictionTests.CanFarTouch::case:ccd63fc5b9c064fb a5568e0040a3c0ac8875a11596b7d0799ac5169b919e4fc65587555b2d3edd52 translated
#[test]
fn far_touch_fartouch_value() {
assert_eq!(far_touch("@fartouch:0.9=n"), (true, 0.9));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/FarTouchRestrictionTests.cs::FarTouchRestrictionTests.CanFarTouch::case:ae3d093c6c7267ac a5568e0040a3c0ac8875a11596b7d0799ac5169b919e4fc65587555b2d3edd52 translated
#[test]
fn far_touch_touchfar_value() {
assert_eq!(far_touch("@touchfar:0.9=n"), (true, 0.9));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/FarTouchRestrictionTests.cs::FarTouchRestrictionTests.CanFarTouch_Synonym::case:ccd63fc5b9c064fb c7aff866d539ceb26cc028532a901f18b58bb020f34da56444f08c9f4df1eb52 translated
#[test]
fn far_touch_fartouch_synonym() {
assert_eq!(far_touch("@fartouch:0.9=n"), (true, 0.9));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/FarTouchRestrictionTests.cs::FarTouchRestrictionTests.CanFarTouch_Synonym::case:ae3d093c6c7267ac c7aff866d539ceb26cc028532a901f18b58bb020f34da56444f08c9f4df1eb52 translated
#[test]
fn far_touch_touchfar_synonym() {
assert_eq!(far_touch("@touchfar:0.9=n"), (true, 0.9));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/FarTouchRestrictionTests.cs::FarTouchRestrictionTests.CanFarTouch_Default::case:ccd63fc5b9c064fb e894c744ea780a0a46cd2387157077c1a62c3c6b982303f3b7bff0b5d950816a translated
#[test]
fn far_touch_fartouch_default() {
assert_eq!(far_touch("@fartouch=n"), (true, 1.5));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/FarTouchRestrictionTests.cs::FarTouchRestrictionTests.CanFarTouch_Default::case:ae3d093c6c7267ac e894c744ea780a0a46cd2387157077c1a62c3c6b982303f3b7bff0b5d950816a translated
#[test]
fn far_touch_touchfar_default() {
assert_eq!(far_touch("@touchfar=n"), (true, 1.5));
}
fn far_touch_multiple_matches(first: &str, second: &str) -> bool {
let h = harness();
process(
&h,
&[&format!("@{first}:12.34=n"), &format!("@{second}:6.78=n")],
);
let mut before_removal = 0.0;
let found_before = h
.service
.permissions()
.try_get_max_far_touch_distance(&mut before_removal);
process(&h, &[&format!("@{first}:6.78=y")]);
let mut after_removal = 0.0;
let found_after = h
.service
.permissions()
.try_get_max_far_touch_distance(&mut after_removal);
found_before
&& found_after
&& (after_removal - 12.34).abs() < 0.0001
&& (before_removal - 6.78).abs() < 0.0001
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/FarTouchRestrictionTests.cs::FarTouchRestrictionTests.CanFarTouch_Multiple_Synonyms::case:5788809ef8877342 423a8781a2de94943fa028ac64d61532509c90375cf1ca80edf1d0ef8edd9905 translated
#[test]
fn far_touch_multiple_fartouch_fartouch() {
assert!(far_touch_multiple_matches("fartouch", "fartouch"));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/FarTouchRestrictionTests.cs::FarTouchRestrictionTests.CanFarTouch_Multiple_Synonyms::case:b3ebeae1885ed5db 423a8781a2de94943fa028ac64d61532509c90375cf1ca80edf1d0ef8edd9905 translated
#[test]
fn far_touch_multiple_fartouch_touchfar() {
assert!(far_touch_multiple_matches("fartouch", "touchfar"));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/FarTouchRestrictionTests.cs::FarTouchRestrictionTests.CanFarTouch_Multiple_Synonyms::case:07cf5c5cabecfebf 423a8781a2de94943fa028ac64d61532509c90375cf1ca80edf1d0ef8edd9905 translated
#[test]
fn far_touch_multiple_touchfar_touchfar() {
assert!(far_touch_multiple_matches("touchfar", "touchfar"));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/FarTouchRestrictionTests.cs::FarTouchRestrictionTests.CanFarTouch_Multiple_Synonyms::case:8008f95bc76b47e9 423a8781a2de94943fa028ac64d61532509c90375cf1ca80edf1d0ef8edd9905 translated
#[test]
fn far_touch_multiple_touchfar_fartouch() {
assert!(far_touch_multiple_matches("touchfar", "fartouch"));
}
fn sit_tp(h: &RlvHarness) -> (bool, f32) {
let mut distance = 0.0;
let active = h.service.permissions().can_sit_tp(&mut distance).unwrap();
(active, distance)
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/SitTpRestrictionTests.cs::SitTpRestrictionTests.CanSitTp_Default::test ddcdba94af060ede43f0d585688966ccd923238a2365164b32a301b04d83cdfc translated
#[test]
fn sit_tp_default() {
assert_eq!(sit_tp(&harness()), (false, 1.5));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/SitTpRestrictionTests.cs::SitTpRestrictionTests.CanSitTp_Single::test 041c57829ab1032eed79e6f47c8b9026124b681fb6ffa4b3c5ac16b16d0b354b translated
#[test]
fn sit_tp_single() {
let h = harness();
process(&h, &["@SitTp:2.5=n"]);
assert_eq!(sit_tp(&h), (true, 2.5));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/SitTpRestrictionTests.cs::SitTpRestrictionTests.CanSitTp_Multiple_SingleSender::test feed9f3cca3395e1eb5a8d831304a4171e79f6e1d93f03a4aca0e27edba5ed6d translated
#[test]
fn sit_tp_multiple_single_sender() {
let h = harness();
process(&h, &["@SitTp:3.5=n", "@SitTp:4.5=n", "@SitTp:2.5=n"]);
assert_eq!(sit_tp(&h), (true, 2.5));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/SitTpRestrictionTests.cs::SitTpRestrictionTests.CanSitTp_Multiple_SingleSender_WithRemoval::test 4b26c525e0a13fbc79b280f0a6c3b0f9e3e0e664241e9f55a88eda3dd80b203a translated
#[test]
fn sit_tp_multiple_single_sender_with_removal() {
let h = harness();
process(
&h,
&[
"@SitTp:3.5=n",
"@SitTp:4.5=n",
"@SitTp:2.5=n",
"@SitTp:8.5=n",
"@SitTp:8.5=y",
],
);
assert_eq!(sit_tp(&h), (true, 2.5));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/SitTpRestrictionTests.cs::SitTpRestrictionTests.CanSitTp_Multiple_MultipleSenders::test cd9e3508d44e2e008609ac0cc12d3e207ec454a3f5c6e36aa325d33be9b6718f translated
#[test]
fn sit_tp_multiple_senders() {
let h = harness();
process(&h, &["@SitTp:3.5=n"]);
block_on(h.process_from("@SitTp:4.5=n", SENDER_2, "Sender 2")).unwrap();
block_on(h.process_from("@SitTp:2.5=n", SENDER_3, "Sender 3")).unwrap();
assert_eq!(sit_tp(&h), (true, 2.5));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/SitTpRestrictionTests.cs::SitTpRestrictionTests.CanSitTp_Off::test e871d15d797e0f8f0b02613c2a421b47b87068c8757bbd0104cd15d406137854 translated
#[test]
fn sit_tp_off() {
let h = harness();
process(&h, &["@SitTp:2.5=n", "@SitTp:2.5=y"]);
assert_eq!(sit_tp(&h), (false, 1.5));
}
fn touch(
h: &RlvHarness,
location: TouchLocation,
object: &str,
user: Option<&str>,
distance: Option<f32>,
) -> bool {
h.service
.permissions()
.can_touch(
location,
guid(object),
user.map(|value| Some(guid(value))),
distance.map(Some),
)
.unwrap()
}
fn touch_matrix(h: &RlvHarness) -> [bool; 4] {
[
touch(h, TouchLocation::AttachedSelf, OBJECT_1, None, None),
touch(
h,
TouchLocation::AttachedOther,
OBJECT_1,
Some(USER_1),
None,
),
touch(h, TouchLocation::RezzedInWorld, OBJECT_1, None, Some(5.0)),
touch(h, TouchLocation::Hud, OBJECT_1, None, None),
]
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/TouchAllRestrictionTests.cs::TouchAllRestrictionTests.TouchAll::test 06da3251125bf4d3b2d542cfba7fa0a7b0c18dc0f97024a57c0e0ddf6cfc8dd6 translated
#[test]
fn touch_all_default_permissions() {
assert_eq!(touch_matrix(&harness()), [true, true, true, true]);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/TouchAllRestrictionTests.cs::TouchAllRestrictionTests.TouchAll_default::test 9526d7bed6473afd41f97fb11ec950caae157865cec8eee719030ca109ab2681 translated
#[test]
fn touch_all_restricted() {
let h = harness();
process(&h, &["@touchall=n"]);
assert_eq!(touch_matrix(&h), [false, false, false, true]);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/TouchAttachOtherRestrictionTests.cs::TouchAttachOtherRestrictionTests.TouchAttachOther_default::test 1f8157f5fd5db8b5a4596d5be6a5d780704cac85370204c77eca08da286adb86 translated
#[test]
fn touch_attach_other_default() {
let h = harness();
process(&h, &["@touchattachother=n"]);
assert_eq!(touch_matrix(&h), [true, false, true, true]);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/TouchAttachOtherRestrictionTests.cs::TouchAttachOtherRestrictionTests.TouchAttachOther_Specific::test add9d393d4aaf03768239611a8a64b2ef73fc4c8561dbbc51950a10c006198e6 translated
#[test]
fn touch_attach_other_specific_user() {
let h = harness();
process(&h, &[&format!("@touchattachother:{USER_2}=n")]);
assert!(touch(&h, TouchLocation::AttachedSelf, OBJECT_1, None, None));
assert!(touch(
&h,
TouchLocation::AttachedOther,
OBJECT_1,
Some(USER_1),
None
));
assert!(!touch(
&h,
TouchLocation::AttachedOther,
OBJECT_1,
Some(USER_2),
None
));
assert!(touch(
&h,
TouchLocation::RezzedInWorld,
OBJECT_1,
None,
Some(5.0)
));
assert!(touch(&h, TouchLocation::Hud, OBJECT_1, None, None));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/TouchAttachRestrictionTests.cs::TouchAttachRestrictionTests.TouchAttach_default::test 4c4c65f8ed4b29367c353a02e52c91e9402788ffd35c75e5a6a40a827710e20a translated
#[test]
fn touch_attach_default() {
let h = harness();
process(&h, &["@touchattach=n"]);
assert_eq!(touch_matrix(&h), [false, false, true, true]);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/TouchAttachSelfRestrictionTests.cs::TouchAttachSelfRestrictionTests.TouchAttachSelf_default::test 09f7d7a45a9899746c1c63608f95db89ef2ae4a875437a2b594bb120da8139ff translated
#[test]
fn touch_attach_self_default() {
let h = harness();
process(&h, &["@touchattachself=n"]);
assert_eq!(touch_matrix(&h), [false, true, true, true]);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/TouchHudRestrictionTests.cs::TouchHudRestrictionTests.TouchHud_default::test b15afadb1f45b51eb47651a9d890ed2a6b1de8066d986d9b1ccc33da734c0194 translated
#[test]
fn touch_hud_default() {
let h = harness();
process(&h, &["@touchhud=n"]);
assert_eq!(touch_matrix(&h), [true, true, true, false]);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/TouchHudRestrictionTests.cs::TouchHudRestrictionTests.TouchHud_specific::test 4c4e1a9493e5cf34f220ebec54c5373e1b30c81044803deece263dced5f7155d translated
#[test]
fn touch_hud_specific_object() {
let h = harness();
process(&h, &[&format!("@touchhud:{OBJECT_2}=n")]);
assert_eq!(touch_matrix(&h), [true, true, true, true]);
assert!(!touch(&h, TouchLocation::Hud, OBJECT_2, None, None));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/TouchWorldRestrictionTests.cs::TouchWorldRestrictionTests.TouchWorld_default::test 5995288721c44beaa329b266e15d619f2314c9ca74386145294183c7c509b42a translated
#[test]
fn touch_world_default() {
let h = harness();
process(&h, &["@touchworld=n"]);
assert_eq!(touch_matrix(&h), [true, true, false, true]);
}
fn tp_local_matches(command: &str, expected_distance: f32) -> bool {
let h = harness();
process(&h, &[command]);
let mut distance = -1.0;
h.service.permissions().can_tp_local(&mut distance).unwrap()
&& (distance - expected_distance).abs() < 0.0001
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/TpLocalRestrictionTests.cs::TpLocalRestrictionTests.CanTpLocal_Default::test 4b251429c6561c1d29f19f8fbc33dd0fb11344fe0d10962e789823ffedb3777b translated
#[test]
fn tp_local_default_distance() {
assert!(tp_local_matches("@TpLocal=n", 0.0));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/TpLocalRestrictionTests.cs::TpLocalRestrictionTests.CanTpLocal::test f9dd3daf337533beab1f4c2dce488f44dea5d17880e8f61b33e3c17c1a4c776f translated
#[test]
fn tp_local_explicit_distance() {
assert!(tp_local_matches("@TpLocal:0.9=n", 0.9));
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/TpLureRestrictionTests.cs::TpLureRestrictionTests.CanTpLure_Default::test 595e468736aab4136404842adf36a79f37b9900c3ee3993079621a5a6c96dec1 translated
#[test]
fn tp_lure_default() {
let permissions = harness().service.permissions();
assert!(permissions.can_tp_lure(None).unwrap());
assert!(permissions.can_tp_lure(Some(Some(guid(SENDER_2)))).unwrap());
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/TpLureRestrictionTests.cs::TpLureRestrictionTests.CanTpLure::test a57f7803128d75a0f1ba35a1c7489f78ca99d7e5e540f06b84725da8a5cd10da translated
#[test]
fn tp_lure_restricted() {
let h = harness();
process(&h, &["@tplure=n"]);
let permissions = h.service.permissions();
assert!(!permissions.can_tp_lure(None).unwrap());
assert!(!permissions.can_tp_lure(Some(Some(guid(SENDER_2)))).unwrap());
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/TpLureSecRestrictionTests.cs::TpLureSecRestrictionTests.CanTpLure_Secure_Default::test 577c2c8d22ba1aa8d4426832807ea4ed8cd243836b0d38b0ebc9f32a851c34f4 translated
#[test]
fn secure_tp_lure_default() {
let h = harness();
process(&h, &["@tplure_sec=n"]);
let permissions = h.service.permissions();
assert!(!permissions.can_tp_lure(None).unwrap());
assert!(!permissions.can_tp_lure(Some(Some(guid(OBJECT_1)))).unwrap());
assert!(!permissions.can_tp_lure(Some(Some(guid(OBJECT_2)))).unwrap());
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/TpLureSecRestrictionTests.cs::TpLureSecRestrictionTests.CanTpLure_Secure::test 38f2894e39bdd7c3c8e1520fa6ed02573be3dfdef0bc5bd1073d9d2240917804 translated
#[test]
fn secure_tp_lure_exceptions_are_sender_scoped() {
let h = harness();
process(&h, &["@tplure_sec=n", &format!("@tplure:{OBJECT_1}=add")]);
block_on(h.process_from(&format!("@tplure:{OBJECT_2}=add"), SENDER_2, "Sender 2")).unwrap();
let permissions = h.service.permissions();
assert!(!permissions.can_tp_lure(None).unwrap());
assert!(permissions.can_tp_lure(Some(Some(guid(OBJECT_1)))).unwrap());
assert!(!permissions.can_tp_lure(Some(Some(guid(OBJECT_2)))).unwrap());
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/TpRequestRestrictionTests.cs::TpRequestRestrictionTests.CanTpRequest::test 08ddf0e6dd1faf1f249bc7f7a9545d9e33efb5a438eacc3606b1495a83cf57db translated
#[test]
fn tp_request_restricted() {
let h = harness();
process(&h, &["@tprequest=n"]);
let permissions = h.service.permissions();
assert!(!permissions.can_tp_request(None).unwrap());
assert!(
!permissions
.can_tp_request(Some(Some(guid(SENDER_2))))
.unwrap()
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/TpRequestRestrictionTests.cs::TpRequestRestrictionTests.CanTpRequest_Except::test 89ccb1dd172928c41079555cb6d7ff3fcbd34594dcff0399670cdebc739ac109 translated
#[test]
fn tp_request_exception() {
let h = harness();
process(&h, &["@tprequest=n", &format!("@tprequest:{OBJECT_1}=add")]);
let permissions = h.service.permissions();
assert!(!permissions.can_tp_request(None).unwrap());
assert!(
permissions
.can_tp_request(Some(Some(guid(OBJECT_1))))
.unwrap()
);
assert!(
!permissions
.can_tp_request(Some(Some(guid(OBJECT_2))))
.unwrap()
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/TpRequestSecRestrictionTests.cs::TpRequestSecRestrictionTests.CanTpRequest_Secure_Default::test 87cb0ffa95d408d55045ade0966979360c28762e05729893b068801ed3b877ed translated
#[test]
fn secure_tp_request_default() {
let h = harness();
process(&h, &["@tprequest_sec=n"]);
let permissions = h.service.permissions();
assert!(!permissions.can_tp_request(None).unwrap());
assert!(
!permissions
.can_tp_request(Some(Some(guid(OBJECT_1))))
.unwrap()
);
assert!(
!permissions
.can_tp_request(Some(Some(guid(OBJECT_2))))
.unwrap()
);
}
// parity-case: LibreMetaverse.Tests/RLV/Restrictions/TpRequestSecRestrictionTests.cs::TpRequestSecRestrictionTests.CanTpRequest_Secure::test 623310f5c9150f6d6527b0db0446e2c33bf873a849a8dc68b78a4173d130da93 translated
#[test]
fn secure_tp_request_exceptions_are_sender_scoped() {
let h = harness();
process(
&h,
&["@tprequest_sec=n", &format!("@tprequest:{OBJECT_1}=add")],
);
block_on(h.process_from(&format!("@tprequest:{OBJECT_2}=add"), SENDER_2, "Sender 2")).unwrap();
let permissions = h.service.permissions();
assert!(!permissions.can_tp_request(None).unwrap());
assert!(
permissions
.can_tp_request(Some(Some(guid(OBJECT_1))))
.unwrap()
);
assert!(
!permissions
.can_tp_request(Some(Some(guid(OBJECT_2))))
.unwrap()
);
}