1# Copyright (C) 2010 Apple Inc. All rights reserved.
2#
3# Redistribution and use in source and binary forms, with or without
4# modification, are permitted provided that the following conditions
5# are met:
6# 1.  Redistributions of source code must retain the above copyright
7#     notice, this list of conditions and the following disclaimer.
8# 2.  Redistributions in binary form must reproduce the above copyright
9#     notice, this list of conditions and the following disclaimer in the
10#     documentation and/or other materials provided with the distribution.
11#
12# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND
13# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
14# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
15# DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR
16# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
17# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
18# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
19# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
20# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
21# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
22
23import os
24import unittest
25from StringIO import StringIO
26
27import messages
28import parser
29
30print os.getcwd()
31
32script_directory = os.path.dirname(os.path.realpath(__file__))
33
34with open(os.path.join(script_directory, 'test-messages.in')) as file:
35    _messages_file_contents = file.read()
36
37with open(os.path.join(script_directory, 'test-legacy-messages.in')) as file:
38    _legacy_messages_file_contents = file.read()
39
40with open(os.path.join(script_directory, 'test-superclass-messages.in')) as file:
41    _superclass_messages_file_contents = file.read()
42
43
44with open(os.path.join(script_directory, 'Messages-expected.h')) as file:
45    _expected_receiver_header = file.read()
46
47with open(os.path.join(script_directory, 'LegacyMessages-expected.h')) as file:
48    _expected_legacy_receiver_header = file.read()
49
50with open(os.path.join(script_directory, 'MessagesSuperclass-expected.h')) as file:
51    _expected_superclass_receiver_header = file.read()
52
53
54with open(os.path.join(script_directory, 'MessageReceiver-expected.cpp')) as file:
55    _expected_receiver_implementation = file.read()
56
57with open(os.path.join(script_directory, 'LegacyMessageReceiver-expected.cpp')) as file:
58    _expected_legacy_receiver_implementation = file.read()
59
60with open(os.path.join(script_directory, 'MessageReceiverSuperclass-expected.cpp')) as file:
61    _expected_superclass_receiver_implementation = file.read()
62
63_expected_results = {
64    'name': 'WebPage',
65    'conditions': ('(ENABLE(WEBKIT2) && (NESTED_MASTER_CONDITION || MASTER_OR && MASTER_AND))'),
66    'messages': (
67        {
68            'name': 'LoadURL',
69            'parameters': (
70                ('String', 'url'),
71            ),
72            'conditions': (None),
73        },
74        {
75            'name': 'LoadSomething',
76            'parameters': (
77                ('String', 'url'),
78            ),
79            'conditions': ('ENABLE(TOUCH_EVENTS)'),
80        },
81        {
82            'name': 'TouchEvent',
83            'parameters': (
84                ('WebKit::WebTouchEvent', 'event'),
85            ),
86            'conditions': ('(ENABLE(TOUCH_EVENTS) && (NESTED_MESSAGE_CONDITION || SOME_OTHER_MESSAGE_CONDITION))'),
87        },
88        {
89            'name': 'AddEvent',
90            'parameters': (
91                ('WebKit::WebTouchEvent', 'event'),
92            ),
93            'conditions': ('(ENABLE(TOUCH_EVENTS) && (NESTED_MESSAGE_CONDITION && SOME_OTHER_MESSAGE_CONDITION))'),
94        },
95        {
96            'name': 'LoadSomethingElse',
97            'parameters': (
98                ('String', 'url'),
99            ),
100            'conditions': ('ENABLE(TOUCH_EVENTS)'),
101        },
102        {
103            'name': 'DidReceivePolicyDecision',
104            'parameters': (
105                ('uint64_t', 'frameID'),
106                ('uint64_t', 'listenerID'),
107                ('uint32_t', 'policyAction'),
108            ),
109            'conditions': (None),
110        },
111        {
112            'name': 'Close',
113            'parameters': (),
114            'conditions': (None),
115        },
116        {
117            'name': 'PreferencesDidChange',
118            'parameters': (
119                ('WebKit::WebPreferencesStore', 'store'),
120            ),
121            'conditions': (None),
122        },
123        {
124            'name': 'SendDoubleAndFloat',
125            'parameters': (
126                ('double', 'd'),
127                ('float', 'f'),
128            ),
129            'conditions': (None),
130        },
131        {
132            'name': 'SendInts',
133            'parameters': (
134                ('Vector<uint64_t>', 'ints'),
135                ('Vector<Vector<uint64_t>>', 'intVectors')
136            ),
137            'conditions': (None),
138        },
139        {
140            'name': 'CreatePlugin',
141            'parameters': (
142                ('uint64_t', 'pluginInstanceID'),
143                ('WebKit::Plugin::Parameters', 'parameters')
144            ),
145            'reply_parameters': (
146                ('bool', 'result'),
147            ),
148            'conditions': (None),
149        },
150        {
151            'name': 'RunJavaScriptAlert',
152            'parameters': (
153                ('uint64_t', 'frameID'),
154                ('String', 'message')
155            ),
156            'reply_parameters': (),
157            'conditions': (None),
158        },
159        {
160            'name': 'GetPlugins',
161            'parameters': (
162                ('bool', 'refresh'),
163            ),
164            'reply_parameters': (
165                ('Vector<WebCore::PluginInfo>', 'plugins'),
166            ),
167            'conditions': (None),
168        },
169        {
170            'name': 'GetPluginProcessConnection',
171            'parameters': (
172                ('String', 'pluginPath'),
173            ),
174            'reply_parameters': (
175                ('IPC::Connection::Handle', 'connectionHandle'),
176            ),
177            'conditions': (None),
178        },
179        {
180            'name': 'TestMultipleAttributes',
181            'parameters': (
182            ),
183            'reply_parameters': (
184            ),
185            'conditions': (None),
186        },
187        {
188            'name': 'TestParameterAttributes',
189            'parameters': (
190                ('uint64_t', 'foo', ('AttributeOne', 'AttributeTwo')),
191                ('double', 'bar'),
192                ('double', 'baz', ('AttributeThree',)),
193            ),
194            'conditions': (None),
195        },
196        {
197            'name': 'TemplateTest',
198            'parameters': (
199                ('HashMap<String, std::pair<String, uint64_t>>', 'a'),
200            ),
201            'conditions': (None),
202        },
203        {
204            'name': 'SetVideoLayerID',
205            'parameters': (
206                ('WebCore::GraphicsLayer::PlatformLayerID', 'videoLayerID'),
207            ),
208            'conditions': (None),
209        },
210        {
211            'name': 'DidCreateWebProcessConnection',
212            'parameters': (
213                ('IPC::MachPort', 'connectionIdentifier'),
214            ),
215            'conditions': ('PLATFORM(MAC)'),
216        },
217        {
218            'name': 'InterpretKeyEvent',
219            'parameters': (
220                ('uint32_t', 'type'),
221            ),
222            'reply_parameters': (
223                ('Vector<WebCore::KeypressCommand>', 'commandName'),
224            ),
225            'conditions': ('PLATFORM(MAC)'),
226        },
227        {
228            'name': 'DeprecatedOperation',
229            'parameters': (
230                ('IPC::DummyType', 'dummy'),
231            ),
232            'conditions': ('ENABLE(DEPRECATED_FEATURE)'),
233        },
234        {
235            'name': 'ExperimentalOperation',
236            'parameters': (
237                ('IPC::DummyType', 'dummy'),
238            ),
239            'conditions': ('ENABLE(EXPERIMENTAL_FEATURE)'),
240        }
241    ),
242}
243
244_expected_superclass_results = {
245    'name': 'WebPage',
246    'superclass' : 'WebPageBase',
247    'conditions': None,
248    'messages': (
249        {
250            'name': 'LoadURL',
251            'parameters': (
252                ('String', 'url'),
253            ),
254            'conditions': (None),
255        },
256    ),
257}
258
259
260class MessagesTest(unittest.TestCase):
261    def setUp(self):
262        self.receiver = parser.parse(StringIO(_messages_file_contents))
263        self.legacy_receiver = parser.parse(StringIO(_legacy_messages_file_contents))
264        self.superclass_receiver = parser.parse(StringIO(_superclass_messages_file_contents))
265
266
267class ParsingTest(MessagesTest):
268    def check_message(self, message, expected_message):
269        self.assertEquals(message.name, expected_message['name'])
270        self.assertEquals(len(message.parameters), len(expected_message['parameters']))
271        for index, parameter in enumerate(message.parameters):
272            expected_parameter = expected_message['parameters'][index]
273            self.assertEquals(parameter.type, expected_parameter[0])
274            self.assertEquals(parameter.name, expected_parameter[1])
275            if len(expected_parameter) > 2:
276                self.assertEquals(parameter.attributes, frozenset(expected_parameter[2]))
277                for attribute in expected_parameter[2]:
278                    self.assertTrue(parameter.has_attribute(attribute))
279            else:
280                self.assertEquals(parameter.attributes, frozenset())
281        if message.reply_parameters != None:
282            for index, parameter in enumerate(message.reply_parameters):
283                self.assertEquals(parameter.type, expected_message['reply_parameters'][index][0])
284                self.assertEquals(parameter.name, expected_message['reply_parameters'][index][1])
285        else:
286            self.assertFalse('reply_parameters' in expected_message)
287        self.assertEquals(message.condition, expected_message['conditions'])
288
289    def test_receiver(self):
290        """Receiver should be parsed as expected"""
291        self.assertEquals(self.receiver.name, _expected_results['name'])
292        self.assertEquals(self.receiver.condition, _expected_results['conditions'])
293        self.assertEquals(len(self.receiver.messages), len(_expected_results['messages']))
294        for index, message in enumerate(self.receiver.messages):
295            self.check_message(message, _expected_results['messages'][index])
296
297        self.assertEquals(self.legacy_receiver.name, _expected_results['name'])
298        self.assertEquals(self.legacy_receiver.condition, _expected_results['conditions'])
299        self.assertEquals(len(self.legacy_receiver.messages), len(_expected_results['messages']))
300        for index, message in enumerate(self.legacy_receiver.messages):
301            self.check_message(message, _expected_results['messages'][index])
302
303        self.assertEquals(self.superclass_receiver.name, _expected_superclass_results['name'])
304        self.assertEquals(self.superclass_receiver.superclass, _expected_superclass_results['superclass'])
305        self.assertEquals(len(self.superclass_receiver.messages), len(_expected_superclass_results['messages']))
306        for index, message in enumerate(self.superclass_receiver.messages):
307            self.check_message(message, _expected_superclass_results['messages'][index])
308
309
310
311class GeneratedFileContentsTest(unittest.TestCase):
312    def assertGeneratedFileContentsEqual(self, first, second):
313        first_list = first.split('\n')
314        second_list = second.split('\n')
315
316        for index, first_line in enumerate(first_list):
317            self.assertEquals(first_line, second_list[index])
318
319        self.assertEquals(len(first_list), len(second_list))
320
321
322class HeaderTest(GeneratedFileContentsTest):
323    def test_header(self):
324        file_contents = messages.generate_messages_header(StringIO(_messages_file_contents))
325        self.assertGeneratedFileContentsEqual(file_contents, _expected_receiver_header)
326
327        legacy_file_contents = messages.generate_messages_header(StringIO(_legacy_messages_file_contents))
328        self.assertGeneratedFileContentsEqual(legacy_file_contents, _expected_legacy_receiver_header)
329
330        superclass_file_contents = messages.generate_messages_header(StringIO(_superclass_messages_file_contents))
331        self.assertGeneratedFileContentsEqual(superclass_file_contents, _expected_superclass_receiver_header)
332
333
334class ReceiverImplementationTest(GeneratedFileContentsTest):
335    def test_receiver_implementation(self):
336        file_contents = messages.generate_message_handler(StringIO(_messages_file_contents))
337        self.assertGeneratedFileContentsEqual(file_contents, _expected_receiver_implementation)
338
339        legacy_file_contents = messages.generate_message_handler(StringIO(_legacy_messages_file_contents))
340        self.assertGeneratedFileContentsEqual(legacy_file_contents, _expected_legacy_receiver_implementation)
341
342        superclass_file_contents = messages.generate_message_handler(StringIO(_superclass_messages_file_contents))
343        self.assertGeneratedFileContentsEqual(superclass_file_contents, _expected_superclass_receiver_implementation)
344
345
346class UnsupportedPrecompilerDirectiveTest(unittest.TestCase):
347    def test_error_at_else(self):
348        with self.assertRaisesRegexp(Exception, r"ERROR: '#else.*' is not supported in the \*\.in files"):
349            messages.generate_message_handler(StringIO("asd\n#else bla\nfoo"))
350
351    def test_error_at_elif(self):
352        with self.assertRaisesRegexp(Exception, r"ERROR: '#elif.*' is not supported in the \*\.in files"):
353            messages.generate_message_handler(StringIO("asd\n#elif bla\nfoo"))
354
355
356if __name__ == '__main__':
357    unittest.main()
358