summaryrefslogtreecommitdiffstats
path: root/ipc/ipdl/test
diff options
context:
space:
mode:
Diffstat (limited to 'ipc/ipdl/test')
-rw-r--r--ipc/ipdl/test/README.txt13
-rw-r--r--ipc/ipdl/test/cxx/IPDLUnitTestProcessChild.cpp27
-rw-r--r--ipc/ipdl/test/cxx/IPDLUnitTestProcessChild.h28
-rw-r--r--ipc/ipdl/test/cxx/IPDLUnitTestSubprocess.cpp19
-rw-r--r--ipc/ipdl/test/cxx/IPDLUnitTestSubprocess.h34
-rw-r--r--ipc/ipdl/test/cxx/IPDLUnitTestTypes.h43
-rw-r--r--ipc/ipdl/test/cxx/IPDLUnitTestUtils.h28
-rw-r--r--ipc/ipdl/test/cxx/IPDLUnitTests.h85
-rw-r--r--ipc/ipdl/test/cxx/IPDLUnitTests.template.cpp345
-rw-r--r--ipc/ipdl/test/cxx/Makefile.in45
-rw-r--r--ipc/ipdl/test/cxx/PTestActorPunning.ipdl28
-rw-r--r--ipc/ipdl/test/cxx/PTestActorPunningPunned.ipdl18
-rw-r--r--ipc/ipdl/test/cxx/PTestActorPunningSub.ipdl19
-rw-r--r--ipc/ipdl/test/cxx/PTestAsyncReturns.ipdl20
-rw-r--r--ipc/ipdl/test/cxx/PTestBadActor.ipdl21
-rw-r--r--ipc/ipdl/test/cxx/PTestBadActorSub.ipdl20
-rw-r--r--ipc/ipdl/test/cxx/PTestCancel.ipdl39
-rw-r--r--ipc/ipdl/test/cxx/PTestCrashCleanup.ipdl20
-rw-r--r--ipc/ipdl/test/cxx/PTestDataStructures.ipdl109
-rw-r--r--ipc/ipdl/test/cxx/PTestDataStructuresCommon.ipdlh107
-rw-r--r--ipc/ipdl/test/cxx/PTestDataStructuresSub.ipdl18
-rw-r--r--ipc/ipdl/test/cxx/PTestDemon.ipdl24
-rw-r--r--ipc/ipdl/test/cxx/PTestDesc.ipdl24
-rw-r--r--ipc/ipdl/test/cxx/PTestDescSub.ipdl21
-rw-r--r--ipc/ipdl/test/cxx/PTestDescSubsub.ipdl18
-rw-r--r--ipc/ipdl/test/cxx/PTestEndpointBridgeMain.ipdl25
-rw-r--r--ipc/ipdl/test/cxx/PTestEndpointBridgeMainSub.ipdl28
-rw-r--r--ipc/ipdl/test/cxx/PTestEndpointBridgeSub.ipdl25
-rw-r--r--ipc/ipdl/test/cxx/PTestEndpointOpens.ipdl22
-rw-r--r--ipc/ipdl/test/cxx/PTestEndpointOpensOpened.ipdl25
-rw-r--r--ipc/ipdl/test/cxx/PTestFailedCtor.ipdl17
-rw-r--r--ipc/ipdl/test/cxx/PTestFailedCtorSub.ipdl21
-rw-r--r--ipc/ipdl/test/cxx/PTestFailedCtorSubsub.ipdl18
-rw-r--r--ipc/ipdl/test/cxx/PTestHandle.ipdl17
-rw-r--r--ipc/ipdl/test/cxx/PTestHangs.ipdl22
-rw-r--r--ipc/ipdl/test/cxx/PTestHighestPrio.ipdl21
-rw-r--r--ipc/ipdl/test/cxx/PTestIndirectProtocolParam.ipdlh15
-rw-r--r--ipc/ipdl/test/cxx/PTestIndirectProtocolParamFirst.ipdl20
-rw-r--r--ipc/ipdl/test/cxx/PTestIndirectProtocolParamManage.ipdl18
-rw-r--r--ipc/ipdl/test/cxx/PTestIndirectProtocolParamSecond.ipdl14
-rw-r--r--ipc/ipdl/test/cxx/PTestInterruptErrorCleanup.ipdl14
-rw-r--r--ipc/ipdl/test/cxx/PTestInterruptRaces.ipdl27
-rw-r--r--ipc/ipdl/test/cxx/PTestInterruptShutdownRace.ipdl19
-rw-r--r--ipc/ipdl/test/cxx/PTestJSON.ipdl49
-rw-r--r--ipc/ipdl/test/cxx/PTestLatency.ipdl28
-rw-r--r--ipc/ipdl/test/cxx/PTestManyChildAllocs.ipdl22
-rw-r--r--ipc/ipdl/test/cxx/PTestManyChildAllocsSub.ipdl22
-rw-r--r--ipc/ipdl/test/cxx/PTestMultiMgrs.ipdl25
-rw-r--r--ipc/ipdl/test/cxx/PTestMultiMgrsBottom.ipdl18
-rw-r--r--ipc/ipdl/test/cxx/PTestMultiMgrsLeft.ipdl21
-rw-r--r--ipc/ipdl/test/cxx/PTestMultiMgrsRight.ipdl21
-rw-r--r--ipc/ipdl/test/cxx/PTestNestedLoops.ipdl22
-rw-r--r--ipc/ipdl/test/cxx/PTestPaintThread.ipdl15
-rw-r--r--ipc/ipdl/test/cxx/PTestPriority.ipdl24
-rw-r--r--ipc/ipdl/test/cxx/PTestRPC.ipdl24
-rw-r--r--ipc/ipdl/test/cxx/PTestRaceDeadlock.ipdl23
-rw-r--r--ipc/ipdl/test/cxx/PTestRaceDeferral.ipdl22
-rw-r--r--ipc/ipdl/test/cxx/PTestRacyInterruptReplies.ipdl20
-rw-r--r--ipc/ipdl/test/cxx/PTestRacyReentry.ipdl23
-rw-r--r--ipc/ipdl/test/cxx/PTestRacyUndefer.ipdl30
-rw-r--r--ipc/ipdl/test/cxx/PTestSanity.ipdl21
-rw-r--r--ipc/ipdl/test/cxx/PTestSelfManage.ipdl21
-rw-r--r--ipc/ipdl/test/cxx/PTestSelfManageRoot.ipdl20
-rw-r--r--ipc/ipdl/test/cxx/PTestShmem.ipdl17
-rw-r--r--ipc/ipdl/test/cxx/PTestShutdown.ipdl29
-rw-r--r--ipc/ipdl/test/cxx/PTestShutdownSub.ipdl23
-rw-r--r--ipc/ipdl/test/cxx/PTestShutdownSubsub.ipdl17
-rw-r--r--ipc/ipdl/test/cxx/PTestStackHooks.ipdl28
-rw-r--r--ipc/ipdl/test/cxx/PTestSyncError.ipdl20
-rw-r--r--ipc/ipdl/test/cxx/PTestSyncHang.ipdl16
-rw-r--r--ipc/ipdl/test/cxx/PTestSyncWakeup.ipdl23
-rw-r--r--ipc/ipdl/test/cxx/PTestUniquePtrIPC.ipdl26
-rw-r--r--ipc/ipdl/test/cxx/PTestUrgency.ipdl22
-rw-r--r--ipc/ipdl/test/cxx/PTestUrgentHangs.ipdl31
-rw-r--r--ipc/ipdl/test/cxx/README.txt61
-rw-r--r--ipc/ipdl/test/cxx/TestActorPunning.cpp125
-rw-r--r--ipc/ipdl/test/cxx/TestActorPunning.h100
-rw-r--r--ipc/ipdl/test/cxx/TestAsyncReturns.cpp101
-rw-r--r--ipc/ipdl/test/cxx/TestAsyncReturns.h54
-rw-r--r--ipc/ipdl/test/cxx/TestBadActor.cpp59
-rw-r--r--ipc/ipdl/test/cxx/TestBadActor.h84
-rw-r--r--ipc/ipdl/test/cxx/TestCancel.cpp115
-rw-r--r--ipc/ipdl/test/cxx/TestCancel.h54
-rw-r--r--ipc/ipdl/test/cxx/TestCrashCleanup.cpp100
-rw-r--r--ipc/ipdl/test/cxx/TestCrashCleanup.h49
-rw-r--r--ipc/ipdl/test/cxx/TestDataStructures.cpp888
-rw-r--r--ipc/ipdl/test/cxx/TestDataStructures.h180
-rw-r--r--ipc/ipdl/test/cxx/TestDemon.cpp362
-rw-r--r--ipc/ipdl/test/cxx/TestDemon.h91
-rw-r--r--ipc/ipdl/test/cxx/TestDesc.cpp78
-rw-r--r--ipc/ipdl/test/cxx/TestDesc.h115
-rw-r--r--ipc/ipdl/test/cxx/TestEndpointBridgeMain.cpp226
-rw-r--r--ipc/ipdl/test/cxx/TestEndpointBridgeMain.h132
-rw-r--r--ipc/ipdl/test/cxx/TestEndpointOpens.cpp242
-rw-r--r--ipc/ipdl/test/cxx/TestEndpointOpens.h102
-rw-r--r--ipc/ipdl/test/cxx/TestFailedCtor.cpp112
-rw-r--r--ipc/ipdl/test/cxx/TestFailedCtor.h127
-rw-r--r--ipc/ipdl/test/cxx/TestHangs.cpp127
-rw-r--r--ipc/ipdl/test/cxx/TestHangs.h75
-rw-r--r--ipc/ipdl/test/cxx/TestHighestPrio.cpp91
-rw-r--r--ipc/ipdl/test/cxx/TestHighestPrio.h55
-rw-r--r--ipc/ipdl/test/cxx/TestInterruptErrorCleanup.cpp138
-rw-r--r--ipc/ipdl/test/cxx/TestInterruptErrorCleanup.h52
-rw-r--r--ipc/ipdl/test/cxx/TestInterruptRaces.cpp169
-rw-r--r--ipc/ipdl/test/cxx/TestInterruptRaces.h104
-rw-r--r--ipc/ipdl/test/cxx/TestInterruptShutdownRace.cpp111
-rw-r--r--ipc/ipdl/test/cxx/TestInterruptShutdownRace.h56
-rw-r--r--ipc/ipdl/test/cxx/TestJSON.cpp113
-rw-r--r--ipc/ipdl/test/cxx/TestJSON.h93
-rw-r--r--ipc/ipdl/test/cxx/TestLatency.cpp210
-rw-r--r--ipc/ipdl/test/cxx/TestLatency.h107
-rw-r--r--ipc/ipdl/test/cxx/TestManyChildAllocs.cpp83
-rw-r--r--ipc/ipdl/test/cxx/TestManyChildAllocs.h82
-rw-r--r--ipc/ipdl/test/cxx/TestMultiMgrs.cpp83
-rw-r--r--ipc/ipdl/test/cxx/TestMultiMgrs.h222
-rw-r--r--ipc/ipdl/test/cxx/TestNestedLoops.cpp78
-rw-r--r--ipc/ipdl/test/cxx/TestNestedLoops.h59
-rw-r--r--ipc/ipdl/test/cxx/TestRPC.cpp107
-rw-r--r--ipc/ipdl/test/cxx/TestRPC.h60
-rw-r--r--ipc/ipdl/test/cxx/TestRaceDeadlock.cpp102
-rw-r--r--ipc/ipdl/test/cxx/TestRaceDeadlock.h68
-rw-r--r--ipc/ipdl/test/cxx/TestRaceDeferral.cpp84
-rw-r--r--ipc/ipdl/test/cxx/TestRaceDeferral.h67
-rw-r--r--ipc/ipdl/test/cxx/TestRacyInterruptReplies.cpp94
-rw-r--r--ipc/ipdl/test/cxx/TestRacyInterruptReplies.h65
-rw-r--r--ipc/ipdl/test/cxx/TestRacyReentry.cpp63
-rw-r--r--ipc/ipdl/test/cxx/TestRacyReentry.h59
-rw-r--r--ipc/ipdl/test/cxx/TestRacyUndefer.cpp83
-rw-r--r--ipc/ipdl/test/cxx/TestRacyUndefer.h62
-rw-r--r--ipc/ipdl/test/cxx/TestSanity.cpp52
-rw-r--r--ipc/ipdl/test/cxx/TestSanity.h55
-rw-r--r--ipc/ipdl/test/cxx/TestSelfManageRoot.cpp54
-rw-r--r--ipc/ipdl/test/cxx/TestSelfManageRoot.h117
-rw-r--r--ipc/ipdl/test/cxx/TestShmem.cpp106
-rw-r--r--ipc/ipdl/test/cxx/TestShmem.h55
-rw-r--r--ipc/ipdl/test/cxx/TestShutdown.cpp185
-rw-r--r--ipc/ipdl/test/cxx/TestShutdown.h168
-rw-r--r--ipc/ipdl/test/cxx/TestStackHooks.cpp122
-rw-r--r--ipc/ipdl/test/cxx/TestStackHooks.h107
-rw-r--r--ipc/ipdl/test/cxx/TestSyncError.cpp45
-rw-r--r--ipc/ipdl/test/cxx/TestSyncError.h61
-rw-r--r--ipc/ipdl/test/cxx/TestSyncHang.cpp62
-rw-r--r--ipc/ipdl/test/cxx/TestSyncHang.h50
-rw-r--r--ipc/ipdl/test/cxx/TestSyncWakeup.cpp106
-rw-r--r--ipc/ipdl/test/cxx/TestSyncWakeup.h66
-rw-r--r--ipc/ipdl/test/cxx/TestUniquePtrIPC.cpp81
-rw-r--r--ipc/ipdl/test/cxx/TestUniquePtrIPC.h61
-rw-r--r--ipc/ipdl/test/cxx/TestUrgency.cpp117
-rw-r--r--ipc/ipdl/test/cxx/TestUrgency.h57
-rw-r--r--ipc/ipdl/test/cxx/TestUrgentHangs.cpp174
-rw-r--r--ipc/ipdl/test/cxx/TestUrgentHangs.h64
-rw-r--r--ipc/ipdl/test/cxx/app/TestIPDL.cpp24
-rw-r--r--ipc/ipdl/test/cxx/app/moz.build20
-rw-r--r--ipc/ipdl/test/cxx/genIPDLUnitTests.py193
-rw-r--r--ipc/ipdl/test/cxx/moz.build172
-rw-r--r--ipc/ipdl/test/gtest/IPDLUnitTest.cpp308
-rw-r--r--ipc/ipdl/test/gtest/IPDLUnitTest.h79
-rw-r--r--ipc/ipdl/test/gtest/IPDLUnitTestChild.h32
-rw-r--r--ipc/ipdl/test/gtest/IPDLUnitTestParent.h50
-rw-r--r--ipc/ipdl/test/gtest/PIPDLUnitTest.ipdl34
-rw-r--r--ipc/ipdl/test/gtest/PTestBasic.ipdl15
-rw-r--r--ipc/ipdl/test/gtest/PTestCrossProcessSemaphore.ipdl17
-rw-r--r--ipc/ipdl/test/gtest/PTestInduceConnectionError.ipdl19
-rw-r--r--ipc/ipdl/test/gtest/PTestManyHandles.ipdl15
-rw-r--r--ipc/ipdl/test/gtest/TestBasic.cpp29
-rw-r--r--ipc/ipdl/test/gtest/TestBasicChild.h26
-rw-r--r--ipc/ipdl/test/gtest/TestBasicParent.h23
-rw-r--r--ipc/ipdl/test/gtest/TestCrossProcessSemaphore.cpp63
-rw-r--r--ipc/ipdl/test/gtest/TestInduceConnectionError.cpp95
-rw-r--r--ipc/ipdl/test/gtest/TestManyHandles.cpp78
-rw-r--r--ipc/ipdl/test/gtest/moz.build35
-rw-r--r--ipc/ipdl/test/ipdl/IPDLCompile.py78
-rw-r--r--ipc/ipdl/test/ipdl/Makefile.in17
-rw-r--r--ipc/ipdl/test/ipdl/error/AsyncCtorReturns.ipdl11
-rw-r--r--ipc/ipdl/test/ipdl/error/AsyncCtorReturnsManagee.ipdl11
-rw-r--r--ipc/ipdl/test/ipdl/error/AsyncInsideSync.ipdl10
-rw-r--r--ipc/ipdl/test/ipdl/error/ExtendedAttrBadValue.ipdlh5
-rw-r--r--ipc/ipdl/test/ipdl/error/ExtendedAttrEmpty.ipdlh5
-rw-r--r--ipc/ipdl/test/ipdl/error/ExtendedAttrInvalidNestedValue.ipdl7
-rw-r--r--ipc/ipdl/test/ipdl/error/ExtendedAttrInvalidPriorityValue.ipdl7
-rw-r--r--ipc/ipdl/test/ipdl/error/ExtendedAttrRepeated.ipdlh5
-rw-r--r--ipc/ipdl/test/ipdl/error/ExtendedAttrUnknown.ipdlh5
-rw-r--r--ipc/ipdl/test/ipdl/error/ForgottenManagee.ipdl12
-rw-r--r--ipc/ipdl/test/ipdl/error/ForgottenManager.ipdl12
-rw-r--r--ipc/ipdl/test/ipdl/error/InsideCpowToChild.ipdl10
-rw-r--r--ipc/ipdl/test/ipdl/error/IntrAsyncManagee.ipdl9
-rw-r--r--ipc/ipdl/test/ipdl/error/IntrAsyncManager.ipdl10
-rw-r--r--ipc/ipdl/test/ipdl/error/IntrSyncManagee.ipdl9
-rw-r--r--ipc/ipdl/test/ipdl/error/IntrSyncManager.ipdl10
-rw-r--r--ipc/ipdl/test/ipdl/error/ManageeForgot.ipdl12
-rw-r--r--ipc/ipdl/test/ipdl/error/ManagerForgot.ipdl12
-rw-r--r--ipc/ipdl/test/ipdl/error/Nullable.ipdl7
-rw-r--r--ipc/ipdl/test/ipdl/error/Nullable2.ipdl11
-rw-r--r--ipc/ipdl/test/ipdl/error/PBadArrayBase.ipdl8
-rw-r--r--ipc/ipdl/test/ipdl/error/PBadNestedManagee.ipdl10
-rw-r--r--ipc/ipdl/test/ipdl/error/PBadNestedManager.ipdl10
-rw-r--r--ipc/ipdl/test/ipdl/error/PBadSideImpl.ipdl8
-rw-r--r--ipc/ipdl/test/ipdl/error/PBadUniquePtrBase.ipdl8
-rw-r--r--ipc/ipdl/test/ipdl/error/PCompressInvalid.ipdl9
-rw-r--r--ipc/ipdl/test/ipdl/error/PDouble.ipdl12
-rw-r--r--ipc/ipdl/test/ipdl/error/PExtendedAttrInvalidValue.ipdl7
-rw-r--r--ipc/ipdl/test/ipdl/error/PExtendedAttrRepeated.ipdl7
-rw-r--r--ipc/ipdl/test/ipdl/error/PExtendedAttrUnexpectedValue.ipdl7
-rw-r--r--ipc/ipdl/test/ipdl/error/PExtendedAttrUnknownAttribute.ipdl7
-rw-r--r--ipc/ipdl/test/ipdl/error/PInconsistentMoveOnly.ipdl14
-rw-r--r--ipc/ipdl/test/ipdl/error/PIntrNested.ipdl7
-rw-r--r--ipc/ipdl/test/ipdl/error/PIntrNestedProtocol.ipdl7
-rw-r--r--ipc/ipdl/test/ipdl/error/PIntrPriority.ipdl7
-rw-r--r--ipc/ipdl/test/ipdl/error/PLazySendInvalid.ipdl7
-rw-r--r--ipc/ipdl/test/ipdl/error/PLazySendSync.ipdl7
-rw-r--r--ipc/ipdl/test/ipdl/error/PManagerManualDealloc.ipdl13
-rw-r--r--ipc/ipdl/test/ipdl/error/PMissingProc.ipdl6
-rw-r--r--ipc/ipdl/test/ipdl/error/PNoTaintWithoutTainted.ipdl7
-rw-r--r--ipc/ipdl/test/ipdl/error/PToplevelManualDealloc.ipdl7
-rw-r--r--ipc/ipdl/test/ipdl/error/PUniquePtrRecursive.ipdl6
-rw-r--r--ipc/ipdl/test/ipdl/error/PUniquePtrSelfRecStruct.ipdl10
-rw-r--r--ipc/ipdl/test/ipdl/error/PUniquePtrSelfRecUnion.ipdl8
-rw-r--r--ipc/ipdl/test/ipdl/error/PUnknownProc.ipdl7
-rw-r--r--ipc/ipdl/test/ipdl/error/PasyncMessageListed.ipdl7
-rw-r--r--ipc/ipdl/test/ipdl/error/ReplyPrioWithoutReturns.ipdl8
-rw-r--r--ipc/ipdl/test/ipdl/error/SyncAsyncManagee.ipdl10
-rw-r--r--ipc/ipdl/test/ipdl/error/SyncAsyncManager.ipdl10
-rw-r--r--ipc/ipdl/test/ipdl/error/SyncPrio.ipdl8
-rw-r--r--ipc/ipdl/test/ipdl/error/array_Recursive.ipdl6
-rw-r--r--ipc/ipdl/test/ipdl/error/badProtocolInclude.ipdl10
-rw-r--r--ipc/ipdl/test/ipdl/error/compressCtor.ipdl12
-rw-r--r--ipc/ipdl/test/ipdl/error/compressCtorManagee.ipdl11
-rw-r--r--ipc/ipdl/test/ipdl/error/conflictProtocolMsg.ipdl10
-rw-r--r--ipc/ipdl/test/ipdl/error/cyclecheck_Child.ipdl15
-rw-r--r--ipc/ipdl/test/ipdl/error/cyclecheck_Grandchild.ipdl15
-rw-r--r--ipc/ipdl/test/ipdl/error/cyclecheck_Parent.ipdl13
-rw-r--r--ipc/ipdl/test/ipdl/error/dtorReserved.ipdl11
-rw-r--r--ipc/ipdl/test/ipdl/error/empty.ipdl1
-rw-r--r--ipc/ipdl/test/ipdl/error/extra/PDouble.ipdl5
-rw-r--r--ipc/ipdl/test/ipdl/error/extra/PManagerManualDeallocManaged.ipdl9
-rw-r--r--ipc/ipdl/test/ipdl/error/extra/PManagerManualDeallocTop.ipdl9
-rw-r--r--ipc/ipdl/test/ipdl/error/inconsistentRC.ipdl10
-rw-r--r--ipc/ipdl/test/ipdl/error/intrMessageCompress.ipdl10
-rw-r--r--ipc/ipdl/test/ipdl/error/lex1.ipdl2
-rw-r--r--ipc/ipdl/test/ipdl/error/manageSelfToplevel.ipdl10
-rw-r--r--ipc/ipdl/test/ipdl/error/managedNoDtor.ipdl7
-rw-r--r--ipc/ipdl/test/ipdl/error/managerNoDtor.ipdl11
-rw-r--r--ipc/ipdl/test/ipdl/error/maybe_Recursive.ipdl6
-rw-r--r--ipc/ipdl/test/ipdl/error/maybe_SelfRecStruct.ipdl10
-rw-r--r--ipc/ipdl/test/ipdl/error/maybe_SelfRecUnion.ipdl8
-rw-r--r--ipc/ipdl/test/ipdl/error/messageNoDirection.ipdl6
-rw-r--r--ipc/ipdl/test/ipdl/error/multimanDupMgrs.ipdl10
-rw-r--r--ipc/ipdl/test/ipdl/error/multimanDupMgrsMgr.ipdl12
-rw-r--r--ipc/ipdl/test/ipdl/error/multimanNonexistentMgrs.ipdl10
-rw-r--r--ipc/ipdl/test/ipdl/error/mutualRecStruct.ipdl25
-rw-r--r--ipc/ipdl/test/ipdl/error/mutualRecStructUnion.ipdl25
-rw-r--r--ipc/ipdl/test/ipdl/error/noProtocolInHeader.ipdlh7
-rw-r--r--ipc/ipdl/test/ipdl/error/oldIncludeSyntax.ipdl8
-rw-r--r--ipc/ipdl/test/ipdl/error/parser.ipdl3
-rw-r--r--ipc/ipdl/test/ipdl/error/redeclMessage.ipdl13
-rw-r--r--ipc/ipdl/test/ipdl/error/redeclParamReturn.ipdl10
-rw-r--r--ipc/ipdl/test/ipdl/error/redeclScope.ipdlh12
-rw-r--r--ipc/ipdl/test/ipdl/error/shmem.ipdl9
-rw-r--r--ipc/ipdl/test/ipdl/error/structRedecl.ipdl11
-rw-r--r--ipc/ipdl/test/ipdl/error/structUnknownField.ipdl10
-rw-r--r--ipc/ipdl/test/ipdl/error/syncMessageCompress.ipdl7
-rw-r--r--ipc/ipdl/test/ipdl/error/syncParentToChild.ipdl9
-rw-r--r--ipc/ipdl/test/ipdl/error/tooWeakIntrAsync.ipdl10
-rw-r--r--ipc/ipdl/test/ipdl/error/tooWeakIntrSync.ipdl9
-rw-r--r--ipc/ipdl/test/ipdl/error/tooWeakSyncAsync.ipdl10
-rw-r--r--ipc/ipdl/test/ipdl/error/twoprotocols.ipdl13
-rw-r--r--ipc/ipdl/test/ipdl/error/undeclParamType.ipdl8
-rw-r--r--ipc/ipdl/test/ipdl/error/undeclProtocol.ipdl9
-rw-r--r--ipc/ipdl/test/ipdl/error/undeclReturnType.ipdl8
-rw-r--r--ipc/ipdl/test/ipdl/error/undefMutualRecStruct.ipdl12
-rw-r--r--ipc/ipdl/test/ipdl/error/undefMutualRecStructUnion.ipdl12
-rw-r--r--ipc/ipdl/test/ipdl/error/undefMutualRecUnion.ipdl12
-rw-r--r--ipc/ipdl/test/ipdl/error/undefSelfRecStruct.ipdl8
-rw-r--r--ipc/ipdl/test/ipdl/error/undefSelfRecUnion.ipdl8
-rw-r--r--ipc/ipdl/test/ipdl/error/unknownIntrMessage.ipdl7
-rw-r--r--ipc/ipdl/test/ipdl/error/unknownSyncMessage.ipdl7
-rw-r--r--ipc/ipdl/test/ipdl/message-metadata.ini2
-rw-r--r--ipc/ipdl/test/ipdl/moz.build8
-rw-r--r--ipc/ipdl/test/ipdl/ok/MutRecHeader1.ipdlh34
-rw-r--r--ipc/ipdl/test/ipdl/ok/MutRecHeader2.ipdlh8
-rw-r--r--ipc/ipdl/test/ipdl/ok/MutRecHeader3.ipdlh8
-rw-r--r--ipc/ipdl/test/ipdl/ok/MyTypes.ipdlh6
-rw-r--r--ipc/ipdl/test/ipdl/ok/PAsyncReturn.ipdl9
-rw-r--r--ipc/ipdl/test/ipdl/ok/PDelete.ipdl9
-rw-r--r--ipc/ipdl/test/ipdl/ok/PDeleteSub.ipdl10
-rw-r--r--ipc/ipdl/test/ipdl/ok/PEndpointDecl.ipdl19
-rw-r--r--ipc/ipdl/test/ipdl/ok/PEndpointUse.ipdl10
-rw-r--r--ipc/ipdl/test/ipdl/ok/PExtendedAttrMultipleAttributes.ipdl5
-rw-r--r--ipc/ipdl/test/ipdl/ok/PLazySend.ipdl7
-rw-r--r--ipc/ipdl/test/ipdl/ok/PManagedEndpointDecl.ipdl23
-rw-r--r--ipc/ipdl/test/ipdl/ok/PManagedEndpointManager.ipdl15
-rw-r--r--ipc/ipdl/test/ipdl/ok/PManualDealloc.ipdl8
-rw-r--r--ipc/ipdl/test/ipdl/ok/PManualDealloc_manager.ipdl8
-rw-r--r--ipc/ipdl/test/ipdl/ok/PMessageTainted.ipdl5
-rw-r--r--ipc/ipdl/test/ipdl/ok/PMessageTaintedWithPassback.ipdl5
-rw-r--r--ipc/ipdl/test/ipdl/ok/PMyManaged.ipdl13
-rw-r--r--ipc/ipdl/test/ipdl/ok/PMyManager.ipdl31
-rw-r--r--ipc/ipdl/test/ipdl/ok/PNested.ipdl8
-rw-r--r--ipc/ipdl/test/ipdl/ok/PNullable.ipdl22
-rw-r--r--ipc/ipdl/test/ipdl/ok/PSideImpl.ipdl5
-rw-r--r--ipc/ipdl/test/ipdl/ok/PStruct.ipdl11
-rw-r--r--ipc/ipdl/test/ipdl/ok/PStructComparable.ipdl11
-rw-r--r--ipc/ipdl/test/ipdl/ok/PSyncSyncManagee.ipdl7
-rw-r--r--ipc/ipdl/test/ipdl/ok/PSyncSyncManager.ipdl12
-rw-r--r--ipc/ipdl/test/ipdl/ok/PUniquePtrBasic.ipdl5
-rw-r--r--ipc/ipdl/test/ipdl/ok/PUniquePtrOfActors.ipdl11
-rw-r--r--ipc/ipdl/test/ipdl/ok/PUniquePtrOfActorsSub.ipdl7
-rw-r--r--ipc/ipdl/test/ipdl/ok/PUniquePtrRecUnion.ipdl22
-rw-r--r--ipc/ipdl/test/ipdl/ok/PUniquePtrUnion.ipdl11
-rw-r--r--ipc/ipdl/test/ipdl/ok/PVirtualSendImpl.ipdl6
-rw-r--r--ipc/ipdl/test/ipdl/ok/Pactorparam.ipdl6
-rw-r--r--ipc/ipdl/test/ipdl/ok/Pactorreturn.ipdl7
-rw-r--r--ipc/ipdl/test/ipdl/ok/Parray_Basic.ipdl5
-rw-r--r--ipc/ipdl/test/ipdl/ok/Parray_OfActors.ipdl11
-rw-r--r--ipc/ipdl/test/ipdl/ok/Parray_OfActorsSub.ipdl7
-rw-r--r--ipc/ipdl/test/ipdl/ok/Parray_Union.ipdl11
-rw-r--r--ipc/ipdl/test/ipdl/ok/PbasicUsing.ipdl51
-rw-r--r--ipc/ipdl/test/ipdl/ok/Pbuiltins.ipdl22
-rw-r--r--ipc/ipdl/test/ipdl/ok/Pbytebuf.ipdl14
-rw-r--r--ipc/ipdl/test/ipdl/ok/Pempty.ipdl4
-rw-r--r--ipc/ipdl/test/ipdl/ok/PemptyStruct.ipdl4
-rw-r--r--ipc/ipdl/test/ipdl/ok/PheaderProto.ipdl11
-rw-r--r--ipc/ipdl/test/ipdl/ok/PintrProtocol.ipdl14
-rw-r--r--ipc/ipdl/test/ipdl/ok/Pjetpack.ipdl6
-rw-r--r--ipc/ipdl/test/ipdl/ok/PmanageSelf.ipdl10
-rw-r--r--ipc/ipdl/test/ipdl/ok/PmanageSelf_Toplevel.ipdl10
-rw-r--r--ipc/ipdl/test/ipdl/ok/PmanagedProtocol.ipdl8
-rw-r--r--ipc/ipdl/test/ipdl/ok/PmanagerProtocol.ipdl12
-rw-r--r--ipc/ipdl/test/ipdl/ok/Pmaybe_Basic.ipdl5
-rw-r--r--ipc/ipdl/test/ipdl/ok/Pmaybe_OfActors.ipdl11
-rw-r--r--ipc/ipdl/test/ipdl/ok/Pmaybe_OfActorsSub.ipdl7
-rw-r--r--ipc/ipdl/test/ipdl/ok/Pmaybe_Union.ipdl11
-rw-r--r--ipc/ipdl/test/ipdl/ok/Pmedia.ipdl6
-rw-r--r--ipc/ipdl/test/ipdl/ok/PmessageCompress.ipdl6
-rw-r--r--ipc/ipdl/test/ipdl/ok/PmultiManaged.ipdl9
-rw-r--r--ipc/ipdl/test/ipdl/ok/PmultiManager1.ipdl9
-rw-r--r--ipc/ipdl/test/ipdl/ok/PmultiManager2.ipdl9
-rw-r--r--ipc/ipdl/test/ipdl/ok/PmultipleUsingCxxTypes.ipdl8
-rw-r--r--ipc/ipdl/test/ipdl/ok/PmutualRecStructUnion.ipdl22
-rw-r--r--ipc/ipdl/test/ipdl/ok/PmutualRecUnion.ipdl22
-rw-r--r--ipc/ipdl/test/ipdl/ok/Pnamespace_Basic.ipdl13
-rw-r--r--ipc/ipdl/test/ipdl/ok/PnoRedeclCrossMessage.ipdl10
-rw-r--r--ipc/ipdl/test/ipdl/ok/Pplugin.ipdl6
-rw-r--r--ipc/ipdl/test/ipdl/ok/Prio.ipdl12
-rw-r--r--ipc/ipdl/test/ipdl/ok/PselfRecUnion.ipdl12
-rw-r--r--ipc/ipdl/test/ipdl/ok/Pshmem.ipdl14
-rw-r--r--ipc/ipdl/test/ipdl/ok/PsyncProtocol.ipdl12
-rw-r--r--ipc/ipdl/test/ipdl/ok/PthreeDirections.ipdl14
-rw-r--r--ipc/ipdl/test/ipdl/ok/Punion_Basic.ipdl12
-rw-r--r--ipc/ipdl/test/ipdl/ok/Punion_Comparable.ipdl12
-rw-r--r--ipc/ipdl/test/ipdl/ok/Punion_Namespaced.ipdl19
-rw-r--r--ipc/ipdl/test/ipdl/ok/header.ipdlh15
-rw-r--r--ipc/ipdl/test/ipdl/runtests.py119
-rw-r--r--ipc/ipdl/test/ipdl/sync-messages.ini50
-rw-r--r--ipc/ipdl/test/moz.build9
355 files changed, 14228 insertions, 0 deletions
diff --git a/ipc/ipdl/test/README.txt b/ipc/ipdl/test/README.txt
new file mode 100644
index 0000000000..ca6db8bb3c
--- /dev/null
+++ b/ipc/ipdl/test/README.txt
@@ -0,0 +1,13 @@
+There are two major categories of tests, segregated into different
+top-level directories under test/.
+
+The first category (ipdl/) is IPDL-compiler tests. These tests check
+that the IPDL compiler is successfully compiling correct
+specifications, and successfully rejecting erroneous specifications.
+
+To run these tests yourself locally, the correct invocation is
+ make -C obj-dir/ipc/ipdl/test/ipdl check
+
+The second category (cxx/) is C++ tests of IPDL semantics. These
+tests check that async/sync/rpc semantics are implemented correctly,
+ctors/dtors behave as they should, etc.
diff --git a/ipc/ipdl/test/cxx/IPDLUnitTestProcessChild.cpp b/ipc/ipdl/test/cxx/IPDLUnitTestProcessChild.cpp
new file mode 100644
index 0000000000..7683808535
--- /dev/null
+++ b/ipc/ipdl/test/cxx/IPDLUnitTestProcessChild.cpp
@@ -0,0 +1,27 @@
+/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8 -*- */
+/* 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 "mozilla/ipc/IOThreadChild.h"
+
+#include "IPDLUnitTestProcessChild.h"
+#include "IPDLUnitTests.h"
+
+#include "nsRegion.h"
+
+using mozilla::ipc::IOThreadChild;
+
+namespace mozilla {
+namespace _ipdltest {
+
+bool IPDLUnitTestProcessChild::Init(int aArgc, char* aArgv[]) {
+ // FIXME(nika): this is quite clearly broken and needs to be fixed.
+ IPDLUnitTestChildInit(IOThreadChild::TakeChannel(), ParentPid(),
+ IOThreadChild::message_loop());
+
+ return true;
+}
+
+} // namespace _ipdltest
+} // namespace mozilla
diff --git a/ipc/ipdl/test/cxx/IPDLUnitTestProcessChild.h b/ipc/ipdl/test/cxx/IPDLUnitTestProcessChild.h
new file mode 100644
index 0000000000..94578e3520
--- /dev/null
+++ b/ipc/ipdl/test/cxx/IPDLUnitTestProcessChild.h
@@ -0,0 +1,28 @@
+/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8 -*- */
+/* 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/. */
+
+#ifndef mozilla__ipdltest_IPDLUnitTestThreadChild_h
+#define mozilla__ipdltest_IPDLUnitTestThreadChild_h 1
+
+#include "mozilla/ipc/ProcessChild.h"
+
+namespace mozilla {
+namespace _ipdltest {
+
+class IPDLUnitTestProcessChild : public mozilla::ipc::ProcessChild {
+ typedef mozilla::ipc::ProcessChild ProcessChild;
+
+ public:
+ using ProcessChild::ProcessChild;
+
+ ~IPDLUnitTestProcessChild() {}
+
+ virtual bool Init(int aArgc, char* aArgv[]) override;
+};
+
+} // namespace _ipdltest
+} // namespace mozilla
+
+#endif // ifndef mozilla__ipdltest_IPDLUnitTestThreadChild_h
diff --git a/ipc/ipdl/test/cxx/IPDLUnitTestSubprocess.cpp b/ipc/ipdl/test/cxx/IPDLUnitTestSubprocess.cpp
new file mode 100644
index 0000000000..660e5928d3
--- /dev/null
+++ b/ipc/ipdl/test/cxx/IPDLUnitTestSubprocess.cpp
@@ -0,0 +1,19 @@
+/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8 -*- */
+/* 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 "IPDLUnitTestSubprocess.h"
+
+using mozilla::ipc::GeckoChildProcessHost;
+
+namespace mozilla {
+namespace _ipdltest {
+
+IPDLUnitTestSubprocess::IPDLUnitTestSubprocess()
+ : GeckoChildProcessHost(GeckoProcessType_IPDLUnitTest) {}
+
+IPDLUnitTestSubprocess::~IPDLUnitTestSubprocess() {}
+
+} // namespace _ipdltest
+} // namespace mozilla
diff --git a/ipc/ipdl/test/cxx/IPDLUnitTestSubprocess.h b/ipc/ipdl/test/cxx/IPDLUnitTestSubprocess.h
new file mode 100644
index 0000000000..384cf25ce9
--- /dev/null
+++ b/ipc/ipdl/test/cxx/IPDLUnitTestSubprocess.h
@@ -0,0 +1,34 @@
+/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8 -*- */
+/* 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/. */
+
+#ifndef mozilla__ipdltest_IPDLUnitTestTestSubprocess_h
+#define mozilla__ipdltest_IPDLUnitTestTestSubprocess_h 1
+
+#include "mozilla/ipc/GeckoChildProcessHost.h"
+
+namespace mozilla {
+namespace _ipdltest {
+//-----------------------------------------------------------------------------
+
+class IPDLUnitTestSubprocess : public mozilla::ipc::GeckoChildProcessHost {
+ public:
+ IPDLUnitTestSubprocess();
+
+ /**
+ * Asynchronously launch the plugin process.
+ */
+ // Could override parent Launch, but don't need to here
+ // bool Launch();
+
+ private:
+ ~IPDLUnitTestSubprocess();
+
+ DISALLOW_EVIL_CONSTRUCTORS(IPDLUnitTestSubprocess);
+};
+
+} // namespace _ipdltest
+} // namespace mozilla
+
+#endif // ifndef mozilla__ipdltest_IPDLUnitTestTestSubprocess_h
diff --git a/ipc/ipdl/test/cxx/IPDLUnitTestTypes.h b/ipc/ipdl/test/cxx/IPDLUnitTestTypes.h
new file mode 100644
index 0000000000..02696f7df7
--- /dev/null
+++ b/ipc/ipdl/test/cxx/IPDLUnitTestTypes.h
@@ -0,0 +1,43 @@
+/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8 -*- */
+/* 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/. */
+
+#ifndef mozilla__ipdltest_IPDLUnitTestTypes_h
+#define mozilla__ipdltest_IPDLUnitTestTypes_h
+
+#include "mozilla/ipc/ProtocolUtils.h" // ActorDestroyReason
+
+namespace mozilla {
+namespace _ipdltest {
+
+struct DirtyRect {
+ int x;
+ int y;
+ int w;
+ int h;
+};
+
+} // namespace _ipdltest
+} // namespace mozilla
+
+namespace IPC {
+template <>
+struct ParamTraits<mozilla::_ipdltest::DirtyRect> {
+ typedef mozilla::_ipdltest::DirtyRect paramType;
+ static void Write(MessageWriter* aWriter, const paramType& aParam) {
+ WriteParam(aWriter, aParam.x);
+ WriteParam(aWriter, aParam.y);
+ WriteParam(aWriter, aParam.w);
+ WriteParam(aWriter, aParam.h);
+ }
+ static bool Read(MessageReader* aReader, void** aIter, paramType* aResult) {
+ return (ReadParam(aReader, aIter, &aResult->x) &&
+ ReadParam(aReader, aIter, &aResult->y) &&
+ ReadParam(aReader, aIter, &aResult->w) &&
+ ReadParam(aReader, aIter, &aResult->h));
+ }
+};
+} // namespace IPC
+
+#endif // ifndef mozilla__ipdltest_IPDLUnitTestTypes_h
diff --git a/ipc/ipdl/test/cxx/IPDLUnitTestUtils.h b/ipc/ipdl/test/cxx/IPDLUnitTestUtils.h
new file mode 100644
index 0000000000..e454ae7b61
--- /dev/null
+++ b/ipc/ipdl/test/cxx/IPDLUnitTestUtils.h
@@ -0,0 +1,28 @@
+
+#ifndef mozilla__ipdltest_IPDLUnitTestUtils
+#define mozilla__ipdltest_IPDLUnitTestUtils 1
+
+#include "ipc/IPCMessageUtils.h"
+
+namespace mozilla {
+namespace _ipdltest {
+
+struct Bad {};
+
+} // namespace _ipdltest
+} // namespace mozilla
+
+namespace IPC {
+
+template <>
+struct ParamTraits<mozilla::_ipdltest::Bad> {
+ typedef mozilla::_ipdltest::Bad paramType;
+
+ // Defined in TestActorPunning.cpp.
+ static void Write(MessageWriter* aWriter, const paramType& aParam);
+ static bool Read(MessageReader* aReader, paramType* aResult);
+};
+
+} // namespace IPC
+
+#endif // mozilla__ipdltest_IPDLUnitTestUtils
diff --git a/ipc/ipdl/test/cxx/IPDLUnitTests.h b/ipc/ipdl/test/cxx/IPDLUnitTests.h
new file mode 100644
index 0000000000..28fc4ee372
--- /dev/null
+++ b/ipc/ipdl/test/cxx/IPDLUnitTests.h
@@ -0,0 +1,85 @@
+/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8 -*- */
+/* 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/. */
+
+#ifndef mozilla__ipdltest_IPDLUnitTests_h
+#define mozilla__ipdltest_IPDLUnitTests_h 1
+
+#include "base/message_loop.h"
+#include "base/process.h"
+#include "chrome/common/ipc_channel.h"
+
+#include "nsCOMPtr.h"
+#include "nsDebug.h"
+#include "nsServiceManagerUtils.h" // do_GetService()
+#include "nsWidgetsCID.h" // NS_APPSHELL_CID
+#include "nsXULAppAPI.h"
+
+#define MOZ_IPDL_TESTFAIL_LABEL "TEST-UNEXPECTED-FAIL"
+#define MOZ_IPDL_TESTPASS_LABEL "TEST-PASS"
+#define MOZ_IPDL_TESTINFO_LABEL "TEST-INFO"
+
+namespace mozilla {
+namespace _ipdltest {
+
+//-----------------------------------------------------------------------------
+// both processes
+const char* IPDLUnitTestName();
+
+// NB: these are named like the similar functions in
+// xpcom/test/TestHarness.h. The names should nominally be kept in
+// sync.
+
+inline void fail(const char* fmt, ...) {
+ va_list ap;
+
+ fprintf(stderr, MOZ_IPDL_TESTFAIL_LABEL " | %s | ", IPDLUnitTestName());
+
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+
+ fputc('\n', stderr);
+
+ MOZ_CRASH("failed test");
+}
+
+inline void passed(const char* fmt, ...) {
+ va_list ap;
+
+ printf(MOZ_IPDL_TESTPASS_LABEL " | %s | ", IPDLUnitTestName());
+
+ va_start(ap, fmt);
+ vprintf(fmt, ap);
+ va_end(ap);
+
+ fputc('\n', stdout);
+}
+
+//-----------------------------------------------------------------------------
+// parent process only
+
+class IPDLUnitTestSubprocess;
+
+extern void* gParentActor;
+extern IPDLUnitTestSubprocess* gSubprocess;
+
+void IPDLUnitTestMain(void* aData);
+
+void QuitParent();
+
+//-----------------------------------------------------------------------------
+// child process only
+
+extern void* gChildActor;
+
+void IPDLUnitTestChildInit(IPC::Channel* transport, base::ProcessId parentPid,
+ MessageLoop* worker);
+
+void QuitChild();
+
+} // namespace _ipdltest
+} // namespace mozilla
+
+#endif // ifndef mozilla__ipdltest_IPDLUnitTests_h
diff --git a/ipc/ipdl/test/cxx/IPDLUnitTests.template.cpp b/ipc/ipdl/test/cxx/IPDLUnitTests.template.cpp
new file mode 100644
index 0000000000..113e7cd287
--- /dev/null
+++ b/ipc/ipdl/test/cxx/IPDLUnitTests.template.cpp
@@ -0,0 +1,345 @@
+//
+// Autogenerated from Python template. Hands off.
+//
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "IPDLUnitTests.h"
+
+#include "base/command_line.h"
+#include "base/string_util.h"
+#include "base/task.h"
+#include "base/thread.h"
+
+#include "nsRegion.h"
+
+#include "IPDLUnitTestSubprocess.h"
+
+// clang-format off
+//-----------------------------------------------------------------------------
+//===== TEMPLATED =====
+${INCLUDES}
+//-----------------------------------------------------------------------------
+// clang-format on
+
+using namespace std;
+
+using base::Thread;
+
+namespace mozilla {
+namespace _ipdltest {
+
+void* gParentActor;
+IPDLUnitTestSubprocess* gSubprocess;
+
+void* gChildActor;
+
+// Note: in threaded mode, this will be non-null (for both parent and
+// child, since they share one set of globals).
+Thread* gChildThread;
+MessageLoop* gParentMessageLoop;
+bool gParentDone;
+bool gChildDone;
+
+void DeleteChildActor();
+
+//-----------------------------------------------------------------------------
+// data/functions accessed by both parent and child processes
+
+char* gIPDLUnitTestName = nullptr;
+
+const char* IPDLUnitTestName() {
+ if (!gIPDLUnitTestName) {
+#if defined(XP_WIN)
+ vector<wstring> args = CommandLine::ForCurrentProcess()->GetLooseValues();
+ gIPDLUnitTestName = ::strdup(WideToUTF8(args[0]).c_str());
+#else
+ vector<string> argv = CommandLine::ForCurrentProcess()->argv();
+ gIPDLUnitTestName = ::moz_xstrdup(argv[1].c_str());
+#endif
+ }
+ return gIPDLUnitTestName;
+}
+
+} // namespace _ipdltest
+} // namespace mozilla
+
+namespace {
+
+enum IPDLUnitTestType {
+ NoneTest = 0,
+
+ // clang-format off
+//-----------------------------------------------------------------------------
+//===== TEMPLATED =====
+${ENUM_VALUES}
+
+ LastTest = ${LAST_ENUM}
+//-----------------------------------------------------------------------------
+//clang-format on
+};
+
+IPDLUnitTestType IPDLUnitTestFromString(const char* const aString) {
+ if (!aString) return static_cast<IPDLUnitTestType>(0);
+// clang-format off
+//-----------------------------------------------------------------------------
+//===== TEMPLATED =====
+${STRING_TO_ENUMS}
+//-----------------------------------------------------------------------------
+ // clang-format on
+ else return static_cast<IPDLUnitTestType>(0);
+}
+
+IPDLUnitTestType IPDLUnitTest() {
+ return IPDLUnitTestFromString(::mozilla::_ipdltest::IPDLUnitTestName());
+}
+
+} // namespace
+
+//-----------------------------------------------------------------------------
+// parent process only
+
+namespace mozilla {
+namespace _ipdltest {
+
+void DeferredParentShutdown();
+
+void IPDLUnitTestThreadMain(char* testString);
+
+void IPDLUnitTestMain(void* aData) {
+ char* testString = reinterpret_cast<char*>(aData);
+
+ // Check if we are to run the test using threads instead:
+ const char* prefix = "thread:";
+ const int prefixLen = strlen(prefix);
+ if (!strncmp(testString, prefix, prefixLen)) {
+ IPDLUnitTestThreadMain(testString + prefixLen);
+ return;
+ }
+
+ IPDLUnitTestType test = IPDLUnitTestFromString(testString);
+ if (!test) {
+ // use this instead of |fail()| because we don't know what the test is
+ fprintf(stderr, MOZ_IPDL_TESTFAIL_LABEL "| %s | unknown unit test %s\n",
+ "<--->", testString);
+ MOZ_CRASH("can't continue");
+ }
+ gIPDLUnitTestName = testString;
+
+ // Check whether this test is enabled for processes:
+ switch (test) {
+ // clang-format off
+//-----------------------------------------------------------------------------
+//===== TEMPLATED =====
+${PARENT_ENABLED_CASES_PROC}
+//-----------------------------------------------------------------------------
+ // clang-format on
+
+ default:
+ fail("not reached");
+ return; // unreached
+ }
+
+ printf(MOZ_IPDL_TESTINFO_LABEL "| running test | %s\n", gIPDLUnitTestName);
+
+ std::vector<std::string> testCaseArgs;
+ testCaseArgs.push_back(testString);
+
+ gSubprocess = new IPDLUnitTestSubprocess();
+ if (!gSubprocess->SyncLaunch(testCaseArgs))
+ fail("problem launching subprocess");
+
+ IPC::Channel* transport = gSubprocess->GetChannel();
+ if (!transport) fail("no transport");
+
+ base::ProcessId child = base::GetProcId(gSubprocess->GetChildProcessHandle());
+
+ switch (test) {
+ // clang-format off
+//-----------------------------------------------------------------------------
+//===== TEMPLATED =====
+${PARENT_MAIN_CASES_PROC}
+//-----------------------------------------------------------------------------
+ // clang-format on
+
+ default:
+ fail("not reached");
+ return; // unreached
+ }
+}
+
+void IPDLUnitTestThreadMain(char* testString) {
+ IPDLUnitTestType test = IPDLUnitTestFromString(testString);
+ if (!test) {
+ // use this instead of |fail()| because we don't know what the test is
+ fprintf(stderr, MOZ_IPDL_TESTFAIL_LABEL "| %s | unknown unit test %s\n",
+ "<--->", testString);
+ MOZ_CRASH("can't continue");
+ }
+ gIPDLUnitTestName = testString;
+
+ // Check whether this test is enabled for threads:
+ switch (test) {
+ // clang-format off
+//-----------------------------------------------------------------------------
+//===== TEMPLATED =====
+${PARENT_ENABLED_CASES_THREAD}
+//-----------------------------------------------------------------------------
+ // clang-format on
+
+ default:
+ fail("not reached");
+ return; // unreached
+ }
+
+ printf(MOZ_IPDL_TESTINFO_LABEL "| running test | %s\n", gIPDLUnitTestName);
+
+ std::vector<std::string> testCaseArgs;
+ testCaseArgs.push_back(testString);
+
+ gChildThread = new Thread("ParentThread");
+ if (!gChildThread->Start()) fail("starting parent thread");
+
+ gParentMessageLoop = MessageLoop::current();
+ MessageLoop* childMessageLoop = gChildThread->message_loop();
+
+ switch (test) {
+ // clang-format off
+//-----------------------------------------------------------------------------
+//===== TEMPLATED =====
+${PARENT_MAIN_CASES_THREAD}
+//-----------------------------------------------------------------------------
+ // clang-format on
+
+ default:
+ fail("not reached");
+ return; // unreached
+ }
+}
+
+void DeleteParentActor() {
+ if (!gParentActor) return;
+
+ switch (IPDLUnitTest()) {
+ // clang-format off
+//-----------------------------------------------------------------------------
+//===== TEMPLATED =====
+${PARENT_DELETE_CASES}
+//-----------------------------------------------------------------------------
+ // clang-format on
+ default:
+ ::mozilla::_ipdltest::fail("???");
+ }
+}
+
+void QuitXPCOM() {
+ DeleteParentActor();
+
+ static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
+ nsCOMPtr<nsIAppShell> appShell(do_GetService(kAppShellCID));
+ appShell->Exit();
+}
+
+void DeleteSubprocess(MessageLoop* uiLoop) {
+ // pong to QuitXPCOM
+ gSubprocess->Destroy();
+ gSubprocess = nullptr;
+ uiLoop->PostTask(NewRunnableFunction("QuitXPCOM", QuitXPCOM));
+}
+
+void DeferredParentShutdown() {
+ // ping to DeleteSubprocess
+ XRE_GetIOMessageLoop()->PostTask(NewRunnableFunction(
+ "DeleteSubprocess", DeleteSubprocess, MessageLoop::current()));
+}
+
+void TryThreadedShutdown() {
+ // Stop if either:
+ // - the child has not finished,
+ // - the parent has not finished,
+ // - or this code has already executed.
+ // Remember: this TryThreadedShutdown() task is enqueued
+ // by both parent and child (though always on parent's msg loop).
+ if (!gChildDone || !gParentDone || !gChildThread) return;
+
+ delete gChildThread;
+ gChildThread = 0;
+ DeferredParentShutdown();
+}
+
+void ChildCompleted() {
+ // Executes on the parent message loop once child has completed.
+ gChildDone = true;
+ TryThreadedShutdown();
+}
+
+void QuitParent() {
+ if (gChildThread) {
+ gParentDone = true;
+ MessageLoop::current()->PostTask(
+ NewRunnableFunction("TryThreadedShutdown", TryThreadedShutdown));
+ } else {
+ // defer "real" shutdown to avoid *Channel::Close() racing with the
+ // deletion of the subprocess
+ MessageLoop::current()->PostTask(
+ NewRunnableFunction("DeferredParentShutdown", DeferredParentShutdown));
+ }
+}
+
+static void ChildDie() {
+ DeleteChildActor();
+ XRE_ShutdownChildProcess();
+}
+
+void QuitChild() {
+ if (gChildThread) { // Threaded-mode test
+ gParentMessageLoop->PostTask(
+ NewRunnableFunction("ChildCompleted", ChildCompleted));
+ } else { // Process-mode test
+ MessageLoop::current()->PostTask(NewRunnableFunction("ChildDie", ChildDie));
+ }
+}
+
+} // namespace _ipdltest
+} // namespace mozilla
+
+//-----------------------------------------------------------------------------
+// child process only
+
+namespace mozilla {
+namespace _ipdltest {
+
+void DeleteChildActor() {
+ if (!gChildActor) return;
+
+ switch (IPDLUnitTest()) {
+ // clang-format off
+//-----------------------------------------------------------------------------
+//===== TEMPLATED =====
+${CHILD_DELETE_CASES}
+//-----------------------------------------------------------------------------
+ // clang-format on
+ default:
+ ::mozilla::_ipdltest::fail("???");
+ }
+}
+
+void IPDLUnitTestChildInit(IPC::Channel* transport, base::ProcessId parentPid,
+ MessageLoop* worker) {
+ switch (IPDLUnitTest()) {
+ // clang-format off
+//-----------------------------------------------------------------------------
+//===== TEMPLATED =====
+${CHILD_INIT_CASES}
+//-----------------------------------------------------------------------------
+ // clang-format on
+
+ default:
+ fail("not reached");
+ return; // unreached
+ }
+}
+
+} // namespace _ipdltest
+} // namespace mozilla
diff --git a/ipc/ipdl/test/cxx/Makefile.in b/ipc/ipdl/test/cxx/Makefile.in
new file mode 100644
index 0000000000..b32533a648
--- /dev/null
+++ b/ipc/ipdl/test/cxx/Makefile.in
@@ -0,0 +1,45 @@
+# 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/.
+
+IPDLTESTSRCS = $(filter Test%,$(CPPSRCS))
+IPDLTESTS = $(IPDLTESTSRCS:.cpp=)
+
+EXTRA_PROTOCOLS = \
+ TestEndpointBridgeSub \
+ $(NULL)
+
+IPDLTESTHDRS = $(addprefix $(srcdir)/,$(addsuffix .h,$(IPDLTESTS)))
+
+TESTER_TEMPLATE := $(srcdir)/IPDLUnitTests.template.cpp
+GENTESTER := $(srcdir)/genIPDLUnitTests.py
+
+include $(topsrcdir)/config/rules.mk
+
+
+IPDLUNITTEST_BIN = $(DEPTH)/dist/bin/ipdlunittest$(BIN_SUFFIX)
+
+IPDLUnitTests.cpp : Makefile.in moz.build $(GENTESTER) $(TESTER_TEMPLATE) $(IPDLTESTHDRS)
+ $(PYTHON3) $(GENTESTER) $(TESTER_TEMPLATE) -t $(IPDLTESTS) -e $(EXTRA_PROTOCOLS) > $@
+
+check-proc::
+ @$(EXIT_ON_ERROR) \
+ for test in $(IPDLTESTS); do \
+ $(RUN_TEST_PROGRAM) $(IPDLUNITTEST_BIN) $$test ; \
+ done
+
+check-thread::
+ @$(EXIT_ON_ERROR) \
+ for test in $(IPDLTESTS); do \
+ $(RUN_TEST_PROGRAM) $(IPDLUNITTEST_BIN) thread:$$test ; \
+ done
+
+check:: check-proc check-thread
+
+check-valgrind::
+ @$(EXIT_ON_ERROR) \
+ for test in $(IPDLTESTS); do \
+ $(RUN_TEST_PROGRAM) -g -d \
+ valgrind -a '--leak-check=full --trace-children=yes -q' \
+ $(IPDLUNITTEST_BIN) $$test ; \
+ done
diff --git a/ipc/ipdl/test/cxx/PTestActorPunning.ipdl b/ipc/ipdl/test/cxx/PTestActorPunning.ipdl
new file mode 100644
index 0000000000..0aec430d9f
--- /dev/null
+++ b/ipc/ipdl/test/cxx/PTestActorPunning.ipdl
@@ -0,0 +1,28 @@
+
+include protocol PTestActorPunningPunned;
+include protocol PTestActorPunningSub;
+include "mozilla/_ipdltest/IPDLUnitTestUtils.h";
+include "mozilla/_ipdltest/TestActorPunning.h";
+
+using struct mozilla::_ipdltest::Bad from "mozilla/_ipdltest/IPDLUnitTestUtils.h";
+
+namespace mozilla {
+namespace _ipdltest {
+
+[ManualDealloc, ChildImpl="TestActorPunningChild", ParentImpl="TestActorPunningParent"]
+protocol PTestActorPunning {
+ manages PTestActorPunningPunned;
+ manages PTestActorPunningSub;
+
+child:
+ async Start();
+
+parent:
+ async PTestActorPunningPunned();
+ async PTestActorPunningSub();
+ async Pun(PTestActorPunningSub a, Bad bad);
+ async __delete__();
+};
+
+} // namespace mozilla
+} // namespace _ipdltest
diff --git a/ipc/ipdl/test/cxx/PTestActorPunningPunned.ipdl b/ipc/ipdl/test/cxx/PTestActorPunningPunned.ipdl
new file mode 100644
index 0000000000..5cca8a8ab5
--- /dev/null
+++ b/ipc/ipdl/test/cxx/PTestActorPunningPunned.ipdl
@@ -0,0 +1,18 @@
+
+include protocol PTestActorPunning;
+
+include "mozilla/_ipdltest/TestActorPunning.h";
+
+namespace mozilla {
+namespace _ipdltest {
+
+[ManualDealloc, ChildImpl="TestActorPunningPunnedChild", ParentImpl="TestActorPunningPunnedParent"]
+protocol PTestActorPunningPunned {
+ manager PTestActorPunning;
+
+child:
+ async __delete__();
+};
+
+} // namespace mozilla
+} // namespace _ipdltes
diff --git a/ipc/ipdl/test/cxx/PTestActorPunningSub.ipdl b/ipc/ipdl/test/cxx/PTestActorPunningSub.ipdl
new file mode 100644
index 0000000000..0cb522255c
--- /dev/null
+++ b/ipc/ipdl/test/cxx/PTestActorPunningSub.ipdl
@@ -0,0 +1,19 @@
+
+include protocol PTestActorPunning;
+
+include "mozilla/_ipdltest/TestActorPunning.h";
+
+namespace mozilla {
+namespace _ipdltest {
+
+[ManualDealloc, ChildImpl="TestActorPunningSubChild", ParentImpl="TestActorPunningSubParent"]
+protocol PTestActorPunningSub {
+ manager PTestActorPunning;
+
+child:
+ async Bad();
+ async __delete__();
+};
+
+} // namespace mozilla
+} // namespace _ipdltes
diff --git a/ipc/ipdl/test/cxx/PTestAsyncReturns.ipdl b/ipc/ipdl/test/cxx/PTestAsyncReturns.ipdl
new file mode 100644
index 0000000000..42ef17d1e8
--- /dev/null
+++ b/ipc/ipdl/test/cxx/PTestAsyncReturns.ipdl
@@ -0,0 +1,20 @@
+include "mozilla/_ipdltest/TestAsyncReturns.h";
+
+namespace mozilla {
+namespace _ipdltest {
+
+
+[ManualDealloc, ChildImpl="TestAsyncReturnsChild", ParentImpl="TestAsyncReturnsParent"]
+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/cxx/PTestBadActor.ipdl b/ipc/ipdl/test/cxx/PTestBadActor.ipdl
new file mode 100644
index 0000000000..991e6eb945
--- /dev/null
+++ b/ipc/ipdl/test/cxx/PTestBadActor.ipdl
@@ -0,0 +1,21 @@
+include protocol PTestBadActorSub;
+
+include "mozilla/_ipdltest/TestBadActor.h";
+
+namespace mozilla {
+namespace _ipdltest {
+
+// Test that a parent sending a reentrant __delete__ message
+// is not killed if a child's message races with the reply.
+
+[ManualDealloc, ChildImpl="TestBadActorChild", ParentImpl="TestBadActorParent"]
+intr protocol PTestBadActor {
+ manages PTestBadActorSub;
+
+child:
+ async PTestBadActorSub();
+ async __delete__();
+};
+
+} // namespace _ipdltest
+} // namespace mozilla
diff --git a/ipc/ipdl/test/cxx/PTestBadActorSub.ipdl b/ipc/ipdl/test/cxx/PTestBadActorSub.ipdl
new file mode 100644
index 0000000000..aadd8b6739
--- /dev/null
+++ b/ipc/ipdl/test/cxx/PTestBadActorSub.ipdl
@@ -0,0 +1,20 @@
+include protocol PTestBadActor;
+
+include "mozilla/_ipdltest/TestBadActor.h";
+
+namespace mozilla {
+namespace _ipdltest {
+
+[ManualDealloc, ChildImpl="TestBadActorSubChild", ParentImpl="TestBadActorSubParent"]
+intr protocol PTestBadActorSub {
+ manager PTestBadActor;
+
+child:
+ [LegacyIntr] intr __delete__();
+
+parent:
+ async Ping();
+};
+
+} // namespace _ipdltest
+} // namespace mozilla
diff --git a/ipc/ipdl/test/cxx/PTestCancel.ipdl b/ipc/ipdl/test/cxx/PTestCancel.ipdl
new file mode 100644
index 0000000000..4ad902e8e1
--- /dev/null
+++ b/ipc/ipdl/test/cxx/PTestCancel.ipdl
@@ -0,0 +1,39 @@
+include "mozilla/_ipdltest/TestCancel.h";
+
+namespace mozilla {
+namespace _ipdltest {
+
+[ManualDealloc, NestedUpTo=inside_sync, ChildImpl="TestCancelChild", ParentImpl="TestCancelParent"]
+sync protocol PTestCancel
+{
+// Test1
+child:
+ [Nested=inside_sync] sync Test1_1();
+parent:
+ async Done1();
+
+// Test2
+child:
+ async Start2();
+ [Nested=inside_sync] sync Test2_2();
+parent:
+ sync Test2_1();
+
+// Test3
+child:
+ [Nested=inside_sync] sync Test3_1();
+parent:
+ async Start3();
+ [Nested=inside_sync] sync Test3_2();
+
+parent:
+ async Done();
+
+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/cxx/PTestCrashCleanup.ipdl b/ipc/ipdl/test/cxx/PTestCrashCleanup.ipdl
new file mode 100644
index 0000000000..43d955f1c7
--- /dev/null
+++ b/ipc/ipdl/test/cxx/PTestCrashCleanup.ipdl
@@ -0,0 +1,20 @@
+include "mozilla/_ipdltest/TestCrashCleanup.h";
+
+// See bug 538586: if the top-level protocol's actor is deleted before
+// the "connection error" notification comes in from the IO thread,
+// IPDL teardown never occurs, even if Channel::Close() is called
+// after the error.
+
+namespace mozilla {
+namespace _ipdltest {
+
+// NB: needs to be RPC so that the parent blocks on the child's crash.
+[ManualDealloc, ChildImpl="TestCrashCleanupChild", ParentImpl="TestCrashCleanupParent"]
+intr protocol PTestCrashCleanup {
+child:
+ [LegacyIntr] intr DIEDIEDIE();
+ async __delete__();
+};
+
+}
+}
diff --git a/ipc/ipdl/test/cxx/PTestDataStructures.ipdl b/ipc/ipdl/test/cxx/PTestDataStructures.ipdl
new file mode 100644
index 0000000000..64b6970666
--- /dev/null
+++ b/ipc/ipdl/test/cxx/PTestDataStructures.ipdl
@@ -0,0 +1,109 @@
+include protocol PTestDataStructuresSub;
+include PTestDataStructuresCommon;
+
+include "mozilla/GfxMessageUtils.h";
+include "mozilla/_ipdltest/TestDataStructures.h";
+
+namespace mozilla {
+namespace _ipdltest {
+
+[ManualDealloc, ChildImpl="TestDataStructuresChild", ParentImpl="TestDataStructuresParent"]
+sync protocol PTestDataStructures {
+ manages PTestDataStructuresSub;
+
+child:
+ async PTestDataStructuresSub(int i);
+
+ async Start();
+
+parent:
+ async __delete__();
+
+ sync Test1(int[] i1)
+ returns (int[] o1);
+
+ sync Test2(PTestDataStructuresSub[] i1)
+ returns (PTestDataStructuresSub[] o1);
+
+ sync Test3(IntDouble i1,
+ IntDouble i2)
+ returns (IntDouble o1,
+ IntDouble o2);
+
+ sync Test4(IntDouble[] i1)
+ returns (IntDouble[] o1);
+
+ sync Test5(IntDoubleArrays i1,
+ IntDoubleArrays i2,
+ IntDoubleArrays i3)
+ returns (IntDoubleArrays o1,
+ IntDoubleArrays o2,
+ IntDoubleArrays o3);
+
+ sync Test6(IntDoubleArrays[] i1)
+ returns (IntDoubleArrays[] o1);
+
+ sync Test7_0(ActorWrapper a1)
+ returns (ActorWrapper o1);
+
+ sync Test7(Actors i1,
+ Actors i2,
+ Actors i3)
+ returns (Actors o1,
+ Actors o2,
+ Actors o3);
+
+ sync Test8(Actors[] i1)
+ returns (Actors[] o1);
+
+ sync Test9(Unions i1,
+ Unions i2,
+ Unions i3,
+ Unions i4)
+ returns (Unions o1,
+ Unions o2,
+ Unions o3,
+ Unions o4);
+
+ sync Test10(Unions[] i1)
+ returns (Unions[] o1);
+
+ sync Test11(SIntDouble i)
+ returns (SIntDouble o);
+
+ sync Test12(SIntDoubleArrays i)
+ returns (SIntDoubleArrays o);
+
+ sync Test13(SActors i)
+ returns (SActors o);
+
+ sync Test14(Structs i)
+ returns (Structs o);
+
+ sync Test15(WithStructs i1,
+ WithStructs i2,
+ WithStructs i3,
+ WithStructs i4,
+ WithStructs i5)
+ returns (WithStructs o1,
+ WithStructs o2,
+ WithStructs o3,
+ WithStructs o4,
+ WithStructs o5);
+
+ sync Test16(WithUnions i)
+ returns (WithUnions o);
+
+ sync Test17(Op[] ops);
+
+ // test that the ParamTraits<nsTArray>::Read() workaround for
+ // nsTArray's incorrect memmove() semantics works properly
+ // (nsIntRegion isn't memmove()able)
+ sync Test18(nsIntRegion[] ops);
+
+ sync Dummy(ShmemUnion su) returns (ShmemUnion rsu);
+};
+
+} // namespace _ipdltest
+} // namespace mozilla
+
diff --git a/ipc/ipdl/test/cxx/PTestDataStructuresCommon.ipdlh b/ipc/ipdl/test/cxx/PTestDataStructuresCommon.ipdlh
new file mode 100644
index 0000000000..39d7f482b3
--- /dev/null
+++ b/ipc/ipdl/test/cxx/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 {
+ 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/cxx/PTestDataStructuresSub.ipdl b/ipc/ipdl/test/cxx/PTestDataStructuresSub.ipdl
new file mode 100644
index 0000000000..4f546a8d29
--- /dev/null
+++ b/ipc/ipdl/test/cxx/PTestDataStructuresSub.ipdl
@@ -0,0 +1,18 @@
+include PTestDataStructuresCommon;
+include protocol PTestDataStructures;
+
+include "mozilla/_ipdltest/TestDataStructures.h";
+
+namespace mozilla {
+namespace _ipdltest {
+
+[ManualDealloc, ChildImpl="TestDataStructuresSub", ParentImpl="TestDataStructuresSub"]
+sync protocol PTestDataStructuresSub {
+ manager PTestDataStructures;
+
+parent:
+ sync __delete__();
+};
+
+} // namespace _ipdltest
+} // namespace mozilla
diff --git a/ipc/ipdl/test/cxx/PTestDemon.ipdl b/ipc/ipdl/test/cxx/PTestDemon.ipdl
new file mode 100644
index 0000000000..f5af2396e6
--- /dev/null
+++ b/ipc/ipdl/test/cxx/PTestDemon.ipdl
@@ -0,0 +1,24 @@
+include "mozilla/_ipdltest/TestDemon.h";
+
+namespace mozilla {
+namespace _ipdltest {
+
+[ManualDealloc, NestedUpTo=inside_cpow, ChildImpl="TestDemonChild", ParentImpl="TestDemonParent"]
+sync protocol PTestDemon
+{
+child:
+ async Start();
+
+both:
+ async AsyncMessage(int n);
+ [Nested=inside_sync] sync HiPrioSyncMessage();
+
+parent:
+ sync SyncMessage(int n);
+
+ [Nested=inside_cpow] async UrgentAsyncMessage(int n);
+ [Nested=inside_cpow] sync UrgentSyncMessage(int n);
+};
+
+} // namespace _ipdltest
+} // namespace mozilla
diff --git a/ipc/ipdl/test/cxx/PTestDesc.ipdl b/ipc/ipdl/test/cxx/PTestDesc.ipdl
new file mode 100644
index 0000000000..d18d2d8598
--- /dev/null
+++ b/ipc/ipdl/test/cxx/PTestDesc.ipdl
@@ -0,0 +1,24 @@
+include protocol PTestDescSub;
+include protocol PTestDescSubsub;
+
+include "mozilla/_ipdltest/TestDesc.h";
+
+namespace mozilla {
+namespace _ipdltest {
+
+[ManualDealloc, ChildImpl="TestDescChild", ParentImpl="TestDescParent"]
+intr protocol PTestDesc {
+ manages PTestDescSub;
+child:
+ [LegacyIntr] intr PTestDescSub(nullable PTestDescSubsub dummy);
+
+ async Test(PTestDescSubsub a);
+
+ async __delete__();
+
+parent:
+ async Ok(PTestDescSubsub a);
+};
+
+}
+}
diff --git a/ipc/ipdl/test/cxx/PTestDescSub.ipdl b/ipc/ipdl/test/cxx/PTestDescSub.ipdl
new file mode 100644
index 0000000000..a05451c639
--- /dev/null
+++ b/ipc/ipdl/test/cxx/PTestDescSub.ipdl
@@ -0,0 +1,21 @@
+include protocol PTestDesc;
+include protocol PTestDescSubsub;
+
+include "mozilla/_ipdltest/TestDesc.h";
+
+namespace mozilla {
+namespace _ipdltest {
+
+[ManualDealloc, ChildImpl="TestDescSubChild", ParentImpl="TestDescSubParent"]
+intr protocol PTestDescSub {
+ manager PTestDesc;
+ manages PTestDescSubsub;
+
+child:
+ async __delete__();
+
+ [LegacyIntr] intr PTestDescSubsub();
+};
+
+}
+}
diff --git a/ipc/ipdl/test/cxx/PTestDescSubsub.ipdl b/ipc/ipdl/test/cxx/PTestDescSubsub.ipdl
new file mode 100644
index 0000000000..542a03e2d2
--- /dev/null
+++ b/ipc/ipdl/test/cxx/PTestDescSubsub.ipdl
@@ -0,0 +1,18 @@
+
+include protocol PTestDescSub;
+
+include "mozilla/_ipdltest/TestDesc.h";
+
+namespace mozilla {
+namespace _ipdltest {
+
+[ManualDealloc, ChildImpl="TestDescSubsubChild", ParentImpl="TestDescSubsubParent"]
+intr protocol PTestDescSubsub {
+ manager PTestDescSub;
+
+child:
+ [LegacyIntr] intr __delete__();
+};
+
+}
+}
diff --git a/ipc/ipdl/test/cxx/PTestEndpointBridgeMain.ipdl b/ipc/ipdl/test/cxx/PTestEndpointBridgeMain.ipdl
new file mode 100644
index 0000000000..c51967b1fa
--- /dev/null
+++ b/ipc/ipdl/test/cxx/PTestEndpointBridgeMain.ipdl
@@ -0,0 +1,25 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+
+include protocol PTestEndpointBridgeMainSub;
+include protocol PTestEndpointBridgeSub;
+
+include "mozilla/_ipdltest/TestEndpointBridgeMain.h";
+
+namespace mozilla {
+namespace _ipdltest {
+
+
+[ManualDealloc, ChildImpl="TestEndpointBridgeMainChild", ParentImpl="TestEndpointBridgeMainParent"]
+protocol PTestEndpointBridgeMain {
+
+child:
+ async Start();
+
+parent:
+ async Bridged(Endpoint<PTestEndpointBridgeMainSubParent> endpoint);
+};
+
+
+} // namespace mozilla
+} // namespace _ipdltest
diff --git a/ipc/ipdl/test/cxx/PTestEndpointBridgeMainSub.ipdl b/ipc/ipdl/test/cxx/PTestEndpointBridgeMainSub.ipdl
new file mode 100644
index 0000000000..e899fca7aa
--- /dev/null
+++ b/ipc/ipdl/test/cxx/PTestEndpointBridgeMainSub.ipdl
@@ -0,0 +1,28 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+
+include protocol PTestEndpointBridgeMain;
+include protocol PTestEndpointBridgeSub;
+
+include "mozilla/_ipdltest/TestEndpointBridgeMain.h";
+
+namespace mozilla {
+namespace _ipdltest {
+
+// (Bridge protocols can have different semantics than the endpoints
+// they bridge)
+[ManualDealloc, ChildImpl="TestEndpointBridgeMainSubChild", ParentImpl="TestEndpointBridgeMainSubParent"]
+intr protocol PTestEndpointBridgeMainSub {
+child:
+ async Hi();
+ [LegacyIntr] intr HiRpc();
+
+parent:
+ async Hello();
+ sync HelloSync();
+ [LegacyIntr] intr HelloRpc();
+};
+
+
+} // namespace mozilla
+} // namespace _ipdltest
diff --git a/ipc/ipdl/test/cxx/PTestEndpointBridgeSub.ipdl b/ipc/ipdl/test/cxx/PTestEndpointBridgeSub.ipdl
new file mode 100644
index 0000000000..ab12e3bdb5
--- /dev/null
+++ b/ipc/ipdl/test/cxx/PTestEndpointBridgeSub.ipdl
@@ -0,0 +1,25 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+
+include protocol PTestEndpointBridgeMainSub;
+
+include "mozilla/_ipdltest/TestEndpointBridgeMain.h";
+
+namespace mozilla {
+namespace _ipdltest {
+
+
+[ManualDealloc, ChildImpl="TestEndpointBridgeSubChild", ParentImpl="TestEndpointBridgeSubParent"]
+protocol PTestEndpointBridgeSub {
+child:
+ async Ping();
+
+ async Bridged(Endpoint<PTestEndpointBridgeMainSubChild> endpoint);
+
+parent:
+ async BridgeEm();
+};
+
+
+} // namespace mozilla
+} // namespace _ipdltest
diff --git a/ipc/ipdl/test/cxx/PTestEndpointOpens.ipdl b/ipc/ipdl/test/cxx/PTestEndpointOpens.ipdl
new file mode 100644
index 0000000000..6cb20bf8eb
--- /dev/null
+++ b/ipc/ipdl/test/cxx/PTestEndpointOpens.ipdl
@@ -0,0 +1,22 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+include protocol PTestEndpointOpensOpened;
+
+include "mozilla/_ipdltest/TestEndpointOpens.h";
+
+namespace mozilla {
+namespace _ipdltest {
+
+[ManualDealloc, ChildImpl="TestEndpointOpensChild", ParentImpl="TestEndpointOpensParent"]
+protocol PTestEndpointOpens {
+child:
+ async Start();
+
+parent:
+ async StartSubprotocol(Endpoint<PTestEndpointOpensOpenedParent> endpoint);
+
+ async __delete__();
+};
+
+} // namespace mozilla
+} // namespace _ipdltest
diff --git a/ipc/ipdl/test/cxx/PTestEndpointOpensOpened.ipdl b/ipc/ipdl/test/cxx/PTestEndpointOpensOpened.ipdl
new file mode 100644
index 0000000000..7f72828c30
--- /dev/null
+++ b/ipc/ipdl/test/cxx/PTestEndpointOpensOpened.ipdl
@@ -0,0 +1,25 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+include "mozilla/_ipdltest/TestEndpointOpens.h";
+
+namespace mozilla {
+namespace _ipdltest2 {
+
+// (Opens protocols can have different semantics than the endpoints
+// that opened them)
+[ManualDealloc, ChildImpl="TestEndpointOpensOpenedChild", ParentImpl="TestEndpointOpensOpenedParent"]
+intr protocol PTestEndpointOpensOpened {
+child:
+ async Hi();
+ [LegacyIntr] intr HiRpc();
+
+parent:
+ async Hello();
+ sync HelloSync();
+ [LegacyIntr] intr HelloRpc();
+ async __delete__();
+};
+
+
+} // namespace mozilla
+} // namespace _ipdltest2
diff --git a/ipc/ipdl/test/cxx/PTestFailedCtor.ipdl b/ipc/ipdl/test/cxx/PTestFailedCtor.ipdl
new file mode 100644
index 0000000000..0144f66dba
--- /dev/null
+++ b/ipc/ipdl/test/cxx/PTestFailedCtor.ipdl
@@ -0,0 +1,17 @@
+include protocol PTestFailedCtorSub;
+
+include "mozilla/_ipdltest/TestFailedCtor.h";
+
+namespace mozilla {
+namespace _ipdltest {
+
+[ManualDealloc, ChildImpl="TestFailedCtorChild", ParentImpl="TestFailedCtorParent"]
+intr protocol PTestFailedCtor {
+ manages PTestFailedCtorSub;
+child:
+ [LegacyIntr] intr PTestFailedCtorSub();
+ async __delete__();
+};
+
+}
+}
diff --git a/ipc/ipdl/test/cxx/PTestFailedCtorSub.ipdl b/ipc/ipdl/test/cxx/PTestFailedCtorSub.ipdl
new file mode 100644
index 0000000000..97bc4d4bf8
--- /dev/null
+++ b/ipc/ipdl/test/cxx/PTestFailedCtorSub.ipdl
@@ -0,0 +1,21 @@
+include protocol PTestFailedCtor;
+include protocol PTestFailedCtorSubsub;
+
+include "mozilla/_ipdltest/TestFailedCtor.h";
+
+namespace mozilla {
+namespace _ipdltest {
+
+[ManualDealloc, ChildImpl="TestFailedCtorSubChild", ParentImpl="TestFailedCtorSubParent"]
+intr protocol PTestFailedCtorSub {
+ manager PTestFailedCtor;
+ manages PTestFailedCtorSubsub;
+
+parent:
+ async PTestFailedCtorSubsub();
+ sync Sync();
+ async __delete__();
+};
+
+}
+}
diff --git a/ipc/ipdl/test/cxx/PTestFailedCtorSubsub.ipdl b/ipc/ipdl/test/cxx/PTestFailedCtorSubsub.ipdl
new file mode 100644
index 0000000000..84cb2a0eb8
--- /dev/null
+++ b/ipc/ipdl/test/cxx/PTestFailedCtorSubsub.ipdl
@@ -0,0 +1,18 @@
+
+include protocol PTestFailedCtorSub;
+
+include "mozilla/_ipdltest/TestFailedCtor.h";
+
+namespace mozilla {
+namespace _ipdltest {
+
+[ManualDealloc, ChildImpl="TestFailedCtorSubsub", ParentImpl="TestFailedCtorSubsub"]
+intr protocol PTestFailedCtorSubsub {
+ manager PTestFailedCtorSub;
+
+parent:
+ async __delete__();
+};
+
+}
+}
diff --git a/ipc/ipdl/test/cxx/PTestHandle.ipdl b/ipc/ipdl/test/cxx/PTestHandle.ipdl
new file mode 100644
index 0000000000..b0a65f69c0
--- /dev/null
+++ b/ipc/ipdl/test/cxx/PTestHandle.ipdl
@@ -0,0 +1,17 @@
+include protocol PTestJSON;
+
+include "mozilla/_ipdltest/TestJSON.h";
+
+namespace mozilla {
+namespace _ipdltest {
+
+[ManualDealloc, ChildImpl="TestHandleChild", ParentImpl="TestHandleParent"]
+protocol PTestHandle {
+ manager PTestJSON;
+
+child:
+ async __delete__();
+};
+
+} // namespace mozilla
+} // namespace _ipdltest
diff --git a/ipc/ipdl/test/cxx/PTestHangs.ipdl b/ipc/ipdl/test/cxx/PTestHangs.ipdl
new file mode 100644
index 0000000000..cadc1eda2e
--- /dev/null
+++ b/ipc/ipdl/test/cxx/PTestHangs.ipdl
@@ -0,0 +1,22 @@
+
+include "mozilla/_ipdltest/TestHangs.h";
+
+namespace mozilla {
+namespace _ipdltest {
+
+[ManualDealloc, ChildImpl="TestHangsChild", ParentImpl="TestHangsParent"]
+intr protocol PTestHangs {
+both:
+ [LegacyIntr] intr StackFrame();
+
+parent:
+ async Nonce();
+
+child:
+ async Start();
+ [LegacyIntr] intr Hang();
+ async __delete__();
+};
+
+} // namespace _ipdltest
+} // namespace mozilla
diff --git a/ipc/ipdl/test/cxx/PTestHighestPrio.ipdl b/ipc/ipdl/test/cxx/PTestHighestPrio.ipdl
new file mode 100644
index 0000000000..877ba427b6
--- /dev/null
+++ b/ipc/ipdl/test/cxx/PTestHighestPrio.ipdl
@@ -0,0 +1,21 @@
+include "mozilla/_ipdltest/TestHighestPrio.h";
+
+namespace mozilla {
+namespace _ipdltest {
+
+[ManualDealloc, NestedUpTo=inside_cpow, ChildImpl="TestHighestPrioChild", ParentImpl="TestHighestPrioParent"]
+sync protocol PTestHighestPrio
+{
+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/cxx/PTestIndirectProtocolParam.ipdlh b/ipc/ipdl/test/cxx/PTestIndirectProtocolParam.ipdlh
new file mode 100644
index 0000000000..a81fcdee46
--- /dev/null
+++ b/ipc/ipdl/test/cxx/PTestIndirectProtocolParam.ipdlh
@@ -0,0 +1,15 @@
+include protocol PTestIndirectProtocolParamSecond;
+
+namespace mozilla {
+namespace _ipdltest {
+
+struct IndirectParamStruct {
+ PTestIndirectProtocolParamSecond actor;
+};
+
+union IndirectParamUnion {
+ IndirectParamStruct;
+};
+
+}
+}
diff --git a/ipc/ipdl/test/cxx/PTestIndirectProtocolParamFirst.ipdl b/ipc/ipdl/test/cxx/PTestIndirectProtocolParamFirst.ipdl
new file mode 100644
index 0000000000..5364d79ffb
--- /dev/null
+++ b/ipc/ipdl/test/cxx/PTestIndirectProtocolParamFirst.ipdl
@@ -0,0 +1,20 @@
+include protocol PTestIndirectProtocolParamManage;
+// FIXME/bug 792908 protocol PTestIndirectProtocolParamSecond is
+// already included in PTestIndirectProtocolParam.ipdlh
+include protocol PTestIndirectProtocolParamSecond;
+include PTestIndirectProtocolParam;
+
+namespace mozilla {
+namespace _ipdltest {
+
+[ManualDealloc, ChildImpl=virtual, ParentImpl=virtual]
+sync protocol PTestIndirectProtocolParamFirst {
+ manager PTestIndirectProtocolParamManage;
+parent:
+ sync Test(IndirectParamUnion actor);
+both:
+ async __delete__();
+};
+
+}
+}
diff --git a/ipc/ipdl/test/cxx/PTestIndirectProtocolParamManage.ipdl b/ipc/ipdl/test/cxx/PTestIndirectProtocolParamManage.ipdl
new file mode 100644
index 0000000000..8d3c6f81b1
--- /dev/null
+++ b/ipc/ipdl/test/cxx/PTestIndirectProtocolParamManage.ipdl
@@ -0,0 +1,18 @@
+include protocol PTestIndirectProtocolParamFirst;
+include protocol PTestIndirectProtocolParamSecond;
+
+namespace mozilla {
+namespace _ipdltest {
+
+[ManualDealloc, ChildImpl=virtual, ParentImpl=virtual]
+sync protocol PTestIndirectProtocolParamManage {
+ manages PTestIndirectProtocolParamFirst;
+ manages PTestIndirectProtocolParamSecond;
+both:
+ async PTestIndirectProtocolParamFirst();
+ async PTestIndirectProtocolParamSecond();
+ async __delete__();
+};
+
+}
+}
diff --git a/ipc/ipdl/test/cxx/PTestIndirectProtocolParamSecond.ipdl b/ipc/ipdl/test/cxx/PTestIndirectProtocolParamSecond.ipdl
new file mode 100644
index 0000000000..27545ca2cb
--- /dev/null
+++ b/ipc/ipdl/test/cxx/PTestIndirectProtocolParamSecond.ipdl
@@ -0,0 +1,14 @@
+include protocol PTestIndirectProtocolParamManage;
+
+namespace mozilla {
+namespace _ipdltest {
+
+[ManualDealloc, ChildImpl=virtual, ParentImpl=virtual]
+sync protocol PTestIndirectProtocolParamSecond {
+ manager PTestIndirectProtocolParamManage;
+both:
+ async __delete__();
+};
+
+}
+}
diff --git a/ipc/ipdl/test/cxx/PTestInterruptErrorCleanup.ipdl b/ipc/ipdl/test/cxx/PTestInterruptErrorCleanup.ipdl
new file mode 100644
index 0000000000..ab6754cc1b
--- /dev/null
+++ b/ipc/ipdl/test/cxx/PTestInterruptErrorCleanup.ipdl
@@ -0,0 +1,14 @@
+include "mozilla/_ipdltest/TestInterruptErrorCleanup.h";
+
+namespace mozilla {
+namespace _ipdltest {
+
+[ManualDealloc, ChildImpl="TestInterruptErrorCleanupChild", ParentImpl="TestInterruptErrorCleanupParent"]
+intr protocol PTestInterruptErrorCleanup {
+child:
+ [LegacyIntr] intr Error();
+ [LegacyIntr] intr __delete__();
+};
+
+} // namespace _ipdltest
+} // namespace mozilla
diff --git a/ipc/ipdl/test/cxx/PTestInterruptRaces.ipdl b/ipc/ipdl/test/cxx/PTestInterruptRaces.ipdl
new file mode 100644
index 0000000000..aa66966938
--- /dev/null
+++ b/ipc/ipdl/test/cxx/PTestInterruptRaces.ipdl
@@ -0,0 +1,27 @@
+include "mozilla/_ipdltest/TestInterruptRaces.h";
+
+namespace mozilla {
+namespace _ipdltest {
+
+[ManualDealloc, ChildImpl="TestInterruptRacesChild", ParentImpl="TestInterruptRacesParent"]
+intr protocol PTestInterruptRaces {
+both:
+ [LegacyIntr] intr Race() returns (bool hasReply);
+ [LegacyIntr] intr StackFrame() returns ();
+ [LegacyIntr] intr StackFrame3() returns ();
+
+parent:
+ sync StartRace();
+ [LegacyIntr] intr Parent();
+ sync GetAnsweredParent() returns (bool answeredParent);
+
+child:
+ async Start();
+ async Wakeup();
+ async Wakeup3();
+ [LegacyIntr] intr Child();
+ async __delete__();
+};
+
+} // namespace _ipdltest
+} // namespace mozilla
diff --git a/ipc/ipdl/test/cxx/PTestInterruptShutdownRace.ipdl b/ipc/ipdl/test/cxx/PTestInterruptShutdownRace.ipdl
new file mode 100644
index 0000000000..84bc6f0a97
--- /dev/null
+++ b/ipc/ipdl/test/cxx/PTestInterruptShutdownRace.ipdl
@@ -0,0 +1,19 @@
+include "mozilla/_ipdltest/TestInterruptShutdownRace.h";
+
+namespace mozilla {
+namespace _ipdltest {
+
+[ManualDealloc, ChildImpl="TestInterruptShutdownRaceChild", ParentImpl="TestInterruptShutdownRaceParent"]
+intr protocol PTestInterruptShutdownRace {
+parent:
+ sync StartDeath();
+ async Orphan();
+
+child:
+ async Start();
+ [LegacyIntr] intr Exit();
+ async __delete__();
+};
+
+} // namespace _ipdltest
+} // namespace mozilla
diff --git a/ipc/ipdl/test/cxx/PTestJSON.ipdl b/ipc/ipdl/test/cxx/PTestJSON.ipdl
new file mode 100644
index 0000000000..c785abe77a
--- /dev/null
+++ b/ipc/ipdl/test/cxx/PTestJSON.ipdl
@@ -0,0 +1,49 @@
+include protocol PTestHandle;
+
+include "mozilla/_ipdltest/TestJSON.h";
+
+using struct mozilla::void_t from "mozilla/ipc/IPCCore.h";
+using struct mozilla::null_t from "mozilla/ipc/IPCCore.h";
+
+namespace mozilla {
+namespace _ipdltest {
+
+union Key {
+// int;
+// double;
+ nsString;
+};
+
+struct KeyValue {
+ Key key;
+ JSONVariant value;
+};
+
+union JSONVariant {
+ void_t;
+ null_t;
+ bool;
+ int;
+ double;
+ nsString;
+ PTestHandle;
+ KeyValue[];
+ JSONVariant[];
+};
+
+[ManualDealloc, ChildImpl="TestJSONChild", ParentImpl="TestJSONParent"]
+sync protocol PTestJSON {
+ manages PTestHandle;
+
+child:
+ async Start();
+
+parent:
+ async PTestHandle();
+ sync Test(JSONVariant i)
+ returns (JSONVariant o);
+ async __delete__();
+};
+
+} // namespace mozilla
+} // namespace _ipdltest
diff --git a/ipc/ipdl/test/cxx/PTestLatency.ipdl b/ipc/ipdl/test/cxx/PTestLatency.ipdl
new file mode 100644
index 0000000000..d868d119a2
--- /dev/null
+++ b/ipc/ipdl/test/cxx/PTestLatency.ipdl
@@ -0,0 +1,28 @@
+include "mozilla/_ipdltest/TestLatency.h";
+
+namespace mozilla {
+namespace _ipdltest {
+
+
+[ManualDealloc, ChildImpl="TestLatencyChild", ParentImpl="TestLatencyParent"]
+intr protocol PTestLatency {
+
+child:
+ async __delete__();
+ async Ping();
+ async Ping5();
+ [LegacyIntr] intr Rpc();
+ async Spam();
+ [LegacyIntr] intr Synchro();
+ [Compress] async CompressedSpam(uint32_t seqno);
+ [LegacyIntr] intr Synchro2() returns (uint32_t lastSeqno,
+ uint32_t numMessagesDispatched);
+
+parent:
+ async Pong();
+ async Pong5();
+};
+
+
+} // namespace mozilla
+} // namespace _ipdltest
diff --git a/ipc/ipdl/test/cxx/PTestManyChildAllocs.ipdl b/ipc/ipdl/test/cxx/PTestManyChildAllocs.ipdl
new file mode 100644
index 0000000000..6f8a0e1187
--- /dev/null
+++ b/ipc/ipdl/test/cxx/PTestManyChildAllocs.ipdl
@@ -0,0 +1,22 @@
+include protocol PTestManyChildAllocsSub;
+
+include "mozilla/_ipdltest/TestManyChildAllocs.h";
+
+namespace mozilla {
+namespace _ipdltest {
+
+[ManualDealloc, ChildImpl="TestManyChildAllocsChild", ParentImpl="TestManyChildAllocsParent"]
+protocol PTestManyChildAllocs {
+ manages PTestManyChildAllocsSub;
+
+child:
+ async Go(); // start allocating
+
+parent:
+ async Done();
+
+ async PTestManyChildAllocsSub();
+};
+
+} // namespace _ipdltest
+} // namespace mozilla
diff --git a/ipc/ipdl/test/cxx/PTestManyChildAllocsSub.ipdl b/ipc/ipdl/test/cxx/PTestManyChildAllocsSub.ipdl
new file mode 100644
index 0000000000..e20c2badfd
--- /dev/null
+++ b/ipc/ipdl/test/cxx/PTestManyChildAllocsSub.ipdl
@@ -0,0 +1,22 @@
+include protocol PTestManyChildAllocs;
+
+include "mozilla/_ipdltest/TestManyChildAllocs.h";
+
+namespace mozilla {
+namespace _ipdltest {
+
+[ManualDealloc, ChildImpl="TestManyChildAllocsSubChild", ParentImpl="TestManyChildAllocsSubParent"]
+protocol PTestManyChildAllocsSub {
+ manager PTestManyChildAllocs;
+
+child:
+ async __delete__();
+
+parent:
+ async Hello();
+
+ // empty
+};
+
+} // namespace _ipdltest
+} // namespace mozilla
diff --git a/ipc/ipdl/test/cxx/PTestMultiMgrs.ipdl b/ipc/ipdl/test/cxx/PTestMultiMgrs.ipdl
new file mode 100644
index 0000000000..65272fa991
--- /dev/null
+++ b/ipc/ipdl/test/cxx/PTestMultiMgrs.ipdl
@@ -0,0 +1,25 @@
+include protocol PTestMultiMgrsLeft;
+include protocol PTestMultiMgrsRight;
+
+include "mozilla/_ipdltest/TestMultiMgrs.h";
+
+namespace mozilla {
+namespace _ipdltest {
+
+[ManualDealloc, ChildImpl="TestMultiMgrsChild", ParentImpl="TestMultiMgrsParent"]
+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/cxx/PTestMultiMgrsBottom.ipdl b/ipc/ipdl/test/cxx/PTestMultiMgrsBottom.ipdl
new file mode 100644
index 0000000000..be85b1547b
--- /dev/null
+++ b/ipc/ipdl/test/cxx/PTestMultiMgrsBottom.ipdl
@@ -0,0 +1,18 @@
+include protocol PTestMultiMgrsLeft;
+include protocol PTestMultiMgrsRight;
+
+include "mozilla/_ipdltest/TestMultiMgrs.h";
+
+namespace mozilla {
+namespace _ipdltest {
+
+[ManualDealloc, ChildImpl="TestMultiMgrsBottomChild", ParentImpl="TestMultiMgrsBottomParent"]
+protocol PTestMultiMgrsBottom {
+ manager PTestMultiMgrsLeft or PTestMultiMgrsRight;
+
+child:
+ async __delete__();
+};
+
+} // namespace _ipdltest
+} // namespace mozilla
diff --git a/ipc/ipdl/test/cxx/PTestMultiMgrsLeft.ipdl b/ipc/ipdl/test/cxx/PTestMultiMgrsLeft.ipdl
new file mode 100644
index 0000000000..3796ff315e
--- /dev/null
+++ b/ipc/ipdl/test/cxx/PTestMultiMgrsLeft.ipdl
@@ -0,0 +1,21 @@
+include protocol PTestMultiMgrs;
+include protocol PTestMultiMgrsBottom;
+
+include "mozilla/_ipdltest/TestMultiMgrs.h";
+
+namespace mozilla {
+namespace _ipdltest {
+
+[ManualDealloc, ChildImpl="TestMultiMgrsLeftChild", ParentImpl="TestMultiMgrsLeftParent"]
+protocol PTestMultiMgrsLeft {
+ manager PTestMultiMgrs;
+
+ manages PTestMultiMgrsBottom;
+
+child:
+ async PTestMultiMgrsBottom();
+ async __delete__();
+};
+
+} // namespace _ipdltest
+} // namespace mozilla
diff --git a/ipc/ipdl/test/cxx/PTestMultiMgrsRight.ipdl b/ipc/ipdl/test/cxx/PTestMultiMgrsRight.ipdl
new file mode 100644
index 0000000000..174ada5ca3
--- /dev/null
+++ b/ipc/ipdl/test/cxx/PTestMultiMgrsRight.ipdl
@@ -0,0 +1,21 @@
+include protocol PTestMultiMgrs;
+include protocol PTestMultiMgrsBottom;
+
+include "mozilla/_ipdltest/TestMultiMgrs.h";
+
+namespace mozilla {
+namespace _ipdltest {
+
+[ManualDealloc, ChildImpl="TestMultiMgrsRightChild", ParentImpl="TestMultiMgrsRightParent"]
+protocol PTestMultiMgrsRight {
+ manager PTestMultiMgrs;
+
+ manages PTestMultiMgrsBottom;
+
+child:
+ async PTestMultiMgrsBottom();
+ async __delete__();
+};
+
+} // namespace _ipdltest
+} // namespace mozilla
diff --git a/ipc/ipdl/test/cxx/PTestNestedLoops.ipdl b/ipc/ipdl/test/cxx/PTestNestedLoops.ipdl
new file mode 100644
index 0000000000..168461ab41
--- /dev/null
+++ b/ipc/ipdl/test/cxx/PTestNestedLoops.ipdl
@@ -0,0 +1,22 @@
+
+include "mozilla/_ipdltest/TestNestedLoops.h";
+
+namespace mozilla {
+namespace _ipdltest {
+
+
+[ManualDealloc, ChildImpl="TestNestedLoopsChild", ParentImpl="TestNestedLoopsParent"]
+intr protocol PTestNestedLoops {
+
+child:
+ async Start();
+ [LegacyIntr] intr R();
+ async __delete__();
+
+parent:
+ async Nonce();
+};
+
+
+} // namespace mozilla
+} // namespace _ipdltest
diff --git a/ipc/ipdl/test/cxx/PTestPaintThread.ipdl b/ipc/ipdl/test/cxx/PTestPaintThread.ipdl
new file mode 100644
index 0000000000..00d46c9757
--- /dev/null
+++ b/ipc/ipdl/test/cxx/PTestPaintThread.ipdl
@@ -0,0 +1,15 @@
+include "mozilla/_ipdltest/TestOffMainThreadPainting.h";
+
+namespace mozilla {
+namespace _ipdltest {
+
+// This is supposed to be analagous to PPaintingBridge.
+[ManualDealloc, ChildImpl="TestPaintThreadChild", ParentImpl="TestPaintThreadParent"]
+sync protocol PTestPaintThread
+{
+parent:
+ sync FinishedPaint(uint64_t aTxnId);
+};
+
+} // namespace mozilla
+} // namespace _ipdltest
diff --git a/ipc/ipdl/test/cxx/PTestPriority.ipdl b/ipc/ipdl/test/cxx/PTestPriority.ipdl
new file mode 100644
index 0000000000..8b85368072
--- /dev/null
+++ b/ipc/ipdl/test/cxx/PTestPriority.ipdl
@@ -0,0 +1,24 @@
+namespace mozilla {
+namespace _ipdltest {
+
+[ManualDealloc, ChildImpl=virtual, ParentImpl=virtual]
+sync protocol PTestPriority {
+parent:
+ [Priority=input] async PMsg1();
+ [Priority=input] sync PMsg2();
+ [Priority=vsync] async PMsg3();
+ [Priority=vsync] sync PMsg4();
+ [Priority=mediumhigh] async PMsg5();
+ [Priority=mediumhigh] sync PMsg6();
+ [Priority=control] async PMsg7();
+ [Priority=control] sync PMsg8();
+
+child:
+ [Priority=input] async CMsg1();
+ [Priority=vsync] async CMsg2();
+ [Priority=mediumhigh] async CMsg3();
+ [Priority=control] async CMsg4();
+};
+
+} // namespace _ipdltest
+} // namespace mozilla
diff --git a/ipc/ipdl/test/cxx/PTestRPC.ipdl b/ipc/ipdl/test/cxx/PTestRPC.ipdl
new file mode 100644
index 0000000000..4d459eeb03
--- /dev/null
+++ b/ipc/ipdl/test/cxx/PTestRPC.ipdl
@@ -0,0 +1,24 @@
+include "mozilla/_ipdltest/TestRPC.h";
+
+namespace mozilla {
+namespace _ipdltest {
+
+[ManualDealloc, NestedUpTo=inside_sync, ChildImpl="TestRPCChild", ParentImpl="TestRPCParent"]
+sync protocol PTestRPC
+{
+parent:
+ [Nested=inside_sync] sync Test1_Start() returns (uint32_t result);
+ [Nested=inside_sync] sync Test1_InnerEvent() returns (uint32_t result);
+ async Test2_Start();
+ [Nested=inside_sync] sync Test2_OutOfOrder();
+
+child:
+ async Start();
+ [Nested=inside_sync] sync Test1_InnerQuery() returns (uint32_t result);
+ [Nested=inside_sync] sync Test1_NoReenter() returns (uint32_t result);
+ [Nested=inside_sync] sync Test2_FirstUrgent();
+ [Nested=inside_sync] sync Test2_SecondUrgent();
+};
+
+} // namespace _ipdltest
+} // namespace mozilla
diff --git a/ipc/ipdl/test/cxx/PTestRaceDeadlock.ipdl b/ipc/ipdl/test/cxx/PTestRaceDeadlock.ipdl
new file mode 100644
index 0000000000..125919f9af
--- /dev/null
+++ b/ipc/ipdl/test/cxx/PTestRaceDeadlock.ipdl
@@ -0,0 +1,23 @@
+include "mozilla/_ipdltest/TestRaceDeadlock.h";
+
+namespace mozilla {
+namespace _ipdltest {
+
+[ManualDealloc, ChildImpl="TestRaceDeadlockChild", ParentImpl="TestRaceDeadlockParent"]
+intr protocol PTestRaceDeadlock {
+both:
+ async StartRace();
+
+parent:
+ [LegacyIntr] intr Lose();
+
+child:
+ [LegacyIntr] intr Win();
+ [LegacyIntr] intr Rpc();
+ async __delete__();
+
+/* Tests that race resolution does not cause deadlocks */
+};
+
+} // namespace _ipdltest
+} // namespace mozilla
diff --git a/ipc/ipdl/test/cxx/PTestRaceDeferral.ipdl b/ipc/ipdl/test/cxx/PTestRaceDeferral.ipdl
new file mode 100644
index 0000000000..f165fa1cea
--- /dev/null
+++ b/ipc/ipdl/test/cxx/PTestRaceDeferral.ipdl
@@ -0,0 +1,22 @@
+include "mozilla/_ipdltest/TestRaceDeferral.h";
+
+namespace mozilla {
+namespace _ipdltest {
+
+[ManualDealloc, ChildImpl="TestRaceDeferralChild", ParentImpl="TestRaceDeferralParent"]
+intr protocol PTestRaceDeferral {
+parent:
+ [LegacyIntr] intr Lose();
+
+child:
+ async StartRace();
+ [LegacyIntr] intr Win();
+ [LegacyIntr] intr Rpc();
+ async __delete__();
+
+// Test that messages deferred due to race resolution are
+// re-considered when the winner makes later RPCs
+};
+
+} // namespace _ipdltest
+} // namespace mozilla
diff --git a/ipc/ipdl/test/cxx/PTestRacyInterruptReplies.ipdl b/ipc/ipdl/test/cxx/PTestRacyInterruptReplies.ipdl
new file mode 100644
index 0000000000..37b7973e6d
--- /dev/null
+++ b/ipc/ipdl/test/cxx/PTestRacyInterruptReplies.ipdl
@@ -0,0 +1,20 @@
+include "mozilla/_ipdltest/TestRacyInterruptReplies.h";
+
+namespace mozilla {
+namespace _ipdltest {
+
+[ManualDealloc, ChildImpl="TestRacyInterruptRepliesChild", ParentImpl="TestRacyInterruptRepliesParent"]
+intr protocol PTestRacyInterruptReplies {
+child:
+ [LegacyIntr] intr R_() returns (int replyNum);
+ async _A();
+ async ChildTest();
+ async __delete__();
+
+parent:
+ [LegacyIntr] intr _R() returns (int replyNum);
+ async A_();
+};
+
+} // namespace _ipdltest
+} // namespace mozilla
diff --git a/ipc/ipdl/test/cxx/PTestRacyReentry.ipdl b/ipc/ipdl/test/cxx/PTestRacyReentry.ipdl
new file mode 100644
index 0000000000..b9579cef24
--- /dev/null
+++ b/ipc/ipdl/test/cxx/PTestRacyReentry.ipdl
@@ -0,0 +1,23 @@
+include "mozilla/_ipdltest/TestRacyReentry.h";
+
+namespace mozilla {
+namespace _ipdltest {
+
+
+[ManualDealloc, ChildImpl="TestRacyReentryChild", ParentImpl="TestRacyReentryParent"]
+intr protocol PTestRacyReentry {
+
+parent:
+ [LegacyIntr] intr E();
+ async __delete__();
+
+child:
+ async Start();
+
+ async N();
+ [LegacyIntr] intr H();
+};
+
+
+} // namespace mozilla
+} // namespace _ipdltest
diff --git a/ipc/ipdl/test/cxx/PTestRacyUndefer.ipdl b/ipc/ipdl/test/cxx/PTestRacyUndefer.ipdl
new file mode 100644
index 0000000000..6256eca9db
--- /dev/null
+++ b/ipc/ipdl/test/cxx/PTestRacyUndefer.ipdl
@@ -0,0 +1,30 @@
+include "mozilla/_ipdltest/TestRacyUndefer.h";
+
+namespace mozilla {
+namespace _ipdltest {
+
+
+[ManualDealloc, ChildImpl="TestRacyUndeferChild", ParentImpl="TestRacyUndeferParent"]
+intr protocol PTestRacyUndefer {
+
+child:
+ async Start();
+
+ async AwakenSpam();
+ async AwakenRaceWinTwice();
+
+ [LegacyIntr] intr Race();
+
+ async __delete__();
+
+parent:
+
+ [LegacyIntr] intr Spam();
+ [LegacyIntr] intr RaceWinTwice();
+
+ async Done();
+};
+
+
+} // namespace mozilla
+} // namespace _ipdltest
diff --git a/ipc/ipdl/test/cxx/PTestSanity.ipdl b/ipc/ipdl/test/cxx/PTestSanity.ipdl
new file mode 100644
index 0000000000..3b3e130d4a
--- /dev/null
+++ b/ipc/ipdl/test/cxx/PTestSanity.ipdl
@@ -0,0 +1,21 @@
+
+include "mozilla/_ipdltest/TestSanity.h";
+
+namespace mozilla {
+namespace _ipdltest {
+
+
+[ManualDealloc, ChildImpl="TestSanityChild", ParentImpl="TestSanityParent"]
+protocol PTestSanity {
+
+child:
+ async Ping(int zero, float zeroPtFive, int8_t dummy);
+ async __delete__();
+
+parent:
+ async Pong(int one, float zeroPtTwoFive, uint8_t dummy);
+};
+
+
+} // namespace mozilla
+} // namespace _ipdltest
diff --git a/ipc/ipdl/test/cxx/PTestSelfManage.ipdl b/ipc/ipdl/test/cxx/PTestSelfManage.ipdl
new file mode 100644
index 0000000000..19f81a5ae7
--- /dev/null
+++ b/ipc/ipdl/test/cxx/PTestSelfManage.ipdl
@@ -0,0 +1,21 @@
+include protocol PTestSelfManageRoot;
+
+include "mozilla/_ipdltest/TestSelfManageRoot.h";
+
+namespace mozilla {
+namespace _ipdltest {
+
+
+[ManualDealloc, ChildImpl="TestSelfManageChild", ParentImpl="TestSelfManageParent"]
+protocol PTestSelfManage {
+ manager PTestSelfManageRoot or PTestSelfManage;
+ manages PTestSelfManage;
+
+child:
+ async PTestSelfManage();
+ async __delete__();
+};
+
+
+} // namespace mozilla
+} // namespace _ipdltest
diff --git a/ipc/ipdl/test/cxx/PTestSelfManageRoot.ipdl b/ipc/ipdl/test/cxx/PTestSelfManageRoot.ipdl
new file mode 100644
index 0000000000..29953228af
--- /dev/null
+++ b/ipc/ipdl/test/cxx/PTestSelfManageRoot.ipdl
@@ -0,0 +1,20 @@
+include protocol PTestSelfManage;
+
+include "mozilla/_ipdltest/TestSelfManageRoot.h";
+
+namespace mozilla {
+namespace _ipdltest {
+
+
+[ManualDealloc, ChildImpl="TestSelfManageRootChild", ParentImpl="TestSelfManageRootParent"]
+protocol PTestSelfManageRoot {
+ manages PTestSelfManage;
+
+child:
+ async PTestSelfManage();
+ async __delete__();
+};
+
+
+} // namespace mozilla
+} // namespace _ipdltest
diff --git a/ipc/ipdl/test/cxx/PTestShmem.ipdl b/ipc/ipdl/test/cxx/PTestShmem.ipdl
new file mode 100644
index 0000000000..7eb6dfdc36
--- /dev/null
+++ b/ipc/ipdl/test/cxx/PTestShmem.ipdl
@@ -0,0 +1,17 @@
+include "mozilla/_ipdltest/TestShmem.h";
+
+namespace mozilla {
+namespace _ipdltest {
+
+[ManualDealloc, ChildImpl="TestShmemChild", ParentImpl="TestShmemParent"]
+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/cxx/PTestShutdown.ipdl b/ipc/ipdl/test/cxx/PTestShutdown.ipdl
new file mode 100644
index 0000000000..e57defa46a
--- /dev/null
+++ b/ipc/ipdl/test/cxx/PTestShutdown.ipdl
@@ -0,0 +1,29 @@
+include protocol PTestShutdownSub;
+
+include "mozilla/_ipdltest/TestShutdown.h";
+
+namespace mozilla {
+namespace _ipdltest {
+
+[ManualDealloc, ChildImpl="TestShutdownChild", ParentImpl="TestShutdownParent"]
+intr protocol PTestShutdown {
+ manages PTestShutdownSub;
+
+child:
+ async Start();
+
+parent:
+ // NB: we test deletion and crashing only, not shutdown, because
+ // crashing is the same code path as shutdown, and other IPDL unit
+ // tests check shutdown semantics
+ async PTestShutdownSub(bool expectCrash);
+
+ // Used to synchronize between parent and child, to avoid races
+ // around flushing socket write queues
+ sync Sync();
+
+ async __delete__();
+};
+
+} // namespace _ipdltest
+} // namespace mozilla
diff --git a/ipc/ipdl/test/cxx/PTestShutdownSub.ipdl b/ipc/ipdl/test/cxx/PTestShutdownSub.ipdl
new file mode 100644
index 0000000000..e91caca740
--- /dev/null
+++ b/ipc/ipdl/test/cxx/PTestShutdownSub.ipdl
@@ -0,0 +1,23 @@
+include protocol PTestShutdown;
+include protocol PTestShutdownSubsub;
+
+include "mozilla/_ipdltest/TestShutdown.h";
+
+namespace mozilla {
+namespace _ipdltest {
+
+[ManualDealloc, ChildImpl="TestShutdownSubChild", ParentImpl="TestShutdownSubParent"]
+intr protocol PTestShutdownSub {
+ manager PTestShutdown;
+ manages PTestShutdownSubsub;
+
+both:
+ [LegacyIntr] intr StackFrame();
+
+parent:
+ async PTestShutdownSubsub(bool expectParentDeleted);
+ sync __delete__();
+};
+
+} // namespace _ipdltest
+} // namespace mozilla
diff --git a/ipc/ipdl/test/cxx/PTestShutdownSubsub.ipdl b/ipc/ipdl/test/cxx/PTestShutdownSubsub.ipdl
new file mode 100644
index 0000000000..3b1cc5cb6b
--- /dev/null
+++ b/ipc/ipdl/test/cxx/PTestShutdownSubsub.ipdl
@@ -0,0 +1,17 @@
+include protocol PTestShutdownSub;
+
+include "mozilla/_ipdltest/TestShutdown.h";
+
+namespace mozilla {
+namespace _ipdltest {
+
+[ManualDealloc, ChildImpl="TestShutdownSubsubChild", ParentImpl="TestShutdownSubsubParent"]
+sync protocol PTestShutdownSubsub {
+ manager PTestShutdownSub;
+
+parent:
+ sync __delete__();
+};
+
+} // namespace _ipdltest
+} // namespace mozilla
diff --git a/ipc/ipdl/test/cxx/PTestStackHooks.ipdl b/ipc/ipdl/test/cxx/PTestStackHooks.ipdl
new file mode 100644
index 0000000000..3026dfbfbe
--- /dev/null
+++ b/ipc/ipdl/test/cxx/PTestStackHooks.ipdl
@@ -0,0 +1,28 @@
+include "mozilla/_ipdltest/TestStackHooks.h";
+
+namespace mozilla {
+namespace _ipdltest {
+
+
+[ManualDealloc, ChildImpl="TestStackHooksChild", ParentImpl="TestStackHooksParent"]
+intr protocol PTestStackHooks {
+child:
+ async Start();
+
+ // These tests are more fruitful running child->parent, because
+ // children can send |sync| messages
+parent:
+ async Async();
+ sync Sync();
+ [LegacyIntr] intr Rpc();
+
+both:
+ [LegacyIntr] intr StackFrame();
+
+parent:
+ async __delete__();
+};
+
+
+} // namespace mozilla
+} // namespace _ipdltest
diff --git a/ipc/ipdl/test/cxx/PTestSyncError.ipdl b/ipc/ipdl/test/cxx/PTestSyncError.ipdl
new file mode 100644
index 0000000000..a4b6d428e8
--- /dev/null
+++ b/ipc/ipdl/test/cxx/PTestSyncError.ipdl
@@ -0,0 +1,20 @@
+include "mozilla/_ipdltest/TestSyncError.h";
+
+namespace mozilla {
+namespace _ipdltest {
+
+
+[ManualDealloc, ChildImpl="TestSyncErrorChild", ParentImpl="TestSyncErrorParent"]
+sync protocol PTestSyncError {
+
+child:
+ async Start();
+
+parent:
+ sync Error();
+ async __delete__();
+};
+
+
+} // namespace mozilla
+} // namespace _ipdltest
diff --git a/ipc/ipdl/test/cxx/PTestSyncHang.ipdl b/ipc/ipdl/test/cxx/PTestSyncHang.ipdl
new file mode 100644
index 0000000000..05521d6ed2
--- /dev/null
+++ b/ipc/ipdl/test/cxx/PTestSyncHang.ipdl
@@ -0,0 +1,16 @@
+include "mozilla/_ipdltest/TestSyncHang.h";
+
+namespace mozilla {
+namespace _ipdltest {
+
+
+[ManualDealloc, ChildImpl="TestSyncHangChild", ParentImpl="TestSyncHangParent"]
+protocol PTestSyncHang {
+
+child:
+ async UnusedMessage();
+};
+
+
+} // namespace mozilla
+} // namespace _ipdltest
diff --git a/ipc/ipdl/test/cxx/PTestSyncWakeup.ipdl b/ipc/ipdl/test/cxx/PTestSyncWakeup.ipdl
new file mode 100644
index 0000000000..807f558dfa
--- /dev/null
+++ b/ipc/ipdl/test/cxx/PTestSyncWakeup.ipdl
@@ -0,0 +1,23 @@
+include "mozilla/_ipdltest/TestSyncWakeup.h";
+
+namespace mozilla {
+namespace _ipdltest {
+
+[ManualDealloc, ChildImpl="TestSyncWakeupChild", ParentImpl="TestSyncWakeupParent"]
+intr protocol PTestSyncWakeup {
+both:
+ [LegacyIntr] intr StackFrame();
+
+child:
+ async Start();
+ async Note1();
+ async Note2();
+
+parent:
+ sync Sync1();
+ sync Sync2();
+ async __delete__();
+};
+
+} // namespace _ipdltest
+} // namespace mozilla
diff --git a/ipc/ipdl/test/cxx/PTestUniquePtrIPC.ipdl b/ipc/ipdl/test/cxx/PTestUniquePtrIPC.ipdl
new file mode 100644
index 0000000000..b436dcbbb3
--- /dev/null
+++ b/ipc/ipdl/test/cxx/PTestUniquePtrIPC.ipdl
@@ -0,0 +1,26 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=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/. */
+
+include "mozilla/_ipdltest/TestUniquePtrIPC.h";
+
+namespace mozilla {
+namespace _ipdltest {
+
+struct DummyStruct {
+ int x;
+};
+
+[ManualDealloc, ChildImpl="TestUniquePtrIPCChild", ParentImpl="TestUniquePtrIPCParent"]
+protocol PTestUniquePtrIPC
+{
+child:
+ async TestMessage(UniquePtr<int> a1, UniquePtr<DummyStruct> a2,
+ DummyStruct a3, UniquePtr<int> a4);
+ async TestSendReference(UniquePtr<DummyStruct> a);
+};
+
+}
+}
diff --git a/ipc/ipdl/test/cxx/PTestUrgency.ipdl b/ipc/ipdl/test/cxx/PTestUrgency.ipdl
new file mode 100644
index 0000000000..7653d12102
--- /dev/null
+++ b/ipc/ipdl/test/cxx/PTestUrgency.ipdl
@@ -0,0 +1,22 @@
+include "mozilla/_ipdltest/TestUrgency.h";
+
+namespace mozilla {
+namespace _ipdltest {
+
+[ManualDealloc, NestedUpTo=inside_cpow, ChildImpl="TestUrgencyChild", ParentImpl="TestUrgencyParent"]
+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/cxx/PTestUrgentHangs.ipdl b/ipc/ipdl/test/cxx/PTestUrgentHangs.ipdl
new file mode 100644
index 0000000000..2c19a7afe1
--- /dev/null
+++ b/ipc/ipdl/test/cxx/PTestUrgentHangs.ipdl
@@ -0,0 +1,31 @@
+include "mozilla/_ipdltest/TestUrgentHangs.h";
+
+namespace mozilla {
+namespace _ipdltest {
+
+[ManualDealloc, NestedUpTo=inside_sync, ChildImpl="TestUrgentHangsChild", ParentImpl="TestUrgentHangsParent"]
+sync protocol PTestUrgentHangs
+{
+parent:
+ [Nested=inside_sync] sync Test1_2();
+
+ [Nested=inside_sync] sync TestInner();
+ [Nested=inside_cpow] sync TestInnerUrgent();
+
+child:
+ [Nested=inside_sync] sync Test1_1();
+ [Nested=inside_sync] sync Test1_3();
+
+ [Nested=inside_sync] sync Test2();
+
+ [Nested=inside_sync] sync Test3();
+
+ async Test4();
+ [Nested=inside_sync] sync Test4_1();
+
+ async Test5();
+ [Nested=inside_sync] sync Test5_1();
+};
+
+} // namespace _ipdltest
+} // namespace mozilla
diff --git a/ipc/ipdl/test/cxx/README.txt b/ipc/ipdl/test/cxx/README.txt
new file mode 100644
index 0000000000..0fe6c07320
--- /dev/null
+++ b/ipc/ipdl/test/cxx/README.txt
@@ -0,0 +1,61 @@
+To add a new IPDL C++ unit test, you need to create (at least) the
+following files (for a test "TestFoo"):
+
+ - PTestFoo.ipdl, specifying the top-level protocol used for the test
+
+ - TestFoo.h, declaring the top-level parent/child actors used for
+ the test
+
+ - TestFoo.cpp, defining the top-level actors
+
+ - (make sure all are in the namespace mozilla::_ipdltest)
+
+Next
+
+ - add PTestFoo.ipdl to ipdl.mk
+
+ - append TestFoo to the variable IPDLTESTS in Makefile.in
+
+You must define three methods in your |TestFooParent| class:
+
+ - static methods |bool RunTestInProcesses()| and
+ |bool RunTestInThreads()|. These methods control whether
+ to execute the test using actors in separate processes and
+ threads respectively. Generally, both should return true.
+
+ - an instance method |void Main()|. The test harness wil first
+ initialize the processes or threads, create and open both actors,
+ and then kick off the test using |Main()|. Make sure you define
+ it.
+
+If your test passes its criteria, please call
+|MOZ_IPDL_TESTPASS("msg")| and "exit gracefully".
+
+If your tests fails, please call |MOZ_IPDL_TESTFAIL("msg")| and "exit
+ungracefully", preferably by abort()ing.
+
+
+If all goes well, running
+
+ make -C $OBJDIR/ipc/ipdl/test/cxx
+
+will update the file IPDLUnitTests.cpp (the test launcher), and your
+new code will be built automatically.
+
+
+You can launch your new test by invoking one of
+
+ make -C $OBJDIR/ipc/ipdl/test/cxx check-proc (test process-based tests)
+ make -C $OBJDIR/ipc/ipdl/test/cxx check-threads (test thread-based tests)
+ make -C $OBJDIR/ipc/ipdl/test/cxx check (tests both)
+
+If you want to launch only your test, run
+
+ cd $OBJDIR/dist/bin
+ ./run-mozilla.sh ./ipdlunittest TestFoo (test in two processes, if appl.)
+ ./run-mozilla.sh ./ipdlunittest thread:TestFoo (test in two threads, if appl.)
+
+
+For a bare-bones example of adding a test, take a look at
+PTestSanity.ipdl, TestSanity.h, TestSanity.cpp, and how "TestSanity"
+is included in ipdl.mk and Makefile.in.
diff --git a/ipc/ipdl/test/cxx/TestActorPunning.cpp b/ipc/ipdl/test/cxx/TestActorPunning.cpp
new file mode 100644
index 0000000000..5825796f54
--- /dev/null
+++ b/ipc/ipdl/test/cxx/TestActorPunning.cpp
@@ -0,0 +1,125 @@
+#include "TestActorPunning.h"
+
+#include "IPDLUnitTests.h" // fail etc.
+#include "mozilla/Unused.h"
+
+namespace mozilla {
+namespace _ipdltest {
+
+//-----------------------------------------------------------------------------
+// parent
+
+void TestActorPunningParent::Main() {
+ if (!SendStart()) fail("sending Start");
+}
+
+mozilla::ipc::IPCResult TestActorPunningParent::RecvPun(
+ PTestActorPunningSubParent* a, const Bad& bad) {
+ if (a->SendBad()) fail("bad!");
+ fail("shouldn't have received this message in the first place");
+ return IPC_OK();
+}
+
+// By default, fatal errors kill the parent process, but this makes it
+// hard to test, so instead we use the previous behavior and kill the
+// child process.
+void TestActorPunningParent::HandleFatalError(const char* aErrorMsg) {
+ if (!!strcmp(aErrorMsg, "Error deserializing 'PTestActorPunningSubParent'")) {
+ fail("wrong fatal error");
+ }
+
+ ipc::ScopedProcessHandle otherProcessHandle;
+ if (!base::OpenProcessHandle(OtherPid(), &otherProcessHandle.rwget())) {
+ fail("couldn't open child process");
+ } else {
+ if (!base::KillProcess(otherProcessHandle, 0, false)) {
+ fail("terminating child process");
+ }
+ }
+}
+
+PTestActorPunningPunnedParent*
+TestActorPunningParent::AllocPTestActorPunningPunnedParent() {
+ return new TestActorPunningPunnedParent();
+}
+
+bool TestActorPunningParent::DeallocPTestActorPunningPunnedParent(
+ PTestActorPunningPunnedParent* a) {
+ delete a;
+ return true;
+}
+
+PTestActorPunningSubParent*
+TestActorPunningParent::AllocPTestActorPunningSubParent() {
+ return new TestActorPunningSubParent();
+}
+
+bool TestActorPunningParent::DeallocPTestActorPunningSubParent(
+ PTestActorPunningSubParent* a) {
+ delete a;
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// child
+
+PTestActorPunningPunnedChild*
+TestActorPunningChild::AllocPTestActorPunningPunnedChild() {
+ return new TestActorPunningPunnedChild();
+}
+
+bool TestActorPunningChild::DeallocPTestActorPunningPunnedChild(
+ PTestActorPunningPunnedChild*) {
+ fail("should have died by now");
+ return true;
+}
+
+PTestActorPunningSubChild*
+TestActorPunningChild::AllocPTestActorPunningSubChild() {
+ return new TestActorPunningSubChild();
+}
+
+bool TestActorPunningChild::DeallocPTestActorPunningSubChild(
+ PTestActorPunningSubChild*) {
+ fail("should have died by now");
+ return true;
+}
+
+mozilla::ipc::IPCResult TestActorPunningChild::RecvStart() {
+ SendPTestActorPunningSubConstructor();
+ SendPTestActorPunningPunnedConstructor();
+ PTestActorPunningSubChild* a = SendPTestActorPunningSubConstructor();
+ // We can't assert whether this succeeds or fails, due to race
+ // conditions.
+ SendPun(a, Bad());
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult TestActorPunningSubChild::RecvBad() {
+ fail("things are going really badly right now");
+ return IPC_OK();
+}
+
+} // namespace _ipdltest
+} // namespace mozilla
+
+namespace IPC {
+using namespace mozilla::_ipdltest;
+using namespace mozilla::ipc;
+
+/*static*/ void ParamTraits<Bad>::Write(MessageWriter* aWriter,
+ const paramType& aParam) {
+ // Skip past the sentinel for the actor as well as the actor.
+ int32_t* ptr = aWriter->GetInt32PtrForTest(2 * sizeof(int32_t));
+ ActorHandle* ah = reinterpret_cast<ActorHandle*>(ptr);
+ if (ah->mId != -3)
+ fail("guessed wrong offset (value is %d, should be -3)", ah->mId);
+ ah->mId = -2;
+}
+
+/*static*/ bool ParamTraits<Bad>::Read(MessageReader* aReader,
+ paramType* aResult) {
+ return true;
+}
+
+} // namespace IPC
diff --git a/ipc/ipdl/test/cxx/TestActorPunning.h b/ipc/ipdl/test/cxx/TestActorPunning.h
new file mode 100644
index 0000000000..cd88106c0c
--- /dev/null
+++ b/ipc/ipdl/test/cxx/TestActorPunning.h
@@ -0,0 +1,100 @@
+#ifndef mozilla__ipdltest_TestActorPunning_h
+#define mozilla__ipdltest_TestActorPunning_h 1
+
+#include "mozilla/_ipdltest/IPDLUnitTests.h"
+
+#include "mozilla/_ipdltest/PTestActorPunningParent.h"
+#include "mozilla/_ipdltest/PTestActorPunningPunnedParent.h"
+#include "mozilla/_ipdltest/PTestActorPunningSubParent.h"
+#include "mozilla/_ipdltest/PTestActorPunningChild.h"
+#include "mozilla/_ipdltest/PTestActorPunningPunnedChild.h"
+#include "mozilla/_ipdltest/PTestActorPunningSubChild.h"
+
+namespace mozilla {
+namespace _ipdltest {
+
+class TestActorPunningParent : public PTestActorPunningParent {
+ friend class PTestActorPunningParent;
+
+ public:
+ static bool RunTestInProcesses() { return true; }
+ static bool RunTestInThreads() { return false; }
+
+ void Main();
+
+ protected:
+ PTestActorPunningPunnedParent* AllocPTestActorPunningPunnedParent();
+ bool DeallocPTestActorPunningPunnedParent(PTestActorPunningPunnedParent* a);
+
+ PTestActorPunningSubParent* AllocPTestActorPunningSubParent();
+ bool DeallocPTestActorPunningSubParent(PTestActorPunningSubParent* a);
+
+ mozilla::ipc::IPCResult RecvPun(PTestActorPunningSubParent* a,
+ const Bad& bad);
+
+ virtual void ActorDestroy(ActorDestroyReason why) override {
+ if (NormalShutdown == why) fail("should have died from error!");
+ passed("ok");
+ QuitParent();
+ }
+
+ virtual void HandleFatalError(const char* aErrorMsg) override;
+};
+
+class TestActorPunningPunnedParent : public PTestActorPunningPunnedParent {
+ public:
+ TestActorPunningPunnedParent() {}
+ virtual ~TestActorPunningPunnedParent() {}
+
+ protected:
+ virtual void ActorDestroy(ActorDestroyReason why) override {}
+};
+
+class TestActorPunningSubParent : public PTestActorPunningSubParent {
+ public:
+ TestActorPunningSubParent() {}
+ virtual ~TestActorPunningSubParent() {}
+
+ protected:
+ virtual void ActorDestroy(ActorDestroyReason why) override {}
+};
+
+class TestActorPunningChild : public PTestActorPunningChild {
+ friend class PTestActorPunningChild;
+
+ public:
+ TestActorPunningChild() {}
+ virtual ~TestActorPunningChild() {}
+
+ protected:
+ PTestActorPunningPunnedChild* AllocPTestActorPunningPunnedChild();
+ bool DeallocPTestActorPunningPunnedChild(PTestActorPunningPunnedChild* a);
+
+ PTestActorPunningSubChild* AllocPTestActorPunningSubChild();
+ bool DeallocPTestActorPunningSubChild(PTestActorPunningSubChild* a);
+
+ mozilla::ipc::IPCResult RecvStart();
+
+ virtual void ActorDestroy(ActorDestroyReason why) override {
+ fail("should have been killed off!");
+ }
+};
+
+class TestActorPunningPunnedChild : public PTestActorPunningPunnedChild {
+ public:
+ TestActorPunningPunnedChild() {}
+ virtual ~TestActorPunningPunnedChild() {}
+};
+
+class TestActorPunningSubChild : public PTestActorPunningSubChild {
+ public:
+ TestActorPunningSubChild() {}
+ virtual ~TestActorPunningSubChild() {}
+
+ mozilla::ipc::IPCResult RecvBad();
+};
+
+} // namespace _ipdltest
+} // namespace mozilla
+
+#endif // ifndef mozilla__ipdltest_TestActorPunning_h
diff --git a/ipc/ipdl/test/cxx/TestAsyncReturns.cpp b/ipc/ipdl/test/cxx/TestAsyncReturns.cpp
new file mode 100644
index 0000000000..76597143c0
--- /dev/null
+++ b/ipc/ipdl/test/cxx/TestAsyncReturns.cpp
@@ -0,0 +1,101 @@
+#include "TestAsyncReturns.h"
+
+#include "IPDLUnitTests.h" // fail etc.
+
+#include "mozilla/AbstractThread.h"
+#include "mozilla/Unused.h"
+
+namespace mozilla {
+namespace _ipdltest {
+
+static uint32_t sMagic1 = 0x105b59fb;
+static uint32_t sMagic2 = 0x09b6f5e3;
+
+//-----------------------------------------------------------------------------
+// parent
+
+TestAsyncReturnsParent::TestAsyncReturnsParent() {
+ MOZ_COUNT_CTOR(TestAsyncReturnsParent);
+}
+
+TestAsyncReturnsParent::~TestAsyncReturnsParent() {
+ MOZ_COUNT_DTOR(TestAsyncReturnsParent);
+}
+
+void TestAsyncReturnsParent::Main() {
+ SendNoReturn()->Then(
+ MessageLoop::current()->SerialEventTarget(), __func__,
+ [](bool unused) { fail("resolve handler should not be called"); },
+ [](ResponseRejectReason&& aReason) {
+ // MozPromise asserts in debug build if the
+ // handler is not called
+ if (aReason != ResponseRejectReason::ChannelClosed) {
+ fail("reject with wrong reason");
+ }
+ passed("reject handler called on channel close");
+ });
+ SendPing()->Then(
+ MessageLoop::current()->SerialEventTarget(), __func__,
+ [this](bool one) {
+ if (one) {
+ passed("take one argument");
+ } else {
+ fail("get one argument but has wrong value");
+ }
+
+ // Also try with the callback-based API.
+ SendPing(
+ [this](bool one) {
+ if (one) {
+ passed("take one argument");
+ } else {
+ fail("get one argument but has wrong value");
+ }
+ Close();
+ },
+ [](ResponseRejectReason&& aReason) { fail("sending Ping"); });
+ },
+ [](ResponseRejectReason&& aReason) { fail("sending Ping"); });
+}
+
+mozilla::ipc::IPCResult TestAsyncReturnsParent::RecvPong(
+ PongResolver&& aResolve) {
+ aResolve(std::tuple<const uint32_t&, const uint32_t&>(sMagic1, sMagic2));
+ return IPC_OK();
+}
+
+//-----------------------------------------------------------------------------
+// child
+
+TestAsyncReturnsChild::TestAsyncReturnsChild() {
+ MOZ_COUNT_CTOR(TestAsyncReturnsChild);
+}
+
+TestAsyncReturnsChild::~TestAsyncReturnsChild() {
+ MOZ_COUNT_DTOR(TestAsyncReturnsChild);
+}
+
+mozilla::ipc::IPCResult TestAsyncReturnsChild::RecvNoReturn(
+ NoReturnResolver&& aResolve) {
+ // Not resolving the promise intentionally
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult TestAsyncReturnsChild::RecvPing(
+ PingResolver&& aResolve) {
+ SendPong()->Then(
+ MessageLoop::current()->SerialEventTarget(), __func__,
+ [aResolve](const std::tuple<uint32_t, uint32_t>& aParam) {
+ if (std::get<0>(aParam) == sMagic1 && std::get<1>(aParam) == sMagic2) {
+ passed("take two arguments");
+ } else {
+ fail("get two argument but has wrong value");
+ }
+ aResolve(true);
+ },
+ [](ResponseRejectReason&& aReason) { fail("sending Pong"); });
+ return IPC_OK();
+}
+
+} // namespace _ipdltest
+} // namespace mozilla
diff --git a/ipc/ipdl/test/cxx/TestAsyncReturns.h b/ipc/ipdl/test/cxx/TestAsyncReturns.h
new file mode 100644
index 0000000000..5dad3da0ab
--- /dev/null
+++ b/ipc/ipdl/test/cxx/TestAsyncReturns.h
@@ -0,0 +1,54 @@
+#ifndef mozilla__ipdltest_TestAsyncReturns_h
+#define mozilla__ipdltest_TestAsyncReturns_h 1
+
+#include "mozilla/_ipdltest/IPDLUnitTests.h"
+
+#include "mozilla/_ipdltest/PTestAsyncReturnsParent.h"
+#include "mozilla/_ipdltest/PTestAsyncReturnsChild.h"
+
+namespace mozilla {
+namespace _ipdltest {
+
+class TestAsyncReturnsParent : public PTestAsyncReturnsParent {
+ friend class PTestAsyncReturnsParent;
+
+ public:
+ TestAsyncReturnsParent();
+ virtual ~TestAsyncReturnsParent();
+
+ static bool RunTestInProcesses() { return true; }
+ static bool RunTestInThreads() { return true; }
+
+ void Main();
+
+ protected:
+ mozilla::ipc::IPCResult RecvPong(PongResolver&& aResolve);
+
+ virtual void ActorDestroy(ActorDestroyReason why) override {
+ if (NormalShutdown != why) fail("unexpected destruction!");
+ passed("ok");
+ QuitParent();
+ }
+};
+
+class TestAsyncReturnsChild : public PTestAsyncReturnsChild {
+ friend class PTestAsyncReturnsChild;
+
+ public:
+ TestAsyncReturnsChild();
+ virtual ~TestAsyncReturnsChild();
+
+ protected:
+ mozilla::ipc::IPCResult RecvPing(PingResolver&& aResolve);
+ mozilla::ipc::IPCResult RecvNoReturn(NoReturnResolver&& aResolve);
+
+ virtual void ActorDestroy(ActorDestroyReason why) override {
+ if (NormalShutdown != why) fail("unexpected destruction!");
+ QuitChild();
+ }
+};
+
+} // namespace _ipdltest
+} // namespace mozilla
+
+#endif // ifndef mozilla__ipdltest_TestAsyncReturns_h
diff --git a/ipc/ipdl/test/cxx/TestBadActor.cpp b/ipc/ipdl/test/cxx/TestBadActor.cpp
new file mode 100644
index 0000000000..6c6991dbb2
--- /dev/null
+++ b/ipc/ipdl/test/cxx/TestBadActor.cpp
@@ -0,0 +1,59 @@
+#include "TestBadActor.h"
+#include "IPDLUnitTests.h"
+#include "mozilla/Unused.h"
+
+namespace mozilla {
+namespace _ipdltest {
+
+void TestBadActorParent::Main() {
+ // This test is designed to test a race condition where the child sends us
+ // a message on an actor that we've already destroyed. The child process
+ // should die, and the parent process should not abort.
+
+ PTestBadActorSubParent* child = SendPTestBadActorSubConstructor();
+ if (!child) fail("Sending constructor");
+
+ Unused << child->Call__delete__(child);
+}
+
+// By default, fatal errors kill the parent process, but this makes it
+// hard to test, so instead we use the previous behavior and kill the
+// child process.
+void TestBadActorParent::HandleFatalError(const char* aErrorMsg) {
+ if (!!strcmp(aErrorMsg, "incoming message racing with actor deletion")) {
+ fail("wrong fatal error");
+ }
+
+ ipc::ScopedProcessHandle otherProcessHandle;
+ if (!base::OpenProcessHandle(OtherPid(), &otherProcessHandle.rwget())) {
+ fail("couldn't open child process");
+ } else {
+ if (!base::KillProcess(otherProcessHandle, 0, false)) {
+ fail("terminating child process");
+ }
+ }
+}
+
+PTestBadActorSubParent* TestBadActorParent::AllocPTestBadActorSubParent() {
+ return new TestBadActorSubParent();
+}
+
+mozilla::ipc::IPCResult TestBadActorSubParent::RecvPing() {
+ fail("Shouldn't have received ping.");
+ return IPC_FAIL_NO_REASON(this);
+}
+
+PTestBadActorSubChild* TestBadActorChild::AllocPTestBadActorSubChild() {
+ return new TestBadActorSubChild();
+}
+
+mozilla::ipc::IPCResult TestBadActorChild::RecvPTestBadActorSubConstructor(
+ PTestBadActorSubChild* actor) {
+ if (!actor->SendPing()) {
+ fail("Couldn't send ping to an actor which supposedly isn't dead yet.");
+ }
+ return IPC_OK();
+}
+
+} // namespace _ipdltest
+} // namespace mozilla
diff --git a/ipc/ipdl/test/cxx/TestBadActor.h b/ipc/ipdl/test/cxx/TestBadActor.h
new file mode 100644
index 0000000000..cefe0288f4
--- /dev/null
+++ b/ipc/ipdl/test/cxx/TestBadActor.h
@@ -0,0 +1,84 @@
+#ifndef mozilla__ipdltest_TestBadActor_h
+#define mozilla__ipdltest_TestBadActor_h
+
+#include "mozilla/_ipdltest/IPDLUnitTests.h"
+
+#include "mozilla/_ipdltest/PTestBadActorParent.h"
+#include "mozilla/_ipdltest/PTestBadActorChild.h"
+
+#include "mozilla/_ipdltest/PTestBadActorSubParent.h"
+#include "mozilla/_ipdltest/PTestBadActorSubChild.h"
+
+namespace mozilla {
+namespace _ipdltest {
+
+class TestBadActorParent : public PTestBadActorParent {
+ friend class PTestBadActorParent;
+
+ public:
+ TestBadActorParent() {}
+ virtual ~TestBadActorParent() {}
+
+ static bool RunTestInProcesses() { return true; }
+ static bool RunTestInThreads() { return false; }
+
+ void Main();
+
+ protected:
+ virtual void ActorDestroy(ActorDestroyReason why) override {
+ if (AbnormalShutdown != why) fail("unexpected destruction");
+ passed("ok");
+ QuitParent();
+ }
+
+ virtual void HandleFatalError(const char* aErrorMsg) override;
+
+ PTestBadActorSubParent* AllocPTestBadActorSubParent();
+
+ bool DeallocPTestBadActorSubParent(PTestBadActorSubParent* actor) {
+ delete actor;
+ return true;
+ }
+};
+
+class TestBadActorSubParent : public PTestBadActorSubParent {
+ friend class PTestBadActorSubParent;
+
+ public:
+ TestBadActorSubParent() {}
+ virtual ~TestBadActorSubParent() {}
+
+ protected:
+ virtual void ActorDestroy(ActorDestroyReason why) override {}
+ mozilla::ipc::IPCResult RecvPing();
+};
+
+class TestBadActorChild : public PTestBadActorChild {
+ friend class PTestBadActorChild;
+
+ public:
+ TestBadActorChild() {}
+ virtual ~TestBadActorChild() {}
+
+ protected:
+ virtual PTestBadActorSubChild* AllocPTestBadActorSubChild();
+
+ virtual bool DeallocPTestBadActorSubChild(PTestBadActorSubChild* actor) {
+ delete actor;
+ return true;
+ }
+
+ virtual mozilla::ipc::IPCResult RecvPTestBadActorSubConstructor(
+ PTestBadActorSubChild* actor);
+};
+
+class TestBadActorSubChild : public PTestBadActorSubChild {
+ public:
+ TestBadActorSubChild() {}
+ virtual ~TestBadActorSubChild() {}
+};
+
+} // namespace _ipdltest
+} // namespace mozilla
+
+#endif // mozilla__ipdltest_TestBadActor_h
diff --git a/ipc/ipdl/test/cxx/TestCancel.cpp b/ipc/ipdl/test/cxx/TestCancel.cpp
new file mode 100644
index 0000000000..2f97aa2e93
--- /dev/null
+++ b/ipc/ipdl/test/cxx/TestCancel.cpp
@@ -0,0 +1,115 @@
+#include "TestCancel.h"
+
+#include "IPDLUnitTests.h" // fail etc.
+
+namespace mozilla {
+namespace _ipdltest {
+
+//-----------------------------------------------------------------------------
+// parent
+
+TestCancelParent::TestCancelParent() { MOZ_COUNT_CTOR(TestCancelParent); }
+
+TestCancelParent::~TestCancelParent() { MOZ_COUNT_DTOR(TestCancelParent); }
+
+void TestCancelParent::Main() {
+ if (SendTest1_1()) fail("sending Test1_1");
+
+ uint32_t value = 0;
+ if (!SendCheckChild(&value)) fail("Test1 CheckChild");
+
+ if (value != 12) fail("Test1 CheckChild reply");
+}
+
+mozilla::ipc::IPCResult TestCancelParent::RecvDone1() {
+ if (!SendStart2()) fail("sending Start2");
+
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult TestCancelParent::RecvTest2_1() {
+ if (SendTest2_2()) fail("sending Test2_2");
+
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult TestCancelParent::RecvStart3() {
+ if (SendTest3_1()) fail("sending Test3_1");
+
+ uint32_t value = 0;
+ if (!SendCheckChild(&value)) fail("Test1 CheckChild");
+
+ if (value != 12) fail("Test1 CheckChild reply");
+
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult TestCancelParent::RecvTest3_2() {
+ GetIPCChannel()->CancelCurrentTransaction();
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult TestCancelParent::RecvDone() {
+ MessageLoop::current()->PostTask(NewNonOwningRunnableMethod(
+ "ipc::IToplevelProtocol::Close", this, &TestCancelParent::Close));
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult TestCancelParent::RecvCheckParent(uint32_t* reply) {
+ *reply = 12;
+ return IPC_OK();
+}
+
+//-----------------------------------------------------------------------------
+// child
+
+mozilla::ipc::IPCResult TestCancelChild::RecvTest1_1() {
+ GetIPCChannel()->CancelCurrentTransaction();
+
+ uint32_t value = 0;
+ if (!SendCheckParent(&value)) fail("Test1 CheckParent");
+
+ if (value != 12) fail("Test1 CheckParent reply");
+
+ if (!SendDone1()) fail("Test1 CheckParent");
+
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult TestCancelChild::RecvStart2() {
+ if (!SendTest2_1()) fail("sending Test2_1");
+
+ if (!SendStart3()) fail("sending Start3");
+
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult TestCancelChild::RecvTest2_2() {
+ GetIPCChannel()->CancelCurrentTransaction();
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult TestCancelChild::RecvTest3_1() {
+ if (SendTest3_2()) fail("sending Test3_2");
+
+ uint32_t value = 0;
+ if (!SendCheckParent(&value)) fail("Test1 CheckParent");
+
+ if (value != 12) fail("Test1 CheckParent reply");
+
+ if (!SendDone()) fail("sending Done");
+
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult TestCancelChild::RecvCheckChild(uint32_t* reply) {
+ *reply = 12;
+ return IPC_OK();
+}
+
+TestCancelChild::TestCancelChild() { MOZ_COUNT_CTOR(TestCancelChild); }
+
+TestCancelChild::~TestCancelChild() { MOZ_COUNT_DTOR(TestCancelChild); }
+
+} // namespace _ipdltest
+} // namespace mozilla
diff --git a/ipc/ipdl/test/cxx/TestCancel.h b/ipc/ipdl/test/cxx/TestCancel.h
new file mode 100644
index 0000000000..7d944d6a69
--- /dev/null
+++ b/ipc/ipdl/test/cxx/TestCancel.h
@@ -0,0 +1,54 @@
+#ifndef mozilla__ipdltest_TestCancel_h
+#define mozilla__ipdltest_TestCancel_h 1
+
+#include "mozilla/_ipdltest/IPDLUnitTests.h"
+
+#include "mozilla/_ipdltest/PTestCancelParent.h"
+#include "mozilla/_ipdltest/PTestCancelChild.h"
+
+namespace mozilla {
+namespace _ipdltest {
+
+class TestCancelParent : public PTestCancelParent {
+ public:
+ TestCancelParent();
+ virtual ~TestCancelParent();
+
+ static bool RunTestInProcesses() { return true; }
+ static bool RunTestInThreads() { return false; }
+
+ void Main();
+
+ mozilla::ipc::IPCResult RecvDone1();
+ mozilla::ipc::IPCResult RecvTest2_1();
+ mozilla::ipc::IPCResult RecvStart3();
+ mozilla::ipc::IPCResult RecvTest3_2();
+ mozilla::ipc::IPCResult RecvDone();
+
+ mozilla::ipc::IPCResult RecvCheckParent(uint32_t* reply);
+
+ virtual void ActorDestroy(ActorDestroyReason why) override {
+ passed("ok");
+ QuitParent();
+ }
+};
+
+class TestCancelChild : public PTestCancelChild {
+ public:
+ TestCancelChild();
+ virtual ~TestCancelChild();
+
+ mozilla::ipc::IPCResult RecvTest1_1();
+ mozilla::ipc::IPCResult RecvStart2();
+ mozilla::ipc::IPCResult RecvTest2_2();
+ mozilla::ipc::IPCResult RecvTest3_1();
+
+ mozilla::ipc::IPCResult RecvCheckChild(uint32_t* reply);
+
+ virtual void ActorDestroy(ActorDestroyReason why) override { QuitChild(); }
+};
+
+} // namespace _ipdltest
+} // namespace mozilla
+
+#endif // ifndef mozilla__ipdltest_TestCancel_h
diff --git a/ipc/ipdl/test/cxx/TestCrashCleanup.cpp b/ipc/ipdl/test/cxx/TestCrashCleanup.cpp
new file mode 100644
index 0000000000..6a19cc0f65
--- /dev/null
+++ b/ipc/ipdl/test/cxx/TestCrashCleanup.cpp
@@ -0,0 +1,100 @@
+#include "TestCrashCleanup.h"
+
+#include "base/task.h"
+#include "mozilla/CondVar.h"
+#include "mozilla/Mutex.h"
+
+#include "IPDLUnitTests.h" // fail etc.
+#include "IPDLUnitTestSubprocess.h"
+
+using mozilla::CondVar;
+using mozilla::Mutex;
+using mozilla::MutexAutoLock;
+
+namespace mozilla {
+namespace _ipdltest {
+
+//-----------------------------------------------------------------------------
+// parent
+
+namespace {
+
+// NB: this test does its own shutdown, rather than going through
+// QuitParent(), because it's testing degenerate edge cases
+
+void DeleteSubprocess(Mutex* mutex, CondVar* cvar) {
+ MutexAutoLock lock(*mutex);
+
+ gSubprocess->Destroy();
+ gSubprocess = nullptr;
+
+ cvar->Notify();
+}
+
+void DeleteTheWorld() {
+ delete static_cast<TestCrashCleanupParent*>(gParentActor);
+ gParentActor = nullptr;
+
+ // needs to be synchronous to avoid affecting event ordering on
+ // the main thread
+ Mutex mutex MOZ_UNANNOTATED("TestCrashCleanup.DeleteTheWorld.mutex");
+ CondVar cvar(mutex, "TestCrashCleanup.DeleteTheWorld.cvar");
+
+ MutexAutoLock lock(mutex);
+
+ XRE_GetIOMessageLoop()->PostTask(
+ NewRunnableFunction("DeleteSubprocess", DeleteSubprocess, &mutex, &cvar));
+
+ cvar.Wait();
+}
+
+void Done() {
+ static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
+ nsCOMPtr<nsIAppShell> appShell(do_GetService(kAppShellCID));
+ appShell->Exit();
+
+ passed(__FILE__);
+}
+
+} // namespace
+
+TestCrashCleanupParent::TestCrashCleanupParent() : mCleanedUp(false) {
+ MOZ_COUNT_CTOR(TestCrashCleanupParent);
+}
+
+TestCrashCleanupParent::~TestCrashCleanupParent() {
+ MOZ_COUNT_DTOR(TestCrashCleanupParent);
+
+ if (!mCleanedUp) fail("should have been ActorDestroy()d!");
+}
+
+void TestCrashCleanupParent::Main() {
+ // NB: has to be enqueued before IO thread's error notification
+ MessageLoop::current()->PostTask(
+ NewRunnableFunction("DeleteTheWorld", DeleteTheWorld));
+
+ if (CallDIEDIEDIE()) fail("expected an error!");
+
+ Close();
+
+ MessageLoop::current()->PostTask(NewRunnableFunction("Done", Done));
+}
+
+//-----------------------------------------------------------------------------
+// child
+
+TestCrashCleanupChild::TestCrashCleanupChild() {
+ MOZ_COUNT_CTOR(TestCrashCleanupChild);
+}
+
+TestCrashCleanupChild::~TestCrashCleanupChild() {
+ MOZ_COUNT_DTOR(TestCrashCleanupChild);
+}
+
+mozilla::ipc::IPCResult TestCrashCleanupChild::AnswerDIEDIEDIE() {
+ _exit(0);
+ MOZ_CRASH("unreached");
+}
+
+} // namespace _ipdltest
+} // namespace mozilla
diff --git a/ipc/ipdl/test/cxx/TestCrashCleanup.h b/ipc/ipdl/test/cxx/TestCrashCleanup.h
new file mode 100644
index 0000000000..30371264e6
--- /dev/null
+++ b/ipc/ipdl/test/cxx/TestCrashCleanup.h
@@ -0,0 +1,49 @@
+#ifndef mozilla__ipdltest_TestCrashCleanup_h
+#define mozilla__ipdltest_TestCrashCleanup_h 1
+
+#include "mozilla/_ipdltest/IPDLUnitTests.h"
+
+#include "mozilla/_ipdltest/PTestCrashCleanupParent.h"
+#include "mozilla/_ipdltest/PTestCrashCleanupChild.h"
+
+namespace mozilla {
+namespace _ipdltest {
+
+class TestCrashCleanupParent : public PTestCrashCleanupParent {
+ public:
+ TestCrashCleanupParent();
+ virtual ~TestCrashCleanupParent();
+
+ static bool RunTestInProcesses() { return true; }
+ static bool RunTestInThreads() { return false; }
+
+ void Main();
+
+ protected:
+ virtual void ActorDestroy(ActorDestroyReason why) override {
+ if (AbnormalShutdown != why) fail("unexpected destruction!");
+ mCleanedUp = true;
+ }
+
+ bool mCleanedUp;
+};
+
+class TestCrashCleanupChild : public PTestCrashCleanupChild {
+ friend class PTestCrashCleanupChild;
+
+ public:
+ TestCrashCleanupChild();
+ virtual ~TestCrashCleanupChild();
+
+ protected:
+ mozilla::ipc::IPCResult AnswerDIEDIEDIE();
+
+ virtual void ActorDestroy(ActorDestroyReason why) override {
+ fail("should have 'crashed'!");
+ }
+};
+
+} // namespace _ipdltest
+} // namespace mozilla
+
+#endif // ifndef mozilla__ipdltest_TestCrashCleanup_h
diff --git a/ipc/ipdl/test/cxx/TestDataStructures.cpp b/ipc/ipdl/test/cxx/TestDataStructures.cpp
new file mode 100644
index 0000000000..5b1cabfe7d
--- /dev/null
+++ b/ipc/ipdl/test/cxx/TestDataStructures.cpp
@@ -0,0 +1,888 @@
+#include "TestDataStructures.h"
+
+#include "mozilla/Unused.h"
+
+#include "IPDLUnitTests.h" // fail etc.
+
+typedef nsTArray<nsIntRegion> RegionArray;
+
+namespace mozilla {
+namespace _ipdltest {
+
+static const uint32_t nactors = 10;
+
+#define test_assert(_cond, _msg) \
+ if (!(_cond)) fail(_msg)
+
+template <typename T>
+static void assert_arrays_equal(const nsTArray<T>& a, const nsTArray<T>& b) {
+ test_assert(a == b, "arrays equal");
+}
+
+inline static TestDataStructuresSub& Cast(PTestDataStructuresSubParent* a) {
+ return *static_cast<TestDataStructuresSub*>(a);
+}
+
+//-----------------------------------------------------------------------------
+// parent
+
+TestDataStructuresParent::TestDataStructuresParent() {
+ MOZ_COUNT_CTOR(TestDataStructuresParent);
+}
+
+TestDataStructuresParent::~TestDataStructuresParent() {
+ MOZ_COUNT_DTOR(TestDataStructuresParent);
+}
+
+void TestDataStructuresParent::Main() {
+ for (uint32_t i = 0; i < nactors; ++i)
+ if (!SendPTestDataStructuresSubConstructor(i)) fail("can't alloc actor");
+
+ if (!SendStart()) fail("can't send Start()");
+}
+
+bool TestDataStructuresParent::DeallocPTestDataStructuresSubParent(
+ PTestDataStructuresSubParent* actor) {
+ test_assert(Cast(actor).mI == Cast(mKids[0]).mI, "dtor sent to wrong actor");
+ mKids.RemoveElementAt(0);
+ delete actor;
+ if (mKids.Length() > 0) return true;
+
+ return true;
+}
+
+mozilla::ipc::IPCResult TestDataStructuresParent::RecvTest1(nsTArray<int>&& ia,
+ nsTArray<int>* oa) {
+ test_assert(5 == ia.Length(), "wrong length");
+ for (int i = 0; i < 5; ++i) test_assert(i == ia[i], "wrong value");
+
+ *oa = ia;
+
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult TestDataStructuresParent::RecvTest2(
+ nsTArray<PTestDataStructuresSubParent*>&& i1,
+ nsTArray<PTestDataStructuresSubParent*>* o1) {
+ test_assert(nactors == i1.Length(), "wrong #actors");
+ for (uint32_t i = 0; i < i1.Length(); ++i)
+ test_assert(i == Cast(i1[i]).mI, "wrong mI value");
+ *o1 = i1;
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult TestDataStructuresParent::RecvTest3(const IntDouble& i1,
+ const IntDouble& i2,
+ IntDouble* o1,
+ IntDouble* o2) {
+ test_assert(42 == i1.get_int(), "wrong value");
+ test_assert(4.0 == i2.get_double(), "wrong value");
+
+ *o1 = i1;
+ *o2 = i2;
+
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult TestDataStructuresParent::RecvTest4(
+ nsTArray<IntDouble>&& i1, nsTArray<IntDouble>* o1) {
+ test_assert(4 == i1.Length(), "wrong length");
+ test_assert(1 == i1[0].get_int(), "wrong value");
+ test_assert(2.0 == i1[1].get_double(), "wrong value");
+ test_assert(3 == i1[2].get_int(), "wrong value");
+ test_assert(4.0 == i1[3].get_double(), "wrong value");
+
+ *o1 = i1;
+
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult TestDataStructuresParent::RecvTest5(
+ const IntDoubleArrays& i1, const IntDoubleArrays& i2,
+ const IntDoubleArrays& i3, IntDoubleArrays* o1, IntDoubleArrays* o2,
+ IntDoubleArrays* o3) {
+ test_assert(42 == i1.get_int(), "wrong value");
+
+ const nsTArray<int>& i2a = i2.get_ArrayOfint();
+ test_assert(3 == i2a.Length(), "wrong length");
+ test_assert(1 == i2a[0], "wrong value");
+ test_assert(2 == i2a[1], "wrong value");
+ test_assert(3 == i2a[2], "wrong value");
+
+ const nsTArray<double>& i3a = i3.get_ArrayOfdouble();
+ test_assert(3 == i3a.Length(), "wrong length");
+ test_assert(1.0 == i3a[0], "wrong value");
+ test_assert(2.0 == i3a[1], "wrong value");
+ test_assert(3.0 == i3a[2], "wrong value");
+
+ *o1 = i1;
+ *o2 = i2a;
+ *o3 = i3a;
+
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult TestDataStructuresParent::RecvTest7_0(
+ const ActorWrapper& i1, ActorWrapper* o1) {
+ if (i1.actorChild() != nullptr)
+ fail("child side actor should always be null");
+
+ if (i1.actorParent() != mKids[0])
+ fail("should have got back same actor on parent side");
+
+ o1->actorParent() = mKids[0];
+ // malicious behavior
+ o1->actorChild() =
+ reinterpret_cast<PTestDataStructuresSubChild*>(uintptr_t(0xdeadbeef));
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult TestDataStructuresParent::RecvTest6(
+ nsTArray<IntDoubleArrays>&& i1, nsTArray<IntDoubleArrays>* o1) {
+ test_assert(3 == i1.Length(), "wrong length");
+
+ IntDoubleArrays id1(i1[0]);
+ test_assert(42 == id1.get_int(), "wrong value");
+
+ nsTArray<int> i2a(i1[1].get_ArrayOfint());
+ test_assert(3 == i2a.Length(), "wrong length");
+ test_assert(1 == i2a[0], "wrong value");
+ test_assert(2 == i2a[1], "wrong value");
+ test_assert(3 == i2a[2], "wrong value");
+
+ nsTArray<double> i3a(i1[2].get_ArrayOfdouble());
+ test_assert(3 == i3a.Length(), "wrong length");
+ test_assert(1.0 == i3a[0], "wrong value");
+ test_assert(2.0 == i3a[1], "wrong value");
+ test_assert(3.0 == i3a[2], "wrong value");
+
+ o1->AppendElement(id1);
+ o1->AppendElement(IntDoubleArrays(i2a));
+ o1->AppendElement(IntDoubleArrays(i3a));
+
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult TestDataStructuresParent::RecvTest7(
+ const Actors& i1, const Actors& i2, const Actors& i3, Actors* o1,
+ Actors* o2, Actors* o3) {
+ test_assert(42 == i1.get_int(), "wrong value");
+
+ nsTArray<int> i2a(i2.get_ArrayOfint());
+ test_assert(3 == i2a.Length(), "wrong length");
+ test_assert(1 == i2a[0], "wrong value");
+ test_assert(2 == i2a[1], "wrong value");
+ test_assert(3 == i2a[2], "wrong value");
+
+ assert_arrays_equal(mKids, i3.get_ArrayOfPTestDataStructuresSubParent());
+
+ *o1 = 42;
+ *o2 = i2a;
+ *o3 = mKids;
+
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult TestDataStructuresParent::RecvTest8(
+ nsTArray<Actors>&& i1, nsTArray<Actors>* o1) {
+ test_assert(3 == i1.Length(), "wrong length");
+ test_assert(42 == i1[0].get_int(), "wrong value");
+
+ const nsTArray<int>& i2a = i1[1].get_ArrayOfint();
+ test_assert(3 == i2a.Length(), "wrong length");
+ test_assert(1 == i2a[0], "wrong value");
+ test_assert(2 == i2a[1], "wrong value");
+ test_assert(3 == i2a[2], "wrong value");
+
+ assert_arrays_equal(mKids, i1[2].get_ArrayOfPTestDataStructuresSubParent());
+
+ *o1 = i1;
+
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult TestDataStructuresParent::RecvTest9(
+ const Unions& i1, const Unions& i2, const Unions& i3, const Unions& i4,
+ Unions* o1, Unions* o2, Unions* o3, Unions* o4) {
+ test_assert(42 == i1.get_int(), "wrong value");
+
+ const nsTArray<int>& i2a = i2.get_ArrayOfint();
+ test_assert(3 == i2a.Length(), "wrong length");
+ test_assert(1 == i2a[0], "wrong value");
+ test_assert(2 == i2a[1], "wrong value");
+ test_assert(3 == i2a[2], "wrong value");
+
+ assert_arrays_equal(mKids, i3.get_ArrayOfPTestDataStructuresSubParent());
+
+ const nsTArray<PTestDataStructuresSubParent*>& i4a =
+ i4.get_ArrayOfActors()[0].get_ArrayOfPTestDataStructuresSubParent();
+ assert_arrays_equal(mKids, i4a);
+
+ *o1 = i1;
+ *o2 = i2;
+ *o3 = i3;
+ *o4 = i4;
+
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult TestDataStructuresParent::RecvTest10(
+ nsTArray<Unions>&& i1, nsTArray<Unions>* o1) {
+ test_assert(42 == i1[0].get_int(), "wrong value");
+
+ const nsTArray<int>& i2a = i1[1].get_ArrayOfint();
+ test_assert(3 == i2a.Length(), "wrong length");
+ test_assert(1 == i2a[0], "wrong value");
+ test_assert(2 == i2a[1], "wrong value");
+ test_assert(3 == i2a[2], "wrong value");
+
+ assert_arrays_equal(mKids, i1[2].get_ArrayOfPTestDataStructuresSubParent());
+
+ const nsTArray<PTestDataStructuresSubParent*>& i4a =
+ i1[3].get_ArrayOfActors()[0].get_ArrayOfPTestDataStructuresSubParent();
+ assert_arrays_equal(mKids, i4a);
+
+ *o1 = i1;
+
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult TestDataStructuresParent::RecvTest11(
+ const SIntDouble& i, SIntDouble* o) {
+ test_assert(1 == i.i(), "wrong value");
+ test_assert(2.0 == i.d(), "wrong value");
+ *o = i;
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult TestDataStructuresParent::RecvTest12(
+ const SIntDoubleArrays& i, SIntDoubleArrays* o) {
+ 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);
+
+ test_assert(42 == i.i(), "wrong value");
+ assert_arrays_equal(ai, i.ai());
+ assert_arrays_equal(ad, i.ad());
+
+ *o = i;
+
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult TestDataStructuresParent::RecvTest13(const SActors& i,
+ SActors* o) {
+ nsTArray<int> ai;
+ ai.AppendElement(1);
+ ai.AppendElement(2);
+ ai.AppendElement(3);
+
+ test_assert(42 == i.i(), "wrong value");
+ assert_arrays_equal(ai, i.ai());
+ assert_arrays_equal(mKids, i.apParent());
+
+ *o = i;
+
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult TestDataStructuresParent::RecvTest14(const Structs& i,
+ Structs* o) {
+ nsTArray<int> ai;
+ ai.AppendElement(1);
+ ai.AppendElement(2);
+ ai.AppendElement(3);
+
+ test_assert(42 == i.i(), "wrong value");
+ assert_arrays_equal(ai, i.ai());
+ assert_arrays_equal(mKids, i.apParent());
+
+ const SActors& ia = i.aa()[0];
+ test_assert(42 == ia.i(), "wrong value");
+ assert_arrays_equal(ai, ia.ai());
+ assert_arrays_equal(mKids, ia.apParent());
+
+ *o = i;
+
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult TestDataStructuresParent::RecvTest15(
+ 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) {
+ nsTArray<int> ai;
+ ai.AppendElement(1);
+ ai.AppendElement(2);
+ ai.AppendElement(3);
+
+ test_assert(i1 == int(42), "wrong value");
+ assert_arrays_equal(i2.get_ArrayOfint(), ai);
+ assert_arrays_equal(i3.get_ArrayOfPTestDataStructuresSubParent(), mKids);
+
+ const SActors& ia = i4.get_ArrayOfSActors()[0];
+ test_assert(42 == ia.i(), "wrong value");
+ assert_arrays_equal(ai, ia.ai());
+ assert_arrays_equal(mKids, ia.apParent());
+
+ const Structs& is = i5.get_ArrayOfStructs()[0];
+ test_assert(42 == is.i(), "wrong value");
+ assert_arrays_equal(ai, is.ai());
+ assert_arrays_equal(mKids, is.apParent());
+
+ const SActors& isa = is.aa()[0];
+ test_assert(42 == isa.i(), "wrong value");
+ assert_arrays_equal(ai, isa.ai());
+ assert_arrays_equal(mKids, isa.apParent());
+
+ *o1 = i1;
+ *o2 = i2;
+ *o3 = i3;
+ *o4 = i4;
+ *o5 = i5;
+
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult TestDataStructuresParent::RecvTest16(
+ const WithUnions& i, WithUnions* o) {
+ test_assert(i.i() == 42, "wrong value");
+
+ nsTArray<int> ai;
+ ai.AppendElement(1);
+ ai.AppendElement(2);
+ ai.AppendElement(3);
+ assert_arrays_equal(ai, i.ai());
+
+ assert_arrays_equal(i.apParent(), mKids);
+
+ assert_arrays_equal(mKids,
+ i.aa()[0].get_ArrayOfPTestDataStructuresSubParent());
+
+ const nsTArray<Unions>& iau = i.au();
+ test_assert(iau[0] == 42, "wrong value");
+ assert_arrays_equal(ai, iau[1].get_ArrayOfint());
+ assert_arrays_equal(mKids, iau[2].get_ArrayOfPTestDataStructuresSubParent());
+ assert_arrays_equal(
+ mKids,
+ iau[3].get_ArrayOfActors()[0].get_ArrayOfPTestDataStructuresSubParent());
+
+ *o = i;
+
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult TestDataStructuresParent::RecvTest17(
+ nsTArray<Op>&& sa) {
+ test_assert(sa.Length() == 1 && Op::TSetAttrs == sa[0].type(), "wrong value");
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult TestDataStructuresParent::RecvTest18(RegionArray&& ra) {
+ 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();
+}
+
+//-----------------------------------------------------------------------------
+// child
+
+TestDataStructuresChild::TestDataStructuresChild() {
+ MOZ_COUNT_CTOR(TestDataStructuresChild);
+}
+
+TestDataStructuresChild::~TestDataStructuresChild() {
+ MOZ_COUNT_DTOR(TestDataStructuresChild);
+}
+
+mozilla::ipc::IPCResult TestDataStructuresChild::RecvStart() {
+ puts("[TestDataStructuresChild] starting");
+
+ Test1();
+ Test2();
+ Test3();
+ Test4();
+ Test5();
+ Test6();
+ Test7_0();
+ Test7();
+ Test8();
+ Test9();
+ Test10();
+ Test11();
+ Test12();
+ Test13();
+ Test14();
+ Test15();
+ Test16();
+ Test17();
+ if (OtherPid() != base::GetCurrentProcId()) {
+ // FIXME/bug 703317 allocation of nsIntRegion uses a global
+ // region pool which breaks threads
+ Test18();
+ }
+
+ for (uint32_t i = 0; i < nactors; ++i)
+ if (!PTestDataStructuresSubChild::Send__delete__(mKids[i]))
+ fail("can't send dtor");
+
+ Close();
+
+ return IPC_OK();
+}
+
+void TestDataStructuresChild::Test1() {
+ nsTArray<int> ia;
+
+ for (int i = 0; i < 5; ++i) ia.AppendElement(i);
+
+ nsTArray<int> oa;
+ if (!SendTest1(ia, &oa)) fail("can't send Test1");
+
+ assert_arrays_equal(ia, oa);
+
+ printf(" passed %s\n", __FUNCTION__);
+}
+
+void TestDataStructuresChild::Test2() {
+ nsTArray<PTestDataStructuresSubChild*> oa;
+ if (!SendTest2(mKids, &oa)) fail("can't send Test2");
+ assert_arrays_equal(mKids, oa);
+
+ printf(" passed %s\n", __FUNCTION__);
+}
+
+void TestDataStructuresChild::Test3() {
+ int i1i = 42;
+ double i2d = 4.0;
+ IntDouble i1(i1i);
+ IntDouble i2(i2d);
+ IntDouble o1, o2;
+
+ SendTest3(i1, i2, &o1, &o2);
+
+ test_assert(i1i == o1.get_int(), "wrong value");
+ test_assert(i2d == o2.get_double(), "wrong value");
+
+ printf(" passed %s\n", __FUNCTION__);
+}
+
+void TestDataStructuresChild::Test4() {
+ 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;
+ if (!SendTest4(i1, &o1)) fail("can't send Test4");
+
+ // TODO Union::operator==()
+ test_assert(i1.Length() == o1.Length(), "wrong length");
+ test_assert(1 == o1[0].get_int(), "wrong value");
+ test_assert(2.0 == o1[1].get_double(), "wrong value");
+ test_assert(3 == o1[2].get_int(), "wrong value");
+ test_assert(4.0 == o1[3].get_double(), "wrong value");
+
+ printf(" passed %s\n", __FUNCTION__);
+}
+
+void TestDataStructuresChild::Test5() {
+ 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;
+ if (!SendTest5(i1, IntDoubleArrays(i2), IntDoubleArrays(i3), &o1, &o2, &o3))
+ fail("can't send Test5");
+
+ test_assert(42 == o1.get_int(), "wrong value");
+ assert_arrays_equal(i2, o2.get_ArrayOfint());
+ assert_arrays_equal(i3, o3.get_ArrayOfdouble());
+
+ printf(" passed %s\n", __FUNCTION__);
+}
+
+void TestDataStructuresChild::Test6() {
+ 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;
+ if (!SendTest6(i1, &o1)) fail("can't send Test6");
+
+ test_assert(3 == o1.Length(), "wrong length");
+ IntDoubleArrays od1(o1[0]);
+ nsTArray<int> od2(o1[1].get_ArrayOfint());
+ nsTArray<double> od3(o1[2].get_ArrayOfdouble());
+
+ test_assert(42 == od1.get_int(), "wrong value");
+ assert_arrays_equal(id2, od2);
+ assert_arrays_equal(id3, od3);
+
+ printf(" passed %s\n", __FUNCTION__);
+}
+
+void TestDataStructuresChild::Test7_0() {
+ ActorWrapper iaw;
+ if (iaw.actorChild() != nullptr || iaw.actorParent() != nullptr)
+ fail("actor members should be null initially");
+
+ iaw.actorChild() = mKids[0];
+ if (iaw.actorParent() != nullptr)
+ fail("parent should be null on child side after set");
+
+ ActorWrapper oaw;
+ if (!SendTest7_0(iaw, &oaw)) fail("sending Test7_0");
+
+ if (oaw.actorParent() != nullptr)
+ fail(
+ "parent accessor on actor-struct members should always be null in "
+ "child");
+
+ if (oaw.actorChild() != mKids[0])
+ fail("should have got back same child-side actor");
+}
+
+void TestDataStructuresChild::Test7() {
+ Actors i1(42);
+ nsTArray<int> i2a;
+ i2a.AppendElement(1);
+ i2a.AppendElement(2);
+ i2a.AppendElement(3);
+
+ Actors o1, o2, o3;
+ if (!SendTest7(i1, Actors(i2a), Actors(mKids), &o1, &o2, &o3))
+ fail("can't send Test7");
+
+ test_assert(42 == o1.get_int(), "wrong value");
+ assert_arrays_equal(i2a, o2.get_ArrayOfint());
+ assert_arrays_equal(mKids, o3.get_ArrayOfPTestDataStructuresSubChild());
+
+ printf(" passed %s\n", __FUNCTION__);
+}
+
+void TestDataStructuresChild::Test8() {
+ 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(mKids);
+
+ nsTArray<Actors> o1;
+ if (!SendTest8(i1, &o1)) fail("can't send Test8");
+
+ test_assert(3 == o1.Length(), "wrong length");
+ test_assert(42 == o1[0].get_int(), "wrong value");
+ assert_arrays_equal(i2a, o1[1].get_ArrayOfint());
+ assert_arrays_equal(mKids, o1[2].get_ArrayOfPTestDataStructuresSubChild());
+
+ printf(" passed %s\n", __FUNCTION__);
+}
+
+void TestDataStructuresChild::Test9() {
+ Unions i1(int(42));
+
+ nsTArray<int> i2a;
+ i2a.AppendElement(1);
+ i2a.AppendElement(2);
+ i2a.AppendElement(3);
+
+ nsTArray<Actors> i4a;
+ i4a.AppendElement(mKids);
+
+ Unions o1, o2, o3, o4;
+ if (!SendTest9(i1, Unions(i2a), Unions(mKids), Unions(i4a), &o1, &o2, &o3,
+ &o4))
+ fail("can't send Test9");
+
+ test_assert(42 == o1.get_int(), "wrong value");
+ assert_arrays_equal(i2a, o2.get_ArrayOfint());
+ assert_arrays_equal(mKids, o3.get_ArrayOfPTestDataStructuresSubChild());
+ assert_arrays_equal(
+ mKids,
+ o4.get_ArrayOfActors()[0].get_ArrayOfPTestDataStructuresSubChild());
+
+ printf(" passed %s\n", __FUNCTION__);
+}
+
+void TestDataStructuresChild::Test10() {
+ Unions i1a(int(42));
+
+ nsTArray<int> i2a;
+ i2a.AppendElement(1);
+ i2a.AppendElement(2);
+ i2a.AppendElement(3);
+
+ nsTArray<Actors> i4a;
+ i4a.AppendElement(mKids);
+
+ nsTArray<Unions> i1;
+ i1.AppendElement(i1a);
+ i1.AppendElement(Unions(i2a));
+ i1.AppendElement(Unions(mKids));
+ i1.AppendElement(Unions(i4a));
+
+ nsTArray<Unions> o1;
+ if (!SendTest10(i1, &o1)) fail("can't send Test10");
+
+ test_assert(4 == o1.Length(), "wrong length");
+ test_assert(42 == o1[0].get_int(), "wrong value");
+ assert_arrays_equal(i2a, o1[1].get_ArrayOfint());
+ assert_arrays_equal(mKids, o1[2].get_ArrayOfPTestDataStructuresSubChild());
+ assert_arrays_equal(
+ mKids,
+ o1[3].get_ArrayOfActors()[0].get_ArrayOfPTestDataStructuresSubChild());
+
+ printf(" passed %s\n", __FUNCTION__);
+}
+
+void TestDataStructuresChild::Test11() {
+ SIntDouble i(1, 2.0);
+ SIntDouble o;
+
+ if (!SendTest11(i, &o)) fail("sending Test11");
+
+ test_assert(1 == o.i() && 2.0 == o.d(), "wrong values");
+
+ printf(" passed %s\n", __FUNCTION__);
+}
+
+void TestDataStructuresChild::Test12() {
+ 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;
+
+ if (!SendTest12(i, &o)) fail("sending Test12");
+
+ test_assert(42 == o.i(), "wrong value");
+ assert_arrays_equal(ai, o.ai());
+ assert_arrays_equal(ad, o.ad());
+
+ printf(" passed %s\n", __FUNCTION__);
+}
+
+void TestDataStructuresChild::Test13() {
+ nsTArray<int> ai;
+ ai.AppendElement(1);
+ ai.AppendElement(2);
+ ai.AppendElement(3);
+
+ SActors i;
+ i.i() = 42;
+ i.ai() = ai;
+ i.apChild() = mKids;
+
+ SActors o;
+ if (!SendTest13(i, &o)) fail("can't send Test13");
+
+ test_assert(42 == o.i(), "wrong value");
+ assert_arrays_equal(ai, o.ai());
+ assert_arrays_equal(mKids, o.apChild());
+
+ printf(" passed %s\n", __FUNCTION__);
+}
+
+void TestDataStructuresChild::Test14() {
+ nsTArray<int> ai;
+ ai.AppendElement(1);
+ ai.AppendElement(2);
+ ai.AppendElement(3);
+
+ SActors ia;
+ ia.i() = 42;
+ ia.ai() = ai;
+ ia.apChild() = mKids;
+ nsTArray<SActors> aa;
+ aa.AppendElement(ia);
+
+ Structs i;
+ i.i() = 42;
+ i.ai() = ai;
+ i.apChild() = mKids;
+ i.aa() = aa;
+
+ Structs o;
+ if (!SendTest14(i, &o)) fail("can't send Test14");
+
+ test_assert(42 == o.i(), "wrong value");
+ assert_arrays_equal(ai, o.ai());
+ assert_arrays_equal(mKids, o.apChild());
+
+ const SActors& os = o.aa()[0];
+ test_assert(42 == os.i(), "wrong value");
+ assert_arrays_equal(ai, os.ai());
+ assert_arrays_equal(mKids, os.apChild());
+
+ printf(" passed %s\n", __FUNCTION__);
+}
+
+void TestDataStructuresChild::Test15() {
+ nsTArray<int> ai;
+ ai.AppendElement(1);
+ ai.AppendElement(2);
+ ai.AppendElement(3);
+
+ SActors ia;
+ ia.i() = 42;
+ ia.ai() = ai;
+ ia.apChild() = mKids;
+ nsTArray<SActors> iaa;
+ iaa.AppendElement(ia);
+
+ Structs is;
+ is.i() = 42;
+ is.ai() = ai;
+ is.apChild() = mKids;
+ is.aa() = iaa;
+ nsTArray<Structs> isa;
+ isa.AppendElement(is);
+
+ WithStructs o1, o2, o3, o4, o5;
+ if (!SendTest15(WithStructs(42), WithStructs(ai), WithStructs(mKids),
+ WithStructs(iaa), WithStructs(isa), &o1, &o2, &o3, &o4, &o5))
+ fail("sending Test15");
+
+ test_assert(o1 == int(42), "wrong value");
+ assert_arrays_equal(o2.get_ArrayOfint(), ai);
+ assert_arrays_equal(o3.get_ArrayOfPTestDataStructuresSubChild(), mKids);
+
+ const SActors& oa = o4.get_ArrayOfSActors()[0];
+ test_assert(42 == oa.i(), "wrong value");
+ assert_arrays_equal(ai, oa.ai());
+ assert_arrays_equal(mKids, oa.apChild());
+
+ const Structs& os = o5.get_ArrayOfStructs()[0];
+ test_assert(42 == os.i(), "wrong value");
+ assert_arrays_equal(ai, os.ai());
+ assert_arrays_equal(mKids, os.apChild());
+
+ const SActors& osa = os.aa()[0];
+ test_assert(42 == osa.i(), "wrong value");
+ assert_arrays_equal(ai, osa.ai());
+ assert_arrays_equal(mKids, osa.apChild());
+
+ printf(" passed %s\n", __FUNCTION__);
+}
+
+void TestDataStructuresChild::Test16() {
+ WithUnions i;
+
+ i.i() = 42;
+
+ nsTArray<int> ai;
+ ai.AppendElement(1);
+ ai.AppendElement(2);
+ ai.AppendElement(3);
+ i.ai() = ai;
+
+ i.apChild() = mKids;
+
+ nsTArray<Actors> iaa;
+ iaa.AppendElement(mKids);
+ i.aa() = iaa;
+
+ nsTArray<Unions> iau;
+ iau.AppendElement(int(42));
+ iau.AppendElement(ai);
+ iau.AppendElement(mKids);
+ iau.AppendElement(iaa);
+ i.au() = iau;
+
+ WithUnions o;
+ if (!SendTest16(i, &o)) fail("sending Test16");
+
+ test_assert(42 == o.i(), "wrong value");
+ assert_arrays_equal(o.ai(), ai);
+ assert_arrays_equal(o.apChild(), mKids);
+
+ const Actors& oaa = o.aa()[0];
+ assert_arrays_equal(oaa.get_ArrayOfPTestDataStructuresSubChild(), mKids);
+
+ const nsTArray<Unions>& oau = o.au();
+ test_assert(oau[0] == 42, "wrong value");
+ assert_arrays_equal(oau[1].get_ArrayOfint(), ai);
+ assert_arrays_equal(oau[2].get_ArrayOfPTestDataStructuresSubChild(), mKids);
+ assert_arrays_equal(
+ oau[3].get_ArrayOfActors()[0].get_ArrayOfPTestDataStructuresSubChild(),
+ mKids);
+
+ printf(" passed %s\n", __FUNCTION__);
+}
+
+void TestDataStructuresChild::Test17() {
+ Attrs attrs;
+ attrs.common() = CommonAttrs(true);
+ attrs.specific() = BarAttrs(1.0f);
+
+ nsTArray<Op> ops;
+ ops.AppendElement(SetAttrs(nullptr, mKids[0], attrs));
+
+ if (!SendTest17(ops)) fail("sending Test17");
+
+ printf(" passed %s\n", __FUNCTION__);
+}
+
+void TestDataStructuresChild::Test18() {
+ 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);
+ }
+
+ if (!SendTest18(ra)) fail("sending Test18");
+
+ printf(" passed %s\n", __FUNCTION__);
+}
+
+} // namespace _ipdltest
+} // namespace mozilla
diff --git a/ipc/ipdl/test/cxx/TestDataStructures.h b/ipc/ipdl/test/cxx/TestDataStructures.h
new file mode 100644
index 0000000000..dc25b5282c
--- /dev/null
+++ b/ipc/ipdl/test/cxx/TestDataStructures.h
@@ -0,0 +1,180 @@
+#ifndef mozilla__ipdltest_TestDataStructures_h
+#define mozilla__ipdltest_TestDataStructures_h 1
+
+#include "mozilla/_ipdltest/IPDLUnitTests.h"
+
+#include "mozilla/_ipdltest/PTestDataStructuresParent.h"
+#include "mozilla/_ipdltest/PTestDataStructuresChild.h"
+
+#include "mozilla/_ipdltest/PTestDataStructuresSubParent.h"
+#include "mozilla/_ipdltest/PTestDataStructuresSubChild.h"
+
+namespace mozilla {
+namespace _ipdltest {
+
+//-----------------------------------------------------------------------------
+// Subprotocol actors
+
+class TestDataStructuresSub : public PTestDataStructuresSubParent,
+ public PTestDataStructuresSubChild {
+ public:
+ explicit TestDataStructuresSub(uint32_t i) : mI(i) {}
+ virtual ~TestDataStructuresSub() {}
+ virtual void ActorDestroy(ActorDestroyReason why) override {
+ if (Deletion != why) fail("unexpected destruction!");
+ }
+ uint32_t mI;
+};
+
+//-----------------------------------------------------------------------------
+// Main actors
+
+class TestDataStructuresParent : public PTestDataStructuresParent {
+ friend class PTestDataStructuresParent;
+
+ public:
+ TestDataStructuresParent();
+ virtual ~TestDataStructuresParent();
+
+ static bool RunTestInProcesses() { return true; }
+ static bool RunTestInThreads() { return true; }
+
+ void Main();
+
+ protected:
+ PTestDataStructuresSubParent* AllocPTestDataStructuresSubParent(
+ const int& i) {
+ PTestDataStructuresSubParent* actor = new TestDataStructuresSub(i);
+ mKids.AppendElement(actor);
+ return actor;
+ }
+
+ bool DeallocPTestDataStructuresSubParent(PTestDataStructuresSubParent* actor);
+
+ mozilla::ipc::IPCResult RecvTest1(nsTArray<int>&& i1, nsTArray<int>* o1);
+
+ mozilla::ipc::IPCResult RecvTest2(
+ nsTArray<PTestDataStructuresSubParent*>&& i1,
+ nsTArray<PTestDataStructuresSubParent*>* o1);
+
+ mozilla::ipc::IPCResult RecvTest3(const IntDouble& i1, const IntDouble& i2,
+ IntDouble* o1, IntDouble* o2);
+
+ mozilla::ipc::IPCResult RecvTest4(nsTArray<IntDouble>&& i1,
+ nsTArray<IntDouble>* o1);
+
+ mozilla::ipc::IPCResult RecvTest5(const IntDoubleArrays& i1,
+ const IntDoubleArrays& i2,
+ const IntDoubleArrays& i3,
+ IntDoubleArrays* o1, IntDoubleArrays* o2,
+ IntDoubleArrays* o3);
+
+ mozilla::ipc::IPCResult RecvTest6(nsTArray<IntDoubleArrays>&& i1,
+ nsTArray<IntDoubleArrays>* o1);
+
+ mozilla::ipc::IPCResult RecvTest7_0(const ActorWrapper& i1, ActorWrapper* o1);
+
+ mozilla::ipc::IPCResult RecvTest7(const Actors& i1, const Actors& i2,
+ const Actors& i3, Actors* o1, Actors* o2,
+ Actors* o3);
+
+ mozilla::ipc::IPCResult RecvTest8(nsTArray<Actors>&& i1,
+ nsTArray<Actors>* o1);
+
+ mozilla::ipc::IPCResult RecvTest9(const Unions& i1, const Unions& i2,
+ const Unions& i3, const Unions& i4,
+ Unions* o1, Unions* o2, Unions* o3,
+ Unions* o4);
+
+ mozilla::ipc::IPCResult RecvTest10(nsTArray<Unions>&& i1,
+ nsTArray<Unions>* o1);
+
+ mozilla::ipc::IPCResult RecvTest11(const SIntDouble& i, SIntDouble* o);
+
+ mozilla::ipc::IPCResult RecvTest12(const SIntDoubleArrays& i,
+ SIntDoubleArrays* o);
+
+ mozilla::ipc::IPCResult RecvTest13(const SActors& i, SActors* o);
+
+ mozilla::ipc::IPCResult RecvTest14(const Structs& i, Structs* o);
+
+ mozilla::ipc::IPCResult RecvTest15(
+ 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);
+
+ mozilla::ipc::IPCResult RecvTest16(const WithUnions& i, WithUnions* o);
+
+ mozilla::ipc::IPCResult RecvTest17(nsTArray<Op>&& sa);
+
+ mozilla::ipc::IPCResult RecvTest18(nsTArray<nsIntRegion>&& ra);
+
+ mozilla::ipc::IPCResult RecvDummy(const ShmemUnion& su, ShmemUnion* rsu) {
+ *rsu = su;
+ return IPC_OK();
+ }
+
+ virtual void ActorDestroy(ActorDestroyReason why) override {
+ if (NormalShutdown != why) fail("unexpected destruction!");
+ passed("ok");
+ QuitParent();
+ }
+
+ private:
+ nsTArray<PTestDataStructuresSubParent*> mKids;
+};
+
+class TestDataStructuresChild : public PTestDataStructuresChild {
+ friend class PTestDataStructuresChild;
+
+ public:
+ TestDataStructuresChild();
+ virtual ~TestDataStructuresChild();
+
+ protected:
+ PTestDataStructuresSubChild* AllocPTestDataStructuresSubChild(const int& i) {
+ PTestDataStructuresSubChild* actor = new TestDataStructuresSub(i);
+ mKids.AppendElement(actor);
+ return actor;
+ }
+
+ bool DeallocPTestDataStructuresSubChild(PTestDataStructuresSubChild* actor) {
+ delete actor;
+ return true;
+ }
+
+ mozilla::ipc::IPCResult RecvStart();
+
+ virtual void ActorDestroy(ActorDestroyReason why) override {
+ if (NormalShutdown != why) fail("unexpected destruction!");
+ QuitChild();
+ }
+
+ private:
+ void Test1();
+ void Test2();
+ void Test3();
+ void Test4();
+ void Test5();
+ void Test6();
+ void Test7_0();
+ void Test7();
+ void Test8();
+ void Test9();
+ void Test10();
+ void Test11();
+ void Test12();
+ void Test13();
+ void Test14();
+ void Test15();
+ void Test16();
+ void Test17();
+ void Test18();
+
+ nsTArray<PTestDataStructuresSubChild*> mKids;
+};
+
+} // namespace _ipdltest
+} // namespace mozilla
+
+#endif // ifndef mozilla__ipdltest_TestDataStructures_h
diff --git a/ipc/ipdl/test/cxx/TestDemon.cpp b/ipc/ipdl/test/cxx/TestDemon.cpp
new file mode 100644
index 0000000000..396974bb56
--- /dev/null
+++ b/ipc/ipdl/test/cxx/TestDemon.cpp
@@ -0,0 +1,362 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim: sw=2 ts=4 et :
+ */
+#include "TestDemon.h"
+
+#include <stdlib.h>
+
+#include "IPDLUnitTests.h" // fail etc.
+#if defined(XP_UNIX)
+# include <sys/time.h>
+# include <unistd.h>
+#else
+# include <time.h>
+# include <windows.h>
+#endif
+
+namespace mozilla {
+namespace _ipdltest {
+
+const int kMaxStackHeight = 4;
+
+static LazyLogModule sLogModule("demon");
+
+#define DEMON_LOG(...) MOZ_LOG(sLogModule, LogLevel::Debug, (__VA_ARGS__))
+
+static int gStackHeight = 0;
+static bool gFlushStack = false;
+
+static int Choose(int count) {
+#if defined(XP_UNIX)
+ return random() % count;
+#else
+ return rand() % count;
+#endif
+}
+
+//-----------------------------------------------------------------------------
+// parent
+
+TestDemonParent::TestDemonParent() : mDone(false), mIncoming(), mOutgoing() {
+ MOZ_COUNT_CTOR(TestDemonParent);
+}
+
+TestDemonParent::~TestDemonParent() { MOZ_COUNT_DTOR(TestDemonParent); }
+
+void TestDemonParent::Main() {
+ if (!getenv("MOZ_TEST_IPC_DEMON")) {
+ QuitParent();
+ return;
+ }
+#if defined(XP_UNIX)
+ srandom(time(nullptr));
+#else
+ srand(time(nullptr));
+#endif
+
+ DEMON_LOG("Start demon");
+
+ if (!SendStart()) fail("sending Start");
+
+ RunUnlimitedSequence();
+}
+
+#ifdef DEBUG
+bool TestDemonParent::ShouldContinueFromReplyTimeout() {
+ return Choose(2) == 0;
+}
+
+bool TestDemonParent::ArtificialTimeout() { return Choose(5) == 0; }
+
+void TestDemonParent::ArtificialSleep() {
+ if (Choose(2) == 0) {
+ // Sleep for anywhere from 0 to 100 milliseconds.
+ unsigned micros = Choose(100) * 1000;
+# ifdef XP_UNIX
+ usleep(micros);
+# else
+ Sleep(micros / 1000);
+# endif
+ }
+}
+#endif
+
+mozilla::ipc::IPCResult TestDemonParent::RecvAsyncMessage(const int& n) {
+ DEMON_LOG("Start RecvAsync [%d]", n);
+
+ MOZ_ASSERT(n == mIncoming[0]);
+ mIncoming[0]++;
+
+ RunLimitedSequence();
+
+ DEMON_LOG("End RecvAsync [%d]", n);
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult TestDemonParent::RecvHiPrioSyncMessage() {
+ DEMON_LOG("Start RecvHiPrioSyncMessage");
+ RunLimitedSequence();
+ DEMON_LOG("End RecvHiPrioSyncMessage");
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult TestDemonParent::RecvSyncMessage(const int& n) {
+ DEMON_LOG("Start RecvSync [%d]", n);
+
+ MOZ_ASSERT(n == mIncoming[0]);
+ mIncoming[0]++;
+
+ RunLimitedSequence(ASYNC_ONLY);
+
+ DEMON_LOG("End RecvSync [%d]", n);
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult TestDemonParent::RecvUrgentAsyncMessage(const int& n) {
+ DEMON_LOG("Start RecvUrgentAsyncMessage [%d]", n);
+
+ MOZ_ASSERT(n == mIncoming[2]);
+ mIncoming[2]++;
+
+ RunLimitedSequence(ASYNC_ONLY);
+
+ DEMON_LOG("End RecvUrgentAsyncMessage [%d]", n);
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult TestDemonParent::RecvUrgentSyncMessage(const int& n) {
+ DEMON_LOG("Start RecvUrgentSyncMessage [%d]", n);
+
+ MOZ_ASSERT(n == mIncoming[2]);
+ mIncoming[2]++;
+
+ RunLimitedSequence(ASYNC_ONLY);
+
+ DEMON_LOG("End RecvUrgentSyncMessage [%d]", n);
+ return IPC_OK();
+}
+
+void TestDemonParent::RunUnlimitedSequence() {
+ if (mDone) {
+ return;
+ }
+
+ gFlushStack = false;
+ DoAction();
+
+ MessageLoop::current()->PostTask(NewNonOwningRunnableMethod(
+ "_ipdltest::TestDemonParent::RunUnlimitedSequence", this,
+ &TestDemonParent::RunUnlimitedSequence));
+}
+
+void TestDemonParent::RunLimitedSequence(int flags) {
+ if (gStackHeight >= kMaxStackHeight) {
+ return;
+ }
+ gStackHeight++;
+
+ int count = Choose(20);
+ for (int i = 0; i < count; i++) {
+ if (!DoAction(flags)) {
+ gFlushStack = true;
+ }
+ if (gFlushStack) {
+ gStackHeight--;
+ return;
+ }
+ }
+
+ gStackHeight--;
+}
+
+static bool AllowAsync(int outgoing, int incoming) {
+ return incoming >= outgoing - 5;
+}
+
+bool TestDemonParent::DoAction(int flags) {
+ if (flags & ASYNC_ONLY) {
+ if (AllowAsync(mOutgoing[0], mIncoming[0])) {
+ DEMON_LOG("SendAsyncMessage [%d]", mOutgoing[0]);
+ return SendAsyncMessage(mOutgoing[0]++);
+ } else {
+ return true;
+ }
+ } else {
+ switch (Choose(3)) {
+ case 0:
+ if (AllowAsync(mOutgoing[0], mIncoming[0])) {
+ DEMON_LOG("SendAsyncMessage [%d]", mOutgoing[0]);
+ return SendAsyncMessage(mOutgoing[0]++);
+ } else {
+ return true;
+ }
+
+ case 1: {
+ DEMON_LOG("Start SendHiPrioSyncMessage");
+ bool r = SendHiPrioSyncMessage();
+ DEMON_LOG("End SendHiPrioSyncMessage result=%d", r);
+ return r;
+ }
+
+ case 2:
+ DEMON_LOG("Cancel");
+ GetIPCChannel()->CancelCurrentTransaction();
+ return true;
+ }
+ }
+ MOZ_CRASH();
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// child
+
+TestDemonChild::TestDemonChild() : mIncoming(), mOutgoing() {
+ MOZ_COUNT_CTOR(TestDemonChild);
+}
+
+TestDemonChild::~TestDemonChild() { MOZ_COUNT_DTOR(TestDemonChild); }
+
+mozilla::ipc::IPCResult TestDemonChild::RecvStart() {
+#ifdef XP_UNIX
+ srandom(time(nullptr));
+#else
+ srand(time(nullptr));
+#endif
+
+ DEMON_LOG("RecvStart");
+
+ RunUnlimitedSequence();
+ return IPC_OK();
+}
+
+#ifdef DEBUG
+void TestDemonChild::ArtificialSleep() {
+ if (Choose(2) == 0) {
+ // Sleep for anywhere from 0 to 100 milliseconds.
+ unsigned micros = Choose(100) * 1000;
+# ifdef XP_UNIX
+ usleep(micros);
+# else
+ Sleep(micros / 1000);
+# endif
+ }
+}
+#endif
+
+mozilla::ipc::IPCResult TestDemonChild::RecvAsyncMessage(const int& n) {
+ DEMON_LOG("Start RecvAsyncMessage [%d]", n);
+
+ MOZ_ASSERT(n == mIncoming[0]);
+ mIncoming[0]++;
+
+ RunLimitedSequence();
+
+ DEMON_LOG("End RecvAsyncMessage [%d]", n);
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult TestDemonChild::RecvHiPrioSyncMessage() {
+ DEMON_LOG("Start RecvHiPrioSyncMessage");
+ RunLimitedSequence();
+ DEMON_LOG("End RecvHiPrioSyncMessage");
+ return IPC_OK();
+}
+
+void TestDemonChild::RunUnlimitedSequence() {
+ gFlushStack = false;
+ DoAction();
+
+ MessageLoop::current()->PostTask(NewNonOwningRunnableMethod(
+ "_ipdltest::TestDemonChild::RunUnlimitedSequence", this,
+ &TestDemonChild::RunUnlimitedSequence));
+}
+
+void TestDemonChild::RunLimitedSequence() {
+ if (gStackHeight >= kMaxStackHeight) {
+ return;
+ }
+ gStackHeight++;
+
+ int count = Choose(20);
+ for (int i = 0; i < count; i++) {
+ if (!DoAction()) {
+ gFlushStack = true;
+ }
+ if (gFlushStack) {
+ gStackHeight--;
+ return;
+ }
+ }
+
+ gStackHeight--;
+}
+
+bool TestDemonChild::DoAction() {
+ switch (Choose(6)) {
+ case 0:
+ if (AllowAsync(mOutgoing[0], mIncoming[0])) {
+ DEMON_LOG("SendAsyncMessage [%d]", mOutgoing[0]);
+ return SendAsyncMessage(mOutgoing[0]++);
+ } else {
+ return true;
+ }
+
+ case 1: {
+ DEMON_LOG("Start SendHiPrioSyncMessage");
+ bool r = SendHiPrioSyncMessage();
+ DEMON_LOG("End SendHiPrioSyncMessage result=%d", r);
+ return r;
+ }
+
+ case 2: {
+ DEMON_LOG("Start SendSyncMessage [%d]", mOutgoing[0]);
+ bool r = SendSyncMessage(mOutgoing[0]++);
+ switch (GetIPCChannel()->LastSendError()) {
+ case SyncSendError::PreviousTimeout:
+ case SyncSendError::SendingCPOWWhileDispatchingSync:
+ case SyncSendError::SendingCPOWWhileDispatchingUrgent:
+ case SyncSendError::NotConnectedBeforeSend:
+ case SyncSendError::CancelledBeforeSend:
+ mOutgoing[0]--;
+ break;
+ default:
+ break;
+ }
+ DEMON_LOG("End SendSyncMessage result=%d", r);
+ return r;
+ }
+
+ case 3:
+ DEMON_LOG("SendUrgentAsyncMessage [%d]", mOutgoing[2]);
+ return SendUrgentAsyncMessage(mOutgoing[2]++);
+
+ case 4: {
+ DEMON_LOG("Start SendUrgentSyncMessage [%d]", mOutgoing[2]);
+ bool r = SendUrgentSyncMessage(mOutgoing[2]++);
+ switch (GetIPCChannel()->LastSendError()) {
+ case SyncSendError::PreviousTimeout:
+ case SyncSendError::SendingCPOWWhileDispatchingSync:
+ case SyncSendError::SendingCPOWWhileDispatchingUrgent:
+ case SyncSendError::NotConnectedBeforeSend:
+ case SyncSendError::CancelledBeforeSend:
+ mOutgoing[2]--;
+ break;
+ default:
+ break;
+ }
+ DEMON_LOG("End SendUrgentSyncMessage result=%d", r);
+ return r;
+ }
+
+ case 5:
+ DEMON_LOG("Cancel");
+ GetIPCChannel()->CancelCurrentTransaction();
+ return true;
+ }
+ MOZ_CRASH();
+ return false;
+}
+
+} // namespace _ipdltest
+} // namespace mozilla
diff --git a/ipc/ipdl/test/cxx/TestDemon.h b/ipc/ipdl/test/cxx/TestDemon.h
new file mode 100644
index 0000000000..ba5b003436
--- /dev/null
+++ b/ipc/ipdl/test/cxx/TestDemon.h
@@ -0,0 +1,91 @@
+#ifndef mozilla__ipdltest_TestDemon_h
+#define mozilla__ipdltest_TestDemon_h 1
+
+#include "mozilla/_ipdltest/IPDLUnitTests.h"
+
+#include "mozilla/_ipdltest/PTestDemonParent.h"
+#include "mozilla/_ipdltest/PTestDemonChild.h"
+
+using namespace mozilla::ipc;
+
+namespace mozilla {
+namespace _ipdltest {
+
+class TestDemonParent : public PTestDemonParent {
+ public:
+ TestDemonParent();
+ virtual ~TestDemonParent();
+
+ static bool RunTestInProcesses() { return true; }
+ static bool RunTestInThreads() { return true; }
+
+ void Main();
+
+#ifdef DEBUG
+ bool ShouldContinueFromReplyTimeout() override;
+ bool ArtificialTimeout() override;
+
+ bool NeedArtificialSleep() override { return true; }
+ void ArtificialSleep() override;
+#endif
+
+ mozilla::ipc::IPCResult RecvAsyncMessage(const int& n);
+ mozilla::ipc::IPCResult RecvHiPrioSyncMessage();
+
+ mozilla::ipc::IPCResult RecvSyncMessage(const int& n);
+ mozilla::ipc::IPCResult RecvUrgentAsyncMessage(const int& n);
+ mozilla::ipc::IPCResult RecvUrgentSyncMessage(const int& n);
+
+ virtual void ActorDestroy(ActorDestroyReason why) override {
+ mDone = true;
+ printf("Parent ActorDestroy\n");
+ passed("ok");
+ QuitParent();
+ }
+
+ private:
+ bool mDone;
+ int mIncoming[3];
+ int mOutgoing[3];
+
+ enum {
+ ASYNC_ONLY = 1,
+ };
+
+ void RunUnlimitedSequence();
+ void RunLimitedSequence(int flags = 0);
+ bool DoAction(int flags = 0);
+};
+
+class TestDemonChild : public PTestDemonChild {
+ public:
+ TestDemonChild();
+ virtual ~TestDemonChild();
+
+ mozilla::ipc::IPCResult RecvStart();
+
+#ifdef DEBUG
+ bool NeedArtificialSleep() override { return true; }
+ void ArtificialSleep() override;
+#endif
+
+ mozilla::ipc::IPCResult RecvAsyncMessage(const int& n);
+ mozilla::ipc::IPCResult RecvHiPrioSyncMessage();
+
+ virtual void ActorDestroy(ActorDestroyReason why) override { _exit(0); }
+
+ virtual void IntentionalCrash() override { _exit(0); }
+
+ private:
+ int mIncoming[3];
+ int mOutgoing[3];
+
+ void RunUnlimitedSequence();
+ void RunLimitedSequence();
+ bool DoAction();
+};
+
+} // namespace _ipdltest
+} // namespace mozilla
+
+#endif // ifndef mozilla__ipdltest_TestDemon_h
diff --git a/ipc/ipdl/test/cxx/TestDesc.cpp b/ipc/ipdl/test/cxx/TestDesc.cpp
new file mode 100644
index 0000000000..2ae199457d
--- /dev/null
+++ b/ipc/ipdl/test/cxx/TestDesc.cpp
@@ -0,0 +1,78 @@
+#include "TestDesc.h"
+
+#include "IPDLUnitTests.h" // fail etc.
+
+namespace mozilla {
+namespace _ipdltest {
+
+//-----------------------------------------------------------------------------
+// parent
+void TestDescParent::Main() {
+ PTestDescSubParent* p = CallPTestDescSubConstructor(0);
+ if (!p) fail("can't allocate Sub");
+
+ PTestDescSubsubParent* pp = p->CallPTestDescSubsubConstructor();
+ if (!pp) fail("can't allocate Subsub");
+
+ if (!SendTest(pp)) fail("can't send Subsub");
+}
+
+mozilla::ipc::IPCResult TestDescParent::RecvOk(PTestDescSubsubParent* a) {
+ if (!a) fail("didn't receive Subsub");
+
+ if (!PTestDescSubsubParent::Call__delete__(a)) fail("deleting Subsub");
+
+ Close();
+
+ return IPC_OK();
+}
+
+PTestDescSubParent* TestDescParent::AllocPTestDescSubParent(
+ PTestDescSubsubParent* dummy) {
+ if (dummy) fail("actor supposed to be null");
+ return new TestDescSubParent();
+}
+bool TestDescParent::DeallocPTestDescSubParent(PTestDescSubParent* actor) {
+ delete actor;
+ return true;
+}
+
+PTestDescSubsubParent* TestDescSubParent::AllocPTestDescSubsubParent() {
+ return new TestDescSubsubParent();
+}
+bool TestDescSubParent::DeallocPTestDescSubsubParent(
+ PTestDescSubsubParent* actor) {
+ delete actor;
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// child
+
+mozilla::ipc::IPCResult TestDescChild::RecvTest(PTestDescSubsubChild* a) {
+ if (!a) fail("didn't receive Subsub");
+ if (!SendOk(a)) fail("couldn't send Ok()");
+ return IPC_OK();
+}
+
+PTestDescSubChild* TestDescChild::AllocPTestDescSubChild(
+ PTestDescSubsubChild* dummy) {
+ if (dummy) fail("actor supposed to be null");
+ return new TestDescSubChild();
+}
+bool TestDescChild::DeallocPTestDescSubChild(PTestDescSubChild* actor) {
+ delete actor;
+ return true;
+}
+
+PTestDescSubsubChild* TestDescSubChild::AllocPTestDescSubsubChild() {
+ return new TestDescSubsubChild();
+}
+bool TestDescSubChild::DeallocPTestDescSubsubChild(
+ PTestDescSubsubChild* actor) {
+ delete actor;
+ return true;
+}
+
+} // namespace _ipdltest
+} // namespace mozilla
diff --git a/ipc/ipdl/test/cxx/TestDesc.h b/ipc/ipdl/test/cxx/TestDesc.h
new file mode 100644
index 0000000000..c9fa04f89c
--- /dev/null
+++ b/ipc/ipdl/test/cxx/TestDesc.h
@@ -0,0 +1,115 @@
+#ifndef mozilla_ipdltest_TestDesc_h
+#define mozilla_ipdltest_TestDesc_h
+
+#include "mozilla/_ipdltest/IPDLUnitTests.h"
+
+#include "mozilla/_ipdltest/PTestDescParent.h"
+#include "mozilla/_ipdltest/PTestDescChild.h"
+
+#include "mozilla/_ipdltest/PTestDescSubParent.h"
+#include "mozilla/_ipdltest/PTestDescSubChild.h"
+
+#include "mozilla/_ipdltest/PTestDescSubsubParent.h"
+#include "mozilla/_ipdltest/PTestDescSubsubChild.h"
+
+namespace mozilla {
+namespace _ipdltest {
+
+//-----------------------------------------------------------------------------
+// Top-level
+//
+class TestDescParent : public PTestDescParent {
+ friend class PTestDescParent;
+
+ public:
+ TestDescParent() {}
+ virtual ~TestDescParent() {}
+
+ static bool RunTestInProcesses() { return true; }
+ static bool RunTestInThreads() { return true; }
+
+ void Main();
+
+ mozilla::ipc::IPCResult RecvOk(PTestDescSubsubParent* a);
+
+ protected:
+ PTestDescSubParent* AllocPTestDescSubParent(PTestDescSubsubParent*);
+ bool DeallocPTestDescSubParent(PTestDescSubParent* actor);
+
+ virtual void ActorDestroy(ActorDestroyReason why) override {
+ if (NormalShutdown != why) fail("unexpected destruction!");
+ passed("ok");
+ QuitParent();
+ }
+};
+
+class TestDescChild : public PTestDescChild {
+ friend class PTestDescChild;
+
+ public:
+ TestDescChild() {}
+ virtual ~TestDescChild() {}
+
+ protected:
+ PTestDescSubChild* AllocPTestDescSubChild(PTestDescSubsubChild*);
+
+ bool DeallocPTestDescSubChild(PTestDescSubChild* actor);
+
+ mozilla::ipc::IPCResult RecvTest(PTestDescSubsubChild* a);
+
+ virtual void ActorDestroy(ActorDestroyReason why) override {
+ if (NormalShutdown != why) fail("unexpected destruction!");
+ QuitChild();
+ }
+};
+
+//-----------------------------------------------------------------------------
+// First descendent
+//
+class TestDescSubParent : public PTestDescSubParent {
+ friend class PTestDescSubParent;
+
+ public:
+ TestDescSubParent() {}
+ virtual ~TestDescSubParent() {}
+
+ protected:
+ virtual void ActorDestroy(ActorDestroyReason why) override {}
+ PTestDescSubsubParent* AllocPTestDescSubsubParent();
+ bool DeallocPTestDescSubsubParent(PTestDescSubsubParent* actor);
+};
+
+class TestDescSubChild : public PTestDescSubChild {
+ friend class PTestDescSubChild;
+
+ public:
+ TestDescSubChild() {}
+ virtual ~TestDescSubChild() {}
+
+ protected:
+ PTestDescSubsubChild* AllocPTestDescSubsubChild();
+ bool DeallocPTestDescSubsubChild(PTestDescSubsubChild* actor);
+};
+
+//-----------------------------------------------------------------------------
+// Grand-descendent
+//
+class TestDescSubsubParent : public PTestDescSubsubParent {
+ public:
+ TestDescSubsubParent() {}
+ virtual ~TestDescSubsubParent() {}
+
+ protected:
+ virtual void ActorDestroy(ActorDestroyReason why) override {}
+};
+
+class TestDescSubsubChild : public PTestDescSubsubChild {
+ public:
+ TestDescSubsubChild() {}
+ virtual ~TestDescSubsubChild() {}
+};
+
+} // namespace _ipdltest
+} // namespace mozilla
+
+#endif // ifndef mozilla_ipdltest_TestDesc_h
diff --git a/ipc/ipdl/test/cxx/TestEndpointBridgeMain.cpp b/ipc/ipdl/test/cxx/TestEndpointBridgeMain.cpp
new file mode 100644
index 0000000000..4a4366f0ba
--- /dev/null
+++ b/ipc/ipdl/test/cxx/TestEndpointBridgeMain.cpp
@@ -0,0 +1,226 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+
+#include "TestEndpointBridgeMain.h"
+
+#include "base/task.h"
+#include "IPDLUnitTests.h" // fail etc.
+#include "IPDLUnitTestSubprocess.h"
+
+using namespace std;
+
+namespace mozilla {
+namespace _ipdltest {
+
+//-----------------------------------------------------------------------------
+// main process
+void TestEndpointBridgeMainParent::Main() {
+ if (!SendStart()) {
+ fail("sending Start");
+ }
+}
+
+mozilla::ipc::IPCResult TestEndpointBridgeMainParent::RecvBridged(
+ Endpoint<PTestEndpointBridgeMainSubParent>&& endpoint) {
+ TestEndpointBridgeMainSubParent* a = new TestEndpointBridgeMainSubParent();
+ if (!endpoint.Bind(a)) {
+ fail("Bind failed");
+ }
+ return IPC_OK();
+}
+
+void TestEndpointBridgeMainParent::ActorDestroy(ActorDestroyReason why) {
+ if (NormalShutdown != why) {
+ fail("unexpected destruction!");
+ }
+ passed("ok");
+ QuitParent();
+}
+
+mozilla::ipc::IPCResult TestEndpointBridgeMainSubParent::RecvHello() {
+ if (!SendHi()) {
+ return IPC_FAIL_NO_REASON(this);
+ }
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult TestEndpointBridgeMainSubParent::RecvHelloSync() {
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult TestEndpointBridgeMainSubParent::AnswerHelloRpc() {
+ if (!CallHiRpc()) {
+ return IPC_FAIL_NO_REASON(this);
+ }
+ return IPC_OK();
+}
+
+void TestEndpointBridgeMainSubParent::ActorDestroy(ActorDestroyReason why) {
+ if (NormalShutdown != why) {
+ fail("unexpected destruction!");
+ }
+
+ // ActorDestroy() is just a callback from IPDL-generated code,
+ // which needs the top-level actor (this) to stay alive a little
+ // longer so other things can be cleaned up.
+ MessageLoop::current()->PostTask(
+ do_AddRef(new DeleteTask<TestEndpointBridgeMainSubParent>(this)));
+}
+
+//-----------------------------------------------------------------------------
+// sub process --- child of main
+TestEndpointBridgeMainChild* gEndpointBridgeMainChild;
+
+TestEndpointBridgeMainChild::TestEndpointBridgeMainChild()
+ : mSubprocess(nullptr) {
+ gEndpointBridgeMainChild = this;
+}
+
+mozilla::ipc::IPCResult TestEndpointBridgeMainChild::RecvStart() {
+ vector<string> subsubArgs;
+ subsubArgs.push_back("TestEndpointBridgeSub");
+
+ mSubprocess = new IPDLUnitTestSubprocess();
+ if (!mSubprocess->SyncLaunch(subsubArgs)) {
+ fail("problem launching subprocess");
+ }
+
+ IPC::Channel* transport = mSubprocess->GetChannel();
+ if (!transport) {
+ fail("no transport");
+ }
+
+ TestEndpointBridgeSubParent* bsp = new TestEndpointBridgeSubParent();
+ bsp->Open(transport, base::GetProcId(mSubprocess->GetChildProcessHandle()));
+
+ bsp->Main();
+ return IPC_OK();
+}
+
+void TestEndpointBridgeMainChild::ActorDestroy(ActorDestroyReason why) {
+ if (NormalShutdown != why) {
+ fail("unexpected destruction!");
+ }
+ // NB: this is kosher because QuitChild() joins with the IO thread
+ mSubprocess->Destroy();
+ mSubprocess = nullptr;
+ QuitChild();
+}
+
+void TestEndpointBridgeSubParent::Main() {
+ if (!SendPing()) {
+ fail("sending Ping");
+ }
+}
+
+mozilla::ipc::IPCResult TestEndpointBridgeSubParent::RecvBridgeEm() {
+ Endpoint<PTestEndpointBridgeMainSubParent> parent;
+ Endpoint<PTestEndpointBridgeMainSubChild> child;
+ nsresult rv;
+ rv = PTestEndpointBridgeMainSub::CreateEndpoints(
+ gEndpointBridgeMainChild->OtherPid(), OtherPid(), &parent, &child);
+ if (NS_FAILED(rv)) {
+ fail("opening PTestEndpointOpensOpened");
+ }
+
+ if (!gEndpointBridgeMainChild->SendBridged(std::move(parent))) {
+ fail("SendBridge failed for parent");
+ }
+ if (!SendBridged(std::move(child))) {
+ fail("SendBridge failed for child");
+ }
+
+ return IPC_OK();
+}
+
+void TestEndpointBridgeSubParent::ActorDestroy(ActorDestroyReason why) {
+ if (NormalShutdown != why) {
+ fail("unexpected destruction!");
+ }
+ gEndpointBridgeMainChild->Close();
+
+ // ActorDestroy() is just a callback from IPDL-generated code,
+ // which needs the top-level actor (this) to stay alive a little
+ // longer so other things can be cleaned up.
+ MessageLoop::current()->PostTask(
+ do_AddRef(new DeleteTask<TestEndpointBridgeSubParent>(this)));
+}
+
+//-----------------------------------------------------------------------------
+// subsub process --- child of sub
+
+static TestEndpointBridgeSubChild* gBridgeSubChild;
+
+TestEndpointBridgeSubChild::TestEndpointBridgeSubChild() {
+ gBridgeSubChild = this;
+}
+
+mozilla::ipc::IPCResult TestEndpointBridgeSubChild::RecvPing() {
+ if (!SendBridgeEm()) {
+ fail("sending BridgeEm");
+ }
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult TestEndpointBridgeSubChild::RecvBridged(
+ Endpoint<PTestEndpointBridgeMainSubChild>&& endpoint) {
+ TestEndpointBridgeMainSubChild* a = new TestEndpointBridgeMainSubChild();
+
+ if (!endpoint.Bind(a)) {
+ fail("failed to Bind");
+ }
+
+ if (!a->SendHello()) {
+ fail("sending Hello");
+ }
+
+ return IPC_OK();
+}
+
+void TestEndpointBridgeSubChild::ActorDestroy(ActorDestroyReason why) {
+ if (NormalShutdown != why) {
+ fail("unexpected destruction!");
+ }
+ QuitChild();
+}
+
+mozilla::ipc::IPCResult TestEndpointBridgeMainSubChild::RecvHi() {
+ if (!SendHelloSync()) {
+ fail("sending HelloSync");
+ }
+ if (!CallHelloRpc()) {
+ fail("calling HelloRpc");
+ }
+ if (!mGotHi) {
+ fail("didn't answer HiRpc");
+ }
+
+ // Need to close the channel without message-processing frames on
+ // the C++ stack
+ MessageLoop::current()->PostTask(
+ NewNonOwningRunnableMethod("ipc::IToplevelProtocol::Close", this,
+ &TestEndpointBridgeMainSubChild::Close));
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult TestEndpointBridgeMainSubChild::AnswerHiRpc() {
+ mGotHi = true; // d00d
+ return IPC_OK();
+}
+
+void TestEndpointBridgeMainSubChild::ActorDestroy(ActorDestroyReason why) {
+ if (NormalShutdown != why) {
+ fail("unexpected destruction!");
+ }
+
+ gBridgeSubChild->Close();
+
+ // ActorDestroy() is just a callback from IPDL-generated code,
+ // which needs the top-level actor (this) to stay alive a little
+ // longer so other things can be cleaned up.
+ MessageLoop::current()->PostTask(
+ do_AddRef(new DeleteTask<TestEndpointBridgeMainSubChild>(this)));
+}
+
+} // namespace _ipdltest
+} // namespace mozilla
diff --git a/ipc/ipdl/test/cxx/TestEndpointBridgeMain.h b/ipc/ipdl/test/cxx/TestEndpointBridgeMain.h
new file mode 100644
index 0000000000..88ac12d71b
--- /dev/null
+++ b/ipc/ipdl/test/cxx/TestEndpointBridgeMain.h
@@ -0,0 +1,132 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+
+#ifndef mozilla__ipdltest_TestEndpointBridgeMain_h
+#define mozilla__ipdltest_TestEndpointBridgeMain_h 1
+
+#include "mozilla/_ipdltest/IPDLUnitTests.h"
+
+#include "mozilla/_ipdltest/PTestEndpointBridgeMainParent.h"
+#include "mozilla/_ipdltest/PTestEndpointBridgeMainChild.h"
+
+#include "mozilla/_ipdltest/PTestEndpointBridgeSubParent.h"
+#include "mozilla/_ipdltest/PTestEndpointBridgeSubChild.h"
+
+#include "mozilla/_ipdltest/PTestEndpointBridgeMainSubParent.h"
+#include "mozilla/_ipdltest/PTestEndpointBridgeMainSubChild.h"
+
+namespace mozilla {
+namespace _ipdltest {
+
+//-----------------------------------------------------------------------------
+// "Main" process
+//
+class TestEndpointBridgeMainParent : public PTestEndpointBridgeMainParent {
+ friend class PTestEndpointBridgeMainParent;
+
+ public:
+ TestEndpointBridgeMainParent() {}
+ virtual ~TestEndpointBridgeMainParent() {}
+
+ static bool RunTestInProcesses() { return true; }
+ static bool RunTestInThreads() { return false; }
+
+ void Main();
+
+ protected:
+ mozilla::ipc::IPCResult RecvBridged(
+ mozilla::ipc::Endpoint<PTestEndpointBridgeMainSubParent>&& endpoint);
+
+ virtual void ActorDestroy(ActorDestroyReason why) override;
+};
+
+class TestEndpointBridgeMainSubParent
+ : public PTestEndpointBridgeMainSubParent {
+ friend class PTestEndpointBridgeMainSubParent;
+
+ public:
+ explicit TestEndpointBridgeMainSubParent() {}
+ virtual ~TestEndpointBridgeMainSubParent() {}
+
+ protected:
+ mozilla::ipc::IPCResult RecvHello();
+ mozilla::ipc::IPCResult RecvHelloSync();
+ mozilla::ipc::IPCResult AnswerHelloRpc();
+
+ virtual void ActorDestroy(ActorDestroyReason why) override;
+};
+
+//-----------------------------------------------------------------------------
+// "Sub" process --- child of "main"
+//
+class TestEndpointBridgeSubParent;
+
+class TestEndpointBridgeMainChild : public PTestEndpointBridgeMainChild {
+ friend class PTestEndpointBridgeMainChild;
+
+ public:
+ TestEndpointBridgeMainChild();
+ virtual ~TestEndpointBridgeMainChild() {}
+
+ protected:
+ mozilla::ipc::IPCResult RecvStart();
+
+ virtual void ActorDestroy(ActorDestroyReason why) override;
+
+ IPDLUnitTestSubprocess* mSubprocess;
+};
+
+class TestEndpointBridgeSubParent : public PTestEndpointBridgeSubParent {
+ friend class PTestEndpointBridgeSubParent;
+
+ public:
+ TestEndpointBridgeSubParent() {}
+ virtual ~TestEndpointBridgeSubParent() {}
+
+ void Main();
+
+ protected:
+ mozilla::ipc::IPCResult RecvBridgeEm();
+
+ virtual void ActorDestroy(ActorDestroyReason why) override;
+};
+
+//-----------------------------------------------------------------------------
+// "Subsub" process --- child of "sub"
+//
+class TestEndpointBridgeSubChild : public PTestEndpointBridgeSubChild {
+ friend class PTestEndpointBridgeSubChild;
+
+ public:
+ TestEndpointBridgeSubChild();
+ virtual ~TestEndpointBridgeSubChild() {}
+
+ protected:
+ mozilla::ipc::IPCResult RecvPing();
+
+ mozilla::ipc::IPCResult RecvBridged(
+ Endpoint<PTestEndpointBridgeMainSubChild>&& endpoint);
+
+ virtual void ActorDestroy(ActorDestroyReason why) override;
+};
+
+class TestEndpointBridgeMainSubChild : public PTestEndpointBridgeMainSubChild {
+ friend class PTestEndpointBridgeMainSubChild;
+
+ public:
+ explicit TestEndpointBridgeMainSubChild() : mGotHi(false) {}
+ virtual ~TestEndpointBridgeMainSubChild() {}
+
+ protected:
+ mozilla::ipc::IPCResult RecvHi();
+ mozilla::ipc::IPCResult AnswerHiRpc();
+
+ virtual void ActorDestroy(ActorDestroyReason why) override;
+
+ bool mGotHi;
+};
+
+} // namespace _ipdltest
+} // namespace mozilla
+
+#endif // ifndef mozilla__ipdltest_TestEndpointBridgeMain_h
diff --git a/ipc/ipdl/test/cxx/TestEndpointOpens.cpp b/ipc/ipdl/test/cxx/TestEndpointOpens.cpp
new file mode 100644
index 0000000000..ca141f7b58
--- /dev/null
+++ b/ipc/ipdl/test/cxx/TestEndpointOpens.cpp
@@ -0,0 +1,242 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+
+#include "base/task.h"
+#include "base/thread.h"
+
+#include "TestEndpointOpens.h"
+
+#include "IPDLUnitTests.h" // fail etc.
+
+using namespace mozilla::ipc;
+
+using base::ProcessHandle;
+using base::Thread;
+
+namespace mozilla {
+// NB: this is generally bad style, but I am lazy.
+using namespace _ipdltest;
+using namespace _ipdltest2;
+
+static MessageLoop* gMainThread;
+
+static void AssertNotMainThread() {
+ if (!gMainThread) {
+ fail("gMainThread is not initialized");
+ }
+ if (MessageLoop::current() == gMainThread) {
+ fail("unexpectedly called on the main thread");
+ }
+}
+
+//-----------------------------------------------------------------------------
+// parent
+
+// Thread on which TestEndpointOpensOpenedParent runs
+static Thread* gParentThread;
+
+void TestEndpointOpensParent::Main() {
+ if (!SendStart()) {
+ fail("sending Start");
+ }
+}
+
+static void OpenParent(TestEndpointOpensOpenedParent* aParent,
+ Endpoint<PTestEndpointOpensOpenedParent>&& aEndpoint) {
+ AssertNotMainThread();
+
+ // 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.
+ if (!aEndpoint.Bind(aParent)) {
+ fail("binding Parent");
+ }
+}
+
+mozilla::ipc::IPCResult TestEndpointOpensParent::RecvStartSubprotocol(
+ mozilla::ipc::Endpoint<PTestEndpointOpensOpenedParent>&& endpoint) {
+ gMainThread = MessageLoop::current();
+
+ gParentThread = new Thread("ParentThread");
+ if (!gParentThread->Start()) {
+ fail("starting parent thread");
+ }
+
+ TestEndpointOpensOpenedParent* a = new TestEndpointOpensOpenedParent();
+ gParentThread->message_loop()->PostTask(
+ NewRunnableFunction("OpenParent", OpenParent, a, std::move(endpoint)));
+
+ return IPC_OK();
+}
+
+void TestEndpointOpensParent::ActorDestroy(ActorDestroyReason why) {
+ // Stops the thread and joins it
+ delete gParentThread;
+
+ if (NormalShutdown != why) {
+ fail("unexpected destruction A!");
+ }
+ passed("ok");
+ QuitParent();
+}
+
+mozilla::ipc::IPCResult TestEndpointOpensOpenedParent::RecvHello() {
+ AssertNotMainThread();
+ if (!SendHi()) {
+ return IPC_FAIL_NO_REASON(this);
+ }
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult TestEndpointOpensOpenedParent::RecvHelloSync() {
+ AssertNotMainThread();
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult TestEndpointOpensOpenedParent::AnswerHelloRpc() {
+ AssertNotMainThread();
+ if (!CallHiRpc()) {
+ return IPC_FAIL_NO_REASON(this);
+ }
+ return IPC_OK();
+}
+
+static void ShutdownTestEndpointOpensOpenedParent(
+ TestEndpointOpensOpenedParent* parent, Transport* transport) {
+ delete parent;
+}
+
+void TestEndpointOpensOpenedParent::ActorDestroy(ActorDestroyReason why) {
+ AssertNotMainThread();
+
+ if (NormalShutdown != why) {
+ fail("unexpected destruction B!");
+ }
+
+ // ActorDestroy() is just a callback from IPDL-generated code,
+ // which needs the top-level actor (this) to stay alive a little
+ // longer so other things can be cleaned up.
+ gParentThread->message_loop()->PostTask(NewRunnableFunction(
+ "ShutdownTestEndpointOpensOpenedParent",
+ ShutdownTestEndpointOpensOpenedParent, this, GetTransport()));
+}
+
+//-----------------------------------------------------------------------------
+// child
+
+static TestEndpointOpensChild* gOpensChild;
+// Thread on which TestEndpointOpensOpenedChild runs
+static Thread* gChildThread;
+
+TestEndpointOpensChild::TestEndpointOpensChild() { gOpensChild = this; }
+
+static void OpenChild(TestEndpointOpensOpenedChild* aChild,
+ Endpoint<PTestEndpointOpensOpenedChild>&& endpoint) {
+ AssertNotMainThread();
+
+ // 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.
+ if (!endpoint.Bind(aChild)) {
+ fail("binding child endpoint");
+ }
+
+ // Kick off the unit tests
+ if (!aChild->SendHello()) {
+ fail("sending Hello");
+ }
+}
+
+mozilla::ipc::IPCResult TestEndpointOpensChild::RecvStart() {
+ Endpoint<PTestEndpointOpensOpenedParent> parent;
+ Endpoint<PTestEndpointOpensOpenedChild> child;
+ nsresult rv;
+ rv = PTestEndpointOpensOpened::CreateEndpoints(
+ OtherPid(), base::GetCurrentProcId(), &parent, &child);
+ if (NS_FAILED(rv)) {
+ fail("opening PTestEndpointOpensOpened");
+ }
+
+ gMainThread = MessageLoop::current();
+
+ gChildThread = new Thread("ChildThread");
+ if (!gChildThread->Start()) {
+ fail("starting child thread");
+ }
+
+ TestEndpointOpensOpenedChild* a = new TestEndpointOpensOpenedChild();
+ gChildThread->message_loop()->PostTask(
+ NewRunnableFunction("OpenChild", OpenChild, a, std::move(child)));
+
+ if (!SendStartSubprotocol(std::move(parent))) {
+ fail("send StartSubprotocol");
+ }
+
+ return IPC_OK();
+}
+
+void TestEndpointOpensChild::ActorDestroy(ActorDestroyReason why) {
+ // Stops the thread and joins it
+ delete gChildThread;
+
+ if (NormalShutdown != why) {
+ fail("unexpected destruction C!");
+ }
+ QuitChild();
+}
+
+mozilla::ipc::IPCResult TestEndpointOpensOpenedChild::RecvHi() {
+ AssertNotMainThread();
+
+ if (!SendHelloSync()) {
+ fail("sending HelloSync");
+ }
+ if (!CallHelloRpc()) {
+ fail("calling HelloRpc");
+ }
+ if (!mGotHi) {
+ fail("didn't answer HiRpc");
+ }
+
+ // Need to close the channel without message-processing frames on
+ // the C++ stack
+ MessageLoop::current()->PostTask(
+ NewNonOwningRunnableMethod("ipc::IToplevelProtocol::Close", this,
+ &TestEndpointOpensOpenedChild::Close));
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult TestEndpointOpensOpenedChild::AnswerHiRpc() {
+ AssertNotMainThread();
+
+ mGotHi = true; // d00d
+ return IPC_OK();
+}
+
+static void ShutdownTestEndpointOpensOpenedChild(
+ TestEndpointOpensOpenedChild* child, Transport* transport) {
+ delete child;
+
+ // Kick off main-thread shutdown.
+ gMainThread->PostTask(
+ NewNonOwningRunnableMethod("ipc::IToplevelProtocol::Close", gOpensChild,
+ &TestEndpointOpensChild::Close));
+}
+
+void TestEndpointOpensOpenedChild::ActorDestroy(ActorDestroyReason why) {
+ AssertNotMainThread();
+
+ if (NormalShutdown != why) {
+ fail("unexpected destruction D!");
+ }
+
+ // ActorDestroy() is just a callback from IPDL-generated code,
+ // which needs the top-level actor (this) to stay alive a little
+ // longer so other things can be cleaned up. Defer shutdown to
+ // let cleanup finish.
+ gChildThread->message_loop()->PostTask(NewRunnableFunction(
+ "ShutdownTestEndpointOpensOpenedChild",
+ ShutdownTestEndpointOpensOpenedChild, this, GetTransport()));
+}
+
+} // namespace mozilla
diff --git a/ipc/ipdl/test/cxx/TestEndpointOpens.h b/ipc/ipdl/test/cxx/TestEndpointOpens.h
new file mode 100644
index 0000000000..6721274937
--- /dev/null
+++ b/ipc/ipdl/test/cxx/TestEndpointOpens.h
@@ -0,0 +1,102 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+
+#ifndef mozilla__ipdltest_TestEndpointOpens_h
+#define mozilla__ipdltest_TestEndpointOpens_h 1
+
+#include "mozilla/_ipdltest/IPDLUnitTests.h"
+
+#include "mozilla/_ipdltest/PTestEndpointOpensParent.h"
+#include "mozilla/_ipdltest/PTestEndpointOpensChild.h"
+
+#include "mozilla/_ipdltest2/PTestEndpointOpensOpenedParent.h"
+#include "mozilla/_ipdltest2/PTestEndpointOpensOpenedChild.h"
+
+namespace mozilla {
+
+// parent process
+
+namespace _ipdltest {
+
+class TestEndpointOpensParent : public PTestEndpointOpensParent {
+ friend class PTestEndpointOpensParent;
+
+ public:
+ TestEndpointOpensParent() {}
+ virtual ~TestEndpointOpensParent() {}
+
+ static bool RunTestInProcesses() { return true; }
+ static bool RunTestInThreads() { return false; }
+
+ void Main();
+
+ protected:
+ mozilla::ipc::IPCResult RecvStartSubprotocol(
+ mozilla::ipc::Endpoint<PTestEndpointOpensOpenedParent>&& endpoint);
+
+ virtual void ActorDestroy(ActorDestroyReason why) override;
+};
+
+} // namespace _ipdltest
+
+namespace _ipdltest2 {
+
+class TestEndpointOpensOpenedParent : public PTestEndpointOpensOpenedParent {
+ friend class PTestEndpointOpensOpenedParent;
+
+ public:
+ explicit TestEndpointOpensOpenedParent() {}
+ virtual ~TestEndpointOpensOpenedParent() {}
+
+ protected:
+ mozilla::ipc::IPCResult RecvHello();
+ mozilla::ipc::IPCResult RecvHelloSync();
+ mozilla::ipc::IPCResult AnswerHelloRpc();
+
+ virtual void ActorDestroy(ActorDestroyReason why) override;
+};
+
+} // namespace _ipdltest2
+
+// child process
+
+namespace _ipdltest {
+
+class TestEndpointOpensChild : public PTestEndpointOpensChild {
+ friend class PTestEndpointOpensChild;
+
+ public:
+ TestEndpointOpensChild();
+ virtual ~TestEndpointOpensChild() {}
+
+ protected:
+ mozilla::ipc::IPCResult RecvStart();
+
+ virtual void ActorDestroy(ActorDestroyReason why) override;
+};
+
+} // namespace _ipdltest
+
+namespace _ipdltest2 {
+
+class TestEndpointOpensOpenedChild : public PTestEndpointOpensOpenedChild {
+ friend class PTestEndpointOpensOpenedChild;
+
+ public:
+ explicit TestEndpointOpensOpenedChild() : mGotHi(false) {}
+ virtual ~TestEndpointOpensOpenedChild() {}
+
+ protected:
+ mozilla::ipc::IPCResult RecvHi();
+ mozilla::ipc::IPCResult AnswerHiRpc();
+
+ virtual void ActorDestroy(ActorDestroyReason why) override;
+
+ bool mGotHi;
+};
+
+} // namespace _ipdltest2
+
+} // namespace mozilla
+
+#endif // ifndef mozilla__ipdltest_TestEndpointOpens_h
diff --git a/ipc/ipdl/test/cxx/TestFailedCtor.cpp b/ipc/ipdl/test/cxx/TestFailedCtor.cpp
new file mode 100644
index 0000000000..2f08d2eeb0
--- /dev/null
+++ b/ipc/ipdl/test/cxx/TestFailedCtor.cpp
@@ -0,0 +1,112 @@
+#include "TestFailedCtor.h"
+
+#include "IPDLUnitTests.h" // fail etc.
+
+namespace mozilla {
+namespace _ipdltest {
+
+//-----------------------------------------------------------------------------
+// parent
+void TestFailedCtorParent::Main() {
+ PTestFailedCtorSubParent* p = CallPTestFailedCtorSubConstructor();
+ if (p) fail("expected ctor to fail");
+
+ Close();
+}
+
+PTestFailedCtorSubParent*
+TestFailedCtorParent::AllocPTestFailedCtorSubParent() {
+ return new TestFailedCtorSubParent();
+}
+bool TestFailedCtorParent::DeallocPTestFailedCtorSubParent(
+ PTestFailedCtorSubParent* actor) {
+ delete actor;
+ return true;
+}
+
+PTestFailedCtorSubsubParent*
+TestFailedCtorSubParent::AllocPTestFailedCtorSubsubParent() {
+ TestFailedCtorSubsub* a = new TestFailedCtorSubsub();
+ if (!mOne) {
+ return mOne = a;
+ } else if (!mTwo) {
+ return mTwo = a;
+ } else if (!mThree) {
+ return mThree = a;
+ } else {
+ fail("unexpected Alloc()");
+ return nullptr;
+ }
+}
+bool TestFailedCtorSubParent::DeallocPTestFailedCtorSubsubParent(
+ PTestFailedCtorSubsubParent* actor) {
+ static_cast<TestFailedCtorSubsub*>(actor)->mDealloced = true;
+ return true;
+}
+
+void TestFailedCtorSubParent::ActorDestroy(ActorDestroyReason why) {
+ if (mOne->mWhy != Deletion) fail("Subsub one got wrong ActorDestroyReason");
+ if (mTwo->mWhy != AncestorDeletion)
+ fail("Subsub two got wrong ActorDestroyReason");
+ if (mThree->mWhy != AncestorDeletion)
+ fail("Subsub three got wrong ActorDestroyReason");
+
+ if (FailedConstructor != why) fail("unexpected destruction!");
+}
+
+TestFailedCtorSubParent::~TestFailedCtorSubParent() {
+ if (!(mOne->mDealloced && mTwo->mDealloced && mThree->mDealloced))
+ fail("Not all subsubs were Dealloc'd");
+ delete mOne;
+ delete mTwo;
+ delete mThree;
+}
+
+//-----------------------------------------------------------------------------
+// child
+
+PTestFailedCtorSubChild* TestFailedCtorChild::AllocPTestFailedCtorSubChild() {
+ return new TestFailedCtorSubChild();
+}
+
+mozilla::ipc::IPCResult
+TestFailedCtorChild::AnswerPTestFailedCtorSubConstructor(
+ PTestFailedCtorSubChild* actor) {
+ PTestFailedCtorSubsubChild* c1 =
+ actor->SendPTestFailedCtorSubsubConstructor();
+ PTestFailedCtorSubsubChild::Send__delete__(c1);
+
+ if (!actor->SendPTestFailedCtorSubsubConstructor() ||
+ !actor->SendPTestFailedCtorSubsubConstructor() || !actor->SendSync())
+ fail("setting up test");
+
+ // This causes our process to die
+ return IPC_FAIL_NO_REASON(this);
+}
+
+bool TestFailedCtorChild::DeallocPTestFailedCtorSubChild(
+ PTestFailedCtorSubChild* actor) {
+ delete actor;
+ return true;
+}
+
+void TestFailedCtorChild::ProcessingError(Result aCode, const char* aReason) {
+ if (OtherPid() != base::GetCurrentProcId()) // thread-mode
+ _exit(0);
+}
+
+PTestFailedCtorSubsubChild*
+TestFailedCtorSubChild::AllocPTestFailedCtorSubsubChild() {
+ return new TestFailedCtorSubsub();
+}
+
+bool TestFailedCtorSubChild::DeallocPTestFailedCtorSubsubChild(
+ PTestFailedCtorSubsubChild* actor) {
+ delete actor;
+ return true;
+}
+
+void TestFailedCtorSubChild::ActorDestroy(ActorDestroyReason why) {}
+
+} // namespace _ipdltest
+} // namespace mozilla
diff --git a/ipc/ipdl/test/cxx/TestFailedCtor.h b/ipc/ipdl/test/cxx/TestFailedCtor.h
new file mode 100644
index 0000000000..6fac4eb278
--- /dev/null
+++ b/ipc/ipdl/test/cxx/TestFailedCtor.h
@@ -0,0 +1,127 @@
+#ifndef mozilla_ipdltest_TestFailedCtor_h
+#define mozilla_ipdltest_TestFailedCtor_h
+
+#include "mozilla/_ipdltest/IPDLUnitTests.h"
+
+#include "mozilla/_ipdltest/PTestFailedCtorParent.h"
+#include "mozilla/_ipdltest/PTestFailedCtorChild.h"
+
+#include "mozilla/_ipdltest/PTestFailedCtorSubParent.h"
+#include "mozilla/_ipdltest/PTestFailedCtorSubChild.h"
+
+#include "mozilla/_ipdltest/PTestFailedCtorSubsubParent.h"
+#include "mozilla/_ipdltest/PTestFailedCtorSubsubChild.h"
+
+namespace mozilla {
+namespace _ipdltest {
+
+//-----------------------------------------------------------------------------
+// Top-level
+//
+class TestFailedCtorParent : public PTestFailedCtorParent {
+ friend class PTestFailedCtorParent;
+
+ public:
+ TestFailedCtorParent() {}
+ virtual ~TestFailedCtorParent() {}
+
+ static bool RunTestInProcesses() { return true; }
+
+ // FIXME/bug 703322 Disabled because child calls exit() to end
+ // test, not clear how to handle failed ctor in
+ // threaded mode.
+ static bool RunTestInThreads() { return false; }
+
+ void Main();
+
+ protected:
+ PTestFailedCtorSubParent* AllocPTestFailedCtorSubParent();
+ bool DeallocPTestFailedCtorSubParent(PTestFailedCtorSubParent* actor);
+
+ virtual void ActorDestroy(ActorDestroyReason why) override {
+ if (AbnormalShutdown != why) fail("unexpected destruction!");
+ passed("ok");
+ QuitParent();
+ }
+};
+
+class TestFailedCtorChild : public PTestFailedCtorChild {
+ friend class PTestFailedCtorChild;
+
+ public:
+ TestFailedCtorChild() {}
+ virtual ~TestFailedCtorChild() {}
+
+ protected:
+ PTestFailedCtorSubChild* AllocPTestFailedCtorSubChild();
+
+ mozilla::ipc::IPCResult AnswerPTestFailedCtorSubConstructor(
+ PTestFailedCtorSubChild* actor) override;
+
+ bool DeallocPTestFailedCtorSubChild(PTestFailedCtorSubChild* actor);
+
+ virtual void ProcessingError(Result aCode, const char* aReason) override;
+
+ virtual void ActorDestroy(ActorDestroyReason why) override {
+ fail("should have _exit()ed");
+ }
+};
+
+//-----------------------------------------------------------------------------
+// First descendent
+//
+class TestFailedCtorSubsub;
+
+class TestFailedCtorSubParent : public PTestFailedCtorSubParent {
+ friend class PTestFailedCtorSubParent;
+
+ public:
+ TestFailedCtorSubParent() : mOne(nullptr), mTwo(nullptr), mThree(nullptr) {}
+ virtual ~TestFailedCtorSubParent();
+
+ protected:
+ PTestFailedCtorSubsubParent* AllocPTestFailedCtorSubsubParent();
+
+ bool DeallocPTestFailedCtorSubsubParent(PTestFailedCtorSubsubParent* actor);
+ mozilla::ipc::IPCResult RecvSync() { return IPC_OK(); }
+
+ virtual void ActorDestroy(ActorDestroyReason why) override;
+
+ TestFailedCtorSubsub* mOne;
+ TestFailedCtorSubsub* mTwo;
+ TestFailedCtorSubsub* mThree;
+};
+
+class TestFailedCtorSubChild : public PTestFailedCtorSubChild {
+ friend class PTestFailedCtorSubChild;
+
+ public:
+ TestFailedCtorSubChild() {}
+ virtual ~TestFailedCtorSubChild() {}
+
+ protected:
+ PTestFailedCtorSubsubChild* AllocPTestFailedCtorSubsubChild();
+ bool DeallocPTestFailedCtorSubsubChild(PTestFailedCtorSubsubChild* actor);
+
+ virtual void ActorDestroy(ActorDestroyReason why) override;
+};
+
+//-----------------------------------------------------------------------------
+// Grand-descendent
+//
+class TestFailedCtorSubsub : public PTestFailedCtorSubsubParent,
+ public PTestFailedCtorSubsubChild {
+ public:
+ TestFailedCtorSubsub() : mWhy(ActorDestroyReason(-1)), mDealloced(false) {}
+ virtual ~TestFailedCtorSubsub() {}
+
+ virtual void ActorDestroy(ActorDestroyReason why) override { mWhy = why; }
+
+ ActorDestroyReason mWhy;
+ bool mDealloced;
+};
+
+} // namespace _ipdltest
+} // namespace mozilla
+
+#endif // ifndef mozilla_ipdltest_TestFailedCtor_h
diff --git a/ipc/ipdl/test/cxx/TestHangs.cpp b/ipc/ipdl/test/cxx/TestHangs.cpp
new file mode 100644
index 0000000000..2694cbfdab
--- /dev/null
+++ b/ipc/ipdl/test/cxx/TestHangs.cpp
@@ -0,0 +1,127 @@
+#include "base/process_util.h"
+
+#include "TestHangs.h"
+
+#include "IPDLUnitTests.h" // fail etc.
+
+using base::KillProcess;
+
+namespace mozilla {
+namespace _ipdltest {
+
+//-----------------------------------------------------------------------------
+// parent
+
+TestHangsParent::TestHangsParent()
+ : mDetectedHang(false), mNumAnswerStackFrame(0) {
+ MOZ_COUNT_CTOR(TestHangsParent);
+}
+
+TestHangsParent::~TestHangsParent() { MOZ_COUNT_DTOR(TestHangsParent); }
+
+void TestHangsParent::Main() {
+ // Here we try to set things up to test the following sequence of events:
+ //
+ // - subprocess causes an OnMaybeDequeueOne() task to be posted to
+ // this thread
+ //
+ // - subprocess hangs just long enough for the hang timer to expire
+ //
+ // - hang-kill code in the parent starts running
+ //
+ // - subprocess replies to message while hang code runs
+ //
+ // - reply is processed in OnMaybeDequeueOne() before Close() has
+ // been called or the channel error notification has been posted
+
+ // this tells the subprocess to send us Nonce()
+ if (!SendStart()) fail("sending Start");
+
+ // now we sleep here for a while awaiting the Nonce() message from
+ // the child. since we're not blocked on anything, the IO thread
+ // will enqueue an OnMaybeDequeueOne() task to process that
+ // message
+ //
+ // NB: PR_Sleep is exactly what we want, only the current thread
+ // sleeping
+ PR_Sleep(5000);
+
+ // when we call into this, we'll pull the Nonce() message out of
+ // the mPending queue, but that doesn't matter ... the
+ // OnMaybeDequeueOne() event will remain
+ if (CallStackFrame() && mDetectedHang) fail("should have timed out!");
+
+ // the Close() task in the queue will shut us down
+}
+
+bool TestHangsParent::ShouldContinueFromReplyTimeout() {
+ mDetectedHang = true;
+
+ // so we've detected a timeout after 2 ms ... now we cheat and
+ // sleep for a long time, to allow the subprocess's reply to come
+ // in
+
+ PR_Sleep(5000);
+
+ // reply should be here; we'll post a task to shut things down.
+ // This must be after OnMaybeDequeueOne() in the event queue.
+ MessageLoop::current()->PostTask(NewNonOwningRunnableMethod(
+ "_ipdltest::TestHangsParent::CleanUp", this, &TestHangsParent::CleanUp));
+
+ GetIPCChannel()->CloseWithTimeout();
+
+ return false;
+}
+
+mozilla::ipc::IPCResult TestHangsParent::AnswerStackFrame() {
+ ++mNumAnswerStackFrame;
+
+ if (mNumAnswerStackFrame == 1) {
+ if (CallStackFrame()) {
+ fail("should have timed out!");
+ }
+ } else if (mNumAnswerStackFrame == 2) {
+ // minimum possible, 2 ms. We want to detecting a hang to race
+ // with the reply coming in, as reliably as possible
+ SetReplyTimeoutMs(2);
+
+ if (CallHang()) fail("should have timed out!");
+ } else {
+ fail("unexpected state");
+ }
+
+ return IPC_OK();
+}
+
+void TestHangsParent::CleanUp() {
+ ipc::ScopedProcessHandle otherProcessHandle;
+ if (!base::OpenProcessHandle(OtherPid(), &otherProcessHandle.rwget())) {
+ fail("couldn't open child process");
+ } else {
+ if (!KillProcess(otherProcessHandle, 0, false)) {
+ fail("terminating child process");
+ }
+ }
+ Close();
+}
+
+//-----------------------------------------------------------------------------
+// child
+
+TestHangsChild::TestHangsChild() { MOZ_COUNT_CTOR(TestHangsChild); }
+
+TestHangsChild::~TestHangsChild() { MOZ_COUNT_DTOR(TestHangsChild); }
+
+mozilla::ipc::IPCResult TestHangsChild::AnswerHang() {
+ puts(" (child process is 'hanging' now)");
+
+ // just sleep until we're reasonably confident the 1ms hang
+ // detector fired in the parent process and it's sleeping in
+ // ShouldContinueFromReplyTimeout()
+ PR_Sleep(1000);
+
+ return IPC_OK();
+}
+
+} // namespace _ipdltest
+} // namespace mozilla
diff --git a/ipc/ipdl/test/cxx/TestHangs.h b/ipc/ipdl/test/cxx/TestHangs.h
new file mode 100644
index 0000000000..a3dfb991f5
--- /dev/null
+++ b/ipc/ipdl/test/cxx/TestHangs.h
@@ -0,0 +1,75 @@
+#ifndef mozilla__ipdltest_TestHangs_h
+#define mozilla__ipdltest_TestHangs_h 1
+
+#include "mozilla/_ipdltest/IPDLUnitTests.h"
+
+#include "mozilla/_ipdltest/PTestHangsParent.h"
+#include "mozilla/_ipdltest/PTestHangsChild.h"
+
+namespace mozilla {
+namespace _ipdltest {
+
+class TestHangsParent : public PTestHangsParent {
+ friend class PTestHangsParent;
+
+ public:
+ TestHangsParent();
+ virtual ~TestHangsParent();
+
+ static bool RunTestInProcesses() { return true; }
+
+ // FIXME/bug 703320 Disabled because parent kills child proc, not
+ // clear how that should work in threads.
+ static bool RunTestInThreads() { return false; }
+
+ void Main();
+
+ protected:
+ virtual bool ShouldContinueFromReplyTimeout() override;
+
+ mozilla::ipc::IPCResult RecvNonce() { return IPC_OK(); }
+
+ mozilla::ipc::IPCResult AnswerStackFrame();
+
+ virtual void ActorDestroy(ActorDestroyReason why) override {
+ if (AbnormalShutdown != why) fail("unexpected destruction!");
+ passed("ok");
+ QuitParent();
+ }
+
+ void CleanUp();
+
+ bool mDetectedHang;
+ int32_t mNumAnswerStackFrame;
+};
+
+class TestHangsChild : public PTestHangsChild {
+ friend class PTestHangsChild;
+
+ public:
+ TestHangsChild();
+ virtual ~TestHangsChild();
+
+ protected:
+ mozilla::ipc::IPCResult RecvStart() {
+ if (!SendNonce()) fail("sending Nonce");
+ return IPC_OK();
+ }
+
+ mozilla::ipc::IPCResult AnswerStackFrame() {
+ if (CallStackFrame()) fail("should have failed");
+ return IPC_OK();
+ }
+
+ mozilla::ipc::IPCResult AnswerHang();
+
+ virtual void ActorDestroy(ActorDestroyReason why) override {
+ if (AbnormalShutdown != why) fail("unexpected destruction!");
+ QuitChild();
+ }
+};
+
+} // namespace _ipdltest
+} // namespace mozilla
+
+#endif // ifndef mozilla__ipdltest_TestHangs_h
diff --git a/ipc/ipdl/test/cxx/TestHighestPrio.cpp b/ipc/ipdl/test/cxx/TestHighestPrio.cpp
new file mode 100644
index 0000000000..499c352a5a
--- /dev/null
+++ b/ipc/ipdl/test/cxx/TestHighestPrio.cpp
@@ -0,0 +1,91 @@
+/* -*- 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/. */
+
+#include "TestHighestPrio.h"
+
+#include "IPDLUnitTests.h" // fail etc.
+#if defined(XP_UNIX)
+# include <unistd.h>
+#else
+# include <windows.h>
+#endif
+
+namespace mozilla {
+namespace _ipdltest {
+
+//-----------------------------------------------------------------------------
+// parent
+
+TestHighestPrioParent::TestHighestPrioParent() : msg_num_(0) {
+ MOZ_COUNT_CTOR(TestHighestPrioParent);
+}
+
+TestHighestPrioParent::~TestHighestPrioParent() {
+ MOZ_COUNT_DTOR(TestHighestPrioParent);
+}
+
+void TestHighestPrioParent::Main() {
+ if (!SendStart()) fail("sending Start");
+}
+
+mozilla::ipc::IPCResult TestHighestPrioParent::RecvMsg1() {
+ MOZ_ASSERT(msg_num_ == 0);
+ msg_num_ = 1;
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult TestHighestPrioParent::RecvMsg2() {
+ MOZ_ASSERT(msg_num_ == 1);
+ msg_num_ = 2;
+
+ if (!SendStartInner()) fail("sending StartInner");
+
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult TestHighestPrioParent::RecvMsg3() {
+ MOZ_ASSERT(msg_num_ == 2);
+ msg_num_ = 3;
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult TestHighestPrioParent::RecvMsg4() {
+ MOZ_ASSERT(msg_num_ == 3);
+ msg_num_ = 4;
+ return IPC_OK();
+}
+
+//-----------------------------------------------------------------------------
+// child
+
+TestHighestPrioChild::TestHighestPrioChild() {
+ MOZ_COUNT_CTOR(TestHighestPrioChild);
+}
+
+TestHighestPrioChild::~TestHighestPrioChild() {
+ MOZ_COUNT_DTOR(TestHighestPrioChild);
+}
+
+mozilla::ipc::IPCResult TestHighestPrioChild::RecvStart() {
+ if (!SendMsg1()) fail("sending Msg1");
+
+ if (!SendMsg2()) fail("sending Msg2");
+
+ Close();
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult TestHighestPrioChild::RecvStartInner() {
+ if (!SendMsg3()) fail("sending Msg3");
+
+ if (!SendMsg4()) fail("sending Msg4");
+
+ return IPC_OK();
+}
+
+} // namespace _ipdltest
+} // namespace mozilla
diff --git a/ipc/ipdl/test/cxx/TestHighestPrio.h b/ipc/ipdl/test/cxx/TestHighestPrio.h
new file mode 100644
index 0000000000..34563d7708
--- /dev/null
+++ b/ipc/ipdl/test/cxx/TestHighestPrio.h
@@ -0,0 +1,55 @@
+#ifndef mozilla__ipdltest_TestHighestPrio_h
+#define mozilla__ipdltest_TestHighestPrio_h 1
+
+#include "mozilla/_ipdltest/IPDLUnitTests.h"
+
+#include "mozilla/_ipdltest/PTestHighestPrioParent.h"
+#include "mozilla/_ipdltest/PTestHighestPrioChild.h"
+
+namespace mozilla {
+namespace _ipdltest {
+
+class TestHighestPrioParent : public PTestHighestPrioParent {
+ public:
+ TestHighestPrioParent();
+ virtual ~TestHighestPrioParent();
+
+ static bool RunTestInProcesses() { return true; }
+ static bool RunTestInThreads() { return false; }
+
+ void Main();
+
+ mozilla::ipc::IPCResult RecvMsg1();
+ mozilla::ipc::IPCResult RecvMsg2();
+ mozilla::ipc::IPCResult RecvMsg3();
+ mozilla::ipc::IPCResult RecvMsg4();
+
+ virtual void ActorDestroy(ActorDestroyReason why) override {
+ if (NormalShutdown != why) fail("unexpected destruction!");
+ if (msg_num_ != 4) fail("missed IPC call");
+ passed("ok");
+ QuitParent();
+ }
+
+ private:
+ int msg_num_;
+};
+
+class TestHighestPrioChild : public PTestHighestPrioChild {
+ public:
+ TestHighestPrioChild();
+ virtual ~TestHighestPrioChild();
+
+ mozilla::ipc::IPCResult RecvStart();
+ mozilla::ipc::IPCResult RecvStartInner();
+
+ virtual void ActorDestroy(ActorDestroyReason why) override {
+ if (NormalShutdown != why) fail("unexpected destruction!");
+ QuitChild();
+ }
+};
+
+} // namespace _ipdltest
+} // namespace mozilla
+
+#endif // ifndef mozilla__ipdltest_TestHighestPrio_h
diff --git a/ipc/ipdl/test/cxx/TestInterruptErrorCleanup.cpp b/ipc/ipdl/test/cxx/TestInterruptErrorCleanup.cpp
new file mode 100644
index 0000000000..3af7ad620d
--- /dev/null
+++ b/ipc/ipdl/test/cxx/TestInterruptErrorCleanup.cpp
@@ -0,0 +1,138 @@
+#include "TestInterruptErrorCleanup.h"
+
+#include "base/task.h"
+#include "mozilla/CondVar.h"
+#include "mozilla/Mutex.h"
+
+#include "IPDLUnitTests.h" // fail etc.
+#include "IPDLUnitTestSubprocess.h"
+
+using mozilla::CondVar;
+using mozilla::Mutex;
+using mozilla::MutexAutoLock;
+
+namespace mozilla {
+namespace _ipdltest {
+
+//-----------------------------------------------------------------------------
+// parent
+
+namespace {
+
+// NB: this test does its own shutdown, rather than going through
+// QuitParent(), because it's testing degenerate edge cases
+
+void DeleteSubprocess(Mutex* mutex, CondVar* cvar) {
+ MutexAutoLock lock(*mutex);
+
+ gSubprocess->Destroy();
+ gSubprocess = nullptr;
+
+ cvar->Notify();
+}
+
+void DeleteTheWorld() {
+ delete static_cast<TestInterruptErrorCleanupParent*>(gParentActor);
+ gParentActor = nullptr;
+
+ // needs to be synchronous to avoid affecting event ordering on
+ // the main thread
+ Mutex mutex MOZ_UNANNOTATED("TestInterruptErrorCleanup.DeleteTheWorld.mutex");
+ CondVar cvar(mutex, "TestInterruptErrorCleanup.DeleteTheWorld.cvar");
+
+ MutexAutoLock lock(mutex);
+
+ XRE_GetIOMessageLoop()->PostTask(
+ NewRunnableFunction("DeleteSubprocess", DeleteSubprocess, &mutex, &cvar));
+
+ cvar.Wait();
+}
+
+void Done() {
+ static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
+ nsCOMPtr<nsIAppShell> appShell(do_GetService(kAppShellCID));
+ appShell->Exit();
+
+ passed(__FILE__);
+}
+
+} // namespace
+
+TestInterruptErrorCleanupParent::TestInterruptErrorCleanupParent()
+ : mGotProcessingError(false) {
+ MOZ_COUNT_CTOR(TestInterruptErrorCleanupParent);
+}
+
+TestInterruptErrorCleanupParent::~TestInterruptErrorCleanupParent() {
+ MOZ_COUNT_DTOR(TestInterruptErrorCleanupParent);
+}
+
+void TestInterruptErrorCleanupParent::Main() {
+ // This test models the following sequence of events
+ //
+ // (1) Parent: Interrupt out-call
+ // (2) Child: crash
+ // --[Parent-only hereafter]--
+ // (3) Interrupt out-call return false
+ // (4) Close()
+ // --[event loop]--
+ // (5) delete parentActor
+ // (6) delete childProcess
+ // --[event loop]--
+ // (7) Channel::OnError notification
+ // --[event loop]--
+ // (8) Done, quit
+ //
+ // See bug 535298 and friends; this seqeunce of events captures
+ // three differnent potential errors
+ // - Close()-after-error (semantic error previously)
+ // - use-after-free of parentActor
+ // - use-after-free of channel
+ //
+ // Because of legacy constraints related to nsNPAPI* code, we need
+ // to ensure that this sequence of events can occur without
+ // errors/crashes.
+
+ MessageLoop::current()->PostTask(
+ NewRunnableFunction("DeleteTheWorld", DeleteTheWorld));
+
+ // it's a failure if this *succeeds*
+ if (CallError()) fail("expected an error!");
+
+ if (!mGotProcessingError) fail("expected a ProcessingError() notification");
+
+ // it's OK to Close() a channel after an error, because nsNPAPI*
+ // wants to do this
+ Close();
+
+ // we know that this event *must* be after the MaybeError
+ // notification enqueued by AsyncChannel, because that event is
+ // enqueued within the same mutex that ends up signaling the
+ // wakeup-on-error of |CallError()| above
+ MessageLoop::current()->PostTask(NewRunnableFunction("Done", Done));
+}
+
+void TestInterruptErrorCleanupParent::ProcessingError(Result aCode,
+ const char* aReason) {
+ if (aCode != MsgDropped) fail("unexpected processing error");
+ mGotProcessingError = true;
+}
+
+//-----------------------------------------------------------------------------
+// child
+
+TestInterruptErrorCleanupChild::TestInterruptErrorCleanupChild() {
+ MOZ_COUNT_CTOR(TestInterruptErrorCleanupChild);
+}
+
+TestInterruptErrorCleanupChild::~TestInterruptErrorCleanupChild() {
+ MOZ_COUNT_DTOR(TestInterruptErrorCleanupChild);
+}
+
+mozilla::ipc::IPCResult TestInterruptErrorCleanupChild::AnswerError() {
+ _exit(0);
+ MOZ_CRASH("unreached");
+}
+
+} // namespace _ipdltest
+} // namespace mozilla
diff --git a/ipc/ipdl/test/cxx/TestInterruptErrorCleanup.h b/ipc/ipdl/test/cxx/TestInterruptErrorCleanup.h
new file mode 100644
index 0000000000..9ae0493cf0
--- /dev/null
+++ b/ipc/ipdl/test/cxx/TestInterruptErrorCleanup.h
@@ -0,0 +1,52 @@
+#ifndef mozilla__ipdltest_TestInterruptErrorCleanup_h
+#define mozilla__ipdltest_TestInterruptErrorCleanup_h 1
+
+#include "mozilla/_ipdltest/IPDLUnitTests.h"
+
+#include "mozilla/_ipdltest/PTestInterruptErrorCleanupParent.h"
+#include "mozilla/_ipdltest/PTestInterruptErrorCleanupChild.h"
+
+namespace mozilla {
+namespace _ipdltest {
+
+class TestInterruptErrorCleanupParent
+ : public PTestInterruptErrorCleanupParent {
+ public:
+ TestInterruptErrorCleanupParent();
+ virtual ~TestInterruptErrorCleanupParent();
+
+ static bool RunTestInProcesses() { return true; }
+ // FIXME/bug 703323 Could work if modified
+ static bool RunTestInThreads() { return false; }
+
+ void Main();
+
+ protected:
+ virtual void ActorDestroy(ActorDestroyReason why) override {
+ if (AbnormalShutdown != why) fail("unexpected destruction!");
+ }
+
+ virtual void ProcessingError(Result aCode, const char* aReason) override;
+
+ bool mGotProcessingError;
+};
+
+class TestInterruptErrorCleanupChild : public PTestInterruptErrorCleanupChild {
+ friend class PTestInterruptErrorCleanupChild;
+
+ public:
+ TestInterruptErrorCleanupChild();
+ virtual ~TestInterruptErrorCleanupChild();
+
+ protected:
+ mozilla::ipc::IPCResult AnswerError();
+
+ virtual void ActorDestroy(ActorDestroyReason why) override {
+ fail("should have 'crashed'!");
+ }
+};
+
+} // namespace _ipdltest
+} // namespace mozilla
+
+#endif // ifndef mozilla__ipdltest_TestInterruptErrorCleanup_h
diff --git a/ipc/ipdl/test/cxx/TestInterruptRaces.cpp b/ipc/ipdl/test/cxx/TestInterruptRaces.cpp
new file mode 100644
index 0000000000..02b42cfbc3
--- /dev/null
+++ b/ipc/ipdl/test/cxx/TestInterruptRaces.cpp
@@ -0,0 +1,169 @@
+#include "TestInterruptRaces.h"
+
+#include "IPDLUnitTests.h" // fail etc.
+
+using mozilla::ipc::MessageChannel;
+
+namespace mozilla {
+namespace _ipdltest {
+
+ipc::RacyInterruptPolicy MediateRace(const MessageChannel::MessageInfo& parent,
+ const MessageChannel::MessageInfo& child) {
+ return (PTestInterruptRaces::Msg_Child__ID == parent.type())
+ ? ipc::RIPParentWins
+ : ipc::RIPChildWins;
+}
+
+//-----------------------------------------------------------------------------
+// parent
+void TestInterruptRacesParent::Main() {
+ if (!SendStart()) fail("sending Start()");
+}
+
+mozilla::ipc::IPCResult TestInterruptRacesParent::RecvStartRace() {
+ MessageLoop::current()->PostTask(NewNonOwningRunnableMethod(
+ "_ipdltest::TestInterruptRacesParent::OnRaceTime", this,
+ &TestInterruptRacesParent::OnRaceTime));
+ return IPC_OK();
+}
+
+void TestInterruptRacesParent::OnRaceTime() {
+ if (!CallRace(&mChildHasReply)) fail("problem calling Race()");
+
+ if (!mChildHasReply) fail("child should have got a reply already");
+
+ mHasReply = true;
+
+ MessageLoop::current()->PostTask(
+ NewNonOwningRunnableMethod("_ipdltest::TestInterruptRacesParent::Test2",
+ this, &TestInterruptRacesParent::Test2));
+}
+
+mozilla::ipc::IPCResult TestInterruptRacesParent::AnswerRace(bool* hasReply) {
+ if (mHasReply) fail("apparently the parent won the Interrupt race!");
+ *hasReply = hasReply;
+ return IPC_OK();
+}
+
+void TestInterruptRacesParent::Test2() {
+ puts(" passed");
+ puts("Test 2");
+
+ mHasReply = false;
+ mChildHasReply = false;
+
+ if (!CallStackFrame()) fail("can't set up a stack frame");
+
+ puts(" passed");
+
+ MessageLoop::current()->PostTask(
+ NewNonOwningRunnableMethod("_ipdltest::TestInterruptRacesParent::Test3",
+ this, &TestInterruptRacesParent::Test3));
+}
+
+mozilla::ipc::IPCResult TestInterruptRacesParent::AnswerStackFrame() {
+ if (!SendWakeup()) fail("can't wake up the child");
+
+ if (!CallRace(&mChildHasReply)) fail("can't set up race condition");
+ mHasReply = true;
+
+ if (!mChildHasReply) fail("child should have got a reply already");
+
+ return IPC_OK();
+}
+
+void TestInterruptRacesParent::Test3() {
+ puts("Test 3");
+
+ if (!CallStackFrame3()) fail("can't set up a stack frame");
+
+ puts(" passed");
+
+ Close();
+}
+
+mozilla::ipc::IPCResult TestInterruptRacesParent::AnswerStackFrame3() {
+ if (!SendWakeup3()) fail("can't wake up the child");
+
+ if (!CallChild()) fail("can't set up race condition");
+
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult TestInterruptRacesParent::AnswerParent() {
+ mAnsweredParent = true;
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult TestInterruptRacesParent::RecvGetAnsweredParent(
+ bool* answeredParent) {
+ *answeredParent = mAnsweredParent;
+ return IPC_OK();
+}
+
+//-----------------------------------------------------------------------------
+// child
+mozilla::ipc::IPCResult TestInterruptRacesChild::RecvStart() {
+ puts("Test 1");
+
+ if (!SendStartRace()) fail("problem sending StartRace()");
+
+ bool dontcare;
+ if (!CallRace(&dontcare)) fail("problem calling Race()");
+
+ mHasReply = true;
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult TestInterruptRacesChild::AnswerRace(bool* hasReply) {
+ if (!mHasReply) fail("apparently the child lost the Interrupt race!");
+
+ *hasReply = mHasReply;
+
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult TestInterruptRacesChild::AnswerStackFrame() {
+ // reset for the second test
+ mHasReply = false;
+
+ if (!CallStackFrame()) fail("can't set up stack frame");
+
+ if (!mHasReply) fail("should have had reply by now");
+
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult TestInterruptRacesChild::RecvWakeup() {
+ bool dontcare;
+ if (!CallRace(&dontcare)) fail("can't set up race condition");
+
+ mHasReply = true;
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult TestInterruptRacesChild::AnswerStackFrame3() {
+ if (!CallStackFrame3()) fail("can't set up stack frame");
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult TestInterruptRacesChild::RecvWakeup3() {
+ if (!CallParent()) fail("can't set up race condition");
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult TestInterruptRacesChild::AnswerChild() {
+ bool parentAnsweredParent;
+ // the parent is supposed to win the race, which means its
+ // message, Child(), is supposed to be processed before the
+ // child's message, Parent()
+ if (!SendGetAnsweredParent(&parentAnsweredParent))
+ fail("sending GetAnsweredParent");
+
+ if (parentAnsweredParent) fail("parent was supposed to win the race!");
+
+ return IPC_OK();
+}
+
+} // namespace _ipdltest
+} // namespace mozilla
diff --git a/ipc/ipdl/test/cxx/TestInterruptRaces.h b/ipc/ipdl/test/cxx/TestInterruptRaces.h
new file mode 100644
index 0000000000..6fa184da1a
--- /dev/null
+++ b/ipc/ipdl/test/cxx/TestInterruptRaces.h
@@ -0,0 +1,104 @@
+#ifndef mozilla__ipdltest_TestInterruptRaces_h
+#define mozilla__ipdltest_TestInterruptRaces_h
+
+#include "mozilla/_ipdltest/IPDLUnitTests.h"
+
+#include "mozilla/_ipdltest/PTestInterruptRacesParent.h"
+#include "mozilla/_ipdltest/PTestInterruptRacesChild.h"
+
+namespace mozilla {
+namespace _ipdltest {
+
+mozilla::ipc::RacyInterruptPolicy MediateRace(
+ const mozilla::ipc::MessageChannel::MessageInfo& parent,
+ const mozilla::ipc::MessageChannel::MessageInfo& child);
+
+class TestInterruptRacesParent : public PTestInterruptRacesParent {
+ friend class PTestInterruptRacesParent;
+
+ public:
+ TestInterruptRacesParent()
+ : mHasReply(false), mChildHasReply(false), mAnsweredParent(false) {}
+ virtual ~TestInterruptRacesParent() {}
+
+ static bool RunTestInProcesses() { return true; }
+ static bool RunTestInThreads() { return true; }
+
+ void Main();
+
+ protected:
+ mozilla::ipc::IPCResult RecvStartRace();
+
+ mozilla::ipc::IPCResult AnswerRace(bool* hasRace);
+
+ mozilla::ipc::IPCResult AnswerStackFrame();
+
+ mozilla::ipc::IPCResult AnswerStackFrame3();
+
+ mozilla::ipc::IPCResult AnswerParent();
+
+ mozilla::ipc::IPCResult RecvGetAnsweredParent(bool* answeredParent);
+
+ mozilla::ipc::RacyInterruptPolicy MediateInterruptRace(
+ const MessageInfo& parent, const MessageInfo& child) override {
+ return MediateRace(parent, child);
+ }
+
+ virtual void ActorDestroy(ActorDestroyReason why) override {
+ if (NormalShutdown != why) fail("unexpected destruction!");
+ if (!(mHasReply && mChildHasReply)) fail("both sides should have replies!");
+ passed("ok");
+ QuitParent();
+ }
+
+ private:
+ void OnRaceTime();
+
+ void Test2();
+ void Test3();
+
+ bool mHasReply;
+ bool mChildHasReply;
+ bool mAnsweredParent;
+};
+
+class TestInterruptRacesChild : public PTestInterruptRacesChild {
+ friend class PTestInterruptRacesChild;
+
+ public:
+ TestInterruptRacesChild() : mHasReply(false) {}
+ virtual ~TestInterruptRacesChild() {}
+
+ protected:
+ mozilla::ipc::IPCResult RecvStart();
+
+ mozilla::ipc::IPCResult AnswerRace(bool* hasRace);
+
+ mozilla::ipc::IPCResult AnswerStackFrame();
+
+ mozilla::ipc::IPCResult AnswerStackFrame3();
+
+ mozilla::ipc::IPCResult RecvWakeup();
+
+ mozilla::ipc::IPCResult RecvWakeup3();
+
+ mozilla::ipc::IPCResult AnswerChild();
+
+ virtual mozilla::ipc::RacyInterruptPolicy MediateInterruptRace(
+ const MessageInfo& parent, const MessageInfo& child) override {
+ return MediateRace(parent, child);
+ }
+
+ virtual void ActorDestroy(ActorDestroyReason why) override {
+ if (NormalShutdown != why) fail("unexpected destruction!");
+ QuitChild();
+ }
+
+ private:
+ bool mHasReply;
+};
+
+} // namespace _ipdltest
+} // namespace mozilla
+
+#endif // ifndef mozilla__ipdltest_TestInterruptRaces_h
diff --git a/ipc/ipdl/test/cxx/TestInterruptShutdownRace.cpp b/ipc/ipdl/test/cxx/TestInterruptShutdownRace.cpp
new file mode 100644
index 0000000000..5482893995
--- /dev/null
+++ b/ipc/ipdl/test/cxx/TestInterruptShutdownRace.cpp
@@ -0,0 +1,111 @@
+#include "TestInterruptShutdownRace.h"
+
+#include "base/task.h"
+#include "IPDLUnitTests.h" // fail etc.
+#include "IPDLUnitTestSubprocess.h"
+
+namespace mozilla {
+namespace _ipdltest {
+
+//-----------------------------------------------------------------------------
+// parent
+
+namespace {
+
+// NB: this test does its own shutdown, rather than going through
+// QuitParent(), because it's testing degenerate edge cases
+
+void DeleteSubprocess() {
+ gSubprocess->Destroy();
+ gSubprocess = nullptr;
+}
+
+void Done() {
+ passed(__FILE__);
+ QuitParent();
+}
+
+} // namespace
+
+TestInterruptShutdownRaceParent::TestInterruptShutdownRaceParent() {
+ MOZ_COUNT_CTOR(TestInterruptShutdownRaceParent);
+}
+
+TestInterruptShutdownRaceParent::~TestInterruptShutdownRaceParent() {
+ MOZ_COUNT_DTOR(TestInterruptShutdownRaceParent);
+}
+
+void TestInterruptShutdownRaceParent::Main() {
+ if (!SendStart()) fail("sending Start");
+}
+
+mozilla::ipc::IPCResult TestInterruptShutdownRaceParent::RecvStartDeath() {
+ // this will be ordered before the OnMaybeDequeueOne event of
+ // Orphan in the queue
+ MessageLoop::current()->PostTask(NewNonOwningRunnableMethod(
+ "_ipdltest::TestInterruptShutdownRaceParent::StartShuttingDown", this,
+ &TestInterruptShutdownRaceParent::StartShuttingDown));
+ return IPC_OK();
+}
+
+void TestInterruptShutdownRaceParent::StartShuttingDown() {
+ // NB: we sleep here to try and avoid receiving the Orphan message
+ // while waiting for the CallExit() reply. if we fail at that, it
+ // will cause the test to pass spuriously, because there won't be
+ // an OnMaybeDequeueOne task for Orphan
+ PR_Sleep(2000);
+
+ if (CallExit()) fail("connection was supposed to be interrupted");
+
+ Close();
+
+ delete static_cast<TestInterruptShutdownRaceParent*>(gParentActor);
+ gParentActor = nullptr;
+
+ XRE_GetIOMessageLoop()->PostTask(
+ NewRunnableFunction("DeleteSubprocess", DeleteSubprocess));
+
+ // this is ordered after the OnMaybeDequeueOne event in the queue
+ MessageLoop::current()->PostTask(NewRunnableFunction("Done", Done));
+
+ // |this| has been deleted, be mindful
+}
+
+mozilla::ipc::IPCResult TestInterruptShutdownRaceParent::RecvOrphan() {
+ // it would be nice to fail() here, but we'll process this message
+ // while waiting for the reply CallExit(). The OnMaybeDequeueOne
+ // task will still be in the queue, it just wouldn't have had any
+ // work to do, if we hadn't deleted ourself
+ return IPC_OK();
+}
+
+//-----------------------------------------------------------------------------
+// child
+
+TestInterruptShutdownRaceChild::TestInterruptShutdownRaceChild() {
+ MOZ_COUNT_CTOR(TestInterruptShutdownRaceChild);
+}
+
+TestInterruptShutdownRaceChild::~TestInterruptShutdownRaceChild() {
+ MOZ_COUNT_DTOR(TestInterruptShutdownRaceChild);
+}
+
+mozilla::ipc::IPCResult TestInterruptShutdownRaceChild::RecvStart() {
+ if (!SendStartDeath()) fail("sending StartDeath");
+
+ // See comment in StartShuttingDown(): we want to send Orphan()
+ // while the parent is in its PR_Sleep()
+ PR_Sleep(1000);
+
+ if (!SendOrphan()) fail("sending Orphan");
+
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult TestInterruptShutdownRaceChild::AnswerExit() {
+ _exit(0);
+ MOZ_CRASH("unreached");
+}
+
+} // namespace _ipdltest
+} // namespace mozilla
diff --git a/ipc/ipdl/test/cxx/TestInterruptShutdownRace.h b/ipc/ipdl/test/cxx/TestInterruptShutdownRace.h
new file mode 100644
index 0000000000..17425fc06c
--- /dev/null
+++ b/ipc/ipdl/test/cxx/TestInterruptShutdownRace.h
@@ -0,0 +1,56 @@
+#ifndef mozilla__ipdltest_TestInterruptShutdownRace_h
+#define mozilla__ipdltest_TestInterruptShutdownRace_h 1
+
+#include "mozilla/_ipdltest/IPDLUnitTests.h"
+
+#include "mozilla/_ipdltest/PTestInterruptShutdownRaceParent.h"
+#include "mozilla/_ipdltest/PTestInterruptShutdownRaceChild.h"
+
+namespace mozilla {
+namespace _ipdltest {
+
+class TestInterruptShutdownRaceParent
+ : public PTestInterruptShutdownRaceParent {
+ public:
+ TestInterruptShutdownRaceParent();
+ virtual ~TestInterruptShutdownRaceParent();
+
+ static bool RunTestInProcesses() { return true; }
+ // FIXME/bug 703323 Could work if modified
+ static bool RunTestInThreads() { return false; }
+
+ void Main();
+
+ mozilla::ipc::IPCResult RecvStartDeath();
+
+ mozilla::ipc::IPCResult RecvOrphan();
+
+ protected:
+ void StartShuttingDown();
+
+ virtual void ActorDestroy(ActorDestroyReason why) override {
+ if (AbnormalShutdown != why) fail("unexpected destruction!");
+ }
+};
+
+class TestInterruptShutdownRaceChild : public PTestInterruptShutdownRaceChild {
+ friend class PTestInterruptShutdownRaceChild;
+
+ public:
+ TestInterruptShutdownRaceChild();
+ virtual ~TestInterruptShutdownRaceChild();
+
+ protected:
+ mozilla::ipc::IPCResult RecvStart();
+
+ mozilla::ipc::IPCResult AnswerExit();
+
+ virtual void ActorDestroy(ActorDestroyReason why) override {
+ fail("should have 'crashed'!");
+ }
+};
+
+} // namespace _ipdltest
+} // namespace mozilla
+
+#endif // ifndef mozilla__ipdltest_TestInterruptShutdownRace_h
diff --git a/ipc/ipdl/test/cxx/TestJSON.cpp b/ipc/ipdl/test/cxx/TestJSON.cpp
new file mode 100644
index 0000000000..42fac919d1
--- /dev/null
+++ b/ipc/ipdl/test/cxx/TestJSON.cpp
@@ -0,0 +1,113 @@
+#include "TestJSON.h"
+
+#include "IPDLUnitTests.h" // fail etc.
+
+#define test_assert(_cond, _msg) \
+ if (!(_cond)) fail(_msg)
+
+namespace mozilla {
+namespace _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);
+
+ test_assert(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);
+
+ test_assert(outer == outer, "operator== is broken");
+
+ return JSONVariant(outer);
+}
+
+//-----------------------------------------------------------------------------
+// parent
+
+void TestJSONParent::Main() {
+ if (!SendStart()) fail("sending Start");
+}
+
+mozilla::ipc::IPCResult TestJSONParent::RecvTest(const JSONVariant& i,
+ JSONVariant* o) {
+ test_assert(i == i, "operator== is broken");
+ test_assert(i == MakeTestVariant(mKid), "inparam mangled en route");
+
+ *o = i;
+
+ test_assert(i == *o, "operator= is broken");
+
+ return IPC_OK();
+}
+
+//-----------------------------------------------------------------------------
+// child
+
+mozilla::ipc::IPCResult TestJSONChild::RecvStart() {
+ if (!SendPTestHandleConstructor()) fail("sending Handle ctor");
+
+ JSONVariant i(MakeTestVariant(mKid));
+ test_assert(i == i, "operator== is broken");
+ test_assert(i == MakeTestVariant(mKid), "copy ctor is broken");
+
+ JSONVariant o;
+ if (!SendTest(i, &o)) fail("sending Test");
+
+ test_assert(i == o, "round-trip mangled input data");
+ test_assert(o == MakeTestVariant(mKid), "outparam mangled en route");
+
+ Close();
+ return IPC_OK();
+}
+
+} // namespace _ipdltest
+} // namespace mozilla
diff --git a/ipc/ipdl/test/cxx/TestJSON.h b/ipc/ipdl/test/cxx/TestJSON.h
new file mode 100644
index 0000000000..eaf7516525
--- /dev/null
+++ b/ipc/ipdl/test/cxx/TestJSON.h
@@ -0,0 +1,93 @@
+#ifndef mozilla__ipdltest_TestJSON_h
+#define mozilla__ipdltest_TestJSON_h 1
+
+#include "mozilla/_ipdltest/IPDLUnitTests.h"
+
+#include "mozilla/_ipdltest/PTestJSONParent.h"
+#include "mozilla/_ipdltest/PTestJSONChild.h"
+
+#include "mozilla/_ipdltest/PTestHandleParent.h"
+#include "mozilla/_ipdltest/PTestHandleChild.h"
+
+namespace mozilla {
+namespace _ipdltest {
+
+class TestHandleParent : public PTestHandleParent {
+ public:
+ TestHandleParent() {}
+ virtual ~TestHandleParent() {}
+
+ protected:
+ virtual void ActorDestroy(ActorDestroyReason why) override {}
+};
+
+class TestJSONParent : public PTestJSONParent {
+ friend class PTestJSONParent;
+
+ public:
+ TestJSONParent() {}
+ virtual ~TestJSONParent() {}
+
+ static bool RunTestInProcesses() { return true; }
+ static bool RunTestInThreads() { return true; }
+
+ void Main();
+
+ protected:
+ mozilla::ipc::IPCResult RecvTest(const JSONVariant& i, JSONVariant* o);
+
+ PTestHandleParent* AllocPTestHandleParent() {
+ return mKid = new TestHandleParent();
+ }
+
+ bool DeallocPTestHandleParent(PTestHandleParent* actor) {
+ delete actor;
+ return true;
+ }
+
+ virtual void ActorDestroy(ActorDestroyReason why) override {
+ if (NormalShutdown != why) fail("unexpected destruction!");
+ passed("ok");
+ QuitParent();
+ }
+
+ PTestHandleParent* mKid;
+};
+
+class TestHandleChild : public PTestHandleChild {
+ public:
+ TestHandleChild() {}
+ virtual ~TestHandleChild() {}
+};
+
+class TestJSONChild : public PTestJSONChild {
+ friend class PTestJSONChild;
+
+ public:
+ TestJSONChild() {}
+ virtual ~TestJSONChild() {}
+
+ protected:
+ mozilla::ipc::IPCResult RecvStart();
+
+ PTestHandleChild* AllocPTestHandleChild() {
+ return mKid = new TestHandleChild();
+ }
+
+ bool DeallocPTestHandleChild(PTestHandleChild* actor) {
+ delete actor;
+ return true;
+ }
+
+ virtual void ActorDestroy(ActorDestroyReason why) override {
+ if (NormalShutdown != why) fail("unexpected destruction!");
+ QuitChild();
+ }
+
+ PTestHandleChild* mKid;
+};
+
+} // namespace _ipdltest
+} // namespace mozilla
+
+#endif // ifndef mozilla__ipdltest_TestJSON_h
diff --git a/ipc/ipdl/test/cxx/TestLatency.cpp b/ipc/ipdl/test/cxx/TestLatency.cpp
new file mode 100644
index 0000000000..f88d8ea644
--- /dev/null
+++ b/ipc/ipdl/test/cxx/TestLatency.cpp
@@ -0,0 +1,210 @@
+#include "TestLatency.h"
+
+#include "IPDLUnitTests.h" // fail etc.
+
+// A ping/pong trial takes O(100us) or more, so if we don't have 10us
+// resolution or better, the results will not be terribly useful
+static const double kTimingResolutionCutoff = 0.00001; // 10us
+
+namespace mozilla {
+namespace _ipdltest {
+
+//-----------------------------------------------------------------------------
+// parent
+
+TestLatencyParent::TestLatencyParent()
+ : mStart(),
+ mPPTimeTotal(),
+ mPP5TimeTotal(),
+ mRpcTimeTotal(),
+ mPPTrialsToGo(NR_TRIALS),
+ mPP5TrialsToGo(NR_TRIALS),
+ mNumChildProcessedCompressedSpams(0),
+ mWhichPong5(0) {
+ MOZ_COUNT_CTOR(TestLatencyParent);
+}
+
+TestLatencyParent::~TestLatencyParent() { MOZ_COUNT_DTOR(TestLatencyParent); }
+
+void TestLatencyParent::Main() {
+ TimeDuration resolution = TimeDuration::Resolution();
+ if (resolution.ToSeconds() > kTimingResolutionCutoff) {
+ puts(" (skipping TestLatency, timing resolution is too poor)");
+ Close();
+ return;
+ }
+
+ printf(" timing resolution: %g seconds\n", resolution.ToSecondsSigDigits());
+
+ if (mozilla::ipc::LoggingEnabled())
+ MOZ_CRASH(
+ "you really don't want to log all IPC messages during this test, trust "
+ "me");
+
+ PingPongTrial();
+}
+
+void TestLatencyParent::PingPongTrial() {
+ mStart = TimeStamp::Now();
+ if (!SendPing()) fail("sending Ping()");
+}
+
+void TestLatencyParent::Ping5Pong5Trial() {
+ mStart = TimeStamp::Now();
+
+ if (!SendPing5() || !SendPing5() || !SendPing5() || !SendPing5() ||
+ !SendPing5())
+ fail("sending Ping5()");
+}
+
+mozilla::ipc::IPCResult TestLatencyParent::RecvPong() {
+ TimeDuration thisTrial = (TimeStamp::Now() - mStart);
+ mPPTimeTotal += thisTrial;
+
+ if (0 == (mPPTrialsToGo % 1000))
+ printf(" PP trial %d: %g\n", mPPTrialsToGo,
+ thisTrial.ToSecondsSigDigits());
+
+ if (--mPPTrialsToGo > 0)
+ PingPongTrial();
+ else
+ Ping5Pong5Trial();
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult TestLatencyParent::RecvPong5() {
+ ++mWhichPong5;
+
+ if (mWhichPong5 < 5) {
+ return IPC_OK();
+ }
+
+ mWhichPong5 = 0;
+
+ TimeDuration thisTrial = (TimeStamp::Now() - mStart);
+ mPP5TimeTotal += thisTrial;
+
+ if (0 == (mPP5TrialsToGo % 1000))
+ printf(" PP5 trial %d: %g\n", mPP5TrialsToGo,
+ thisTrial.ToSecondsSigDigits());
+
+ if (0 < --mPP5TrialsToGo)
+ Ping5Pong5Trial();
+ else
+ RpcTrials();
+
+ return IPC_OK();
+}
+
+void TestLatencyParent::RpcTrials() {
+ TimeStamp start = TimeStamp::Now();
+ for (int i = 0; i < NR_TRIALS; ++i) {
+ if (!CallRpc()) fail("can't call Rpc()");
+ if (0 == (i % 1000)) printf(" Rpc trial %d\n", i);
+ }
+ mRpcTimeTotal = (TimeStamp::Now() - start);
+
+ SpamTrial();
+}
+
+void TestLatencyParent::SpamTrial() {
+ TimeStamp start = TimeStamp::Now();
+ for (int i = 0; i < NR_SPAMS - 1; ++i) {
+ if (!SendSpam()) fail("sending Spam()");
+ if (0 == (i % 10000)) printf(" Spam trial %d\n", i);
+ }
+
+ // Synchronize with the child process to ensure all messages have
+ // been processed. This adds the overhead of a reply message from
+ // child-->here, but should be insignificant compared to >>
+ // NR_SPAMS.
+ if (!CallSynchro()) fail("calling Synchro()");
+
+ mSpamTimeTotal = (TimeStamp::Now() - start);
+
+ CompressedSpamTrial();
+}
+
+void TestLatencyParent::CompressedSpamTrial() {
+ for (int i = 0; i < NR_SPAMS; ++i) {
+ if (!SendCompressedSpam(i + 1)) fail("sending CompressedSpam()");
+ if (0 == (i % 10000)) printf(" CompressedSpam trial %d\n", i);
+ }
+
+ uint32_t lastSeqno;
+ if (!CallSynchro2(&lastSeqno, &mNumChildProcessedCompressedSpams))
+ fail("calling Synchro2()");
+
+ if (lastSeqno != NR_SPAMS)
+ fail("last seqno was %u, expected %u", lastSeqno, NR_SPAMS);
+
+ // NB: since this is testing an optimization, it's somewhat bogus.
+ // Need to make a warning if it actually intermittently fails in
+ // practice, which is doubtful.
+ if (!(mNumChildProcessedCompressedSpams < NR_SPAMS))
+ fail("Didn't compress any messages?");
+
+ Exit();
+}
+
+void TestLatencyParent::Exit() { Close(); }
+
+//-----------------------------------------------------------------------------
+// child
+
+TestLatencyChild::TestLatencyChild()
+ : mLastSeqno(0), mNumProcessedCompressedSpams(0), mWhichPing5(0) {
+ MOZ_COUNT_CTOR(TestLatencyChild);
+}
+
+TestLatencyChild::~TestLatencyChild() { MOZ_COUNT_DTOR(TestLatencyChild); }
+
+mozilla::ipc::IPCResult TestLatencyChild::RecvPing() {
+ SendPong();
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult TestLatencyChild::RecvPing5() {
+ ++mWhichPing5;
+
+ if (mWhichPing5 < 5) {
+ return IPC_OK();
+ }
+
+ mWhichPing5 = 0;
+
+ if (!SendPong5() || !SendPong5() || !SendPong5() || !SendPong5() ||
+ !SendPong5())
+ fail("sending Pong5()");
+
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult TestLatencyChild::AnswerRpc() { return IPC_OK(); }
+
+mozilla::ipc::IPCResult TestLatencyChild::RecvSpam() {
+ // no-op
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult TestLatencyChild::AnswerSynchro() { return IPC_OK(); }
+
+mozilla::ipc::IPCResult TestLatencyChild::RecvCompressedSpam(
+ const uint32_t& seqno) {
+ if (seqno <= mLastSeqno)
+ fail("compressed seqnos must monotonically increase");
+
+ mLastSeqno = seqno;
+ ++mNumProcessedCompressedSpams;
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult TestLatencyChild::AnswerSynchro2(
+ uint32_t* lastSeqno, uint32_t* numMessagesDispatched) {
+ *lastSeqno = mLastSeqno;
+ *numMessagesDispatched = mNumProcessedCompressedSpams;
+ return IPC_OK();
+}
+
+} // namespace _ipdltest
+} // namespace mozilla
diff --git a/ipc/ipdl/test/cxx/TestLatency.h b/ipc/ipdl/test/cxx/TestLatency.h
new file mode 100644
index 0000000000..687b107808
--- /dev/null
+++ b/ipc/ipdl/test/cxx/TestLatency.h
@@ -0,0 +1,107 @@
+#ifndef mozilla__ipdltest_TestLatency_h
+#define mozilla__ipdltest_TestLatency_h 1
+
+#include "mozilla/_ipdltest/IPDLUnitTests.h"
+
+#include "mozilla/_ipdltest/PTestLatencyParent.h"
+#include "mozilla/_ipdltest/PTestLatencyChild.h"
+
+#include "mozilla/TimeStamp.h"
+
+#define NR_TRIALS 10000
+#define NR_SPAMS 25000
+
+namespace mozilla {
+namespace _ipdltest {
+
+class TestLatencyParent : public PTestLatencyParent {
+ friend class PTestLatencyParent;
+
+ private:
+ typedef mozilla::TimeStamp TimeStamp;
+ typedef mozilla::TimeDuration TimeDuration;
+
+ public:
+ TestLatencyParent();
+ virtual ~TestLatencyParent();
+
+ static bool RunTestInProcesses() { return true; }
+ static bool RunTestInThreads() { return true; }
+
+ void Main();
+
+ protected:
+ mozilla::ipc::IPCResult RecvPong();
+ mozilla::ipc::IPCResult RecvPong5();
+
+ virtual void ActorDestroy(ActorDestroyReason why) override {
+ if (NormalShutdown != why) fail("unexpected destruction!");
+
+ passed(
+ "\n"
+ " average #ping-pong/sec: %g\n"
+ " average #ping5-pong5/sec: %g\n"
+ " average #RPC call-answer/sec: %g\n"
+ " average #spams/sec: %g\n"
+ " pct. spams compressed away: %g\n",
+ double(NR_TRIALS) / mPPTimeTotal.ToSecondsSigDigits(),
+ double(NR_TRIALS) / mPP5TimeTotal.ToSecondsSigDigits(),
+ double(NR_TRIALS) / mRpcTimeTotal.ToSecondsSigDigits(),
+ double(NR_SPAMS) / mSpamTimeTotal.ToSecondsSigDigits(),
+ 100.0 * (double(NR_SPAMS - mNumChildProcessedCompressedSpams) /
+ double(NR_SPAMS)));
+
+ QuitParent();
+ }
+
+ private:
+ void PingPongTrial();
+ void Ping5Pong5Trial();
+ void RpcTrials();
+ void SpamTrial();
+ void CompressedSpamTrial();
+ void Exit();
+
+ TimeStamp mStart;
+ TimeDuration mPPTimeTotal;
+ TimeDuration mPP5TimeTotal;
+ TimeDuration mRpcTimeTotal;
+ TimeDuration mSpamTimeTotal;
+
+ int mPPTrialsToGo;
+ int mPP5TrialsToGo;
+ uint32_t mNumChildProcessedCompressedSpams;
+ uint32_t mWhichPong5;
+};
+
+class TestLatencyChild : public PTestLatencyChild {
+ friend class PTestLatencyChild;
+
+ public:
+ TestLatencyChild();
+ virtual ~TestLatencyChild();
+
+ protected:
+ mozilla::ipc::IPCResult RecvPing();
+ mozilla::ipc::IPCResult RecvPing5();
+ mozilla::ipc::IPCResult AnswerRpc();
+ mozilla::ipc::IPCResult RecvSpam();
+ mozilla::ipc::IPCResult AnswerSynchro();
+ mozilla::ipc::IPCResult RecvCompressedSpam(const uint32_t& seqno);
+ mozilla::ipc::IPCResult AnswerSynchro2(uint32_t* lastSeqno,
+ uint32_t* numMessagesDispatched);
+
+ virtual void ActorDestroy(ActorDestroyReason why) override {
+ if (NormalShutdown != why) fail("unexpected destruction!");
+ QuitChild();
+ }
+
+ uint32_t mLastSeqno;
+ uint32_t mNumProcessedCompressedSpams;
+ uint32_t mWhichPing5;
+};
+
+} // namespace _ipdltest
+} // namespace mozilla
+
+#endif // ifndef mozilla__ipdltest_TestLatency_h
diff --git a/ipc/ipdl/test/cxx/TestManyChildAllocs.cpp b/ipc/ipdl/test/cxx/TestManyChildAllocs.cpp
new file mode 100644
index 0000000000..77d5786cfa
--- /dev/null
+++ b/ipc/ipdl/test/cxx/TestManyChildAllocs.cpp
@@ -0,0 +1,83 @@
+#include "TestManyChildAllocs.h"
+
+#include "IPDLUnitTests.h" // fail etc.
+
+#define NALLOCS 10
+
+namespace mozilla {
+namespace _ipdltest {
+
+// parent code
+
+TestManyChildAllocsParent::TestManyChildAllocsParent() {
+ MOZ_COUNT_CTOR(TestManyChildAllocsParent);
+}
+
+TestManyChildAllocsParent::~TestManyChildAllocsParent() {
+ MOZ_COUNT_DTOR(TestManyChildAllocsParent);
+}
+
+void TestManyChildAllocsParent::Main() {
+ if (!SendGo()) fail("can't send Go()");
+}
+
+mozilla::ipc::IPCResult TestManyChildAllocsParent::RecvDone() {
+ // explicitly *not* cleaning up, so we can sanity-check IPDL's
+ // auto-shutdown/cleanup handling
+ Close();
+
+ return IPC_OK();
+}
+
+bool TestManyChildAllocsParent::DeallocPTestManyChildAllocsSubParent(
+ PTestManyChildAllocsSubParent* __a) {
+ delete __a;
+ return true;
+}
+
+PTestManyChildAllocsSubParent*
+TestManyChildAllocsParent::AllocPTestManyChildAllocsSubParent() {
+ return new TestManyChildAllocsSubParent();
+}
+
+// child code
+
+TestManyChildAllocsChild::TestManyChildAllocsChild() {
+ MOZ_COUNT_CTOR(TestManyChildAllocsChild);
+}
+
+TestManyChildAllocsChild::~TestManyChildAllocsChild() {
+ MOZ_COUNT_DTOR(TestManyChildAllocsChild);
+}
+
+mozilla::ipc::IPCResult TestManyChildAllocsChild::RecvGo() {
+ for (int i = 0; i < NALLOCS; ++i) {
+ PTestManyChildAllocsSubChild* child =
+ SendPTestManyChildAllocsSubConstructor();
+
+ if (!child) fail("can't send ctor()");
+
+ if (!child->SendHello()) fail("can't send Hello()");
+ }
+
+ size_t len = ManagedPTestManyChildAllocsSubChild().Count();
+ if (NALLOCS != len) fail("expected %lu kids, got %lu", NALLOCS, len);
+
+ if (!SendDone()) fail("can't send Done()");
+
+ return IPC_OK();
+}
+
+bool TestManyChildAllocsChild::DeallocPTestManyChildAllocsSubChild(
+ PTestManyChildAllocsSubChild* __a) {
+ delete __a;
+ return true;
+}
+
+PTestManyChildAllocsSubChild*
+TestManyChildAllocsChild::AllocPTestManyChildAllocsSubChild() {
+ return new TestManyChildAllocsSubChild();
+}
+
+} // namespace _ipdltest
+} // namespace mozilla
diff --git a/ipc/ipdl/test/cxx/TestManyChildAllocs.h b/ipc/ipdl/test/cxx/TestManyChildAllocs.h
new file mode 100644
index 0000000000..3da6461810
--- /dev/null
+++ b/ipc/ipdl/test/cxx/TestManyChildAllocs.h
@@ -0,0 +1,82 @@
+#ifndef mozilla__ipdltest_TestManyChildAllocs_h
+#define mozilla__ipdltest_TestManyChildAllocs_h 1
+
+#include "mozilla/_ipdltest/IPDLUnitTests.h"
+
+#include "mozilla/_ipdltest/PTestManyChildAllocsParent.h"
+#include "mozilla/_ipdltest/PTestManyChildAllocsChild.h"
+
+#include "mozilla/_ipdltest/PTestManyChildAllocsSubParent.h"
+#include "mozilla/_ipdltest/PTestManyChildAllocsSubChild.h"
+
+namespace mozilla {
+namespace _ipdltest {
+
+// top-level protocol
+
+class TestManyChildAllocsParent : public PTestManyChildAllocsParent {
+ friend class PTestManyChildAllocsParent;
+
+ public:
+ TestManyChildAllocsParent();
+ virtual ~TestManyChildAllocsParent();
+
+ static bool RunTestInProcesses() { return true; }
+ static bool RunTestInThreads() { return true; }
+
+ void Main();
+
+ protected:
+ mozilla::ipc::IPCResult RecvDone();
+ bool DeallocPTestManyChildAllocsSubParent(PTestManyChildAllocsSubParent* __a);
+ PTestManyChildAllocsSubParent* AllocPTestManyChildAllocsSubParent();
+
+ virtual void ActorDestroy(ActorDestroyReason why) override {
+ if (NormalShutdown != why) fail("unexpected destruction!");
+ passed("ok");
+ QuitParent();
+ }
+};
+
+class TestManyChildAllocsChild : public PTestManyChildAllocsChild {
+ friend class PTestManyChildAllocsChild;
+
+ public:
+ TestManyChildAllocsChild();
+ virtual ~TestManyChildAllocsChild();
+
+ protected:
+ mozilla::ipc::IPCResult RecvGo();
+ bool DeallocPTestManyChildAllocsSubChild(PTestManyChildAllocsSubChild* __a);
+ PTestManyChildAllocsSubChild* AllocPTestManyChildAllocsSubChild();
+
+ virtual void ActorDestroy(ActorDestroyReason why) override {
+ if (NormalShutdown != why) fail("unexpected destruction!");
+ QuitChild();
+ }
+};
+
+// do-nothing sub-protocol actors
+
+class TestManyChildAllocsSubParent : public PTestManyChildAllocsSubParent {
+ friend class PTestManyChildAllocsSubParent;
+
+ public:
+ TestManyChildAllocsSubParent() {}
+ virtual ~TestManyChildAllocsSubParent() {}
+
+ protected:
+ virtual void ActorDestroy(ActorDestroyReason why) override {}
+ mozilla::ipc::IPCResult RecvHello() { return IPC_OK(); }
+};
+
+class TestManyChildAllocsSubChild : public PTestManyChildAllocsSubChild {
+ public:
+ TestManyChildAllocsSubChild() {}
+ virtual ~TestManyChildAllocsSubChild() {}
+};
+
+} // namespace _ipdltest
+} // namespace mozilla
+
+#endif // ifndef mozilla__ipdltest_TestManyChildAllocs_h
diff --git a/ipc/ipdl/test/cxx/TestMultiMgrs.cpp b/ipc/ipdl/test/cxx/TestMultiMgrs.cpp
new file mode 100644
index 0000000000..f09bb9ca7b
--- /dev/null
+++ b/ipc/ipdl/test/cxx/TestMultiMgrs.cpp
@@ -0,0 +1,83 @@
+#include "TestMultiMgrs.h"
+
+#include "IPDLUnitTests.h" // fail etc.
+#include "mozilla/ipc/ProtocolUtils.h"
+
+namespace mozilla {
+namespace _ipdltest {
+
+//-----------------------------------------------------------------------------
+// parent
+
+void TestMultiMgrsParent::Main() {
+ TestMultiMgrsLeftParent* leftie = new TestMultiMgrsLeftParent();
+ if (!SendPTestMultiMgrsLeftConstructor(leftie)) fail("error sending ctor");
+
+ TestMultiMgrsRightParent* rightie = new TestMultiMgrsRightParent();
+ if (!SendPTestMultiMgrsRightConstructor(rightie)) fail("error sending ctor");
+
+ TestMultiMgrsBottomParent* bottomL = new TestMultiMgrsBottomParent();
+ if (!leftie->SendPTestMultiMgrsBottomConstructor(bottomL))
+ fail("error sending ctor");
+
+ TestMultiMgrsBottomParent* bottomR = new TestMultiMgrsBottomParent();
+ if (!rightie->SendPTestMultiMgrsBottomConstructor(bottomR))
+ fail("error sending ctor");
+
+ if (!leftie->HasChild(bottomL))
+ fail("leftie didn't have a child it was supposed to!");
+ if (leftie->HasChild(bottomR)) fail("leftie had rightie's child!");
+
+ if (!rightie->HasChild(bottomR))
+ fail("rightie didn't have a child it was supposed to!");
+ if (rightie->HasChild(bottomL)) fail("rightie had rightie's child!");
+
+ if (!SendCheck()) fail("couldn't kick off the child-side check");
+}
+
+mozilla::ipc::IPCResult TestMultiMgrsParent::RecvOK() {
+ Close();
+ return IPC_OK();
+}
+
+//-----------------------------------------------------------------------------
+// child
+
+mozilla::ipc::IPCResult
+TestMultiMgrsLeftChild::RecvPTestMultiMgrsBottomConstructor(
+ PTestMultiMgrsBottomChild* actor) {
+ static_cast<TestMultiMgrsChild*>(Manager())->mBottomL = actor;
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult
+TestMultiMgrsRightChild::RecvPTestMultiMgrsBottomConstructor(
+ PTestMultiMgrsBottomChild* actor) {
+ static_cast<TestMultiMgrsChild*>(Manager())->mBottomR = actor;
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult TestMultiMgrsChild::RecvCheck() {
+ if (1 != ManagedPTestMultiMgrsLeftChild().Count()) fail("where's leftie?");
+ if (1 != ManagedPTestMultiMgrsRightChild().Count()) fail("where's rightie?");
+
+ TestMultiMgrsLeftChild* leftie = static_cast<TestMultiMgrsLeftChild*>(
+ LoneManagedOrNullAsserts(ManagedPTestMultiMgrsLeftChild()));
+ TestMultiMgrsRightChild* rightie = static_cast<TestMultiMgrsRightChild*>(
+ LoneManagedOrNullAsserts(ManagedPTestMultiMgrsRightChild()));
+
+ if (!leftie->HasChild(mBottomL))
+ fail("leftie didn't have a child it was supposed to!");
+ if (leftie->HasChild(mBottomR)) fail("leftie had rightie's child!");
+
+ if (!rightie->HasChild(mBottomR))
+ fail("rightie didn't have a child it was supposed to!");
+ if (rightie->HasChild(mBottomL)) fail("rightie had leftie's child!");
+
+ if (!SendOK()) fail("couldn't send OK()");
+
+ return IPC_OK();
+}
+
+} // namespace _ipdltest
+} // namespace mozilla
diff --git a/ipc/ipdl/test/cxx/TestMultiMgrs.h b/ipc/ipdl/test/cxx/TestMultiMgrs.h
new file mode 100644
index 0000000000..71826d42a7
--- /dev/null
+++ b/ipc/ipdl/test/cxx/TestMultiMgrs.h
@@ -0,0 +1,222 @@
+#ifndef mozilla__ipdltest_TestMultiMgrs_h
+#define mozilla__ipdltest_TestMultiMgrs_h 1
+
+#include "mozilla/_ipdltest/IPDLUnitTests.h"
+
+#include "mozilla/_ipdltest/PTestMultiMgrsParent.h"
+#include "mozilla/_ipdltest/PTestMultiMgrsChild.h"
+#include "mozilla/_ipdltest/PTestMultiMgrsBottomParent.h"
+#include "mozilla/_ipdltest/PTestMultiMgrsBottomChild.h"
+#include "mozilla/_ipdltest/PTestMultiMgrsLeftParent.h"
+#include "mozilla/_ipdltest/PTestMultiMgrsLeftChild.h"
+#include "mozilla/_ipdltest/PTestMultiMgrsRightParent.h"
+#include "mozilla/_ipdltest/PTestMultiMgrsRightChild.h"
+
+namespace mozilla {
+namespace _ipdltest {
+
+//-----------------------------------------------------------------------------
+// Parent side
+//
+
+class TestMultiMgrsBottomParent : public PTestMultiMgrsBottomParent {
+ public:
+ TestMultiMgrsBottomParent() {}
+ virtual ~TestMultiMgrsBottomParent() {}
+
+ protected:
+ virtual void ActorDestroy(ActorDestroyReason why) override {}
+};
+
+class TestMultiMgrsLeftParent : public PTestMultiMgrsLeftParent {
+ friend class PTestMultiMgrsLeftParent;
+
+ public:
+ TestMultiMgrsLeftParent() {}
+ virtual ~TestMultiMgrsLeftParent() {}
+
+ bool HasChild(TestMultiMgrsBottomParent* c) {
+ return ManagedPTestMultiMgrsBottomParent().Contains(c);
+ }
+
+ protected:
+ virtual void ActorDestroy(ActorDestroyReason why) override {}
+
+ PTestMultiMgrsBottomParent* AllocPTestMultiMgrsBottomParent() {
+ return new TestMultiMgrsBottomParent();
+ }
+
+ bool DeallocPTestMultiMgrsBottomParent(PTestMultiMgrsBottomParent* actor) {
+ delete actor;
+ return true;
+ }
+};
+
+class TestMultiMgrsRightParent : public PTestMultiMgrsRightParent {
+ friend class PTestMultiMgrsRightParent;
+
+ public:
+ TestMultiMgrsRightParent() {}
+ virtual ~TestMultiMgrsRightParent() {}
+
+ bool HasChild(TestMultiMgrsBottomParent* c) {
+ return ManagedPTestMultiMgrsBottomParent().Contains(c);
+ }
+
+ protected:
+ virtual void ActorDestroy(ActorDestroyReason why) override {}
+
+ PTestMultiMgrsBottomParent* AllocPTestMultiMgrsBottomParent() {
+ return new TestMultiMgrsBottomParent();
+ }
+
+ bool DeallocPTestMultiMgrsBottomParent(PTestMultiMgrsBottomParent* actor) {
+ delete actor;
+ return true;
+ }
+};
+
+class TestMultiMgrsParent : public PTestMultiMgrsParent {
+ friend class PTestMultiMgrsParent;
+
+ public:
+ TestMultiMgrsParent() {}
+ virtual ~TestMultiMgrsParent() {}
+
+ static bool RunTestInProcesses() { return true; }
+ static bool RunTestInThreads() { return true; }
+
+ void Main();
+
+ protected:
+ mozilla::ipc::IPCResult RecvOK();
+
+ PTestMultiMgrsLeftParent* AllocPTestMultiMgrsLeftParent() {
+ return new TestMultiMgrsLeftParent();
+ }
+
+ bool DeallocPTestMultiMgrsLeftParent(PTestMultiMgrsLeftParent* actor) {
+ delete actor;
+ return true;
+ }
+
+ PTestMultiMgrsRightParent* AllocPTestMultiMgrsRightParent() {
+ return new TestMultiMgrsRightParent();
+ }
+
+ bool DeallocPTestMultiMgrsRightParent(PTestMultiMgrsRightParent* actor) {
+ delete actor;
+ return true;
+ }
+
+ virtual void ActorDestroy(ActorDestroyReason why) override {
+ if (NormalShutdown != why) fail("unexpected destruction!");
+ passed("ok");
+ QuitParent();
+ }
+};
+
+//-----------------------------------------------------------------------------
+// Child side
+//
+
+class TestMultiMgrsBottomChild : public PTestMultiMgrsBottomChild {
+ public:
+ TestMultiMgrsBottomChild() {}
+ virtual ~TestMultiMgrsBottomChild() {}
+};
+
+class TestMultiMgrsLeftChild : public PTestMultiMgrsLeftChild {
+ friend class PTestMultiMgrsLeftChild;
+
+ public:
+ TestMultiMgrsLeftChild() {}
+ virtual ~TestMultiMgrsLeftChild() {}
+
+ bool HasChild(PTestMultiMgrsBottomChild* c) {
+ return ManagedPTestMultiMgrsBottomChild().Contains(c);
+ }
+
+ protected:
+ virtual mozilla::ipc::IPCResult RecvPTestMultiMgrsBottomConstructor(
+ PTestMultiMgrsBottomChild* actor) override;
+
+ PTestMultiMgrsBottomChild* AllocPTestMultiMgrsBottomChild() {
+ return new TestMultiMgrsBottomChild();
+ }
+
+ bool DeallocPTestMultiMgrsBottomChild(PTestMultiMgrsBottomChild* actor) {
+ delete actor;
+ return true;
+ }
+};
+
+class TestMultiMgrsRightChild : public PTestMultiMgrsRightChild {
+ friend class PTestMultiMgrsRightChild;
+
+ public:
+ TestMultiMgrsRightChild() {}
+ virtual ~TestMultiMgrsRightChild() {}
+
+ bool HasChild(PTestMultiMgrsBottomChild* c) {
+ return ManagedPTestMultiMgrsBottomChild().Contains(c);
+ }
+
+ protected:
+ virtual mozilla::ipc::IPCResult RecvPTestMultiMgrsBottomConstructor(
+ PTestMultiMgrsBottomChild* actor) override;
+
+ PTestMultiMgrsBottomChild* AllocPTestMultiMgrsBottomChild() {
+ return new TestMultiMgrsBottomChild();
+ }
+
+ bool DeallocPTestMultiMgrsBottomChild(PTestMultiMgrsBottomChild* actor) {
+ delete actor;
+ return true;
+ }
+};
+
+class TestMultiMgrsChild : public PTestMultiMgrsChild {
+ friend class PTestMultiMgrsChild;
+
+ public:
+ TestMultiMgrsChild() {}
+ virtual ~TestMultiMgrsChild() {}
+
+ void Main();
+
+ PTestMultiMgrsBottomChild* mBottomL;
+ PTestMultiMgrsBottomChild* mBottomR;
+
+ protected:
+ mozilla::ipc::IPCResult RecvCheck();
+
+ PTestMultiMgrsLeftChild* AllocPTestMultiMgrsLeftChild() {
+ return new TestMultiMgrsLeftChild();
+ }
+
+ bool DeallocPTestMultiMgrsLeftChild(PTestMultiMgrsLeftChild* actor) {
+ delete actor;
+ return true;
+ }
+
+ PTestMultiMgrsRightChild* AllocPTestMultiMgrsRightChild() {
+ return new TestMultiMgrsRightChild();
+ }
+
+ bool DeallocPTestMultiMgrsRightChild(PTestMultiMgrsRightChild* actor) {
+ delete actor;
+ return true;
+ }
+
+ virtual void ActorDestroy(ActorDestroyReason why) override {
+ if (NormalShutdown != why) fail("unexpected destruction!");
+ passed("ok");
+ QuitChild();
+ }
+};
+
+} // namespace _ipdltest
+} // namespace mozilla
+
+#endif // ifndef mozilla__ipdltest_TestMultiMgrs_h
diff --git a/ipc/ipdl/test/cxx/TestNestedLoops.cpp b/ipc/ipdl/test/cxx/TestNestedLoops.cpp
new file mode 100644
index 0000000000..3658d7dfb6
--- /dev/null
+++ b/ipc/ipdl/test/cxx/TestNestedLoops.cpp
@@ -0,0 +1,78 @@
+#include "base/basictypes.h"
+
+#include "nsThreadUtils.h"
+
+#include "TestNestedLoops.h"
+
+#include "IPDLUnitTests.h" // fail etc.
+
+namespace mozilla {
+namespace _ipdltest {
+
+//-----------------------------------------------------------------------------
+// parent
+
+TestNestedLoopsParent::TestNestedLoopsParent() : mBreakNestedLoop(false) {
+ MOZ_COUNT_CTOR(TestNestedLoopsParent);
+}
+
+TestNestedLoopsParent::~TestNestedLoopsParent() {
+ MOZ_COUNT_DTOR(TestNestedLoopsParent);
+}
+
+void TestNestedLoopsParent::Main() {
+ if (!SendStart()) fail("sending Start");
+
+ // sigh ... spin for a while to let Nonce arrive
+ puts(" (sleeping to wait for nonce ... sorry)");
+ PR_Sleep(5000);
+
+ // while waiting for the reply to R, we'll receive Nonce
+ if (!CallR()) fail("calling R");
+
+ Close();
+}
+
+mozilla::ipc::IPCResult TestNestedLoopsParent::RecvNonce() {
+ // if we have an OnMaybeDequeueOne waiting for us (we may not, due
+ // to the inherent race condition in this test, then this event
+ // must be ordered after it in the queue
+ MessageLoop::current()->PostTask(NewNonOwningRunnableMethod(
+ "_ipdltest::TestNestedLoopsParent::BreakNestedLoop", this,
+ &TestNestedLoopsParent::BreakNestedLoop));
+
+ // sigh ... spin for a while to let the reply to R arrive
+ puts(" (sleeping to wait for reply to R ... sorry)");
+ PR_Sleep(5000);
+
+ // sigh ... we have no idea when code might do this
+ do {
+ if (!NS_ProcessNextEvent(nullptr, false))
+ fail("expected at least one pending event");
+ } while (!mBreakNestedLoop);
+
+ return IPC_OK();
+}
+
+void TestNestedLoopsParent::BreakNestedLoop() { mBreakNestedLoop = true; }
+
+//-----------------------------------------------------------------------------
+// child
+
+TestNestedLoopsChild::TestNestedLoopsChild() {
+ MOZ_COUNT_CTOR(TestNestedLoopsChild);
+}
+
+TestNestedLoopsChild::~TestNestedLoopsChild() {
+ MOZ_COUNT_DTOR(TestNestedLoopsChild);
+}
+
+mozilla::ipc::IPCResult TestNestedLoopsChild::RecvStart() {
+ if (!SendNonce()) fail("sending Nonce");
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult TestNestedLoopsChild::AnswerR() { return IPC_OK(); }
+
+} // namespace _ipdltest
+} // namespace mozilla
diff --git a/ipc/ipdl/test/cxx/TestNestedLoops.h b/ipc/ipdl/test/cxx/TestNestedLoops.h
new file mode 100644
index 0000000000..001b571494
--- /dev/null
+++ b/ipc/ipdl/test/cxx/TestNestedLoops.h
@@ -0,0 +1,59 @@
+#ifndef mozilla__ipdltest_TestNestedLoops_h
+#define mozilla__ipdltest_TestNestedLoops_h 1
+
+#include "mozilla/_ipdltest/IPDLUnitTests.h"
+
+#include "mozilla/_ipdltest/PTestNestedLoopsParent.h"
+#include "mozilla/_ipdltest/PTestNestedLoopsChild.h"
+
+namespace mozilla {
+namespace _ipdltest {
+
+class TestNestedLoopsParent : public PTestNestedLoopsParent {
+ friend class PTestNestedLoopsParent;
+
+ public:
+ TestNestedLoopsParent();
+ virtual ~TestNestedLoopsParent();
+
+ static bool RunTestInProcesses() { return true; }
+ static bool RunTestInThreads() { return true; }
+
+ void Main();
+
+ protected:
+ mozilla::ipc::IPCResult RecvNonce();
+
+ void BreakNestedLoop();
+
+ virtual void ActorDestroy(ActorDestroyReason why) override {
+ if (NormalShutdown != why) fail("unexpected destruction!");
+ passed("ok");
+ QuitParent();
+ }
+
+ bool mBreakNestedLoop;
+};
+
+class TestNestedLoopsChild : public PTestNestedLoopsChild {
+ friend class PTestNestedLoopsChild;
+
+ public:
+ TestNestedLoopsChild();
+ virtual ~TestNestedLoopsChild();
+
+ protected:
+ mozilla::ipc::IPCResult RecvStart();
+
+ mozilla::ipc::IPCResult AnswerR();
+
+ virtual void ActorDestroy(ActorDestroyReason why) override {
+ if (NormalShutdown != why) fail("unexpected destruction!");
+ QuitChild();
+ }
+};
+
+} // namespace _ipdltest
+} // namespace mozilla
+
+#endif // ifndef mozilla__ipdltest_TestNestedLoops_h
diff --git a/ipc/ipdl/test/cxx/TestRPC.cpp b/ipc/ipdl/test/cxx/TestRPC.cpp
new file mode 100644
index 0000000000..cf7a1b6c36
--- /dev/null
+++ b/ipc/ipdl/test/cxx/TestRPC.cpp
@@ -0,0 +1,107 @@
+#include "TestRPC.h"
+
+#include "IPDLUnitTests.h" // fail etc.
+#if defined(XP_UNIX)
+# include <unistd.h>
+#else
+# include <windows.h>
+#endif
+
+namespace mozilla {
+namespace _ipdltest {
+
+//-----------------------------------------------------------------------------
+// parent
+
+TestRPCParent::TestRPCParent()
+ : reentered_(false), resolved_first_cpow_(false) {
+ MOZ_COUNT_CTOR(TestRPCParent);
+}
+
+TestRPCParent::~TestRPCParent() { MOZ_COUNT_DTOR(TestRPCParent); }
+
+void TestRPCParent::Main() {
+ if (!SendStart()) fail("sending Start");
+}
+
+mozilla::ipc::IPCResult TestRPCParent::RecvTest1_Start(uint32_t* aResult) {
+ uint32_t result;
+ if (!SendTest1_InnerQuery(&result)) fail("SendTest1_InnerQuery");
+ if (result != 300) fail("Wrong result (expected 300)");
+
+ *aResult = 100;
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult TestRPCParent::RecvTest1_InnerEvent(uint32_t* aResult) {
+ uint32_t result;
+ if (!SendTest1_NoReenter(&result)) fail("SendTest1_NoReenter");
+ if (result != 400) fail("Wrong result (expected 400)");
+
+ *aResult = 200;
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult TestRPCParent::RecvTest2_Start() {
+ // Send a CPOW. During this time, we must NOT process the RPC message, as
+ // we could start receiving CPOW replies out-of-order.
+ if (!SendTest2_FirstUrgent()) fail("SendTest2_FirstUrgent");
+
+ MOZ_ASSERT(!reentered_);
+ resolved_first_cpow_ = true;
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult TestRPCParent::RecvTest2_OutOfOrder() {
+ // Send a CPOW. If this RPC call was initiated while waiting for the first
+ // CPOW to resolve, replies will be processed out of order, and we'll crash.
+ if (!SendTest2_SecondUrgent()) fail("SendTest2_SecondUrgent");
+
+ reentered_ = true;
+ return IPC_OK();
+}
+
+//-----------------------------------------------------------------------------
+// child
+
+TestRPCChild::TestRPCChild() { MOZ_COUNT_CTOR(TestRPCChild); }
+
+TestRPCChild::~TestRPCChild() { MOZ_COUNT_DTOR(TestRPCChild); }
+
+mozilla::ipc::IPCResult TestRPCChild::RecvStart() {
+ uint32_t result;
+ if (!SendTest1_Start(&result)) fail("SendTest1_Start");
+ if (result != 100) fail("Wrong result (expected 100)");
+
+ if (!SendTest2_Start()) fail("SendTest2_Start");
+
+ if (!SendTest2_OutOfOrder()) fail("SendTest2_OutOfOrder");
+
+ Close();
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult TestRPCChild::RecvTest1_InnerQuery(uint32_t* aResult) {
+ uint32_t result;
+ if (!SendTest1_InnerEvent(&result)) fail("SendTest1_InnerEvent");
+ if (result != 200) fail("Wrong result (expected 200)");
+
+ *aResult = 300;
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult TestRPCChild::RecvTest1_NoReenter(uint32_t* aResult) {
+ *aResult = 400;
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult TestRPCChild::RecvTest2_FirstUrgent() {
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult TestRPCChild::RecvTest2_SecondUrgent() {
+ return IPC_OK();
+}
+
+} // namespace _ipdltest
+} // namespace mozilla
diff --git a/ipc/ipdl/test/cxx/TestRPC.h b/ipc/ipdl/test/cxx/TestRPC.h
new file mode 100644
index 0000000000..907d3fde36
--- /dev/null
+++ b/ipc/ipdl/test/cxx/TestRPC.h
@@ -0,0 +1,60 @@
+#ifndef mozilla__ipdltest_TestRPC_h
+#define mozilla__ipdltest_TestRPC_h 1
+
+#include "mozilla/_ipdltest/IPDLUnitTests.h"
+
+#include "mozilla/_ipdltest/PTestRPCParent.h"
+#include "mozilla/_ipdltest/PTestRPCChild.h"
+
+namespace mozilla {
+namespace _ipdltest {
+
+class TestRPCParent : public PTestRPCParent {
+ public:
+ TestRPCParent();
+ virtual ~TestRPCParent();
+
+ static bool RunTestInProcesses() { return true; }
+ static bool RunTestInThreads() { return false; }
+
+ void Main();
+
+ mozilla::ipc::IPCResult RecvTest1_Start(uint32_t* aResult);
+ mozilla::ipc::IPCResult RecvTest1_InnerEvent(uint32_t* aResult);
+ mozilla::ipc::IPCResult RecvTest2_Start();
+ mozilla::ipc::IPCResult RecvTest2_OutOfOrder();
+
+ virtual void ActorDestroy(ActorDestroyReason why) override {
+ if (NormalShutdown != why) fail("unexpected destruction!");
+ if (!reentered_) fail("never processed raced RPC call!");
+ if (!resolved_first_cpow_) fail("never resolved first CPOW!");
+ passed("ok");
+ QuitParent();
+ }
+
+ private:
+ bool reentered_;
+ bool resolved_first_cpow_;
+};
+
+class TestRPCChild : public PTestRPCChild {
+ public:
+ TestRPCChild();
+ virtual ~TestRPCChild();
+
+ mozilla::ipc::IPCResult RecvStart();
+ mozilla::ipc::IPCResult RecvTest1_InnerQuery(uint32_t* aResult);
+ mozilla::ipc::IPCResult RecvTest1_NoReenter(uint32_t* aResult);
+ mozilla::ipc::IPCResult RecvTest2_FirstUrgent();
+ mozilla::ipc::IPCResult RecvTest2_SecondUrgent();
+
+ virtual void ActorDestroy(ActorDestroyReason why) override {
+ if (NormalShutdown != why) fail("unexpected destruction!");
+ QuitChild();
+ }
+};
+
+} // namespace _ipdltest
+} // namespace mozilla
+
+#endif // ifndef mozilla__ipdltest_TestRPC_h
diff --git a/ipc/ipdl/test/cxx/TestRaceDeadlock.cpp b/ipc/ipdl/test/cxx/TestRaceDeadlock.cpp
new file mode 100644
index 0000000000..76defe97a5
--- /dev/null
+++ b/ipc/ipdl/test/cxx/TestRaceDeadlock.cpp
@@ -0,0 +1,102 @@
+#include "TestRaceDeadlock.h"
+
+#include "IPDLUnitTests.h" // fail etc.
+
+// #define TEST_TIMEOUT 5000
+
+using namespace mozilla::ipc;
+typedef mozilla::ipc::MessageChannel::Message Message;
+typedef mozilla::ipc::MessageChannel::MessageInfo MessageInfo;
+
+namespace mozilla {
+namespace _ipdltest {
+
+static RacyInterruptPolicy MediateRace(const MessageInfo& parent,
+ const MessageInfo& child) {
+ return (PTestRaceDeadlock::Msg_Win__ID == parent.type()) ? RIPParentWins
+ : RIPChildWins;
+}
+
+//-----------------------------------------------------------------------------
+// parent
+
+TestRaceDeadlockParent::TestRaceDeadlockParent() {
+ MOZ_COUNT_CTOR(TestRaceDeadlockParent);
+}
+
+TestRaceDeadlockParent::~TestRaceDeadlockParent() {
+ MOZ_COUNT_DTOR(TestRaceDeadlockParent);
+}
+
+void TestRaceDeadlockParent::Main() {
+ Test1();
+
+ Close();
+}
+
+bool TestRaceDeadlockParent::ShouldContinueFromReplyTimeout() {
+ fail("This test should not hang");
+ GetIPCChannel()->CloseWithTimeout();
+ return false;
+}
+
+void TestRaceDeadlockParent::Test1() {
+#if defined(TEST_TIMEOUT)
+ SetReplyTimeoutMs(TEST_TIMEOUT);
+#endif
+ if (!SendStartRace()) {
+ fail("sending StartRace");
+ }
+ if (!CallRpc()) {
+ fail("calling Rpc");
+ }
+}
+
+mozilla::ipc::IPCResult TestRaceDeadlockParent::AnswerLose() {
+ return IPC_OK();
+}
+
+RacyInterruptPolicy TestRaceDeadlockParent::MediateInterruptRace(
+ const MessageInfo& parent, const MessageInfo& child) {
+ return MediateRace(parent, child);
+}
+
+//-----------------------------------------------------------------------------
+// child
+
+TestRaceDeadlockChild::TestRaceDeadlockChild() {
+ MOZ_COUNT_CTOR(TestRaceDeadlockChild);
+}
+
+TestRaceDeadlockChild::~TestRaceDeadlockChild() {
+ MOZ_COUNT_DTOR(TestRaceDeadlockChild);
+}
+
+mozilla::ipc::IPCResult TestRaceDeadlockParent::RecvStartRace() {
+ if (!CallWin()) {
+ fail("calling Win");
+ }
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult TestRaceDeadlockChild::RecvStartRace() {
+ if (!SendStartRace()) {
+ fail("calling SendStartRace");
+ }
+ if (!CallLose()) {
+ fail("calling Lose");
+ }
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult TestRaceDeadlockChild::AnswerWin() { return IPC_OK(); }
+
+mozilla::ipc::IPCResult TestRaceDeadlockChild::AnswerRpc() { return IPC_OK(); }
+
+RacyInterruptPolicy TestRaceDeadlockChild::MediateInterruptRace(
+ const MessageInfo& parent, const MessageInfo& child) {
+ return MediateRace(parent, child);
+}
+
+} // namespace _ipdltest
+} // namespace mozilla
diff --git a/ipc/ipdl/test/cxx/TestRaceDeadlock.h b/ipc/ipdl/test/cxx/TestRaceDeadlock.h
new file mode 100644
index 0000000000..2c5617130d
--- /dev/null
+++ b/ipc/ipdl/test/cxx/TestRaceDeadlock.h
@@ -0,0 +1,68 @@
+#ifndef mozilla__ipdltest_TestRaceDeadlock_h
+#define mozilla__ipdltest_TestRaceDeadlock_h 1
+
+#include "mozilla/_ipdltest/IPDLUnitTests.h"
+
+#include "mozilla/_ipdltest/PTestRaceDeadlockParent.h"
+#include "mozilla/_ipdltest/PTestRaceDeadlockChild.h"
+
+namespace mozilla {
+namespace _ipdltest {
+
+class TestRaceDeadlockParent : public PTestRaceDeadlockParent {
+ friend class PTestRaceDeadlockParent;
+
+ public:
+ TestRaceDeadlockParent();
+ virtual ~TestRaceDeadlockParent();
+
+ static bool RunTestInProcesses() { return true; }
+ static bool RunTestInThreads() { return true; }
+
+ void Main();
+
+ protected:
+ virtual bool ShouldContinueFromReplyTimeout() override;
+
+ void Test1();
+
+ mozilla::ipc::IPCResult RecvStartRace();
+ mozilla::ipc::IPCResult AnswerLose();
+
+ virtual mozilla::ipc::RacyInterruptPolicy MediateInterruptRace(
+ const MessageInfo& parent, const MessageInfo& child) override;
+
+ virtual void ActorDestroy(ActorDestroyReason why) override {
+ if (NormalShutdown != why) fail("unexpected destruction!");
+ passed("ok");
+ QuitParent();
+ }
+};
+
+class TestRaceDeadlockChild : public PTestRaceDeadlockChild {
+ friend class PTestRaceDeadlockChild;
+
+ public:
+ TestRaceDeadlockChild();
+ virtual ~TestRaceDeadlockChild();
+
+ protected:
+ mozilla::ipc::IPCResult RecvStartRace();
+
+ mozilla::ipc::IPCResult AnswerWin();
+
+ mozilla::ipc::IPCResult AnswerRpc();
+
+ virtual mozilla::ipc::RacyInterruptPolicy MediateInterruptRace(
+ const MessageInfo& parent, const MessageInfo& child) override;
+
+ virtual void ActorDestroy(ActorDestroyReason why) override {
+ if (NormalShutdown != why) fail("unexpected destruction!");
+ QuitChild();
+ }
+};
+
+} // namespace _ipdltest
+} // namespace mozilla
+
+#endif // ifndef mozilla__ipdltest_TestRaceDeadlock_h
diff --git a/ipc/ipdl/test/cxx/TestRaceDeferral.cpp b/ipc/ipdl/test/cxx/TestRaceDeferral.cpp
new file mode 100644
index 0000000000..c327b57c16
--- /dev/null
+++ b/ipc/ipdl/test/cxx/TestRaceDeferral.cpp
@@ -0,0 +1,84 @@
+#include "TestRaceDeferral.h"
+
+#include "IPDLUnitTests.h" // fail etc.
+
+using namespace mozilla::ipc;
+typedef mozilla::ipc::MessageChannel::Message Message;
+typedef mozilla::ipc::MessageChannel::MessageInfo MessageInfo;
+
+namespace mozilla {
+namespace _ipdltest {
+
+static RacyInterruptPolicy MediateRace(const MessageInfo& parent,
+ const MessageInfo& child) {
+ return (PTestRaceDeferral::Msg_Win__ID == parent.type()) ? RIPParentWins
+ : RIPChildWins;
+}
+
+//-----------------------------------------------------------------------------
+// parent
+
+TestRaceDeferralParent::TestRaceDeferralParent() : mProcessedLose(false) {
+ MOZ_COUNT_CTOR(TestRaceDeferralParent);
+}
+
+TestRaceDeferralParent::~TestRaceDeferralParent() {
+ MOZ_COUNT_DTOR(TestRaceDeferralParent);
+
+ if (!mProcessedLose) fail("never processed Lose");
+}
+
+void TestRaceDeferralParent::Main() {
+ Test1();
+
+ Close();
+}
+
+void TestRaceDeferralParent::Test1() {
+ if (!SendStartRace()) fail("sending StartRace");
+
+ if (!CallWin()) fail("calling Win");
+ if (mProcessedLose) fail("Lose didn't lose");
+
+ if (!CallRpc()) fail("calling Rpc");
+ if (!mProcessedLose) fail("didn't resolve Rpc vs. Lose 'race' correctly");
+}
+
+mozilla::ipc::IPCResult TestRaceDeferralParent::AnswerLose() {
+ if (mProcessedLose) fail("processed Lose twice");
+ mProcessedLose = true;
+ return IPC_OK();
+}
+
+RacyInterruptPolicy TestRaceDeferralParent::MediateInterruptRace(
+ const MessageInfo& parent, const MessageInfo& child) {
+ return MediateRace(parent, child);
+}
+
+//-----------------------------------------------------------------------------
+// child
+
+TestRaceDeferralChild::TestRaceDeferralChild() {
+ MOZ_COUNT_CTOR(TestRaceDeferralChild);
+}
+
+TestRaceDeferralChild::~TestRaceDeferralChild() {
+ MOZ_COUNT_DTOR(TestRaceDeferralChild);
+}
+
+mozilla::ipc::IPCResult TestRaceDeferralChild::RecvStartRace() {
+ if (!CallLose()) fail("calling Lose");
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult TestRaceDeferralChild::AnswerWin() { return IPC_OK(); }
+
+mozilla::ipc::IPCResult TestRaceDeferralChild::AnswerRpc() { return IPC_OK(); }
+
+RacyInterruptPolicy TestRaceDeferralChild::MediateInterruptRace(
+ const MessageInfo& parent, const MessageInfo& child) {
+ return MediateRace(parent, child);
+}
+
+} // namespace _ipdltest
+} // namespace mozilla
diff --git a/ipc/ipdl/test/cxx/TestRaceDeferral.h b/ipc/ipdl/test/cxx/TestRaceDeferral.h
new file mode 100644
index 0000000000..b30264fb64
--- /dev/null
+++ b/ipc/ipdl/test/cxx/TestRaceDeferral.h
@@ -0,0 +1,67 @@
+#ifndef mozilla__ipdltest_TestRaceDeferral_h
+#define mozilla__ipdltest_TestRaceDeferral_h 1
+
+#include "mozilla/_ipdltest/IPDLUnitTests.h"
+
+#include "mozilla/_ipdltest/PTestRaceDeferralParent.h"
+#include "mozilla/_ipdltest/PTestRaceDeferralChild.h"
+
+namespace mozilla {
+namespace _ipdltest {
+
+class TestRaceDeferralParent : public PTestRaceDeferralParent {
+ friend class PTestRaceDeferralParent;
+
+ public:
+ TestRaceDeferralParent();
+ virtual ~TestRaceDeferralParent();
+
+ static bool RunTestInProcesses() { return true; }
+ static bool RunTestInThreads() { return true; }
+
+ void Main();
+
+ protected:
+ void Test1();
+
+ mozilla::ipc::IPCResult AnswerLose();
+
+ virtual mozilla::ipc::RacyInterruptPolicy MediateInterruptRace(
+ const MessageInfo& parent, const MessageInfo& child) override;
+
+ virtual void ActorDestroy(ActorDestroyReason why) override {
+ if (NormalShutdown != why) fail("unexpected destruction!");
+ passed("ok");
+ QuitParent();
+ }
+
+ bool mProcessedLose;
+};
+
+class TestRaceDeferralChild : public PTestRaceDeferralChild {
+ friend class PTestRaceDeferralChild;
+
+ public:
+ TestRaceDeferralChild();
+ virtual ~TestRaceDeferralChild();
+
+ protected:
+ mozilla::ipc::IPCResult RecvStartRace();
+
+ mozilla::ipc::IPCResult AnswerWin();
+
+ mozilla::ipc::IPCResult AnswerRpc();
+
+ virtual mozilla::ipc::RacyInterruptPolicy MediateInterruptRace(
+ const MessageInfo& parent, const MessageInfo& child) override;
+
+ virtual void ActorDestroy(ActorDestroyReason why) override {
+ if (NormalShutdown != why) fail("unexpected destruction!");
+ QuitChild();
+ }
+};
+
+} // namespace _ipdltest
+} // namespace mozilla
+
+#endif // ifndef mozilla__ipdltest_TestRaceDeferral_h
diff --git a/ipc/ipdl/test/cxx/TestRacyInterruptReplies.cpp b/ipc/ipdl/test/cxx/TestRacyInterruptReplies.cpp
new file mode 100644
index 0000000000..cda950b1a1
--- /dev/null
+++ b/ipc/ipdl/test/cxx/TestRacyInterruptReplies.cpp
@@ -0,0 +1,94 @@
+#include "TestRacyInterruptReplies.h"
+
+#include "IPDLUnitTests.h" // fail etc.
+
+namespace mozilla {
+namespace _ipdltest {
+
+//-----------------------------------------------------------------------------
+// parent
+
+TestRacyInterruptRepliesParent::TestRacyInterruptRepliesParent()
+ : mReplyNum(0) {
+ MOZ_COUNT_CTOR(TestRacyInterruptRepliesParent);
+}
+
+TestRacyInterruptRepliesParent::~TestRacyInterruptRepliesParent() {
+ MOZ_COUNT_DTOR(TestRacyInterruptRepliesParent);
+}
+
+void TestRacyInterruptRepliesParent::Main() {
+ int replyNum = -1;
+ if (!CallR_(&replyNum)) fail("calling R()");
+
+ if (1 != replyNum) fail("this should have been the first reply to R()");
+
+ if (!SendChildTest()) fail("sending ChildStart");
+}
+
+mozilla::ipc::IPCResult TestRacyInterruptRepliesParent::RecvA_() {
+ int replyNum = -1;
+ // this R() call races with the reply being generated by the other
+ // side to the R() call from Main(). This is a pretty nasty edge
+ // case for which one could argue we're breaking in-order message
+ // delivery, since this side will process the second reply to R()
+ // before the first.
+ if (!CallR_(&replyNum)) fail("calling R()");
+
+ if (2 != replyNum) fail("this should have been the second reply to R()");
+
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult TestRacyInterruptRepliesParent::Answer_R(
+ int* replyNum) {
+ *replyNum = ++mReplyNum;
+
+ if (1 == *replyNum)
+ if (!Send_A()) fail("sending _A()");
+
+ return IPC_OK();
+}
+
+//-----------------------------------------------------------------------------
+// child
+
+TestRacyInterruptRepliesChild::TestRacyInterruptRepliesChild() : mReplyNum(0) {
+ MOZ_COUNT_CTOR(TestRacyInterruptRepliesChild);
+}
+
+TestRacyInterruptRepliesChild::~TestRacyInterruptRepliesChild() {
+ MOZ_COUNT_DTOR(TestRacyInterruptRepliesChild);
+}
+
+mozilla::ipc::IPCResult TestRacyInterruptRepliesChild::AnswerR_(int* replyNum) {
+ *replyNum = ++mReplyNum;
+
+ if (1 == *replyNum) SendA_();
+
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult TestRacyInterruptRepliesChild::RecvChildTest() {
+ int replyNum = -1;
+ if (!Call_R(&replyNum)) fail("calling R()");
+
+ if (1 != replyNum) fail("this should have been the first reply to R()");
+
+ Close();
+
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult TestRacyInterruptRepliesChild::Recv_A() {
+ int replyNum = -1;
+
+ if (!Call_R(&replyNum)) fail("calling _R()");
+
+ if (2 != replyNum) fail("this should have been the second reply to R()");
+
+ return IPC_OK();
+}
+
+} // namespace _ipdltest
+} // namespace mozilla
diff --git a/ipc/ipdl/test/cxx/TestRacyInterruptReplies.h b/ipc/ipdl/test/cxx/TestRacyInterruptReplies.h
new file mode 100644
index 0000000000..182c07f314
--- /dev/null
+++ b/ipc/ipdl/test/cxx/TestRacyInterruptReplies.h
@@ -0,0 +1,65 @@
+#ifndef mozilla__ipdltest_TestRacyInterruptReplies_h
+#define mozilla__ipdltest_TestRacyInterruptReplies_h 1
+
+#include "mozilla/_ipdltest/IPDLUnitTests.h"
+
+#include "mozilla/_ipdltest/PTestRacyInterruptRepliesParent.h"
+#include "mozilla/_ipdltest/PTestRacyInterruptRepliesChild.h"
+
+namespace mozilla {
+namespace _ipdltest {
+
+class TestRacyInterruptRepliesParent : public PTestRacyInterruptRepliesParent {
+ friend class PTestRacyInterruptRepliesParent;
+
+ public:
+ TestRacyInterruptRepliesParent();
+ virtual ~TestRacyInterruptRepliesParent();
+
+ static bool RunTestInProcesses() { return true; }
+ static bool RunTestInThreads() { return true; }
+
+ void Main();
+
+ protected:
+ mozilla::ipc::IPCResult RecvA_();
+
+ mozilla::ipc::IPCResult Answer_R(int* replyNum);
+
+ virtual void ActorDestroy(ActorDestroyReason why) override {
+ if (NormalShutdown != why) fail("unexpected destruction!");
+ passed("ok");
+ QuitParent();
+ }
+
+ private:
+ int mReplyNum;
+};
+
+class TestRacyInterruptRepliesChild : public PTestRacyInterruptRepliesChild {
+ friend class PTestRacyInterruptRepliesChild;
+
+ public:
+ TestRacyInterruptRepliesChild();
+ virtual ~TestRacyInterruptRepliesChild();
+
+ protected:
+ mozilla::ipc::IPCResult AnswerR_(int* replyNum);
+
+ mozilla::ipc::IPCResult RecvChildTest();
+
+ mozilla::ipc::IPCResult Recv_A();
+
+ virtual void ActorDestroy(ActorDestroyReason why) override {
+ if (NormalShutdown != why) fail("unexpected destruction!");
+ QuitChild();
+ }
+
+ private:
+ int mReplyNum;
+};
+
+} // namespace _ipdltest
+} // namespace mozilla
+
+#endif // ifndef mozilla__ipdltest_TestRacyInterruptReplies_h
diff --git a/ipc/ipdl/test/cxx/TestRacyReentry.cpp b/ipc/ipdl/test/cxx/TestRacyReentry.cpp
new file mode 100644
index 0000000000..4224018e11
--- /dev/null
+++ b/ipc/ipdl/test/cxx/TestRacyReentry.cpp
@@ -0,0 +1,63 @@
+#include "TestRacyReentry.h"
+
+#include "IPDLUnitTests.h" // fail etc.
+
+namespace mozilla {
+namespace _ipdltest {
+
+//-----------------------------------------------------------------------------
+// parent
+
+TestRacyReentryParent::TestRacyReentryParent() : mRecvdE(false) {
+ MOZ_COUNT_CTOR(TestRacyReentryParent);
+}
+
+TestRacyReentryParent::~TestRacyReentryParent() {
+ MOZ_COUNT_DTOR(TestRacyReentryParent);
+}
+
+void TestRacyReentryParent::Main() {
+ if (!SendStart()) fail("sending Start");
+
+ if (!SendN()) fail("sending N");
+}
+
+mozilla::ipc::IPCResult TestRacyReentryParent::AnswerE() {
+ if (!mRecvdE) {
+ mRecvdE = true;
+ return IPC_OK();
+ }
+
+ if (!CallH()) fail("calling H");
+
+ return IPC_OK();
+}
+
+//-----------------------------------------------------------------------------
+// child
+
+TestRacyReentryChild::TestRacyReentryChild() {
+ MOZ_COUNT_CTOR(TestRacyReentryChild);
+}
+
+TestRacyReentryChild::~TestRacyReentryChild() {
+ MOZ_COUNT_DTOR(TestRacyReentryChild);
+}
+
+mozilla::ipc::IPCResult TestRacyReentryChild::RecvStart() {
+ if (!CallE()) fail("calling E");
+
+ Close();
+
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult TestRacyReentryChild::RecvN() {
+ if (!CallE()) fail("calling E");
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult TestRacyReentryChild::AnswerH() { return IPC_OK(); }
+
+} // namespace _ipdltest
+} // namespace mozilla
diff --git a/ipc/ipdl/test/cxx/TestRacyReentry.h b/ipc/ipdl/test/cxx/TestRacyReentry.h
new file mode 100644
index 0000000000..e31f90c0e3
--- /dev/null
+++ b/ipc/ipdl/test/cxx/TestRacyReentry.h
@@ -0,0 +1,59 @@
+#ifndef mozilla__ipdltest_TestRacyReentry_h
+#define mozilla__ipdltest_TestRacyReentry_h 1
+
+#include "mozilla/_ipdltest/IPDLUnitTests.h"
+
+#include "mozilla/_ipdltest/PTestRacyReentryParent.h"
+#include "mozilla/_ipdltest/PTestRacyReentryChild.h"
+
+namespace mozilla {
+namespace _ipdltest {
+
+class TestRacyReentryParent : public PTestRacyReentryParent {
+ friend class PTestRacyReentryParent;
+
+ public:
+ TestRacyReentryParent();
+ virtual ~TestRacyReentryParent();
+
+ static bool RunTestInProcesses() { return true; }
+ static bool RunTestInThreads() { return true; }
+
+ void Main();
+
+ protected:
+ mozilla::ipc::IPCResult AnswerE();
+
+ virtual void ActorDestroy(ActorDestroyReason why) override {
+ if (NormalShutdown != why) fail("unexpected destruction!");
+ passed("ok");
+ QuitParent();
+ }
+
+ bool mRecvdE;
+};
+
+class TestRacyReentryChild : public PTestRacyReentryChild {
+ friend class PTestRacyReentryChild;
+
+ public:
+ TestRacyReentryChild();
+ virtual ~TestRacyReentryChild();
+
+ protected:
+ mozilla::ipc::IPCResult RecvStart();
+
+ mozilla::ipc::IPCResult RecvN();
+
+ mozilla::ipc::IPCResult AnswerH();
+
+ virtual void ActorDestroy(ActorDestroyReason why) override {
+ if (NormalShutdown != why) fail("unexpected destruction!");
+ QuitChild();
+ }
+};
+
+} // namespace _ipdltest
+} // namespace mozilla
+
+#endif // ifndef mozilla__ipdltest_TestRacyReentry_h
diff --git a/ipc/ipdl/test/cxx/TestRacyUndefer.cpp b/ipc/ipdl/test/cxx/TestRacyUndefer.cpp
new file mode 100644
index 0000000000..a46db5618e
--- /dev/null
+++ b/ipc/ipdl/test/cxx/TestRacyUndefer.cpp
@@ -0,0 +1,83 @@
+#include "base/basictypes.h"
+
+#include "TestRacyUndefer.h"
+
+#include "IPDLUnitTests.h" // fail etc.
+
+namespace mozilla {
+namespace _ipdltest {
+
+//-----------------------------------------------------------------------------
+// parent
+
+TestRacyUndeferParent::TestRacyUndeferParent() {
+ MOZ_COUNT_CTOR(TestRacyUndeferParent);
+}
+
+TestRacyUndeferParent::~TestRacyUndeferParent() {
+ MOZ_COUNT_DTOR(TestRacyUndeferParent);
+}
+
+void TestRacyUndeferParent::Main() {
+ if (!SendStart()) fail("sending Start");
+}
+
+mozilla::ipc::IPCResult TestRacyUndeferParent::AnswerSpam() {
+ static bool spammed = false;
+ static bool raced = false;
+ if (!spammed) {
+ spammed = true;
+
+ if (!SendAwakenSpam()) fail("sending AwakenSpam");
+ } else if (!raced) {
+ raced = true;
+
+ if (!SendAwakenRaceWinTwice()) fail("sending WinRaceTwice");
+
+ if (!CallRace()) fail("calling Race1");
+ }
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult TestRacyUndeferParent::AnswerRaceWinTwice() {
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult TestRacyUndeferParent::RecvDone() {
+ Close();
+ return IPC_OK();
+}
+
+//-----------------------------------------------------------------------------
+// child
+
+TestRacyUndeferChild::TestRacyUndeferChild() {
+ MOZ_COUNT_CTOR(TestRacyUndeferChild);
+}
+
+TestRacyUndeferChild::~TestRacyUndeferChild() {
+ MOZ_COUNT_DTOR(TestRacyUndeferChild);
+}
+
+mozilla::ipc::IPCResult TestRacyUndeferChild::RecvStart() {
+ if (!CallSpam()) fail("calling Spam");
+
+ if (!SendDone()) fail("sending Done");
+
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult TestRacyUndeferChild::RecvAwakenSpam() {
+ if (!CallSpam()) fail("calling Spam");
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult TestRacyUndeferChild::RecvAwakenRaceWinTwice() {
+ if (!CallRaceWinTwice()) fail("calling RaceWinTwice");
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult TestRacyUndeferChild::AnswerRace() { return IPC_OK(); }
+
+} // namespace _ipdltest
+} // namespace mozilla
diff --git a/ipc/ipdl/test/cxx/TestRacyUndefer.h b/ipc/ipdl/test/cxx/TestRacyUndefer.h
new file mode 100644
index 0000000000..1e157a541b
--- /dev/null
+++ b/ipc/ipdl/test/cxx/TestRacyUndefer.h
@@ -0,0 +1,62 @@
+#ifndef mozilla__ipdltest_TestRacyUndefer_h
+#define mozilla__ipdltest_TestRacyUndefer_h 1
+
+#include "mozilla/_ipdltest/IPDLUnitTests.h"
+
+#include "mozilla/_ipdltest/PTestRacyUndeferParent.h"
+#include "mozilla/_ipdltest/PTestRacyUndeferChild.h"
+
+namespace mozilla {
+namespace _ipdltest {
+
+class TestRacyUndeferParent : public PTestRacyUndeferParent {
+ friend class PTestRacyUndeferParent;
+
+ public:
+ TestRacyUndeferParent();
+ virtual ~TestRacyUndeferParent();
+
+ static bool RunTestInProcesses() { return true; }
+ static bool RunTestInThreads() { return true; }
+
+ void Main();
+
+ protected:
+ mozilla::ipc::IPCResult AnswerSpam();
+
+ mozilla::ipc::IPCResult AnswerRaceWinTwice();
+
+ mozilla::ipc::IPCResult RecvDone();
+
+ virtual void ActorDestroy(ActorDestroyReason why) override {
+ if (NormalShutdown != why) fail("unexpected destruction!");
+ passed("ok");
+ QuitParent();
+ }
+};
+
+class TestRacyUndeferChild : public PTestRacyUndeferChild {
+ friend class PTestRacyUndeferChild;
+
+ public:
+ TestRacyUndeferChild();
+ virtual ~TestRacyUndeferChild();
+
+ protected:
+ mozilla::ipc::IPCResult RecvStart();
+
+ mozilla::ipc::IPCResult RecvAwakenSpam();
+ mozilla::ipc::IPCResult RecvAwakenRaceWinTwice();
+
+ mozilla::ipc::IPCResult AnswerRace();
+
+ virtual void ActorDestroy(ActorDestroyReason why) override {
+ if (NormalShutdown != why) fail("unexpected destruction!");
+ QuitChild();
+ }
+};
+
+} // namespace _ipdltest
+} // namespace mozilla
+
+#endif // ifndef mozilla__ipdltest_TestRacyUndefer_h
diff --git a/ipc/ipdl/test/cxx/TestSanity.cpp b/ipc/ipdl/test/cxx/TestSanity.cpp
new file mode 100644
index 0000000000..ba1920fdcc
--- /dev/null
+++ b/ipc/ipdl/test/cxx/TestSanity.cpp
@@ -0,0 +1,52 @@
+#include "TestSanity.h"
+
+#include "IPDLUnitTests.h" // fail etc.
+
+namespace mozilla {
+namespace _ipdltest {
+
+//-----------------------------------------------------------------------------
+// parent
+
+TestSanityParent::TestSanityParent() { MOZ_COUNT_CTOR(TestSanityParent); }
+
+TestSanityParent::~TestSanityParent() { MOZ_COUNT_DTOR(TestSanityParent); }
+
+void TestSanityParent::Main() {
+ if (!SendPing(0, 0.5f, 0)) fail("sending Ping");
+}
+
+mozilla::ipc::IPCResult TestSanityParent::RecvPong(const int& one,
+ const float& zeroPtTwoFive,
+ const uint8_t& /*unused*/) {
+ if (1 != one) fail("invalid argument `%d', should have been `1'", one);
+
+ if (0.25f != zeroPtTwoFive)
+ fail("invalid argument `%g', should have been `0.25'", zeroPtTwoFive);
+
+ Close();
+
+ return IPC_OK();
+}
+
+//-----------------------------------------------------------------------------
+// child
+
+TestSanityChild::TestSanityChild() { MOZ_COUNT_CTOR(TestSanityChild); }
+
+TestSanityChild::~TestSanityChild() { MOZ_COUNT_DTOR(TestSanityChild); }
+
+mozilla::ipc::IPCResult TestSanityChild::RecvPing(const int& zero,
+ const float& zeroPtFive,
+ const int8_t& /*unused*/) {
+ if (0 != zero) fail("invalid argument `%d', should have been `0'", zero);
+
+ if (0.5f != zeroPtFive)
+ fail("invalid argument `%g', should have been `0.5'", zeroPtFive);
+
+ if (!SendPong(1, 0.25f, 0)) fail("sending Pong");
+ return IPC_OK();
+}
+
+} // namespace _ipdltest
+} // namespace mozilla
diff --git a/ipc/ipdl/test/cxx/TestSanity.h b/ipc/ipdl/test/cxx/TestSanity.h
new file mode 100644
index 0000000000..ca29d67672
--- /dev/null
+++ b/ipc/ipdl/test/cxx/TestSanity.h
@@ -0,0 +1,55 @@
+#ifndef mozilla__ipdltest_TestSanity_h
+#define mozilla__ipdltest_TestSanity_h 1
+
+#include "mozilla/_ipdltest/IPDLUnitTests.h"
+
+#include "mozilla/_ipdltest/PTestSanityParent.h"
+#include "mozilla/_ipdltest/PTestSanityChild.h"
+
+namespace mozilla {
+namespace _ipdltest {
+
+class TestSanityParent : public PTestSanityParent {
+ friend class PTestSanityParent;
+
+ public:
+ TestSanityParent();
+ virtual ~TestSanityParent();
+
+ static bool RunTestInProcesses() { return true; }
+ static bool RunTestInThreads() { return true; }
+
+ void Main();
+
+ protected:
+ mozilla::ipc::IPCResult RecvPong(const int& one, const float& zeroPtTwoFive,
+ const uint8_t& dummy);
+
+ virtual void ActorDestroy(ActorDestroyReason why) override {
+ if (NormalShutdown != why) fail("unexpected destruction!");
+ passed("ok");
+ QuitParent();
+ }
+};
+
+class TestSanityChild : public PTestSanityChild {
+ friend class PTestSanityChild;
+
+ public:
+ TestSanityChild();
+ virtual ~TestSanityChild();
+
+ protected:
+ mozilla::ipc::IPCResult RecvPing(const int& zero, const float& zeroPtFive,
+ const int8_t& dummy);
+
+ virtual void ActorDestroy(ActorDestroyReason why) override {
+ if (NormalShutdown != why) fail("unexpected destruction!");
+ QuitChild();
+ }
+};
+
+} // namespace _ipdltest
+} // namespace mozilla
+
+#endif // ifndef mozilla__ipdltest_TestSanity_h
diff --git a/ipc/ipdl/test/cxx/TestSelfManageRoot.cpp b/ipc/ipdl/test/cxx/TestSelfManageRoot.cpp
new file mode 100644
index 0000000000..5e09aa4d7e
--- /dev/null
+++ b/ipc/ipdl/test/cxx/TestSelfManageRoot.cpp
@@ -0,0 +1,54 @@
+#include "TestSelfManageRoot.h"
+
+#include "IPDLUnitTests.h" // fail etc.
+
+#define ASSERT(c) \
+ do { \
+ if (!(c)) fail(#c); \
+ } while (0)
+
+namespace mozilla {
+namespace _ipdltest {
+
+//-----------------------------------------------------------------------------
+// parent
+
+void TestSelfManageRootParent::Main() {
+ TestSelfManageParent* a =
+ static_cast<TestSelfManageParent*>(SendPTestSelfManageConstructor());
+ if (!a) fail("constructing PTestSelfManage");
+
+ ASSERT(1 == ManagedPTestSelfManageParent().Count());
+
+ TestSelfManageParent* aa =
+ static_cast<TestSelfManageParent*>(a->SendPTestSelfManageConstructor());
+ if (!aa) fail("constructing PTestSelfManage");
+
+ ASSERT(1 == ManagedPTestSelfManageParent().Count() &&
+ 1 == a->ManagedPTestSelfManageParent().Count());
+
+ if (!PTestSelfManageParent::Send__delete__(aa))
+ fail("destroying PTestSelfManage");
+ ASSERT(Deletion == aa->mWhy && 1 == ManagedPTestSelfManageParent().Count() &&
+ 0 == a->ManagedPTestSelfManageParent().Count());
+ delete aa;
+
+ aa = static_cast<TestSelfManageParent*>(a->SendPTestSelfManageConstructor());
+ if (!aa) fail("constructing PTestSelfManage");
+
+ ASSERT(1 == ManagedPTestSelfManageParent().Count() &&
+ 1 == a->ManagedPTestSelfManageParent().Count());
+
+ if (!PTestSelfManageParent::Send__delete__(a))
+ fail("destroying PTestSelfManage");
+ ASSERT(Deletion == a->mWhy && AncestorDeletion == aa->mWhy &&
+ 0 == ManagedPTestSelfManageParent().Count() &&
+ 0 == a->ManagedPTestSelfManageParent().Count());
+ delete a;
+ delete aa;
+
+ Close();
+}
+
+} // namespace _ipdltest
+} // namespace mozilla
diff --git a/ipc/ipdl/test/cxx/TestSelfManageRoot.h b/ipc/ipdl/test/cxx/TestSelfManageRoot.h
new file mode 100644
index 0000000000..5cea09b10d
--- /dev/null
+++ b/ipc/ipdl/test/cxx/TestSelfManageRoot.h
@@ -0,0 +1,117 @@
+#ifndef mozilla__ipdltest_TestSelfManageRoot_h
+#define mozilla__ipdltest_TestSelfManageRoot_h 1
+
+#include "mozilla/_ipdltest/IPDLUnitTests.h"
+
+#include "mozilla/_ipdltest/PTestSelfManageRootParent.h"
+#include "mozilla/_ipdltest/PTestSelfManageRootChild.h"
+#include "mozilla/_ipdltest/PTestSelfManageParent.h"
+#include "mozilla/_ipdltest/PTestSelfManageChild.h"
+
+namespace mozilla {
+namespace _ipdltest {
+
+//-----------------------------------------------------------------------------
+// Parent side
+
+class TestSelfManageParent : public PTestSelfManageParent {
+ friend class PTestSelfManageParent;
+
+ public:
+ MOZ_COUNTED_DEFAULT_CTOR(TestSelfManageParent)
+ MOZ_COUNTED_DTOR_OVERRIDE(TestSelfManageParent)
+
+ ActorDestroyReason mWhy;
+
+ protected:
+ PTestSelfManageParent* AllocPTestSelfManageParent() {
+ return new TestSelfManageParent();
+ }
+
+ bool DeallocPTestSelfManageParent(PTestSelfManageParent* a) { return true; }
+
+ virtual void ActorDestroy(ActorDestroyReason why) override { mWhy = why; }
+};
+
+class TestSelfManageRootParent : public PTestSelfManageRootParent {
+ friend class PTestSelfManageRootParent;
+
+ public:
+ MOZ_COUNTED_DEFAULT_CTOR(TestSelfManageRootParent)
+ virtual ~TestSelfManageRootParent() {
+ MOZ_COUNT_DTOR(TestSelfManageRootParent);
+ }
+
+ static bool RunTestInProcesses() { return true; }
+ static bool RunTestInThreads() { return true; }
+
+ void Main();
+
+ protected:
+ PTestSelfManageParent* AllocPTestSelfManageParent() {
+ return new TestSelfManageParent();
+ }
+
+ bool DeallocPTestSelfManageParent(PTestSelfManageParent* a) { return true; }
+
+ virtual void ActorDestroy(ActorDestroyReason why) override {
+ if (NormalShutdown != why) fail("unexpected destruction!");
+ passed("ok");
+ QuitParent();
+ }
+};
+
+//-----------------------------------------------------------------------------
+// Child side
+
+class TestSelfManageChild : public PTestSelfManageChild {
+ friend class PTestSelfManageChild;
+
+ public:
+ MOZ_COUNTED_DEFAULT_CTOR(TestSelfManageChild)
+ MOZ_COUNTED_DTOR_OVERRIDE(TestSelfManageChild)
+
+ protected:
+ PTestSelfManageChild* AllocPTestSelfManageChild() {
+ return new TestSelfManageChild();
+ }
+
+ bool DeallocPTestSelfManageChild(PTestSelfManageChild* a) {
+ delete a;
+ return true;
+ }
+
+ virtual void ActorDestroy(ActorDestroyReason why) override {}
+};
+
+class TestSelfManageRootChild : public PTestSelfManageRootChild {
+ friend class PTestSelfManageRootChild;
+
+ public:
+ MOZ_COUNTED_DEFAULT_CTOR(TestSelfManageRootChild)
+ virtual ~TestSelfManageRootChild() {
+ MOZ_COUNT_DTOR(TestSelfManageRootChild);
+ }
+
+ void Main();
+
+ protected:
+ PTestSelfManageChild* AllocPTestSelfManageChild() {
+ return new TestSelfManageChild();
+ }
+
+ bool DeallocPTestSelfManageChild(PTestSelfManageChild* a) {
+ delete a;
+ return true;
+ }
+
+ virtual void ActorDestroy(ActorDestroyReason why) override {
+ if (NormalShutdown != why) fail("unexpected destruction!");
+ QuitChild();
+ }
+};
+
+} // namespace _ipdltest
+} // namespace mozilla
+
+#endif // ifndef mozilla__ipdltest_TestSelfManageRoot_h
diff --git a/ipc/ipdl/test/cxx/TestShmem.cpp b/ipc/ipdl/test/cxx/TestShmem.cpp
new file mode 100644
index 0000000000..0a778e5322
--- /dev/null
+++ b/ipc/ipdl/test/cxx/TestShmem.cpp
@@ -0,0 +1,106 @@
+#include "TestShmem.h"
+
+#include "IPDLUnitTests.h" // fail etc.
+
+namespace mozilla {
+namespace _ipdltest {
+
+//-----------------------------------------------------------------------------
+// Parent
+
+void TestShmemParent::Main() {
+ Shmem mem;
+ Shmem unsafe;
+
+ size_t size = 12345;
+ if (!AllocShmem(size, &mem)) fail("can't alloc shmem");
+ if (!AllocUnsafeShmem(size, &unsafe)) fail("can't alloc shmem");
+
+ if (mem.Size<char>() != size)
+ fail("shmem is wrong size: expected %lu, got %lu", size, mem.Size<char>());
+ if (unsafe.Size<char>() != size)
+ fail("shmem is wrong size: expected %lu, got %lu", size,
+ 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;
+ if (!SendGive(std::move(mem), std::move(unsafe), size))
+ fail("can't send Give()");
+
+ // 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;
+}
+
+mozilla::ipc::IPCResult TestShmemParent::RecvTake(Shmem&& mem, Shmem&& unsafe,
+ const size_t& expectedSize) {
+ if (mem.Size<char>() != expectedSize)
+ fail("expected shmem size %lu, but it has size %lu", expectedSize,
+ mem.Size<char>());
+ if (unsafe.Size<char>() != expectedSize)
+ fail("expected shmem size %lu, but it has size %lu", expectedSize,
+ unsafe.Size<char>());
+
+ if (strcmp(mem.get<char>(), "And yourself!"))
+ fail("expected message was not written");
+ if (strcmp(unsafe.get<char>(), "And yourself!"))
+ fail("expected message was not written");
+
+ if (!DeallocShmem(mem)) fail("DeallocShmem");
+ if (!DeallocShmem(unsafe)) fail("DeallocShmem");
+
+ Close();
+
+ return IPC_OK();
+}
+
+//-----------------------------------------------------------------------------
+// Child
+
+mozilla::ipc::IPCResult TestShmemChild::RecvGive(Shmem&& mem, Shmem&& unsafe,
+ const size_t& expectedSize) {
+ if (mem.Size<char>() != expectedSize)
+ fail("expected shmem size %lu, but it has size %lu", expectedSize,
+ mem.Size<char>());
+ if (unsafe.Size<char>() != expectedSize)
+ fail("expected shmem size %lu, but it has size %lu", expectedSize,
+ unsafe.Size<char>());
+
+ if (strcmp(mem.get<char>(), "Hello!"))
+ fail("expected message was not written");
+ if (strcmp(unsafe.get<char>(), "Hello!"))
+ fail("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;
+ if (!SendTake(std::move(mem), std::move(unsafe), expectedSize))
+ fail("can't send Take()");
+
+ // these checks also shouldn't fail in the child
+ char uc1 = *unsafeptr;
+ (void)uc1;
+ char uc2 = *unsafecopy.get<char>();
+ (void)uc2;
+
+ return IPC_OK();
+}
+
+} // namespace _ipdltest
+} // namespace mozilla
diff --git a/ipc/ipdl/test/cxx/TestShmem.h b/ipc/ipdl/test/cxx/TestShmem.h
new file mode 100644
index 0000000000..4ef1f4fd7b
--- /dev/null
+++ b/ipc/ipdl/test/cxx/TestShmem.h
@@ -0,0 +1,55 @@
+#ifndef mozilla__ipdltest_TestShmem_h
+#define mozilla__ipdltest_TestShmem_h
+
+#include "mozilla/_ipdltest/IPDLUnitTests.h"
+
+#include "mozilla/_ipdltest/PTestShmemParent.h"
+#include "mozilla/_ipdltest/PTestShmemChild.h"
+
+namespace mozilla {
+namespace _ipdltest {
+
+class TestShmemParent : public PTestShmemParent {
+ friend class PTestShmemParent;
+
+ public:
+ TestShmemParent() {}
+ virtual ~TestShmemParent() {}
+
+ static bool RunTestInProcesses() { return true; }
+ static bool RunTestInThreads() { return true; }
+
+ void Main();
+
+ protected:
+ mozilla::ipc::IPCResult RecvTake(Shmem&& mem, Shmem&& unsafe,
+ const size_t& expectedSize);
+
+ virtual void ActorDestroy(ActorDestroyReason why) override {
+ if (NormalShutdown != why) fail("unexpected destruction!");
+ passed("ok");
+ QuitParent();
+ }
+};
+
+class TestShmemChild : public PTestShmemChild {
+ friend class PTestShmemChild;
+
+ public:
+ TestShmemChild() {}
+ virtual ~TestShmemChild() {}
+
+ protected:
+ mozilla::ipc::IPCResult RecvGive(Shmem&& mem, Shmem&& unsafe,
+ const size_t& expectedSize);
+
+ virtual void ActorDestroy(ActorDestroyReason why) override {
+ if (NormalShutdown != why) fail("unexpected destruction!");
+ QuitChild();
+ }
+};
+
+} // namespace _ipdltest
+} // namespace mozilla
+
+#endif // ifndef mozilla__ipdltest_TestShmem_h
diff --git a/ipc/ipdl/test/cxx/TestShutdown.cpp b/ipc/ipdl/test/cxx/TestShutdown.cpp
new file mode 100644
index 0000000000..502695bd88
--- /dev/null
+++ b/ipc/ipdl/test/cxx/TestShutdown.cpp
@@ -0,0 +1,185 @@
+#include "TestShutdown.h"
+
+namespace mozilla {
+namespace _ipdltest {
+
+//-----------------------------------------------------------------------------
+// Parent side
+void TestShutdownParent::Main() {
+ if (!SendStart()) fail("sending Start()");
+}
+
+void TestShutdownParent::ActorDestroy(ActorDestroyReason why) {
+ if (AbnormalShutdown != why) fail("should have ended test with crash!");
+
+ passed("ok");
+
+ QuitParent();
+}
+
+void TestShutdownSubParent::ActorDestroy(ActorDestroyReason why) {
+ if (Manager()->ManagedPTestShutdownSubParent().Count() == 0)
+ fail("manager should still have managees!");
+
+ if (mExpectCrash && AbnormalShutdown != why)
+ fail("expected crash!");
+ else if (!mExpectCrash && AbnormalShutdown == why)
+ fail("wasn't expecting crash!");
+
+ if (mExpectCrash && 0 == ManagedPTestShutdownSubsubParent().Count())
+ fail("expected to *still* have kids");
+}
+
+void TestShutdownSubsubParent::ActorDestroy(ActorDestroyReason why) {
+ if (Manager()->ManagedPTestShutdownSubsubParent().Count() == 0)
+ fail("manager should still have managees!");
+
+ if (mExpectParentDeleted && AncestorDeletion != why)
+ fail("expected ParentDeleted == why");
+ else if (!mExpectParentDeleted && AncestorDeletion == why)
+ fail("wasn't expecting parent delete");
+}
+
+//-----------------------------------------------------------------------------
+// Child side
+
+mozilla::ipc::IPCResult TestShutdownChild::RecvStart() {
+ // test 1: alloc some actors and subactors, delete in
+ // managee-before-manager order
+ {
+ bool expectCrash = false, expectParentDeleted = false;
+
+ PTestShutdownSubChild* c1 = SendPTestShutdownSubConstructor(expectCrash);
+ if (!c1) fail("problem sending ctor");
+
+ PTestShutdownSubChild* c2 = SendPTestShutdownSubConstructor(expectCrash);
+ if (!c2) fail("problem sending ctor");
+
+ PTestShutdownSubsubChild* c1s1 =
+ c1->SendPTestShutdownSubsubConstructor(expectParentDeleted);
+ if (!c1s1) fail("problem sending ctor");
+ PTestShutdownSubsubChild* c1s2 =
+ c1->SendPTestShutdownSubsubConstructor(expectParentDeleted);
+ if (!c1s2) fail("problem sending ctor");
+
+ PTestShutdownSubsubChild* c2s1 =
+ c2->SendPTestShutdownSubsubConstructor(expectParentDeleted);
+ if (!c2s1) fail("problem sending ctor");
+ PTestShutdownSubsubChild* c2s2 =
+ c2->SendPTestShutdownSubsubConstructor(expectParentDeleted);
+ if (!c2s2) fail("problem sending ctor");
+
+ if (!PTestShutdownSubsubChild::Send__delete__(c1s1))
+ fail("problem sending dtor");
+ if (!PTestShutdownSubsubChild::Send__delete__(c1s2))
+ fail("problem sending dtor");
+ if (!PTestShutdownSubsubChild::Send__delete__(c2s1))
+ fail("problem sending dtor");
+ if (!PTestShutdownSubsubChild::Send__delete__(c2s2))
+ fail("problem sending dtor");
+
+ if (!c1->CallStackFrame()) fail("problem creating dummy stack frame");
+ if (!c2->CallStackFrame()) fail("problem creating dummy stack frame");
+ }
+
+ // test 2: alloc some actors and subactors, delete managers first
+ {
+ bool expectCrash = false, expectParentDeleted = true;
+
+ PTestShutdownSubChild* c1 = SendPTestShutdownSubConstructor(expectCrash);
+ if (!c1) fail("problem sending ctor");
+
+ PTestShutdownSubChild* c2 = SendPTestShutdownSubConstructor(expectCrash);
+ if (!c2) fail("problem sending ctor");
+
+ PTestShutdownSubsubChild* c1s1 =
+ c1->SendPTestShutdownSubsubConstructor(expectParentDeleted);
+ if (!c1s1) fail("problem sending ctor");
+ PTestShutdownSubsubChild* c1s2 =
+ c1->SendPTestShutdownSubsubConstructor(expectParentDeleted);
+ if (!c1s2) fail("problem sending ctor");
+
+ PTestShutdownSubsubChild* c2s1 =
+ c2->SendPTestShutdownSubsubConstructor(expectParentDeleted);
+ if (!c2s1) fail("problem sending ctor");
+ PTestShutdownSubsubChild* c2s2 =
+ c2->SendPTestShutdownSubsubConstructor(expectParentDeleted);
+ if (!c2s2) fail("problem sending ctor");
+
+ // delete parents without deleting kids
+ if (!c1->CallStackFrame()) fail("problem creating dummy stack frame");
+ if (!c2->CallStackFrame()) fail("problem creating dummy stack frame");
+ }
+
+ // test 3: alloc some actors and subactors, then crash
+ {
+ bool expectCrash = true, expectParentDeleted = false;
+
+ PTestShutdownSubChild* c1 = SendPTestShutdownSubConstructor(expectCrash);
+ if (!c1) fail("problem sending ctor");
+
+ PTestShutdownSubChild* c2 = SendPTestShutdownSubConstructor(expectCrash);
+ if (!c2) fail("problem sending ctor");
+
+ PTestShutdownSubsubChild* c1s1 =
+ c1->SendPTestShutdownSubsubConstructor(expectParentDeleted);
+ if (!c1s1) fail("problem sending ctor");
+ PTestShutdownSubsubChild* c1s2 =
+ c1->SendPTestShutdownSubsubConstructor(expectParentDeleted);
+ if (!c1s2) fail("problem sending ctor");
+
+ PTestShutdownSubsubChild* c2s1 =
+ c2->SendPTestShutdownSubsubConstructor(expectParentDeleted);
+ if (!c2s1) fail("problem sending ctor");
+ PTestShutdownSubsubChild* c2s2 =
+ c2->SendPTestShutdownSubsubConstructor(expectParentDeleted);
+ if (!c2s2) fail("problem sending ctor");
+
+ // make sure the ctors have been processed by the other side;
+ // the write end of the socket may temporarily be unwriteable
+ if (!SendSync()) fail("can't synchronize with parent");
+
+ // "crash", but without tripping tinderbox assert/abort
+ // detectors
+ _exit(0);
+ }
+}
+
+void TestShutdownChild::ActorDestroy(ActorDestroyReason why) {
+ fail("hey wait ... we should have crashed!");
+}
+
+mozilla::ipc::IPCResult TestShutdownSubChild::AnswerStackFrame() {
+ if (!PTestShutdownSubChild::Send__delete__(this))
+ fail("problem sending dtor");
+
+ // WATCH OUT! |this| has just deleted
+
+ return IPC_OK();
+}
+
+void TestShutdownSubChild::ActorDestroy(ActorDestroyReason why) {
+ if (Manager()->ManagedPTestShutdownSubChild().Count() == 0)
+ fail("manager should still have managees!");
+
+ if (mExpectCrash && AbnormalShutdown != why)
+ fail("expected crash!");
+ else if (!mExpectCrash && AbnormalShutdown == why)
+ fail("wasn't expecting crash!");
+
+ if (mExpectCrash && 0 == ManagedPTestShutdownSubsubChild().Count())
+ fail("expected to *still* have kids");
+}
+
+void TestShutdownSubsubChild::ActorDestroy(ActorDestroyReason why) {
+ if (Manager()->ManagedPTestShutdownSubsubChild().Count() == 0)
+ fail("manager should still have managees!");
+
+ if (mExpectParentDeleted && AncestorDeletion != why)
+ fail("expected ParentDeleted == why");
+ else if (!mExpectParentDeleted && AncestorDeletion == why)
+ fail("wasn't expecting parent delete");
+}
+
+} // namespace _ipdltest
+} // namespace mozilla
diff --git a/ipc/ipdl/test/cxx/TestShutdown.h b/ipc/ipdl/test/cxx/TestShutdown.h
new file mode 100644
index 0000000000..224e42496d
--- /dev/null
+++ b/ipc/ipdl/test/cxx/TestShutdown.h
@@ -0,0 +1,168 @@
+#ifndef mozilla__ipdltest_TestShutdown_h
+#define mozilla__ipdltest_TestShutdown_h 1
+
+#include "mozilla/_ipdltest/IPDLUnitTests.h"
+
+#include "mozilla/_ipdltest/PTestShutdownParent.h"
+#include "mozilla/_ipdltest/PTestShutdownChild.h"
+
+#include "mozilla/_ipdltest/PTestShutdownSubParent.h"
+#include "mozilla/_ipdltest/PTestShutdownSubChild.h"
+
+#include "mozilla/_ipdltest/PTestShutdownSubsubParent.h"
+#include "mozilla/_ipdltest/PTestShutdownSubsubChild.h"
+
+namespace mozilla {
+namespace _ipdltest {
+
+//-----------------------------------------------------------------------------
+// Parent side
+
+class TestShutdownSubsubParent : public PTestShutdownSubsubParent {
+ public:
+ explicit TestShutdownSubsubParent(bool expectParentDeleted)
+ : mExpectParentDeleted(expectParentDeleted) {}
+
+ virtual ~TestShutdownSubsubParent() {}
+
+ protected:
+ virtual void ActorDestroy(ActorDestroyReason why) override;
+
+ private:
+ bool mExpectParentDeleted;
+};
+
+class TestShutdownSubParent : public PTestShutdownSubParent {
+ friend class PTestShutdownSubParent;
+
+ public:
+ explicit TestShutdownSubParent(bool expectCrash)
+ : mExpectCrash(expectCrash), mDeletedCount(0) {}
+
+ virtual ~TestShutdownSubParent() {
+ if (2 != mDeletedCount) fail("managees outliving manager!");
+ }
+
+ protected:
+ mozilla::ipc::IPCResult AnswerStackFrame() {
+ if (!CallStackFrame()) {
+ return IPC_FAIL_NO_REASON(this);
+ }
+ return IPC_OK();
+ }
+
+ PTestShutdownSubsubParent* AllocPTestShutdownSubsubParent(
+ const bool& expectParentDelete) {
+ return new TestShutdownSubsubParent(expectParentDelete);
+ }
+
+ bool DeallocPTestShutdownSubsubParent(PTestShutdownSubsubParent* actor) {
+ delete actor;
+ ++mDeletedCount;
+ return true;
+ }
+
+ virtual void ActorDestroy(ActorDestroyReason why) override;
+
+ private:
+ bool mExpectCrash;
+ int mDeletedCount;
+};
+
+class TestShutdownParent : public PTestShutdownParent {
+ friend class PTestShutdownParent;
+
+ public:
+ TestShutdownParent() {}
+ virtual ~TestShutdownParent() {}
+
+ static bool RunTestInProcesses() { return true; }
+ // FIXME/bug 703323 Could work if modified
+ static bool RunTestInThreads() { return false; }
+
+ void Main();
+
+ protected:
+ mozilla::ipc::IPCResult RecvSync() { return IPC_OK(); }
+
+ PTestShutdownSubParent* AllocPTestShutdownSubParent(const bool& expectCrash) {
+ return new TestShutdownSubParent(expectCrash);
+ }
+
+ bool DeallocPTestShutdownSubParent(PTestShutdownSubParent* actor) {
+ delete actor;
+ return true;
+ }
+
+ virtual void ActorDestroy(ActorDestroyReason why) override;
+};
+
+//-----------------------------------------------------------------------------
+// Child side
+
+class TestShutdownSubsubChild : public PTestShutdownSubsubChild {
+ public:
+ explicit TestShutdownSubsubChild(bool expectParentDeleted)
+ : mExpectParentDeleted(expectParentDeleted) {}
+ virtual ~TestShutdownSubsubChild() {}
+
+ protected:
+ virtual void ActorDestroy(ActorDestroyReason why) override;
+
+ private:
+ bool mExpectParentDeleted;
+};
+
+class TestShutdownSubChild : public PTestShutdownSubChild {
+ friend class PTestShutdownSubChild;
+
+ public:
+ explicit TestShutdownSubChild(bool expectCrash) : mExpectCrash(expectCrash) {}
+
+ virtual ~TestShutdownSubChild() {}
+
+ protected:
+ mozilla::ipc::IPCResult AnswerStackFrame();
+
+ PTestShutdownSubsubChild* AllocPTestShutdownSubsubChild(
+ const bool& expectParentDelete) {
+ return new TestShutdownSubsubChild(expectParentDelete);
+ }
+
+ bool DeallocPTestShutdownSubsubChild(PTestShutdownSubsubChild* actor) {
+ delete actor;
+ return true;
+ }
+
+ virtual void ActorDestroy(ActorDestroyReason why) override;
+
+ private:
+ bool mExpectCrash;
+};
+
+class TestShutdownChild : public PTestShutdownChild {
+ friend class PTestShutdownChild;
+
+ public:
+ TestShutdownChild() {}
+ virtual ~TestShutdownChild() {}
+
+ protected:
+ mozilla::ipc::IPCResult RecvStart();
+
+ PTestShutdownSubChild* AllocPTestShutdownSubChild(const bool& expectCrash) {
+ return new TestShutdownSubChild(expectCrash);
+ }
+
+ bool DeallocPTestShutdownSubChild(PTestShutdownSubChild* actor) {
+ delete actor;
+ return true;
+ }
+
+ virtual void ActorDestroy(ActorDestroyReason why) override;
+};
+
+} // namespace _ipdltest
+} // namespace mozilla
+
+#endif // ifndef mozilla__ipdltest_TestShutdown_h
diff --git a/ipc/ipdl/test/cxx/TestStackHooks.cpp b/ipc/ipdl/test/cxx/TestStackHooks.cpp
new file mode 100644
index 0000000000..9800ac54e7
--- /dev/null
+++ b/ipc/ipdl/test/cxx/TestStackHooks.cpp
@@ -0,0 +1,122 @@
+#include "TestStackHooks.h"
+
+#include "base/task.h"
+#include "IPDLUnitTests.h" // fail etc.
+
+namespace mozilla {
+namespace _ipdltest {
+
+//-----------------------------------------------------------------------------
+// parent
+
+TestStackHooksParent::TestStackHooksParent()
+ : mOnStack(false), mIncallDepth(0) {
+ MOZ_COUNT_CTOR(TestStackHooksParent);
+}
+
+TestStackHooksParent::~TestStackHooksParent() {
+ MOZ_COUNT_DTOR(TestStackHooksParent);
+}
+
+void TestStackHooksParent::Main() {
+ if (!SendStart()) fail("sending Start()");
+}
+
+mozilla::ipc::IPCResult TestStackHooksParent::AnswerStackFrame() {
+ if (!mOnStack) fail("not on C++ stack?!");
+
+ if (!CallStackFrame()) fail("calling StackFrame()");
+
+ if (!mOnStack) fail("not on C++ stack?!");
+
+ if (1 != mIncallDepth) fail("missed EnteredCall or ExitedCall hook");
+
+ return IPC_OK();
+}
+
+//-----------------------------------------------------------------------------
+// child
+
+TestStackHooksChild::TestStackHooksChild()
+ : mOnStack(false),
+ mEntered(0),
+ mExited(0),
+ mIncallDepth(0),
+ mNumAnswerStackFrame(0) {
+ MOZ_COUNT_CTOR(TestStackHooksChild);
+}
+
+TestStackHooksChild::~TestStackHooksChild() {
+ MOZ_COUNT_DTOR(TestStackHooksChild);
+}
+
+namespace {
+void RunTestsFn() {
+ static_cast<TestStackHooksChild*>(gChildActor)->RunTests();
+}
+} // namespace
+
+mozilla::ipc::IPCResult TestStackHooksChild::RecvStart() {
+ if (!mOnStack) fail("missed stack notification");
+
+ if (0 != mIncallDepth) fail("EnteredCall/ExitedCall malfunction");
+
+ // kick off tests from a runnable so that we can start with
+ // MessageChannel code on the C++ stack
+ MessageLoop::current()->PostTask(
+ NewRunnableFunction("RunTestsFn", RunTestsFn));
+
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult TestStackHooksChild::AnswerStackFrame() {
+ ++mNumAnswerStackFrame;
+
+ if (!mOnStack) fail("missed stack notification");
+
+ if (1 != mIncallDepth) fail("missed EnteredCall or ExitedCall hook");
+
+ if (mNumAnswerStackFrame == 1) {
+ if (!SendAsync()) fail("sending Async()");
+ } else if (mNumAnswerStackFrame == 2) {
+ if (!SendSync()) fail("sending Sync()");
+ } else {
+ fail("unexpected state");
+ }
+
+ if (!mOnStack) fail("bad stack exit notification");
+
+ return IPC_OK();
+}
+
+void TestStackHooksChild::RunTests() {
+ // 1 because of RecvStart()
+ if (1 != mEntered) fail("missed stack notification");
+ if (mOnStack) fail("spurious stack notification");
+ if (0 != mIncallDepth) fail("EnteredCall/ExitedCall malfunction");
+
+ if (!SendAsync()) fail("sending Async()");
+ if (mOnStack) fail("spurious stack notification");
+ if (0 != mIncallDepth) fail("EnteredCall/ExitedCall malfunction");
+ if (2 != mEntered) fail("missed stack notification");
+
+ if (!SendSync()) fail("sending Sync()");
+ if (mOnStack) fail("spurious stack notification");
+ if (0 != mIncallDepth) fail("EnteredCall/ExitedCall malfunction");
+ if (3 != mEntered) fail("missed stack notification");
+
+ if (!CallRpc()) fail("calling RPC()");
+ if (mOnStack) fail("spurious stack notification");
+ if (0 != mIncallDepth) fail("EnteredCall/ExitedCall malfunction");
+ if (4 != mEntered) fail("missed stack notification");
+
+ if (!CallStackFrame()) fail("calling StackFrame()");
+ if (mOnStack) fail("spurious stack notification");
+ if (0 != mIncallDepth) fail("EnteredCall/ExitedCall malfunction");
+ if (5 != mEntered) fail("missed stack notification");
+
+ Close();
+}
+
+} // namespace _ipdltest
+} // namespace mozilla
diff --git a/ipc/ipdl/test/cxx/TestStackHooks.h b/ipc/ipdl/test/cxx/TestStackHooks.h
new file mode 100644
index 0000000000..315a3c1ae5
--- /dev/null
+++ b/ipc/ipdl/test/cxx/TestStackHooks.h
@@ -0,0 +1,107 @@
+#ifndef mozilla__ipdltest_TestStackHooks_h
+#define mozilla__ipdltest_TestStackHooks_h 1
+
+#include "mozilla/_ipdltest/IPDLUnitTests.h"
+
+#include "mozilla/_ipdltest/PTestStackHooksParent.h"
+#include "mozilla/_ipdltest/PTestStackHooksChild.h"
+
+namespace mozilla {
+namespace _ipdltest {
+
+class TestStackHooksParent : public PTestStackHooksParent {
+ friend class PTestStackHooksParent;
+
+ public:
+ TestStackHooksParent();
+ virtual ~TestStackHooksParent();
+
+ static bool RunTestInProcesses() { return true; }
+ static bool RunTestInThreads() { return true; }
+
+ void Main();
+
+ protected:
+ mozilla::ipc::IPCResult RecvAsync() {
+ if (!mOnStack) fail("not on C++ stack?!");
+ return IPC_OK();
+ }
+
+ mozilla::ipc::IPCResult RecvSync() {
+ if (!mOnStack) fail("not on C++ stack?!");
+ return IPC_OK();
+ }
+
+ mozilla::ipc::IPCResult AnswerRpc() {
+ if (!mOnStack) fail("not on C++ stack?!");
+ return IPC_OK();
+ }
+
+ mozilla::ipc::IPCResult AnswerStackFrame();
+
+ virtual void ActorDestroy(ActorDestroyReason why) override {
+ if (NormalShutdown != why) fail("unexpected destruction!");
+ passed("ok");
+ QuitParent();
+ }
+
+ virtual void EnteredCxxStack() override { mOnStack = true; }
+ virtual void ExitedCxxStack() override { mOnStack = false; }
+
+ virtual void EnteredCall() override { ++mIncallDepth; }
+ virtual void ExitedCall() override { --mIncallDepth; }
+
+ private:
+ bool mOnStack;
+ int mIncallDepth;
+};
+
+class TestStackHooksChild : public PTestStackHooksChild {
+ friend class PTestStackHooksChild;
+
+ public:
+ TestStackHooksChild();
+ virtual ~TestStackHooksChild();
+
+ void RunTests();
+
+ protected:
+ mozilla::ipc::IPCResult RecvStart();
+
+ mozilla::ipc::IPCResult AnswerStackFrame();
+
+ virtual void ActorDestroy(ActorDestroyReason why) override {
+ if (NormalShutdown != why) fail("unexpected destruction!");
+
+ if (mEntered != mExited) fail("unbalanced enter/exit notifications");
+
+ if (mOnStack)
+ fail("computing mOnStack went awry; should have failed above assertion");
+
+ QuitChild();
+ }
+
+ virtual void EnteredCxxStack() override {
+ ++mEntered;
+ mOnStack = true;
+ }
+ virtual void ExitedCxxStack() override {
+ ++mExited;
+ mOnStack = false;
+ }
+
+ virtual void EnteredCall() override { ++mIncallDepth; }
+ virtual void ExitedCall() override { --mIncallDepth; }
+
+ private:
+ bool mOnStack;
+ int mEntered;
+ int mExited;
+ int mIncallDepth;
+ int32_t mNumAnswerStackFrame;
+};
+
+} // namespace _ipdltest
+} // namespace mozilla
+
+#endif // ifndef mozilla__ipdltest_TestStackHooks_h
diff --git a/ipc/ipdl/test/cxx/TestSyncError.cpp b/ipc/ipdl/test/cxx/TestSyncError.cpp
new file mode 100644
index 0000000000..6c21590a87
--- /dev/null
+++ b/ipc/ipdl/test/cxx/TestSyncError.cpp
@@ -0,0 +1,45 @@
+#include "TestSyncError.h"
+
+#include "IPDLUnitTests.h" // fail etc.
+
+namespace mozilla {
+namespace _ipdltest {
+
+//-----------------------------------------------------------------------------
+// parent
+
+TestSyncErrorParent::TestSyncErrorParent() {
+ MOZ_COUNT_CTOR(TestSyncErrorParent);
+}
+
+TestSyncErrorParent::~TestSyncErrorParent() {
+ MOZ_COUNT_DTOR(TestSyncErrorParent);
+}
+
+void TestSyncErrorParent::Main() {
+ if (!SendStart()) fail("sending Start");
+}
+
+mozilla::ipc::IPCResult TestSyncErrorParent::RecvError() {
+ return IPC_FAIL_NO_REASON(this);
+}
+
+//-----------------------------------------------------------------------------
+// child
+
+TestSyncErrorChild::TestSyncErrorChild() { MOZ_COUNT_CTOR(TestSyncErrorChild); }
+
+TestSyncErrorChild::~TestSyncErrorChild() {
+ MOZ_COUNT_DTOR(TestSyncErrorChild);
+}
+
+mozilla::ipc::IPCResult TestSyncErrorChild::RecvStart() {
+ if (SendError()) fail("Error() should have return false");
+
+ Close();
+
+ return IPC_OK();
+}
+
+} // namespace _ipdltest
+} // namespace mozilla
diff --git a/ipc/ipdl/test/cxx/TestSyncError.h b/ipc/ipdl/test/cxx/TestSyncError.h
new file mode 100644
index 0000000000..8b84ed5e0b
--- /dev/null
+++ b/ipc/ipdl/test/cxx/TestSyncError.h
@@ -0,0 +1,61 @@
+#ifndef mozilla__ipdltest_TestSyncError_h
+#define mozilla__ipdltest_TestSyncError_h 1
+
+#include "mozilla/_ipdltest/IPDLUnitTests.h"
+
+#include "mozilla/_ipdltest/PTestSyncErrorParent.h"
+#include "mozilla/_ipdltest/PTestSyncErrorChild.h"
+
+namespace mozilla {
+namespace _ipdltest {
+
+class TestSyncErrorParent : public PTestSyncErrorParent {
+ friend class PTestSyncErrorParent;
+
+ public:
+ TestSyncErrorParent();
+ virtual ~TestSyncErrorParent();
+
+ static bool RunTestInProcesses() { return true; }
+ static bool RunTestInThreads() { return true; }
+
+ void Main();
+
+ protected:
+ mozilla::ipc::IPCResult RecvError();
+
+ virtual void ProcessingError(Result aCode, const char* aReason) override {
+ // Ignore errors
+ }
+
+ virtual void ActorDestroy(ActorDestroyReason why) override {
+ if (NormalShutdown != why) fail("unexpected destruction!");
+ passed("ok");
+ QuitParent();
+ }
+};
+
+class TestSyncErrorChild : public PTestSyncErrorChild {
+ friend class PTestSyncErrorChild;
+
+ public:
+ TestSyncErrorChild();
+ virtual ~TestSyncErrorChild();
+
+ protected:
+ mozilla::ipc::IPCResult RecvStart();
+
+ virtual void ProcessingError(Result aCode, const char* aReason) override {
+ // Ignore errors
+ }
+
+ virtual void ActorDestroy(ActorDestroyReason why) override {
+ if (NormalShutdown != why) fail("unexpected destruction!");
+ QuitChild();
+ }
+};
+
+} // namespace _ipdltest
+} // namespace mozilla
+
+#endif // ifndef mozilla__ipdltest_TestSyncError_h
diff --git a/ipc/ipdl/test/cxx/TestSyncHang.cpp b/ipc/ipdl/test/cxx/TestSyncHang.cpp
new file mode 100644
index 0000000000..f53054787b
--- /dev/null
+++ b/ipc/ipdl/test/cxx/TestSyncHang.cpp
@@ -0,0 +1,62 @@
+#include "TestSyncHang.h"
+#include "base/task.h"
+#include "mozilla/ipc/GeckoChildProcessHost.h"
+
+#include "IPDLUnitTests.h" // fail etc.
+
+using std::string;
+using std::vector;
+
+namespace mozilla {
+namespace _ipdltest {
+
+//-----------------------------------------------------------------------------
+// parent
+
+mozilla::ipc::GeckoChildProcessHost* gSyncHangSubprocess;
+
+TestSyncHangParent::TestSyncHangParent() { MOZ_COUNT_CTOR(TestSyncHangParent); }
+
+TestSyncHangParent::~TestSyncHangParent() {
+ MOZ_COUNT_DTOR(TestSyncHangParent);
+}
+
+void DeleteSyncHangSubprocess(MessageLoop* uiLoop) {
+ gSyncHangSubprocess->Destroy();
+ gSyncHangSubprocess = nullptr;
+}
+
+void DeferredSyncHangParentShutdown() {
+ // ping to DeleteSubprocess
+ XRE_GetIOMessageLoop()->PostTask(
+ NewRunnableFunction("DeleteSyncHangSubprocess", DeleteSyncHangSubprocess,
+ MessageLoop::current()));
+}
+
+void TestSyncHangParent::Main() {
+ vector<string> args;
+ args.push_back("fake/path");
+ gSyncHangSubprocess =
+ new mozilla::ipc::GeckoChildProcessHost(GeckoProcessType_Plugin);
+ bool launched = gSyncHangSubprocess->SyncLaunch(args, 2);
+ if (launched)
+ fail("Calling SyncLaunch with an invalid path should return false");
+
+ MessageLoop::current()->PostTask(NewRunnableFunction(
+ "DeferredSyncHangParentShutdown", DeferredSyncHangParentShutdown));
+ Close();
+}
+
+//-----------------------------------------------------------------------------
+// child
+
+TestSyncHangChild::TestSyncHangChild() { MOZ_COUNT_CTOR(TestSyncHangChild); }
+
+TestSyncHangChild::~TestSyncHangChild() { MOZ_COUNT_DTOR(TestSyncHangChild); }
+
+mozilla::ipc::IPCResult TestSyncHangChild::RecvUnusedMessage() {
+ return IPC_OK();
+}
+
+} // namespace _ipdltest
+} // namespace mozilla
diff --git a/ipc/ipdl/test/cxx/TestSyncHang.h b/ipc/ipdl/test/cxx/TestSyncHang.h
new file mode 100644
index 0000000000..911f05cd31
--- /dev/null
+++ b/ipc/ipdl/test/cxx/TestSyncHang.h
@@ -0,0 +1,50 @@
+#ifndef mozilla__ipdltest_TestSyncHang_h
+#define mozilla__ipdltest_TestSyncHang_h 1
+
+#include "mozilla/_ipdltest/IPDLUnitTests.h"
+
+#include "mozilla/_ipdltest/PTestSyncHangParent.h"
+#include "mozilla/_ipdltest/PTestSyncHangChild.h"
+
+namespace mozilla {
+namespace _ipdltest {
+
+class TestSyncHangParent : public PTestSyncHangParent {
+ public:
+ TestSyncHangParent();
+ virtual ~TestSyncHangParent();
+
+ static bool RunTestInProcesses() { return true; }
+ // FIXME/bug 703323 Could work if modified
+ static bool RunTestInThreads() { return false; }
+
+ void Main();
+
+ protected:
+ virtual void ActorDestroy(ActorDestroyReason why) override {
+ if (NormalShutdown != why) fail("unexpected destruction!");
+ passed("ok");
+ QuitParent();
+ }
+};
+
+class TestSyncHangChild : public PTestSyncHangChild {
+ friend class PTestSyncHangChild;
+
+ public:
+ TestSyncHangChild();
+ virtual ~TestSyncHangChild();
+
+ protected:
+ mozilla::ipc::IPCResult RecvUnusedMessage();
+
+ virtual void ActorDestroy(ActorDestroyReason why) override {
+ if (NormalShutdown != why) fail("unexpected destruction!");
+ QuitChild();
+ }
+};
+
+} // namespace _ipdltest
+} // namespace mozilla
+
+#endif // ifndef mozilla__ipdltest_TestSyncHang_h
diff --git a/ipc/ipdl/test/cxx/TestSyncWakeup.cpp b/ipc/ipdl/test/cxx/TestSyncWakeup.cpp
new file mode 100644
index 0000000000..90875b702b
--- /dev/null
+++ b/ipc/ipdl/test/cxx/TestSyncWakeup.cpp
@@ -0,0 +1,106 @@
+#if defined(XP_UNIX)
+# include <unistd.h> // sleep()
+#endif
+
+#include "TestSyncWakeup.h"
+
+#include "IPDLUnitTests.h" // fail etc.
+
+namespace mozilla {
+namespace _ipdltest {
+
+//-----------------------------------------------------------------------------
+// parent
+
+TestSyncWakeupParent::TestSyncWakeupParent() {
+ MOZ_COUNT_CTOR(TestSyncWakeupParent);
+}
+
+TestSyncWakeupParent::~TestSyncWakeupParent() {
+ MOZ_COUNT_DTOR(TestSyncWakeupParent);
+}
+
+void TestSyncWakeupParent::Main() {
+ if (!SendStart()) fail("sending Start()");
+}
+
+mozilla::ipc::IPCResult TestSyncWakeupParent::AnswerStackFrame() {
+ if (!CallStackFrame()) fail("calling StackFrame()");
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult TestSyncWakeupParent::RecvSync1() {
+ if (!SendNote1()) fail("sending Note1()");
+
+ // XXX ugh ... need to ensure that the async message and sync
+ // reply come in "far enough" apart that this test doesn't pass on
+ // accident
+#if defined(XP_UNIX)
+ // NB: can't use PR_Sleep (i.e. Sleep() on windows) because it's
+ // only spec'd to block the current thread, not the current
+ // process. We need the IO thread to sleep as well.
+ puts(" (sleeping for 5 seconds. sorry!)");
+ sleep(5);
+#endif
+
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult TestSyncWakeupParent::RecvSync2() {
+ if (!SendNote2()) fail("sending Note2()");
+
+#if defined(XP_UNIX)
+ // see above
+ sleep(5);
+ puts(" (sleeping for 5 seconds. sorry!)");
+#endif
+
+ return IPC_OK();
+}
+
+//-----------------------------------------------------------------------------
+// child
+
+TestSyncWakeupChild::TestSyncWakeupChild() : mDone(false) {
+ MOZ_COUNT_CTOR(TestSyncWakeupChild);
+}
+
+TestSyncWakeupChild::~TestSyncWakeupChild() {
+ MOZ_COUNT_DTOR(TestSyncWakeupChild);
+}
+
+mozilla::ipc::IPCResult TestSyncWakeupChild::RecvStart() {
+ // First test: the parent fires back an async message while
+ // replying to a sync one
+ if (!SendSync1()) fail("sending Sync()");
+
+ // drop back into the event loop to get Note1(), then kick off the
+ // second test
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult TestSyncWakeupChild::RecvNote1() {
+ // Second test: the parent fires back an async message while
+ // replying to a sync one, with a frame on the RPC stack
+ if (!CallStackFrame()) fail("calling StackFrame()");
+
+ if (!mDone) fail("should have received Note2()!");
+
+ Close();
+
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult TestSyncWakeupChild::AnswerStackFrame() {
+ if (!SendSync2()) fail("sending Sync()");
+
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult TestSyncWakeupChild::RecvNote2() {
+ mDone = true;
+ return IPC_OK();
+}
+
+} // namespace _ipdltest
+} // namespace mozilla
diff --git a/ipc/ipdl/test/cxx/TestSyncWakeup.h b/ipc/ipdl/test/cxx/TestSyncWakeup.h
new file mode 100644
index 0000000000..5666307929
--- /dev/null
+++ b/ipc/ipdl/test/cxx/TestSyncWakeup.h
@@ -0,0 +1,66 @@
+#ifndef mozilla__ipdltest_TestSyncWakeup_h
+#define mozilla__ipdltest_TestSyncWakeup_h 1
+
+#include "mozilla/_ipdltest/IPDLUnitTests.h"
+
+#include "mozilla/_ipdltest/PTestSyncWakeupParent.h"
+#include "mozilla/_ipdltest/PTestSyncWakeupChild.h"
+
+namespace mozilla {
+namespace _ipdltest {
+
+class TestSyncWakeupParent : public PTestSyncWakeupParent {
+ friend class PTestSyncWakeupParent;
+
+ public:
+ TestSyncWakeupParent();
+ virtual ~TestSyncWakeupParent();
+
+ static bool RunTestInProcesses() { return true; }
+ static bool RunTestInThreads() { return true; }
+
+ void Main();
+
+ protected:
+ mozilla::ipc::IPCResult AnswerStackFrame();
+
+ mozilla::ipc::IPCResult RecvSync1();
+
+ mozilla::ipc::IPCResult RecvSync2();
+
+ virtual void ActorDestroy(ActorDestroyReason why) override {
+ if (NormalShutdown != why) fail("unexpected destruction!");
+ passed("ok");
+ QuitParent();
+ }
+};
+
+class TestSyncWakeupChild : public PTestSyncWakeupChild {
+ friend class PTestSyncWakeupChild;
+
+ public:
+ TestSyncWakeupChild();
+ virtual ~TestSyncWakeupChild();
+
+ protected:
+ mozilla::ipc::IPCResult RecvStart();
+
+ mozilla::ipc::IPCResult RecvNote1();
+
+ mozilla::ipc::IPCResult AnswerStackFrame();
+
+ mozilla::ipc::IPCResult RecvNote2();
+
+ virtual void ActorDestroy(ActorDestroyReason why) override {
+ if (NormalShutdown != why) fail("unexpected destruction!");
+ QuitChild();
+ }
+
+ private:
+ bool mDone;
+};
+
+} // namespace _ipdltest
+} // namespace mozilla
+
+#endif // ifndef mozilla__ipdltest_TestSyncWakeup_h
diff --git a/ipc/ipdl/test/cxx/TestUniquePtrIPC.cpp b/ipc/ipdl/test/cxx/TestUniquePtrIPC.cpp
new file mode 100644
index 0000000000..7d0e8dd6ca
--- /dev/null
+++ b/ipc/ipdl/test/cxx/TestUniquePtrIPC.cpp
@@ -0,0 +1,81 @@
+/* -*- 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/. */
+
+#include "TestUniquePtrIPC.h"
+
+namespace mozilla {
+namespace _ipdltest {
+
+// ---------------------------------------------------------------------------
+// PARENT PROCESS
+// ---------------------------------------------------------------------------
+
+void TestUniquePtrIPCParent::Main() {
+ UniquePtr<int> a1 = MakeUnique<int>(1);
+ UniquePtr<DummyStruct> a2 = MakeUnique<DummyStruct>(2);
+ DummyStruct a3(3);
+ UniquePtr<int> a4;
+
+ if (!SendTestMessage(std::move(a1), std::move(a2), a3, std::move(a4))) {
+ fail("failed sending UniquePtr items");
+ }
+
+ if (a1 || a2) {
+ fail("did not move TestMessage items in parent");
+ }
+
+ if (a4) {
+ fail("somehow turned null ptr into non-null by sending it");
+ }
+
+ // Pass UniquePtr by reference
+ UniquePtr<DummyStruct> b = MakeUnique<DummyStruct>(1);
+
+ if (!SendTestSendReference(std::move(b))) {
+ fail("failed sending UniquePtr by reference");
+ }
+ if (b) {
+ fail("did not move UniquePtr sent by reference");
+ }
+}
+
+// ---------------------------------------------------------------------------
+// CHILD PROCESS
+// ---------------------------------------------------------------------------
+
+mozilla::ipc::IPCResult TestUniquePtrIPCChild::RecvTestMessage(
+ UniquePtr<int>&& aA1, UniquePtr<DummyStruct>&& aA2, const DummyStruct& aA3,
+ UniquePtr<int>&& aA4) {
+ if ((!aA1) || (!aA2)) {
+ fail("TestMessage received NULL items in child");
+ }
+
+ if (aA4) {
+ fail("TestMessage received non-NULL when expecting NULL");
+ }
+
+ if ((*aA1 != 1) || (aA2->x() != 2) || (aA3.x() != 3)) {
+ fail("TestMessage received incorrect items in child");
+ }
+
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult TestUniquePtrIPCChild::RecvTestSendReference(
+ UniquePtr<DummyStruct>&& aA) {
+ if (!aA) {
+ fail("TestSendReference received NULL item in child");
+ }
+
+ if (*aA != 1) {
+ fail("TestSendReference received incorrect item in child");
+ }
+
+ Close();
+ return IPC_OK();
+}
+
+} // namespace _ipdltest
+} // namespace mozilla
diff --git a/ipc/ipdl/test/cxx/TestUniquePtrIPC.h b/ipc/ipdl/test/cxx/TestUniquePtrIPC.h
new file mode 100644
index 0000000000..3c9de33df3
--- /dev/null
+++ b/ipc/ipdl/test/cxx/TestUniquePtrIPC.h
@@ -0,0 +1,61 @@
+/* -*- 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/. */
+
+#ifndef mozilla_TestUniquePtrIPC_h
+#define mozilla_TestUniquePtrIPC_h
+
+#include "mozilla/_ipdltest/IPDLUnitTests.h"
+
+#include "mozilla/_ipdltest/PTestUniquePtrIPCParent.h"
+#include "mozilla/_ipdltest/PTestUniquePtrIPCChild.h"
+
+namespace mozilla {
+namespace _ipdltest {
+
+class TestUniquePtrIPCParent : public PTestUniquePtrIPCParent {
+ public:
+ MOZ_COUNTED_DEFAULT_CTOR(TestUniquePtrIPCParent)
+ MOZ_COUNTED_DTOR_OVERRIDE(TestUniquePtrIPCParent)
+
+ static bool RunTestInProcesses() { return true; }
+ static bool RunTestInThreads() { return false; }
+
+ void Main();
+
+ bool ShouldContinueFromReplyTimeout() override { return false; }
+
+ virtual void ActorDestroy(ActorDestroyReason why) override {
+ if (NormalShutdown != why) {
+ fail("Abnormal shutdown of parent");
+ }
+ passed("ok");
+ QuitParent();
+ }
+};
+
+class TestUniquePtrIPCChild : public PTestUniquePtrIPCChild {
+ public:
+ MOZ_COUNTED_DEFAULT_CTOR(TestUniquePtrIPCChild)
+ MOZ_COUNTED_DTOR_OVERRIDE(TestUniquePtrIPCChild)
+
+ mozilla::ipc::IPCResult RecvTestMessage(UniquePtr<int>&& aA1,
+ UniquePtr<DummyStruct>&& aA2,
+ const DummyStruct& aA3,
+ UniquePtr<int>&& aA4);
+
+ mozilla::ipc::IPCResult RecvTestSendReference(UniquePtr<DummyStruct>&& aA);
+
+ virtual void ActorDestroy(ActorDestroyReason why) override {
+ if (NormalShutdown != why) {
+ fail("Abnormal shutdown of child");
+ }
+ QuitChild();
+ }
+};
+
+} // namespace _ipdltest
+} // namespace mozilla
+
+#endif // mozilla_TestUniquePtrIPC_h
diff --git a/ipc/ipdl/test/cxx/TestUrgency.cpp b/ipc/ipdl/test/cxx/TestUrgency.cpp
new file mode 100644
index 0000000000..840b9d71e9
--- /dev/null
+++ b/ipc/ipdl/test/cxx/TestUrgency.cpp
@@ -0,0 +1,117 @@
+#include "TestUrgency.h"
+
+#include "IPDLUnitTests.h" // fail etc.
+#if defined(XP_UNIX)
+# include <unistd.h>
+#else
+# include <windows.h>
+#endif
+
+namespace mozilla {
+namespace _ipdltest {
+
+#if defined(XP_UNIX)
+static void Sleep(int ms) { sleep(ms / 1000); }
+#endif
+
+//-----------------------------------------------------------------------------
+// parent
+
+TestUrgencyParent::TestUrgencyParent() : inreply_(false) {
+ MOZ_COUNT_CTOR(TestUrgencyParent);
+}
+
+TestUrgencyParent::~TestUrgencyParent() { MOZ_COUNT_DTOR(TestUrgencyParent); }
+
+void TestUrgencyParent::Main() {
+ if (!SendStart()) fail("sending Start");
+}
+
+mozilla::ipc::IPCResult TestUrgencyParent::RecvTest1(uint32_t* value) {
+ if (!SendReply1(value)) fail("sending Reply1");
+ if (*value != 99) fail("bad value");
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult TestUrgencyParent::RecvTest2() {
+ uint32_t value;
+ inreply_ = true;
+ if (!SendReply2(&value)) fail("sending Reply2");
+ inreply_ = false;
+ if (value != 500) fail("bad value");
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult TestUrgencyParent::RecvTest3(uint32_t* value) {
+ if (inreply_) fail("nested non-urgent on top of urgent rpc");
+ *value = 1000;
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult TestUrgencyParent::RecvFinalTest_Begin() {
+ return IPC_OK();
+}
+
+//-----------------------------------------------------------------------------
+// child
+
+enum {
+ kFirstTestBegin = 1,
+ kFirstTestGotReply,
+ kSecondTestBegin,
+ kSecondTestGotReply,
+};
+
+mozilla::ipc::IPCResult TestUrgencyChild::RecvStart() {
+ uint32_t result;
+
+ // Send a synchronous message, expect to get an urgent message while
+ // blocked.
+ test_ = kFirstTestBegin;
+ if (!SendTest1(&result)) fail("calling SendTest1");
+ if (result != 99) fail("bad result in RecvStart");
+ if (test_ != kFirstTestGotReply) fail("never received 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;
+ if (!SendTest2()) fail("calling SendTest2");
+ if (!SendTest3(&result)) fail("calling SendTest3");
+ if (test_ != kSecondTestGotReply) fail("never received urgent message #2");
+ if (result != 1000) fail("wrong value from test3");
+
+ if (!SendFinalTest_Begin()) fail("Final test should have succeeded");
+
+ Close();
+
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult TestUrgencyChild::RecvReply1(uint32_t* reply) {
+ if (test_ != kFirstTestBegin) fail("wrong test # in RecvReply1");
+
+ *reply = 99;
+ test_ = kFirstTestGotReply;
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult TestUrgencyChild::RecvReply2(uint32_t* reply) {
+ if (test_ != kSecondTestBegin) fail("wrong test # in RecvReply2");
+
+ // sleep for 5 seconds so the parent process tries to deliver more messages.
+ Sleep(5000);
+
+ *reply = 500;
+ test_ = kSecondTestGotReply;
+ return IPC_OK();
+}
+
+TestUrgencyChild::TestUrgencyChild() : test_(0) {
+ MOZ_COUNT_CTOR(TestUrgencyChild);
+}
+
+TestUrgencyChild::~TestUrgencyChild() { MOZ_COUNT_DTOR(TestUrgencyChild); }
+
+} // namespace _ipdltest
+} // namespace mozilla
diff --git a/ipc/ipdl/test/cxx/TestUrgency.h b/ipc/ipdl/test/cxx/TestUrgency.h
new file mode 100644
index 0000000000..6af73177ee
--- /dev/null
+++ b/ipc/ipdl/test/cxx/TestUrgency.h
@@ -0,0 +1,57 @@
+#ifndef mozilla__ipdltest_TestUrgency_h
+#define mozilla__ipdltest_TestUrgency_h 1
+
+#include "mozilla/_ipdltest/IPDLUnitTests.h"
+
+#include "mozilla/_ipdltest/PTestUrgencyParent.h"
+#include "mozilla/_ipdltest/PTestUrgencyChild.h"
+
+namespace mozilla {
+namespace _ipdltest {
+
+class TestUrgencyParent : public PTestUrgencyParent {
+ public:
+ TestUrgencyParent();
+ virtual ~TestUrgencyParent();
+
+ static bool RunTestInProcesses() { return true; }
+ static bool RunTestInThreads() { return false; }
+
+ void Main();
+
+ mozilla::ipc::IPCResult RecvTest1(uint32_t* value);
+ mozilla::ipc::IPCResult RecvTest2();
+ mozilla::ipc::IPCResult RecvTest3(uint32_t* value);
+ mozilla::ipc::IPCResult RecvTest4_Begin();
+ mozilla::ipc::IPCResult RecvTest4_NestedSync();
+ mozilla::ipc::IPCResult RecvFinalTest_Begin();
+
+ bool ShouldContinueFromReplyTimeout() override { return false; }
+ virtual void ActorDestroy(ActorDestroyReason why) override {
+ passed("ok");
+ QuitParent();
+ }
+
+ private:
+ bool inreply_;
+};
+
+class TestUrgencyChild : public PTestUrgencyChild {
+ public:
+ TestUrgencyChild();
+ virtual ~TestUrgencyChild();
+
+ mozilla::ipc::IPCResult RecvStart();
+ mozilla::ipc::IPCResult RecvReply1(uint32_t* reply);
+ mozilla::ipc::IPCResult RecvReply2(uint32_t* reply);
+
+ virtual void ActorDestroy(ActorDestroyReason why) override { QuitChild(); }
+
+ private:
+ uint32_t test_;
+};
+
+} // namespace _ipdltest
+} // namespace mozilla
+
+#endif // ifndef mozilla__ipdltest_TestUrgency_h
diff --git a/ipc/ipdl/test/cxx/TestUrgentHangs.cpp b/ipc/ipdl/test/cxx/TestUrgentHangs.cpp
new file mode 100644
index 0000000000..96227dd791
--- /dev/null
+++ b/ipc/ipdl/test/cxx/TestUrgentHangs.cpp
@@ -0,0 +1,174 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: sw=2 ts=4 et :
+ */
+#include "TestUrgentHangs.h"
+
+#include "IPDLUnitTests.h" // fail etc.
+#include "prthread.h"
+#if defined(XP_UNIX)
+# include <unistd.h>
+#else
+# include <windows.h>
+#endif
+
+namespace mozilla {
+namespace _ipdltest {
+
+//-----------------------------------------------------------------------------
+// parent
+
+TestUrgentHangsParent::TestUrgentHangsParent()
+ : mInnerCount(0), mInnerUrgentCount(0) {
+ MOZ_COUNT_CTOR(TestUrgentHangsParent);
+}
+
+TestUrgentHangsParent::~TestUrgentHangsParent() {
+ MOZ_COUNT_DTOR(TestUrgentHangsParent);
+}
+
+void TestUrgentHangsParent::Main() {
+ SetReplyTimeoutMs(1000);
+
+ // Should succeed despite the nested sleep call because the content process
+ // responded to the transaction.
+ if (!SendTest1_1()) fail("sending Test1_1");
+
+ // Fails with a timeout.
+ if (SendTest2()) fail("sending Test2");
+
+ // Also fails since we haven't gotten a response for Test2 yet.
+ if (SendTest3()) fail("sending Test3");
+
+ // Do a second round of testing once the reply to Test2 comes back.
+ MessageLoop::current()->PostDelayedTask(
+ NewNonOwningRunnableMethod(
+ "_ipdltest::TestUrgentHangsParent::SecondStage", this,
+ &TestUrgentHangsParent::SecondStage),
+ 3000);
+}
+
+void TestUrgentHangsParent::SecondStage() {
+ // Send an async message that waits 2 seconds and then sends a sync message
+ // (which should be processed).
+ if (!SendTest4()) fail("sending Test4");
+
+ // Send a sync message that will time out because the child is waiting
+ // inside RecvTest4.
+ if (SendTest4_1()) fail("sending Test4_1");
+
+ MessageLoop::current()->PostDelayedTask(
+ NewNonOwningRunnableMethod("_ipdltest::TestUrgentHangsParent::ThirdStage",
+ this, &TestUrgentHangsParent::ThirdStage),
+ 3000);
+}
+
+void TestUrgentHangsParent::ThirdStage() {
+ // The third stage does the same thing as the second stage except that the
+ // child sends an urgent message to us. In this case, we actually answer
+ // that message unconditionally.
+
+ // Send an async message that waits 2 seconds and then sends a sync message
+ // (which should be processed).
+ if (!SendTest5()) fail("sending Test5");
+
+ // Send a sync message that will time out because the child is waiting
+ // inside RecvTest5.
+ if (SendTest5_1()) fail("sending Test5_1");
+
+ // Close the channel after the child finishes its work in RecvTest5.
+ MessageLoop::current()->PostDelayedTask(
+ NewNonOwningRunnableMethod("ipc::IToplevelProtocol::Close", this,
+ &TestUrgentHangsParent::Close),
+ 3000);
+}
+
+mozilla::ipc::IPCResult TestUrgentHangsParent::RecvTest1_2() {
+ if (!SendTest1_3()) fail("sending Test1_3");
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult TestUrgentHangsParent::RecvTestInner() {
+ mInnerCount++;
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult TestUrgentHangsParent::RecvTestInnerUrgent() {
+ mInnerUrgentCount++;
+ return IPC_OK();
+}
+
+//-----------------------------------------------------------------------------
+// child
+
+mozilla::ipc::IPCResult TestUrgentHangsChild::RecvTest1_1() {
+ if (!SendTest1_2()) fail("sending Test1_2");
+
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult TestUrgentHangsChild::RecvTest1_3() {
+ PR_Sleep(PR_SecondsToInterval(2));
+
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult TestUrgentHangsChild::RecvTest2() {
+ PR_Sleep(PR_SecondsToInterval(2));
+
+ // Should fail because of the timeout.
+ if (SendTestInner()) fail("sending TestInner");
+
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult TestUrgentHangsChild::RecvTest3() {
+ fail("RecvTest3 should never be called");
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult TestUrgentHangsChild::RecvTest4() {
+ PR_Sleep(PR_SecondsToInterval(2));
+
+ // This won't fail because we should handle Test4_1 here before actually
+ // sending TestInner to the parent.
+ if (!SendTestInner()) fail("sending TestInner");
+
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult TestUrgentHangsChild::RecvTest4_1() {
+ // This should fail because Test4_1 timed out and hasn't gotten a response
+ // yet.
+ if (SendTestInner()) fail("sending TestInner");
+
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult TestUrgentHangsChild::RecvTest5() {
+ PR_Sleep(PR_SecondsToInterval(2));
+
+ // This message will actually be handled by the parent even though it's in
+ // the timeout state.
+ if (!SendTestInnerUrgent()) fail("sending TestInner");
+
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult TestUrgentHangsChild::RecvTest5_1() {
+ // This message will actually be handled by the parent even though it's in
+ // the timeout state.
+ if (!SendTestInnerUrgent()) fail("sending TestInner");
+
+ return IPC_OK();
+}
+
+TestUrgentHangsChild::TestUrgentHangsChild() {
+ MOZ_COUNT_CTOR(TestUrgentHangsChild);
+}
+
+TestUrgentHangsChild::~TestUrgentHangsChild() {
+ MOZ_COUNT_DTOR(TestUrgentHangsChild);
+}
+
+} // namespace _ipdltest
+} // namespace mozilla
diff --git a/ipc/ipdl/test/cxx/TestUrgentHangs.h b/ipc/ipdl/test/cxx/TestUrgentHangs.h
new file mode 100644
index 0000000000..facda522bf
--- /dev/null
+++ b/ipc/ipdl/test/cxx/TestUrgentHangs.h
@@ -0,0 +1,64 @@
+#ifndef mozilla__ipdltest_TestUrgentHangs_h
+#define mozilla__ipdltest_TestUrgentHangs_h 1
+
+#include "mozilla/_ipdltest/IPDLUnitTests.h"
+
+#include "mozilla/_ipdltest/PTestUrgentHangsParent.h"
+#include "mozilla/_ipdltest/PTestUrgentHangsChild.h"
+
+namespace mozilla {
+namespace _ipdltest {
+
+class TestUrgentHangsParent : public PTestUrgentHangsParent {
+ public:
+ TestUrgentHangsParent();
+ virtual ~TestUrgentHangsParent();
+
+ static bool RunTestInProcesses() { return true; }
+ static bool RunTestInThreads() { return false; }
+
+ void Main();
+ void SecondStage();
+ void ThirdStage();
+
+ mozilla::ipc::IPCResult RecvTest1_2();
+ mozilla::ipc::IPCResult RecvTestInner();
+ mozilla::ipc::IPCResult RecvTestInnerUrgent();
+
+ bool ShouldContinueFromReplyTimeout() override { return false; }
+ virtual void ActorDestroy(ActorDestroyReason why) override {
+ if (mInnerCount != 1) {
+ fail("wrong mInnerCount");
+ }
+ if (mInnerUrgentCount != 2) {
+ fail("wrong mInnerUrgentCount");
+ }
+ passed("ok");
+ QuitParent();
+ }
+
+ private:
+ size_t mInnerCount, mInnerUrgentCount;
+};
+
+class TestUrgentHangsChild : public PTestUrgentHangsChild {
+ public:
+ TestUrgentHangsChild();
+ virtual ~TestUrgentHangsChild();
+
+ mozilla::ipc::IPCResult RecvTest1_1();
+ mozilla::ipc::IPCResult RecvTest1_3();
+ mozilla::ipc::IPCResult RecvTest2();
+ mozilla::ipc::IPCResult RecvTest3();
+ mozilla::ipc::IPCResult RecvTest4();
+ mozilla::ipc::IPCResult RecvTest4_1();
+ mozilla::ipc::IPCResult RecvTest5();
+ mozilla::ipc::IPCResult RecvTest5_1();
+
+ virtual void ActorDestroy(ActorDestroyReason why) override { QuitChild(); }
+};
+
+} // namespace _ipdltest
+} // namespace mozilla
+
+#endif // ifndef mozilla__ipdltest_TestUrgentHangs_h
diff --git a/ipc/ipdl/test/cxx/app/TestIPDL.cpp b/ipc/ipdl/test/cxx/app/TestIPDL.cpp
new file mode 100644
index 0000000000..3891aead62
--- /dev/null
+++ b/ipc/ipdl/test/cxx/app/TestIPDL.cpp
@@ -0,0 +1,24 @@
+/* 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/. */
+
+#define MOZ_IPDL_TESTS
+#include "mozilla/Bootstrap.h"
+
+#if defined(XP_WIN)
+# include <windows.h>
+# include "nsWindowsWMain.cpp"
+#endif
+
+using namespace mozilla;
+
+int main(int argc, char** argv) {
+ // the first argument specifies which IPDL test case/suite to load
+ if (argc < 2) return 1;
+
+ Bootstrap::UniquePtr bootstrap = GetBootstrap();
+ if (!bootstrap) {
+ return 2;
+ }
+ return bootstrap->XRE_RunIPDLTest(argc, argv);
+}
diff --git a/ipc/ipdl/test/cxx/app/moz.build b/ipc/ipdl/test/cxx/app/moz.build
new file mode 100644
index 0000000000..909360062a
--- /dev/null
+++ b/ipc/ipdl/test/cxx/app/moz.build
@@ -0,0 +1,20 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# 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/.
+
+GeckoProgram("ipdlunittest", linkage="dependent")
+
+SOURCES += [
+ "TestIPDL.cpp",
+]
+include("/ipc/chromium/chromium-config.mozbuild")
+
+LOCAL_INCLUDES += [
+ "/toolkit/xre",
+ "/xpcom/base",
+]
+
+if CONFIG["CC_TYPE"] == "clang-cl":
+ WIN32_EXE_LDFLAGS += ["-ENTRY:wmainCRTStartup"]
diff --git a/ipc/ipdl/test/cxx/genIPDLUnitTests.py b/ipc/ipdl/test/cxx/genIPDLUnitTests.py
new file mode 100644
index 0000000000..160b90a031
--- /dev/null
+++ b/ipc/ipdl/test/cxx/genIPDLUnitTests.py
@@ -0,0 +1,193 @@
+# 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/.
+
+import string
+import sys
+
+
+def usage():
+ print(
+ """
+%s template_file -t unit_tests... -e extra_protocols...
+
+ TEMPLATE_FILE is used to generate to generate the unit-tester .cpp
+ UNIT_TESTS are the top-level protocols defining unit tests
+ EXTRA_PROTOCOLS are top-level protocols for subprocesses that can be
+ spawned in tests but are not unit tests in and of
+ themselves
+"""
+ % (sys.argv[0]),
+ file=sys.stderr,
+ )
+ sys.exit(1)
+
+
+def main(argv):
+ template = argv[1]
+
+ if argv[2] != "-t":
+ usage()
+ i = 3
+ unittests = []
+ while argv[i] != "-e":
+ unittests.append(argv[i])
+ i += 1
+
+ extras = argv[(i + 1) :]
+
+ includes = "\n".join(['#include "%s.h"' % (t) for t in unittests])
+
+ enum_values = "\n".join([" %s," % (t) for t in unittests + extras])
+ last_enum = unittests[-1]
+
+ string_to_enums = "\n".join(
+ [
+ """ else if (!strcmp(aString, "%s"))
+ return %s;"""
+ % (t, t)
+ for t in unittests + extras
+ ]
+ )
+
+ enum_to_strings = "\n".join(
+ [
+ """ case %s:
+ return "%s";"""
+ % (t, t)
+ for t in unittests + extras
+ ]
+ )
+
+ parent_delete_cases = "\n".join(
+ [
+ """ case %s: {
+ delete reinterpret_cast<%sParent*>(gParentActor);
+ return;
+ }
+"""
+ % (t, t)
+ for t in unittests
+ ]
+ )
+
+ parent_enabled_cases_proc = "\n".join(
+ [
+ """ case %s: {
+ if (!%sParent::RunTestInProcesses()) {
+ passed("N/A to proc");
+ DeferredParentShutdown();
+ return;
+ }
+ break;
+ }
+"""
+ % (t, t)
+ for t in unittests
+ ]
+ )
+
+ parent_main_cases_proc = "\n".join(
+ [
+ """ case %s: {
+ %sParent** parent =
+ reinterpret_cast<%sParent**>(&gParentActor);
+ *parent = new %sParent();
+ (*parent)->Open(transport, child);
+ return (*parent)->Main();
+ }
+"""
+ % (t, t, t, t)
+ for t in unittests
+ ]
+ )
+
+ parent_enabled_cases_thread = "\n".join(
+ [
+ """ case %s: {
+ if (!%sParent::RunTestInThreads()) {
+ passed("N/A to threads");
+ DeferredParentShutdown();
+ return;
+ }
+ break;
+ }
+"""
+ % (t, t)
+ for t in unittests
+ ]
+ )
+
+ parent_main_cases_thread = "\n".join(
+ [
+ """ case %s: {
+ %sParent** parent =
+ reinterpret_cast<%sParent**>(&gParentActor);
+ *parent = new %sParent();
+
+ %sChild** child =
+ reinterpret_cast<%sChild**>(&gChildActor);
+ *child = new %sChild();
+
+ ::mozilla::ipc::MessageChannel *childChannel = (*child)->GetIPCChannel();
+ ::mozilla::ipc::Side parentSide =
+ ::mozilla::ipc::ParentSide;
+
+ (*parent)->Open(childChannel, childMessageLoop, parentSide);
+ return (*parent)->Main();
+ }
+"""
+ % (t, t, t, t, t, t, t)
+ for t in unittests
+ ]
+ )
+
+ child_delete_cases = "\n".join(
+ [
+ """ case %s: {
+ delete reinterpret_cast<%sChild*>(gChildActor);
+ return;
+ }
+"""
+ % (t, t)
+ for t in unittests + extras
+ ]
+ )
+
+ child_init_cases = "\n".join(
+ [
+ """ case %s: {
+ %sChild** child =
+ reinterpret_cast<%sChild**>(&gChildActor);
+ *child = new %sChild();
+ (*child)->Open(transport, parentPid, worker);
+ return;
+ }
+"""
+ % (t, t, t, t)
+ for t in unittests + extras
+ ]
+ )
+
+ templatefile = open(template, "r", encoding="utf-8")
+ sys.stdout.write(
+ string.Template(templatefile.read()).substitute(
+ INCLUDES=includes,
+ ENUM_VALUES=enum_values,
+ LAST_ENUM=last_enum,
+ STRING_TO_ENUMS=string_to_enums,
+ ENUM_TO_STRINGS=enum_to_strings,
+ PARENT_DELETE_CASES=parent_delete_cases,
+ PARENT_ENABLED_CASES_PROC=parent_enabled_cases_proc,
+ PARENT_MAIN_CASES_PROC=parent_main_cases_proc,
+ PARENT_ENABLED_CASES_THREAD=parent_enabled_cases_thread,
+ PARENT_MAIN_CASES_THREAD=parent_main_cases_thread,
+ CHILD_DELETE_CASES=child_delete_cases,
+ CHILD_INIT_CASES=child_init_cases,
+ )
+ )
+ templatefile.close()
+
+
+if __name__ == "__main__":
+ main(sys.argv)
diff --git a/ipc/ipdl/test/cxx/moz.build b/ipc/ipdl/test/cxx/moz.build
new file mode 100644
index 0000000000..e2650df0aa
--- /dev/null
+++ b/ipc/ipdl/test/cxx/moz.build
@@ -0,0 +1,172 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# 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/.
+
+DIRS += ["app"]
+
+EXPORTS.mozilla._ipdltest += [
+ "IPDLUnitTestProcessChild.h",
+ "IPDLUnitTests.h",
+ "IPDLUnitTestTypes.h",
+ "IPDLUnitTestUtils.h",
+ "TestActorPunning.h",
+ "TestAsyncReturns.h",
+ "TestBadActor.h",
+ "TestCancel.h",
+ "TestCrashCleanup.h",
+ "TestDataStructures.h",
+ "TestDemon.h",
+ "TestDesc.h",
+ "TestEndpointBridgeMain.h",
+ "TestEndpointOpens.h",
+ "TestFailedCtor.h",
+ "TestHangs.h",
+ "TestHighestPrio.h",
+ "TestInterruptErrorCleanup.h",
+ "TestInterruptRaces.h",
+ "TestInterruptShutdownRace.h",
+ "TestJSON.h",
+ "TestLatency.h",
+ "TestManyChildAllocs.h",
+ "TestMultiMgrs.h",
+ "TestNestedLoops.h",
+ "TestOffMainThreadPainting.h",
+ "TestRaceDeadlock.h",
+ "TestRaceDeferral.h",
+ "TestRacyInterruptReplies.h",
+ "TestRacyReentry.h",
+ "TestRacyUndefer.h",
+ "TestRPC.h",
+ "TestSanity.h",
+ "TestSelfManageRoot.h",
+ "TestShmem.h",
+ "TestShutdown.h",
+ "TestStackHooks.h",
+ "TestSyncError.h",
+ "TestSyncHang.h",
+ "TestSyncWakeup.h",
+ "TestUniquePtrIPC.h",
+ "TestUrgency.h",
+ "TestUrgentHangs.h",
+]
+
+SOURCES += [
+ "TestActorPunning.cpp",
+ "TestAsyncReturns.cpp",
+ "TestBadActor.cpp",
+ "TestCancel.cpp",
+ "TestCrashCleanup.cpp",
+ "TestDataStructures.cpp",
+ "TestDemon.cpp",
+ "TestDesc.cpp",
+ "TestEndpointBridgeMain.cpp",
+ "TestEndpointOpens.cpp",
+ "TestFailedCtor.cpp",
+ "TestHangs.cpp",
+ "TestHighestPrio.cpp",
+ "TestInterruptErrorCleanup.cpp",
+ "TestInterruptRaces.cpp",
+ "TestInterruptShutdownRace.cpp",
+ "TestJSON.cpp",
+ "TestLatency.cpp",
+ "TestManyChildAllocs.cpp",
+ "TestMultiMgrs.cpp",
+ "TestNestedLoops.cpp",
+ "TestOffMainThreadPainting.cpp",
+ "TestRaceDeadlock.cpp",
+ "TestRaceDeferral.cpp",
+ "TestRacyInterruptReplies.cpp",
+ "TestRacyReentry.cpp",
+ "TestRacyUndefer.cpp",
+ "TestRPC.cpp",
+ "TestSanity.cpp",
+ "TestSelfManageRoot.cpp",
+ "TestShmem.cpp",
+ "TestShutdown.cpp",
+ "TestStackHooks.cpp",
+ "TestSyncError.cpp",
+ "TestSyncHang.cpp",
+ "TestSyncWakeup.cpp",
+ "TestUniquePtrIPC.cpp",
+ "TestUrgency.cpp",
+ "TestUrgentHangs.cpp",
+]
+
+SOURCES += [
+ "!IPDLUnitTests.cpp",
+ "IPDLUnitTestProcessChild.cpp",
+ "IPDLUnitTestSubprocess.cpp",
+]
+
+IPDL_SOURCES += [
+ "PTestActorPunning.ipdl",
+ "PTestActorPunningPunned.ipdl",
+ "PTestActorPunningSub.ipdl",
+ "PTestAsyncReturns.ipdl",
+ "PTestBadActor.ipdl",
+ "PTestBadActorSub.ipdl",
+ "PTestCancel.ipdl",
+ "PTestCrashCleanup.ipdl",
+ "PTestDataStructures.ipdl",
+ "PTestDataStructuresCommon.ipdlh",
+ "PTestDataStructuresSub.ipdl",
+ "PTestDemon.ipdl",
+ "PTestDesc.ipdl",
+ "PTestDescSub.ipdl",
+ "PTestDescSubsub.ipdl",
+ "PTestEndpointBridgeMain.ipdl",
+ "PTestEndpointBridgeMainSub.ipdl",
+ "PTestEndpointBridgeSub.ipdl",
+ "PTestEndpointOpens.ipdl",
+ "PTestEndpointOpensOpened.ipdl",
+ "PTestFailedCtor.ipdl",
+ "PTestFailedCtorSub.ipdl",
+ "PTestFailedCtorSubsub.ipdl",
+ "PTestHandle.ipdl",
+ "PTestHangs.ipdl",
+ "PTestHighestPrio.ipdl",
+ "PTestIndirectProtocolParam.ipdlh",
+ "PTestIndirectProtocolParamFirst.ipdl",
+ "PTestIndirectProtocolParamManage.ipdl",
+ "PTestIndirectProtocolParamSecond.ipdl",
+ "PTestInterruptErrorCleanup.ipdl",
+ "PTestInterruptRaces.ipdl",
+ "PTestInterruptShutdownRace.ipdl",
+ "PTestJSON.ipdl",
+ "PTestLatency.ipdl",
+ "PTestManyChildAllocs.ipdl",
+ "PTestManyChildAllocsSub.ipdl",
+ "PTestMultiMgrs.ipdl",
+ "PTestMultiMgrsBottom.ipdl",
+ "PTestMultiMgrsLeft.ipdl",
+ "PTestMultiMgrsRight.ipdl",
+ "PTestNestedLoops.ipdl",
+ "PTestPaintThread.ipdl",
+ "PTestPriority.ipdl",
+ "PTestRaceDeadlock.ipdl",
+ "PTestRaceDeferral.ipdl",
+ "PTestRacyInterruptReplies.ipdl",
+ "PTestRacyReentry.ipdl",
+ "PTestRacyUndefer.ipdl",
+ "PTestRPC.ipdl",
+ "PTestSanity.ipdl",
+ "PTestSelfManage.ipdl",
+ "PTestSelfManageRoot.ipdl",
+ "PTestShmem.ipdl",
+ "PTestShutdown.ipdl",
+ "PTestShutdownSub.ipdl",
+ "PTestShutdownSubsub.ipdl",
+ "PTestStackHooks.ipdl",
+ "PTestSyncError.ipdl",
+ "PTestSyncHang.ipdl",
+ "PTestSyncWakeup.ipdl",
+ "PTestUniquePtrIPC.ipdl",
+ "PTestUrgency.ipdl",
+ "PTestUrgentHangs.ipdl",
+]
+
+include("/ipc/chromium/chromium-config.mozbuild")
+
+FINAL_LIBRARY = "xul"
diff --git a/ipc/ipdl/test/gtest/IPDLUnitTest.cpp b/ipc/ipdl/test/gtest/IPDLUnitTest.cpp
new file mode 100644
index 0000000000..0450019ba9
--- /dev/null
+++ b/ipc/ipdl/test/gtest/IPDLUnitTest.cpp
@@ -0,0 +1,308 @@
+/* -*- 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/. */
+
+#include "gtest/gtest.h"
+
+#include "mozilla/_ipdltest/IPDLUnitTest.h"
+#include "mozilla/ipc/IOThreadChild.h"
+#include "mozilla/ipc/NodeController.h"
+#include "mozilla/ipc/ProtocolUtils.h"
+#include "mozilla/ipc/ProcessChild.h"
+#include "mozilla/SpinEventLoopUntil.h"
+#include "nsDebugImpl.h"
+#include "nsThreadManager.h"
+
+#include <string>
+
+#ifdef MOZ_WIDGET_ANDROID
+# include "nsIAppShell.h"
+# include "nsServiceManagerUtils.h"
+# include "nsWidgetsCID.h"
+#endif
+
+namespace mozilla::_ipdltest {
+
+static std::unordered_map<std::string_view, ipc::IToplevelProtocol* (*)()>
+ sAllocChildActorRegistry;
+
+const char* RegisterAllocChildActor(const char* aName,
+ ipc::IToplevelProtocol* (*aFunc)()) {
+ sAllocChildActorRegistry[aName] = aFunc;
+ return aName;
+}
+
+already_AddRefed<IPDLUnitTestParent> IPDLUnitTestParent::CreateCrossProcess() {
+#ifdef MOZ_WIDGET_ANDROID
+ // Force-initialize the appshell on android, as android child process
+ // launching depends on widget component initialization.
+ nsCOMPtr<nsIAppShell> _appShell = do_GetService(NS_APPSHELL_CID);
+#endif
+
+ RefPtr<IPDLUnitTestParent> parent = new IPDLUnitTestParent();
+ parent->mSubprocess =
+ new ipc::GeckoChildProcessHost(GeckoProcessType_IPDLUnitTest);
+
+ std::vector<std::string> extraArgs;
+
+ auto prefSerializer = MakeUnique<ipc::SharedPreferenceSerializer>();
+ if (!prefSerializer->SerializeToSharedMemory(GeckoProcessType_IPDLUnitTest,
+ /* remoteType */ ""_ns)) {
+ ADD_FAILURE()
+ << "SharedPreferenceSerializer::SerializeToSharedMemory failed";
+ return nullptr;
+ }
+ prefSerializer->AddSharedPrefCmdLineArgs(*parent->mSubprocess, extraArgs);
+
+ if (!parent->mSubprocess->SyncLaunch(extraArgs)) {
+ ADD_FAILURE() << "Subprocess launch failed";
+ return nullptr;
+ }
+
+ if (!parent->mSubprocess->TakeInitialEndpoint().Bind(parent.get())) {
+ ADD_FAILURE() << "Opening the parent actor failed";
+ return nullptr;
+ }
+
+ EXPECT_TRUE(parent->CanSend());
+ return parent.forget();
+}
+
+already_AddRefed<IPDLUnitTestParent> IPDLUnitTestParent::CreateCrossThread() {
+ RefPtr<IPDLUnitTestParent> parent = new IPDLUnitTestParent();
+ RefPtr<IPDLUnitTestChild> child = new IPDLUnitTestChild();
+
+ nsresult rv =
+ NS_NewNamedThread("IPDL UnitTest", getter_AddRefs(parent->mOtherThread));
+ if (NS_FAILED(rv)) {
+ ADD_FAILURE() << "Failed to create IPDLUnitTest thread";
+ return nullptr;
+ }
+ if (!parent->Open(child, parent->mOtherThread)) {
+ ADD_FAILURE() << "Opening the actor failed";
+ return nullptr;
+ }
+
+ EXPECT_TRUE(parent->CanSend());
+ return parent.forget();
+}
+
+IPDLUnitTestParent::~IPDLUnitTestParent() {
+ if (mSubprocess) {
+ mSubprocess->Destroy();
+ mSubprocess = nullptr;
+ }
+ if (mOtherThread) {
+ mOtherThread->Shutdown();
+ }
+}
+
+bool IPDLUnitTestParent::Start(const char* aName,
+ ipc::IToplevelProtocol* aActor) {
+ nsID channelId = nsID::GenerateUUID();
+ auto [parentPort, childPort] =
+ ipc::NodeController::GetSingleton()->CreatePortPair();
+ if (!SendStart(nsDependentCString(aName), std::move(childPort), channelId)) {
+ ADD_FAILURE() << "IPDLUnitTestParent::SendStart failed";
+ return false;
+ }
+ if (!aActor->Open(std::move(parentPort), channelId, OtherPid())) {
+ ADD_FAILURE() << "Unable to open parent actor";
+ return false;
+ }
+ return true;
+}
+
+ipc::IPCResult IPDLUnitTestParent::RecvReport(const TestPartResult& aReport) {
+ if (!aReport.failed()) {
+ return IPC_OK();
+ }
+
+ // Report the failure
+ ADD_FAILURE_AT(aReport.filename().get(), aReport.lineNumber())
+ << "[child " << OtherPid() << "] " << aReport.summary();
+
+ // If the failure was fatal, kill the child process to avoid hangs.
+ if (aReport.fatal()) {
+ KillHard();
+ }
+ return IPC_OK();
+}
+
+ipc::IPCResult IPDLUnitTestParent::RecvComplete() {
+ mComplete = true;
+ Close();
+ return IPC_OK();
+}
+
+void IPDLUnitTestParent::KillHard() {
+ if (mCalledKillHard) {
+ return;
+ }
+ mCalledKillHard = true;
+
+ // We can't effectively kill a same-process situation, but we can trigger
+ // shutdown early to avoid hanging.
+ if (mOtherThread) {
+ Close();
+ nsCOMPtr<nsIThread> otherThread = mOtherThread.forget();
+ otherThread->Shutdown();
+ }
+
+ if (mSubprocess) {
+ ProcessHandle handle = mSubprocess->GetChildProcessHandle();
+ if (!base::KillProcess(handle, base::PROCESS_END_KILLED_BY_USER)) {
+ NS_WARNING("failed to kill subprocess!");
+ }
+ mSubprocess->SetAlreadyDead();
+ }
+}
+
+ipc::IPCResult IPDLUnitTestChild::RecvStart(const nsCString& aName,
+ ipc::ScopedPort aPort,
+ const nsID& aMessageChannelId) {
+ auto* allocChildActor =
+ sAllocChildActorRegistry[std::string_view{aName.get()}];
+ if (!allocChildActor) {
+ ADD_FAILURE() << "No AllocChildActor for name " << aName.get()
+ << " registered!";
+ return IPC_FAIL(this, "No AllocChildActor registered!");
+ }
+
+ // Store references to the node & port to watch for test completion.
+ RefPtr<ipc::NodeController> controller = aPort.Controller();
+ mojo::core::ports::PortRef port = aPort.Port();
+
+ RefPtr<IToplevelProtocol> child = allocChildActor();
+ if (!child->Open(std::move(aPort), aMessageChannelId, OtherPid())) {
+ ADD_FAILURE() << "Unable to open child actor";
+ return IPC_FAIL(this, "Unable to open child actor");
+ }
+
+ // Wait for the port which was created for this actor to be fully torn down.
+ SpinEventLoopUntil("IPDLUnitTestChild::RecvStart"_ns,
+ [&] { return controller->GetStatus(port).isNothing(); });
+
+ // Tear down the test actor to end the test.
+ SendComplete();
+ return IPC_OK();
+}
+
+void IPDLUnitTestChild::ActorDestroy(ActorDestroyReason aWhy) {
+ if (!XRE_IsParentProcess()) {
+ XRE_ShutdownChildProcess();
+ }
+}
+
+void IPDLTestHelper::TestWrapper(bool aCrossProcess) {
+ // Create the host and start the test actor with it.
+ RefPtr<IPDLUnitTestParent> host =
+ aCrossProcess ? IPDLUnitTestParent::CreateCrossProcess()
+ : IPDLUnitTestParent::CreateCrossThread();
+ ASSERT_TRUE(host);
+ if (!host->Start(GetName(), GetActor())) {
+ FAIL();
+ }
+
+ // XXX: Consider adding a test timeout?
+
+ // Run the test body. This will send the initial messages to our actor, which
+ // will eventually clean itself up.
+ TestBody();
+
+ // Spin the event loop until the test wrapper host has fully shut down.
+ SpinEventLoopUntil("IPDLTestHelper::TestWrapper"_ns,
+ [&] { return !host->CanSend(); });
+
+ EXPECT_TRUE(host->ReportedComplete())
+ << "child process exited without signalling completion";
+}
+
+// Listener registered within the IPDLUnitTest process used to relay GTest
+// failures to the parent process, so that the are marked as failing the overall
+// gtest.
+class IPDLChildProcessTestListener : public testing::EmptyTestEventListener {
+ public:
+ explicit IPDLChildProcessTestListener(IPDLUnitTestChild* aActor)
+ : mActor(aActor) {}
+
+ virtual void OnTestPartResult(
+ const testing::TestPartResult& aTestPartResult) override {
+ mActor->SendReport(TestPartResult(
+ aTestPartResult.failed(), aTestPartResult.fatally_failed(),
+ nsDependentCString(aTestPartResult.file_name()),
+ aTestPartResult.line_number(),
+ nsDependentCString(aTestPartResult.summary()),
+ nsDependentCString(aTestPartResult.message())));
+ }
+
+ RefPtr<IPDLUnitTestChild> mActor;
+};
+
+// ProcessChild instance used to run the IPDLUnitTest process.
+class IPDLUnitTestProcessChild : public ipc::ProcessChild {
+ public:
+ using ipc::ProcessChild::ProcessChild;
+ bool Init(int aArgc, char* aArgv[]) override {
+ nsDebugImpl::SetMultiprocessMode("IPDLUnitTest");
+
+ if (!ProcessChild::InitPrefs(aArgc, aArgv)) {
+ MOZ_CRASH("InitPrefs failed");
+ return false;
+ }
+
+ if (NS_WARN_IF(NS_FAILED(nsThreadManager::get().Init()))) {
+ MOZ_CRASH("nsThreadManager initialization failed");
+ return false;
+ }
+
+ RefPtr<IPDLUnitTestChild> child = new IPDLUnitTestChild();
+ if (!TakeInitialEndpoint().Bind(child.get())) {
+ MOZ_CRASH("Bind of IPDLUnitTestChild failed");
+ return false;
+ }
+
+ // Register a listener to forward test results from the child process to the
+ // parent process to be handled there.
+ mListener = new IPDLChildProcessTestListener(child);
+ testing::UnitTest::GetInstance()->listeners().Append(mListener);
+
+ if (NS_FAILED(NS_InitMinimalXPCOM())) {
+ MOZ_CRASH("NS_InitMinimalXPCOM failed");
+ return false;
+ }
+
+ ipc::SetThisProcessName("IPDLUnitTest");
+ return true;
+ }
+
+ void CleanUp() override {
+ // Clean up the test listener we registered to get a clean shutdown.
+ if (mListener) {
+ testing::UnitTest::GetInstance()->listeners().Release(mListener);
+ delete mListener;
+ }
+
+ NS_ShutdownXPCOM(nullptr);
+ }
+
+ IPDLChildProcessTestListener* mListener = nullptr;
+};
+
+// Defined in nsEmbedFunctions.cpp
+extern UniquePtr<ipc::ProcessChild> (*gMakeIPDLUnitTestProcessChild)(
+ base::ProcessId, const nsID&);
+
+// Initialize gMakeIPDLUnitTestProcessChild in a static constructor.
+int _childProcessEntryPointStaticConstructor = ([] {
+ gMakeIPDLUnitTestProcessChild =
+ [](base::ProcessId aParentPid,
+ const nsID& aMessageChannelId) -> UniquePtr<ipc::ProcessChild> {
+ return MakeUnique<IPDLUnitTestProcessChild>(aParentPid, aMessageChannelId);
+ };
+ return 0;
+})();
+
+} // namespace mozilla::_ipdltest
diff --git a/ipc/ipdl/test/gtest/IPDLUnitTest.h b/ipc/ipdl/test/gtest/IPDLUnitTest.h
new file mode 100644
index 0000000000..f4548b508c
--- /dev/null
+++ b/ipc/ipdl/test/gtest/IPDLUnitTest.h
@@ -0,0 +1,79 @@
+/* -*- 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/. */
+
+#ifndef mozilla__ipdltest_IPDLUnitTest_h
+#define mozilla__ipdltest_IPDLUnitTest_h
+
+#include "mozilla/_ipdltest/IPDLUnitTestChild.h"
+#include "mozilla/_ipdltest/IPDLUnitTestParent.h"
+#include "mozilla/ipc/ProtocolUtils.h"
+
+namespace mozilla::_ipdltest {
+
+// Should be called from static constructors to register a child actor
+// constructor so that it can be called from the child process.
+const char* RegisterAllocChildActor(
+ const char* aName, mozilla::ipc::IToplevelProtocol* (*aFunc)());
+
+// Internal helper type used to declare IPDL tests.
+class IPDLTestHelper {
+ public:
+ void TestWrapper(bool aCrossProcess);
+ virtual const char* GetName() = 0;
+ virtual ipc::IToplevelProtocol* GetActor() = 0;
+ virtual void TestBody() = 0;
+};
+
+#define IPDL_TEST_CLASS_NAME_(actorname) IPDL_TEST_##actorname
+
+#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_DECL_(testgroup, actorname, crossprocess) \
+ TEST(testgroup, actorname) \
+ { \
+ IPDL_TEST_CLASS_NAME_(actorname) test; \
+ test.TestWrapper(crossprocess); \
+ }
+
+#define IPDL_TEST_BODY_SEGUE_(actorname) \
+ void IPDL_TEST_CLASS_NAME_(actorname)::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.
+//
+// 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)
+
+} // namespace mozilla::_ipdltest
+
+#endif // mozilla__ipdltest_IPDLUnitTest_h
diff --git a/ipc/ipdl/test/gtest/IPDLUnitTestChild.h b/ipc/ipdl/test/gtest/IPDLUnitTestChild.h
new file mode 100644
index 0000000000..3f9243b274
--- /dev/null
+++ b/ipc/ipdl/test/gtest/IPDLUnitTestChild.h
@@ -0,0 +1,32 @@
+/* -*- 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/. */
+
+#ifndef mozilla__ipdltest_IPDLUnitTestChild_h
+#define mozilla__ipdltest_IPDLUnitTestChild_h
+
+#include "mozilla/_ipdltest/PIPDLUnitTestChild.h"
+#include "nsISupportsImpl.h"
+
+namespace mozilla::_ipdltest {
+
+class IPDLUnitTestChild : public PIPDLUnitTestChild {
+ public:
+ NS_INLINE_DECL_THREADSAFE_REFCOUNTING(IPDLUnitTestChild, override)
+
+ private:
+ friend class PIPDLUnitTestChild;
+
+ ipc::IPCResult RecvStart(const nsCString& aName, ipc::ScopedPort aPort,
+ const nsID& aChannelId);
+
+ void ActorDestroy(ActorDestroyReason aReason) override;
+
+ ~IPDLUnitTestChild() = default;
+};
+
+} // namespace mozilla::_ipdltest
+
+#endif // mozilla__ipdltest_IPDLUnitTestChild_h
diff --git a/ipc/ipdl/test/gtest/IPDLUnitTestParent.h b/ipc/ipdl/test/gtest/IPDLUnitTestParent.h
new file mode 100644
index 0000000000..c292506932
--- /dev/null
+++ b/ipc/ipdl/test/gtest/IPDLUnitTestParent.h
@@ -0,0 +1,50 @@
+/* -*- 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/. */
+
+#ifndef mozilla__ipdltest_IPDLUnitTestParent_h
+#define mozilla__ipdltest_IPDLUnitTestParent_h
+
+#include "mozilla/_ipdltest/PIPDLUnitTestParent.h"
+#include "mozilla/ipc/GeckoChildProcessHost.h"
+#include "nsISupportsImpl.h"
+
+namespace mozilla::_ipdltest {
+
+class IPDLUnitTestParent : public PIPDLUnitTestParent {
+ public:
+ NS_INLINE_DECL_THREADSAFE_REFCOUNTING(IPDLUnitTestParent, override)
+
+ static already_AddRefed<IPDLUnitTestParent> CreateCrossProcess();
+ static already_AddRefed<IPDLUnitTestParent> CreateCrossThread();
+
+ // Try to start a connection with the given name and open `aParentActor` with
+ // it. Fails the current test and returns false on failure.
+ bool Start(const char* aName, IToplevelProtocol* aParentActor);
+
+ bool ReportedComplete() const { return mComplete; }
+
+ private:
+ friend class PIPDLUnitTestParent;
+
+ ipc::IPCResult RecvReport(const TestPartResult& aResult);
+ ipc::IPCResult RecvComplete();
+
+ void KillHard();
+
+ ~IPDLUnitTestParent();
+
+ // Only one of these two will be set depending.
+ nsCOMPtr<nsIThread> mOtherThread;
+ mozilla::ipc::GeckoChildProcessHost* mSubprocess = nullptr;
+
+ // Set to true when the test is complete.
+ bool mComplete = false;
+ bool mCalledKillHard = false;
+};
+
+} // namespace mozilla::_ipdltest
+
+#endif // mozilla__ipdltest_IPDLUnitTestParent_h
diff --git a/ipc/ipdl/test/gtest/PIPDLUnitTest.ipdl b/ipc/ipdl/test/gtest/PIPDLUnitTest.ipdl
new file mode 100644
index 0000000000..6bc5693a72
--- /dev/null
+++ b/ipc/ipdl/test/gtest/PIPDLUnitTest.ipdl
@@ -0,0 +1,34 @@
+/* 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/. */
+
+using mozilla::dom::NativeThreadId from "mozilla/dom/NativeThreadId.h";
+[MoveOnly] using class mozilla::ipc::ScopedPort from "mozilla/ipc/ScopedPort.h";
+using struct nsID from "nsID.h";
+
+namespace mozilla {
+namespace _ipdltest {
+
+// IPDL representation of GTest's TestPartResult type.
+struct TestPartResult {
+ bool failed;
+ bool fatal;
+ nsCString filename;
+ int32_t lineNumber;
+ nsCString summary;
+ nsCString message;
+};
+
+// Primary actor for the IPDLUnitTest process and thread.
+[NeedsOtherPid, ChildProc=any]
+async protocol PIPDLUnitTest {
+ child:
+ async Start(nsCString name, ScopedPort port, nsID channelId);
+
+ parent:
+ async Report(TestPartResult result);
+ async Complete();
+};
+
+} // namespace _ipdltest
+} // namespace mozilla
diff --git a/ipc/ipdl/test/gtest/PTestBasic.ipdl b/ipc/ipdl/test/gtest/PTestBasic.ipdl
new file mode 100644
index 0000000000..9bc81f4830
--- /dev/null
+++ b/ipc/ipdl/test/gtest/PTestBasic.ipdl
@@ -0,0 +1,15 @@
+/* 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]
+async protocol PTestBasic {
+child:
+ async Hello();
+};
+
+} // namespace _ipdltest
+} // namespace mozilla
diff --git a/ipc/ipdl/test/gtest/PTestCrossProcessSemaphore.ipdl b/ipc/ipdl/test/gtest/PTestCrossProcessSemaphore.ipdl
new file mode 100644
index 0000000000..fd25afbd13
--- /dev/null
+++ b/ipc/ipdl/test/gtest/PTestCrossProcessSemaphore.ipdl
@@ -0,0 +1,17 @@
+/* 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 {
+
+[ParentImpl=virtual, ChildImpl=virtual, ChildProc=any]
+async protocol PTestCrossProcessSemaphore {
+child:
+ async CrossProcessSemaphore(CrossProcessSemaphoreHandle aSem);
+};
+
+} // namespace _ipdltest
+} // namespace mozilla
diff --git a/ipc/ipdl/test/gtest/PTestInduceConnectionError.ipdl b/ipc/ipdl/test/gtest/PTestInduceConnectionError.ipdl
new file mode 100644
index 0000000000..d5de893884
--- /dev/null
+++ b/ipc/ipdl/test/gtest/PTestInduceConnectionError.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 {
+
+[ParentImpl=virtual, ChildImpl=virtual, ChildProc=any]
+async protocol PTestInduceConnectionError {
+child:
+ async Begin();
+parent:
+ [LazySend] async FirstMessage();
+ [LazySend] async FollowupMessage();
+};
+
+} // namespace _ipdltest
+} // namespace mozilla
+
diff --git a/ipc/ipdl/test/gtest/PTestManyHandles.ipdl b/ipc/ipdl/test/gtest/PTestManyHandles.ipdl
new file mode 100644
index 0000000000..31e03cee6f
--- /dev/null
+++ b/ipc/ipdl/test/gtest/PTestManyHandles.ipdl
@@ -0,0 +1,15 @@
+/* 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 {
+
+[ParentImpl=virtual, ChildImpl=virtual, ChildProc=any]
+async protocol PTestManyHandles {
+child:
+ async ManyHandles(FileDescriptor[] descrs);
+};
+
+} // namespace _ipdltest
+} // namespace mozilla
diff --git a/ipc/ipdl/test/gtest/TestBasic.cpp b/ipc/ipdl/test/gtest/TestBasic.cpp
new file mode 100644
index 0000000000..36ad55ba99
--- /dev/null
+++ b/ipc/ipdl/test/gtest/TestBasic.cpp
@@ -0,0 +1,29 @@
+/* -*- 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/. */
+
+#include "gtest/gtest.h"
+
+#include "mozilla/_ipdltest/IPDLUnitTest.h"
+#include "mozilla/_ipdltest/TestBasicChild.h"
+#include "mozilla/_ipdltest/TestBasicParent.h"
+
+using namespace mozilla::ipc;
+
+namespace mozilla::_ipdltest {
+
+IPCResult TestBasicChild::RecvHello() {
+ EXPECT_TRUE(CanSend());
+ Close();
+ EXPECT_FALSE(CanSend());
+ return IPC_OK();
+}
+
+IPDL_TEST(TestBasic) {
+ bool ok = mActor->SendHello();
+ ASSERT_TRUE(ok);
+}
+
+} // namespace mozilla::_ipdltest
diff --git a/ipc/ipdl/test/gtest/TestBasicChild.h b/ipc/ipdl/test/gtest/TestBasicChild.h
new file mode 100644
index 0000000000..9971073f4c
--- /dev/null
+++ b/ipc/ipdl/test/gtest/TestBasicChild.h
@@ -0,0 +1,26 @@
+/* -*- 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/. */
+
+#ifndef mozilla__ipdltest_TestBasicChild_h
+#define mozilla__ipdltest_TestBasicChild_h
+
+#include "mozilla/_ipdltest/PTestBasicChild.h"
+
+namespace mozilla::_ipdltest {
+
+class TestBasicChild : public PTestBasicChild {
+ NS_INLINE_DECL_THREADSAFE_REFCOUNTING(TestBasicChild, override)
+
+ public:
+ mozilla::ipc::IPCResult RecvHello();
+
+ private:
+ ~TestBasicChild() = default;
+};
+
+} // namespace mozilla::_ipdltest
+
+#endif // mozilla__ipdltest_TestBasicChild_h
diff --git a/ipc/ipdl/test/gtest/TestBasicParent.h b/ipc/ipdl/test/gtest/TestBasicParent.h
new file mode 100644
index 0000000000..22b07375ba
--- /dev/null
+++ b/ipc/ipdl/test/gtest/TestBasicParent.h
@@ -0,0 +1,23 @@
+/* -*- 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/. */
+
+#ifndef mozilla__ipdltest_TestBasicParent_h
+#define mozilla__ipdltest_TestBasicParent_h
+
+#include "mozilla/_ipdltest/PTestBasicParent.h"
+
+namespace mozilla::_ipdltest {
+
+class TestBasicParent : public PTestBasicParent {
+ NS_INLINE_DECL_THREADSAFE_REFCOUNTING(TestBasicParent, override)
+
+ private:
+ ~TestBasicParent() = default;
+};
+
+} // namespace mozilla::_ipdltest
+
+#endif // mozilla__ipdltest_TestBasicParent_h
diff --git a/ipc/ipdl/test/gtest/TestCrossProcessSemaphore.cpp b/ipc/ipdl/test/gtest/TestCrossProcessSemaphore.cpp
new file mode 100644
index 0000000000..dc05614ded
--- /dev/null
+++ b/ipc/ipdl/test/gtest/TestCrossProcessSemaphore.cpp
@@ -0,0 +1,63 @@
+/* -*- 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/. */
+
+#include "gtest/gtest.h"
+
+#include "mozilla/_ipdltest/IPDLUnitTest.h"
+#include "mozilla/_ipdltest/PTestCrossProcessSemaphoreChild.h"
+#include "mozilla/_ipdltest/PTestCrossProcessSemaphoreParent.h"
+
+#include "mozilla/ipc/CrossProcessSemaphore.h"
+
+using namespace mozilla::ipc;
+
+namespace mozilla::_ipdltest {
+
+class TestCrossProcessSemaphoreChild : public PTestCrossProcessSemaphoreChild {
+ NS_INLINE_DECL_THREADSAFE_REFCOUNTING(TestCrossProcessSemaphoreChild,
+ override)
+
+ public:
+ IPCResult RecvCrossProcessSemaphore(
+ CrossProcessSemaphoreHandle&& aSem) override {
+ UniquePtr<CrossProcessSemaphore> cps(
+ CrossProcessSemaphore::Create(std::move(aSem)));
+ EXPECT_TRUE(bool(cps));
+ cps->Signal();
+ Close();
+ return IPC_OK();
+ }
+
+ private:
+ ~TestCrossProcessSemaphoreChild() = default;
+};
+
+class TestCrossProcessSemaphoreParent
+ : public PTestCrossProcessSemaphoreParent {
+ NS_INLINE_DECL_THREADSAFE_REFCOUNTING(TestCrossProcessSemaphoreParent,
+ override)
+
+ private:
+ ~TestCrossProcessSemaphoreParent() = default;
+};
+
+IPDL_TEST(TestCrossProcessSemaphore) {
+ // Create a semaphore with an initial count of 1. The test will then try to
+ // send the semaphore over IPDL to the other end which will signal, increasing
+ // the count to 2. The test will then try to wait on (decrement) the semaphore
+ // twice, which should succeed only if the semaphore was properly signaled.
+ UniquePtr<CrossProcessSemaphore> cps(
+ CrossProcessSemaphore::Create("TestCrossProcessSemaphore", 1));
+ ASSERT_TRUE(bool(cps));
+ CrossProcessSemaphoreHandle handle = cps->CloneHandle();
+ ASSERT_TRUE(bool(handle));
+ bool ok = mActor->SendCrossProcessSemaphore(std::move(handle));
+ ASSERT_TRUE(ok);
+ EXPECT_TRUE(cps->Wait());
+ EXPECT_TRUE(cps->Wait(Some(TimeDuration::FromSeconds(10))));
+}
+
+} // namespace mozilla::_ipdltest
diff --git a/ipc/ipdl/test/gtest/TestInduceConnectionError.cpp b/ipc/ipdl/test/gtest/TestInduceConnectionError.cpp
new file mode 100644
index 0000000000..988e22fe5a
--- /dev/null
+++ b/ipc/ipdl/test/gtest/TestInduceConnectionError.cpp
@@ -0,0 +1,95 @@
+/* -*- 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/. */
+
+#include "gtest/gtest.h"
+
+#include "mozilla/SpinEventLoopUntil.h"
+#include "mozilla/_ipdltest/IPDLUnitTest.h"
+#include "mozilla/_ipdltest/PTestInduceConnectionErrorChild.h"
+#include "mozilla/_ipdltest/PTestInduceConnectionErrorParent.h"
+
+using namespace mozilla::ipc;
+
+namespace mozilla::_ipdltest {
+
+class TestInduceConnectionErrorChild : public PTestInduceConnectionErrorChild {
+ NS_INLINE_DECL_THREADSAFE_REFCOUNTING(TestInduceConnectionErrorChild,
+ override)
+
+ public:
+ IPCResult RecvBegin() override {
+ SendFirstMessage();
+ SendFollowupMessage();
+ Close();
+ return IPC_OK();
+ }
+
+ private:
+ ~TestInduceConnectionErrorChild() = default;
+};
+
+class TestInduceConnectionErrorParent
+ : public PTestInduceConnectionErrorParent {
+ NS_INLINE_DECL_THREADSAFE_REFCOUNTING(TestInduceConnectionErrorParent,
+ override)
+
+ IPCResult RecvFirstMessage() override {
+ EXPECT_TRUE(CanSend()) << "Actor still alive before inducing";
+ GetIPCChannel()->InduceConnectionError();
+ EXPECT_TRUE(CanSend())
+ << "Actor still alive after inducing - notification will be async";
+ mRecvdFirstMessage = true;
+
+ GetCurrentSerialEventTarget()->Dispatch(NS_NewRunnableFunction(
+ "AfterRecvFirstMessage", [self = RefPtr{this}]() {
+ EXPECT_FALSE(self->CanSend())
+ << "Actor shut down after spinning the event loop";
+ self->mTestComplete = true;
+ }));
+ return IPC_OK();
+ }
+
+ IPCResult RecvFollowupMessage() override {
+ MOZ_CRASH(
+ "Should never receive followup message, despite them being sent "
+ "together");
+ }
+
+ void ActorDestroy(ActorDestroyReason aReason) override {
+ EXPECT_TRUE(mRecvdFirstMessage)
+ << "Should have mRecvdFirstMessage set before ActorDestroy";
+ EXPECT_FALSE(mTestComplete) << "The test has not completed";
+ EXPECT_EQ(aReason, ActorDestroyReason::AbnormalShutdown)
+ << "Should be an abnormal shutdown";
+ mDestroyReason = Some(aReason);
+ }
+
+ bool mRecvdFirstMessage = false;
+ bool mTestComplete = false;
+ Maybe<ActorDestroyReason> mDestroyReason;
+
+ private:
+ ~TestInduceConnectionErrorParent() = default;
+};
+
+IPDL_TEST(TestInduceConnectionError) {
+ bool ok = mActor->SendBegin();
+ GTEST_ASSERT_TRUE(ok);
+
+ // Wait for the actor to be shut down.
+ SpinEventLoopUntil("TestInduceConnectionError"_ns,
+ [&] { return mActor->mTestComplete; });
+ EXPECT_TRUE(mActor->mRecvdFirstMessage)
+ << "Actor should have received first message, but not second one";
+ EXPECT_FALSE(mActor->CanSend()) << "Actor can no longer send";
+ GTEST_ASSERT_TRUE(mActor->mDestroyReason.isSome())
+ << "Actor should have been destroyed";
+ EXPECT_EQ(*mActor->mDestroyReason,
+ IProtocol::ActorDestroyReason::AbnormalShutdown)
+ << "Actor should have an 'abnormal shutdown'";
+}
+
+} // namespace mozilla::_ipdltest
diff --git a/ipc/ipdl/test/gtest/TestManyHandles.cpp b/ipc/ipdl/test/gtest/TestManyHandles.cpp
new file mode 100644
index 0000000000..ead8af22b1
--- /dev/null
+++ b/ipc/ipdl/test/gtest/TestManyHandles.cpp
@@ -0,0 +1,78 @@
+/* -*- 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/. */
+
+#include "gtest/gtest.h"
+
+#include "mozilla/_ipdltest/IPDLUnitTest.h"
+#include "mozilla/_ipdltest/PTestManyHandlesChild.h"
+#include "mozilla/_ipdltest/PTestManyHandlesParent.h"
+
+using namespace mozilla::ipc;
+
+namespace mozilla::_ipdltest {
+
+class TestManyHandlesChild : public PTestManyHandlesChild {
+ NS_INLINE_DECL_THREADSAFE_REFCOUNTING(TestManyHandlesChild, override)
+
+ public:
+ IPCResult RecvManyHandles(nsTArray<FileDescriptor>&& aDescrs) override {
+ EXPECT_EQ(aDescrs.Length(), 500u);
+ for (int i = 0; i < static_cast<int>(aDescrs.Length()); ++i) {
+ UniqueFileHandle handle = aDescrs[i].TakePlatformHandle();
+ int value;
+ const int size = sizeof(value);
+#ifdef XP_WIN
+ DWORD numberOfBytesRead;
+ EXPECT_TRUE(
+ ::ReadFile(handle.get(), &value, size, &numberOfBytesRead, nullptr));
+ EXPECT_EQ(numberOfBytesRead, (DWORD)size);
+#else
+ EXPECT_EQ(read(handle.get(), &value, size), size);
+#endif
+ EXPECT_EQ(value, i);
+ }
+ Close();
+ return IPC_OK();
+ }
+
+ private:
+ ~TestManyHandlesChild() = default;
+};
+
+class TestManyHandlesParent : public PTestManyHandlesParent {
+ NS_INLINE_DECL_THREADSAFE_REFCOUNTING(TestManyHandlesParent, override)
+
+ private:
+ ~TestManyHandlesParent() = default;
+};
+
+IPDL_TEST(TestManyHandles) {
+ nsTArray<FileDescriptor> descrs;
+ for (int i = 0; i < 500; ++i) {
+ const int size = sizeof(i);
+ UniqueFileHandle readPipe;
+ UniqueFileHandle writePipe;
+#ifdef XP_WIN
+ ASSERT_TRUE(::CreatePipe(getter_Transfers(readPipe),
+ getter_Transfers(writePipe), nullptr, size));
+ DWORD numberOfBytesWritten;
+ ASSERT_TRUE(
+ ::WriteFile(writePipe.get(), &i, size, &numberOfBytesWritten, nullptr));
+ ASSERT_EQ(numberOfBytesWritten, (DWORD)size);
+#else
+ int fds[2];
+ ASSERT_EQ(pipe(fds), 0);
+ readPipe.reset(fds[0]);
+ writePipe.reset(fds[1]);
+ ASSERT_EQ(write(writePipe.get(), &i, size), size);
+#endif
+ descrs.AppendElement(FileDescriptor(std::move(readPipe)));
+ }
+ bool ok = mActor->SendManyHandles(descrs);
+ ASSERT_TRUE(ok);
+}
+
+} // namespace mozilla::_ipdltest
diff --git a/ipc/ipdl/test/gtest/moz.build b/ipc/ipdl/test/gtest/moz.build
new file mode 100644
index 0000000000..129e366a4b
--- /dev/null
+++ b/ipc/ipdl/test/gtest/moz.build
@@ -0,0 +1,35 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# 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/.
+
+Library("ipdltest")
+
+EXPORTS.mozilla._ipdltest += [
+ "IPDLUnitTest.h",
+ "IPDLUnitTestChild.h",
+ "IPDLUnitTestParent.h",
+ "TestBasicChild.h",
+ "TestBasicParent.h",
+]
+
+SOURCES += [
+ "IPDLUnitTest.cpp",
+ "TestBasic.cpp",
+ "TestCrossProcessSemaphore.cpp",
+ "TestInduceConnectionError.cpp",
+ "TestManyHandles.cpp",
+]
+
+IPDL_SOURCES += [
+ "PIPDLUnitTest.ipdl",
+ "PTestBasic.ipdl",
+ "PTestCrossProcessSemaphore.ipdl",
+ "PTestInduceConnectionError.ipdl",
+ "PTestManyHandles.ipdl",
+]
+
+include("/ipc/chromium/chromium-config.mozbuild")
+
+FINAL_LIBRARY = "xul-gtest"
diff --git a/ipc/ipdl/test/ipdl/IPDLCompile.py b/ipc/ipdl/test/ipdl/IPDLCompile.py
new file mode 100644
index 0000000000..bfaf7860d6
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/IPDLCompile.py
@@ -0,0 +1,78 @@
+import copy
+import os
+import re
+import subprocess
+import tempfile
+
+# We test the compiler indirectly, rather than reaching into the ipdl/
+# module, to make the testing framework as general as possible.
+
+
+class IPDLCompile:
+ def __init__(self, specfilename, ipdlargv=["python", "ipdl.py"]):
+ self.argv = copy.deepcopy(ipdlargv)
+ self.specfilename = specfilename
+ self.stdout = None
+ self.stderr = None
+ self.returncode = None
+
+ def run(self):
+ """Run |self.specfilename| through the IPDL compiler."""
+ assert self.returncode is None
+
+ tmpoutdir = tempfile.mkdtemp(prefix="ipdl_unit_test")
+
+ try:
+ self.argv.extend(["-d", tmpoutdir, self.specfilename])
+
+ proc = subprocess.Popen(
+ args=self.argv,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ universal_newlines=True,
+ )
+ self.stdout, self.stderr = proc.communicate()
+
+ self.returncode = proc.returncode
+ assert self.returncode is not None
+
+ finally:
+ for root, dirs, files in os.walk(tmpoutdir, topdown=0):
+ for name in files:
+ os.remove(os.path.join(root, name))
+ for name in dirs:
+ os.rmdir(os.path.join(root, name))
+ os.rmdir(tmpoutdir)
+
+ if proc.returncode is None:
+ proc.kill()
+
+ def completed(self):
+ return (
+ self.returncode is not None
+ and isinstance(self.stdout, str)
+ and isinstance(self.stderr, str)
+ )
+
+ def error(self, expectedError):
+ """Return True iff compiling self.specstring resulted in an
+ IPDL compiler error."""
+ assert self.completed()
+
+ errorRe = re.compile(re.escape(expectedError))
+ return None is not re.search(errorRe, self.stderr)
+
+ def exception(self):
+ """Return True iff compiling self.specstring resulted in a Python
+ exception being raised."""
+ assert self.completed()
+
+ return None is not re.search(r"Traceback (most recent call last):", self.stderr)
+
+ def ok(self):
+ """Return True iff compiling self.specstring was successful."""
+ assert self.completed()
+
+ return (
+ not self.exception() and not self.error("error:") and (0 == self.returncode)
+ )
diff --git a/ipc/ipdl/test/ipdl/Makefile.in b/ipc/ipdl/test/ipdl/Makefile.in
new file mode 100644
index 0000000000..67f241775b
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/Makefile.in
@@ -0,0 +1,17 @@
+# 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 $(topsrcdir)/config/rules.mk
+
+OKTESTS := $(wildcard $(srcdir)/ok/*.ipdl) $(wildcard $(srcdir)/ok/*.ipdlh)
+ERRORTESTS := $(wildcard $(srcdir)/error/*.ipdl) $(wildcard $(srcdir)/error/*.ipdlh)
+
+check::
+ @$(PYTHON3) $(srcdir)/runtests.py \
+ $(srcdir)/ok $(srcdir)/error \
+ $(PYTHON3) $(topsrcdir)/ipc/ipdl/ipdl.py \
+ --sync-msg-list=$(srcdir)/sync-messages.ini \
+ --msg-metadata=$(srcdir)/message-metadata.ini \
+ OKTESTS $(OKTESTS) \
+ ERRORTESTS $(ERRORTESTS)
diff --git a/ipc/ipdl/test/ipdl/error/AsyncCtorReturns.ipdl b/ipc/ipdl/test/ipdl/error/AsyncCtorReturns.ipdl
new file mode 100644
index 0000000000..8295a1c9a7
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/AsyncCtorReturns.ipdl
@@ -0,0 +1,11 @@
+//error: asynchronous ctor/dtor message `AsyncCtorReturnsManageeConstructor' declares return values
+
+include protocol AsyncCtorReturnsManagee;
+
+[ChildProc=any]
+protocol AsyncCtorReturns {
+ manages AsyncCtorReturnsManagee;
+
+child:
+ async AsyncCtorReturnsManagee() returns (bool unused);
+};
diff --git a/ipc/ipdl/test/ipdl/error/AsyncCtorReturnsManagee.ipdl b/ipc/ipdl/test/ipdl/error/AsyncCtorReturnsManagee.ipdl
new file mode 100644
index 0000000000..46aeb6e9fd
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/AsyncCtorReturnsManagee.ipdl
@@ -0,0 +1,11 @@
+//error: asynchronous ctor/dtor message `AsyncCtorReturnsManageeConstructor' declares return values
+
+include protocol AsyncCtorReturns;
+
+[ChildProc=any]
+protocol AsyncCtorReturnsManagee {
+ manager AsyncCtorReturns;
+
+parent:
+ async __delete__();
+};
diff --git a/ipc/ipdl/test/ipdl/error/AsyncInsideSync.ipdl b/ipc/ipdl/test/ipdl/error/AsyncInsideSync.ipdl
new file mode 100644
index 0000000000..104ced1c72
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/AsyncInsideSync.ipdl
@@ -0,0 +1,10 @@
+// inside_sync nested messages must be sync
+
+//error: inside_sync nested messages must be sync (here, message `Msg' in protocol `AsyncInsideSync')
+//error: message `Msg' requires more powerful send semantics than its protocol `AsyncInsideSync' provides
+
+[ChildProc=any]
+protocol AsyncInsideSync {
+child:
+ [Nested=inside_sync] async Msg();
+};
diff --git a/ipc/ipdl/test/ipdl/error/ExtendedAttrBadValue.ipdlh b/ipc/ipdl/test/ipdl/error/ExtendedAttrBadValue.ipdlh
new file mode 100644
index 0000000000..880bf54179
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/ExtendedAttrBadValue.ipdlh
@@ -0,0 +1,5 @@
+//error: unexpected value for valueless attribute `RefCounted'
+
+[RefCounted=Invalid] using SomeType from "SomeFile.h";
+
+struct ExtendedAttrBadValue {}; \ No newline at end of file
diff --git a/ipc/ipdl/test/ipdl/error/ExtendedAttrEmpty.ipdlh b/ipc/ipdl/test/ipdl/error/ExtendedAttrEmpty.ipdlh
new file mode 100644
index 0000000000..625bedc58a
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/ExtendedAttrEmpty.ipdlh
@@ -0,0 +1,5 @@
+//error: bad syntax near `]'
+
+[ ] using SomeType from "SomeFile.h";
+
+struct ExtendedAttrEmpty {};
diff --git a/ipc/ipdl/test/ipdl/error/ExtendedAttrInvalidNestedValue.ipdl b/ipc/ipdl/test/ipdl/error/ExtendedAttrInvalidNestedValue.ipdl
new file mode 100644
index 0000000000..64899286db
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/ExtendedAttrInvalidNestedValue.ipdl
@@ -0,0 +1,7 @@
+//error: invalid value for attribute `Nested', expected one of: not, inside_sync, inside_cpow
+
+[ChildProc=any]
+protocol ExtendedAttrInvalidNestedValue {
+child:
+ [Nested=invalid] async __delete__();
+};
diff --git a/ipc/ipdl/test/ipdl/error/ExtendedAttrInvalidPriorityValue.ipdl b/ipc/ipdl/test/ipdl/error/ExtendedAttrInvalidPriorityValue.ipdl
new file mode 100644
index 0000000000..51f21f0458
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/ExtendedAttrInvalidPriorityValue.ipdl
@@ -0,0 +1,7 @@
+//error: invalid value for attribute `Priority', expected one of: normal, input, vsync, mediumhigh, control
+
+[ChildProc=any]
+protocol ExtendedAttrInvalidPriorityValue {
+child:
+ [Priority=invalid] async __delete__();
+};
diff --git a/ipc/ipdl/test/ipdl/error/ExtendedAttrRepeated.ipdlh b/ipc/ipdl/test/ipdl/error/ExtendedAttrRepeated.ipdlh
new file mode 100644
index 0000000000..33defc8ca4
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/ExtendedAttrRepeated.ipdlh
@@ -0,0 +1,5 @@
+//error: Repeated extended attribute `RefCounted'
+
+[RefCounted, RefCounted] using SomeType from "SomeFile.h";
+
+struct ExtendedAttrRepeated {};
diff --git a/ipc/ipdl/test/ipdl/error/ExtendedAttrUnknown.ipdlh b/ipc/ipdl/test/ipdl/error/ExtendedAttrUnknown.ipdlh
new file mode 100644
index 0000000000..c41e91008f
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/ExtendedAttrUnknown.ipdlh
@@ -0,0 +1,5 @@
+//error: unknown attribute `InvalidAttribute'
+
+[InvalidAttribute] using SomeType from "SomeFile.h";
+
+struct ExtendedAttrUnknown {};
diff --git a/ipc/ipdl/test/ipdl/error/ForgottenManagee.ipdl b/ipc/ipdl/test/ipdl/error/ForgottenManagee.ipdl
new file mode 100644
index 0000000000..35f6f02e4d
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/ForgottenManagee.ipdl
@@ -0,0 +1,12 @@
+//error: |manager| declaration in protocol `ForgottenManagee' does not match any |manages| declaration in protocol `ManagerForgot'
+
+include protocol ManagerForgot;
+
+// This protocol says ManagerForgot manages it,
+// but ManagerForgot does not manage it.
+
+protocol ForgottenManagee {
+ manager ManagerForgot;
+child:
+ async __delete__();
+};
diff --git a/ipc/ipdl/test/ipdl/error/ForgottenManager.ipdl b/ipc/ipdl/test/ipdl/error/ForgottenManager.ipdl
new file mode 100644
index 0000000000..f2c524056a
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/ForgottenManager.ipdl
@@ -0,0 +1,12 @@
+//error: |manages| declaration in protocol `ForgottenManager' does not match any |manager| declaration in protocol `ManageeForgot'
+
+include protocol ManageeForgot;
+
+// ManageeForgot should have this protocol as its manager.
+
+[ChildProc=any]
+protocol ForgottenManager {
+ manages ManageeForgot;
+child:
+ async ManageeForgot();
+};
diff --git a/ipc/ipdl/test/ipdl/error/InsideCpowToChild.ipdl b/ipc/ipdl/test/ipdl/error/InsideCpowToChild.ipdl
new file mode 100644
index 0000000000..054964a817
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/InsideCpowToChild.ipdl
@@ -0,0 +1,10 @@
+// inside_cpow nested parent-to-child messages are verboten
+
+//error: inside_cpow nested parent-to-child messages are verboten (here, message `Msg' in protocol `InsideCpowToChild')
+//error: message `Msg' requires more powerful send semantics than its protocol `InsideCpowToChild' provides
+
+[ChildProc=any]
+protocol InsideCpowToChild {
+child:
+ [Nested=inside_cpow] sync Msg();
+};
diff --git a/ipc/ipdl/test/ipdl/error/IntrAsyncManagee.ipdl b/ipc/ipdl/test/ipdl/error/IntrAsyncManagee.ipdl
new file mode 100644
index 0000000000..527c007ec4
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/IntrAsyncManagee.ipdl
@@ -0,0 +1,9 @@
+//error: protocol `IntrAsyncManagee' requires more powerful send semantics than its manager `IntrAsyncManager' provides
+
+include protocol IntrAsyncManager;
+
+intr protocol IntrAsyncManagee {
+ manager IntrAsyncManager;
+child:
+ async __delete__();
+};
diff --git a/ipc/ipdl/test/ipdl/error/IntrAsyncManager.ipdl b/ipc/ipdl/test/ipdl/error/IntrAsyncManager.ipdl
new file mode 100644
index 0000000000..dc5768df28
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/IntrAsyncManager.ipdl
@@ -0,0 +1,10 @@
+//error: protocol `IntrAsyncManagee' requires more powerful send semantics than its manager `IntrAsyncManager' provides
+
+include protocol IntrAsyncManagee;
+
+[ChildProc=any]
+async protocol IntrAsyncManager {
+ manages IntrAsyncManagee;
+parent:
+ async IntrAsyncManagee();
+};
diff --git a/ipc/ipdl/test/ipdl/error/IntrSyncManagee.ipdl b/ipc/ipdl/test/ipdl/error/IntrSyncManagee.ipdl
new file mode 100644
index 0000000000..d0b1462e86
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/IntrSyncManagee.ipdl
@@ -0,0 +1,9 @@
+//error: protocol `IntrSyncManagee' requires more powerful send semantics than its manager `IntrSyncManager' provides
+
+include protocol IntrSyncManager;
+
+intr protocol IntrSyncManagee {
+ manager IntrSyncManager;
+child:
+ async __delete__();
+};
diff --git a/ipc/ipdl/test/ipdl/error/IntrSyncManager.ipdl b/ipc/ipdl/test/ipdl/error/IntrSyncManager.ipdl
new file mode 100644
index 0000000000..f8e762093c
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/IntrSyncManager.ipdl
@@ -0,0 +1,10 @@
+//error: protocol `IntrSyncManagee' requires more powerful send semantics than its manager `IntrSyncManager' provides
+
+include protocol IntrSyncManagee;
+
+[ChildProc=any]
+sync protocol IntrSyncManager {
+ manages IntrSyncManagee;
+parent:
+ async IntrSyncManagee();
+};
diff --git a/ipc/ipdl/test/ipdl/error/ManageeForgot.ipdl b/ipc/ipdl/test/ipdl/error/ManageeForgot.ipdl
new file mode 100644
index 0000000000..9e11fe49fd
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/ManageeForgot.ipdl
@@ -0,0 +1,12 @@
+//error: |manages| declaration in protocol `ForgottenManager' does not match any |manager| declaration in protocol `ManageeForgot'
+
+include protocol ForgottenManager;
+
+// See ForgottenManager. This includes ForgottenManager to ensure that
+// loading this file fails.
+
+[ChildProc=any]
+protocol ManageeForgot {
+child:
+ async __delete__();
+};
diff --git a/ipc/ipdl/test/ipdl/error/ManagerForgot.ipdl b/ipc/ipdl/test/ipdl/error/ManagerForgot.ipdl
new file mode 100644
index 0000000000..ae87534fb9
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/ManagerForgot.ipdl
@@ -0,0 +1,12 @@
+//error: |manager| declaration in protocol `ForgottenManagee' does not match any |manages| declaration in protocol `ManagerForgot'
+
+include protocol ForgottenManagee;
+
+// See ForgottenManagee.ipdl. This includes ForgottenManagee to
+// ensure that loading this file fails.
+
+[ChildProc=any]
+protocol ManagerForgot {
+child:
+ async Msg();
+};
diff --git a/ipc/ipdl/test/ipdl/error/Nullable.ipdl b/ipc/ipdl/test/ipdl/error/Nullable.ipdl
new file mode 100644
index 0000000000..c5257accbb
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/Nullable.ipdl
@@ -0,0 +1,7 @@
+//error: `nullable' qualifier for type `int' is unsupported
+
+[ChildProc=any]
+protocol PNullable {
+child:
+ async Msg(nullable int i);
+};
diff --git a/ipc/ipdl/test/ipdl/error/Nullable2.ipdl b/ipc/ipdl/test/ipdl/error/Nullable2.ipdl
new file mode 100644
index 0000000000..3dcd66a321
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/Nullable2.ipdl
@@ -0,0 +1,11 @@
+//error: `nullable' qualifier for type `int' is unsupported
+
+union Union {
+ nullable int;
+};
+
+[ChildProc=any]
+protocol Nullable2 {
+child:
+ async Msg(Union i);
+};
diff --git a/ipc/ipdl/test/ipdl/error/PBadArrayBase.ipdl b/ipc/ipdl/test/ipdl/error/PBadArrayBase.ipdl
new file mode 100644
index 0000000000..3d791761c2
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/PBadArrayBase.ipdl
@@ -0,0 +1,8 @@
+//error: argument typename `X' of message `Test' has not been declared
+
+[ChildProc=any]
+protocol PBadArrayBase {
+child:
+ async Test(X[] x);
+ async __delete__();
+};
diff --git a/ipc/ipdl/test/ipdl/error/PBadNestedManagee.ipdl b/ipc/ipdl/test/ipdl/error/PBadNestedManagee.ipdl
new file mode 100644
index 0000000000..3fda366674
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/PBadNestedManagee.ipdl
@@ -0,0 +1,10 @@
+//error: protocol `PBadNestedManagee' requires more powerful send semantics than its manager `PBadNestedManager' provides
+
+include protocol PBadNestedManager;
+
+[NestedUpTo=inside_sync, ChildProc=any]
+async protocol PBadNestedManagee {
+ manager PBadNestedManager;
+child:
+ async __delete__();
+};
diff --git a/ipc/ipdl/test/ipdl/error/PBadNestedManager.ipdl b/ipc/ipdl/test/ipdl/error/PBadNestedManager.ipdl
new file mode 100644
index 0000000000..b395da2f30
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/PBadNestedManager.ipdl
@@ -0,0 +1,10 @@
+//error: protocol `PBadNestedManagee' requires more powerful send semantics than its manager `PBadNestedManager' provides
+
+include protocol PBadNestedManagee;
+
+[NestedUpTo=not, ChildProc=any]
+async protocol PBadNestedManager {
+ manages PBadNestedManagee;
+parent:
+ async PBadNestedManagee();
+};
diff --git a/ipc/ipdl/test/ipdl/error/PBadSideImpl.ipdl b/ipc/ipdl/test/ipdl/error/PBadSideImpl.ipdl
new file mode 100644
index 0000000000..787bba1d04
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/PBadSideImpl.ipdl
@@ -0,0 +1,8 @@
+//error: invalid value for attribute `ParentImpl', expected one of: virtual, StringLiteral
+//error: invalid value for attribute `ChildImpl', expected one of: virtual, StringLiteral
+
+[ParentImpl=NotQuoted, ChildImpl, ChildProc=any]
+async protocol PBadSideImpl {
+ parent:
+ async __delete__();
+};
diff --git a/ipc/ipdl/test/ipdl/error/PBadUniquePtrBase.ipdl b/ipc/ipdl/test/ipdl/error/PBadUniquePtrBase.ipdl
new file mode 100644
index 0000000000..8058fb5334
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/PBadUniquePtrBase.ipdl
@@ -0,0 +1,8 @@
+//error: argument typename `UndeclaredType' of message `Test' has not been declared
+
+[ChildProc=any]
+protocol PBadUniquePtrBase {
+child:
+ async Test(UniquePtr<UndeclaredType> x);
+ async __delete__();
+};
diff --git a/ipc/ipdl/test/ipdl/error/PCompressInvalid.ipdl b/ipc/ipdl/test/ipdl/error/PCompressInvalid.ipdl
new file mode 100644
index 0000000000..bc81e4544b
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/PCompressInvalid.ipdl
@@ -0,0 +1,9 @@
+//error: invalid value for attribute `Compress', expected one of: None, all
+
+include protocol compressCtor;
+
+[ChildProc=any]
+async protocol PCompressInvalid {
+child:
+ [Compress=Invalid] async Message();
+};
diff --git a/ipc/ipdl/test/ipdl/error/PDouble.ipdl b/ipc/ipdl/test/ipdl/error/PDouble.ipdl
new file mode 100644
index 0000000000..a6c6dd3a8d
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/PDouble.ipdl
@@ -0,0 +1,12 @@
+//error: Trying to load `PDouble' from a file when we'd already seen it in file
+
+// This will load extra/PDouble.ipdl because extra/ is earlier
+// in the list of include directories than the current working
+// directory. Loading the same protocol from two files is
+// obviously bad.
+include protocol PDouble;
+
+[ChildProc=any]
+protocol PDouble {
+child: async Msg();
+};
diff --git a/ipc/ipdl/test/ipdl/error/PExtendedAttrInvalidValue.ipdl b/ipc/ipdl/test/ipdl/error/PExtendedAttrInvalidValue.ipdl
new file mode 100644
index 0000000000..796f25d8c2
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/PExtendedAttrInvalidValue.ipdl
@@ -0,0 +1,7 @@
+//error: invalid value for attribute `NestedUpTo', expected one of: not, inside_sync, inside_cpow
+
+[NestedUpTo=invalid, ChildProc=any]
+async protocol PExtendedAttrInvalidValue {
+parent:
+ async Msg();
+};
diff --git a/ipc/ipdl/test/ipdl/error/PExtendedAttrRepeated.ipdl b/ipc/ipdl/test/ipdl/error/PExtendedAttrRepeated.ipdl
new file mode 100644
index 0000000000..c15dbce788
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/PExtendedAttrRepeated.ipdl
@@ -0,0 +1,7 @@
+//error: Repeated extended attribute `RefCounted'
+
+[RefCounted, RefCounted, ChildProc=any]
+async protocol PExtendedAttrRepeated {
+parent:
+ async Msg();
+};
diff --git a/ipc/ipdl/test/ipdl/error/PExtendedAttrUnexpectedValue.ipdl b/ipc/ipdl/test/ipdl/error/PExtendedAttrUnexpectedValue.ipdl
new file mode 100644
index 0000000000..dcc7b043c5
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/PExtendedAttrUnexpectedValue.ipdl
@@ -0,0 +1,7 @@
+//error: unexpected value for valueless attribute `ManualDealloc'
+
+[ManualDealloc=invalid, ChildProc=any]
+async protocol PExtendedAttrUnexpectedValue {
+parent:
+ async Msg();
+};
diff --git a/ipc/ipdl/test/ipdl/error/PExtendedAttrUnknownAttribute.ipdl b/ipc/ipdl/test/ipdl/error/PExtendedAttrUnknownAttribute.ipdl
new file mode 100644
index 0000000000..193c1d6608
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/PExtendedAttrUnknownAttribute.ipdl
@@ -0,0 +1,7 @@
+//error: unknown attribute `InvalidAttr'
+
+[InvalidAttr, ChildProc=any]
+async protocol PExtendedAttrUnknownValue {
+parent:
+ async Msg();
+};
diff --git a/ipc/ipdl/test/ipdl/error/PInconsistentMoveOnly.ipdl b/ipc/ipdl/test/ipdl/error/PInconsistentMoveOnly.ipdl
new file mode 100644
index 0000000000..9968b3b2ab
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/PInconsistentMoveOnly.ipdl
@@ -0,0 +1,14 @@
+//error: inconsistent moveonly status of type `::mozilla::ipc::SomeMoveonlyType`
+//error: inconsistent moveonly status of type `::mozilla::ipc::SomeMoveonlySendType`
+
+[MoveOnly] using class mozilla::ipc::SomeMoveonlyType from "SomeFile.h";
+using class mozilla::ipc::SomeMoveonlyType from "SomeFile.h";
+
+[MoveOnly=send] using class mozilla::ipc::SomeMoveonlySendType from "SomeFile.h";
+[MoveOnly=data] using class mozilla::ipc::SomeMoveonlySendType from "SomeFile.h";
+
+[ChildProc=any]
+protocol PInconsistentMoveOnly {
+child:
+ async SomeMessage();
+};
diff --git a/ipc/ipdl/test/ipdl/error/PIntrNested.ipdl b/ipc/ipdl/test/ipdl/error/PIntrNested.ipdl
new file mode 100644
index 0000000000..c487bcd49d
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/PIntrNested.ipdl
@@ -0,0 +1,7 @@
+//error: intr message `Msg' cannot specify [Nested]
+
+[ChildProc=any]
+intr protocol PIntrNested {
+child:
+ [Nested=inside_sync, LegacyIntr] intr Msg();
+};
diff --git a/ipc/ipdl/test/ipdl/error/PIntrNestedProtocol.ipdl b/ipc/ipdl/test/ipdl/error/PIntrNestedProtocol.ipdl
new file mode 100644
index 0000000000..dd95a7c002
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/PIntrNestedProtocol.ipdl
@@ -0,0 +1,7 @@
+//error: intr protocol `PIntrNestedProtocol' cannot specify [NestedUpTo]
+
+[NestedUpTo=inside_sync, ChildProc=any]
+intr protocol PIntrNestedProtocol {
+child:
+ [LegacyIntr] intr Msg();
+};
diff --git a/ipc/ipdl/test/ipdl/error/PIntrPriority.ipdl b/ipc/ipdl/test/ipdl/error/PIntrPriority.ipdl
new file mode 100644
index 0000000000..c8bf75e9a3
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/PIntrPriority.ipdl
@@ -0,0 +1,7 @@
+//error: intr message `Msg' cannot specify [Priority]
+
+[ChildProc=any]
+intr protocol PIntrPriority {
+child:
+ [Priority=vsync, LegacyIntr] intr Msg();
+};
diff --git a/ipc/ipdl/test/ipdl/error/PLazySendInvalid.ipdl b/ipc/ipdl/test/ipdl/error/PLazySendInvalid.ipdl
new file mode 100644
index 0000000000..b34f686132
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/PLazySendInvalid.ipdl
@@ -0,0 +1,7 @@
+//error: unexpected value for valueless attribute `LazySend'
+
+[ChildProc=any]
+async protocol PLazySendInvalid {
+child:
+ [LazySend=Invalid] async Message();
+};
diff --git a/ipc/ipdl/test/ipdl/error/PLazySendSync.ipdl b/ipc/ipdl/test/ipdl/error/PLazySendSync.ipdl
new file mode 100644
index 0000000000..76e9e60fb9
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/PLazySendSync.ipdl
@@ -0,0 +1,7 @@
+//error: non-async message `Message' cannot specify [LazySend]
+
+[ChildProc=any]
+sync protocol PLazySendSync {
+child:
+ [LazySend] sync Message() returns (bool ok);
+};
diff --git a/ipc/ipdl/test/ipdl/error/PManagerManualDealloc.ipdl b/ipc/ipdl/test/ipdl/error/PManagerManualDealloc.ipdl
new file mode 100644
index 0000000000..91ff4f4769
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/PManagerManualDealloc.ipdl
@@ -0,0 +1,13 @@
+//error: [ManualDealloc] protocols cannot be managers
+
+include protocol PManagerManualDeallocTop;
+include protocol PManagerManualDeallocManaged;
+
+[ManualDealloc]
+async protocol PManagerManualDealloc {
+ manager PManagerManualDeallocTop;
+ manages PManagerManualDeallocManaged;
+
+child:
+ async __delete__();
+};
diff --git a/ipc/ipdl/test/ipdl/error/PMissingProc.ipdl b/ipc/ipdl/test/ipdl/error/PMissingProc.ipdl
new file mode 100644
index 0000000000..b4d32e55ac
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/PMissingProc.ipdl
@@ -0,0 +1,6 @@
+//error: Toplevel protocols must specify [ChildProc]
+
+protocol PMissingProc {
+parent:
+ async Msg();
+};
diff --git a/ipc/ipdl/test/ipdl/error/PNoTaintWithoutTainted.ipdl b/ipc/ipdl/test/ipdl/error/PNoTaintWithoutTainted.ipdl
new file mode 100644
index 0000000000..b196050c48
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/PNoTaintWithoutTainted.ipdl
@@ -0,0 +1,7 @@
+//error: argument typename `int' of message `foo' has a NoTaint attribute, but the message lacks the Tainted attribute
+
+[ChildProc=any]
+intr protocol PNoTaintWithoutTainted {
+child:
+ async foo([NoTaint=passback] int id);
+};
diff --git a/ipc/ipdl/test/ipdl/error/PToplevelManualDealloc.ipdl b/ipc/ipdl/test/ipdl/error/PToplevelManualDealloc.ipdl
new file mode 100644
index 0000000000..1936fda2bb
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/PToplevelManualDealloc.ipdl
@@ -0,0 +1,7 @@
+//error: Toplevel protocols cannot be [ManualDealloc]
+
+[ManualDealloc, ChildProc=any]
+async protocol PToplevelManualDealloc {
+child:
+ async __delete__();
+};
diff --git a/ipc/ipdl/test/ipdl/error/PUniquePtrRecursive.ipdl b/ipc/ipdl/test/ipdl/error/PUniquePtrRecursive.ipdl
new file mode 100644
index 0000000000..98992f700e
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/PUniquePtrRecursive.ipdl
@@ -0,0 +1,6 @@
+//error: bad syntax near `UniquePtr'
+
+[ChildProc=any]
+protocol PUniquePtrRecursive {
+child: async Msg( UniquePtr< UniquePtr<int> > aa);
+};
diff --git a/ipc/ipdl/test/ipdl/error/PUniquePtrSelfRecStruct.ipdl b/ipc/ipdl/test/ipdl/error/PUniquePtrSelfRecStruct.ipdl
new file mode 100644
index 0000000000..a0fb3b91c0
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/PUniquePtrSelfRecStruct.ipdl
@@ -0,0 +1,10 @@
+//error: struct `X' is only partially defined
+
+struct X {
+ UniquePtr<X> x;
+};
+
+[ChildProc=any]
+protocol PUniquePtrSelfRecStruct {
+child: async Msg(UniquePtr<X> aa);
+};
diff --git a/ipc/ipdl/test/ipdl/error/PUniquePtrSelfRecUnion.ipdl b/ipc/ipdl/test/ipdl/error/PUniquePtrSelfRecUnion.ipdl
new file mode 100644
index 0000000000..396ffef0e2
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/PUniquePtrSelfRecUnion.ipdl
@@ -0,0 +1,8 @@
+//error: union `X' is only partially defined
+
+union X { UniquePtr<X>; };
+
+[ChildProc=any]
+protocol PUniquePtrSelfRecUnion {
+child: async Msg(UniquePtr<X> aa);
+};
diff --git a/ipc/ipdl/test/ipdl/error/PUnknownProc.ipdl b/ipc/ipdl/test/ipdl/error/PUnknownProc.ipdl
new file mode 100644
index 0000000000..0ec4e3f3c7
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/PUnknownProc.ipdl
@@ -0,0 +1,7 @@
+//error: invalid value for attribute `ChildProc', expected one of: any, anychild, anydom, compositor, Parent, Content, IPDLUnitTest, GMPlugin, GPU, VR, RDD, Socket, RemoteSandboxBroker, ForkServer, Utility
+
+[ChildProc=unknowntype]
+protocol PUnknownProc {
+parent:
+ async Msg();
+};
diff --git a/ipc/ipdl/test/ipdl/error/PasyncMessageListed.ipdl b/ipc/ipdl/test/ipdl/error/PasyncMessageListed.ipdl
new file mode 100644
index 0000000000..18d6e85ea4
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/PasyncMessageListed.ipdl
@@ -0,0 +1,7 @@
+//error: IPC message PasyncMessageListed::Msg is async, can be delisted
+
+[ChildProc=any]
+protocol PasyncMessageListed {
+parent:
+ async Msg();
+};
diff --git a/ipc/ipdl/test/ipdl/error/ReplyPrioWithoutReturns.ipdl b/ipc/ipdl/test/ipdl/error/ReplyPrioWithoutReturns.ipdl
new file mode 100644
index 0000000000..be499f6d4c
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/ReplyPrioWithoutReturns.ipdl
@@ -0,0 +1,8 @@
+//error: non-returns message `NormalPrio' cannot specify [ReplyPriority]
+
+[ChildProc=any]
+async protocol ReplyPrioWithoutReturns
+{
+child:
+ [ReplyPriority=normal] async NormalPrio();
+};
diff --git a/ipc/ipdl/test/ipdl/error/SyncAsyncManagee.ipdl b/ipc/ipdl/test/ipdl/error/SyncAsyncManagee.ipdl
new file mode 100644
index 0000000000..e011e90d79
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/SyncAsyncManagee.ipdl
@@ -0,0 +1,10 @@
+//error: protocol `SyncAsyncManagee' requires more powerful send semantics than its manager `SyncAsyncManager' provides
+
+include protocol SyncAsyncManager;
+
+[ChildProc=any]
+sync protocol SyncAsyncManagee {
+ manager SyncAsyncManager;
+child:
+ async __delete__();
+};
diff --git a/ipc/ipdl/test/ipdl/error/SyncAsyncManager.ipdl b/ipc/ipdl/test/ipdl/error/SyncAsyncManager.ipdl
new file mode 100644
index 0000000000..f189df1cbd
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/SyncAsyncManager.ipdl
@@ -0,0 +1,10 @@
+//error: protocol `SyncAsyncManagee' requires more powerful send semantics than its manager `SyncAsyncManager' provides
+
+include protocol SyncAsyncManagee;
+
+[ChildProc=any]
+async protocol SyncAsyncManager {
+ manages SyncAsyncManagee;
+parent:
+ async SyncAsyncManagee();
+};
diff --git a/ipc/ipdl/test/ipdl/error/SyncPrio.ipdl b/ipc/ipdl/test/ipdl/error/SyncPrio.ipdl
new file mode 100644
index 0000000000..73c0cdfd44
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/SyncPrio.ipdl
@@ -0,0 +1,8 @@
+//error: non-async message `NormalPrio' cannot specify [ReplyPriority]
+
+[ChildProc=any]
+sync protocol SyncPrio
+{
+child:
+ [ReplyPriority=normal] sync NormalPrio() returns (bool aValue);
+};
diff --git a/ipc/ipdl/test/ipdl/error/array_Recursive.ipdl b/ipc/ipdl/test/ipdl/error/array_Recursive.ipdl
new file mode 100644
index 0000000000..d89d4b3cad
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/array_Recursive.ipdl
@@ -0,0 +1,6 @@
+//error: bad syntax near `['
+
+[ChildProc=any]
+protocol array_Recursive {
+child: async Msg(int[][] aa);
+};
diff --git a/ipc/ipdl/test/ipdl/error/badProtocolInclude.ipdl b/ipc/ipdl/test/ipdl/error/badProtocolInclude.ipdl
new file mode 100644
index 0000000000..4ff6db2659
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/badProtocolInclude.ipdl
@@ -0,0 +1,10 @@
+//error: can't locate include file `IDONTEXIST.ipdl'
+
+include protocol IDONTEXIST;
+
+// error: nonexistent protocol ^^^
+
+[ChildProc=any]
+protocol badProtocolInclude {
+child: async Msg();
+};
diff --git a/ipc/ipdl/test/ipdl/error/compressCtor.ipdl b/ipc/ipdl/test/ipdl/error/compressCtor.ipdl
new file mode 100644
index 0000000000..93c300333d
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/compressCtor.ipdl
@@ -0,0 +1,12 @@
+//error: destructor messages can't use compression (here, in protocol `compressCtorManagee')
+//error: constructor messages can't use compression (here, in protocol `compressCtor')
+
+include protocol compressCtorManagee;
+
+[ChildProc=any]
+intr protocol compressCtor {
+ manages compressCtorManagee;
+
+parent:
+ [Compress] async compressCtorManagee();
+};
diff --git a/ipc/ipdl/test/ipdl/error/compressCtorManagee.ipdl b/ipc/ipdl/test/ipdl/error/compressCtorManagee.ipdl
new file mode 100644
index 0000000000..52ec2cc1cd
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/compressCtorManagee.ipdl
@@ -0,0 +1,11 @@
+//error: constructor messages can't use compression (here, in protocol `compressCtor')
+//error: destructor messages can't use compression (here, in protocol `compressCtorManagee')
+
+include protocol compressCtor;
+
+intr protocol compressCtorManagee {
+ manager compressCtor;
+
+child:
+ [Compress] async __delete__();
+};
diff --git a/ipc/ipdl/test/ipdl/error/conflictProtocolMsg.ipdl b/ipc/ipdl/test/ipdl/error/conflictProtocolMsg.ipdl
new file mode 100644
index 0000000000..4756e0c032
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/conflictProtocolMsg.ipdl
@@ -0,0 +1,10 @@
+//error: ctor for protocol `conflictProtocolMsg', which is not managed by protocol `conflictProtocolMsg'
+
+[ChildProc=any]
+protocol conflictProtocolMsg {
+
+ // it's an error to re-use the protocol name as a message ID; these
+ // are reserved
+child: async conflictProtocolMsg();
+
+};
diff --git a/ipc/ipdl/test/ipdl/error/cyclecheck_Child.ipdl b/ipc/ipdl/test/ipdl/error/cyclecheck_Child.ipdl
new file mode 100644
index 0000000000..dd27586d8b
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/cyclecheck_Child.ipdl
@@ -0,0 +1,15 @@
+//error: cycle(s) detected in manager/manages hierarchy: `cyclecheck_Parent -> cyclecheck_Child -> cyclecheck_Grandchild -> cyclecheck_Parent'
+//error: |manages| declaration in protocol `cyclecheck_Grandchild' does not match any |manager| declaration in protocol `cyclecheck_Parent'
+
+include protocol cyclecheck_Parent;
+include protocol cyclecheck_Grandchild;
+
+protocol cyclecheck_Child {
+ manager cyclecheck_Parent;
+ manages cyclecheck_Grandchild;
+
+child:
+ async cyclecheck_Grandchild();
+ async __delete__();
+};
+
diff --git a/ipc/ipdl/test/ipdl/error/cyclecheck_Grandchild.ipdl b/ipc/ipdl/test/ipdl/error/cyclecheck_Grandchild.ipdl
new file mode 100644
index 0000000000..9152a56a16
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/cyclecheck_Grandchild.ipdl
@@ -0,0 +1,15 @@
+//error: cycle(s) detected in manager/manages hierarchy: `cyclecheck_Parent -> cyclecheck_Child -> cyclecheck_Grandchild -> cyclecheck_Parent'
+//error: |manages| declaration in protocol `cyclecheck_Grandchild' does not match any |manager| declaration in protocol `cyclecheck_Parent'
+
+include protocol cyclecheck_Child;
+include protocol cyclecheck_Parent;
+
+protocol cyclecheck_Grandchild {
+ manager cyclecheck_Child;
+ manages cyclecheck_Parent;
+
+child:
+ async cyclecheck_Parent();
+ async __delete__();
+};
+
diff --git a/ipc/ipdl/test/ipdl/error/cyclecheck_Parent.ipdl b/ipc/ipdl/test/ipdl/error/cyclecheck_Parent.ipdl
new file mode 100644
index 0000000000..7b3a135518
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/cyclecheck_Parent.ipdl
@@ -0,0 +1,13 @@
+//error: cycle(s) detected in manager/manages hierarchy: `cyclecheck_Parent -> cyclecheck_Child -> cyclecheck_Grandchild -> cyclecheck_Parent'
+
+include protocol cyclecheck_Child;
+
+[ChildProc=any]
+protocol cyclecheck_Parent {
+ manages cyclecheck_Child;
+
+child:
+ async cyclecheck_Child();
+ async __delete__();
+};
+
diff --git a/ipc/ipdl/test/ipdl/error/dtorReserved.ipdl b/ipc/ipdl/test/ipdl/error/dtorReserved.ipdl
new file mode 100644
index 0000000000..ac5d37c7b6
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/dtorReserved.ipdl
@@ -0,0 +1,11 @@
+//error: lexically invalid characters `~SomeMsg();
+
+[ChildProc=any]
+protocol dtorReserved {
+
+ // it's an error to use old-style dtor syntax
+
+child:
+ ~SomeMsg();
+
+};
diff --git a/ipc/ipdl/test/ipdl/error/empty.ipdl b/ipc/ipdl/test/ipdl/error/empty.ipdl
new file mode 100644
index 0000000000..c6249c280b
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/empty.ipdl
@@ -0,0 +1 @@
+//error: bad syntax near `???' \ No newline at end of file
diff --git a/ipc/ipdl/test/ipdl/error/extra/PDouble.ipdl b/ipc/ipdl/test/ipdl/error/extra/PDouble.ipdl
new file mode 100644
index 0000000000..2efae8fff4
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/extra/PDouble.ipdl
@@ -0,0 +1,5 @@
+// This is a valid file.
+
+protocol PDouble {
+child: async Msg();
+};
diff --git a/ipc/ipdl/test/ipdl/error/extra/PManagerManualDeallocManaged.ipdl b/ipc/ipdl/test/ipdl/error/extra/PManagerManualDeallocManaged.ipdl
new file mode 100644
index 0000000000..65cddccf67
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/extra/PManagerManualDeallocManaged.ipdl
@@ -0,0 +1,9 @@
+include protocol PManagerManualDealloc;
+
+[ManualDealloc]
+async protocol PManagerManualDeallocManaged {
+ manager PManagerManualDealloc;
+
+child:
+ async __delete__();
+};
diff --git a/ipc/ipdl/test/ipdl/error/extra/PManagerManualDeallocTop.ipdl b/ipc/ipdl/test/ipdl/error/extra/PManagerManualDeallocTop.ipdl
new file mode 100644
index 0000000000..38eb7511f5
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/extra/PManagerManualDeallocTop.ipdl
@@ -0,0 +1,9 @@
+include protocol PManagerManualDealloc;
+
+[ChildProc=any]
+async protocol PManagerManualDeallocTop {
+ manager PManagerManualDealloc;
+
+child:
+ async __delete__();
+};
diff --git a/ipc/ipdl/test/ipdl/error/inconsistentRC.ipdl b/ipc/ipdl/test/ipdl/error/inconsistentRC.ipdl
new file mode 100644
index 0000000000..a00bca66e4
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/inconsistentRC.ipdl
@@ -0,0 +1,10 @@
+//error: inconsistent refcounted status of type `::mozilla::ipc::SomeRefcountedType`
+
+[RefCounted] using class mozilla::ipc::SomeRefcountedType from "SomeFile.h";
+using class mozilla::ipc::SomeRefcountedType from "SomeFile.h";
+
+[ChildProc=any]
+protocol inconsistentRC {
+child:
+ async SomeMessage();
+};
diff --git a/ipc/ipdl/test/ipdl/error/intrMessageCompress.ipdl b/ipc/ipdl/test/ipdl/error/intrMessageCompress.ipdl
new file mode 100644
index 0000000000..e56cfc5d8c
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/intrMessageCompress.ipdl
@@ -0,0 +1,10 @@
+//error: message `foo' in protocol `intrMessageCompress' requests compression but is not async
+//error: message `bar' in protocol `intrMessageCompress' requests compression but is not async
+
+[ChildProc=any]
+intr protocol intrMessageCompress {
+parent:
+ [Compress, LegacyIntr] intr foo();
+child:
+ [Compress, LegacyIntr] intr bar();
+};
diff --git a/ipc/ipdl/test/ipdl/error/lex1.ipdl b/ipc/ipdl/test/ipdl/error/lex1.ipdl
new file mode 100644
index 0000000000..a00629cbca
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/lex1.ipdl
@@ -0,0 +1,2 @@
+//error: bad syntax near `slkdjfl'
+slkdjfl*&^*
diff --git a/ipc/ipdl/test/ipdl/error/manageSelfToplevel.ipdl b/ipc/ipdl/test/ipdl/error/manageSelfToplevel.ipdl
new file mode 100644
index 0000000000..4540c2c2f6
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/manageSelfToplevel.ipdl
@@ -0,0 +1,10 @@
+//error: top-level protocol `manageSelfToplevel' cannot manage itself
+
+protocol manageSelfToplevel {
+ manager manageSelfToplevel;
+ manages manageSelfToplevel;
+
+child:
+ async manageSelfToplevel();
+ async __delete__();
+};
diff --git a/ipc/ipdl/test/ipdl/error/managedNoDtor.ipdl b/ipc/ipdl/test/ipdl/error/managedNoDtor.ipdl
new file mode 100644
index 0000000000..41bbd76689
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/managedNoDtor.ipdl
@@ -0,0 +1,7 @@
+//error: destructor declaration `__delete__(...)' required for managed protocol `managedNoDtor'
+include protocol managerNoDtor;
+
+protocol managedNoDtor {
+ manager managerNoDtor;
+ // empty
+};
diff --git a/ipc/ipdl/test/ipdl/error/managerNoDtor.ipdl b/ipc/ipdl/test/ipdl/error/managerNoDtor.ipdl
new file mode 100644
index 0000000000..0417cc5ace
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/managerNoDtor.ipdl
@@ -0,0 +1,11 @@
+//error: destructor declaration `__delete__(...)' required for managed protocol `managedNoDtor'
+
+include protocol managedNoDtor;
+
+protocol managerNoDtor {
+ manages managedNoDtor;
+
+parent:
+ async managedNoDtor();
+ // error: no ctor defined
+};
diff --git a/ipc/ipdl/test/ipdl/error/maybe_Recursive.ipdl b/ipc/ipdl/test/ipdl/error/maybe_Recursive.ipdl
new file mode 100644
index 0000000000..2f356b423a
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/maybe_Recursive.ipdl
@@ -0,0 +1,6 @@
+//error: bad syntax near `?'
+
+[ChildProc=any]
+protocol maybe_Recursive {
+child: async Msg(int?? aa);
+};
diff --git a/ipc/ipdl/test/ipdl/error/maybe_SelfRecStruct.ipdl b/ipc/ipdl/test/ipdl/error/maybe_SelfRecStruct.ipdl
new file mode 100644
index 0000000000..9dff6a2152
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/maybe_SelfRecStruct.ipdl
@@ -0,0 +1,10 @@
+//error: struct `X' is only partially defined
+
+struct X {
+ X? x;
+};
+
+[ChildProc=any]
+protocol maybe_SelfRecStruct {
+child: async Msg(X? aa);
+};
diff --git a/ipc/ipdl/test/ipdl/error/maybe_SelfRecUnion.ipdl b/ipc/ipdl/test/ipdl/error/maybe_SelfRecUnion.ipdl
new file mode 100644
index 0000000000..b85497d9c1
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/maybe_SelfRecUnion.ipdl
@@ -0,0 +1,8 @@
+//error: union `X' is only partially defined
+
+union X { X?; };
+
+[ChildProc=any]
+protocol maybe_SelfRecUnion {
+child: async Msg(X? aa);
+};
diff --git a/ipc/ipdl/test/ipdl/error/messageNoDirection.ipdl b/ipc/ipdl/test/ipdl/error/messageNoDirection.ipdl
new file mode 100644
index 0000000000..5e889933cb
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/messageNoDirection.ipdl
@@ -0,0 +1,6 @@
+//error: missing message direction
+
+[ChildProc=any]
+protocol messageNoDirection {
+ async NoDirection();
+};
diff --git a/ipc/ipdl/test/ipdl/error/multimanDupMgrs.ipdl b/ipc/ipdl/test/ipdl/error/multimanDupMgrs.ipdl
new file mode 100644
index 0000000000..805a9f905e
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/multimanDupMgrs.ipdl
@@ -0,0 +1,10 @@
+//error: manager `multimanDupMgrsMgr' appears multiple times
+
+include protocol multimanDupMgrsMgr;
+
+protocol multimanDupMgrs {
+ manager multimanDupMgrsMgr or multimanDupMgrsMgr;
+
+child:
+ async __delete__();
+};
diff --git a/ipc/ipdl/test/ipdl/error/multimanDupMgrsMgr.ipdl b/ipc/ipdl/test/ipdl/error/multimanDupMgrsMgr.ipdl
new file mode 100644
index 0000000000..76e838cc57
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/multimanDupMgrsMgr.ipdl
@@ -0,0 +1,12 @@
+//error: manager `multimanDupMgrsMgr' appears multiple times
+
+include protocol multimanDupMgrs;
+
+[ChildProc=any]
+protocol multimanDupMgrsMgr {
+ manages multimanDupMgrs;
+
+child:
+ async multimanDupMgrs();
+ async __delete__();
+};
diff --git a/ipc/ipdl/test/ipdl/error/multimanNonexistentMgrs.ipdl b/ipc/ipdl/test/ipdl/error/multimanNonexistentMgrs.ipdl
new file mode 100644
index 0000000000..24dafb8163
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/multimanNonexistentMgrs.ipdl
@@ -0,0 +1,10 @@
+//error: protocol `Starsky' referenced as |manager| of `multimanNonexistentMgrs' has not been declared
+//error: protocol `Hutch' referenced as |manager| of `multimanNonexistentMgrs' has not been declared
+
+protocol multimanNonexistentMgrs {
+ manager Starsky or Hutch;
+
+child:
+ async Dummy();
+ async __delete__();
+};
diff --git a/ipc/ipdl/test/ipdl/error/mutualRecStruct.ipdl b/ipc/ipdl/test/ipdl/error/mutualRecStruct.ipdl
new file mode 100644
index 0000000000..3224438e90
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/mutualRecStruct.ipdl
@@ -0,0 +1,25 @@
+//error: struct `X' is only partially defined
+//error: struct `Y' is only partially defined
+//error: struct `Z' is only partially defined
+
+struct X {
+ int i;
+ Y[] y;
+};
+
+struct Y {
+ X x;
+ Z z;
+};
+
+struct Z {
+ double d;
+ X x;
+};
+
+[ChildProc=any]
+protocol mutualRecStruct {
+child:
+ async Test(X x, Y y, Z z);
+ async __delete__();
+};
diff --git a/ipc/ipdl/test/ipdl/error/mutualRecStructUnion.ipdl b/ipc/ipdl/test/ipdl/error/mutualRecStructUnion.ipdl
new file mode 100644
index 0000000000..65345642a5
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/mutualRecStructUnion.ipdl
@@ -0,0 +1,25 @@
+//error: struct `X' is only partially defined
+//error: union `Y' is only partially defined
+//error: struct `Z' is only partially defined
+
+struct X {
+ int i;
+ Y[] y;
+};
+
+union Y {
+ X;
+ Z;
+};
+
+struct Z {
+ double d;
+ X x;
+};
+
+[ChildProc=any]
+protocol mutualRecStructUnion {
+child:
+ async Test(X x, Y y, Z z);
+ async __delete__();
+};
diff --git a/ipc/ipdl/test/ipdl/error/noProtocolInHeader.ipdlh b/ipc/ipdl/test/ipdl/error/noProtocolInHeader.ipdlh
new file mode 100644
index 0000000000..1997eb77d9
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/noProtocolInHeader.ipdlh
@@ -0,0 +1,7 @@
+//error: can't define a protocol in a header. Do it in a protocol spec instead.
+
+[ChildProc=any]
+protocol noProtocolInHeader {
+child:
+ async __delete__();
+};
diff --git a/ipc/ipdl/test/ipdl/error/oldIncludeSyntax.ipdl b/ipc/ipdl/test/ipdl/error/oldIncludeSyntax.ipdl
new file mode 100644
index 0000000000..6f90bc6d5f
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/oldIncludeSyntax.ipdl
@@ -0,0 +1,8 @@
+//error: bad syntax near `"Foo.ipdl"'
+
+include protocol "Foo.ipdl";
+
+[ChildProc=any]
+protocol oldIncludeSyntax {
+child: async __delete__(X x);
+};
diff --git a/ipc/ipdl/test/ipdl/error/parser.ipdl b/ipc/ipdl/test/ipdl/error/parser.ipdl
new file mode 100644
index 0000000000..8bfd63546a
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/parser.ipdl
@@ -0,0 +1,3 @@
+//error: bad syntax near `???'
+
+protocol parser {
diff --git a/ipc/ipdl/test/ipdl/error/redeclMessage.ipdl b/ipc/ipdl/test/ipdl/error/redeclMessage.ipdl
new file mode 100644
index 0000000000..63a70d31a6
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/redeclMessage.ipdl
@@ -0,0 +1,13 @@
+//error: message name `Msg' already declared as `MessageType'
+//error: redeclaration of symbol `Msg', first declared at
+
+[ChildProc=any]
+protocol redeclMessage {
+
+ // can't declare two messages with the same name
+
+child:
+ async Msg();
+ async Msg();
+
+};
diff --git a/ipc/ipdl/test/ipdl/error/redeclParamReturn.ipdl b/ipc/ipdl/test/ipdl/error/redeclParamReturn.ipdl
new file mode 100644
index 0000000000..71a1532bb2
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/redeclParamReturn.ipdl
@@ -0,0 +1,10 @@
+//error: redeclaration of symbol `f', first declared at
+
+[ChildProc=any]
+sync protocol redeclParamReturn {
+
+ // it's an error to name a parameter with the same id as a return
+
+parent: async Msg(int f) returns (bool f);
+
+};
diff --git a/ipc/ipdl/test/ipdl/error/redeclScope.ipdlh b/ipc/ipdl/test/ipdl/error/redeclScope.ipdlh
new file mode 100644
index 0000000000..a64439b599
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/redeclScope.ipdlh
@@ -0,0 +1,12 @@
+//error: redeclaration of symbol `Foo', first declared at
+
+struct Foo {
+ bool b;
+};
+
+struct Bar {
+ // This should produce an error saying that Foo is a redeclaration,
+ // even though the initial declaration was in a different frame of
+ // the symbol table.
+ bool Foo;
+};
diff --git a/ipc/ipdl/test/ipdl/error/shmem.ipdl b/ipc/ipdl/test/ipdl/error/shmem.ipdl
new file mode 100644
index 0000000000..4511ce65dd
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/shmem.ipdl
@@ -0,0 +1,9 @@
+//error: redeclaration of symbol `Shmem', first declared at
+//error: redeclaration of symbol `::mozilla::ipc::Shmem', first declared at
+
+using class mozilla::ipc::Shmem from "mozilla/ipc/Shmem.h"; // redeclaration
+
+[ChildProc=any]
+protocol shmem {
+child: async Msg(Shmem s);
+};
diff --git a/ipc/ipdl/test/ipdl/error/structRedecl.ipdl b/ipc/ipdl/test/ipdl/error/structRedecl.ipdl
new file mode 100644
index 0000000000..37d87d6627
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/structRedecl.ipdl
@@ -0,0 +1,11 @@
+//error: redeclaration of symbol `a', first declared at
+
+struct Redecl {
+ int a;
+ double a;
+};
+
+[ChildProc=any]
+protocol structRedecl {
+child: async __delete__();
+};
diff --git a/ipc/ipdl/test/ipdl/error/structUnknownField.ipdl b/ipc/ipdl/test/ipdl/error/structUnknownField.ipdl
new file mode 100644
index 0000000000..e8702a9b78
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/structUnknownField.ipdl
@@ -0,0 +1,10 @@
+//error: field `i' of struct `S' has unknown type `Foobers'
+
+struct S {
+ Foobers i;
+};
+
+[ChildProc=any]
+protocol structUnknownField {
+child: async __delete__(S s);
+};
diff --git a/ipc/ipdl/test/ipdl/error/syncMessageCompress.ipdl b/ipc/ipdl/test/ipdl/error/syncMessageCompress.ipdl
new file mode 100644
index 0000000000..0a3b63be2c
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/syncMessageCompress.ipdl
@@ -0,0 +1,7 @@
+//error: message `foo' in protocol `syncMessageCompress' requests compression but is not async
+
+[ChildProc=any]
+sync protocol syncMessageCompress {
+parent:
+ [Compress] sync foo();
+};
diff --git a/ipc/ipdl/test/ipdl/error/syncParentToChild.ipdl b/ipc/ipdl/test/ipdl/error/syncParentToChild.ipdl
new file mode 100644
index 0000000000..8ce7c0be47
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/syncParentToChild.ipdl
@@ -0,0 +1,9 @@
+//error: sync parent-to-child messages are verboten (here, message `Msg' in protocol `syncParentToChild')
+
+[ChildProc=any]
+intr protocol syncParentToChild {
+
+ // can't declare sync parent-to-child messages
+child: sync Msg();
+
+};
diff --git a/ipc/ipdl/test/ipdl/error/tooWeakIntrAsync.ipdl b/ipc/ipdl/test/ipdl/error/tooWeakIntrAsync.ipdl
new file mode 100644
index 0000000000..7dad5e68ef
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/tooWeakIntrAsync.ipdl
@@ -0,0 +1,10 @@
+//error: message `Msg' requires more powerful send semantics than its protocol `tooWeakIntrAsync' provides
+
+[ChildProc=any]
+protocol tooWeakIntrAsync {
+
+ // it's an error to declare an async protocol with an intr message
+
+parent: [LegacyIntr] intr Msg();
+
+};
diff --git a/ipc/ipdl/test/ipdl/error/tooWeakIntrSync.ipdl b/ipc/ipdl/test/ipdl/error/tooWeakIntrSync.ipdl
new file mode 100644
index 0000000000..a56e884e73
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/tooWeakIntrSync.ipdl
@@ -0,0 +1,9 @@
+//error: message `Msg' requires more powerful send semantics than its protocol `tooWeakIntrSync' provides
+
+[ChildProc=any]
+sync protocol tooWeakIntrSync {
+
+ // it's an error to declare a sync protocol with an interrupt message
+parent:
+ [LegacyIntr] intr Msg();
+};
diff --git a/ipc/ipdl/test/ipdl/error/tooWeakSyncAsync.ipdl b/ipc/ipdl/test/ipdl/error/tooWeakSyncAsync.ipdl
new file mode 100644
index 0000000000..8ebbfd25da
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/tooWeakSyncAsync.ipdl
@@ -0,0 +1,10 @@
+//error: message `Msg' requires more powerful send semantics than its protocol `tooWeakSyncAsync' provides
+
+[ChildProc=any]
+protocol tooWeakSyncAsync {
+
+ // it's an error to declare an async protocol with a sync message
+
+parent: sync Msg();
+
+};
diff --git a/ipc/ipdl/test/ipdl/error/twoprotocols.ipdl b/ipc/ipdl/test/ipdl/error/twoprotocols.ipdl
new file mode 100644
index 0000000000..93222292a5
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/twoprotocols.ipdl
@@ -0,0 +1,13 @@
+// it's an error to define two protocols in the same file
+
+//error: only one protocol definition per file
+
+[ChildProc=any]
+protocol p1 {
+child: async Msg();
+};
+
+[ChildProc=any]
+protocol p2 {
+child: async Msg();
+};
diff --git a/ipc/ipdl/test/ipdl/error/undeclParamType.ipdl b/ipc/ipdl/test/ipdl/error/undeclParamType.ipdl
new file mode 100644
index 0000000000..efc21f0529
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/undeclParamType.ipdl
@@ -0,0 +1,8 @@
+//error: argument typename `FARGLEGARGLE' of message `Msg' has not been declared
+
+[ChildProc=any]
+protocol undeclParamType {
+
+child: async Msg(FARGLEGARGLE p);
+
+};
diff --git a/ipc/ipdl/test/ipdl/error/undeclProtocol.ipdl b/ipc/ipdl/test/ipdl/error/undeclProtocol.ipdl
new file mode 100644
index 0000000000..19532e3b9c
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/undeclProtocol.ipdl
@@ -0,0 +1,9 @@
+//error: protocol `undeclared', managed by `undeclProtocol', has not been declared
+
+[ChildProc=any]
+protocol undeclProtocol {
+ manages undeclared;
+
+child:
+ async undeclared();
+};
diff --git a/ipc/ipdl/test/ipdl/error/undeclReturnType.ipdl b/ipc/ipdl/test/ipdl/error/undeclReturnType.ipdl
new file mode 100644
index 0000000000..87fe0d6223
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/undeclReturnType.ipdl
@@ -0,0 +1,8 @@
+//error: argument typename `FARGLEGARGLE' of message `Msg' has not been declared
+
+[ChildProc=any]
+sync protocol undeclReturnType {
+
+child: sync Msg() returns (FARGLEGARGLE r);
+
+};
diff --git a/ipc/ipdl/test/ipdl/error/undefMutualRecStruct.ipdl b/ipc/ipdl/test/ipdl/error/undefMutualRecStruct.ipdl
new file mode 100644
index 0000000000..79fa3729cc
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/undefMutualRecStruct.ipdl
@@ -0,0 +1,12 @@
+//error: struct `X' is only partially defined
+//error: struct `Y' is only partially defined
+//error: struct `Z' is only partially defined
+
+struct X { Y y; };
+struct Y { Z z; };
+struct Z { X x; };
+
+[ChildProc=any]
+protocol undefMutualRecStruct {
+child: async __delete__(X x);
+};
diff --git a/ipc/ipdl/test/ipdl/error/undefMutualRecStructUnion.ipdl b/ipc/ipdl/test/ipdl/error/undefMutualRecStructUnion.ipdl
new file mode 100644
index 0000000000..09e7116a68
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/undefMutualRecStructUnion.ipdl
@@ -0,0 +1,12 @@
+//error: struct `X' is only partially defined
+//error: union `Y' is only partially defined
+//error: struct `Z' is only partially defined
+
+struct X { Y y; };
+union Y { Z; };
+struct Z { X x; };
+
+[ChildProc=any]
+protocol undefMutualRecStructUnion {
+child: async __delete__(X x);
+};
diff --git a/ipc/ipdl/test/ipdl/error/undefMutualRecUnion.ipdl b/ipc/ipdl/test/ipdl/error/undefMutualRecUnion.ipdl
new file mode 100644
index 0000000000..497836ba4f
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/undefMutualRecUnion.ipdl
@@ -0,0 +1,12 @@
+//error: union `X' is only partially defined
+//error: union `Y' is only partially defined
+//error: union `Z' is only partially defined
+
+union X { Y; };
+union Y { Z; };
+union Z { X; };
+
+[ChildProc=any]
+protocol undefMutualRecUnion {
+child: async __delete__(X x);
+};
diff --git a/ipc/ipdl/test/ipdl/error/undefSelfRecStruct.ipdl b/ipc/ipdl/test/ipdl/error/undefSelfRecStruct.ipdl
new file mode 100644
index 0000000000..1c23da1a77
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/undefSelfRecStruct.ipdl
@@ -0,0 +1,8 @@
+//error: struct `X' is only partially defined
+
+struct X { X x; };
+
+[ChildProc=any]
+protocol undefSelfRecStruct {
+child: async __delete__(X x);
+};
diff --git a/ipc/ipdl/test/ipdl/error/undefSelfRecUnion.ipdl b/ipc/ipdl/test/ipdl/error/undefSelfRecUnion.ipdl
new file mode 100644
index 0000000000..2c7572f11d
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/undefSelfRecUnion.ipdl
@@ -0,0 +1,8 @@
+//error: union `X' is only partially defined
+
+union X { X; };
+
+[ChildProc=any]
+protocol undefSelfRecUnion {
+child: async __delete__(X x);
+};
diff --git a/ipc/ipdl/test/ipdl/error/unknownIntrMessage.ipdl b/ipc/ipdl/test/ipdl/error/unknownIntrMessage.ipdl
new file mode 100644
index 0000000000..7ce415aba0
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/unknownIntrMessage.ipdl
@@ -0,0 +1,7 @@
+//error: Unknown sync IPC message unknownIntrMessage::Msg
+
+[ChildProc=any]
+intr protocol unknownIntrMessage {
+parent:
+ [LegacyIntr] intr Msg();
+};
diff --git a/ipc/ipdl/test/ipdl/error/unknownSyncMessage.ipdl b/ipc/ipdl/test/ipdl/error/unknownSyncMessage.ipdl
new file mode 100644
index 0000000000..ab1baecd35
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/unknownSyncMessage.ipdl
@@ -0,0 +1,7 @@
+//error: Unknown sync IPC message unknownSyncMessage::Msg
+
+[ChildProc=any]
+sync protocol unknownSyncMessage {
+parent:
+ sync Msg();
+};
diff --git a/ipc/ipdl/test/ipdl/message-metadata.ini b/ipc/ipdl/test/ipdl/message-metadata.ini
new file mode 100644
index 0000000000..02ec1a992f
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/message-metadata.ini
@@ -0,0 +1,2 @@
+# The IPDL parser expects this file to exist, even though we don't
+# need it for parsing tests, so here's an empty file. \ No newline at end of file
diff --git a/ipc/ipdl/test/ipdl/moz.build b/ipc/ipdl/test/ipdl/moz.build
new file mode 100644
index 0000000000..572682b594
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/moz.build
@@ -0,0 +1,8 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# 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/.
+
+# Copy test files so that they can be referenced in the docs.
+SPHINX_TREES["/ipc/_static"] = "ok"
diff --git a/ipc/ipdl/test/ipdl/ok/MutRecHeader1.ipdlh b/ipc/ipdl/test/ipdl/ok/MutRecHeader1.ipdlh
new file mode 100644
index 0000000000..56135b2197
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/ok/MutRecHeader1.ipdlh
@@ -0,0 +1,34 @@
+include MutRecHeader2;
+
+/* MutRecHeader1 (H1) includes MutRecHeader2 (H2), and uses a struct from H2.
+ H2 includes MutRecHeader3 (H3).
+ H3 includes H1.
+
+When type checking H1, GatherDecls::visitInclude will recursively
+cause us to first check H2, which in turn will cause us to first check
+H3.
+
+H3 only includes H1, so when we check it, we do not have any
+declarations from H2 in the context. There used to be code in
+GatherDecls::visitTranslationUnit that would, as part of the "second
+pass", check the validity of all included structures. This would check
+Struct1, and fail, because Struct2 is not declared.
+
+Fundamentally, it doesn't make sense to check anything declared in an
+included file in the context of the file that included it.
+
+Note that this error did not show up when either H2 or H3 was
+checked. This is because in those cases we are not in the middle of
+checking H1 when we check H3, so we end up fully checking H1 before we
+get to the end of checking H3. This means the "visited" tag gets put
+on Struct1 before we get to the end of that troublesome block of code
+in visitTranslationUnit, and visitStructDecl doesn't do anything if
+that tag is set, so we don't end up actually checking H1 in the
+context of H3.
+
+*/
+
+struct Struct1
+{
+ Struct2 b;
+};
diff --git a/ipc/ipdl/test/ipdl/ok/MutRecHeader2.ipdlh b/ipc/ipdl/test/ipdl/ok/MutRecHeader2.ipdlh
new file mode 100644
index 0000000000..142979dc45
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/ok/MutRecHeader2.ipdlh
@@ -0,0 +1,8 @@
+include MutRecHeader3;
+
+// See MutRecHeader1.ipdlh for explanation.
+
+struct Struct2
+{
+ bool b;
+};
diff --git a/ipc/ipdl/test/ipdl/ok/MutRecHeader3.ipdlh b/ipc/ipdl/test/ipdl/ok/MutRecHeader3.ipdlh
new file mode 100644
index 0000000000..2e303ae444
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/ok/MutRecHeader3.ipdlh
@@ -0,0 +1,8 @@
+include MutRecHeader1;
+
+// See MutRecHeader1.ipdlh for explanation.
+
+struct Struct3
+{
+ bool b;
+};
diff --git a/ipc/ipdl/test/ipdl/ok/MyTypes.ipdlh b/ipc/ipdl/test/ipdl/ok/MyTypes.ipdlh
new file mode 100644
index 0000000000..9e33d71c51
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/ok/MyTypes.ipdlh
@@ -0,0 +1,6 @@
+include protocol PMyManaged;
+
+struct MyActorPair {
+ PMyManaged actor1;
+ nullable PMyManaged actor2;
+};
diff --git a/ipc/ipdl/test/ipdl/ok/PAsyncReturn.ipdl b/ipc/ipdl/test/ipdl/ok/PAsyncReturn.ipdl
new file mode 100644
index 0000000000..5deae9216b
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/ok/PAsyncReturn.ipdl
@@ -0,0 +1,9 @@
+// Async messages are not allowed to return values.
+
+//error: asynchronous message `Msg' declares return values
+
+[ChildProc=any]
+protocol PAsyncReturn {
+child:
+ async Msg() returns(int32_t aNumber);
+};
diff --git a/ipc/ipdl/test/ipdl/ok/PDelete.ipdl b/ipc/ipdl/test/ipdl/ok/PDelete.ipdl
new file mode 100644
index 0000000000..006c73dc0d
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/ok/PDelete.ipdl
@@ -0,0 +1,9 @@
+include protocol PDeleteSub;
+
+[ChildProc=any]
+sync protocol PDelete {
+ manages PDeleteSub;
+
+child:
+ async PDeleteSub();
+};
diff --git a/ipc/ipdl/test/ipdl/ok/PDeleteSub.ipdl b/ipc/ipdl/test/ipdl/ok/PDeleteSub.ipdl
new file mode 100644
index 0000000000..12b4c677eb
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/ok/PDeleteSub.ipdl
@@ -0,0 +1,10 @@
+include protocol PDelete;
+
+sync protocol PDeleteSub {
+ manager PDelete;
+
+parent:
+ sync __delete__(int x) returns (double d);
+
+};
+
diff --git a/ipc/ipdl/test/ipdl/ok/PEndpointDecl.ipdl b/ipc/ipdl/test/ipdl/ok/PEndpointDecl.ipdl
new file mode 100644
index 0000000000..f8fe51864a
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/ok/PEndpointDecl.ipdl
@@ -0,0 +1,19 @@
+
+// Basic test that Endpoint types are declared for protocols, within
+// that protocol.
+
+struct Whatever {
+ Endpoint<PEndpointDeclParent> par;
+ Endpoint<PEndpointDeclChild> chi;
+};
+
+namespace mozilla {
+
+[ChildProc=any]
+protocol PEndpointDecl {
+ child:
+ async Message(Endpoint<PEndpointDeclParent> aEndpointParent,
+ Endpoint<PEndpointDeclChild> aEndpointChild);
+};
+
+}
diff --git a/ipc/ipdl/test/ipdl/ok/PEndpointUse.ipdl b/ipc/ipdl/test/ipdl/ok/PEndpointUse.ipdl
new file mode 100644
index 0000000000..8fde19c8e5
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/ok/PEndpointUse.ipdl
@@ -0,0 +1,10 @@
+include protocol PEndpointDecl;
+
+// Basic test that Endpoint types are declared for included protocols.
+
+[ChildProc=any]
+protocol PEndpointUse {
+ child:
+ async Message(Endpoint<PEndpointDeclParent> aEndpointParent,
+ Endpoint<PEndpointDeclChild> aEndpointChild);
+};
diff --git a/ipc/ipdl/test/ipdl/ok/PExtendedAttrMultipleAttributes.ipdl b/ipc/ipdl/test/ipdl/ok/PExtendedAttrMultipleAttributes.ipdl
new file mode 100644
index 0000000000..ce49ed8d2a
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/ok/PExtendedAttrMultipleAttributes.ipdl
@@ -0,0 +1,5 @@
+[NestedUpTo=inside_sync, NeedsOtherPid, ChildProc=any]
+async protocol PExtendedAttrMultipleAttributes {
+parent:
+ async Msg();
+};
diff --git a/ipc/ipdl/test/ipdl/ok/PLazySend.ipdl b/ipc/ipdl/test/ipdl/ok/PLazySend.ipdl
new file mode 100644
index 0000000000..e67b35a153
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/ok/PLazySend.ipdl
@@ -0,0 +1,7 @@
+[ChildProc=any]
+protocol PLazySend {
+child:
+ [LazySend] async foo();
+parent:
+ [LazySend] async bar() returns (bool baz);
+};
diff --git a/ipc/ipdl/test/ipdl/ok/PManagedEndpointDecl.ipdl b/ipc/ipdl/test/ipdl/ok/PManagedEndpointDecl.ipdl
new file mode 100644
index 0000000000..13eb10fcc4
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/ok/PManagedEndpointDecl.ipdl
@@ -0,0 +1,23 @@
+include protocol PManagedEndpointManager;
+
+// Basic test that ManagedEndpoint types are declared for protocols, within
+// that protocol.
+
+struct ManagedWhatever {
+ ManagedEndpoint<PManagedEndpointDeclParent> par;
+ ManagedEndpoint<PManagedEndpointDeclChild> chi;
+};
+
+namespace mozilla {
+
+protocol PManagedEndpointDecl {
+ manager PManagedEndpointManager;
+
+child:
+ async Message(ManagedEndpoint<PManagedEndpointDeclParent> aEndpointParent,
+ ManagedEndpoint<PManagedEndpointDeclChild> aEndpointChild);
+
+ async __delete__();
+};
+
+}
diff --git a/ipc/ipdl/test/ipdl/ok/PManagedEndpointManager.ipdl b/ipc/ipdl/test/ipdl/ok/PManagedEndpointManager.ipdl
new file mode 100644
index 0000000000..2ae381c72b
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/ok/PManagedEndpointManager.ipdl
@@ -0,0 +1,15 @@
+include protocol PManagedEndpointDecl;
+
+namespace mozilla {
+
+[ChildProc=any]
+protocol PManagedEndpointManager {
+ manages PManagedEndpointDecl;
+
+child:
+ async Message(ManagedEndpoint<PManagedEndpointDeclParent> aEndpointParent,
+ ManagedEndpoint<PManagedEndpointDeclChild> aEndpointChild);
+};
+
+}
+
diff --git a/ipc/ipdl/test/ipdl/ok/PManualDealloc.ipdl b/ipc/ipdl/test/ipdl/ok/PManualDealloc.ipdl
new file mode 100644
index 0000000000..53660762ad
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/ok/PManualDealloc.ipdl
@@ -0,0 +1,8 @@
+include protocol PManualDealloc_manager;
+
+[ManualDealloc] async protocol PManualDealloc {
+ manager PManualDealloc_manager;
+
+child:
+ async __delete__();
+};
diff --git a/ipc/ipdl/test/ipdl/ok/PManualDealloc_manager.ipdl b/ipc/ipdl/test/ipdl/ok/PManualDealloc_manager.ipdl
new file mode 100644
index 0000000000..d425a6781f
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/ok/PManualDealloc_manager.ipdl
@@ -0,0 +1,8 @@
+include protocol PManualDealloc;
+
+// [ManualDealloc] types must have a manager, as all toplevel protocols are
+// refcounted.
+[ChildProc=any]
+async protocol PManualDealloc_manager {
+ manages PManualDealloc;
+};
diff --git a/ipc/ipdl/test/ipdl/ok/PMessageTainted.ipdl b/ipc/ipdl/test/ipdl/ok/PMessageTainted.ipdl
new file mode 100644
index 0000000000..deb10fb7ac
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/ok/PMessageTainted.ipdl
@@ -0,0 +1,5 @@
+[ChildProc=any]
+intr protocol PMessageTainted {
+child:
+ [Tainted] async foo();
+};
diff --git a/ipc/ipdl/test/ipdl/ok/PMessageTaintedWithPassback.ipdl b/ipc/ipdl/test/ipdl/ok/PMessageTaintedWithPassback.ipdl
new file mode 100644
index 0000000000..8db2c8b742
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/ok/PMessageTaintedWithPassback.ipdl
@@ -0,0 +1,5 @@
+[ChildProc=any]
+intr protocol PMessageTaintedWithPassback {
+child:
+ [Tainted] async foo([NoTaint=passback] int id);
+};
diff --git a/ipc/ipdl/test/ipdl/ok/PMyManaged.ipdl b/ipc/ipdl/test/ipdl/ok/PMyManaged.ipdl
new file mode 100644
index 0000000000..d6ddb34bf8
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/ok/PMyManaged.ipdl
@@ -0,0 +1,13 @@
+include protocol PMyManager;
+
+namespace mozilla {
+namespace myns {
+
+protocol PMyManaged {
+ manager PMyManager;
+ child:
+ async __delete__(Shmem aShmem);
+};
+
+} // namespace myns
+} // namespace mozilla
diff --git a/ipc/ipdl/test/ipdl/ok/PMyManager.ipdl b/ipc/ipdl/test/ipdl/ok/PMyManager.ipdl
new file mode 100644
index 0000000000..4ed2706ffd
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/ok/PMyManager.ipdl
@@ -0,0 +1,31 @@
+include protocol PMyManaged;
+include MyTypes; // for MyActorPair
+
+using MyActorEnum from "mozilla/myns/MyActorUtils.h";
+using mozilla::myns::MyData from "mozilla/MyDataTypes.h";
+[MoveOnly] using class mozilla::myns::MyOtherData from "mozilla/MyDataTypes.h";
+[RefCounted] using class mozilla::myns::MyThirdData from "mozilla/MyDataTypes.h";
+
+namespace mozilla {
+namespace myns {
+
+[Comparable] union MyUnion {
+ float;
+ MyOtherData;
+};
+
+[ChildProc=any]
+sync protocol PMyManager {
+ manages PMyManaged;
+ parent:
+ async __delete__(nsString aNote);
+ sync SomeMsg(MyActorPair? aActors, MyData[] aMyData)
+ returns (int32_t x, int32_t y, MyUnion aUnion);
+ async PMyManaged();
+ both:
+ [Tainted] async AnotherMsg(MyActorEnum aEnum, int32_t aNumber)
+ returns (MyOtherData aOtherData);
+};
+
+} // namespace myns
+} // namespace mozilla
diff --git a/ipc/ipdl/test/ipdl/ok/PNested.ipdl b/ipc/ipdl/test/ipdl/ok/PNested.ipdl
new file mode 100644
index 0000000000..94865bca6b
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/ok/PNested.ipdl
@@ -0,0 +1,8 @@
+[NestedUpTo=inside_cpow, ChildProc=any]
+sync protocol PNested {
+parent:
+ [Nested=not] async NotNested();
+ [Nested=inside_sync] sync InsideSync();
+ [Nested=inside_cpow] async InsideCpow();
+ [Nested=inside_cpow] sync InsideCpowSync();
+};
diff --git a/ipc/ipdl/test/ipdl/ok/PNullable.ipdl b/ipc/ipdl/test/ipdl/ok/PNullable.ipdl
new file mode 100644
index 0000000000..b7b21ff885
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/ok/PNullable.ipdl
@@ -0,0 +1,22 @@
+[RefCounted] using class nsIURI from "nsIURI.h";
+
+union Union {
+ nullable PNullable;
+ nullable PNullable[];
+ nullable PNullable?;
+ nullable nsIURI;
+ nullable nsIURI[];
+ nullable nsIURI?;
+};
+
+[ChildProc=any]
+protocol PNullable {
+child:
+ async Msg(nullable PNullable n);
+ async Msg2(nullable PNullable[] N);
+ async Msg3(nullable PNullable? n);
+ async Msg4(nullable nsIURI u);
+ async Msg5(nullable nsIURI[] u);
+ async Msg6(nullable nsIURI? u);
+ async Msg7(Union u);
+};
diff --git a/ipc/ipdl/test/ipdl/ok/PSideImpl.ipdl b/ipc/ipdl/test/ipdl/ok/PSideImpl.ipdl
new file mode 100644
index 0000000000..4ebb1b8ec3
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/ok/PSideImpl.ipdl
@@ -0,0 +1,5 @@
+[ParentImpl=virtual, ChildImpl="mozilla::FooBarImpl", ChildProc=any]
+async protocol PSideImpl {
+ parent:
+ async __delete__();
+};
diff --git a/ipc/ipdl/test/ipdl/ok/PStruct.ipdl b/ipc/ipdl/test/ipdl/ok/PStruct.ipdl
new file mode 100644
index 0000000000..f76f7db98f
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/ok/PStruct.ipdl
@@ -0,0 +1,11 @@
+struct S {
+ int i;
+ double d;
+};
+
+[ChildProc=any]
+sync protocol PStruct {
+parent:
+ sync test(S s) returns (S ss);
+ async __delete__();
+};
diff --git a/ipc/ipdl/test/ipdl/ok/PStructComparable.ipdl b/ipc/ipdl/test/ipdl/ok/PStructComparable.ipdl
new file mode 100644
index 0000000000..89576368ec
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/ok/PStructComparable.ipdl
@@ -0,0 +1,11 @@
+[Comparable] struct S {
+ int i;
+ double d;
+};
+
+[ChildProc=any]
+sync protocol PStructComparable {
+parent:
+ sync test(S s) returns (S ss);
+ async __delete__();
+};
diff --git a/ipc/ipdl/test/ipdl/ok/PSyncSyncManagee.ipdl b/ipc/ipdl/test/ipdl/ok/PSyncSyncManagee.ipdl
new file mode 100644
index 0000000000..458f0c83c0
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/ok/PSyncSyncManagee.ipdl
@@ -0,0 +1,7 @@
+include protocol PSyncSyncManager;
+
+sync protocol PSyncSyncManagee {
+ manager PSyncSyncManager;
+child:
+ async __delete__();
+};
diff --git a/ipc/ipdl/test/ipdl/ok/PSyncSyncManager.ipdl b/ipc/ipdl/test/ipdl/ok/PSyncSyncManager.ipdl
new file mode 100644
index 0000000000..d3fc236ff8
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/ok/PSyncSyncManager.ipdl
@@ -0,0 +1,12 @@
+include protocol PSyncSyncManagee;
+
+/* The main reason for this test is that it would have caught a bug
+ * in the Rust IPDL parser that was treating "sync" like "async" in the
+ * nested case.
+ */
+[NestedUpTo=not, ChildProc=any]
+sync protocol PSyncSyncManager {
+ manages PSyncSyncManagee;
+parent:
+ async PSyncSyncManagee();
+};
diff --git a/ipc/ipdl/test/ipdl/ok/PUniquePtrBasic.ipdl b/ipc/ipdl/test/ipdl/ok/PUniquePtrBasic.ipdl
new file mode 100644
index 0000000000..097dd04684
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/ok/PUniquePtrBasic.ipdl
@@ -0,0 +1,5 @@
+[ChildProc=any]
+protocol PUniquePtrBasic {
+child:
+ async Msg(UniquePtr<int> maybe);
+};
diff --git a/ipc/ipdl/test/ipdl/ok/PUniquePtrOfActors.ipdl b/ipc/ipdl/test/ipdl/ok/PUniquePtrOfActors.ipdl
new file mode 100644
index 0000000000..24631db712
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/ok/PUniquePtrOfActors.ipdl
@@ -0,0 +1,11 @@
+include protocol PUniquePtrOfActorsSub;
+
+[ChildProc=any]
+protocol PUniquePtrOfActors {
+ manages PUniquePtrOfActorsSub;
+
+child:
+ async Msg(UniquePtr<PUniquePtrOfActorsSub> p);
+
+ async PUniquePtrOfActorsSub();
+};
diff --git a/ipc/ipdl/test/ipdl/ok/PUniquePtrOfActorsSub.ipdl b/ipc/ipdl/test/ipdl/ok/PUniquePtrOfActorsSub.ipdl
new file mode 100644
index 0000000000..a60c8e475f
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/ok/PUniquePtrOfActorsSub.ipdl
@@ -0,0 +1,7 @@
+include protocol PUniquePtrOfActors;
+
+protocol PUniquePtrOfActorsSub {
+ manager PUniquePtrOfActors;
+
+child: async __delete__();
+};
diff --git a/ipc/ipdl/test/ipdl/ok/PUniquePtrRecUnion.ipdl b/ipc/ipdl/test/ipdl/ok/PUniquePtrRecUnion.ipdl
new file mode 100644
index 0000000000..40ac466b40
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/ok/PUniquePtrRecUnion.ipdl
@@ -0,0 +1,22 @@
+union X {
+ int;
+ Y[];
+ UniquePtr<Y>;
+};
+
+union Y {
+ X;
+ Z;
+};
+
+union Z {
+ double;
+ X;
+};
+
+[ChildProc=any]
+protocol PUniquePtrRecUnion {
+child:
+ async Test(X x, Y y, Z z);
+ async __delete__();
+};
diff --git a/ipc/ipdl/test/ipdl/ok/PUniquePtrUnion.ipdl b/ipc/ipdl/test/ipdl/ok/PUniquePtrUnion.ipdl
new file mode 100644
index 0000000000..de4529c639
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/ok/PUniquePtrUnion.ipdl
@@ -0,0 +1,11 @@
+union UniquePtrUnion {
+ int[];
+ int;
+ double;
+};
+
+[ChildProc=any]
+sync protocol PUniquePtrUnion {
+parent:
+ async Msg(UniquePtrUnion u, UniquePtr<UniquePtrUnion> au) returns (UniquePtrUnion r);
+};
diff --git a/ipc/ipdl/test/ipdl/ok/PVirtualSendImpl.ipdl b/ipc/ipdl/test/ipdl/ok/PVirtualSendImpl.ipdl
new file mode 100644
index 0000000000..ff09108965
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/ok/PVirtualSendImpl.ipdl
@@ -0,0 +1,6 @@
+[ChildProc=any]
+async protocol PVirtualSendImpl
+{
+child:
+ [VirtualSendImpl] async MockableFoo();
+};
diff --git a/ipc/ipdl/test/ipdl/ok/Pactorparam.ipdl b/ipc/ipdl/test/ipdl/ok/Pactorparam.ipdl
new file mode 100644
index 0000000000..bb7bb85518
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/ok/Pactorparam.ipdl
@@ -0,0 +1,6 @@
+[ChildProc=any]
+protocol Pactorparam {
+
+child: async Msg(Pactorparam p);
+
+};
diff --git a/ipc/ipdl/test/ipdl/ok/Pactorreturn.ipdl b/ipc/ipdl/test/ipdl/ok/Pactorreturn.ipdl
new file mode 100644
index 0000000000..4e8e53a9d6
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/ok/Pactorreturn.ipdl
@@ -0,0 +1,7 @@
+[ChildProc=any]
+sync protocol Pactorreturn {
+
+parent:
+ sync Msg(Pactorreturn p) returns (Pactorreturn r);
+
+};
diff --git a/ipc/ipdl/test/ipdl/ok/Parray_Basic.ipdl b/ipc/ipdl/test/ipdl/ok/Parray_Basic.ipdl
new file mode 100644
index 0000000000..7ce682f154
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/ok/Parray_Basic.ipdl
@@ -0,0 +1,5 @@
+[ChildProc=any]
+protocol Parray_Basic {
+child:
+ async Msg(int[] array);
+};
diff --git a/ipc/ipdl/test/ipdl/ok/Parray_OfActors.ipdl b/ipc/ipdl/test/ipdl/ok/Parray_OfActors.ipdl
new file mode 100644
index 0000000000..170f4e902a
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/ok/Parray_OfActors.ipdl
@@ -0,0 +1,11 @@
+include protocol Parray_OfActorsSub;
+
+[ChildProc=any]
+protocol Parray_OfActors {
+ manages Parray_OfActorsSub;
+
+child:
+ async Msg(Parray_OfActorsSub[] p);
+
+ async Parray_OfActorsSub();
+};
diff --git a/ipc/ipdl/test/ipdl/ok/Parray_OfActorsSub.ipdl b/ipc/ipdl/test/ipdl/ok/Parray_OfActorsSub.ipdl
new file mode 100644
index 0000000000..6769e98abb
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/ok/Parray_OfActorsSub.ipdl
@@ -0,0 +1,7 @@
+include protocol Parray_OfActors;
+
+protocol Parray_OfActorsSub {
+ manager Parray_OfActors;
+
+child: async __delete__();
+};
diff --git a/ipc/ipdl/test/ipdl/ok/Parray_Union.ipdl b/ipc/ipdl/test/ipdl/ok/Parray_Union.ipdl
new file mode 100644
index 0000000000..2733d5fc04
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/ok/Parray_Union.ipdl
@@ -0,0 +1,11 @@
+union Union {
+ int[];
+ int;
+ double;
+};
+
+[ChildProc=any]
+sync protocol Parray_Union {
+parent:
+ sync Msg(Union u, Union[] au) returns (Union r);
+};
diff --git a/ipc/ipdl/test/ipdl/ok/PbasicUsing.ipdl b/ipc/ipdl/test/ipdl/ok/PbasicUsing.ipdl
new file mode 100644
index 0000000000..94d57b08d0
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/ok/PbasicUsing.ipdl
@@ -0,0 +1,51 @@
+using SomeType from "SomeFile.h";
+using class SomeClass from "SomeFile.h";
+using struct SomeStruct from "SomeFile.h";
+
+[RefCounted] using SomeRefcountedType from "SomeFile.h";
+[RefCounted] using class SomeRefcountedClass from "SomeFile.h";
+[RefCounted] using struct SomeRefcountedStruct from "SomeFile.h";
+
+[MoveOnly] using SomeMoveonlyType from "SomeFile.h";
+[MoveOnly] using class SomeMoveonlyClass from "SomeFile.h";
+[MoveOnly] using struct SomeMoveonlyStruct from "SomeFile.h";
+
+[RefCounted, MoveOnly] using SomeRefcountedMoveonlyType from "SomeFile.h";
+[RefCounted, MoveOnly] using class SomeRefcountedMoveonlyClass from "SomeFile.h";
+[RefCounted, MoveOnly] using struct SomeRefcountedMoveonlyStruct from "SomeFile.h";
+
+[MoveOnly=data] using SomeMoveonlyDataType from "SomeFile.h";
+[MoveOnly=data] using class SomeMoveonlyDataClass from "SomeFile.h";
+[MoveOnly=data] using struct SomeMoveonlyDataStruct from "SomeFile.h";
+
+[MoveOnly=send] using SomeMoveonlySendType from "SomeFile.h";
+[MoveOnly=send] using class SomeMoveonlySendClass from "SomeFile.h";
+[MoveOnly=send] using struct SomeMoveonlySendStruct from "SomeFile.h";
+
+union SomeUnion
+{
+ SomeType;
+ SomeClass;
+ SomeStruct;
+ SomeRefcountedType;
+ SomeRefcountedClass;
+ SomeRefcountedStruct;
+ SomeMoveonlyType;
+ SomeMoveonlyClass;
+ SomeMoveonlyStruct;
+ SomeRefcountedMoveonlyType;
+ SomeRefcountedMoveonlyClass;
+ SomeRefcountedMoveonlyStruct;
+ SomeMoveonlyDataType;
+ SomeMoveonlyDataClass;
+ SomeMoveonlyDataStruct;
+ SomeMoveonlySendType;
+ SomeMoveonlySendClass;
+ SomeMoveonlySendStruct;
+};
+
+[ChildProc=any]
+protocol PbasicUsing {
+child:
+ async Msg(SomeUnion foo);
+};
diff --git a/ipc/ipdl/test/ipdl/ok/Pbuiltins.ipdl b/ipc/ipdl/test/ipdl/ok/Pbuiltins.ipdl
new file mode 100644
index 0000000000..3cd023a0b6
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/ok/Pbuiltins.ipdl
@@ -0,0 +1,22 @@
+[ChildProc=any]
+protocol Pbuiltins {
+
+ // sanity-check that "essential" builtins are being declared
+
+child: async Msg(bool b,
+ char c,
+ int i,
+ long l,
+
+ float f,
+ double d,
+
+ int8_t i8t,
+ uint8_t u8t,
+ int16_t i16t,
+ uint16_t u16t,
+ int32_t i32t,
+ uint32_t u32t,
+ int64_t i64t,
+ uint64_t u64t);
+};
diff --git a/ipc/ipdl/test/ipdl/ok/Pbytebuf.ipdl b/ipc/ipdl/test/ipdl/ok/Pbytebuf.ipdl
new file mode 100644
index 0000000000..a0ceac937f
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/ok/Pbytebuf.ipdl
@@ -0,0 +1,14 @@
+union Foo {
+ int;
+ ByteBuf;
+};
+
+[ChildProc=any]
+intr protocol Pbytebuf {
+parent:
+ async Msg(ByteBuf s, Foo f);
+ sync SyncMsg(ByteBuf s, Foo f)
+ returns (ByteBuf t, Foo g);
+ [LegacyIntr] intr InterruptMsg(ByteBuf s, Foo f)
+ returns (ByteBuf t, Foo g);
+};
diff --git a/ipc/ipdl/test/ipdl/ok/Pempty.ipdl b/ipc/ipdl/test/ipdl/ok/Pempty.ipdl
new file mode 100644
index 0000000000..4ab603dbc8
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/ok/Pempty.ipdl
@@ -0,0 +1,4 @@
+[ChildProc=any]
+protocol Pempty {
+child: async Msg();
+};
diff --git a/ipc/ipdl/test/ipdl/ok/PemptyStruct.ipdl b/ipc/ipdl/test/ipdl/ok/PemptyStruct.ipdl
new file mode 100644
index 0000000000..a3317cb872
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/ok/PemptyStruct.ipdl
@@ -0,0 +1,4 @@
+struct empty { };
+
+[ChildProc=any]
+protocol PemptyStruct { child: async __delete__(); };
diff --git a/ipc/ipdl/test/ipdl/ok/PheaderProto.ipdl b/ipc/ipdl/test/ipdl/ok/PheaderProto.ipdl
new file mode 100644
index 0000000000..5c9af7c3f9
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/ok/PheaderProto.ipdl
@@ -0,0 +1,11 @@
+include header;
+
+namespace c {
+
+[ChildProc=any]
+protocol PheaderProto {
+child:
+ async __delete__(foo a, baz b, Inner1 c, Inner2 d, X x);
+};
+
+}
diff --git a/ipc/ipdl/test/ipdl/ok/PintrProtocol.ipdl b/ipc/ipdl/test/ipdl/ok/PintrProtocol.ipdl
new file mode 100644
index 0000000000..4b663327e6
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/ok/PintrProtocol.ipdl
@@ -0,0 +1,14 @@
+[ChildProc=any]
+intr protocol PintrProtocol {
+
+ // sanity check of Interrupt protocols
+child:
+ async AsyncMsg();
+
+parent:
+ sync SyncMsg(int i) returns (int r);
+
+both:
+ [LegacyIntr] intr InterruptMsg(int x) returns (int y);
+
+};
diff --git a/ipc/ipdl/test/ipdl/ok/Pjetpack.ipdl b/ipc/ipdl/test/ipdl/ok/Pjetpack.ipdl
new file mode 100644
index 0000000000..7744f59f8f
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/ok/Pjetpack.ipdl
@@ -0,0 +1,6 @@
+[ChildProc=any]
+sync protocol Pjetpack {
+child:
+ async __delete__();
+
+};
diff --git a/ipc/ipdl/test/ipdl/ok/PmanageSelf.ipdl b/ipc/ipdl/test/ipdl/ok/PmanageSelf.ipdl
new file mode 100644
index 0000000000..992f374a58
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/ok/PmanageSelf.ipdl
@@ -0,0 +1,10 @@
+include protocol PmanageSelf_Toplevel;
+
+protocol PmanageSelf {
+ manager PmanageSelf_Toplevel or PmanageSelf;
+ manages PmanageSelf;
+
+child:
+ async PmanageSelf();
+ async __delete__();
+};
diff --git a/ipc/ipdl/test/ipdl/ok/PmanageSelf_Toplevel.ipdl b/ipc/ipdl/test/ipdl/ok/PmanageSelf_Toplevel.ipdl
new file mode 100644
index 0000000000..15be35f838
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/ok/PmanageSelf_Toplevel.ipdl
@@ -0,0 +1,10 @@
+include protocol PmanageSelf;
+
+[ChildProc=any]
+protocol PmanageSelf_Toplevel {
+ manages PmanageSelf;
+
+child:
+ async PmanageSelf();
+ async __delete__();
+};
diff --git a/ipc/ipdl/test/ipdl/ok/PmanagedProtocol.ipdl b/ipc/ipdl/test/ipdl/ok/PmanagedProtocol.ipdl
new file mode 100644
index 0000000000..cab07d06e7
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/ok/PmanagedProtocol.ipdl
@@ -0,0 +1,8 @@
+include protocol PmanagerProtocol;
+
+protocol PmanagedProtocol {
+ manager PmanagerProtocol;
+
+child:
+ async __delete__();
+};
diff --git a/ipc/ipdl/test/ipdl/ok/PmanagerProtocol.ipdl b/ipc/ipdl/test/ipdl/ok/PmanagerProtocol.ipdl
new file mode 100644
index 0000000000..28483426d3
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/ok/PmanagerProtocol.ipdl
@@ -0,0 +1,12 @@
+include protocol PmanagedProtocol;
+
+// sanity check of managed/manager protocols
+
+[ChildProc=any]
+protocol PmanagerProtocol {
+ manages PmanagedProtocol;
+
+parent:
+ async PmanagedProtocol(int i);
+
+};
diff --git a/ipc/ipdl/test/ipdl/ok/Pmaybe_Basic.ipdl b/ipc/ipdl/test/ipdl/ok/Pmaybe_Basic.ipdl
new file mode 100644
index 0000000000..52243d5ca3
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/ok/Pmaybe_Basic.ipdl
@@ -0,0 +1,5 @@
+[ChildProc=any]
+protocol Pmaybe_Basic {
+child:
+ async Msg(int? maybe);
+};
diff --git a/ipc/ipdl/test/ipdl/ok/Pmaybe_OfActors.ipdl b/ipc/ipdl/test/ipdl/ok/Pmaybe_OfActors.ipdl
new file mode 100644
index 0000000000..2252c32827
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/ok/Pmaybe_OfActors.ipdl
@@ -0,0 +1,11 @@
+include protocol Pmaybe_OfActorsSub;
+
+[ChildProc=any]
+protocol Pmaybe_OfActors {
+ manages Pmaybe_OfActorsSub;
+
+child:
+ async Msg(Pmaybe_OfActorsSub? p);
+
+ async Pmaybe_OfActorsSub();
+};
diff --git a/ipc/ipdl/test/ipdl/ok/Pmaybe_OfActorsSub.ipdl b/ipc/ipdl/test/ipdl/ok/Pmaybe_OfActorsSub.ipdl
new file mode 100644
index 0000000000..6a4759953f
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/ok/Pmaybe_OfActorsSub.ipdl
@@ -0,0 +1,7 @@
+include protocol Pmaybe_OfActors;
+
+protocol Pmaybe_OfActorsSub {
+ manager Pmaybe_OfActors;
+
+child: async __delete__();
+};
diff --git a/ipc/ipdl/test/ipdl/ok/Pmaybe_Union.ipdl b/ipc/ipdl/test/ipdl/ok/Pmaybe_Union.ipdl
new file mode 100644
index 0000000000..5701b08fd9
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/ok/Pmaybe_Union.ipdl
@@ -0,0 +1,11 @@
+union MaybeUnion {
+ int[];
+ int;
+ double;
+};
+
+[ChildProc=any]
+sync protocol Pmaybe_Union {
+parent:
+ async Msg(MaybeUnion u, MaybeUnion? au) returns (MaybeUnion r);
+};
diff --git a/ipc/ipdl/test/ipdl/ok/Pmedia.ipdl b/ipc/ipdl/test/ipdl/ok/Pmedia.ipdl
new file mode 100644
index 0000000000..e0f95d2a34
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/ok/Pmedia.ipdl
@@ -0,0 +1,6 @@
+[ChildProc=any]
+sync protocol Pmedia {
+child:
+ async __delete__();
+
+};
diff --git a/ipc/ipdl/test/ipdl/ok/PmessageCompress.ipdl b/ipc/ipdl/test/ipdl/ok/PmessageCompress.ipdl
new file mode 100644
index 0000000000..7e14c888dd
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/ok/PmessageCompress.ipdl
@@ -0,0 +1,6 @@
+[ChildProc=any]
+intr protocol PmessageCompress {
+child:
+ [Compress] async foo();
+ [Compress=all] async bar();
+};
diff --git a/ipc/ipdl/test/ipdl/ok/PmultiManaged.ipdl b/ipc/ipdl/test/ipdl/ok/PmultiManaged.ipdl
new file mode 100644
index 0000000000..d8c47fc9e3
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/ok/PmultiManaged.ipdl
@@ -0,0 +1,9 @@
+include protocol PmultiManager1;
+include protocol PmultiManager2;
+
+protocol PmultiManaged {
+ manager PmultiManager1 or PmultiManager2;
+
+child:
+ async __delete__();
+};
diff --git a/ipc/ipdl/test/ipdl/ok/PmultiManager1.ipdl b/ipc/ipdl/test/ipdl/ok/PmultiManager1.ipdl
new file mode 100644
index 0000000000..ec38412422
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/ok/PmultiManager1.ipdl
@@ -0,0 +1,9 @@
+include protocol PmultiManaged;
+
+[ChildProc=any]
+protocol PmultiManager1 {
+ manages PmultiManaged;
+
+child:
+ async PmultiManaged();
+};
diff --git a/ipc/ipdl/test/ipdl/ok/PmultiManager2.ipdl b/ipc/ipdl/test/ipdl/ok/PmultiManager2.ipdl
new file mode 100644
index 0000000000..b8295fd057
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/ok/PmultiManager2.ipdl
@@ -0,0 +1,9 @@
+include protocol PmultiManaged;
+
+[ChildProc=any]
+protocol PmultiManager2 {
+ manages PmultiManaged;
+
+child:
+ async PmultiManaged();
+};
diff --git a/ipc/ipdl/test/ipdl/ok/PmultipleUsingCxxTypes.ipdl b/ipc/ipdl/test/ipdl/ok/PmultipleUsingCxxTypes.ipdl
new file mode 100644
index 0000000000..5d5ae5e9a8
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/ok/PmultipleUsingCxxTypes.ipdl
@@ -0,0 +1,8 @@
+using struct mozilla::void_t from "mozilla/ipc/IPCCore.h";
+using struct mozilla::void_t from "mozilla/ipc/IPCCore.h";
+
+[ChildProc=any]
+protocol PmultipleUsingCxxTypes {
+child:
+ async Msg(void_t foo);
+};
diff --git a/ipc/ipdl/test/ipdl/ok/PmutualRecStructUnion.ipdl b/ipc/ipdl/test/ipdl/ok/PmutualRecStructUnion.ipdl
new file mode 100644
index 0000000000..b28df7969b
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/ok/PmutualRecStructUnion.ipdl
@@ -0,0 +1,22 @@
+struct X {
+ int i;
+ Y[] y;
+};
+
+union Y {
+ double;
+ X;
+ Z;
+};
+
+struct Z {
+ X x;
+ Y y;
+};
+
+[ChildProc=any]
+protocol PmutualRecStructUnion {
+child:
+ async Test(X x, Y y, Z z);
+ async __delete__();
+};
diff --git a/ipc/ipdl/test/ipdl/ok/PmutualRecUnion.ipdl b/ipc/ipdl/test/ipdl/ok/PmutualRecUnion.ipdl
new file mode 100644
index 0000000000..73c869278f
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/ok/PmutualRecUnion.ipdl
@@ -0,0 +1,22 @@
+union X {
+ int;
+ Y[];
+ Y?;
+};
+
+union Y {
+ X;
+ Z;
+};
+
+union Z {
+ double;
+ X;
+};
+
+[ChildProc=any]
+protocol PmutualRecUnion {
+child:
+ async Test(X x, Y y, Z z);
+ async __delete__();
+};
diff --git a/ipc/ipdl/test/ipdl/ok/Pnamespace_Basic.ipdl b/ipc/ipdl/test/ipdl/ok/Pnamespace_Basic.ipdl
new file mode 100644
index 0000000000..3b2f2fa27f
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/ok/Pnamespace_Basic.ipdl
@@ -0,0 +1,13 @@
+namespace basic {
+
+// sanity check of namespaced protocols
+
+[ChildProc=any]
+protocol Pnamespace_Basic {
+
+child:
+ async Msg();
+
+};
+
+} // namespace basic
diff --git a/ipc/ipdl/test/ipdl/ok/PnoRedeclCrossMessage.ipdl b/ipc/ipdl/test/ipdl/ok/PnoRedeclCrossMessage.ipdl
new file mode 100644
index 0000000000..30c7179e8c
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/ok/PnoRedeclCrossMessage.ipdl
@@ -0,0 +1,10 @@
+[ChildProc=any]
+protocol PnoRedeclCrossMessage {
+
+ // each message has its own scope for param/return names
+
+child:
+ async Msg1(int f);
+ async Msg2(int f);
+
+};
diff --git a/ipc/ipdl/test/ipdl/ok/Pplugin.ipdl b/ipc/ipdl/test/ipdl/ok/Pplugin.ipdl
new file mode 100644
index 0000000000..f7d9352a08
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/ok/Pplugin.ipdl
@@ -0,0 +1,6 @@
+[ChildProc=any]
+intr protocol Pplugin {
+child:
+ async __delete__();
+
+};
diff --git a/ipc/ipdl/test/ipdl/ok/Prio.ipdl b/ipc/ipdl/test/ipdl/ok/Prio.ipdl
new file mode 100644
index 0000000000..fdda57f784
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/ok/Prio.ipdl
@@ -0,0 +1,12 @@
+[ChildProc=any]
+async protocol Prio
+{
+child:
+ [Priority=normal] async NormalPrio();
+ [Priority=vsync] async VsyncPrio();
+ [Priority=input] async InputPrio();
+ [Priority=mediumhigh] async MediumHighPrio();
+ [Priority=control] async ControlPrio();
+ [ReplyPriority=control] async ControlPrioReturns() returns (bool aValue);
+ [Priority=normal, ReplyPriority=control] async NormalControlPrioReturns() returns (bool aValue);
+};
diff --git a/ipc/ipdl/test/ipdl/ok/PselfRecUnion.ipdl b/ipc/ipdl/test/ipdl/ok/PselfRecUnion.ipdl
new file mode 100644
index 0000000000..9d5e3de487
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/ok/PselfRecUnion.ipdl
@@ -0,0 +1,12 @@
+union R {
+ int;
+ double;
+ R;
+};
+
+[ChildProc=any]
+protocol PselfRecUnion {
+child:
+ async Test(R r);
+ async __delete__();
+};
diff --git a/ipc/ipdl/test/ipdl/ok/Pshmem.ipdl b/ipc/ipdl/test/ipdl/ok/Pshmem.ipdl
new file mode 100644
index 0000000000..a46e777d8c
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/ok/Pshmem.ipdl
@@ -0,0 +1,14 @@
+union Foo {
+ int;
+ Shmem;
+};
+
+[ChildProc=any]
+intr protocol Pshmem {
+parent:
+ async Msg(Shmem s, Foo f);
+ sync SyncMsg(Shmem s, Foo f)
+ returns (Shmem t, Foo g);
+ [LegacyIntr] intr InterruptMsg(Shmem s, Foo f)
+ returns (Shmem t, Foo g);
+};
diff --git a/ipc/ipdl/test/ipdl/ok/PsyncProtocol.ipdl b/ipc/ipdl/test/ipdl/ok/PsyncProtocol.ipdl
new file mode 100644
index 0000000000..f73be554e4
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/ok/PsyncProtocol.ipdl
@@ -0,0 +1,12 @@
+[ChildProc=any]
+sync protocol PsyncProtocol {
+
+ // sanity check of sync protocols
+
+child:
+ async AsyncMsg();
+
+parent:
+ sync SyncMsg() returns (int i);
+
+};
diff --git a/ipc/ipdl/test/ipdl/ok/PthreeDirections.ipdl b/ipc/ipdl/test/ipdl/ok/PthreeDirections.ipdl
new file mode 100644
index 0000000000..6474ca5d0d
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/ok/PthreeDirections.ipdl
@@ -0,0 +1,14 @@
+[ChildProc=any]
+protocol PthreeDirections {
+
+ // sanity check that the three direction specifiers are being accepted
+child:
+ async ChildMsg();
+
+parent:
+ async ParentMsg();
+
+both:
+ async BothMsg();
+
+};
diff --git a/ipc/ipdl/test/ipdl/ok/Punion_Basic.ipdl b/ipc/ipdl/test/ipdl/ok/Punion_Basic.ipdl
new file mode 100644
index 0000000000..a049d52e75
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/ok/Punion_Basic.ipdl
@@ -0,0 +1,12 @@
+union Basic {
+ int;
+ double;
+};
+
+[ChildProc=any]
+sync protocol Punion_Basic {
+
+parent:
+ sync Msg(Basic p) returns (Basic r);
+
+};
diff --git a/ipc/ipdl/test/ipdl/ok/Punion_Comparable.ipdl b/ipc/ipdl/test/ipdl/ok/Punion_Comparable.ipdl
new file mode 100644
index 0000000000..05b26f32aa
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/ok/Punion_Comparable.ipdl
@@ -0,0 +1,12 @@
+[Comparable] union Basic {
+ int;
+ double;
+};
+
+[ChildProc=any]
+sync protocol Punion_Comparable {
+
+parent:
+ sync Msg(Basic p) returns (Basic r);
+
+};
diff --git a/ipc/ipdl/test/ipdl/ok/Punion_Namespaced.ipdl b/ipc/ipdl/test/ipdl/ok/Punion_Namespaced.ipdl
new file mode 100644
index 0000000000..4108dfd4df
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/ok/Punion_Namespaced.ipdl
@@ -0,0 +1,19 @@
+namespace kitties {
+
+union Socks {
+ int;
+ double;
+};
+
+} // namespace kitties
+
+
+namespace puppies {
+
+[ChildProc=any]
+protocol Punion_Namespaced {
+child:
+ async Msg(Socks s);
+};
+
+} // namespace puppies
diff --git a/ipc/ipdl/test/ipdl/ok/header.ipdlh b/ipc/ipdl/test/ipdl/ok/header.ipdlh
new file mode 100644
index 0000000000..fc3f8c8279
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/ok/header.ipdlh
@@ -0,0 +1,15 @@
+using foo from "foo.h";
+using bar::baz from "foo.h";
+
+struct Outer { };
+
+namespace a { struct Inner1 { }; }
+
+namespace b { struct Inner2 { }; }
+
+namespace c {
+union X {
+ int32_t;
+ float;
+};
+}
diff --git a/ipc/ipdl/test/ipdl/runtests.py b/ipc/ipdl/test/ipdl/runtests.py
new file mode 100644
index 0000000000..4296eab65c
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/runtests.py
@@ -0,0 +1,119 @@
+import os
+import unittest
+
+from IPDLCompile import IPDLCompile
+
+
+class IPDLTestCase(unittest.TestCase):
+ def __init__(self, ipdlargv, filename):
+ unittest.TestCase.__init__(self, "test")
+ self.filename = filename
+ self.compile = IPDLCompile(filename, ipdlargv)
+
+ def test(self):
+ self.compile.run()
+ self.assertFalse(self.compile.exception(), self.mkFailMsg())
+ self.checkPassed()
+
+ def mkCustomMsg(self, msg):
+ return """
+### Command: %s
+### %s
+### stderr:
+%s""" % (
+ " ".join(self.compile.argv),
+ msg,
+ self.compile.stderr,
+ )
+
+ def mkFailMsg(self):
+ return """
+### Command: %s
+### stderr:
+%s""" % (
+ " ".join(self.compile.argv),
+ self.compile.stderr,
+ )
+
+ def shortDescription(self):
+ return '%s test of "%s"' % (self.__class__.__name__, self.filename)
+
+
+class OkTestCase(IPDLTestCase):
+ """An invocation of the IPDL compiler on a valid specification.
+ The IPDL compiler should not produce errors or exceptions."""
+
+ def __init__(self, ipdlargv, filename):
+ IPDLTestCase.__init__(self, ipdlargv, filename)
+
+ def checkPassed(self):
+ self.assertTrue(self.compile.ok(), self.mkFailMsg())
+
+
+class ErrorTestCase(IPDLTestCase):
+ """An invocation of the IPDL compiler on an *invalid* specification.
+ The IPDL compiler *should* produce errors but not exceptions."""
+
+ def __init__(self, ipdlargv, filename):
+ IPDLTestCase.__init__(self, ipdlargv, filename)
+
+ # Look for expected errors in the input file.
+ f = open(filename, "r")
+ self.expectedErrorMessage = []
+ for l in f:
+ if l.startswith("//error:"):
+ self.expectedErrorMessage.append(l[2:-1])
+ f.close()
+
+ def checkPassed(self):
+ self.assertNotEqual(
+ self.expectedErrorMessage,
+ [],
+ self.mkCustomMsg(
+ "Error test should contain at least "
+ + "one line starting with //error: "
+ + "that indicates the expected failure."
+ ),
+ )
+
+ for e in self.expectedErrorMessage:
+ self.assertTrue(
+ self.compile.error(e),
+ self.mkCustomMsg('Did not see expected error "' + e + '"'),
+ )
+
+
+if __name__ == "__main__":
+ import sys
+
+ okdir = sys.argv[1]
+ assert os.path.isdir(okdir)
+ errordir = sys.argv[2]
+ assert os.path.isdir(errordir)
+
+ ipdlargv = []
+ oksuite = unittest.TestSuite()
+ errorsuite = unittest.TestSuite()
+
+ oktests, errortests = False, False
+ for arg in sys.argv[3:]:
+ if errortests:
+ # The extra subdirectory is used for non-failing files we want
+ # to include from failing files.
+ errorIncludes = ["-I", os.path.join(errordir, "extra"), "-I", errordir]
+ errorsuite.addTest(ErrorTestCase(ipdlargv + errorIncludes, arg))
+ elif oktests:
+ if "ERRORTESTS" == arg:
+ errortests = True
+ continue
+ oksuite.addTest(OkTestCase(ipdlargv + ["-I", okdir], arg))
+ else:
+ if "OKTESTS" == arg:
+ oktests = True
+ continue
+ ipdlargv.append(arg)
+
+ test_result = (unittest.TextTestRunner()).run(
+ unittest.TestSuite([oksuite, errorsuite])
+ )
+ sys.exit(not test_result.wasSuccessful())
diff --git a/ipc/ipdl/test/ipdl/sync-messages.ini b/ipc/ipdl/test/ipdl/sync-messages.ini
new file mode 100644
index 0000000000..989964f0dd
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/sync-messages.ini
@@ -0,0 +1,50 @@
+[Pactorreturn::Msg]
+description = test only
+[Parray_Union::Msg]
+description = test only
+[Punion_Basic::Msg]
+description = test only
+[PStruct::test]
+description = test only
+[PStructComparable::test]
+description = test only
+[Punion_Comparable::Msg]
+description = test only
+[PintrProtocol::SyncMsg]
+description = test only
+[PintrProtocol::InterruptMsg]
+description = test only
+[Pshmem::SyncMsg]
+description = test only
+[Pshmem::InterruptMsg]
+description = test only
+[Pbytebuf::SyncMsg]
+description = test only
+[Pbytebuf::InterruptMsg]
+description = test only
+[PsyncProtocol::SyncMsg]
+description = test only
+[PDeleteSub::__delete__]
+description = test only
+[PintrMessageCompress::foo]
+description = test only
+[PintrMessageCompress::bar]
+description = test only
+[PsyncMessageCompress::foo]
+description = test only
+[PsyncParentToChild::Msg]
+description = test only
+[PtooWeakIntrSync::Msg]
+description = test only
+[PtooWeakSyncAsync::Msg]
+description = test only
+[PundeclReturnType::Msg]
+description = test only
+[PasyncMessageListed::Msg]
+description = test only
+[PNested::InsideSync]
+description = test only
+[PNested::InsideCpowSync]
+description = test only
+[PMyManager::SomeMsg]
+description = test and docs only
diff --git a/ipc/ipdl/test/moz.build b/ipc/ipdl/test/moz.build
new file mode 100644
index 0000000000..a323b4a2eb
--- /dev/null
+++ b/ipc/ipdl/test/moz.build
@@ -0,0 +1,9 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# 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/.
+
+DIRS += ["ipdl"]
+
+TEST_DIRS += ["gtest"]