diff options
Diffstat (limited to 'xpcom/rust/gtest/xpcom')
-rw-r--r-- | xpcom/rust/gtest/xpcom/Cargo.toml | 14 | ||||
-rw-r--r-- | xpcom/rust/gtest/xpcom/TestXpcom.cpp | 66 | ||||
-rw-r--r-- | xpcom/rust/gtest/xpcom/test.rs | 131 |
3 files changed, 211 insertions, 0 deletions
diff --git a/xpcom/rust/gtest/xpcom/Cargo.toml b/xpcom/rust/gtest/xpcom/Cargo.toml new file mode 100644 index 0000000000..777080b33b --- /dev/null +++ b/xpcom/rust/gtest/xpcom/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "xpcom-gtest" +version = "0.1.0" +authors = ["michael@thelayzells.com"] +license = "MPL-2.0" +description = "Tests for rust bindings to xpcom interfaces" + +[dependencies] +xpcom = { path = "../../xpcom" } +nserror = { path = "../../nserror" } +nsstring = { path = "../../nsstring" } + +[lib] +path = "test.rs" diff --git a/xpcom/rust/gtest/xpcom/TestXpcom.cpp b/xpcom/rust/gtest/xpcom/TestXpcom.cpp new file mode 100644 index 0000000000..69425274f6 --- /dev/null +++ b/xpcom/rust/gtest/xpcom/TestXpcom.cpp @@ -0,0 +1,66 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "gtest/gtest.h" +#include "nsCOMPtr.h" +#include "nsIRunnable.h" +#include "nsIObserver.h" +#include "mozilla/Services.h" +#include "nsIObserverService.h" + +extern "C" nsIObserverService* Rust_ObserveFromRust(); + +TEST(RustXpcom, ObserverFromRust) +{ + nsCOMPtr<nsIObserverService> rust = Rust_ObserveFromRust(); + nsCOMPtr<nsIObserverService> cpp = mozilla::services::GetObserverService(); + EXPECT_EQ(rust, cpp); +} + +extern "C" void Rust_ImplementRunnableInRust(bool* aItWorked, + nsIRunnable** aRunnable); + +TEST(RustXpcom, ImplementRunnableInRust) +{ + bool itWorked = false; + nsCOMPtr<nsIRunnable> runnable; + Rust_ImplementRunnableInRust(&itWorked, getter_AddRefs(runnable)); + + EXPECT_TRUE(runnable); + EXPECT_FALSE(itWorked); + runnable->Run(); + EXPECT_TRUE(itWorked); +} + +extern "C" void Rust_GetMultipleInterfaces(nsIRunnable** aRunnable, + nsIObserver** aObserver); + +TEST(RustXpcom, DynamicCastVoid) +{ + nsCOMPtr<nsIRunnable> runnable; + nsCOMPtr<nsIObserver> observer; + Rust_GetMultipleInterfaces(getter_AddRefs(runnable), + getter_AddRefs(observer)); + + // They should have different addresses when `static_cast` to void* + EXPECT_NE(static_cast<void*>(runnable.get()), + static_cast<void*>(observer.get())); + + // These should be the same object + nsCOMPtr<nsISupports> runnableSupports = do_QueryInterface(runnable); + nsCOMPtr<nsISupports> observerSupports = do_QueryInterface(observer); + EXPECT_EQ(runnableSupports.get(), observerSupports.get()); + +#ifndef XP_WIN + // They should have the same address when dynamic_cast to void* + // dynamic_cast<void*> is not supported without rtti on windows. + EXPECT_EQ(dynamic_cast<void*>(runnable.get()), + dynamic_cast<void*>(observer.get())); + + // The nsISupports pointer from `do_QueryInterface` should match + // `dynamic_cast<void*>` + EXPECT_EQ(dynamic_cast<void*>(observer.get()), + static_cast<void*>(observerSupports.get())); +#endif +} diff --git a/xpcom/rust/gtest/xpcom/test.rs b/xpcom/rust/gtest/xpcom/test.rs new file mode 100644 index 0000000000..f26a0140f3 --- /dev/null +++ b/xpcom/rust/gtest/xpcom/test.rs @@ -0,0 +1,131 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#![allow(non_snake_case)] + +#[macro_use] +extern crate xpcom; + +extern crate nserror; + +use nserror::{nsresult, NS_OK}; +use std::ffi::{CStr, CString}; +use std::os::raw::c_char; +use std::ptr; +use xpcom::{interfaces, RefPtr}; + +#[no_mangle] +pub unsafe extern "C" fn Rust_ObserveFromRust() -> *const interfaces::nsIObserverService { + let obssvc: RefPtr<interfaces::nsIObserverService> = + xpcom::components::Observer::service().unwrap(); + + // Define an observer + #[xpcom(implement(nsIObserver), nonatomic)] + struct Observer { + run: *mut bool, + } + impl Observer { + unsafe fn Observe( + &self, + _subject: *const interfaces::nsISupports, + topic: *const c_char, + _data: *const u16, + ) -> nsresult { + *self.run = true; + assert!(CStr::from_ptr(topic).to_str() == Ok("test-rust-observe")); + NS_OK + } + } + + let topic = CString::new("test-rust-observe").unwrap(); + + let mut run = false; + let observer = Observer::allocate(InitObserver { run: &mut run }); + let rv = obssvc.AddObserver( + observer.coerce::<interfaces::nsIObserver>(), + topic.as_ptr(), + false, + ); + assert!(rv.succeeded()); + + let rv = obssvc.NotifyObservers(ptr::null(), topic.as_ptr(), ptr::null()); + assert!(rv.succeeded()); + assert!(run, "The observer should have been run!"); + + let rv = obssvc.RemoveObserver(observer.coerce::<interfaces::nsIObserver>(), topic.as_ptr()); + assert!(rv.succeeded()); + + assert!( + observer.coerce::<interfaces::nsISupports>() as *const _ + == &*observer + .query_interface::<interfaces::nsISupports>() + .unwrap() as *const _ + ); + + &*obssvc +} + +#[no_mangle] +pub unsafe extern "C" fn Rust_ImplementRunnableInRust( + it_worked: *mut bool, + runnable: *mut *const interfaces::nsIRunnable, +) { + // Define a type which implements nsIRunnable in rust. + #[xpcom(implement(nsIRunnable), atomic)] + struct RunnableFn<F: Fn() + 'static> { + run: F, + } + + impl<F: Fn() + 'static> RunnableFn<F> { + unsafe fn Run(&self) -> nsresult { + (self.run)(); + NS_OK + } + } + + let my_runnable = RunnableFn::allocate(InitRunnableFn { + run: move || { + *it_worked = true; + }, + }); + my_runnable + .query_interface::<interfaces::nsIRunnable>() + .unwrap() + .forget(&mut *runnable); +} + +#[no_mangle] +pub unsafe extern "C" fn Rust_GetMultipleInterfaces( + runnable: *mut *const interfaces::nsIRunnable, + observer: *mut *const interfaces::nsIObserver, +) { + // Define a type which implements nsIRunnable and nsIObserver in rust, and + // hand both references back to c++ + #[xpcom(implement(nsIRunnable, nsIObserver), atomic)] + struct MultipleInterfaces {} + + impl MultipleInterfaces { + unsafe fn Run(&self) -> nsresult { + NS_OK + } + unsafe fn Observe( + &self, + _subject: *const interfaces::nsISupports, + _topic: *const c_char, + _data: *const u16, + ) -> nsresult { + NS_OK + } + } + + let instance = MultipleInterfaces::allocate(InitMultipleInterfaces {}); + instance + .query_interface::<interfaces::nsIRunnable>() + .unwrap() + .forget(&mut *runnable); + instance + .query_interface::<interfaces::nsIObserver>() + .unwrap() + .forget(&mut *observer); +} |