Web Inspector: InspectorTest should be a subclass of TestHarness
[WebKit-https.git] / Source / WebInspectorUI / UserInterface / Test / InspectorProtocol.js
1 /*
2  * Copyright (C) 2012 Samsung Electronics. All rights reserved.
3  * Copyright (C) 2014, 2015 Apple Inc. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1.  Redistributions of source code must retain the above copyright
10  *     notice, this list of conditions and the following disclaimer.
11  * 2.  Redistributions in binary form must reproduce the above copyright
12  *     notice, this list of conditions and the following disclaimer in the
13  *     documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
16  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
19  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26
27 InspectorProtocol = {};
28 InspectorProtocol._dispatchTable = [];
29 InspectorProtocol._requestId = -1;
30 InspectorProtocol.eventHandler = {};
31
32 InspectorProtocol.sendCommand = function(methodOrObject, params, handler)
33 {
34     // Allow new-style arguments object, as in awaitCommand.
35     let method = methodOrObject;
36     if (typeof methodOrObject === "object")
37         var {method, params, handler} = methodOrObject;
38
39     this._dispatchTable[++this._requestId] = handler;
40     let messageObject = {method, params, id: this._requestId};
41     this.sendMessage(messageObject);
42
43     return this._requestId;
44 }
45
46 InspectorProtocol.awaitCommand = function(args)
47 {
48     let {method, params} = args;
49     return new Promise(function(resolve, reject) {
50         this._dispatchTable[++this._requestId] = {resolve, reject};
51         let messageObject = {method, params, id: this._requestId};
52         this.sendMessage(messageObject);
53     }.bind(this));
54 }
55
56 InspectorProtocol.awaitEvent = function(args)
57 {
58     let event = args.event;
59     if (typeof event !== "string")
60         throw new Error("Event must be a string.");
61
62     return new Promise(function(resolve, reject) {
63         InspectorProtocol.eventHandler[event] = function(message) {
64             InspectorProtocol.eventHandler[event] = undefined;
65             resolve(message);
66         }
67     });
68 }
69
70 InspectorProtocol.addEventListener = function(eventTypeOrObject, listener)
71 {
72     let event = eventTypeOrObject;
73     if (typeof eventTypeOrObject === "object")
74         var {event, listener} = eventTypeOrObject;
75
76     if (typeof event !== "string")
77         throw new Error("Event name must be a string.");
78
79     if (typeof listener !== "function")
80         throw new Error("Event listener must be callable.");
81
82     // Convert to an array of listeners.
83     let listeners = InspectorProtocol.eventHandler[event];
84     if (!listeners)
85         listeners = InspectorProtocol.eventHandler[event] = [];
86     else if (typeof listeners === "function")
87         listeners = InspectorProtocol.eventHandler[event] = [listeners];
88
89     // Prevent registering multiple times.
90     if (listeners.includes(listener))
91         throw new Error("Cannot register the same listener more than once.");
92
93     listeners.push(listener);
94 }
95
96 InspectorProtocol.sendMessage = function(messageObject)
97 {
98     // This matches the debug dumping in InspectorBackend, which is bypassed
99     // by InspectorProtocol. Return messages should be dumped by InspectorBackend.
100     if (ProtocolTest.dumpInspectorProtocolMessages)
101         console.log("frontend: " + JSON.stringify(messageObject));
102
103     InspectorFrontendHost.sendMessageToBackend(JSON.stringify(messageObject));
104 }
105
106 InspectorProtocol.checkForError = function(responseObject)
107 {
108     if (responseObject.error) {
109         ProtocolTest.log("PROTOCOL ERROR: " + JSON.stringify(responseObject.error));
110         ProtocolTest.completeTest();
111         throw "PROTOCOL ERROR";
112     }
113 }
114
115 InspectorProtocol.dispatchMessageFromBackend = function(messageObject)
116 {
117     // This matches the debug dumping in InspectorBackend, which is bypassed
118     // by InspectorProtocol. Return messages should be dumped by InspectorBackend.
119     if (ProtocolTest.dumpInspectorProtocolMessages)
120         console.log("backend: " + JSON.stringify(messageObject));
121
122     // If the message has an id, then it is a reply to a command.
123     let messageId = messageObject.id;
124     if (typeof messageId === "number") {
125         let handler = InspectorProtocol._dispatchTable[messageId];
126         if (!handler)
127             return;
128
129         if (typeof handler === "function")
130             handler(messageObject);
131         else if (typeof handler === "object") {
132             let {resolve, reject} = handler;
133             if ("error" in messageObject)
134                 reject(messageObject.error.message);
135             else
136                 resolve(messageObject.result);
137         }
138     // Otherwise, it is an event.
139     } else {
140         let eventName = messageObject["method"];
141         let handler = InspectorProtocol.eventHandler[eventName];
142         if (!handler)
143             return;
144
145         if (typeof handler === "function")
146             handler(messageObject);
147         else if (handler instanceof Array) {
148             handler.map(function(listener) {
149                 listener.call(null, messageObject);
150             });
151         } else if (typeof handler === "object") {
152             let {resolve, reject} = handler;
153             if ("error" in messageObject)
154                 reject(messageObject.error.message);
155             else
156                 resolve(messageObject.result);
157         }
158     }
159 }