Bug 1319620 - Check that IPDL unit tests in error/ fail for the right reason. r=billm
authorAndrew McCreight <continuation@gmail.com>
Wed, 15 Mar 2017 10:43:51 -0700
changeset 348983 77b2d02883686bbf683a99afbe275a0c46ef22e3
parent 348982 e3afc4f01b903551aaf48ff31c03991409a23f11
child 348984 f23ce5b464f89824fa836efc6cb93d33a2ae99e0
push id31541
push usercbook@mozilla.com
push dateThu, 23 Mar 2017 12:43:04 +0000
treeherdermozilla-central@89b93d310da5 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbillm
bugs1319620, 1347527
milestone55.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1319620 - Check that IPDL unit tests in error/ fail for the right reason. r=billm An IPDL unit test that is intended to fail should check that the reason the test fails matches the expected reason for failure. We have had a number of cases where some change, like renaming a keyword, causes tests to start failing for the wrong reason, which means they are no longer testing anything useful. To support this, each file in error/ must contain one or more error annotations. An error annotation is a line starting with "//error:", followed by whatever the rest of the expected error is. For every one of these annotations that a file has, the stderr output of compiling the test must contain the specified string, including the "error:". It is also an error for an error/ file to not contain an error annotation. To generate the initial set of annotations, I just copied and pasted the error that each test produced. I did some light auditing to check that the errors are reasonable, which did turn up one minor error which I fixed as part of bug 1347527. This patch does not check that every error produced by compiling the file is in the list of expected errors. I think that's less of a problem if it does occur. MozReview-Commit-ID: BrePLGPPRil
ipc/ipdl/test/ipdl/IPDLCompile.py
ipc/ipdl/test/ipdl/error/AsyncInsideSync.ipdl
ipc/ipdl/test/ipdl/error/AsyncReturn.ipdl
ipc/ipdl/test/ipdl/error/BadNestedManagee.ipdl
ipc/ipdl/test/ipdl/error/BadNestedManager.ipdl
ipc/ipdl/test/ipdl/error/ForgottenManagee.ipdl
ipc/ipdl/test/ipdl/error/ForgottenManager.ipdl
ipc/ipdl/test/ipdl/error/InsideCpowToChild.ipdl
ipc/ipdl/test/ipdl/error/IntrAsyncManagee.ipdl
ipc/ipdl/test/ipdl/error/IntrAsyncManager.ipdl
ipc/ipdl/test/ipdl/error/IntrSyncManagee.ipdl
ipc/ipdl/test/ipdl/error/IntrSyncManager.ipdl
ipc/ipdl/test/ipdl/error/ManageeForgot.ipdl
ipc/ipdl/test/ipdl/error/ManagerForgot.ipdl
ipc/ipdl/test/ipdl/error/Nullable.ipdl
ipc/ipdl/test/ipdl/error/Nullable2.ipdl
ipc/ipdl/test/ipdl/error/SyncAsyncManagee.ipdl
ipc/ipdl/test/ipdl/error/SyncAsyncManager.ipdl
ipc/ipdl/test/ipdl/error/array_Recursive.ipdl
ipc/ipdl/test/ipdl/error/asyncMessageListed.ipdl
ipc/ipdl/test/ipdl/error/badProtocolInclude.ipdl
ipc/ipdl/test/ipdl/error/compressCtor.ipdl
ipc/ipdl/test/ipdl/error/compressCtorManagee.ipdl
ipc/ipdl/test/ipdl/error/conflictProtocolMsg.ipdl
ipc/ipdl/test/ipdl/error/cyclecheck_Child.ipdl
ipc/ipdl/test/ipdl/error/cyclecheck_Grandchild.ipdl
ipc/ipdl/test/ipdl/error/cyclecheck_Parent.ipdl
ipc/ipdl/test/ipdl/error/dtorReserved.ipdl
ipc/ipdl/test/ipdl/error/empty.ipdl
ipc/ipdl/test/ipdl/error/intrMessageCompress.ipdl
ipc/ipdl/test/ipdl/error/lex1.ipdl
ipc/ipdl/test/ipdl/error/manageSelfToplevel.ipdl
ipc/ipdl/test/ipdl/error/managedNoCtor.ipdl
ipc/ipdl/test/ipdl/error/managedNoDtor.ipdl
ipc/ipdl/test/ipdl/error/managerNoCtor.ipdl
ipc/ipdl/test/ipdl/error/managerNoDtor.ipdl
ipc/ipdl/test/ipdl/error/messageNoDirection.ipdl
ipc/ipdl/test/ipdl/error/multimanDupMgrs.ipdl
ipc/ipdl/test/ipdl/error/multimanDupMgrsMgr.ipdl
ipc/ipdl/test/ipdl/error/multimanNonexistentMgrs.ipdl
ipc/ipdl/test/ipdl/error/mutualRecStruct.ipdl
ipc/ipdl/test/ipdl/error/mutualRecStructUnion.ipdl
ipc/ipdl/test/ipdl/error/noEmptyToplevel.ipdl
ipc/ipdl/test/ipdl/error/noProtocolInHeader.ipdlh
ipc/ipdl/test/ipdl/error/oldIncludeSyntax.ipdl
ipc/ipdl/test/ipdl/error/parser.ipdl
ipc/ipdl/test/ipdl/error/redeclMessage.ipdl
ipc/ipdl/test/ipdl/error/redeclParamReturn.ipdl
ipc/ipdl/test/ipdl/error/redeclScope.ipdlh
ipc/ipdl/test/ipdl/error/shmem.ipdl
ipc/ipdl/test/ipdl/error/structRedecl.ipdl
ipc/ipdl/test/ipdl/error/structUnknownField.ipdl
ipc/ipdl/test/ipdl/error/syncMessageCompress.ipdl
ipc/ipdl/test/ipdl/error/syncParentToChild.ipdl
ipc/ipdl/test/ipdl/error/tooWeakIntrAsync.ipdl
ipc/ipdl/test/ipdl/error/tooWeakIntrSync.ipdl
ipc/ipdl/test/ipdl/error/tooWeakSyncAsync.ipdl
ipc/ipdl/test/ipdl/error/twoprotocols.ipdl
ipc/ipdl/test/ipdl/error/undeclParamType.ipdl
ipc/ipdl/test/ipdl/error/undeclProtocol.ipdl
ipc/ipdl/test/ipdl/error/undeclReturnType.ipdl
ipc/ipdl/test/ipdl/error/undefMutualRecStruct.ipdl
ipc/ipdl/test/ipdl/error/undefMutualRecStructUnion.ipdl
ipc/ipdl/test/ipdl/error/undefMutualRecUnion.ipdl
ipc/ipdl/test/ipdl/error/undefSelfRecStruct.ipdl
ipc/ipdl/test/ipdl/error/undefSelfRecUnion.ipdl
ipc/ipdl/test/ipdl/error/unknownIntrMessage.ipdl
ipc/ipdl/test/ipdl/error/unknownSyncMessage.ipdl
ipc/ipdl/test/ipdl/runtests.py
--- a/ipc/ipdl/test/ipdl/IPDLCompile.py
+++ b/ipc/ipdl/test/ipdl/IPDLCompile.py
@@ -45,31 +45,32 @@ class IPDLCompile:
 
 
     def completed(self):
         return (self.returncode is not None
                 and isinstance(self.stdout, str)
                 and isinstance(self.stderr, str))
 
 
-    def error(self):
+    def error(self, expectedError):
         '''Return True iff compiling self.specstring resulted in an
 IPDL compiler error.'''
         assert self.completed()
 
-        return None is not re.search(r'error:', self.stderr)
+        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()
+                and not self.error("error:")
                 and (0 == self.returncode))
--- a/ipc/ipdl/test/ipdl/error/AsyncInsideSync.ipdl
+++ b/ipc/ipdl/test/ipdl/error/AsyncInsideSync.ipdl
@@ -1,6 +1,9 @@
 // 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
+
 protocol AsyncInsideSync {
 child:
     nested(inside_sync) async Msg();
 };
--- a/ipc/ipdl/test/ipdl/error/AsyncReturn.ipdl
+++ b/ipc/ipdl/test/ipdl/error/AsyncReturn.ipdl
@@ -1,6 +1,8 @@
 // Async messages are not allowed to return values.
 
+//error: asynchronous message `Msg' declares return values
+
 protocol AsyncReturn {
 child:
     async Msg() returns(int32_t aNumber);
 };
--- a/ipc/ipdl/test/ipdl/error/BadNestedManagee.ipdl
+++ b/ipc/ipdl/test/ipdl/error/BadNestedManagee.ipdl
@@ -1,7 +1,9 @@
+//error: protocol `BadNestedManagee' requires more powerful send semantics than its manager `BadNestedManager' provides
+
 include protocol BadNestedManager;
 
 nested(upto inside_sync) async protocol BadNestedManagee {
     manager BadNestedManager;
 child:
     async __delete__();
 };
--- a/ipc/ipdl/test/ipdl/error/BadNestedManager.ipdl
+++ b/ipc/ipdl/test/ipdl/error/BadNestedManager.ipdl
@@ -1,7 +1,9 @@
+//error: protocol `BadNestedManagee' requires more powerful send semantics than its manager `BadNestedManager' provides
+
 include protocol BadNestedManagee;
 
 nested(upto not) async protocol BadNestedManager {
     manages BadNestedManagee;
 parent:
     async BadNestedManagee();
 };
--- a/ipc/ipdl/test/ipdl/error/ForgottenManagee.ipdl
+++ b/ipc/ipdl/test/ipdl/error/ForgottenManagee.ipdl
@@ -1,8 +1,10 @@
+//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:
--- a/ipc/ipdl/test/ipdl/error/ForgottenManager.ipdl
+++ b/ipc/ipdl/test/ipdl/error/ForgottenManager.ipdl
@@ -1,8 +1,10 @@
+//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.
 
 protocol ForgottenManager {
     manages ManageeForgot;
 child:
     async ManageeForgot();
--- a/ipc/ipdl/test/ipdl/error/InsideCpowToChild.ipdl
+++ b/ipc/ipdl/test/ipdl/error/InsideCpowToChild.ipdl
@@ -1,6 +1,9 @@
 // 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
+
 protocol InsideCpowToChild {
 child:
     nested(inside_cpow) sync Msg();
 };
--- a/ipc/ipdl/test/ipdl/error/IntrAsyncManagee.ipdl
+++ b/ipc/ipdl/test/ipdl/error/IntrAsyncManagee.ipdl
@@ -1,7 +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__();
 };
--- a/ipc/ipdl/test/ipdl/error/IntrAsyncManager.ipdl
+++ b/ipc/ipdl/test/ipdl/error/IntrAsyncManager.ipdl
@@ -1,7 +1,9 @@
+//error: protocol `IntrAsyncManagee' requires more powerful send semantics than its manager `IntrAsyncManager' provides
+
 include protocol IntrAsyncManagee;
 
 async protocol IntrAsyncManager {
     manages IntrAsyncManagee;
 parent:
     async IntrAsyncManagee();
 };
--- a/ipc/ipdl/test/ipdl/error/IntrSyncManagee.ipdl
+++ b/ipc/ipdl/test/ipdl/error/IntrSyncManagee.ipdl
@@ -1,7 +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__();
 };
--- a/ipc/ipdl/test/ipdl/error/IntrSyncManager.ipdl
+++ b/ipc/ipdl/test/ipdl/error/IntrSyncManager.ipdl
@@ -1,7 +1,9 @@
+//error: protocol `IntrSyncManagee' requires more powerful send semantics than its manager `IntrSyncManager' provides
+
 include protocol IntrSyncManagee;
 
 sync protocol IntrSyncManager {
     manages IntrSyncManagee;
 parent:
     async IntrSyncManagee();
 };
--- a/ipc/ipdl/test/ipdl/error/ManageeForgot.ipdl
+++ b/ipc/ipdl/test/ipdl/error/ManageeForgot.ipdl
@@ -1,8 +1,10 @@
+//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.
 
 protocol ManageeForgot {
 child:
     async __delete__();
--- a/ipc/ipdl/test/ipdl/error/ManagerForgot.ipdl
+++ b/ipc/ipdl/test/ipdl/error/ManagerForgot.ipdl
@@ -1,8 +1,10 @@
+//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.
 
 protocol ManagerForgot {
 child:
     async Msg();
--- a/ipc/ipdl/test/ipdl/error/Nullable.ipdl
+++ b/ipc/ipdl/test/ipdl/error/Nullable.ipdl
@@ -1,4 +1,6 @@
+//error: `nullable' qualifier for type `int' makes no sense
+
 protocol Nullable {
 child:
     async Msg(nullable int i);
 };
--- a/ipc/ipdl/test/ipdl/error/Nullable2.ipdl
+++ b/ipc/ipdl/test/ipdl/error/Nullable2.ipdl
@@ -1,8 +1,10 @@
+//error: `nullable' qualifier for type `int' makes no sense
+
 union Union {
     nullable int;
 };
 
 protocol Nullable2 {
 child:
     async Msg(Union i);
 };
--- a/ipc/ipdl/test/ipdl/error/SyncAsyncManagee.ipdl
+++ b/ipc/ipdl/test/ipdl/error/SyncAsyncManagee.ipdl
@@ -1,7 +1,9 @@
+//error: protocol `SyncAsyncManagee' requires more powerful send semantics than its manager `SyncAsyncManager' provides
+
 include protocol SyncAsyncManager;
 
 sync protocol SyncAsyncManagee {
     manager SyncAsyncManager;
 child:
     async __delete__();
 };
--- a/ipc/ipdl/test/ipdl/error/SyncAsyncManager.ipdl
+++ b/ipc/ipdl/test/ipdl/error/SyncAsyncManager.ipdl
@@ -1,7 +1,9 @@
+//error: protocol `SyncAsyncManagee' requires more powerful send semantics than its manager `SyncAsyncManager' provides
+
 include protocol SyncAsyncManagee;
 
 async protocol SyncAsyncManager {
     manages SyncAsyncManagee;
 parent:
     async SyncAsyncManagee();
 };
--- a/ipc/ipdl/test/ipdl/error/array_Recursive.ipdl
+++ b/ipc/ipdl/test/ipdl/error/array_Recursive.ipdl
@@ -1,3 +1,5 @@
+//error: bad syntax near `['
+
 protocol array_Recursive {
 child: async Msg(int[][] aa);
 };
--- a/ipc/ipdl/test/ipdl/error/asyncMessageListed.ipdl
+++ b/ipc/ipdl/test/ipdl/error/asyncMessageListed.ipdl
@@ -1,4 +1,6 @@
+//error: IPC message asyncMessageListed::Msg is async, can be delisted
+
 protocol asyncMessageListed {
 parent:
     async Msg();
 };
--- a/ipc/ipdl/test/ipdl/error/badProtocolInclude.ipdl
+++ b/ipc/ipdl/test/ipdl/error/badProtocolInclude.ipdl
@@ -1,7 +1,9 @@
+//error: can't locate include file `IDONTEXIST.ipdl'
+
 include protocol IDONTEXIST;
 
 // error: nonexistent protocol ^^^
 
 protocol badProtocolInclude {
 child: Msg();
 };
--- a/ipc/ipdl/test/ipdl/error/compressCtor.ipdl
+++ b/ipc/ipdl/test/ipdl/error/compressCtor.ipdl
@@ -1,8 +1,11 @@
+//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;
 
 intr protocol compressCtor {
     manages compressCtorManagee;
 
 parent:
     async compressCtorManagee() compress;
 };
--- a/ipc/ipdl/test/ipdl/error/compressCtorManagee.ipdl
+++ b/ipc/ipdl/test/ipdl/error/compressCtorManagee.ipdl
@@ -1,8 +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:
     async __delete__() compress;
 };
--- a/ipc/ipdl/test/ipdl/error/conflictProtocolMsg.ipdl
+++ b/ipc/ipdl/test/ipdl/error/conflictProtocolMsg.ipdl
@@ -1,7 +1,9 @@
+//error: ctor for protocol `conflictProtocolMsg', which is not managed by protocol `conflictProtocolMsg'
+
 protocol conflictProtocolMsg {
 
     // it's an error to re-use the protocol name as a message ID; these
     // are reserved
 child: async conflictProtocolMsg();
 
 };
--- a/ipc/ipdl/test/ipdl/error/cyclecheck_Child.ipdl
+++ b/ipc/ipdl/test/ipdl/error/cyclecheck_Child.ipdl
@@ -1,8 +1,11 @@
+//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:
--- a/ipc/ipdl/test/ipdl/error/cyclecheck_Grandchild.ipdl
+++ b/ipc/ipdl/test/ipdl/error/cyclecheck_Grandchild.ipdl
@@ -1,8 +1,11 @@
+//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:
--- a/ipc/ipdl/test/ipdl/error/cyclecheck_Parent.ipdl
+++ b/ipc/ipdl/test/ipdl/error/cyclecheck_Parent.ipdl
@@ -1,8 +1,10 @@
+//error: cycle(s) detected in manager/manages hierarchy: `cyclecheck_Parent -> cyclecheck_Child -> cyclecheck_Grandchild -> cyclecheck_Parent'
+
 include protocol cyclecheck_Child;
 
 protocol cyclecheck_Parent {
     manages cyclecheck_Child;
 
 child:
     async cyclecheck_Child();
     async __delete__();
--- a/ipc/ipdl/test/ipdl/error/dtorReserved.ipdl
+++ b/ipc/ipdl/test/ipdl/error/dtorReserved.ipdl
@@ -1,8 +1,10 @@
+//error: lexically invalid characters `~SomeMsg();
+
 protocol dtorReserved {
 
     // it's an error to use old-style dtor syntax
 
 child:
     ~SomeMsg();
 
 };
--- a/ipc/ipdl/test/ipdl/error/empty.ipdl
+++ b/ipc/ipdl/test/ipdl/error/empty.ipdl
@@ -1,1 +1,1 @@
-
+//error: bad syntax near `???'
\ No newline at end of file
--- a/ipc/ipdl/test/ipdl/error/intrMessageCompress.ipdl
+++ b/ipc/ipdl/test/ipdl/error/intrMessageCompress.ipdl
@@ -1,6 +1,9 @@
+//error: message `foo' in protocol `intrMessageCompress' requests compression but is not async
+//error: message `bar' in protocol `intrMessageCompress' requests compression but is not async
+
 intr protocol intrMessageCompress {
 parent:
     intr foo() compress;
 child:
     intr bar() compress;
 };
--- a/ipc/ipdl/test/ipdl/error/lex1.ipdl
+++ b/ipc/ipdl/test/ipdl/error/lex1.ipdl
@@ -1,1 +1,2 @@
+//error: bad syntax near `slkdjfl'
 slkdjfl*&^*
--- a/ipc/ipdl/test/ipdl/error/manageSelfToplevel.ipdl
+++ b/ipc/ipdl/test/ipdl/error/manageSelfToplevel.ipdl
@@ -1,8 +1,10 @@
+//error: top-level protocol `manageSelfToplevel' cannot manage itself
+
 protocol manageSelfToplevel {
     manager manageSelfToplevel;
     manages manageSelfToplevel;
 
 child:
     async manageSelfToplevel();
     async __delete__();
 };
--- a/ipc/ipdl/test/ipdl/error/managedNoCtor.ipdl
+++ b/ipc/ipdl/test/ipdl/error/managedNoCtor.ipdl
@@ -1,7 +1,9 @@
+//error: constructor declaration required for managed protocol `managedNoCtor' (managed by protocol `managerNoCtor')
+
 include protocol managerNoCtor;
 
 protocol managedNoCtor {
     manager managerNoCtor;
     // empty
 child: async __delete__();
 };
--- a/ipc/ipdl/test/ipdl/error/managedNoDtor.ipdl
+++ b/ipc/ipdl/test/ipdl/error/managedNoDtor.ipdl
@@ -1,6 +1,7 @@
+//error: destructor declaration `__delete__(...)' required for managed protocol `managedNoDtor'
 include protocol managerNoDtor;
 
 protocol managedNoDtor {
     manager managerNoDtor;
     // empty
 };
--- a/ipc/ipdl/test/ipdl/error/managerNoCtor.ipdl
+++ b/ipc/ipdl/test/ipdl/error/managerNoCtor.ipdl
@@ -1,8 +1,10 @@
+//error: constructor declaration required for managed protocol `managedNoCtor' (managed by protocol `managerNoCtor')
+
 include protocol managedNoCtor;
 
 protocol managerNoCtor {
     manages managedNoCtor;
 
 parent:
     // error: no ctor defined
     async __delete__();
--- a/ipc/ipdl/test/ipdl/error/managerNoDtor.ipdl
+++ b/ipc/ipdl/test/ipdl/error/managerNoDtor.ipdl
@@ -1,8 +1,10 @@
+//error: destructor declaration `__delete__(...)' required for managed protocol `managedNoDtor'
+
 include protocol managedNoDtor;
 
 protocol managerNoDtor {
     manages managedNoDtor;
 
 parent:
     async managedNoDtor();
     // error: no ctor defined
--- a/ipc/ipdl/test/ipdl/error/messageNoDirection.ipdl
+++ b/ipc/ipdl/test/ipdl/error/messageNoDirection.ipdl
@@ -1,3 +1,5 @@
+//error: missing message direction
+
 protocol messageNoDirection {
     async NoDirection();
 };
--- a/ipc/ipdl/test/ipdl/error/multimanDupMgrs.ipdl
+++ b/ipc/ipdl/test/ipdl/error/multimanDupMgrs.ipdl
@@ -1,8 +1,10 @@
+//error: manager `multimanDupMgrsMgr' appears multiple times
+
 include protocol multimanDupMgrsMgr;
 
 protocol multimanDupMgrs {
     manager multimanDupMgrsMgr or multimanDupMgrsMgr;
 
 child:
     async __delete__();
 };
--- a/ipc/ipdl/test/ipdl/error/multimanDupMgrsMgr.ipdl
+++ b/ipc/ipdl/test/ipdl/error/multimanDupMgrsMgr.ipdl
@@ -1,8 +1,10 @@
+//error: manager `multimanDupMgrsMgr' appears multiple times
+
 include protocol multimanDupMgrs;
 
 protocol multimanDupMgrsMgr {
     manages multimanDupMgrs;
 
 child:
     async multimanDupMgrs();
     async __delete__();
--- a/ipc/ipdl/test/ipdl/error/multimanNonexistentMgrs.ipdl
+++ b/ipc/ipdl/test/ipdl/error/multimanNonexistentMgrs.ipdl
@@ -1,7 +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__();
 };
--- a/ipc/ipdl/test/ipdl/error/mutualRecStruct.ipdl
+++ b/ipc/ipdl/test/ipdl/error/mutualRecStruct.ipdl
@@ -1,8 +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 {
     int i;
     Y[] y;
 };
 
 struct Y {
     X x;
     Z z;
--- a/ipc/ipdl/test/ipdl/error/mutualRecStructUnion.ipdl
+++ b/ipc/ipdl/test/ipdl/error/mutualRecStructUnion.ipdl
@@ -1,8 +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 {
     int i;
     Y[] y;
 };
 
 union Y {
     X;
     Z;
--- a/ipc/ipdl/test/ipdl/error/noEmptyToplevel.ipdl
+++ b/ipc/ipdl/test/ipdl/error/noEmptyToplevel.ipdl
@@ -1,5 +1,7 @@
+//error: top-level protocol `noEmptyToplevel' cannot be empty
+
 protocol noEmptyToplevel {
 
     // it's an error for top-level protocols to be empty
 
 };
--- a/ipc/ipdl/test/ipdl/error/noProtocolInHeader.ipdlh
+++ b/ipc/ipdl/test/ipdl/error/noProtocolInHeader.ipdlh
@@ -1,4 +1,6 @@
+//error: can't define a protocol in a header.  Do it in a protocol spec instead.
+
 protocol noProtocolInHeader {
 child:
     async __delete__();
 };
--- a/ipc/ipdl/test/ipdl/error/oldIncludeSyntax.ipdl
+++ b/ipc/ipdl/test/ipdl/error/oldIncludeSyntax.ipdl
@@ -1,5 +1,7 @@
+//error: bad syntax near `Foo.ipdl'
+
 include protocol "Foo.ipdl";
 
 protocol oldIncludeSyntax {
 child: async __delete__(X x);
 };
--- a/ipc/ipdl/test/ipdl/error/parser.ipdl
+++ b/ipc/ipdl/test/ipdl/error/parser.ipdl
@@ -1,1 +1,3 @@
+//error: bad syntax near `???'
+
 protocol parser {
--- a/ipc/ipdl/test/ipdl/error/redeclMessage.ipdl
+++ b/ipc/ipdl/test/ipdl/error/redeclMessage.ipdl
@@ -1,8 +1,11 @@
+//error: message name `Msg' already declared as `MessageType'
+//error: redeclaration of symbol `Msg', first declared at
+
 protocol redeclMessage {
 
     // can't declare two messages with the same name
 
 child:
     async Msg();
     async Msg();
 
--- a/ipc/ipdl/test/ipdl/error/redeclParamReturn.ipdl
+++ b/ipc/ipdl/test/ipdl/error/redeclParamReturn.ipdl
@@ -1,7 +1,9 @@
+//error: redeclaration of symbol `f', first declared at
+
 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);
 
 };
--- a/ipc/ipdl/test/ipdl/error/redeclScope.ipdlh
+++ b/ipc/ipdl/test/ipdl/error/redeclScope.ipdlh
@@ -1,8 +1,10 @@
+//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.
--- a/ipc/ipdl/test/ipdl/error/shmem.ipdl
+++ b/ipc/ipdl/test/ipdl/error/shmem.ipdl
@@ -1,5 +1,8 @@
+//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
 
 protocol shmem {
 child: async Msg(Shmem s);
 };
--- a/ipc/ipdl/test/ipdl/error/structRedecl.ipdl
+++ b/ipc/ipdl/test/ipdl/error/structRedecl.ipdl
@@ -1,8 +1,10 @@
+//error: redeclaration of symbol `a', first declared at
+
 struct Redecl {
     int a;
     double a;
 };
 
 protocol structRedecl {
 child: async __delete__();
 };
--- a/ipc/ipdl/test/ipdl/error/structUnknownField.ipdl
+++ b/ipc/ipdl/test/ipdl/error/structUnknownField.ipdl
@@ -1,7 +1,9 @@
+//error: field `i' of struct `S' has unknown type `Foobers'
+
 struct S {
     Foobers i;
 };
 
 protocol structUnknownField {
 child: async __delete__(S s);
 };
--- a/ipc/ipdl/test/ipdl/error/syncMessageCompress.ipdl
+++ b/ipc/ipdl/test/ipdl/error/syncMessageCompress.ipdl
@@ -1,4 +1,6 @@
+//error: message `foo' in protocol `syncMessageCompress' requests compression but is not async
+
 sync protocol syncMessageCompress {
 parent:
     sync foo() compress;
 };
--- a/ipc/ipdl/test/ipdl/error/syncParentToChild.ipdl
+++ b/ipc/ipdl/test/ipdl/error/syncParentToChild.ipdl
@@ -1,6 +1,8 @@
+//error: sync parent-to-child messages are verboten (here, message `Msg' in protocol `syncParentToChild')
+
 intr protocol syncParentToChild {
 
     // can't declare sync parent-to-child messages
 child: sync Msg();
 
 };
--- a/ipc/ipdl/test/ipdl/error/tooWeakIntrAsync.ipdl
+++ b/ipc/ipdl/test/ipdl/error/tooWeakIntrAsync.ipdl
@@ -1,7 +1,9 @@
+//error: message `Msg' requires more powerful send semantics than its protocol `tooWeakIntrAsync' provides
+
 protocol tooWeakIntrAsync {
 
     // it's an error to declare an async protocol with an intr message
 
 parent: intr Msg();
 
 };
--- a/ipc/ipdl/test/ipdl/error/tooWeakIntrSync.ipdl
+++ b/ipc/ipdl/test/ipdl/error/tooWeakIntrSync.ipdl
@@ -1,6 +1,8 @@
+//error: message `Msg' requires more powerful send semantics than its protocol `tooWeakIntrSync' provides
+
 sync protocol tooWeakIntrSync {
 
     // it's an error to declare a sync protocol with an interrupt message
 parent:
   intr Msg();
 };
--- a/ipc/ipdl/test/ipdl/error/tooWeakSyncAsync.ipdl
+++ b/ipc/ipdl/test/ipdl/error/tooWeakSyncAsync.ipdl
@@ -1,7 +1,9 @@
+//error: message `Msg' requires more powerful send semantics than its protocol `tooWeakSyncAsync' provides
+
 protocol tooWeakSyncAsync {
 
     // it's an error to declare an async protocol with a sync message
 
 parent:  sync Msg();
 
 };
--- a/ipc/ipdl/test/ipdl/error/twoprotocols.ipdl
+++ b/ipc/ipdl/test/ipdl/error/twoprotocols.ipdl
@@ -1,9 +1,11 @@
 // it's an error to define two protocols in the same file
 
+//error: only one protocol definition per file
+
 protocol p1 {
 child: async Msg();
 };
 
 protocol p2 {
 child: async Msg();
 };
--- a/ipc/ipdl/test/ipdl/error/undeclParamType.ipdl
+++ b/ipc/ipdl/test/ipdl/error/undeclParamType.ipdl
@@ -1,5 +1,7 @@
+//error: argument typename `FARGLEGARGLE' of message `Msg' has not been declared
+
 protocol undeclParamType {
 
 child: async Msg(FARGLEGARGLE p);
 
 };
--- a/ipc/ipdl/test/ipdl/error/undeclProtocol.ipdl
+++ b/ipc/ipdl/test/ipdl/error/undeclProtocol.ipdl
@@ -1,6 +1,9 @@
+//error: protocol `undeclared', managed by `undeclProtocol', has not been declared
+//error: constructor declaration required for managed protocol `undeclared' (managed by protocol `undeclProtocol')
+
 protocol undeclProtocol {
     manages undeclared;
 
 child:
     async undeclared();
 };
--- a/ipc/ipdl/test/ipdl/error/undeclReturnType.ipdl
+++ b/ipc/ipdl/test/ipdl/error/undeclReturnType.ipdl
@@ -1,5 +1,7 @@
+//error: argument typename `FARGLEGARGLE' of message `Msg' has not been declared
+
 sync protocol undeclReturnType {
 
 child:  sync Msg() returns (FARGLEGARGLE r);
 
 };
--- a/ipc/ipdl/test/ipdl/error/undefMutualRecStruct.ipdl
+++ b/ipc/ipdl/test/ipdl/error/undefMutualRecStruct.ipdl
@@ -1,7 +1,11 @@
+//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; };
 
 protocol undefMutualRecStruct {
 child: async __delete__(X x);
 };
--- a/ipc/ipdl/test/ipdl/error/undefMutualRecStructUnion.ipdl
+++ b/ipc/ipdl/test/ipdl/error/undefMutualRecStructUnion.ipdl
@@ -1,7 +1,11 @@
+//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; };
 
 protocol undefMutualRecStructUnion {
 child: async __delete__(X x);
 };
--- a/ipc/ipdl/test/ipdl/error/undefMutualRecUnion.ipdl
+++ b/ipc/ipdl/test/ipdl/error/undefMutualRecUnion.ipdl
@@ -1,7 +1,11 @@
+//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; };
 
 protocol undefMutualRecUnion {
 child: async __delete__(X x);
 };
--- a/ipc/ipdl/test/ipdl/error/undefSelfRecStruct.ipdl
+++ b/ipc/ipdl/test/ipdl/error/undefSelfRecStruct.ipdl
@@ -1,5 +1,7 @@
+//error: struct `X' is only partially defined
+
 struct X { X x; };
 
 protocol undefSelfRecStruct {
 child: async __delete__(X x);
 };
--- a/ipc/ipdl/test/ipdl/error/undefSelfRecUnion.ipdl
+++ b/ipc/ipdl/test/ipdl/error/undefSelfRecUnion.ipdl
@@ -1,5 +1,7 @@
+//error: union `X' is only partially defined
+
 union X { X; };
 
 protocol undefSelfRecUnion {
 child: async __delete__(X x);
 };
--- a/ipc/ipdl/test/ipdl/error/unknownIntrMessage.ipdl
+++ b/ipc/ipdl/test/ipdl/error/unknownIntrMessage.ipdl
@@ -1,4 +1,6 @@
+//error: Unknown sync IPC message unknownIntrMessage::Msg
+
 intr protocol unknownIntrMessage {
 parent:
     intr Msg();
 };
--- a/ipc/ipdl/test/ipdl/error/unknownSyncMessage.ipdl
+++ b/ipc/ipdl/test/ipdl/error/unknownSyncMessage.ipdl
@@ -1,4 +1,6 @@
+//error: Unknown sync IPC message unknownSyncMessage::Msg
+
 sync protocol unknownSyncMessage {
 parent:
     sync Msg();
 };
--- a/ipc/ipdl/test/ipdl/runtests.py
+++ b/ipc/ipdl/test/ipdl/runtests.py
@@ -9,16 +9,23 @@ class IPDLTestCase(unittest.TestCase):
         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)
@@ -37,18 +44,35 @@ The IPDL compiler should not produce err
 
 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.assertTrue(self.compile.error(), self.mkFailMsg())
+        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]