diff --git a/remote-trait-object/Cargo.toml b/remote-trait-object/Cargo.toml index 11aff52..775f67e 100644 --- a/remote-trait-object/Cargo.toml +++ b/remote-trait-object/Cargo.toml @@ -13,4 +13,5 @@ serde_cbor = "0.11.1" linkme = "0.2.1" [dev-dependencies] -remote-trait-object-macro = { path = "../remote-trait-object-macro"} \ No newline at end of file +env_logger = "0.7.1" +remote-trait-object-macro = { path = "../remote-trait-object-macro"} diff --git a/remote-trait-object/src/tests.rs b/remote-trait-object/src/tests.rs index dd8ff10..52efc44 100644 --- a/remote-trait-object/src/tests.rs +++ b/remote-trait-object/src/tests.rs @@ -14,6 +14,8 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . +mod complex_trait; + use crate as remote_trait_object; use remote_trait_object_macro as rto_macro; diff --git a/remote-trait-object/src/tests/complex_trait.rs b/remote-trait-object/src/tests/complex_trait.rs new file mode 100644 index 0000000..8fd9bc9 --- /dev/null +++ b/remote-trait-object/src/tests/complex_trait.rs @@ -0,0 +1,174 @@ +// Copyright 2020 Kodebox, Inc. +// This file is part of CodeChain. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +use super::TestPort; +use crate as remote_trait_object; +use crate::{ExportService, ImportService, Port, SArc, Service}; +use remote_trait_object_macro as rto_macro; +use std::sync::{Arc, Mutex}; + +#[rto_macro::service] +trait A: Service { + fn service_object_as_argument(&self, b: SArc); + fn service_object_as_return(&self) -> SArc; + fn recursive_service_object(&self) -> SArc; + fn get_recursion_count(&self) -> u32; +} + +#[rto_macro::service] +trait B: Service { + fn inc(&self); + fn get(&self) -> i32; +} + +struct SimpleA { + recursion_count: u32, +} + +impl SimpleA { + pub fn new() -> Self { + Self { + recursion_count: 0, + } + } + + pub fn with_recursion_count(recursion_count: u32) -> Self { + Self { + recursion_count, + } + } +} + +impl A for SimpleA { + fn service_object_as_argument(&self, b: SArc) { + let b = b.unwrap(); + assert_eq!(0, b.get()); + b.inc(); + b.inc(); + b.inc(); + assert_eq!(3, b.get()); + } + + fn service_object_as_return(&self) -> SArc { + let b = Arc::new(SimpleB::new()); + SArc::new(b) + } + + fn recursive_service_object(&self) -> SArc { + let a = Arc::new(SimpleA::with_recursion_count(self.recursion_count + 1)); + SArc::new(a) + } + + fn get_recursion_count(&self) -> u32 { + self.recursion_count + } +} + +impl Service for SimpleA {} + +struct SimpleB { + count: Mutex, +} + +impl SimpleB { + pub fn new() -> Self { + Self { + count: Mutex::new(0), + } + } +} + +impl Service for SimpleB {} +impl B for SimpleB { + fn inc(&self) { + *self.count.lock().unwrap() += 1 + } + fn get(&self) -> i32 { + *self.count.lock().unwrap() + } +} + +fn init_logger() { + let _ = env_logger::builder().is_test(true).try_init(); +} + +fn create_remote_a(port: Arc) -> Arc { + let a: Arc = Arc::new(SimpleA::new()); + let handle = >::export(Arc::downgrade(&port), a); + >::import(Arc::downgrade(&port), handle) +} + +#[test] +fn service_object_as_return() { + init_logger(); + + let port = Arc::new(TestPort::new()); + let remote_a = create_remote_a(port.clone()); + + let remote_b = remote_a.service_object_as_return().unwrap(); + assert_eq!(remote_b.get(), 0); + remote_b.inc(); + assert_eq!(remote_b.get(), 1); + remote_b.inc(); + assert_eq!(remote_b.get(), 2); + + drop(remote_a); + drop(remote_b); + drop(port) +} + +#[test] +fn service_object_as_argument() { + init_logger(); + + let port = Arc::new(TestPort::new()); + let remote_a = create_remote_a(port.clone()); + + let service_object_b = Arc::new(SimpleB::new()); + remote_a.service_object_as_argument(SArc::new(service_object_b)); + + drop(remote_a); + drop(port) +} + +#[test] +fn recursive_service_object() { + init_logger(); + + let port = Arc::new(TestPort::new()); + let mut remote_a = create_remote_a(port.clone()); + let mut remote_as = Vec::new(); + remote_as.push(Arc::clone(&remote_a)); + + for i in 0..10 { + assert_eq!(remote_a.get_recursion_count(), i); + remote_a = remote_a.recursive_service_object().unwrap(); + remote_as.push(Arc::clone(&remote_a)); + } + assert_eq!(remote_a.get_recursion_count(), 10); + + let remote_b = remote_a.service_object_as_return().unwrap(); + remote_b.inc(); + assert_eq!(remote_b.get(), 1); + + // remote_a + remote_b + recursive 10 remote_a = 12 + assert_eq!(port.register_len(), 12); + + drop(remote_as); + drop(remote_a); + drop(remote_b); + drop(port) +}