Support construction variable expansion anywhere in a file or path name.
[scons.git] / test / QT.py
1 #!/usr/bin/env python
2 #
3 # __COPYRIGHT__
4 #
5 # Permission is hereby granted, free of charge, to any person obtaining
6 # a copy of this software and associated documentation files (the
7 # "Software"), to deal in the Software without restriction, including
8 # without limitation the rights to use, copy, modify, merge, publish,
9 # distribute, sublicense, and/or sell copies of the Software, and to
10 # permit persons to whom the Software is furnished to do so, subject to
11 # the following conditions:
12 #
13 # The above copyright notice and this permission notice shall be included
14 # in all copies or substantial portions of the Software.
15 #
16 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
17 # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
18 # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20 # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 #
24
25 __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
26
27 """
28 Testing the 'qt' tool, i.e. support for .ui files and automatic
29 generation of qt's moc files.
30 """
31
32 import TestSCons
33 import os.path
34
35 python = TestSCons.python
36 _exe = TestSCons._exe
37 _dll = TestSCons._dll
38 lib_ = TestSCons.lib_
39
40 test = TestSCons.TestSCons()
41
42 test.subdir( 'qt', ['qt', 'bin'], ['qt', 'include'], ['qt', 'lib'] )
43
44 # create a dummy qt installation
45
46 test.write(['qt', 'bin', 'mymoc.py'], """
47 import getopt
48 import sys
49 import string
50 import re
51 cmd_opts, args = getopt.getopt(sys.argv[1:], 'io:', [])
52 output = None
53 impl = 0
54 opt_string = ''
55 for opt, arg in cmd_opts:
56     if opt == '-o': output = open(arg, 'wb')
57     elif opt == '-i': impl = 1
58     else: opt_string = opt_string + ' ' + opt
59 for a in args:
60     contents = open(a, 'rb').read()
61     subst = r'{ my_qt_symbol( "' + a + '\\\\n" ); }'
62     if impl:
63         contents = re.sub( r'#include.*', '', contents )
64     output.write(string.replace(contents, 'Q_OBJECT', subst))
65 output.close()
66 sys.exit(0)
67 """ )
68
69 test.write(['qt', 'bin', 'myuic.py'], """
70 import sys
71 import string
72 output_arg = 0
73 impl_arg = 0
74 impl = None
75 source = None
76 for arg in sys.argv[1:]:
77     if output_arg:
78         output = open(arg, 'wb')
79         output_arg = 0
80     elif impl_arg:
81         impl = arg
82         impl_arg = 0
83     elif arg == "-o":
84         output_arg = 1
85     elif arg == "-impl":
86         impl_arg = 1
87     else:
88         if source:
89             sys.exit(1)
90         source = open(arg, 'rb')
91 if impl:
92     output.write( '#include "' + impl + '"\\n' )
93 else:
94     output.write( '#include "my_qobject.h"\\n' + source.read() + " Q_OBJECT \\n" )
95 output.close()
96 sys.exit(0)
97 """ )
98
99 test.write(['qt', 'include', 'my_qobject.h'], r"""
100 #define Q_OBJECT ;
101 void my_qt_symbol(const char *arg);
102 """)
103
104 test.write(['qt', 'lib', 'my_qobject.cpp'], r"""
105 #include "../include/my_qobject.h"
106 #include <stdio.h>
107 void my_qt_symbol(const char *arg) {
108   printf( arg );
109 }
110 """)
111
112 test.write(['qt', 'lib', 'SConstruct'], r"""
113 env = Environment()
114 env.StaticLibrary( 'myqt', 'my_qobject.cpp' )
115 """)
116
117 test.run(chdir=test.workpath('qt','lib'), arguments = '.')
118
119 QT = test.workpath('qt')
120 QT_LIB = 'myqt'
121 QT_MOC = '%s %s' % (python, test.workpath('qt','bin','mymoc.py'))
122 QT_UIC = '%s %s' % (python, test.workpath('qt','bin','myuic.py'))
123
124 # 3 test cases with 3 different operation modes
125
126 def createSConstruct(test,place):
127     test.write(place, """
128 env = Environment(QTDIR = r'%s',
129                   QT_LIB = r'%s',
130                   QT_MOC = r'%s',
131                   QT_UIC = r'%s',
132                   tools=['default','qt'])
133 if ARGUMENTS.get('build_dir', 0):
134     if ARGUMENTS.get('chdir', 0):
135         SConscriptChdir(1)
136     else:
137         SConscriptChdir(0)
138     BuildDir('build', '.', duplicate=1)
139     sconscript = Dir('build').File('SConscript')
140 else:
141     sconscript = File('SConscript')
142 Export("env")
143 SConscript( sconscript )
144 """ % (QT, QT_LIB, QT_MOC, QT_UIC))
145
146 test.subdir( 'work1', 'work2', 'work3', 'work4' )
147
148 # 1. create a moc file from a header file.
149
150 aaa_exe = 'aaa' + _exe
151 moc = 'moc_aaa.cc'
152
153 createSConstruct(test, ['work1', 'SConstruct'])
154 test.write( ['work1', 'SConscript'], """
155 Import("env")
156 env.Program(target = 'aaa', source = 'aaa.cpp')
157 """)
158
159 test.write(['work1', 'aaa.cpp'], r"""
160 #include "aaa.h"
161 int main() { aaa(); return 0; }
162 """)
163
164 test.write(['work1', 'aaa.h'], r"""
165 #include "my_qobject.h"
166 void aaa(void) Q_OBJECT;
167 """)
168
169 test.run(chdir='work1', arguments = aaa_exe)
170 test.up_to_date(chdir='work1', options = '-n', arguments=aaa_exe)
171
172 test.up_to_date(chdir='work1', options = '-n', arguments = aaa_exe)
173 test.write(['work1', 'aaa.h'], r"""
174 /* a change */
175 #include "my_qobject.h"
176 void aaa(void) Q_OBJECT;
177 """)
178 test.not_up_to_date(chdir='work1', options='-n', arguments = moc)
179 test.run(program = test.workpath('work1', aaa_exe), stdout = 'aaa.h\n')
180
181 test.run(chdir='work1',
182          arguments = "build_dir=1 " +
183                      test.workpath('work1', 'build', aaa_exe) )
184 test.run(chdir='work1',
185          arguments = "build_dir=1 chdir=1 " +
186                      test.workpath('work1', 'build', aaa_exe) )
187
188 test.fail_test( not os.path.exists(test.workpath('work1', 'build', moc)) )
189
190 # 2. create .cpp, .h, moc_....cpp from .ui file
191
192 aaa_dll = lib_ + 'aaa' + _dll
193 moc = 'moc_aaa.cc'
194 cpp = 'aaa.cc'
195 h = 'aaa.h'
196
197 createSConstruct(test, ['work2', 'SConstruct'])
198 test.write(['work2', 'SConscript'], """
199 Import("env")
200 env.SharedLibrary(target = 'aaa', source = ['aaa.ui', 'useit.cpp'])
201 """)
202
203 test.write(['work2', 'aaa.ui'], r"""
204 void aaa(void)
205 """)
206
207 test.write(['work2', 'useit.cpp'], r"""
208 #include "aaa.h"
209 void useit() {
210   aaa();
211 }
212 """)
213
214 test.run(chdir='work2', arguments = aaa_dll)
215 test.up_to_date(chdir='work2', options='-n',arguments = aaa_dll)
216 test.write(['work2', 'aaa.ui'], r"""
217 /* a change */
218 void aaa(void)
219 """)
220 test.not_up_to_date(chdir='work2', options = '-n', arguments = moc)
221 test.not_up_to_date(chdir='work2', options = '-n', arguments = cpp)
222 test.not_up_to_date(chdir='work2', options = '-n', arguments = h)
223 test.run(chdir='work2', arguments = aaa_dll)
224 test.write(['work2', 'aaa.ui.h'], r"""
225 /* test dependency to .ui.h */
226 """)
227 test.not_up_to_date(chdir='work2', options = '-n', arguments = cpp)
228 test.up_to_date(chdir='work2', options = '-n', arguments = h)
229 test.up_to_date(chdir='work2', options = '-n', arguments = moc)
230
231 test.run(chdir='work2',
232          arguments = "build_dir=1 " +
233                      test.workpath('work2', 'build', aaa_dll) )
234 test.run(chdir='work2',
235          arguments = "build_dir=1 chdir=1 " +
236                      test.workpath('work2', 'build', aaa_dll) )
237
238 test.fail_test(not os.path.exists(test.workpath('work2','build',moc)) or
239                not os.path.exists(test.workpath('work2','build',cpp)) or
240                not os.path.exists(test.workpath('work2','build',h)))
241
242 # 3. create a moc file from a cpp file
243
244 lib_aaa = lib_ + 'aaa.a'
245 moc = 'moc_aaa.cc'
246
247 createSConstruct(test, ['work3', 'SConstruct'])
248 test.write(['work3', 'SConscript'], """
249 Import("env")
250 env.StaticLibrary(target = '%s', source = ['aaa.cpp','useit.cpp'])
251 """ % lib_aaa)
252
253 test.write(['work3', 'aaa.h'], r"""
254 void aaa(void);
255 """)
256
257 test.write(['work3', 'aaa.cpp'], r"""
258 #include "my_qobject.h"
259 void aaa(void) Q_OBJECT
260 #include "%s"
261 """ % moc)
262
263 test.write(['work3', 'useit.cpp'], r"""
264 #include "aaa.h"
265 void useit() {
266   aaa();
267 }
268 """)
269
270 test.run(chdir='work3', arguments = lib_aaa)
271 test.up_to_date(chdir='work3', options = '-n', arguments = lib_aaa)
272 test.write(['work3', 'aaa.cpp'], r"""
273 #include "my_qobject.h"
274 /* a change */
275 void aaa(void) Q_OBJECT
276 #include "%s"
277 """ % moc)
278 test.not_up_to_date(chdir='work3', options = '-n', arguments = moc)
279
280 test.run(chdir='work3',
281          arguments = "build_dir=1 " +
282                      test.workpath('work3', 'build', lib_aaa) )
283 test.run(chdir='work3',
284          arguments = "build_dir=1 chdir=1 " +
285                      test.workpath('work3', 'build', lib_aaa) )
286
287 test.fail_test(not os.path.exists(test.workpath('work3', 'build', moc)))
288
289
290 # look if qt is installed, and try out all builders
291
292 if os.environ.get('QTDIR', None):
293
294     test.write( ['work4', 'SConstruct'],"""
295 import os
296 env = Environment(tools=['default','qt'], CXXFILESUFFIX=".cpp")
297 env.Program('test_realqt', ['mocFromCpp.cpp',
298                             'mocFromH.cpp',
299                             'anUiFile.ui',
300                             'main.cpp'])
301 """)
302
303     test.write( ['work4', 'mocFromCpp.h'],"""
304 void mocFromCpp();
305 """)
306
307     test.write( ['work4', 'mocFromCpp.cpp'],"""
308 #include <qobject.h>
309 #include "mocFromCpp.h"
310 class MyClass1 : public QObject {
311   Q_OBJECT
312   public:
313   MyClass1() : QObject() {};
314   public slots:
315   void myslot() {};
316 };
317 void mocFromCpp() {
318   MyClass1 myclass;
319 }
320 #include "moc_mocFromCpp.cpp"
321 """)
322
323     test.write( ['work4', 'mocFromH.h'],"""
324 #include <qobject.h>
325 class MyClass2 : public QObject {
326   Q_OBJECT;
327   public:
328   MyClass2();
329   public slots:
330   void myslot();
331 };
332 void mocFromH();
333 """)
334     
335     test.write( ['work4', 'mocFromH.cpp'],"""
336 #include "mocFromH.h"
337     
338 MyClass2::MyClass2() : QObject() {}
339 void MyClass2::myslot() {}
340 void mocFromH() {
341   MyClass2 myclass;
342 }
343 """)
344     
345     test.write( ['work4', 'anUiFile.ui'],"""
346 <!DOCTYPE UI><UI>
347 <class>MyWidget</class>
348 <widget>
349     <class>QWidget</class>
350     <property name="name">
351         <cstring>MyWidget</cstring>
352     </property>
353     <property name="caption">
354         <string>MyWidget</string>
355     </property>
356 </widget>
357 <layoutdefaults spacing="6" margin="11"/>
358 </UI>
359 """)
360
361     test.write( ['work4', 'main.cpp'], """
362 #include "mocFromCpp.h"
363 #include "mocFromH.h"
364 #include "anUiFile.h"
365 int main() {
366   mocFromCpp();
367   mocFromH();
368   MyWidget mywidget();
369 }
370 """)
371
372     test.run(chdir='work4', arguments="test_realqt" + _exe)
373 else:
374     print "Could not find QT, skipping test(s)."
375
376
377 test.pass_test()