summaryrefslogtreecommitdiffstats
path: root/xpcom/rust/gtest/xpcom
diff options
context:
space:
mode:
Diffstat (limited to 'xpcom/rust/gtest/xpcom')
-rw-r--r--xpcom/rust/gtest/xpcom/Cargo.toml14
-rw-r--r--xpcom/rust/gtest/xpcom/TestXpcom.cpp66
-rw-r--r--xpcom/rust/gtest/xpcom/test.rs131
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);
+}