Imported Upstream version 1.57.0
[platform/upstream/boost.git] / tools / build / test / MockToolset.py
1 #!/usr/bin/python
2
3 # Copyright (C) 2013 Steven Watanabe
4 # Distributed under the Boost Software License, Version 1.0.
5 # (See accompanying file LICENSE_1_0.txt or copy at
6 # http://www.boost.org/LICENSE_1_0.txt)
7
8 import sys
9
10 def create(t):
11   t.write('''mockinfo.py''', '''
12 import re
13 import optparse
14 import os
15
16 parser = optparse.OptionParser()
17 parser.add_option('-o', dest="output_file")
18 parser.add_option('-x', dest="language")
19 parser.add_option('-c', dest="compile", action="store_true")
20 parser.add_option('-I', dest="includes", action="append")
21 parser.add_option('-L', dest="library_path", action="append")
22 parser.add_option('--dll', dest="dll", action="store_true")
23 parser.add_option('--archive', dest="archive", action="store_true")
24 parser.add_option('--static-lib', dest="static_libraries", action="append")
25 parser.add_option('--shared-lib', dest="shared_libraries", action="append")
26
27 cwd = os.environ["JAM_CWD"]
28
29 class MockInfo(object):
30   def __init__(self, verbose=False):
31     self.files = dict()
32     self.commands = list()
33     self.verbose = verbose
34   def source_file(self, name, pattern):
35     self.files[name] = pattern
36   def action(self, command, status=0):
37     self.commands.append((command, status))
38   def check(self, command):
39     print "Testing command", command
40     for (raw, status) in self.commands:
41       if self.matches(raw, command):
42         return status
43   def matches(self, raw, command):
44     (expected_options, expected_args) = parser.parse_args(raw.split())
45     options = command[0]
46     input_files = list(command[1])
47     if self.verbose:
48       print "  - matching against", (expected_options, expected_args)
49     if len(expected_args) != len(input_files):
50       if self.verbose:
51         print "  argument list sizes differ"
52       return False
53     for arg in expected_args:
54       if arg.startswith('$'):
55         fileid = arg[1:]
56         pattern = self.files[fileid] if fileid in self.files else fileid
57         matching_file = None
58         for input_file in input_files:
59           with open(input_file, 'r') as f:
60             contents = f.read()
61           if pattern == contents:
62             matching_file = input_file
63             break
64         if matching_file is not None:
65           input_files.remove(matching_file)
66         else:
67           if self.verbose:
68             print "    Failed to match input file contents: %s" % arg
69           return False
70       else:
71         if arg in input_files:
72           input_files.remove(arg)
73         else:
74           if self.verbose:
75             print "    Failed to match input file: %s" % arg
76           return False
77
78     if options.language != expected_options.language:
79       if self.verbose:
80         print "    Failed to match -c"
81       return False
82
83     if options.compile != expected_options.compile:
84       if self.verbose:
85         print "    Failed to match -x"
86       return False
87
88     # Normalize a path for comparison purposes
89     def adjust_path(p):
90       return os.path.normcase(os.path.normpath(os.path.join(cwd, p)))
91
92     # order matters
93     if options.includes is None:
94       options.includes = []
95     if expected_options.includes is None:
96       expected_options.includes = []
97     if map(adjust_path, options.includes) != \
98         map(adjust_path, expected_options.includes):
99       if self.verbose:
100         print "    Failed to match -I ",  map(adjust_path, options.includes), \
101           " != ", map(adjust_path, expected_options.includes)
102       return False
103
104     if options.library_path is None:
105       options.library_path = []
106     if expected_options.library_path is None:
107       expected_options.library_path = []
108     if map(adjust_path, options.library_path) != \
109         map(adjust_path, expected_options.library_path):
110       if self.verbose:
111         print "    Failed to match -L ",  map(adjust_path, options.library_path), \
112           " != ", map(adjust_path, expected_options.library_path)
113       return False
114
115     if options.static_libraries != expected_options.static_libraries:
116       if self.verbose:
117         print "    Failed to match --static-lib"
118       return False
119
120     if options.shared_libraries != expected_options.shared_libraries:
121       if self.verbose:
122         print "    Failed to match --shared-lib"
123       return False
124
125     if options.dll != expected_options.dll:
126       if self.verbose:
127         print "    Failed to match --dll"
128       return False
129
130     if options.archive != expected_options.archive:
131       if self.verbose:
132         print "    Failed to match --archive"
133       return False
134
135     # The output must be handled after everything else
136     # is validated
137     if expected_options.output_file is not None:
138       if options.output_file is not None:
139         if expected_options.output_file.startswith('$'):
140           fileid = expected_options.output_file[1:]
141           if fileid not in self.files:
142             self.files[fileid] = fileid
143           else:
144             assert(self.files[fileid] == fileid)
145           with open(options.output_file, 'w') as output:
146             output.write(fileid)
147       else:
148         if self.verbose:
149           print "Failed to match -o"
150         return False
151     elif options.output_file is not None:
152       if self.verbose:
153         print "Failed to match -o"
154       return False
155
156     # if we've gotten here, then everything matched
157     if self.verbose:
158       print "    Matched"
159     return True
160 ''')
161
162   t.write('mock.py', '''
163 import mockinfo
164 import markup
165 import sys
166
167 status = markup.info.check(mockinfo.parser.parse_args())
168 if status is not None:
169   exit(status)
170 else:
171   print("Unrecognized command: " + ' '.join(sys.argv))
172   exit(1)
173 ''')
174
175   t.write('mock.jam', '''
176 import feature ;
177 import toolset ;
178 import path ;
179 import modules ;
180 import common ;
181 import type ;
182
183 .python-cmd = "\"%s\"" ;
184
185 # Behave the same as gcc on Windows, because that's what
186 # the test system expects
187 type.set-generated-target-prefix SHARED_LIB : <toolset>mock <target-os>windows : lib ;
188 type.set-generated-target-suffix STATIC_LIB : <toolset>mock <target-os>windows : a ;
189
190 rule init ( )
191 {
192     local here = [ path.make [ modules.binding $(__name__) ] ] ;
193     here = [ path.native [ path.root [ path.parent $(here) ] [ path.pwd ] ] ] ;
194     .config-cmd = [ common.variable-setting-command JAM_CWD : $(here) ] $(.python-cmd) -B ;
195 }
196
197 feature.extend toolset : mock ;
198
199 generators.register-c-compiler mock.compile.c++ : CPP : OBJ : <toolset>mock ;
200 generators.register-c-compiler mock.compile.c : C : OBJ : <toolset>mock ;
201
202 generators.register-linker mock.link : LIB OBJ : EXE : <toolset>mock ;
203 generators.register-linker mock.link.dll : LIB OBJ : SHARED_LIB : <toolset>mock ;
204 generators.register-archiver mock.archive : OBJ : STATIC_LIB : <toolset>mock ;
205
206 toolset.flags mock.compile INCLUDES <include> ;
207
208 actions compile.c
209 {
210    $(.config-cmd) mock.py -c -x c -I"$(INCLUDES)" "$(>)" -o "$(<)"
211 }
212
213 actions compile.c++
214 {
215     $(.config-cmd) mock.py -c -x c++ -I"$(INCLUDES)" "$(>)" -o "$(<)"
216 }
217
218 toolset.flags mock.link USER_OPTIONS <linkflags> ;
219 toolset.flags mock.link FINDLIBS-STATIC <find-static-library> ;
220 toolset.flags mock.link FINDLIBS-SHARED <find-shared-library> ;
221 toolset.flags mock.link LINK_PATH <library-path> ;
222 toolset.flags mock.link LIBRARIES <library-file> ;
223
224 actions link
225 {
226     $(.config-cmd) mock.py "$(>)" -o "$(<)" $(USER_OPTIONS) -L"$(LINK_PATH)" --static-lib=$(FINDLIBS-STATIC) --shared-lib=$(FINDLIBS-SHARED)
227 }
228
229 actions archive
230 {
231     $(.config-cmd) mock.py --archive "$(>)" -o "$(<)" $(USER_OPTIONS)
232 }
233
234 actions link.dll
235 {
236     $(.config-cmd) mock.py --dll "$(>)" -o "$(<)" $(USER_OPTIONS) -L"$(LINK_PATH)" --static-lib=$(FINDLIBS-STATIC) --shared-lib=$(FINDLIBS-SHARED)
237 }
238
239 ''' % sys.executable.replace('\\', '\\\\'))
240
241 def set_expected(t, markup):
242   verbose = "True" if t.verbose else "False"
243   t.write('markup.py', '''
244 import mockinfo
245 info = mockinfo.MockInfo(%s)
246 def source_file(name, contents):
247   info.source_file(name, contents)
248 def action(command, status=0):
249   info.action(command, status)
250 ''' % verbose + markup)