summaryrefslogtreecommitdiffstats
path: root/ipc/ipdl/test/gtest
diff options
context:
space:
mode:
Diffstat (limited to 'ipc/ipdl/test/gtest')
-rw-r--r--ipc/ipdl/test/gtest/IPDLUnitTest.h97
-rw-r--r--ipc/ipdl/test/gtest/PTestAsyncReturns.ipdl19
-rw-r--r--ipc/ipdl/test/gtest/PTestCancel.ipdl39
-rw-r--r--ipc/ipdl/test/gtest/PTestDataStructures.ipdl106
-rw-r--r--ipc/ipdl/test/gtest/PTestDataStructuresCommon.ipdlh107
-rw-r--r--ipc/ipdl/test/gtest/PTestDataStructuresSub.ipdl15
-rw-r--r--ipc/ipdl/test/gtest/PTestDescendant.ipdl22
-rw-r--r--ipc/ipdl/test/gtest/PTestDescendantSub.ipdl19
-rw-r--r--ipc/ipdl/test/gtest/PTestDescendantSubsub.ipdl14
-rw-r--r--ipc/ipdl/test/gtest/PTestEndpointOpens.ipdl22
-rw-r--r--ipc/ipdl/test/gtest/PTestEndpointOpensOpened.ipdl22
-rw-r--r--ipc/ipdl/test/gtest/PTestHangs.ipdl20
-rw-r--r--ipc/ipdl/test/gtest/PTestJSON.ipdl43
-rw-r--r--ipc/ipdl/test/gtest/PTestJSONHandle.ipdl15
-rw-r--r--ipc/ipdl/test/gtest/PTestManyChildAllocs.ipdl18
-rw-r--r--ipc/ipdl/test/gtest/PTestManyChildAllocsSub.ipdl18
-rw-r--r--ipc/ipdl/test/gtest/PTestMostNested.ipdl23
-rw-r--r--ipc/ipdl/test/gtest/PTestMultiMgrs.ipdl23
-rw-r--r--ipc/ipdl/test/gtest/PTestMultiMgrsBottom.ipdl16
-rw-r--r--ipc/ipdl/test/gtest/PTestMultiMgrsLeft.ipdl19
-rw-r--r--ipc/ipdl/test/gtest/PTestMultiMgrsRight.ipdl19
-rw-r--r--ipc/ipdl/test/gtest/PTestSelfManage.ipdl17
-rw-r--r--ipc/ipdl/test/gtest/PTestSelfManageRoot.ipdl16
-rw-r--r--ipc/ipdl/test/gtest/PTestShmem.ipdl15
-rw-r--r--ipc/ipdl/test/gtest/PTestSyncError.ipdl16
-rw-r--r--ipc/ipdl/test/gtest/PTestUniquePtrIPC.ipdl17
-rw-r--r--ipc/ipdl/test/gtest/PTestUrgency.ipdl20
-rw-r--r--ipc/ipdl/test/gtest/TestAsyncReturns.cpp77
-rw-r--r--ipc/ipdl/test/gtest/TestCancel.cpp126
-rw-r--r--ipc/ipdl/test/gtest/TestDataStructures.cpp864
-rw-r--r--ipc/ipdl/test/gtest/TestDescendant.cpp98
-rw-r--r--ipc/ipdl/test/gtest/TestEndpointOpens.cpp159
-rw-r--r--ipc/ipdl/test/gtest/TestHangs.cpp133
-rw-r--r--ipc/ipdl/test/gtest/TestJSON.cpp157
-rw-r--r--ipc/ipdl/test/gtest/TestManyChildAllocs.cpp82
-rw-r--r--ipc/ipdl/test/gtest/TestMostNested.cpp88
-rw-r--r--ipc/ipdl/test/gtest/TestMultiMgrs.cpp202
-rw-r--r--ipc/ipdl/test/gtest/TestSelfManage.cpp100
-rw-r--r--ipc/ipdl/test/gtest/TestShmem.cpp122
-rw-r--r--ipc/ipdl/test/gtest/TestSyncError.cpp44
-rw-r--r--ipc/ipdl/test/gtest/TestUniquePtrIPC.cpp80
-rw-r--r--ipc/ipdl/test/gtest/TestUrgency.cpp115
-rw-r--r--ipc/ipdl/test/gtest/moz.build41
43 files changed, 3248 insertions, 37 deletions
diff --git a/ipc/ipdl/test/gtest/IPDLUnitTest.h b/ipc/ipdl/test/gtest/IPDLUnitTest.h
index f4548b508c..e2c44630b7 100644
--- a/ipc/ipdl/test/gtest/IPDLUnitTest.h
+++ b/ipc/ipdl/test/gtest/IPDLUnitTest.h
@@ -27,52 +27,75 @@ class IPDLTestHelper {
virtual void TestBody() = 0;
};
-#define IPDL_TEST_CLASS_NAME_(actorname) IPDL_TEST_##actorname
+#define IPDL_TEST_CLASS_NAME_(actorname, ...) IPDL_TEST_##actorname##__VA_ARGS__
-#define IPDL_TEST_HEAD_(actorname) \
- class IPDL_TEST_CLASS_NAME_(actorname) \
- : public ::mozilla::_ipdltest::IPDLTestHelper { \
- public: \
- IPDL_TEST_CLASS_NAME_(actorname)() : mActor(new actorname##Parent) {} \
- \
- private: \
- void TestBody() override; \
- const char* GetName() override { return sName; }; \
- actorname##Parent* GetActor() override { return mActor; }; \
- \
- RefPtr<actorname##Parent> mActor; \
- static const char* sName; \
- }; \
- const char* IPDL_TEST_CLASS_NAME_(actorname)::sName = \
- ::mozilla::_ipdltest::RegisterAllocChildActor( \
- #actorname, []() -> ::mozilla::ipc::IToplevelProtocol* { \
- return new actorname##Child; \
+#define IPDL_TEST_HEAD_(actorname, ...) \
+ class IPDL_TEST_CLASS_NAME_(actorname, ##__VA_ARGS__) \
+ : public ::mozilla::_ipdltest::IPDLTestHelper { \
+ public: \
+ IPDL_TEST_CLASS_NAME_(actorname, ##__VA_ARGS__) \
+ () : mActor(new actorname##Parent) {} \
+ \
+ private: \
+ void TestBody() override; \
+ const char* GetName() override { return sName; }; \
+ actorname##Parent* GetActor() override { return mActor; }; \
+ \
+ RefPtr<actorname##Parent> mActor; \
+ static const char* sName; \
+ }; \
+ const char* IPDL_TEST_CLASS_NAME_(actorname, ##__VA_ARGS__)::sName = \
+ ::mozilla::_ipdltest::RegisterAllocChildActor( \
+ #actorname, []() -> ::mozilla::ipc::IToplevelProtocol* { \
+ return new actorname##Child; \
});
-#define IPDL_TEST_DECL_(testgroup, actorname, crossprocess) \
- TEST(testgroup, actorname) \
- { \
- IPDL_TEST_CLASS_NAME_(actorname) test; \
- test.TestWrapper(crossprocess); \
+#define IPDL_TEST_DECL_CROSSPROCESS_(actorname, ...) \
+ TEST(IPDLTest_CrossProcess, actorname##__VA_ARGS__) \
+ { \
+ IPDL_TEST_CLASS_NAME_(actorname, ##__VA_ARGS__) test; \
+ test.TestWrapper(true); \
}
-#define IPDL_TEST_BODY_SEGUE_(actorname) \
- void IPDL_TEST_CLASS_NAME_(actorname)::TestBody()
+#define IPDL_TEST_DECL_CROSSTHREAD_(actorname, ...) \
+ TEST(IPDLTest_CrossThread, actorname##__VA_ARGS__) \
+ { \
+ IPDL_TEST_CLASS_NAME_(actorname, ##__VA_ARGS__) test; \
+ test.TestWrapper(false); \
+ }
+
+#define IPDL_TEST_DECL_ANY_(actorname, ...) \
+ IPDL_TEST_DECL_CROSSPROCESS_(actorname, ##__VA_ARGS__) \
+ IPDL_TEST_DECL_CROSSTHREAD_(actorname, ##__VA_ARGS__)
+
+#define IPDL_TEST_BODY_SEGUE_(actorname, ...) \
+ void IPDL_TEST_CLASS_NAME_(actorname, ##__VA_ARGS__)::TestBody()
-// Declare a basic IPDL unit test which will be run in both both cross-thread
-// and cross-process configurations. The actor `actorname` will be instantiated
-// by default-constructing the parent & child actors in the relevant processes,
-// and the test block will be executed, with `mActor` being a pointer to the
-// parent actor. The test is asynchronous, and will end when the IPDL connection
-// between the created actors is destroyed.
+// Declare an IPDL unit test. The `mode` should be set to either `CROSSTHREAD`,
+// `CROSSPROCESS`, or `ANY` to run in the selected configuration(s). The actor
+// `actorname` will be instantiated by default-constructing the parent & child
+// actors in the relevant processes, and the test block will be executed, with
+// `mActor` being a pointer to the parent actor. The test is asynchronous, and
+// will end when the IPDL connection between the created actors is destroyed.
+// `aCrossProcess` will indicate whether the test is running cross-process
+// (true) or cross-thread (false).
+//
+// You can optionally pass a single additional argument which provides a
+// `testname`, which will be appended to `actorname` as the full GTest test
+// name. It should be of the form usually passed to the `TEST` gtest macro (an
+// identifier).
//
// GTest assertions fired in the child process will be relayed to the parent
// process, and should generally function correctly.
-#define IPDL_TEST(actorname) \
- IPDL_TEST_HEAD_(actorname) \
- IPDL_TEST_DECL_(IPDLTest_CrossProcess, actorname, true) \
- IPDL_TEST_DECL_(IPDLTest_CrossThread, actorname, false) \
- IPDL_TEST_BODY_SEGUE_(actorname)
+#define IPDL_TEST_ON(mode, actorname, ...) \
+ IPDL_TEST_HEAD_(actorname, ##__VA_ARGS__) \
+ IPDL_TEST_DECL_##mode##_(actorname, ##__VA_ARGS__) \
+ IPDL_TEST_BODY_SEGUE_(actorname, ##__VA_ARGS__)
+
+// Declare an IPDL unit test that will run in both cross-thread and
+// cross-process configurations. See the documentation of IPDL_TEST_ON for more
+// info.
+#define IPDL_TEST(actorname, ...) IPDL_TEST_ON(ANY, actorname, ##__VA_ARGS__)
} // namespace mozilla::_ipdltest
diff --git a/ipc/ipdl/test/gtest/PTestAsyncReturns.ipdl b/ipc/ipdl/test/gtest/PTestAsyncReturns.ipdl
new file mode 100644
index 0000000000..5cae489b4a
--- /dev/null
+++ b/ipc/ipdl/test/gtest/PTestAsyncReturns.ipdl
@@ -0,0 +1,19 @@
+/* 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/. */
+
+namespace mozilla {
+namespace _ipdltest {
+
+[ChildProc=any, ChildImpl=virtual, ParentImpl=virtual]
+protocol PTestAsyncReturns {
+child:
+ async Ping() returns (bool one);
+ async NoReturn() returns (bool unused);
+
+parent:
+ async Pong() returns (uint32_t param1, uint32_t param2);
+};
+
+} // namespace mozilla
+} // namespace _ipdltest
diff --git a/ipc/ipdl/test/gtest/PTestCancel.ipdl b/ipc/ipdl/test/gtest/PTestCancel.ipdl
new file mode 100644
index 0000000000..b0af04bae7
--- /dev/null
+++ b/ipc/ipdl/test/gtest/PTestCancel.ipdl
@@ -0,0 +1,39 @@
+/* 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/. */
+
+namespace mozilla {
+namespace _ipdltest {
+
+[NestedUpTo=inside_sync, ChildProc=any, ChildImpl=virtual, ParentImpl=virtual]
+sync protocol PTestCancel
+{
+ // Immediate Cancel: child sync function cancels immediately, both ends check after cancellation.
+child:
+ [Nested=inside_sync] sync ImmediateCancel();
+
+
+ // Nested Cancel: child nested sync function cancels
+child:
+ async StartNestedCancel();
+ [Nested=inside_sync] sync NestedCancel();
+parent:
+ [Nested=inside_sync] sync CallNestedCancel();
+
+
+ // Nested Cancel Parent: parent nested sync function cancels
+child:
+ [Nested=inside_sync] sync StartNestedCancelParent();
+parent:
+ [Nested=inside_sync] sync NestedCancelParent();
+
+
+// Common functions to check that sync messages still work.
+child:
+ [Nested=inside_sync] sync CheckChild() returns (uint32_t reply);
+parent:
+ [Nested=inside_sync] sync CheckParent() returns (uint32_t reply);
+};
+
+} // namespace _ipdltest
+} // namespace mozilla
diff --git a/ipc/ipdl/test/gtest/PTestDataStructures.ipdl b/ipc/ipdl/test/gtest/PTestDataStructures.ipdl
new file mode 100644
index 0000000000..7b2bdd3ced
--- /dev/null
+++ b/ipc/ipdl/test/gtest/PTestDataStructures.ipdl
@@ -0,0 +1,106 @@
+include protocol PTestDataStructuresSub;
+include PTestDataStructuresCommon;
+
+include "mozilla/GfxMessageUtils.h";
+
+namespace mozilla {
+namespace _ipdltest {
+
+[ChildProc=any, ChildImpl=virtual, ParentImpl=virtual]
+sync protocol PTestDataStructures {
+ manages PTestDataStructuresSub;
+
+child:
+ async PTestDataStructuresSub(int i);
+
+ async Start();
+
+parent:
+ async __delete__();
+
+ sync TestArrayOfInt(int[] i1)
+ returns (int[] o1);
+
+ sync TestArrayOfActor(PTestDataStructuresSub[] i1)
+ returns (PTestDataStructuresSub[] o1);
+
+ sync TestUnion(IntDouble i1,
+ IntDouble i2)
+ returns (IntDouble o1,
+ IntDouble o2);
+
+ sync TestArrayOfUnion(IntDouble[] i1)
+ returns (IntDouble[] o1);
+
+ sync TestUnionWithArray(IntDoubleArrays i1,
+ IntDoubleArrays i2,
+ IntDoubleArrays i3)
+ returns (IntDoubleArrays o1,
+ IntDoubleArrays o2,
+ IntDoubleArrays o3);
+
+ sync TestArrayOfUnionWithArray(IntDoubleArrays[] i1)
+ returns (IntDoubleArrays[] o1);
+
+ sync TestStructWithActor(ActorWrapper a1)
+ returns (ActorWrapper o1);
+
+ sync TestUnionWithActors(Actors i1,
+ Actors i2,
+ Actors i3)
+ returns (Actors o1,
+ Actors o2,
+ Actors o3);
+
+ sync TestArrayOfUnionWithActors(Actors[] i1)
+ returns (Actors[] o1);
+
+ sync TestUnions(Unions i1,
+ Unions i2,
+ Unions i3,
+ Unions i4)
+ returns (Unions o1,
+ Unions o2,
+ Unions o3,
+ Unions o4);
+
+ sync TestArrayOfUnions(Unions[] i1)
+ returns (Unions[] o1);
+
+ sync TestStruct(SIntDouble i)
+ returns (SIntDouble o);
+
+ sync TestStructWithArrays(SIntDoubleArrays i)
+ returns (SIntDoubleArrays o);
+
+ sync TestStructWithActors(SActors i)
+ returns (SActors o);
+
+ sync TestStructs(Structs i)
+ returns (Structs o);
+
+ sync TestUnionWithStructs(WithStructs i1,
+ WithStructs i2,
+ WithStructs i3,
+ WithStructs i4,
+ WithStructs i5)
+ returns (WithStructs o1,
+ WithStructs o2,
+ WithStructs o3,
+ WithStructs o4,
+ WithStructs o5);
+
+ sync TestStructWithUnions(WithUnions i)
+ returns (WithUnions o);
+
+ sync TestUnionWithCxx(Op[] ops);
+
+ // test that the ParamTraits<nsTArray>::Read() workaround for
+ // nsTArray's incorrect memmove() semantics works properly
+ // (nsIntRegion isn't memmove()able)
+ sync TestNsIntRegion(nsIntRegion[] ops);
+};
+
+} // namespace _ipdltest
+} // namespace mozilla
+
diff --git a/ipc/ipdl/test/gtest/PTestDataStructuresCommon.ipdlh b/ipc/ipdl/test/gtest/PTestDataStructuresCommon.ipdlh
new file mode 100644
index 0000000000..36549cc2c6
--- /dev/null
+++ b/ipc/ipdl/test/gtest/PTestDataStructuresCommon.ipdlh
@@ -0,0 +1,107 @@
+include protocol PTestDataStructuresSub;
+
+using struct mozilla::null_t from "mozilla/ipc/IPCCore.h";
+using nsIntRegion from "nsRegion.h";
+
+namespace mozilla {
+namespace _foo {
+
+union IntDouble {
+ int;
+ double;
+};
+
+struct SIntDouble {
+ int i;
+ double d;
+};
+
+union IntDoubleArrays {
+ int;
+ int[];
+ double[];
+};
+
+struct SIntDoubleArrays {
+ int i;
+ int[] ai;
+ double[] ad;
+};
+
+struct ActorWrapper {
+ nullable PTestDataStructuresSub actor;
+};
+
+union Actors {
+ int;
+ int[];
+ PTestDataStructuresSub[];
+};
+
+struct SActors {
+ int i;
+ int[] ai;
+ PTestDataStructuresSub[] ap;
+};
+
+union Unions {
+ int;
+ int[];
+ PTestDataStructuresSub[];
+ Actors[];
+};
+
+struct Structs {
+ int i;
+ int[] ai;
+ PTestDataStructuresSub[] ap;
+ SActors[] aa;
+};
+
+union WithStructs {
+ int;
+ int[];
+ PTestDataStructuresSub[];
+ SActors[];
+ Structs[];
+};
+
+struct WithUnions {
+ int i;
+ int[] ai;
+ PTestDataStructuresSub[] ap;
+ Actors[] aa;
+ Unions[] au;
+};
+
+struct CommonAttrs { bool dummy; };
+struct FooAttrs { int dummy; };
+struct BarAttrs { float dummy; };
+union SpecificAttrs {
+ FooAttrs;
+ BarAttrs;
+};
+struct Attrs {
+ CommonAttrs common;
+ SpecificAttrs specific;
+};
+struct SetAttrs {
+ PTestDataStructuresSub x;
+ Attrs attrs;
+};
+union Op { null_t; SetAttrs; };
+
+struct ShmemStruct {
+ int i;
+ Shmem mem;
+};
+
+union ShmemUnion {
+ int;
+ Shmem;
+};
+
+struct Empty { };
+
+} // namespace _foo
+} // namespace mozilla
diff --git a/ipc/ipdl/test/gtest/PTestDataStructuresSub.ipdl b/ipc/ipdl/test/gtest/PTestDataStructuresSub.ipdl
new file mode 100644
index 0000000000..f9f7d69411
--- /dev/null
+++ b/ipc/ipdl/test/gtest/PTestDataStructuresSub.ipdl
@@ -0,0 +1,15 @@
+include protocol PTestDataStructures;
+
+namespace mozilla {
+namespace _ipdltest {
+
+[ChildProc=any, ChildImpl=virtual, ParentImpl=virtual]
+async protocol PTestDataStructuresSub {
+ manager PTestDataStructures;
+
+parent:
+ async __delete__();
+};
+
+} // namespace _ipdltest
+} // namespace mozilla
diff --git a/ipc/ipdl/test/gtest/PTestDescendant.ipdl b/ipc/ipdl/test/gtest/PTestDescendant.ipdl
new file mode 100644
index 0000000000..b8524babab
--- /dev/null
+++ b/ipc/ipdl/test/gtest/PTestDescendant.ipdl
@@ -0,0 +1,22 @@
+include protocol PTestDescendantSub;
+include protocol PTestDescendantSubsub;
+
+namespace mozilla {
+namespace _ipdltest {
+
+[ChildProc=any, ChildImpl=virtual, ParentImpl=virtual]
+async protocol PTestDescendant {
+ manages PTestDescendantSub;
+child:
+ async PTestDescendantSub(nullable PTestDescendantSubsub dummy);
+
+ async Test(PTestDescendantSubsub a);
+
+ async __delete__();
+
+parent:
+ async Ok(PTestDescendantSubsub a);
+};
+
+}
+}
diff --git a/ipc/ipdl/test/gtest/PTestDescendantSub.ipdl b/ipc/ipdl/test/gtest/PTestDescendantSub.ipdl
new file mode 100644
index 0000000000..dd76801a43
--- /dev/null
+++ b/ipc/ipdl/test/gtest/PTestDescendantSub.ipdl
@@ -0,0 +1,19 @@
+include protocol PTestDescendant;
+include protocol PTestDescendantSubsub;
+
+namespace mozilla {
+namespace _ipdltest {
+
+[ChildProc=any, ChildImpl=virtual, ParentImpl=virtual]
+async protocol PTestDescendantSub {
+ manager PTestDescendant;
+ manages PTestDescendantSubsub;
+
+child:
+ async __delete__();
+
+ async PTestDescendantSubsub();
+};
+
+}
+}
diff --git a/ipc/ipdl/test/gtest/PTestDescendantSubsub.ipdl b/ipc/ipdl/test/gtest/PTestDescendantSubsub.ipdl
new file mode 100644
index 0000000000..a2fac12d72
--- /dev/null
+++ b/ipc/ipdl/test/gtest/PTestDescendantSubsub.ipdl
@@ -0,0 +1,14 @@
+include protocol PTestDescendantSub;
+
+namespace mozilla {
+namespace _ipdltest {
+
+[ChildProc=any, ChildImpl=virtual, ParentImpl=virtual]
+async protocol PTestDescendantSubsub {
+ manager PTestDescendantSub;
+child:
+ async __delete__();
+};
+
+}
+}
diff --git a/ipc/ipdl/test/gtest/PTestEndpointOpens.ipdl b/ipc/ipdl/test/gtest/PTestEndpointOpens.ipdl
new file mode 100644
index 0000000000..0ee1759b7f
--- /dev/null
+++ b/ipc/ipdl/test/gtest/PTestEndpointOpens.ipdl
@@ -0,0 +1,22 @@
+/* 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 protocol PTestEndpointOpensOpened;
+
+namespace mozilla {
+namespace _ipdltest {
+
+[ChildProc=any, ChildImpl=virtual, ParentImpl=virtual]
+protocol PTestEndpointOpens {
+child:
+ async Start();
+
+parent:
+ async StartSubprotocol(Endpoint<PTestEndpointOpensOpenedParent> endpoint);
+
+ async __delete__();
+};
+
+} // namespace _ipdltest
+} // namespace mozilla
diff --git a/ipc/ipdl/test/gtest/PTestEndpointOpensOpened.ipdl b/ipc/ipdl/test/gtest/PTestEndpointOpensOpened.ipdl
new file mode 100644
index 0000000000..1baa662235
--- /dev/null
+++ b/ipc/ipdl/test/gtest/PTestEndpointOpensOpened.ipdl
@@ -0,0 +1,22 @@
+/* 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/. */
+
+namespace mozilla {
+namespace _ipdltest {
+
+// (Opens protocols can have different semantics than the endpoints
+// that opened them)
+[ChildProc=any, ChildImpl=virtual, ParentImpl=virtual]
+sync protocol PTestEndpointOpensOpened {
+child:
+ async Hi();
+
+parent:
+ async Hello();
+ sync HelloSync();
+ async __delete__();
+};
+
+} // namespace _ipdltest
+} // namespace mozilla
diff --git a/ipc/ipdl/test/gtest/PTestHangs.ipdl b/ipc/ipdl/test/gtest/PTestHangs.ipdl
new file mode 100644
index 0000000000..7df791cee6
--- /dev/null
+++ b/ipc/ipdl/test/gtest/PTestHangs.ipdl
@@ -0,0 +1,20 @@
+/* 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/. */
+
+[MoveOnly] using mozilla::CrossProcessSemaphoreHandle from "mozilla/ipc/CrossProcessSemaphore.h";
+
+namespace mozilla {
+namespace _ipdltest {
+
+[ChildProc=any, ChildImpl=virtual, ParentImpl=virtual]
+sync protocol PTestHangs {
+parent:
+ sync Hang(uint32_t hangMode, CrossProcessSemaphoreHandle timeout);
+child:
+ async Start(uint32_t hangMode)
+ returns (bool detectedHang);
+};
+
+} // namespace _ipdltest
+} // namespace mozilla
diff --git a/ipc/ipdl/test/gtest/PTestJSON.ipdl b/ipc/ipdl/test/gtest/PTestJSON.ipdl
new file mode 100644
index 0000000000..2486e85378
--- /dev/null
+++ b/ipc/ipdl/test/gtest/PTestJSON.ipdl
@@ -0,0 +1,43 @@
+include protocol PTestJSONHandle;
+
+using struct mozilla::void_t from "mozilla/ipc/IPCCore.h";
+using struct mozilla::null_t from "mozilla/ipc/IPCCore.h";
+
+namespace mozilla {
+namespace _ipdltest {
+
+[Comparable]
+struct KeyValue {
+ nsString key;
+ JSONVariant value;
+};
+
+[Comparable]
+union JSONVariant {
+ void_t;
+ null_t;
+ bool;
+ int;
+ double;
+ nsString;
+ PTestJSONHandle;
+ KeyValue[];
+ JSONVariant[];
+};
+
+[ChildProc=any, ChildImpl=virtual, ParentImpl=virtual]
+sync protocol PTestJSON {
+ manages PTestJSONHandle;
+
+child:
+ async Start();
+
+parent:
+ async PTestJSONHandle();
+ sync Test(JSONVariant i)
+ returns (JSONVariant o);
+ async __delete__();
+};
+
+} // namespace mozilla
+} // namespace _ipdltest
diff --git a/ipc/ipdl/test/gtest/PTestJSONHandle.ipdl b/ipc/ipdl/test/gtest/PTestJSONHandle.ipdl
new file mode 100644
index 0000000000..81bbb913b4
--- /dev/null
+++ b/ipc/ipdl/test/gtest/PTestJSONHandle.ipdl
@@ -0,0 +1,15 @@
+include protocol PTestJSON;
+
+namespace mozilla {
+namespace _ipdltest {
+
+[ChildProc=any, ChildImpl=virtual, ParentImpl=virtual]
+protocol PTestJSONHandle {
+ manager PTestJSON;
+
+child:
+ async __delete__();
+};
+
+} // namespace mozilla
+} // namespace _ipdltest
diff --git a/ipc/ipdl/test/gtest/PTestManyChildAllocs.ipdl b/ipc/ipdl/test/gtest/PTestManyChildAllocs.ipdl
new file mode 100644
index 0000000000..149e5aefab
--- /dev/null
+++ b/ipc/ipdl/test/gtest/PTestManyChildAllocs.ipdl
@@ -0,0 +1,18 @@
+include protocol PTestManyChildAllocsSub;
+
+namespace mozilla {
+namespace _ipdltest {
+
+[ChildProc=any, ChildImpl=virtual, ParentImpl=virtual]
+protocol PTestManyChildAllocs {
+ manages PTestManyChildAllocsSub;
+child:
+ async Go(); // start allocating
+
+parent:
+ async Done();
+ async PTestManyChildAllocsSub();
+};
+
+} // namespace _ipdltest
+} // namespace mozilla
diff --git a/ipc/ipdl/test/gtest/PTestManyChildAllocsSub.ipdl b/ipc/ipdl/test/gtest/PTestManyChildAllocsSub.ipdl
new file mode 100644
index 0000000000..4a34af2e52
--- /dev/null
+++ b/ipc/ipdl/test/gtest/PTestManyChildAllocsSub.ipdl
@@ -0,0 +1,18 @@
+include protocol PTestManyChildAllocs;
+
+namespace mozilla {
+namespace _ipdltest {
+
+[ChildProc=any, ChildImpl=virtual, ParentImpl=virtual]
+protocol PTestManyChildAllocsSub {
+ manager PTestManyChildAllocs;
+
+child:
+ async __delete__();
+
+parent:
+ async Hello();
+};
+
+} // namespace _ipdltest
+} // namespace mozilla
diff --git a/ipc/ipdl/test/gtest/PTestMostNested.ipdl b/ipc/ipdl/test/gtest/PTestMostNested.ipdl
new file mode 100644
index 0000000000..2c6750137c
--- /dev/null
+++ b/ipc/ipdl/test/gtest/PTestMostNested.ipdl
@@ -0,0 +1,23 @@
+/* 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/. */
+
+namespace mozilla {
+namespace _ipdltest {
+
+[ChildProc=any, NestedUpTo=inside_cpow, ChildImpl=virtual, ParentImpl=virtual]
+sync protocol PTestMostNested
+{
+parent:
+ [Nested=inside_cpow] async Msg1();
+ [Nested=inside_sync] sync Msg2();
+ [Nested=inside_cpow] async Msg3();
+ [Nested=inside_cpow] sync Msg4();
+
+child:
+ async Start();
+ [Nested=inside_sync] sync StartInner();
+};
+
+}
+}
diff --git a/ipc/ipdl/test/gtest/PTestMultiMgrs.ipdl b/ipc/ipdl/test/gtest/PTestMultiMgrs.ipdl
new file mode 100644
index 0000000000..80de57459d
--- /dev/null
+++ b/ipc/ipdl/test/gtest/PTestMultiMgrs.ipdl
@@ -0,0 +1,23 @@
+include protocol PTestMultiMgrsLeft;
+include protocol PTestMultiMgrsRight;
+
+namespace mozilla {
+namespace _ipdltest {
+
+[ChildProc=any, ChildImpl=virtual, ParentImpl=virtual]
+protocol PTestMultiMgrs {
+ manages PTestMultiMgrsLeft;
+ manages PTestMultiMgrsRight;
+
+parent:
+ async OK();
+
+child:
+ async PTestMultiMgrsLeft();
+ async PTestMultiMgrsRight();
+ async Check();
+ async __delete__();
+};
+
+} // namespace _ipdltest
+} // namespace mozilla
diff --git a/ipc/ipdl/test/gtest/PTestMultiMgrsBottom.ipdl b/ipc/ipdl/test/gtest/PTestMultiMgrsBottom.ipdl
new file mode 100644
index 0000000000..03bbc7f886
--- /dev/null
+++ b/ipc/ipdl/test/gtest/PTestMultiMgrsBottom.ipdl
@@ -0,0 +1,16 @@
+include protocol PTestMultiMgrsLeft;
+include protocol PTestMultiMgrsRight;
+
+namespace mozilla {
+namespace _ipdltest {
+
+[ChildProc=any, ChildImpl=virtual, ParentImpl=virtual]
+protocol PTestMultiMgrsBottom {
+ manager PTestMultiMgrsLeft or PTestMultiMgrsRight;
+
+child:
+ async __delete__();
+};
+
+} // namespace _ipdltest
+} // namespace mozilla
diff --git a/ipc/ipdl/test/gtest/PTestMultiMgrsLeft.ipdl b/ipc/ipdl/test/gtest/PTestMultiMgrsLeft.ipdl
new file mode 100644
index 0000000000..ee62fc3487
--- /dev/null
+++ b/ipc/ipdl/test/gtest/PTestMultiMgrsLeft.ipdl
@@ -0,0 +1,19 @@
+include protocol PTestMultiMgrs;
+include protocol PTestMultiMgrsBottom;
+
+namespace mozilla {
+namespace _ipdltest {
+
+[ChildProc=any, ChildImpl=virtual, ParentImpl=virtual]
+protocol PTestMultiMgrsLeft {
+ manager PTestMultiMgrs;
+
+ manages PTestMultiMgrsBottom;
+
+child:
+ async PTestMultiMgrsBottom();
+ async __delete__();
+};
+
+} // namespace _ipdltest
+} // namespace mozilla
diff --git a/ipc/ipdl/test/gtest/PTestMultiMgrsRight.ipdl b/ipc/ipdl/test/gtest/PTestMultiMgrsRight.ipdl
new file mode 100644
index 0000000000..202f60247e
--- /dev/null
+++ b/ipc/ipdl/test/gtest/PTestMultiMgrsRight.ipdl
@@ -0,0 +1,19 @@
+include protocol PTestMultiMgrs;
+include protocol PTestMultiMgrsBottom;
+
+namespace mozilla {
+namespace _ipdltest {
+
+[ChildProc=any, ChildImpl=virtual, ParentImpl=virtual]
+protocol PTestMultiMgrsRight {
+ manager PTestMultiMgrs;
+
+ manages PTestMultiMgrsBottom;
+
+child:
+ async PTestMultiMgrsBottom();
+ async __delete__();
+};
+
+} // namespace _ipdltest
+} // namespace mozilla
diff --git a/ipc/ipdl/test/gtest/PTestSelfManage.ipdl b/ipc/ipdl/test/gtest/PTestSelfManage.ipdl
new file mode 100644
index 0000000000..e7dc077808
--- /dev/null
+++ b/ipc/ipdl/test/gtest/PTestSelfManage.ipdl
@@ -0,0 +1,17 @@
+include protocol PTestSelfManageRoot;
+
+namespace mozilla {
+namespace _ipdltest {
+
+[ChildProc=any, ChildImpl=virtual, ParentImpl=virtual]
+protocol PTestSelfManage {
+ manager PTestSelfManageRoot or PTestSelfManage;
+ manages PTestSelfManage;
+
+child:
+ async PTestSelfManage();
+ async __delete__();
+};
+
+} // namespace mozilla
+} // namespace _ipdltest
diff --git a/ipc/ipdl/test/gtest/PTestSelfManageRoot.ipdl b/ipc/ipdl/test/gtest/PTestSelfManageRoot.ipdl
new file mode 100644
index 0000000000..37e8218720
--- /dev/null
+++ b/ipc/ipdl/test/gtest/PTestSelfManageRoot.ipdl
@@ -0,0 +1,16 @@
+include protocol PTestSelfManage;
+
+namespace mozilla {
+namespace _ipdltest {
+
+[ChildProc=any, ChildImpl=virtual, ParentImpl=virtual]
+protocol PTestSelfManageRoot {
+ manages PTestSelfManage;
+
+child:
+ async PTestSelfManage();
+ async __delete__();
+};
+
+} // namespace mozilla
+} // namespace _ipdltest
diff --git a/ipc/ipdl/test/gtest/PTestShmem.ipdl b/ipc/ipdl/test/gtest/PTestShmem.ipdl
new file mode 100644
index 0000000000..33eeabffdf
--- /dev/null
+++ b/ipc/ipdl/test/gtest/PTestShmem.ipdl
@@ -0,0 +1,15 @@
+namespace mozilla {
+namespace _ipdltest {
+
+[ChildProc=any, ChildImpl=virtual, ParentImpl=virtual]
+protocol PTestShmem {
+child:
+ async Give(Shmem mem, Shmem unsafe, uint32_t expectedSize);
+
+parent:
+ async Take(Shmem mem, Shmem unsafe, uint32_t expectedSize);
+ async __delete__();
+};
+
+}
+}
diff --git a/ipc/ipdl/test/gtest/PTestSyncError.ipdl b/ipc/ipdl/test/gtest/PTestSyncError.ipdl
new file mode 100644
index 0000000000..e549bde919
--- /dev/null
+++ b/ipc/ipdl/test/gtest/PTestSyncError.ipdl
@@ -0,0 +1,16 @@
+namespace mozilla {
+namespace _ipdltest {
+
+[ChildProc=any, ChildImpl=virtual, ParentImpl=virtual]
+sync protocol PTestSyncError {
+
+child:
+ async Start();
+
+parent:
+ sync Error();
+ async __delete__();
+};
+
+} // namespace mozilla
+} // namespace _ipdltest
diff --git a/ipc/ipdl/test/gtest/PTestUniquePtrIPC.ipdl b/ipc/ipdl/test/gtest/PTestUniquePtrIPC.ipdl
new file mode 100644
index 0000000000..b55d8f19d1
--- /dev/null
+++ b/ipc/ipdl/test/gtest/PTestUniquePtrIPC.ipdl
@@ -0,0 +1,17 @@
+namespace mozilla {
+namespace _ipdltest {
+
+struct DummyStruct {
+ int x;
+};
+
+[ChildProc=any, ChildImpl=virtual, ParentImpl=virtual]
+protocol PTestUniquePtrIPC {
+child:
+ async TestMessage(UniquePtr<int> a1, UniquePtr<DummyStruct> a2,
+ DummyStruct a3, UniquePtr<int> a4);
+ async TestSendReference(UniquePtr<DummyStruct> a);
+};
+
+} // namespace _ipdltest
+} // namespace mozilla
diff --git a/ipc/ipdl/test/gtest/PTestUrgency.ipdl b/ipc/ipdl/test/gtest/PTestUrgency.ipdl
new file mode 100644
index 0000000000..ee9b44b543
--- /dev/null
+++ b/ipc/ipdl/test/gtest/PTestUrgency.ipdl
@@ -0,0 +1,20 @@
+namespace mozilla {
+namespace _ipdltest {
+
+[ChildProc=any, NestedUpTo=inside_cpow, ChildImpl=virtual, ParentImpl=virtual]
+sync protocol PTestUrgency
+{
+parent:
+ [Nested=inside_sync] sync Test1() returns (uint32_t result);
+ async Test2();
+ sync Test3() returns (uint32_t result);
+ sync FinalTest_Begin();
+
+child:
+ async Start();
+ [Nested=inside_sync] sync Reply1() returns (uint32_t result);
+ [Nested=inside_sync] sync Reply2() returns (uint32_t result);
+};
+
+} // namespace _ipdltest
+} // namespace mozilla
diff --git a/ipc/ipdl/test/gtest/TestAsyncReturns.cpp b/ipc/ipdl/test/gtest/TestAsyncReturns.cpp
new file mode 100644
index 0000000000..960a2954db
--- /dev/null
+++ b/ipc/ipdl/test/gtest/TestAsyncReturns.cpp
@@ -0,0 +1,77 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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/. */
+
+/*
+ * These tests ensure that async function return values work as expected.
+ */
+
+#include "gtest/gtest.h"
+
+#include "mozilla/_ipdltest/IPDLUnitTest.h"
+#include "mozilla/_ipdltest/PTestAsyncReturnsChild.h"
+#include "mozilla/_ipdltest/PTestAsyncReturnsParent.h"
+
+using namespace mozilla::ipc;
+
+namespace mozilla::_ipdltest {
+
+static uint32_t sMagic1 = 0x105b59fb;
+static uint32_t sMagic2 = 0x09b6f5e3;
+
+class TestAsyncReturnsChild : public PTestAsyncReturnsChild {
+ NS_INLINE_DECL_THREADSAFE_REFCOUNTING(TestAsyncReturnsChild, override)
+ private:
+ IPCResult RecvPing(PingResolver&& resolve) final override {
+ SendPong(
+ [resolve](const std::tuple<uint32_t, uint32_t>& aParam) {
+ EXPECT_EQ(std::get<0>(aParam), sMagic1);
+ EXPECT_EQ(std::get<1>(aParam), sMagic2);
+ resolve(true);
+ },
+ [](ResponseRejectReason&& aReason) { FAIL() << "sending Pong"; });
+ return IPC_OK();
+ }
+
+ IPCResult RecvNoReturn(NoReturnResolver&& resolve) final override {
+ // Not calling `resolve` intentionally
+ return IPC_OK();
+ }
+
+ ~TestAsyncReturnsChild() = default;
+};
+
+class TestAsyncReturnsParent : public PTestAsyncReturnsParent {
+ NS_INLINE_DECL_THREADSAFE_REFCOUNTING(TestAsyncReturnsParent, override)
+ private:
+ IPCResult RecvPong(PongResolver&& resolve) final override {
+ resolve(std::tuple<const uint32_t&, const uint32_t&>(sMagic1, sMagic2));
+ return IPC_OK();
+ }
+
+ ~TestAsyncReturnsParent() = default;
+};
+
+IPDL_TEST(TestAsyncReturns, NoReturn) {
+ mActor->SendNoReturn(
+ [](bool unused) { FAIL() << "resolve handler should not be called"; },
+ [=](ResponseRejectReason&& aReason) {
+ if (aReason != ResponseRejectReason::ResolverDestroyed) {
+ FAIL() << "reject with wrong reason";
+ }
+ mActor->Close();
+ });
+}
+
+IPDL_TEST(TestAsyncReturns, PingPong) {
+ mActor->SendPing(
+ [=](bool one) {
+ EXPECT_TRUE(one);
+ mActor->Close();
+ },
+ [](ResponseRejectReason&& aReason) { FAIL() << "sending Ping"; });
+}
+
+} // namespace mozilla::_ipdltest
diff --git a/ipc/ipdl/test/gtest/TestCancel.cpp b/ipc/ipdl/test/gtest/TestCancel.cpp
new file mode 100644
index 0000000000..79f31751dd
--- /dev/null
+++ b/ipc/ipdl/test/gtest/TestCancel.cpp
@@ -0,0 +1,126 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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/. */
+
+/*
+ * Test that IPC channel transaction cancellation (which applies to nested sync
+ * messages) works as expected.
+ */
+
+#include "gtest/gtest.h"
+
+#include "mozilla/_ipdltest/IPDLUnitTest.h"
+#include "mozilla/_ipdltest/PTestCancelChild.h"
+#include "mozilla/_ipdltest/PTestCancelParent.h"
+
+using namespace mozilla::ipc;
+
+namespace mozilla::_ipdltest {
+
+class TestCancelParent : public PTestCancelParent {
+ NS_INLINE_DECL_THREADSAFE_REFCOUNTING(TestCancelParent, override)
+ private:
+ IPCResult RecvCallNestedCancel() final override {
+ EXPECT_FALSE(SendNestedCancel()) << "SendNestedCancel should fail";
+ EXPECT_EQ(GetIPCChannel()->LastSendError(),
+ SyncSendError::CancelledAfterSend)
+ << "SendNestedCancel should be cancelled";
+
+ return IPC_OK();
+ }
+
+ IPCResult RecvNestedCancelParent() final override {
+ GetIPCChannel()->CancelCurrentTransaction();
+ return IPC_OK();
+ }
+
+ IPCResult RecvCheckParent(uint32_t* reply) final override {
+ *reply = 42;
+ return IPC_OK();
+ }
+
+ ~TestCancelParent() = default;
+};
+
+class TestCancelChild : public PTestCancelChild {
+ NS_INLINE_DECL_THREADSAFE_REFCOUNTING(TestCancelChild, override)
+ private:
+ IPCResult RecvImmediateCancel() final override {
+ GetIPCChannel()->CancelCurrentTransaction();
+
+ uint32_t value = 0;
+ EXPECT_FALSE(SendCheckParent(&value)) << "channel should be closing";
+
+ return IPC_OK();
+ }
+
+ IPCResult RecvStartNestedCancel() final override {
+ EXPECT_FALSE(SendCallNestedCancel());
+
+ Close();
+ return IPC_OK();
+ }
+
+ IPCResult RecvNestedCancel() final override {
+ GetIPCChannel()->CancelCurrentTransaction();
+
+ uint32_t value = 0;
+ EXPECT_TRUE(SendCheckParent(&value)) << "channel should be closing";
+
+ return IPC_OK();
+ }
+
+ IPCResult RecvStartNestedCancelParent() final override {
+ EXPECT_FALSE(SendNestedCancelParent())
+ << "SendNestedCancelParent should fail";
+ EXPECT_EQ(GetIPCChannel()->LastSendError(),
+ SyncSendError::CancelledAfterSend)
+ << "SendNestedCancelParent should be cancelled";
+
+ uint32_t value = 0;
+ EXPECT_FALSE(SendCheckParent(&value));
+
+ return IPC_OK();
+ }
+
+ IPCResult RecvCheckChild(uint32_t* reply) final override {
+ *reply = 42;
+ return IPC_OK();
+ }
+
+ ~TestCancelChild() = default;
+};
+
+// Nested sync messages can only be received on the main thread, so threaded
+// tests can't be run (the child actor won't be on the main thread).
+
+IPDL_TEST_ON(CROSSPROCESS, TestCancel, ImmediateCancel) {
+ EXPECT_FALSE(mActor->SendImmediateCancel()) << "should immediately cancel";
+ EXPECT_EQ(mActor->GetIPCChannel()->LastSendError(),
+ SyncSendError::CancelledAfterSend);
+
+ uint32_t value = 0;
+ EXPECT_TRUE(mActor->SendCheckChild(&value));
+ EXPECT_EQ(value, (uint32_t)42);
+
+ mActor->Close();
+}
+
+IPDL_TEST_ON(CROSSPROCESS, TestCancel, NestedCancel) {
+ EXPECT_TRUE(mActor->SendStartNestedCancel());
+}
+
+IPDL_TEST_ON(CROSSPROCESS, TestCancel, NestedCancelParent) {
+ EXPECT_FALSE(mActor->SendStartNestedCancelParent())
+ << "StartNestedCancelParent should be cancelled";
+
+ uint32_t value = 0;
+ EXPECT_TRUE(mActor->SendCheckChild(&value));
+ EXPECT_EQ(value, (uint32_t)42);
+
+ mActor->Close();
+}
+
+} // namespace mozilla::_ipdltest
diff --git a/ipc/ipdl/test/gtest/TestDataStructures.cpp b/ipc/ipdl/test/gtest/TestDataStructures.cpp
new file mode 100644
index 0000000000..b7f6a7ae95
--- /dev/null
+++ b/ipc/ipdl/test/gtest/TestDataStructures.cpp
@@ -0,0 +1,864 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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/. */
+
+/*
+ * Test many combinations of data structures (both in argument and return
+ * position) to ensure they are transmitted correctly.
+ */
+
+#include "gtest/gtest.h"
+
+#include "mozilla/_ipdltest/IPDLUnitTest.h"
+#include "mozilla/_ipdltest/PTestDataStructuresChild.h"
+#include "mozilla/_ipdltest/PTestDataStructuresParent.h"
+#include "mozilla/_ipdltest/PTestDataStructuresSubChild.h"
+#include "mozilla/_ipdltest/PTestDataStructuresSubParent.h"
+
+#include "mozilla/Unused.h"
+
+using namespace mozilla::ipc;
+
+using RegionArray = nsTArray<nsIntRegion>;
+
+namespace mozilla::_ipdltest {
+
+static const uint32_t nactors = 10;
+
+class TestDataStructuresSubParent : public PTestDataStructuresSubParent {
+ NS_INLINE_DECL_REFCOUNTING(TestDataStructuresSubParent, override)
+
+ public:
+ explicit TestDataStructuresSubParent(uint32_t i) : mI(i) {}
+ uint32_t mI;
+
+ private:
+ ~TestDataStructuresSubParent() = default;
+};
+
+class TestDataStructuresSubChild : public PTestDataStructuresSubChild {
+ NS_INLINE_DECL_REFCOUNTING(TestDataStructuresSubChild, override)
+
+ public:
+ explicit TestDataStructuresSubChild(uint32_t i) : mI(i) {}
+ uint32_t mI;
+
+ private:
+ ~TestDataStructuresSubChild() = default;
+};
+
+inline static TestDataStructuresSubParent& Cast(
+ PTestDataStructuresSubParent* a) {
+ return *static_cast<TestDataStructuresSubParent*>(a);
+}
+
+class TestDataStructuresParent : public PTestDataStructuresParent {
+ NS_INLINE_DECL_REFCOUNTING(TestDataStructuresParent, override)
+
+ public:
+ nsTArray<NotNull<
+ SideVariant<PTestDataStructuresSubParent*, PTestDataStructuresSubChild*>>>
+ kids;
+
+ private:
+ IPCResult RecvTestArrayOfInt(nsTArray<int>&& ia,
+ nsTArray<int>* oa) final override {
+ EXPECT_EQ(5u, ia.Length());
+ for (int i = 0; i < 5; ++i) EXPECT_EQ(i, ia[i]);
+
+ *oa = std::move(ia);
+
+ return IPC_OK();
+ }
+
+ IPCResult RecvTestArrayOfActor(
+ nsTArray<NotNull<PTestDataStructuresSubParent*>>&& i1,
+ nsTArray<NotNull<PTestDataStructuresSubParent*>>* o1) final override {
+ EXPECT_EQ(nactors, i1.Length());
+ for (uint32_t i = 0; i < i1.Length(); ++i) EXPECT_EQ(i, Cast(i1[i]).mI);
+ *o1 = std::move(i1);
+ return IPC_OK();
+ }
+
+ IPCResult RecvTestUnion(const IntDouble& i1, const IntDouble& i2,
+ IntDouble* o1, IntDouble* o2) final override {
+ EXPECT_EQ(42, i1.get_int());
+ EXPECT_EQ(4.0, i2.get_double());
+
+ *o1 = i1;
+ *o2 = i2;
+
+ return IPC_OK();
+ }
+
+ IPCResult RecvTestArrayOfUnion(nsTArray<IntDouble>&& i1,
+ nsTArray<IntDouble>* o1) final override {
+ EXPECT_EQ(4u, i1.Length());
+ EXPECT_EQ(1, i1[0].get_int());
+ EXPECT_EQ(2.0, i1[1].get_double());
+ EXPECT_EQ(3, i1[2].get_int());
+ EXPECT_EQ(4.0, i1[3].get_double());
+
+ *o1 = std::move(i1);
+
+ return IPC_OK();
+ }
+
+ IPCResult RecvTestUnionWithArray(const IntDoubleArrays& i1,
+ const IntDoubleArrays& i2,
+ const IntDoubleArrays& i3,
+ IntDoubleArrays* o1, IntDoubleArrays* o2,
+ IntDoubleArrays* o3) final override {
+ EXPECT_EQ(42, i1.get_int());
+
+ const nsTArray<int>& i2a = i2.get_ArrayOfint();
+ EXPECT_EQ(3u, i2a.Length());
+ EXPECT_EQ(1, i2a[0]);
+ EXPECT_EQ(2, i2a[1]);
+ EXPECT_EQ(3, i2a[2]);
+
+ const nsTArray<double>& i3a = i3.get_ArrayOfdouble();
+ EXPECT_EQ(3u, i3a.Length());
+ EXPECT_EQ(1.0, i3a[0]);
+ EXPECT_EQ(2.0, i3a[1]);
+ EXPECT_EQ(3.0, i3a[2]);
+
+ *o1 = i1;
+ *o2 = i2a;
+ *o3 = i3a;
+
+ return IPC_OK();
+ }
+
+ IPCResult RecvTestArrayOfUnionWithArray(
+ nsTArray<IntDoubleArrays>&& i1,
+ nsTArray<IntDoubleArrays>* o1) final override {
+ EXPECT_EQ(3u, i1.Length());
+
+ IntDoubleArrays id1(i1[0]);
+ EXPECT_EQ(42, id1.get_int());
+
+ nsTArray<int> i2a = i1[1].get_ArrayOfint().Clone();
+ EXPECT_EQ(3u, i2a.Length());
+ EXPECT_EQ(1, i2a[0]);
+ EXPECT_EQ(2, i2a[1]);
+ EXPECT_EQ(3, i2a[2]);
+
+ nsTArray<double> i3a = i1[2].get_ArrayOfdouble().Clone();
+ EXPECT_EQ(3u, i3a.Length());
+ EXPECT_EQ(1.0, i3a[0]);
+ EXPECT_EQ(2.0, i3a[1]);
+ EXPECT_EQ(3.0, i3a[2]);
+
+ o1->AppendElement(id1);
+ o1->AppendElement(IntDoubleArrays(i2a));
+ o1->AppendElement(IntDoubleArrays(i3a));
+
+ return IPC_OK();
+ }
+
+ IPCResult RecvTestStructWithActor(const ActorWrapper& i1,
+ ActorWrapper* o1) final override {
+ EXPECT_FALSE(i1.actor().IsChild()) << "child side should be empty";
+
+ EXPECT_EQ(i1.actor(), kids[0])
+ << "should have got back same actor on parent side";
+
+ o1->actor() = kids[0];
+ return IPC_OK();
+ }
+
+ IPCResult RecvTestUnionWithActors(const Actors& i1, const Actors& i2,
+ const Actors& i3, Actors* o1, Actors* o2,
+ Actors* o3) final override {
+ EXPECT_EQ(42, i1.get_int());
+
+ nsTArray<int> i2a = i2.get_ArrayOfint().Clone();
+ EXPECT_EQ(3u, i2a.Length());
+ EXPECT_EQ(1, i2a[0]);
+ EXPECT_EQ(2, i2a[1]);
+ EXPECT_EQ(3, i2a[2]);
+
+ const auto& a = i3.get_ArrayOfPTestDataStructuresSub();
+ EXPECT_EQ(a.Length(), kids.Length());
+ for (size_t i = 0; i < a.Length(); ++i) {
+ EXPECT_EQ(a[i], kids[i]);
+ }
+
+ *o1 = 42;
+ *o2 = i2a;
+ *o3 = kids.Clone();
+
+ return IPC_OK();
+ }
+
+ IPCResult RecvTestArrayOfUnionWithActors(
+ nsTArray<Actors>&& i1, nsTArray<Actors>* o1) final override {
+ EXPECT_EQ(3u, i1.Length());
+ EXPECT_EQ(42, i1[0].get_int());
+
+ const nsTArray<int>& i2a = i1[1].get_ArrayOfint();
+ EXPECT_EQ(3u, i2a.Length());
+ EXPECT_EQ(1, i2a[0]);
+ EXPECT_EQ(2, i2a[1]);
+ EXPECT_EQ(3, i2a[2]);
+
+ EXPECT_EQ(kids, i1[2].get_ArrayOfPTestDataStructuresSub());
+
+ *o1 = std::move(i1);
+
+ return IPC_OK();
+ }
+
+ IPCResult RecvTestUnions(const Unions& i1, const Unions& i2, const Unions& i3,
+ const Unions& i4, Unions* o1, Unions* o2, Unions* o3,
+ Unions* o4) final override {
+ EXPECT_EQ(42, i1.get_int());
+
+ const nsTArray<int>& i2a = i2.get_ArrayOfint();
+ EXPECT_EQ(3u, i2a.Length());
+ EXPECT_EQ(1, i2a[0]);
+ EXPECT_EQ(2, i2a[1]);
+ EXPECT_EQ(3, i2a[2]);
+
+ EXPECT_EQ(kids, i3.get_ArrayOfPTestDataStructuresSub());
+
+ const auto& i4a =
+ i4.get_ArrayOfActors()[0].get_ArrayOfPTestDataStructuresSub();
+ EXPECT_EQ(kids, i4a);
+
+ *o1 = i1;
+ *o2 = i2;
+ *o3 = i3;
+ *o4 = i4;
+
+ return IPC_OK();
+ }
+
+ IPCResult RecvTestArrayOfUnions(nsTArray<Unions>&& i1,
+ nsTArray<Unions>* o1) final override {
+ EXPECT_EQ(42, i1[0].get_int());
+
+ const nsTArray<int>& i2a = i1[1].get_ArrayOfint();
+ EXPECT_EQ(3u, i2a.Length());
+ EXPECT_EQ(1, i2a[0]);
+ EXPECT_EQ(2, i2a[1]);
+ EXPECT_EQ(3, i2a[2]);
+
+ EXPECT_EQ(kids, i1[2].get_ArrayOfPTestDataStructuresSub());
+
+ const auto& i4a =
+ i1[3].get_ArrayOfActors()[0].get_ArrayOfPTestDataStructuresSub();
+ EXPECT_EQ(kids, i4a);
+
+ *o1 = std::move(i1);
+
+ return IPC_OK();
+ }
+
+ IPCResult RecvTestStruct(const SIntDouble& i, SIntDouble* o) final override {
+ EXPECT_EQ(1, i.i());
+ EXPECT_EQ(2.0, i.d());
+ *o = i;
+ return IPC_OK();
+ }
+
+ IPCResult RecvTestStructWithArrays(const SIntDoubleArrays& i,
+ SIntDoubleArrays* o) final override {
+ nsTArray<int> ai;
+ ai.AppendElement(1);
+ ai.AppendElement(2);
+ ai.AppendElement(3);
+
+ nsTArray<double> ad;
+ ad.AppendElement(.5);
+ ad.AppendElement(1.0);
+ ad.AppendElement(2.0);
+
+ EXPECT_EQ(42, i.i());
+ EXPECT_EQ(ai, i.ai());
+ EXPECT_EQ(ad, i.ad());
+
+ *o = i;
+
+ return IPC_OK();
+ }
+
+ IPCResult RecvTestStructWithActors(const SActors& i,
+ SActors* o) final override {
+ nsTArray<int> ai;
+ ai.AppendElement(1);
+ ai.AppendElement(2);
+ ai.AppendElement(3);
+
+ EXPECT_EQ(42, i.i());
+ EXPECT_EQ(ai, i.ai());
+ EXPECT_EQ(kids, i.ap());
+
+ *o = i;
+
+ return IPC_OK();
+ }
+
+ IPCResult RecvTestStructs(const Structs& i, Structs* o) final override {
+ nsTArray<int> ai;
+ ai.AppendElement(1);
+ ai.AppendElement(2);
+ ai.AppendElement(3);
+
+ EXPECT_EQ(42, i.i());
+ EXPECT_EQ(ai, i.ai());
+ EXPECT_EQ(kids, i.ap());
+
+ const SActors& ia = i.aa()[0];
+ EXPECT_EQ(42, ia.i());
+ EXPECT_EQ(ai, ia.ai());
+ EXPECT_EQ(kids, ia.ap());
+
+ *o = i;
+
+ return IPC_OK();
+ }
+
+ IPCResult RecvTestUnionWithStructs(
+ const WithStructs& i1, const WithStructs& i2, const WithStructs& i3,
+ const WithStructs& i4, const WithStructs& i5, WithStructs* o1,
+ WithStructs* o2, WithStructs* o3, WithStructs* o4,
+ WithStructs* o5) final override {
+ nsTArray<int> ai;
+ ai.AppendElement(1);
+ ai.AppendElement(2);
+ ai.AppendElement(3);
+
+ EXPECT_EQ(i1, int(42));
+ EXPECT_EQ(i2.get_ArrayOfint(), ai);
+ EXPECT_EQ(i3.get_ArrayOfPTestDataStructuresSub(), kids);
+
+ const SActors& ia = i4.get_ArrayOfSActors()[0];
+ EXPECT_EQ(42, ia.i());
+ EXPECT_EQ(ai, ia.ai());
+ EXPECT_EQ(kids, ia.ap());
+
+ const Structs& is = i5.get_ArrayOfStructs()[0];
+ EXPECT_EQ(42, is.i());
+ EXPECT_EQ(ai, is.ai());
+ EXPECT_EQ(kids, is.ap());
+
+ const SActors& isa = is.aa()[0];
+ EXPECT_EQ(42, isa.i());
+ EXPECT_EQ(ai, isa.ai());
+ EXPECT_EQ(kids, isa.ap());
+
+ *o1 = i1;
+ *o2 = i2;
+ *o3 = i3;
+ *o4 = i4;
+ *o5 = i5;
+
+ return IPC_OK();
+ }
+
+ IPCResult RecvTestStructWithUnions(const WithUnions& i,
+ WithUnions* o) final override {
+ EXPECT_EQ(i.i(), 42);
+
+ nsTArray<int> ai;
+ ai.AppendElement(1);
+ ai.AppendElement(2);
+ ai.AppendElement(3);
+ EXPECT_EQ(ai, i.ai());
+
+ EXPECT_EQ(i.ap(), kids);
+
+ EXPECT_EQ(kids, i.aa()[0].get_ArrayOfPTestDataStructuresSub());
+
+ const nsTArray<Unions>& iau = i.au();
+ EXPECT_EQ(iau[0], 42);
+ EXPECT_EQ(ai, iau[1].get_ArrayOfint());
+ EXPECT_EQ(kids, iau[2].get_ArrayOfPTestDataStructuresSub());
+ EXPECT_EQ(
+ kids,
+ iau[3].get_ArrayOfActors()[0].get_ArrayOfPTestDataStructuresSub());
+
+ *o = i;
+
+ return IPC_OK();
+ }
+
+ IPCResult RecvTestUnionWithCxx(nsTArray<Op>&& sa) final override {
+ EXPECT_EQ(sa.Length(), (size_t)1);
+ EXPECT_EQ(Op::TSetAttrs, sa[0].type());
+ return IPC_OK();
+ }
+
+ IPCResult RecvTestNsIntRegion(RegionArray&& ra) final override {
+ for (RegionArray::index_type i = 0; i < ra.Length(); ++i) {
+ // if |ra| has been realloc()d and given a different allocator
+ // chunk, this loop will nondeterministically crash or iloop.
+ for (auto iter = ra[i].RectIter(); !iter.Done(); iter.Next()) {
+ Unused << iter.Get();
+ }
+ }
+ return IPC_OK();
+ }
+
+ ~TestDataStructuresParent() = default;
+};
+
+class TestDataStructuresChild : public PTestDataStructuresChild {
+ NS_INLINE_DECL_REFCOUNTING(TestDataStructuresChild, override)
+
+ private:
+ nsTArray<NotNull<
+ SideVariant<PTestDataStructuresSubParent*, PTestDataStructuresSubChild*>>>
+ kids;
+ nsTArray<NotNull<PTestDataStructuresSubChild*>> kidsDirect;
+
+ already_AddRefed<PTestDataStructuresSubChild>
+ AllocPTestDataStructuresSubChild(const int& i) final override {
+ auto child = MakeRefPtr<TestDataStructuresSubChild>(i);
+ kids.AppendElement(WrapNotNull(child));
+ kidsDirect.AppendElement(WrapNotNull(child));
+ return child.forget();
+ }
+
+ IPCResult RecvStart() final override {
+ TestArrayOfInt();
+ TestArrayOfActor();
+ TestUnion();
+ TestArrayOfUnion();
+ TestUnionWithArray();
+ TestArrayOfUnionWithArray();
+ TestStructWithActor();
+ TestUnionWithActors();
+ TestArrayOfUnionWithActors();
+ TestUnions();
+ TestArrayOfUnions();
+ TestStruct();
+ TestStructWithArrays();
+ TestStructWithActors();
+ TestStructs();
+ TestUnionWithStructs();
+ TestStructWithUnions();
+ TestUnionWithCxx();
+ TestNsIntRegion();
+
+ auto actors = kidsDirect.Clone();
+ for (auto& actor : actors) {
+ EXPECT_TRUE(PTestDataStructuresSubChild::Send__delete__(actor));
+ }
+
+ Close();
+
+ return IPC_OK();
+ }
+
+ void TestArrayOfInt() {
+ nsTArray<int> ia;
+
+ for (int i = 0; i < 5; ++i) ia.AppendElement(i);
+
+ nsTArray<int> oa;
+ EXPECT_TRUE(SendTestArrayOfInt(ia, &oa));
+
+ EXPECT_EQ(ia, oa);
+ }
+
+ void TestArrayOfActor() {
+ nsTArray<NotNull<PTestDataStructuresSubChild*>> oa;
+ EXPECT_TRUE(SendTestArrayOfActor(kidsDirect, &oa));
+ EXPECT_EQ(kidsDirect, oa);
+ }
+
+ void TestUnion() {
+ int i1i = 42;
+ double i2d = 4.0;
+ IntDouble i1(i1i);
+ IntDouble i2(i2d);
+ IntDouble o1, o2;
+
+ SendTestUnion(i1, i2, &o1, &o2);
+
+ EXPECT_EQ(i1i, o1.get_int());
+ EXPECT_EQ(i2d, o2.get_double());
+ }
+
+ void TestArrayOfUnion() {
+ nsTArray<IntDouble> i1;
+ i1.AppendElement(IntDouble(int(1)));
+ i1.AppendElement(IntDouble(2.0));
+ i1.AppendElement(IntDouble(int(3)));
+ i1.AppendElement(IntDouble(4.0));
+
+ nsTArray<IntDouble> o1;
+ EXPECT_TRUE(SendTestArrayOfUnion(i1, &o1));
+
+ // TODO Union::operator==()
+ EXPECT_EQ(i1.Length(), o1.Length());
+ EXPECT_EQ(1, o1[0].get_int());
+ EXPECT_EQ(2.0, o1[1].get_double());
+ EXPECT_EQ(3, o1[2].get_int());
+ EXPECT_EQ(4.0, o1[3].get_double());
+ }
+
+ void TestUnionWithArray() {
+ IntDoubleArrays i1(int(42));
+ nsTArray<int> i2;
+ i2.AppendElement(1);
+ i2.AppendElement(2);
+ i2.AppendElement(3);
+ nsTArray<double> i3;
+ i3.AppendElement(1.0);
+ i3.AppendElement(2.0);
+ i3.AppendElement(3.0);
+
+ IntDoubleArrays o1, o2, o3;
+ EXPECT_TRUE(SendTestUnionWithArray(i1, IntDoubleArrays(i2),
+ IntDoubleArrays(i3), &o1, &o2, &o3));
+
+ EXPECT_EQ(42, o1.get_int());
+ EXPECT_EQ(i2, o2.get_ArrayOfint());
+ EXPECT_EQ(i3, o3.get_ArrayOfdouble());
+ }
+
+ void TestArrayOfUnionWithArray() {
+ IntDoubleArrays id1(int(42));
+ nsTArray<int> id2;
+ id2.AppendElement(1);
+ id2.AppendElement(2);
+ id2.AppendElement(3);
+ nsTArray<double> id3;
+ id3.AppendElement(1.0);
+ id3.AppendElement(2.0);
+ id3.AppendElement(3.0);
+
+ nsTArray<IntDoubleArrays> i1;
+ i1.AppendElement(id1);
+ i1.AppendElement(IntDoubleArrays(id2));
+ i1.AppendElement(IntDoubleArrays(id3));
+
+ nsTArray<IntDoubleArrays> o1;
+ EXPECT_TRUE(SendTestArrayOfUnionWithArray(i1, &o1));
+
+ EXPECT_EQ(3u, o1.Length());
+ IntDoubleArrays od1(o1[0]);
+ nsTArray<int> od2 = o1[1].get_ArrayOfint().Clone();
+ nsTArray<double> od3 = o1[2].get_ArrayOfdouble().Clone();
+
+ EXPECT_EQ(42, od1.get_int());
+ EXPECT_EQ(id2, od2);
+ EXPECT_EQ(id3, od3);
+ }
+
+ void TestStructWithActor() {
+ ActorWrapper iaw(kidsDirect[0]);
+
+ ActorWrapper oaw;
+ EXPECT_TRUE(SendTestStructWithActor(iaw, &oaw));
+
+ EXPECT_TRUE(oaw.actor().IsChild());
+ EXPECT_EQ(oaw.actor().AsChild(), kidsDirect[0]);
+ }
+
+ void TestUnionWithActors() {
+ Actors i1(42);
+ nsTArray<int> i2a;
+ i2a.AppendElement(1);
+ i2a.AppendElement(2);
+ i2a.AppendElement(3);
+
+ Actors o1, o2, o3;
+ EXPECT_TRUE(
+ SendTestUnionWithActors(i1, Actors(i2a), Actors(kids), &o1, &o2, &o3));
+
+ EXPECT_EQ(42, o1.get_int());
+ EXPECT_EQ(i2a, o2.get_ArrayOfint());
+ EXPECT_EQ(kids, o3.get_ArrayOfPTestDataStructuresSub());
+ }
+
+ void TestArrayOfUnionWithActors() {
+ Actors i1e(42);
+ nsTArray<int> i2a;
+ i2a.AppendElement(1);
+ i2a.AppendElement(2);
+ i2a.AppendElement(3);
+
+ nsTArray<Actors> i1;
+ i1.AppendElement(i1e);
+ i1.AppendElement(i2a);
+ i1.AppendElement(kids);
+
+ nsTArray<Actors> o1;
+ EXPECT_TRUE(SendTestArrayOfUnionWithActors(i1, &o1));
+
+ EXPECT_EQ(3u, o1.Length());
+ EXPECT_EQ(42, o1[0].get_int());
+ EXPECT_EQ(i2a, o1[1].get_ArrayOfint());
+ EXPECT_EQ(kids, o1[2].get_ArrayOfPTestDataStructuresSub());
+ }
+
+ void TestUnions() {
+ Unions i1(int(42));
+
+ nsTArray<int> i2a;
+ i2a.AppendElement(1);
+ i2a.AppendElement(2);
+ i2a.AppendElement(3);
+
+ nsTArray<Actors> i4a;
+ i4a.AppendElement(kids);
+
+ Unions o1, o2, o3, o4;
+ EXPECT_TRUE(SendTestUnions(i1, Unions(i2a), Unions(kids), Unions(i4a), &o1,
+ &o2, &o3, &o4));
+
+ EXPECT_EQ(42, o1.get_int());
+ EXPECT_EQ(i2a, o2.get_ArrayOfint());
+ EXPECT_EQ(kids, o3.get_ArrayOfPTestDataStructuresSub());
+ EXPECT_EQ(kids,
+ o4.get_ArrayOfActors()[0].get_ArrayOfPTestDataStructuresSub());
+ }
+
+ void TestArrayOfUnions() {
+ Unions i1a(int(42));
+
+ nsTArray<int> i2a;
+ i2a.AppendElement(1);
+ i2a.AppendElement(2);
+ i2a.AppendElement(3);
+
+ nsTArray<Actors> i4a;
+ i4a.AppendElement(kids);
+
+ nsTArray<Unions> i1;
+ i1.AppendElement(i1a);
+ i1.AppendElement(Unions(i2a));
+ i1.AppendElement(Unions(kids));
+ i1.AppendElement(Unions(i4a));
+
+ nsTArray<Unions> o1;
+ EXPECT_TRUE(SendTestArrayOfUnions(i1, &o1));
+
+ EXPECT_EQ(4u, o1.Length());
+ EXPECT_EQ(42, o1[0].get_int());
+ EXPECT_EQ(i2a, o1[1].get_ArrayOfint());
+ EXPECT_EQ(kids, o1[2].get_ArrayOfPTestDataStructuresSub());
+ EXPECT_EQ(kids,
+ o1[3].get_ArrayOfActors()[0].get_ArrayOfPTestDataStructuresSub());
+ }
+
+ void TestStruct() {
+ SIntDouble i(1, 2.0);
+ SIntDouble o;
+
+ EXPECT_TRUE(SendTestStruct(i, &o));
+
+ EXPECT_EQ(o.i(), 1);
+ EXPECT_EQ(o.d(), 2.0);
+ }
+
+ void TestStructWithArrays() {
+ nsTArray<int> ai;
+ ai.AppendElement(1);
+ ai.AppendElement(2);
+ ai.AppendElement(3);
+
+ nsTArray<double> ad;
+ ad.AppendElement(.5);
+ ad.AppendElement(1.0);
+ ad.AppendElement(2.0);
+
+ SIntDoubleArrays i(42, ai, ad);
+ SIntDoubleArrays o;
+
+ EXPECT_TRUE(SendTestStructWithArrays(i, &o));
+
+ EXPECT_EQ(42, o.i());
+ EXPECT_EQ(ai, o.ai());
+ EXPECT_EQ(ad, o.ad());
+ }
+
+ void TestStructWithActors() {
+ nsTArray<int> ai;
+ ai.AppendElement(1);
+ ai.AppendElement(2);
+ ai.AppendElement(3);
+
+ SActors i;
+ i.i() = 42;
+ i.ai() = ai.Clone();
+ i.ap() = kids.Clone();
+
+ SActors o;
+ EXPECT_TRUE(SendTestStructWithActors(i, &o));
+
+ EXPECT_EQ(42, o.i());
+ EXPECT_EQ(ai, o.ai());
+ EXPECT_EQ(kids, o.ap());
+ }
+
+ void TestStructs() {
+ nsTArray<int> ai;
+ ai.AppendElement(1);
+ ai.AppendElement(2);
+ ai.AppendElement(3);
+
+ SActors ia;
+ ia.i() = 42;
+ ia.ai() = ai.Clone();
+ ia.ap() = kids.Clone();
+ nsTArray<SActors> aa;
+ aa.AppendElement(ia);
+
+ Structs i;
+ i.i() = 42;
+ i.ai() = ai.Clone();
+ i.ap() = kids.Clone();
+ i.aa() = aa.Clone();
+
+ Structs o;
+ EXPECT_TRUE(SendTestStructs(i, &o));
+
+ EXPECT_EQ(42, o.i());
+ EXPECT_EQ(ai, o.ai());
+ EXPECT_EQ(kids, o.ap());
+
+ const SActors& os = o.aa()[0];
+ EXPECT_EQ(42, os.i());
+ EXPECT_EQ(ai, os.ai());
+ EXPECT_EQ(kids, os.ap());
+ }
+
+ void TestUnionWithStructs() {
+ nsTArray<int> ai;
+ ai.AppendElement(1);
+ ai.AppendElement(2);
+ ai.AppendElement(3);
+
+ SActors ia;
+ ia.i() = 42;
+ ia.ai() = ai.Clone();
+ ia.ap() = kids.Clone();
+ nsTArray<SActors> iaa;
+ iaa.AppendElement(ia);
+
+ Structs is;
+ is.i() = 42;
+ is.ai() = ai.Clone();
+ is.ap() = kids.Clone();
+ is.aa() = iaa.Clone();
+ nsTArray<Structs> isa;
+ isa.AppendElement(is);
+
+ WithStructs o1, o2, o3, o4, o5;
+ EXPECT_TRUE(SendTestUnionWithStructs(
+ WithStructs(42), WithStructs(ai), WithStructs(kids), WithStructs(iaa),
+ WithStructs(isa), &o1, &o2, &o3, &o4, &o5));
+
+ EXPECT_EQ(o1, int(42));
+ EXPECT_EQ(o2.get_ArrayOfint(), ai);
+ EXPECT_EQ(o3.get_ArrayOfPTestDataStructuresSub(), kids);
+
+ const SActors& oa = o4.get_ArrayOfSActors()[0];
+ EXPECT_EQ(42, oa.i());
+ EXPECT_EQ(ai, oa.ai());
+ EXPECT_EQ(kids, oa.ap());
+
+ const Structs& os = o5.get_ArrayOfStructs()[0];
+ EXPECT_EQ(42, os.i());
+ EXPECT_EQ(ai, os.ai());
+ EXPECT_EQ(kids, os.ap());
+
+ const SActors& osa = os.aa()[0];
+ EXPECT_EQ(42, osa.i());
+ EXPECT_EQ(ai, osa.ai());
+ EXPECT_EQ(kids, osa.ap());
+ }
+
+ void TestStructWithUnions() {
+ WithUnions i;
+
+ i.i() = 42;
+
+ nsTArray<int> ai;
+ ai.AppendElement(1);
+ ai.AppendElement(2);
+ ai.AppendElement(3);
+ i.ai() = ai.Clone();
+
+ i.ap() = kids.Clone();
+
+ nsTArray<Actors> iaa;
+ iaa.AppendElement(kids);
+ i.aa() = iaa.Clone();
+
+ nsTArray<Unions> iau;
+ iau.AppendElement(int(42));
+ iau.AppendElement(ai);
+ iau.AppendElement(kids);
+ iau.AppendElement(iaa);
+ i.au() = iau.Clone();
+
+ WithUnions o;
+ EXPECT_TRUE(SendTestStructWithUnions(i, &o));
+
+ EXPECT_EQ(42, o.i());
+ EXPECT_EQ(o.ai(), ai);
+ EXPECT_EQ(o.ap(), kids);
+
+ const Actors& oaa = o.aa()[0];
+ EXPECT_EQ(oaa.get_ArrayOfPTestDataStructuresSub(), kids);
+
+ const nsTArray<Unions>& oau = o.au();
+ EXPECT_EQ(oau[0], 42);
+ EXPECT_EQ(oau[1].get_ArrayOfint(), ai);
+ EXPECT_EQ(oau[2].get_ArrayOfPTestDataStructuresSub(), kids);
+ EXPECT_EQ(oau[3].get_ArrayOfActors()[0].get_ArrayOfPTestDataStructuresSub(),
+ kids);
+ }
+
+ void TestUnionWithCxx() {
+ Attrs attrs;
+ attrs.common() = CommonAttrs(true);
+ attrs.specific() = BarAttrs(1.0f);
+
+ nsTArray<Op> ops;
+ ops.AppendElement(SetAttrs(kids[0], attrs));
+
+ EXPECT_TRUE(SendTestUnionWithCxx(ops));
+ }
+
+ void TestNsIntRegion() {
+ const int nelements = 1000;
+ RegionArray ra;
+ // big enough to hopefully force a realloc to a different chunk of
+ // memory on the receiving side, if the workaround isn't working
+ // correctly. But SetCapacity() here because we don't want to
+ // crash on the sending side.
+ ra.SetCapacity(nelements);
+ for (int i = 0; i < nelements; ++i) {
+ nsIntRegion r;
+ r.Or(nsIntRect(0, 0, 10, 10), nsIntRect(10, 10, 10, 10));
+ ra.AppendElement(r);
+ }
+
+ EXPECT_TRUE(SendTestNsIntRegion(ra));
+ }
+
+ ~TestDataStructuresChild() = default;
+};
+
+IPDL_TEST(TestDataStructures) {
+ for (uint32_t i = 0; i < nactors; ++i) {
+ auto sub = MakeRefPtr<TestDataStructuresSubParent>(i);
+ EXPECT_TRUE(mActor->SendPTestDataStructuresSubConstructor(sub, i))
+ << "can't alloc actor";
+ mActor->kids.AppendElement(WrapNotNull(sub));
+ }
+
+ EXPECT_TRUE(mActor->SendStart()) << "can't send Start()";
+}
+
+} // namespace mozilla::_ipdltest
diff --git a/ipc/ipdl/test/gtest/TestDescendant.cpp b/ipc/ipdl/test/gtest/TestDescendant.cpp
new file mode 100644
index 0000000000..47f619d32a
--- /dev/null
+++ b/ipc/ipdl/test/gtest/TestDescendant.cpp
@@ -0,0 +1,98 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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/. */
+
+/*
+ * Test multiple levels of descendant managed protocols.
+ */
+
+#include "gtest/gtest.h"
+
+#include "mozilla/_ipdltest/IPDLUnitTest.h"
+#include "mozilla/_ipdltest/PTestDescendantChild.h"
+#include "mozilla/_ipdltest/PTestDescendantParent.h"
+#include "mozilla/_ipdltest/PTestDescendantSubChild.h"
+#include "mozilla/_ipdltest/PTestDescendantSubParent.h"
+#include "mozilla/_ipdltest/PTestDescendantSubsubChild.h"
+#include "mozilla/_ipdltest/PTestDescendantSubsubParent.h"
+
+using namespace mozilla::ipc;
+
+namespace mozilla::_ipdltest {
+
+class TestDescendantSubsubParent : public PTestDescendantSubsubParent {
+ NS_INLINE_DECL_REFCOUNTING(TestDescendantSubsubParent, override)
+ private:
+ ~TestDescendantSubsubParent() = default;
+};
+
+class TestDescendantSubsubChild : public PTestDescendantSubsubChild {
+ NS_INLINE_DECL_REFCOUNTING(TestDescendantSubsubChild, override)
+ private:
+ ~TestDescendantSubsubChild() = default;
+};
+
+class TestDescendantSubParent : public PTestDescendantSubParent {
+ NS_INLINE_DECL_REFCOUNTING(TestDescendantSubParent, override)
+ private:
+ ~TestDescendantSubParent() = default;
+};
+
+class TestDescendantSubChild : public PTestDescendantSubChild {
+ NS_INLINE_DECL_REFCOUNTING(TestDescendantSubChild, override)
+ private:
+ already_AddRefed<PTestDescendantSubsubChild> AllocPTestDescendantSubsubChild()
+ final override {
+ return MakeAndAddRef<TestDescendantSubsubChild>();
+ }
+
+ ~TestDescendantSubChild() = default;
+};
+
+class TestDescendantParent : public PTestDescendantParent {
+ NS_INLINE_DECL_REFCOUNTING(TestDescendantParent, override)
+ private:
+ IPCResult RecvOk(NotNull<PTestDescendantSubsubParent*> a) final override {
+ EXPECT_TRUE(PTestDescendantSubsubParent::Send__delete__(a))
+ << "deleting Subsub";
+
+ Close();
+
+ return IPC_OK();
+ }
+
+ ~TestDescendantParent() = default;
+};
+
+class TestDescendantChild : public PTestDescendantChild {
+ NS_INLINE_DECL_REFCOUNTING(TestDescendantChild, override)
+ private:
+ already_AddRefed<PTestDescendantSubChild> AllocPTestDescendantSubChild(
+ PTestDescendantSubsubChild* dummy) final override {
+ EXPECT_FALSE(dummy) << "actor supposed to be null";
+ return MakeAndAddRef<TestDescendantSubChild>();
+ }
+
+ IPCResult RecvTest(NotNull<PTestDescendantSubsubChild*> a) final override {
+ EXPECT_TRUE(SendOk(a)) << "couldn't send Ok()";
+ return IPC_OK();
+ }
+
+ ~TestDescendantChild() = default;
+};
+
+IPDL_TEST(TestDescendant) {
+ auto p = MakeRefPtr<TestDescendantSubParent>();
+ auto* rv1 = mActor->SendPTestDescendantSubConstructor(p, nullptr);
+ EXPECT_EQ(p, rv1) << "can't allocate Sub";
+
+ auto pp = MakeRefPtr<TestDescendantSubsubParent>();
+ auto* rv2 = p->SendPTestDescendantSubsubConstructor(pp);
+ EXPECT_EQ(pp, rv2) << "can't allocate Subsub";
+
+ EXPECT_TRUE(mActor->SendTest(WrapNotNull(pp))) << "can't send Subsub";
+}
+
+} // namespace mozilla::_ipdltest
diff --git a/ipc/ipdl/test/gtest/TestEndpointOpens.cpp b/ipc/ipdl/test/gtest/TestEndpointOpens.cpp
new file mode 100644
index 0000000000..50dab06058
--- /dev/null
+++ b/ipc/ipdl/test/gtest/TestEndpointOpens.cpp
@@ -0,0 +1,159 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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/. */
+
+/*
+ * Test Endpoint usage.
+ */
+
+#include "gtest/gtest.h"
+
+#include "mozilla/_ipdltest/IPDLUnitTest.h"
+#include "mozilla/_ipdltest/PTestEndpointOpensChild.h"
+#include "mozilla/_ipdltest/PTestEndpointOpensParent.h"
+#include "mozilla/_ipdltest/PTestEndpointOpensOpenedChild.h"
+#include "mozilla/_ipdltest/PTestEndpointOpensOpenedParent.h"
+
+#include <memory>
+
+using namespace mozilla::ipc;
+
+namespace mozilla::_ipdltest {
+
+class TestEndpointOpensOpenedParent : public PTestEndpointOpensOpenedParent {
+ NS_INLINE_DECL_THREADSAFE_REFCOUNTING(TestEndpointOpensOpenedParent, override)
+ private:
+ IPCResult RecvHello() final override {
+ EXPECT_FALSE(NS_IsMainThread());
+ if (!SendHi()) {
+ return IPC_TEST_FAIL(this);
+ }
+ return IPC_OK();
+ }
+
+ IPCResult RecvHelloSync() final override {
+ EXPECT_FALSE(NS_IsMainThread());
+ return IPC_OK();
+ }
+
+ void ActorDestroy(ActorDestroyReason why) final override {
+ EXPECT_FALSE(NS_IsMainThread());
+ }
+
+ ~TestEndpointOpensOpenedParent() = default;
+};
+
+class TestEndpointOpensChild : public PTestEndpointOpensChild {
+ NS_INLINE_DECL_THREADSAFE_REFCOUNTING(TestEndpointOpensChild, override)
+ private:
+ IPCResult RecvStart() final override;
+
+ ~TestEndpointOpensChild() = default;
+};
+
+class TestEndpointOpensOpenedChild : public PTestEndpointOpensOpenedChild {
+ NS_INLINE_DECL_THREADSAFE_REFCOUNTING(TestEndpointOpensOpenedChild, override)
+
+ explicit TestEndpointOpensOpenedChild(TestEndpointOpensChild* opensChild)
+ : mOpensChild(opensChild) {}
+
+ private:
+ IPCResult RecvHi() final override {
+ EXPECT_FALSE(NS_IsMainThread());
+
+ EXPECT_TRUE(SendHelloSync());
+
+ Close();
+ return IPC_OK();
+ }
+
+ void ActorDestroy(ActorDestroyReason why) final override {
+ EXPECT_FALSE(NS_IsMainThread());
+
+ // Kick off main-thread shutdown.
+ NS_DispatchToMainThread(NewRunnableMethod("ipc::IToplevelProtocol::Close",
+ mOpensChild,
+ &TestEndpointOpensChild::Close));
+ }
+
+ ~TestEndpointOpensOpenedChild() = default;
+
+ TestEndpointOpensChild* mOpensChild;
+};
+
+class TestEndpointOpensParent : public PTestEndpointOpensParent {
+ NS_INLINE_DECL_THREADSAFE_REFCOUNTING(TestEndpointOpensParent, override)
+ private:
+ IPCResult RecvStartSubprotocol(
+ Endpoint<PTestEndpointOpensOpenedParent>&& endpoint) final override {
+ nsCOMPtr<nsISerialEventTarget> eventTarget;
+ auto rv = NS_CreateBackgroundTaskQueue("ParentThread",
+ getter_AddRefs(eventTarget));
+ if (NS_FAILED(rv)) {
+ ADD_FAILURE() << "creating background task queue for child";
+ return IPC_TEST_FAIL(this);
+ }
+
+ eventTarget->Dispatch(NS_NewRunnableFunction(
+ "OpenParent", [endpoint{std::move(endpoint)}]() mutable {
+ EXPECT_FALSE(NS_IsMainThread());
+
+ // Open the actor on the off-main thread to park it there.
+ // Messages will be delivered to this thread's message loop
+ // instead of the main thread's.
+ auto actor = MakeRefPtr<TestEndpointOpensOpenedParent>();
+ ASSERT_TRUE(endpoint.Bind(actor));
+ }));
+
+ return IPC_OK();
+ }
+
+ ~TestEndpointOpensParent() = default;
+};
+
+IPCResult TestEndpointOpensChild::RecvStart() {
+ Endpoint<PTestEndpointOpensOpenedParent> parent;
+ Endpoint<PTestEndpointOpensOpenedChild> child;
+ nsresult rv;
+ rv = PTestEndpointOpensOpened::CreateEndpoints(
+ OtherPidMaybeInvalid(), base::GetCurrentProcId(), &parent, &child);
+ if (NS_FAILED(rv)) {
+ ADD_FAILURE() << "opening PTestEndpointOpensOpened";
+ return IPC_TEST_FAIL(this);
+ }
+
+ nsCOMPtr<nsISerialEventTarget> childEventTarget;
+ rv = NS_CreateBackgroundTaskQueue("ChildThread",
+ getter_AddRefs(childEventTarget));
+ if (NS_FAILED(rv)) {
+ ADD_FAILURE() << "creating background task queue for child";
+ return IPC_TEST_FAIL(this);
+ }
+
+ auto actor = MakeRefPtr<TestEndpointOpensOpenedChild>(this);
+ childEventTarget->Dispatch(NS_NewRunnableFunction(
+ "OpenChild",
+ [actor{std::move(actor)}, endpoint{std::move(child)}]() mutable {
+ EXPECT_FALSE(NS_IsMainThread());
+
+ // Open the actor on the off-main thread to park it there.
+ // Messages will be delivered to this thread's message loop
+ // instead of the main thread's.
+ ASSERT_TRUE(endpoint.Bind(actor));
+
+ // Kick off the unit tests
+ ASSERT_TRUE(actor->SendHello());
+ }));
+
+ EXPECT_TRUE(SendStartSubprotocol(std::move(parent)));
+
+ return IPC_OK();
+}
+
+IPDL_TEST_ON(CROSSPROCESS, TestEndpointOpens) {
+ EXPECT_TRUE(mActor->SendStart());
+}
+
+} // namespace mozilla::_ipdltest
diff --git a/ipc/ipdl/test/gtest/TestHangs.cpp b/ipc/ipdl/test/gtest/TestHangs.cpp
new file mode 100644
index 0000000000..ddc4a0c7d0
--- /dev/null
+++ b/ipc/ipdl/test/gtest/TestHangs.cpp
@@ -0,0 +1,133 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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/. */
+
+/*
+ * Test various cases of behavior when a synchronous method call times out.
+ */
+
+#include "gtest/gtest.h"
+
+#include "mozilla/_ipdltest/IPDLUnitTest.h"
+#include "mozilla/_ipdltest/PTestHangsChild.h"
+#include "mozilla/_ipdltest/PTestHangsParent.h"
+#include "mozilla/ipc/CrossProcessSemaphore.h"
+
+using namespace mozilla::ipc;
+
+namespace mozilla::_ipdltest {
+
+enum class HangMode : uint32_t {
+ /// No hang should occur.
+ None,
+ /// The synchronous call should time out.
+ Hang,
+ /// The synchronous call should time out but the response should still be
+ /// received
+ /// (racing with the reply timeout logic).
+ HangButReceive,
+ /// The synchronous call should time out but the response should still be
+ /// received because the child indicates that processing should continue after
+ /// timeout.
+ HangPermitted
+};
+
+class TestHangsChild : public PTestHangsChild {
+ NS_INLINE_DECL_REFCOUNTING(TestHangsChild, override)
+
+ TestHangsChild() : timeout(CrossProcessSemaphore::Create("timeout", 0)) {}
+
+ private:
+ IPCResult RecvStart(const uint32_t& hangMode,
+ StartResolver&& resolve) final override {
+ // Minimum possible, 2 ms. We want to detect a hang to race with the reply
+ // coming in, as reliably as possible. After 1ms the wait for a response
+ // will be retried.
+ SetReplyTimeoutMs(2);
+
+ this->hangMode = (HangMode)hangMode;
+
+ auto result = SendHang(hangMode, timeout->CloneHandle());
+ if (this->hangMode == HangMode::Hang) {
+ // Only the `Hang` mode should actually fail.
+ EXPECT_FALSE(result);
+ } else {
+ EXPECT_TRUE(result);
+ }
+
+ resolve(detectedHang);
+
+ return IPC_OK();
+ }
+
+ bool ShouldContinueFromReplyTimeout() final override {
+ timeout->Signal();
+ detectedHang = true;
+
+ if (hangMode == HangMode::HangButReceive) {
+ // Wait until the transaction is complete so that we can still receive the
+ // result after returning.
+ while (!GetIPCChannel()->TestOnlyIsTransactionComplete()) {
+ PR_Sleep(ticksPerSecond / 1000);
+ }
+ }
+
+ // Return true if `HangPermitted` mode (allowing the receive loop to
+ // continue).
+ return hangMode == HangMode::HangPermitted;
+ }
+
+ ~TestHangsChild() = default;
+
+ HangMode hangMode = HangMode::None;
+ uint32_t ticksPerSecond = PR_TicksPerSecond();
+ UniquePtr<CrossProcessSemaphore> timeout;
+
+ public:
+ bool detectedHang = false;
+};
+
+class TestHangsParent : public PTestHangsParent {
+ NS_INLINE_DECL_REFCOUNTING(TestHangsParent, override)
+
+ private:
+ IPCResult RecvHang(
+ const uint32_t& hangMode,
+ CrossProcessSemaphoreHandle&& timeout_handle) final override {
+ UniquePtr<CrossProcessSemaphore> timeout(
+ CrossProcessSemaphore::Create(std::move(timeout_handle)));
+ if (hangMode != (uint32_t)HangMode::None) {
+ // Wait to ensure the child process has called
+ // ShouldContinueFromReplyTimeout().
+ timeout->Wait();
+ }
+ return IPC_OK();
+ }
+
+ ~TestHangsParent() = default;
+};
+
+// We can verify that the Start message callbacks are run with the `Close()`
+// calls; without a `Close()`, the test will hang.
+
+#define TEST_HANGS(mode) \
+ IPDL_TEST(TestHangs, mode) { \
+ mActor->SendStart( \
+ (uint32_t)HangMode::mode, \
+ [=](bool detectedHang) { \
+ EXPECT_EQ(detectedHang, HangMode::mode != HangMode::None); \
+ mActor->Close(); \
+ }, \
+ [](auto&& reason) { FAIL() << "failed to send start"; }); \
+ }
+
+TEST_HANGS(None)
+TEST_HANGS(Hang)
+TEST_HANGS(HangButReceive)
+TEST_HANGS(HangPermitted)
+
+#undef TEST_HANGS
+
+} // namespace mozilla::_ipdltest
diff --git a/ipc/ipdl/test/gtest/TestJSON.cpp b/ipc/ipdl/test/gtest/TestJSON.cpp
new file mode 100644
index 0000000000..a3f881abda
--- /dev/null
+++ b/ipc/ipdl/test/gtest/TestJSON.cpp
@@ -0,0 +1,157 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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/. */
+
+/*
+ * Test sending JSON(-like) objects over IPC.
+ */
+
+#include "gtest/gtest.h"
+
+#include "mozilla/_ipdltest/IPDLUnitTest.h"
+#include "mozilla/_ipdltest/PTestJSONChild.h"
+#include "mozilla/_ipdltest/PTestJSONParent.h"
+#include "mozilla/_ipdltest/PTestJSONHandleChild.h"
+#include "mozilla/_ipdltest/PTestJSONHandleParent.h"
+
+using namespace mozilla::ipc;
+
+namespace mozilla::_ipdltest {
+
+static nsString String(const char* const str) {
+ return NS_ConvertUTF8toUTF16(str);
+}
+
+static void Array123(nsTArray<JSONVariant>& a123) {
+ a123.AppendElement(1);
+ a123.AppendElement(2);
+ a123.AppendElement(3);
+
+ ASSERT_EQ(a123, a123) << "operator== is broken";
+}
+
+template <class HandleT>
+JSONVariant MakeTestVariant(HandleT* handle) {
+ // In JS syntax:
+ //
+ // return [
+ // undefined, null, true, 1.25, "test string",
+ // handle,
+ // [ 1, 2, 3 ],
+ // { "undefined" : undefined,
+ // "null" : null,
+ // "true" : true,
+ // "1.25" : 1.25,
+ // "string" : "string"
+ // "handle" : handle,
+ // "array" : [ 1, 2, 3 ]
+ // }
+ // ]
+ //
+ nsTArray<JSONVariant> outer;
+
+ outer.AppendElement(void_t());
+ outer.AppendElement(null_t());
+ outer.AppendElement(true);
+ outer.AppendElement(1.25);
+ outer.AppendElement(String("test string"));
+
+ outer.AppendElement(handle);
+
+ nsTArray<JSONVariant> tmp;
+ Array123(tmp);
+ outer.AppendElement(tmp);
+
+ nsTArray<KeyValue> obj;
+ obj.AppendElement(KeyValue(String("undefined"), void_t()));
+ obj.AppendElement(KeyValue(String("null"), null_t()));
+ obj.AppendElement(KeyValue(String("true"), true));
+ obj.AppendElement(KeyValue(String("1.25"), 1.25));
+ obj.AppendElement(KeyValue(String("string"), String("value")));
+ obj.AppendElement(KeyValue(String("handle"), handle));
+ nsTArray<JSONVariant> tmp2;
+ Array123(tmp2);
+ obj.AppendElement(KeyValue(String("array"), tmp2));
+
+ outer.AppendElement(obj);
+
+ EXPECT_EQ(outer, outer) << "operator== is broken";
+
+ return JSONVariant(outer);
+}
+
+//-----------------------------------------------------------------------------
+// parent
+
+class TestJSONHandleParent : public PTestJSONHandleParent {
+ NS_INLINE_DECL_REFCOUNTING(TestJSONHandleParent, override)
+ private:
+ ~TestJSONHandleParent() = default;
+};
+
+class TestJSONHandleChild : public PTestJSONHandleChild {
+ NS_INLINE_DECL_REFCOUNTING(TestJSONHandleChild, override)
+ private:
+ ~TestJSONHandleChild() = default;
+};
+
+class TestJSONParent : public PTestJSONParent {
+ NS_INLINE_DECL_REFCOUNTING(TestJSONParent, override)
+ private:
+ IPCResult RecvTest(const JSONVariant& i, JSONVariant* o) final override {
+ EXPECT_EQ(i, MakeTestVariant(mKid.get())) << "inparam mangled en route";
+
+ *o = i;
+
+ EXPECT_EQ(i, *o) << "operator== and/or copy assignment are broken";
+
+ return IPC_OK();
+ }
+
+ already_AddRefed<PTestJSONHandleParent> AllocPTestJSONHandleParent()
+ final override {
+ auto handle = MakeRefPtr<TestJSONHandleParent>();
+ EXPECT_FALSE(mKid);
+ mKid = handle;
+ return handle.forget();
+ }
+
+ ~TestJSONParent() = default;
+
+ RefPtr<PTestJSONHandleParent> mKid;
+};
+
+//-----------------------------------------------------------------------------
+// child
+
+class TestJSONChild : public PTestJSONChild {
+ NS_INLINE_DECL_REFCOUNTING(TestJSONChild, override)
+ private:
+ IPCResult RecvStart() final override {
+ mKid = MakeRefPtr<TestJSONHandleChild>();
+ EXPECT_TRUE(SendPTestJSONHandleConstructor(mKid)) << "sending Handle ctor";
+
+ JSONVariant i(MakeTestVariant(mKid.get()));
+ EXPECT_EQ(i, i) << "operator== is broken";
+ EXPECT_EQ(i, MakeTestVariant(mKid.get())) << "copy ctor is broken";
+
+ JSONVariant o;
+ EXPECT_TRUE(SendTest(i, &o)) << "sending Test";
+
+ EXPECT_EQ(i, o) << "round-trip mangled input data";
+ EXPECT_EQ(o, MakeTestVariant(mKid.get())) << "outparam mangled en route";
+
+ Close();
+ return IPC_OK();
+ }
+
+ ~TestJSONChild() = default;
+
+ RefPtr<PTestJSONHandleChild> mKid;
+};
+
+IPDL_TEST(TestJSON) { EXPECT_TRUE(mActor->SendStart()) << "sending Start"; }
+
+} // namespace mozilla::_ipdltest
diff --git a/ipc/ipdl/test/gtest/TestManyChildAllocs.cpp b/ipc/ipdl/test/gtest/TestManyChildAllocs.cpp
new file mode 100644
index 0000000000..2111f4f49f
--- /dev/null
+++ b/ipc/ipdl/test/gtest/TestManyChildAllocs.cpp
@@ -0,0 +1,82 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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/. */
+
+/*
+ * Test that many child allocations work correctly.
+ */
+
+#include "gtest/gtest.h"
+
+#include "mozilla/_ipdltest/IPDLUnitTest.h"
+#include "mozilla/_ipdltest/PTestManyChildAllocsChild.h"
+#include "mozilla/_ipdltest/PTestManyChildAllocsParent.h"
+#include "mozilla/_ipdltest/PTestManyChildAllocsSubChild.h"
+#include "mozilla/_ipdltest/PTestManyChildAllocsSubParent.h"
+
+using namespace mozilla::ipc;
+
+#define NALLOCS 10
+
+namespace mozilla::_ipdltest {
+
+class TestManyChildAllocsSubParent : public PTestManyChildAllocsSubParent {
+ NS_INLINE_DECL_REFCOUNTING(TestManyChildAllocsSubParent, override)
+ private:
+ IPCResult RecvHello() final override { return IPC_OK(); }
+
+ ~TestManyChildAllocsSubParent() = default;
+};
+
+class TestManyChildAllocsSubChild : public PTestManyChildAllocsSubChild {
+ NS_INLINE_DECL_REFCOUNTING(TestManyChildAllocsSubChild, override)
+ private:
+ ~TestManyChildAllocsSubChild() = default;
+};
+
+class TestManyChildAllocsParent : public PTestManyChildAllocsParent {
+ NS_INLINE_DECL_REFCOUNTING(TestManyChildAllocsParent, override)
+ private:
+ IPCResult RecvDone() final override {
+ Close();
+
+ return IPC_OK();
+ }
+
+ already_AddRefed<PTestManyChildAllocsSubParent>
+ AllocPTestManyChildAllocsSubParent() final override {
+ return MakeAndAddRef<TestManyChildAllocsSubParent>();
+ }
+
+ ~TestManyChildAllocsParent() = default;
+};
+
+class TestManyChildAllocsChild : public PTestManyChildAllocsChild {
+ NS_INLINE_DECL_REFCOUNTING(TestManyChildAllocsChild, override)
+ private:
+ IPCResult RecvGo() final override {
+ for (int i = 0; i < NALLOCS; ++i) {
+ auto child = MakeRefPtr<TestManyChildAllocsSubChild>();
+ EXPECT_TRUE(SendPTestManyChildAllocsSubConstructor(child));
+ EXPECT_TRUE(child->SendHello()) << "can't send Hello()";
+ }
+
+ size_t len = ManagedPTestManyChildAllocsSubChild().Count();
+ EXPECT_EQ((size_t)NALLOCS, len)
+ << "expected " << NALLOCS << " kids, got " << len;
+
+ EXPECT_TRUE(SendDone()) << "can't send Done()";
+
+ return IPC_OK();
+ }
+
+ ~TestManyChildAllocsChild() = default;
+};
+
+IPDL_TEST(TestManyChildAllocs) {
+ EXPECT_TRUE(mActor->SendGo()) << "can't send Go()";
+}
+
+} // namespace mozilla::_ipdltest
diff --git a/ipc/ipdl/test/gtest/TestMostNested.cpp b/ipc/ipdl/test/gtest/TestMostNested.cpp
new file mode 100644
index 0000000000..d3fb3582c6
--- /dev/null
+++ b/ipc/ipdl/test/gtest/TestMostNested.cpp
@@ -0,0 +1,88 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: sw=2 ts=4 et :
+ */
+/* 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/. */
+
+/*
+ * Test nested sync message priorities.
+ */
+
+#include "gtest/gtest.h"
+
+#include "mozilla/_ipdltest/IPDLUnitTest.h"
+#include "mozilla/_ipdltest/PTestMostNestedChild.h"
+#include "mozilla/_ipdltest/PTestMostNestedParent.h"
+
+#if defined(XP_UNIX)
+# include <unistd.h>
+#else
+# include <windows.h>
+#endif
+
+using namespace mozilla::ipc;
+
+namespace mozilla::_ipdltest {
+
+class TestMostNestedChild : public PTestMostNestedChild {
+ NS_INLINE_DECL_REFCOUNTING(TestMostNestedChild, override)
+ private:
+ IPCResult RecvStart() final override {
+ EXPECT_TRUE(SendMsg1());
+ EXPECT_TRUE(SendMsg2());
+
+ Close();
+ return IPC_OK();
+ }
+
+ IPCResult RecvStartInner() final override {
+ EXPECT_TRUE(SendMsg3());
+ EXPECT_TRUE(SendMsg4());
+
+ return IPC_OK();
+ }
+
+ ~TestMostNestedChild() = default;
+};
+
+class TestMostNestedParent : public PTestMostNestedParent {
+ NS_INLINE_DECL_REFCOUNTING(TestMostNestedParent, override)
+ private:
+ IPCResult RecvMsg1() final override {
+ EXPECT_EQ(msg_num, 0);
+ msg_num = 1;
+ return IPC_OK();
+ }
+
+ IPCResult RecvMsg2() final override {
+ EXPECT_EQ(msg_num, 1);
+ msg_num = 2;
+
+ EXPECT_TRUE(SendStartInner());
+
+ return IPC_OK();
+ }
+
+ IPCResult RecvMsg3() final override {
+ EXPECT_EQ(msg_num, 2);
+ msg_num = 3;
+ return IPC_OK();
+ }
+
+ IPCResult RecvMsg4() final override {
+ EXPECT_EQ(msg_num, 3);
+ msg_num = 4;
+ return IPC_OK();
+ }
+
+ ~TestMostNestedParent() = default;
+
+ int msg_num = 0;
+};
+
+// Can only run cross-process because nested sync messages have to come from the
+// main thread.
+IPDL_TEST_ON(CROSSPROCESS, TestMostNested) { EXPECT_TRUE(mActor->SendStart()); }
+
+} // namespace mozilla::_ipdltest
diff --git a/ipc/ipdl/test/gtest/TestMultiMgrs.cpp b/ipc/ipdl/test/gtest/TestMultiMgrs.cpp
new file mode 100644
index 0000000000..06dac581f3
--- /dev/null
+++ b/ipc/ipdl/test/gtest/TestMultiMgrs.cpp
@@ -0,0 +1,202 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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/. */
+
+/*
+ * Test a chain of managers, ensuring ownership is maintained correctly.
+ */
+
+#include "gtest/gtest.h"
+
+#include "mozilla/_ipdltest/IPDLUnitTest.h"
+#include "mozilla/_ipdltest/PTestMultiMgrsChild.h"
+#include "mozilla/_ipdltest/PTestMultiMgrsParent.h"
+#include "mozilla/_ipdltest/PTestMultiMgrsLeftChild.h"
+#include "mozilla/_ipdltest/PTestMultiMgrsLeftParent.h"
+#include "mozilla/_ipdltest/PTestMultiMgrsRightChild.h"
+#include "mozilla/_ipdltest/PTestMultiMgrsRightParent.h"
+#include "mozilla/_ipdltest/PTestMultiMgrsBottomChild.h"
+#include "mozilla/_ipdltest/PTestMultiMgrsBottomParent.h"
+
+#include <algorithm>
+
+using namespace mozilla::ipc;
+
+namespace mozilla::_ipdltest {
+
+class TestMultiMgrsBottomParent : public PTestMultiMgrsBottomParent {
+ NS_INLINE_DECL_REFCOUNTING(TestMultiMgrsBottomParent, override)
+ private:
+ ~TestMultiMgrsBottomParent() = default;
+};
+
+class TestMultiMgrsBottomChild : public PTestMultiMgrsBottomChild {
+ NS_INLINE_DECL_REFCOUNTING(TestMultiMgrsBottomChild, override)
+ private:
+ ~TestMultiMgrsBottomChild() = default;
+};
+
+class TestMultiMgrsChild : public PTestMultiMgrsChild {
+ NS_INLINE_DECL_REFCOUNTING(TestMultiMgrsChild, override)
+ public:
+ PTestMultiMgrsBottomChild* mBottomL = nullptr;
+ PTestMultiMgrsBottomChild* mBottomR = nullptr;
+
+ private:
+ already_AddRefed<PTestMultiMgrsLeftChild> AllocPTestMultiMgrsLeftChild()
+ final override;
+
+ already_AddRefed<PTestMultiMgrsRightChild> AllocPTestMultiMgrsRightChild()
+ final override;
+
+ IPCResult RecvCheck() final override;
+
+ ~TestMultiMgrsChild() = default;
+};
+
+class TestMultiMgrsLeftParent : public PTestMultiMgrsLeftParent {
+ NS_INLINE_DECL_REFCOUNTING(TestMultiMgrsLeftParent, override)
+ public:
+ bool HasChild(PTestMultiMgrsBottomParent* c) {
+ const auto& managed = ManagedPTestMultiMgrsBottomParent();
+ return std::find(managed.begin(), managed.end(), c) != managed.end();
+ }
+
+ private:
+ ~TestMultiMgrsLeftParent() = default;
+};
+
+class TestMultiMgrsLeftChild : public PTestMultiMgrsLeftChild {
+ NS_INLINE_DECL_REFCOUNTING(TestMultiMgrsLeftChild, override)
+ public:
+ bool HasChild(PTestMultiMgrsBottomChild* c) {
+ const auto& managed = ManagedPTestMultiMgrsBottomChild();
+ return std::find(managed.begin(), managed.end(), c) != managed.end();
+ }
+
+ private:
+ already_AddRefed<PTestMultiMgrsBottomChild> AllocPTestMultiMgrsBottomChild()
+ final override {
+ return MakeAndAddRef<TestMultiMgrsBottomChild>();
+ }
+
+ IPCResult RecvPTestMultiMgrsBottomConstructor(
+ PTestMultiMgrsBottomChild* actor) final override {
+ static_cast<TestMultiMgrsChild*>(Manager())->mBottomL = actor;
+ return IPC_OK();
+ }
+
+ ~TestMultiMgrsLeftChild() = default;
+};
+
+class TestMultiMgrsRightParent : public PTestMultiMgrsRightParent {
+ NS_INLINE_DECL_REFCOUNTING(TestMultiMgrsRightParent, override)
+ public:
+ bool HasChild(PTestMultiMgrsBottomParent* c) {
+ const auto& managed = ManagedPTestMultiMgrsBottomParent();
+ return std::find(managed.begin(), managed.end(), c) != managed.end();
+ }
+
+ private:
+ ~TestMultiMgrsRightParent() = default;
+};
+
+class TestMultiMgrsRightChild : public PTestMultiMgrsRightChild {
+ NS_INLINE_DECL_REFCOUNTING(TestMultiMgrsRightChild, override)
+ public:
+ bool HasChild(PTestMultiMgrsBottomChild* c) {
+ const auto& managed = ManagedPTestMultiMgrsBottomChild();
+ return std::find(managed.begin(), managed.end(), c) != managed.end();
+ }
+
+ private:
+ already_AddRefed<PTestMultiMgrsBottomChild> AllocPTestMultiMgrsBottomChild()
+ final override {
+ return MakeAndAddRef<TestMultiMgrsBottomChild>();
+ }
+
+ IPCResult RecvPTestMultiMgrsBottomConstructor(
+ PTestMultiMgrsBottomChild* actor) final override {
+ static_cast<TestMultiMgrsChild*>(Manager())->mBottomR = actor;
+ return IPC_OK();
+ }
+
+ ~TestMultiMgrsRightChild() = default;
+};
+
+class TestMultiMgrsParent : public PTestMultiMgrsParent {
+ NS_INLINE_DECL_REFCOUNTING(TestMultiMgrsParent, override)
+ private:
+ IPCResult RecvOK() final override {
+ Close();
+ return IPC_OK();
+ }
+
+ ~TestMultiMgrsParent() = default;
+};
+
+already_AddRefed<PTestMultiMgrsLeftChild>
+TestMultiMgrsChild::AllocPTestMultiMgrsLeftChild() {
+ return MakeAndAddRef<TestMultiMgrsLeftChild>();
+}
+
+already_AddRefed<PTestMultiMgrsRightChild>
+TestMultiMgrsChild::AllocPTestMultiMgrsRightChild() {
+ return MakeAndAddRef<TestMultiMgrsRightChild>();
+}
+
+IPCResult TestMultiMgrsChild::RecvCheck() {
+ EXPECT_EQ(ManagedPTestMultiMgrsLeftChild().Count(), (uint32_t)1)
+ << "where's leftie?";
+ EXPECT_EQ(ManagedPTestMultiMgrsRightChild().Count(), (uint32_t)1)
+ << "where's rightie?";
+
+ TestMultiMgrsLeftChild* leftie = static_cast<TestMultiMgrsLeftChild*>(
+ LoneManagedOrNullAsserts(ManagedPTestMultiMgrsLeftChild()));
+ TestMultiMgrsRightChild* rightie = static_cast<TestMultiMgrsRightChild*>(
+ LoneManagedOrNullAsserts(ManagedPTestMultiMgrsRightChild()));
+
+ EXPECT_TRUE(leftie->HasChild(mBottomL))
+ << "leftie didn't have a child it was supposed to!";
+ EXPECT_FALSE(leftie->HasChild(mBottomR)) << "leftie had rightie's child!";
+
+ EXPECT_TRUE(rightie->HasChild(mBottomR))
+ << "rightie didn't have a child it was supposed to!";
+ EXPECT_FALSE(rightie->HasChild(mBottomL)) << "rightie had leftie's child!";
+
+ EXPECT_TRUE(SendOK()) << "couldn't send OK()";
+
+ return IPC_OK();
+}
+
+IPDL_TEST(TestMultiMgrs) {
+ auto leftie = MakeRefPtr<TestMultiMgrsLeftParent>();
+ EXPECT_TRUE(mActor->SendPTestMultiMgrsLeftConstructor(leftie))
+ << "error sending ctor";
+
+ auto rightie = MakeRefPtr<TestMultiMgrsRightParent>();
+ EXPECT_TRUE(mActor->SendPTestMultiMgrsRightConstructor(rightie))
+ << "error sending ctor";
+
+ auto bottomL = MakeRefPtr<TestMultiMgrsBottomParent>();
+ EXPECT_TRUE(leftie->SendPTestMultiMgrsBottomConstructor(bottomL))
+ << "error sending ctor";
+
+ auto bottomR = MakeRefPtr<TestMultiMgrsBottomParent>();
+ EXPECT_TRUE(rightie->SendPTestMultiMgrsBottomConstructor(bottomR))
+ << "error sending ctor";
+
+ EXPECT_TRUE(leftie->HasChild(bottomL))
+ << "leftie didn't have a child it was supposed to!";
+ EXPECT_FALSE(leftie->HasChild(bottomR)) << "leftie had rightie's child!";
+
+ EXPECT_TRUE(rightie->HasChild(bottomR))
+ << "rightie didn't have a child it was supposed to!";
+ EXPECT_FALSE(rightie->HasChild(bottomL)) << "rightie had rightie's child!";
+
+ EXPECT_TRUE(mActor->SendCheck()) << "couldn't kick off the child-side check";
+}
+
+} // namespace mozilla::_ipdltest
diff --git a/ipc/ipdl/test/gtest/TestSelfManage.cpp b/ipc/ipdl/test/gtest/TestSelfManage.cpp
new file mode 100644
index 0000000000..6dc1c4b7e4
--- /dev/null
+++ b/ipc/ipdl/test/gtest/TestSelfManage.cpp
@@ -0,0 +1,100 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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/. */
+
+/*
+ * Test that actors can manage other actors of the same type.
+ */
+
+#include "gtest/gtest.h"
+
+#include "mozilla/_ipdltest/IPDLUnitTest.h"
+#include "mozilla/_ipdltest/PTestSelfManageChild.h"
+#include "mozilla/_ipdltest/PTestSelfManageParent.h"
+#include "mozilla/_ipdltest/PTestSelfManageRootChild.h"
+#include "mozilla/_ipdltest/PTestSelfManageRootParent.h"
+
+using namespace mozilla::ipc;
+
+namespace mozilla::_ipdltest {
+
+class TestSelfManageParent : public PTestSelfManageParent {
+ NS_INLINE_DECL_REFCOUNTING(TestSelfManageParent, override)
+ public:
+ ActorDestroyReason mWhy = ActorDestroyReason(-1);
+
+ private:
+ void ActorDestroy(ActorDestroyReason why) final override { mWhy = why; }
+
+ ~TestSelfManageParent() = default;
+};
+
+class TestSelfManageChild : public PTestSelfManageChild {
+ NS_INLINE_DECL_REFCOUNTING(TestSelfManageChild, override)
+ private:
+ already_AddRefed<PTestSelfManageChild> AllocPTestSelfManageChild()
+ final override {
+ return MakeAndAddRef<TestSelfManageChild>();
+ }
+
+ ~TestSelfManageChild() = default;
+};
+
+class TestSelfManageRootParent : public PTestSelfManageRootParent {
+ NS_INLINE_DECL_REFCOUNTING(TestSelfManageRootParent, override)
+ private:
+ ~TestSelfManageRootParent() = default;
+};
+
+class TestSelfManageRootChild : public PTestSelfManageRootChild {
+ NS_INLINE_DECL_REFCOUNTING(TestSelfManageRootChild, override)
+ private:
+ already_AddRefed<PTestSelfManageChild> AllocPTestSelfManageChild()
+ final override {
+ return MakeAndAddRef<TestSelfManageChild>();
+ }
+
+ ~TestSelfManageRootChild() = default;
+};
+
+IPDL_TEST(TestSelfManageRoot) {
+ auto child = MakeRefPtr<TestSelfManageParent>();
+ EXPECT_TRUE(mActor->SendPTestSelfManageConstructor(child));
+
+ EXPECT_EQ(mActor->ManagedPTestSelfManageParent().Count(), 1u);
+
+ {
+ auto childsChild = MakeRefPtr<TestSelfManageParent>();
+ EXPECT_TRUE(child->SendPTestSelfManageConstructor(childsChild));
+
+ EXPECT_EQ(mActor->ManagedPTestSelfManageParent().Count(), 1u);
+ EXPECT_EQ(child->ManagedPTestSelfManageParent().Count(), 1u);
+
+ EXPECT_TRUE(PTestSelfManageParent::Send__delete__(childsChild));
+
+ EXPECT_EQ(childsChild->mWhy, IProtocol::Deletion);
+ EXPECT_EQ(mActor->ManagedPTestSelfManageParent().Count(), 1u);
+ EXPECT_EQ(child->ManagedPTestSelfManageParent().Count(), 0u);
+ }
+
+ {
+ auto childsChild = MakeRefPtr<TestSelfManageParent>();
+ EXPECT_TRUE(child->SendPTestSelfManageConstructor(childsChild));
+
+ EXPECT_EQ(mActor->ManagedPTestSelfManageParent().Count(), 1u);
+ EXPECT_EQ(child->ManagedPTestSelfManageParent().Count(), 1u);
+
+ EXPECT_TRUE(PTestSelfManageParent::Send__delete__(child));
+
+ EXPECT_EQ(child->mWhy, IProtocol::Deletion);
+ EXPECT_EQ(childsChild->mWhy, IProtocol::AncestorDeletion);
+ EXPECT_EQ(mActor->ManagedPTestSelfManageParent().Count(), 0u);
+ EXPECT_EQ(child->ManagedPTestSelfManageParent().Count(), 0u);
+ }
+
+ mActor->Close();
+}
+
+} // namespace mozilla::_ipdltest
diff --git a/ipc/ipdl/test/gtest/TestShmem.cpp b/ipc/ipdl/test/gtest/TestShmem.cpp
new file mode 100644
index 0000000000..e08bcee179
--- /dev/null
+++ b/ipc/ipdl/test/gtest/TestShmem.cpp
@@ -0,0 +1,122 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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/. */
+
+/*
+ * Test sending and receiving Shmem values.
+ */
+
+#include "gtest/gtest.h"
+
+#include "mozilla/_ipdltest/IPDLUnitTest.h"
+#include "mozilla/_ipdltest/PTestShmemChild.h"
+#include "mozilla/_ipdltest/PTestShmemParent.h"
+
+using namespace mozilla::ipc;
+
+namespace mozilla::_ipdltest {
+
+class TestShmemParent : public PTestShmemParent {
+ NS_INLINE_DECL_REFCOUNTING(TestShmemParent, override)
+ private:
+ IPCResult RecvTake(Shmem&& mem, Shmem&& unsafe,
+ const uint32_t& expectedSize) final override {
+ EXPECT_EQ(mem.Size<char>(), expectedSize)
+ << "expected shmem size " << expectedSize << ", but it has size "
+ << mem.Size<char>();
+ EXPECT_EQ(unsafe.Size<char>(), expectedSize)
+ << "expected shmem size " << expectedSize << ", but it has size "
+ << unsafe.Size<char>();
+
+ EXPECT_FALSE(strcmp(mem.get<char>(), "And yourself!"))
+ << "expected message was not written";
+ EXPECT_FALSE(strcmp(unsafe.get<char>(), "And yourself!"))
+ << "expected message was not written";
+
+ EXPECT_TRUE(DeallocShmem(mem));
+ EXPECT_TRUE(DeallocShmem(unsafe));
+
+ Close();
+
+ return IPC_OK();
+ }
+
+ ~TestShmemParent() = default;
+};
+
+class TestShmemChild : public PTestShmemChild {
+ NS_INLINE_DECL_REFCOUNTING(TestShmemChild, override)
+ private:
+ IPCResult RecvGive(Shmem&& mem, Shmem&& unsafe,
+ const uint32_t& expectedSize) final override {
+ EXPECT_EQ(mem.Size<char>(), expectedSize)
+ << "expected shmem size " << expectedSize << ", but it has size "
+ << mem.Size<char>();
+ EXPECT_EQ(unsafe.Size<char>(), expectedSize)
+ << "expected shmem size " << expectedSize << ", but it has size "
+ << unsafe.Size<char>();
+
+ EXPECT_FALSE(strcmp(mem.get<char>(), "Hello!"))
+ << "expected message was not written";
+ EXPECT_FALSE(strcmp(unsafe.get<char>(), "Hello!"))
+ << "expected message was not written";
+
+ char* unsafeptr = unsafe.get<char>();
+
+ memcpy(mem.get<char>(), "And yourself!", sizeof("And yourself!"));
+ memcpy(unsafeptr, "And yourself!", sizeof("And yourself!"));
+
+ Shmem unsafecopy = unsafe;
+ EXPECT_TRUE(SendTake(std::move(mem), std::move(unsafe), expectedSize));
+
+ // these checks also shouldn't fail in the child
+ char uc1 = *unsafeptr;
+ (void)uc1;
+ char uc2 = *unsafecopy.get<char>();
+ (void)uc2;
+
+ return IPC_OK();
+ }
+
+ ~TestShmemChild() = default;
+};
+
+IPDL_TEST(TestShmem) {
+ Shmem mem;
+ Shmem unsafe;
+
+ uint32_t size = 12345;
+ EXPECT_TRUE(mActor->AllocShmem(size, &mem)) << "can't alloc shmem";
+ EXPECT_TRUE(mActor->AllocUnsafeShmem(size, &unsafe)) << "can't alloc shmem";
+
+ EXPECT_EQ(mem.Size<char>(), size) << "shmem is wrong size: expected " << size
+ << ", got " << mem.Size<char>();
+ EXPECT_EQ(unsafe.Size<char>(), size)
+ << "shmem is wrong size: expected " << size << ", got "
+ << unsafe.Size<char>();
+
+ char* ptr = mem.get<char>();
+ memcpy(ptr, "Hello!", sizeof("Hello!"));
+
+ char* unsafeptr = unsafe.get<char>();
+ memcpy(unsafeptr, "Hello!", sizeof("Hello!"));
+
+ Shmem unsafecopy = unsafe;
+ EXPECT_TRUE(mActor->SendGive(std::move(mem), std::move(unsafe), size));
+
+ // uncomment the following line for a (nondeterministic) surprise!
+ // char c1 = *ptr; (void)c1;
+
+ // uncomment the following line for a deterministic surprise!
+ // char c2 = *mem.get<char>(); (void)c2;
+
+ // unsafe shmem gets rid of those checks
+ char uc1 = *unsafeptr;
+ (void)uc1;
+ char uc2 = *unsafecopy.get<char>();
+ (void)uc2;
+}
+
+} // namespace mozilla::_ipdltest
diff --git a/ipc/ipdl/test/gtest/TestSyncError.cpp b/ipc/ipdl/test/gtest/TestSyncError.cpp
new file mode 100644
index 0000000000..f7a85598a6
--- /dev/null
+++ b/ipc/ipdl/test/gtest/TestSyncError.cpp
@@ -0,0 +1,44 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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/. */
+
+/*
+ * Test what happens when a sync message fails.
+ */
+
+#include "gtest/gtest.h"
+
+#include "mozilla/_ipdltest/IPDLUnitTest.h"
+#include "mozilla/_ipdltest/PTestSyncErrorChild.h"
+#include "mozilla/_ipdltest/PTestSyncErrorParent.h"
+
+using namespace mozilla::ipc;
+
+namespace mozilla::_ipdltest {
+
+class TestSyncErrorParent : public PTestSyncErrorParent {
+ NS_INLINE_DECL_REFCOUNTING(TestSyncErrorParent, override)
+ private:
+ IPCResult RecvError() final override { return IPC_TEST_FAIL(this); }
+
+ ~TestSyncErrorParent() = default;
+};
+
+class TestSyncErrorChild : public PTestSyncErrorChild {
+ NS_INLINE_DECL_REFCOUNTING(TestSyncErrorChild, override)
+ private:
+ IPCResult RecvStart() final override {
+ EXPECT_FALSE(SendError()) << "Error() should have return false";
+
+ Close();
+
+ return IPC_OK();
+ }
+ ~TestSyncErrorChild() = default;
+};
+
+IPDL_TEST(TestSyncError) { EXPECT_TRUE(mActor->SendStart()); }
+
+} // namespace mozilla::_ipdltest
diff --git a/ipc/ipdl/test/gtest/TestUniquePtrIPC.cpp b/ipc/ipdl/test/gtest/TestUniquePtrIPC.cpp
new file mode 100644
index 0000000000..52ca322f8e
--- /dev/null
+++ b/ipc/ipdl/test/gtest/TestUniquePtrIPC.cpp
@@ -0,0 +1,80 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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/. */
+
+/*
+ * Test UniquePtr IPC arguments.
+ */
+
+#include "gtest/gtest.h"
+
+#include "mozilla/_ipdltest/IPDLUnitTest.h"
+#include "mozilla/_ipdltest/PTestUniquePtrIPCChild.h"
+#include "mozilla/_ipdltest/PTestUniquePtrIPCParent.h"
+
+using namespace mozilla::ipc;
+
+namespace mozilla::_ipdltest {
+
+class TestUniquePtrIPCParent : public PTestUniquePtrIPCParent {
+ NS_INLINE_DECL_REFCOUNTING(TestUniquePtrIPCParent, override)
+ private:
+ ~TestUniquePtrIPCParent() = default;
+};
+
+class TestUniquePtrIPCChild : public PTestUniquePtrIPCChild {
+ NS_INLINE_DECL_REFCOUNTING(TestUniquePtrIPCChild, override)
+ private:
+ IPCResult RecvTestMessage(const UniquePtr<int>& aA1,
+ const UniquePtr<DummyStruct>& aA2,
+ const DummyStruct& aA3,
+ const UniquePtr<int>& aA4) final override {
+ EXPECT_TRUE(aA1) << "TestMessage received NULL aA1";
+ EXPECT_TRUE(aA2) << "TestMessage received NULL aA2";
+ EXPECT_FALSE(aA4)
+ << "TestMessage received non-NULL when expecting NULL aA4";
+
+ EXPECT_EQ(*aA1, 1);
+ EXPECT_EQ(aA2->x(), 2);
+ EXPECT_EQ(aA3.x(), 3);
+
+ return IPC_OK();
+ }
+
+ IPCResult RecvTestSendReference(
+ const UniquePtr<DummyStruct>& aA) final override {
+ EXPECT_TRUE(aA) << "TestSendReference received NULL item in child";
+ EXPECT_EQ(aA->x(), 1);
+
+ Close();
+ return IPC_OK();
+ }
+
+ ~TestUniquePtrIPCChild() = default;
+};
+
+IPDL_TEST(TestUniquePtrIPC) {
+ UniquePtr<int> a1 = MakeUnique<int>(1);
+ UniquePtr<DummyStruct> a2 = MakeUnique<DummyStruct>(2);
+ DummyStruct a3(3);
+ UniquePtr<int> a4;
+
+ EXPECT_TRUE(mActor->SendTestMessage(a1, a2, a3, a4));
+
+ EXPECT_TRUE(a1)
+ << "IPC arguments are passed by const reference and shouldn't be moved";
+ EXPECT_TRUE(a2)
+ << "IPC arguments are passed by const reference and shouldn't be moved";
+
+ EXPECT_FALSE(a4) << "somehow turned null ptr into non-null by sending it";
+
+ // Pass UniquePtr by reference
+ UniquePtr<DummyStruct> b = MakeUnique<DummyStruct>(1);
+
+ EXPECT_TRUE(mActor->SendTestSendReference(b));
+ EXPECT_TRUE(b)
+ << "IPC arguments are passed by const reference and shouldn't be moved";
+}
+
+} // namespace mozilla::_ipdltest
diff --git a/ipc/ipdl/test/gtest/TestUrgency.cpp b/ipc/ipdl/test/gtest/TestUrgency.cpp
new file mode 100644
index 0000000000..a4f7d0ea3e
--- /dev/null
+++ b/ipc/ipdl/test/gtest/TestUrgency.cpp
@@ -0,0 +1,115 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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/. */
+
+/*
+ * Test that sync messages preempt other messages in the expected way.
+ */
+
+#include "gtest/gtest.h"
+
+#include "mozilla/_ipdltest/IPDLUnitTest.h"
+#include "mozilla/_ipdltest/PTestUrgencyChild.h"
+#include "mozilla/_ipdltest/PTestUrgencyParent.h"
+
+using namespace mozilla::ipc;
+
+namespace mozilla::_ipdltest {
+
+enum {
+ kFirstTestBegin = 1,
+ kFirstTestGotReply,
+ kSecondTestBegin,
+ kSecondTestGotReply,
+};
+
+class TestUrgencyParent : public PTestUrgencyParent {
+ NS_INLINE_DECL_REFCOUNTING(TestUrgencyParent, override)
+ private:
+ IPCResult RecvTest1(uint32_t* value) final override {
+ EXPECT_TRUE(SendReply1(value));
+ EXPECT_EQ(*value, (uint32_t)99) << "unexpected value";
+ return IPC_OK();
+ }
+
+ IPCResult RecvTest2() final override {
+ uint32_t value;
+ inreply_ = true;
+ EXPECT_TRUE(SendReply2(&value));
+ inreply_ = false;
+ EXPECT_EQ(value, (uint32_t)500) << "unexpected value";
+ return IPC_OK();
+ }
+
+ IPCResult RecvTest3(uint32_t* value) final override {
+ EXPECT_FALSE(inreply_) << "nested non-urgent on top of urgent message";
+ *value = 1000;
+ return IPC_OK();
+ }
+
+ IPCResult RecvFinalTest_Begin() final override { return IPC_OK(); }
+
+ ~TestUrgencyParent() = default;
+
+ bool inreply_ = false;
+};
+
+class TestUrgencyChild : public PTestUrgencyChild {
+ NS_INLINE_DECL_REFCOUNTING(TestUrgencyChild, override)
+ private:
+ IPCResult RecvStart() final override {
+ uint32_t result;
+
+ // Send a synchronous message, expect to get an urgent message while
+ // blocked.
+ test_ = kFirstTestBegin;
+ EXPECT_TRUE(SendTest1(&result));
+ EXPECT_EQ(result, (uint32_t)99) << "wrong value from SendTest1";
+ EXPECT_EQ(test_, kFirstTestGotReply)
+ << "never received first urgent message";
+
+ // Initiate the next test by sending an asynchronous message, then becoming
+ // blocked. This tests that the urgent message is still delivered properly,
+ // and that the parent does not try to service the sync
+ test_ = kSecondTestBegin;
+ EXPECT_TRUE(SendTest2());
+ EXPECT_TRUE(SendTest3(&result));
+ EXPECT_EQ(test_, kSecondTestGotReply)
+ << "never received second urgent message";
+ EXPECT_EQ(result, (uint32_t)1000) << "wrong value from SendTest3";
+
+ EXPECT_TRUE(SendFinalTest_Begin());
+
+ Close();
+
+ return IPC_OK();
+ }
+
+ IPCResult RecvReply1(uint32_t* reply) final override {
+ EXPECT_EQ(test_, kFirstTestBegin) << "wrong test state in RecvReply1";
+
+ *reply = 99;
+ test_ = kFirstTestGotReply;
+ return IPC_OK();
+ }
+
+ IPCResult RecvReply2(uint32_t* reply) final override {
+ EXPECT_EQ(test_, kSecondTestBegin) << "wrong test state in RecvReply2";
+
+ *reply = 500;
+ test_ = kSecondTestGotReply;
+ return IPC_OK();
+ }
+
+ ~TestUrgencyChild() = default;
+
+ uint32_t test_ = 0;
+};
+
+// Only run cross-process because we need to send nested sync messages (this can
+// only be done from the main thread).
+IPDL_TEST_ON(CROSSPROCESS, TestUrgency) { EXPECT_TRUE(mActor->SendStart()); }
+
+} // namespace mozilla::_ipdltest
diff --git a/ipc/ipdl/test/gtest/moz.build b/ipc/ipdl/test/gtest/moz.build
index 129e366a4b..86fa2eca9e 100644
--- a/ipc/ipdl/test/gtest/moz.build
+++ b/ipc/ipdl/test/gtest/moz.build
@@ -16,18 +16,59 @@ EXPORTS.mozilla._ipdltest += [
SOURCES += [
"IPDLUnitTest.cpp",
+ "TestAsyncReturns.cpp",
"TestBasic.cpp",
+ "TestCancel.cpp",
"TestCrossProcessSemaphore.cpp",
+ "TestDataStructures.cpp",
+ "TestDescendant.cpp",
+ "TestEndpointOpens.cpp",
+ "TestHangs.cpp",
"TestInduceConnectionError.cpp",
+ "TestJSON.cpp",
+ "TestManyChildAllocs.cpp",
"TestManyHandles.cpp",
+ "TestMostNested.cpp",
+ "TestMultiMgrs.cpp",
+ "TestSelfManage.cpp",
+ "TestShmem.cpp",
+ "TestSyncError.cpp",
+ "TestUniquePtrIPC.cpp",
+ "TestUrgency.cpp",
]
IPDL_SOURCES += [
"PIPDLUnitTest.ipdl",
+ "PTestAsyncReturns.ipdl",
"PTestBasic.ipdl",
+ "PTestCancel.ipdl",
"PTestCrossProcessSemaphore.ipdl",
+ "PTestDataStructures.ipdl",
+ "PTestDataStructuresCommon.ipdlh",
+ "PTestDataStructuresSub.ipdl",
+ "PTestDescendant.ipdl",
+ "PTestDescendantSub.ipdl",
+ "PTestDescendantSubsub.ipdl",
+ "PTestEndpointOpens.ipdl",
+ "PTestEndpointOpensOpened.ipdl",
+ "PTestHangs.ipdl",
"PTestInduceConnectionError.ipdl",
+ "PTestJSON.ipdl",
+ "PTestJSONHandle.ipdl",
+ "PTestManyChildAllocs.ipdl",
+ "PTestManyChildAllocsSub.ipdl",
"PTestManyHandles.ipdl",
+ "PTestMostNested.ipdl",
+ "PTestMultiMgrs.ipdl",
+ "PTestMultiMgrsBottom.ipdl",
+ "PTestMultiMgrsLeft.ipdl",
+ "PTestMultiMgrsRight.ipdl",
+ "PTestSelfManage.ipdl",
+ "PTestSelfManageRoot.ipdl",
+ "PTestShmem.ipdl",
+ "PTestSyncError.ipdl",
+ "PTestUniquePtrIPC.ipdl",
+ "PTestUrgency.ipdl",
]
include("/ipc/chromium/chromium-config.mozbuild")