QtBase  v6.3.1
generate_testcase.py
Go to the documentation of this file.
1 
28 import textwrap
29 import time
30 from subprocess import Popen, PIPE
31 
32 from function_signature import build_function_signature, build_function_name
33 from option_management import need_separate_output_sequence, qt_quirk_case
34 
35 
36 def InputSequenceItem(toptions):
37  if toptions["inputitemtype"] == "standard":
38  return "SequenceItem<tag_input>"
39  if toptions["inputitemtype"] == "noconstruct":
40  return "NoConstructSequenceItem<tag_input>"
41  if toptions["inputitemtype"] == "moveonly":
42  return "MoveOnlySequenceItem<tag_input>"
43  if toptions["inputitemtype"] == "moveonlynoconstruct":
44  return "MoveOnlyNoConstructSequenceItem<tag_input>"
45  assert False
46 
47 
48 def InputSequence(toptions):
49  item = InputSequenceItem(toptions)
50  if toptions["inputsequence"] == "standard":
51  return "std::vector<{}>".format(item)
52  if toptions["inputsequence"] == "moveonly":
53  return "MoveOnlyVector<{}>".format(item)
54  assert False
55 
56 
58  t = InputSequenceItem(toptions)
59  # construct IILE
60  mystring = ("[](){" + InputSequence(toptions) + " result;\n"
61  + "\n".join("result.push_back({}({}, true));".format(t, i) for i in range(1, 7))
62  + "\n return result; }()")
63  return mystring
64 
65 
66 def OutputSequenceItem(toptions):
67  if toptions["map"] and (toptions["inplace"] or toptions["maptype"] == "same"):
68  return InputSequenceItem(toptions)
69 
70  if toptions["map"]:
71  if toptions["mappeditemtype"] == "standard":
72  return "SequenceItem<tag_mapped>"
73  if toptions["mappeditemtype"] == "noconstruct":
74  return "NoConstructSequenceItem<tag_mapped>"
75  if toptions["mappeditemtype"] == "moveonly":
76  return "MoveOnlySequenceItem<tag_mapped>"
77  if toptions["mappeditemtype"] == "moveonlynoconstruct":
78  return "MoveOnlyNoConstructSequenceItem<tag_mapped>"
79  assert(False)
80  else:
81  return InputSequenceItem(toptions)
82 
83 
84 def ReducedItem(toptions):
85  if toptions["reductiontype"] == "same":
86  return OutputSequenceItem(toptions)
87  else:
88  if toptions["reductionitemtype"] == "standard":
89  return "SequenceItem<tag_reduction>"
90  if toptions["reductionitemtype"] == "noconstruct":
91  return "NoConstructSequenceItem<tag_reduction>"
92  if toptions["reductionitemtype"] == "moveonly":
93  return "MoveOnlySequenceItem<tag_reduction>"
94  if toptions["reductionitemtype"] == "moveonlynoconstruct":
95  return "MoveOnlyNoConstructSequenceItem<tag_reduction>"
96  assert(False)
97 
98 
99 def OutputSequence(toptions):
100  item = OutputSequenceItem(toptions)
101  # quirk of qt: not a QFuture<Sequence> is returned
102  if qt_quirk_case(toptions):
103  return "QList<{}>".format(item)
104 
105  needs_extra = need_separate_output_sequence(toptions)
106  if not needs_extra:
107  return InputSequence(toptions)
108 
109 
110  if toptions["outputsequence"] == "standard":
111  return "std::vector<{}>".format(item)
112  if toptions["outputsequence"] == "moveonly":
113  return "MoveOnlyVector<{}>".format(item)
114  assert False
115 
116 
117 def resultData(toptions):
118  result = [1, 2, 3, 4, 5, 6]
119  if toptions["filter"]:
120  result = filter(lambda x: x % 2 == 1, result)
121  if toptions["map"]:
122  result = map(lambda x: 2 * x, result)
123  if toptions["reduce"]:
124  result = sum(result)
125  return result
126 
127 
129  t = OutputSequenceItem(toptions)
130  # construct IILE
131  mystring = ("[](){" + OutputSequence(toptions) + " result;\n"
132  + "\n".join("result.push_back({}({}, true));".format(t, i) for i in resultData(toptions))
133  + "\n return result; }()")
134  return mystring
135 
136 
138  result = resultData(toptions)
139  assert isinstance(result, int)
140  return ReducedItem(toptions) + "(" + str(result) + ", true)"
141 
142 
144  item = InputSequenceItem(toptions)
145  if toptions["filterfunction"] == "function":
146  return "myfilter<{}>".format(item)
147  if toptions["filterfunction"] == "functor":
148  return "MyFilter<{}>{{}}".format(item)
149  if toptions["filterfunction"] == "memberfunction":
150  return "&{}::isOdd".format(item)
151  if toptions["filterfunction"] == "lambda":
152  return "[](const {}& x){{ return myfilter<{}>(x); }}".format(item, item)
153  if toptions["filterfunction"] == "moveonlyfunctor":
154  return "MyMoveOnlyFilter<{}>{{}}".format(item)
155  assert False
156 
157 
159  oldtype = InputSequenceItem(toptions)
160  newtype = OutputSequenceItem(toptions)
161  if toptions["inplace"]:
162  assert oldtype == newtype
163  if toptions["mapfunction"] == "function":
164  return "myInplaceMap<{}>".format(oldtype)
165  if toptions["mapfunction"] == "functor":
166  return "MyInplaceMap<{}>{{}}".format(oldtype)
167  if toptions["mapfunction"] == "memberfunction":
168  return "&{}::multiplyByTwo".format(oldtype)
169  if toptions["mapfunction"] == "lambda":
170  return "[]({}& x){{ return myInplaceMap<{}>(x); }}".format(oldtype, oldtype)
171  if toptions["mapfunction"] == "moveonlyfunctor":
172  return "MyMoveOnlyInplaceMap<{}>{{}}".format(oldtype)
173  assert False
174  else:
175  if toptions["mapfunction"] == "function":
176  return "myMap<{f},{t}>".format(f=oldtype, t=newtype)
177  if toptions["mapfunction"] == "functor":
178  return "MyMap<{f},{t}>{{}}".format(f=oldtype, t=newtype)
179  if toptions["mapfunction"] == "memberfunction":
180  return "&{}::multiplyByTwo".format(newtype)
181  if toptions["mapfunction"] == "lambda":
182  return "[](const {f}& x){{ return myMap<{f},{t}>(x); }}".format(f=oldtype, t=newtype)
183  if toptions["mapfunction"] == "moveonlyfunctor":
184  return "MyMoveOnlyMap<{f},{t}>{{}}".format(f=oldtype, t=newtype)
185  assert False
186 
187 
189  elementtype = OutputSequenceItem(toptions)
190  sumtype = ReducedItem(toptions)
191 
192  if toptions["reductionfunction"] == "function":
193  return "myReduce<{f},{t}>".format(f=elementtype, t=sumtype)
194  if toptions["reductionfunction"] == "functor":
195  return "MyReduce<{f},{t}>{{}}".format(f=elementtype, t=sumtype)
196  if toptions["reductionfunction"] == "lambda":
197  return "[]({t}& sum, const {f}& x){{ return myReduce<{f},{t}>(sum, x); }}".format(f=elementtype, t=sumtype)
198  if toptions["reductionfunction"] == "moveonlyfunctor":
199  return "MyMoveOnlyReduce<{f},{t}>{{}}".format(f=elementtype, t=sumtype)
200  assert False
201 
202 
204  return ReducedItem(options) + "(0, true)"
205 
206 
208  args = []
209  out_s = OutputSequence(options)
210  in_s = InputSequence(options)
211  if options["reduce"] and options["reductionfunction"] == "lambda":
212  args.append(ReducedItem(options))
213  elif out_s != in_s:
214  if not qt_quirk_case(options):
215  args.append(out_s)
216 
217  if len(args):
218  return "<" + ", ".join(args) + ">"
219 
220  return ""
221 
222 
223 numcall = 0
224 
225 
226 def generate_testcase(function_options, testcase_options):
227  options = {**function_options, **testcase_options}
228 
229  option_description = "\n".join(" {}={}".format(
230  a, b) for a, b in testcase_options.items())
231  option_description = textwrap.indent(option_description, " "*12)
232  function_signature = textwrap.indent(build_function_signature(function_options), " "*12)
233  testcase_name = "_".join("{}_{}".format(x, y) for x, y in options.items())
234  global numcall
235  numcall += 1
236  testcase_name = "test" + str(numcall)
237  function_name = build_function_name(options)
238 
239  arguments = []
240 
241  template_args = function_template_args(options)
242 
243  # care about the thread pool
244  if options["pool"]:
245  pool_initialization = """QThreadPool pool;
246  pool.setMaxThreadCount(1);"""
247  arguments.append("&pool")
248  else:
249  pool_initialization = ""
250 
251  # care about the input sequence
252  input_sequence_initialization_string = InputSequenceInitializationString(options)
253 
254  if "inputsequencepassing" in options and options["inputsequencepassing"] == "lvalue" or options["inplace"]:
255  input_sequence_initialization = "auto input_sequence = " + \
256  input_sequence_initialization_string + ";"
257  arguments.append("input_sequence")
258  elif "inputsequencepassing" in options and options["inputsequencepassing"] == "rvalue":
259  input_sequence_initialization = ""
260  arguments.append(input_sequence_initialization_string)
261  else:
262  input_sequence_initialization = "auto input_sequence = " + \
263  input_sequence_initialization_string + ";"
264  arguments.append("input_sequence.begin()")
265  arguments.append("input_sequence.end()")
266 
267  # care about the map:
268  if options["map"]:
269  map_initialization_string = MapInitializationString(options)
270  if options["mapfunctionpassing"] == "lvalue":
271  map_initialization = "auto map = " + map_initialization_string + ";"
272  arguments.append("map")
273  elif options["mapfunctionpassing"] == "rvalue":
274  map_initialization = ""
275  arguments.append(map_initialization_string)
276  else:
277  assert False
278  else:
279  map_initialization = ""
280 
281  # care about the filter
282  if options["filter"]:
283  filter_initialization_string = FilterInitializationString(options)
284  if options["filterfunctionpassing"] == "lvalue":
285  filter_initialization = "auto filter = " + filter_initialization_string + ";"
286  arguments.append("filter")
287  elif options["filterfunctionpassing"] == "rvalue":
288  filter_initialization = ""
289  arguments.append(filter_initialization_string)
290  else:
291  assert (False)
292  else:
293  filter_initialization = ""
294 
295  reduction_initialvalue_initialization = ""
296  # care about reduction
297  if options["reduce"]:
298  reduction_initialization_expression = ReductionInitializationString(options)
299  if options["reductionfunctionpassing"] == "lvalue":
300  reduction_initialization = "auto reductor = " + reduction_initialization_expression + ";"
301  arguments.append("reductor")
302  elif options["reductionfunctionpassing"] == "rvalue":
303  reduction_initialization = ""
304  arguments.append(reduction_initialization_expression)
305  else:
306  assert (False)
307 
308  # initialvalue:
309  if options["initialvalue"]:
310  reduction_initialvalue_initialization_expression = ReductionInitialvalueInitializationString(options)
311  if options["reductioninitialvaluepassing"] == "lvalue":
312  reduction_initialvalue_initialization = "auto initialvalue = " + reduction_initialvalue_initialization_expression + ";"
313  arguments.append("initialvalue")
314  elif options["reductioninitialvaluepassing"] == "rvalue":
315  reduction_initialvalue_initialization = ""
316  arguments.append(reduction_initialvalue_initialization_expression)
317  else:
318  assert (False)
319 
320  if options["reductionoptions"] == "UnorderedReduce":
321  arguments.append("QtConcurrent::UnorderedReduce")
322  elif options["reductionoptions"] == "OrderedReduce":
323  arguments.append("QtConcurrent::OrderedReduce")
324  elif options["reductionoptions"] == "SequentialReduce":
325  arguments.append("QtConcurrent::SequentialReduce")
326  else:
327  assert options["reductionoptions"] == "unspecified"
328  else:
329  reduction_initialization = ""
330 
331  # what is the expected result
332  if options["filter"]:
333  if not options["reduce"]:
334  expected_result_expression = OutputSequenceInitializationString(options)
335  else:
336  expected_result_expression = OutputScalarInitializationString(options)
337  elif options["map"]:
338  if not options["reduce"]:
339  expected_result_expression = OutputSequenceInitializationString(options)
340  else:
341  expected_result_expression = OutputScalarInitializationString(options)
342 
343  wait_result_expression = ""
344  if options["inplace"]:
345  if options["blocking"]:
346  result_accepting = ""
347  result_variable = "input_sequence"
348  else:
349  result_accepting = "auto future = "
350  result_variable = "input_sequence"
351  wait_result_expression = "future.waitForFinished();"
352  elif options["blocking"]:
353  result_accepting = "auto result = "
354  result_variable = "result"
355  else:
356  if not options["reduce"]:
357  result_accepting = "auto result = "
358  result_variable = "result.results()"
359  else:
360  result_accepting = "auto result = "
361  result_variable = "result.takeResult()"
362 
363  arguments_passing = ", ".join(arguments)
364  final_string = f"""
365  void tst_QtConcurrentFilterMapGenerated::{testcase_name}()
366  {{
367  /* test for
368 {function_signature}
369 
370  with
371 {option_description}
372  */
373 
374  {pool_initialization}
375  {input_sequence_initialization}
376  {filter_initialization}
377  {map_initialization}
378  {reduction_initialization}
379  {reduction_initialvalue_initialization}
380 
381  {result_accepting}QtConcurrent::{function_name}{template_args}({arguments_passing});
382 
383  auto expected_result = {expected_result_expression};
384  {wait_result_expression}
385  QCOMPARE({result_variable}, expected_result);
386  }}
387  """
388  p = Popen(["clang-format"], stdin=PIPE, stdout=PIPE, stderr=PIPE)
389  final_string = p.communicate(final_string.encode())[0].decode()
390 
391  return (f" void {testcase_name}();\n", final_string)
QMap< QString, QString > map
[6]
QString str
[2]
def build_function_name(options)
def build_function_signature(options)
def ReducedItem(toptions)
def OutputScalarInitializationString(toptions)
def OutputSequenceItem(toptions)
def ReductionInitialvalueInitializationString(options)
def ReductionInitializationString(toptions)
def InputSequenceInitializationString(toptions)
def OutputSequenceInitializationString(toptions)
def OutputSequence(toptions)
def InputSequenceItem(toptions)
def generate_testcase(function_options, testcase_options)
def resultData(toptions)
def MapInitializationString(toptions)
def InputSequence(toptions)
def function_template_args(options)
def FilterInitializationString(toptions)
def need_separate_output_sequence(options)
def qt_quirk_case(options)
#define assert
Definition: qcborcommon_p.h:63
#define decode(x)
Definition: qurlquery.cpp:242
QFuture< int > sum