| OLD | NEW |
| (Empty) | |
| 1 #!/usr/bin/python |
| 2 # |
| 3 # Copyright (c) 2012 The Native Client Authors. All rights reserved. |
| 4 # Use of this source code is governed by a BSD-style license that can be |
| 5 # found in the LICENSE file. |
| 6 # |
| 7 |
| 8 """ |
| 9 Responsible for generating the testing decoders based on |
| 10 parsed table representations. |
| 11 """ |
| 12 |
| 13 # This file generates testing code for our class decoder. The decoder |
| 14 # tables are specifically written to minimize the number of decoder |
| 15 # classes needed to parse valid ARM instructions. For testing, this is |
| 16 # a problem. We can't (easily) tell if the intended instruction rules |
| 17 # of ARM are being met, since there is not a one-to-one mapping from |
| 18 # class decoders to rules. |
| 19 # |
| 20 # To fix this, we allow table row actions to have multiple identifiers |
| 21 # (between 1 and 4). All but the first is optional (since it defines |
| 22 # what we do in the class decoder in sel_ldr). The general form is: |
| 23 # |
| 24 # =InstClass Rule Pattern Constraints |
| 25 # |
| 26 # The 'InstClass' is the class decoder to use in sel_ldr. 'Rule' is a |
| 27 # name corresponding to a specific instruction layout. 'Pattern' is |
| 28 # the pattern for bits in that specific instruction layout. |
| 29 # |
| 30 # In addition, many specific instruction layouts define additional |
| 31 # constraints (i.e. assumptions) about cases when the instruction |
| 32 # layout doesn't apply. The 'Contraints' identifier is a name |
| 33 # defining a tester (for the InstClass) that checks these additional |
| 34 # constraints. |
| 35 # |
| 36 # Note: The current ARM instruction table has both new and old |
| 37 # actions. Old actions only define the 'InstClass' entry. If the |
| 38 # remaining fields are omitted, the corresponding testing for those |
| 39 # entries are omitted. |
| 40 # |
| 41 # For testing, we would like to know the specific instruction rule |
| 42 # that was being tested. Further, we would like to know what |
| 43 # instruction rule was chosen for each decoder class selection made by |
| 44 # the parse tables. To do this, we do two levels of wrapping. |
| 45 # |
| 46 # The first type of class wrappers is for each Rule associated with an |
| 47 # InstClass. It has the form: |
| 48 # |
| 49 # class RuleInstClass : public Rule { |
| 50 # public: |
| 51 # virtual ~Add_Rule_7_A1_P26() {} |
| 52 # }; |
| 53 # |
| 54 # The second set of wrapper classes is to generate a subclass for each |
| 55 # InstClass, and to generate a subclass for each Rule of an InstClass |
| 56 # (in general, the same InstClass is used in multiple rows, each being |
| 57 # defined with a different Rule). These subclasses are a subclass of |
| 58 # NamedClassDecoder, and add a name to the class decoder, matching the |
| 59 # context for which the decoder classes could be used. |
| 60 # |
| 61 # The named version of each named InstClass is: |
| 62 # |
| 63 # class NamedInstClass : public NamedClassDecoder { |
| 64 # public: |
| 65 # inline NamedInstClass() |
| 66 # : NamedClassDecoder(decoder_, "InstClass") |
| 67 # {} |
| 68 # virtual ~NamedInstClass() {} |
| 69 # protected: |
| 70 # explicit inline NamedInstClass(const char* name) |
| 71 # : NamedClassDecoder(decoder_, name) {} |
| 72 # private: |
| 73 # Binary3RegisterShiftedTest decoder_; |
| 74 #}; |
| 75 # |
| 76 # This makes sure that each decoder class can be identified using a |
| 77 # separate class decoder. The public constructor is for table rows |
| 78 # that don't have rule names. The protected constructor is for table |
| 79 # rows that have a rule name, and will be a subclass of this class. |
| 80 # The class defined for rows with a Rule name is: |
| 81 # |
| 82 # class NamedRuleInstClass : public NamedInstClass { |
| 83 # public: |
| 84 # inline NamedRuleInstClass() |
| 85 # : NamedInstClass("RuleInstClass") |
| 86 # {} |
| 87 # virtual ~NamedAdd_Rule_7_A1_P26Binary4RegisterShiftedOp() {} |
| 88 #}; |
| 89 # |
| 90 # The base class for NamedClassDecoder is specified in |
| 91 # "named_class_decoder.h". This file defines a class that takes a |
| 92 # ClassDecoder (reference) C and a print name NAME, and builds a |
| 93 # corresponding ClassDecoder that acts like C, but will print out |
| 94 # NAME. The behaviour of C is maintained by dispatching each virtual |
| 95 # on the NamedClassDecoder to the corresponding virtual on C. |
| 96 # |
| 97 # We then define the class decoder Decoder, by defining a derived |
| 98 # instance of DecoderState as follows: |
| 99 # |
| 100 # class NamedDecoder : DecoderState { |
| 101 # public: |
| 102 # explicit NamedDecoder(); |
| 103 # virtual ~NamedDecoder(); |
| 104 # const NamedClassDecoder& decode_named(const Instruction) const; |
| 105 # virtual const ClassDecoder& decode(const Instruction) const; |
| 106 # ... |
| 107 # }; |
| 108 # |
| 109 # The method decode is the expected API for the NamedDecoder, which is |
| 110 # an instance of DecoderState (defined in decode.h). The method |
| 111 # decode_named is the same, but returns NamedClassDecoder's so that |
| 112 # good error messages can be generated by the test harnesses for |
| 113 # ClassDecoder's (see decoder_tester.h for more details on |
| 114 # ClassDecoder test harnesses). |
| 115 # |
| 116 # To the NamedDecoder, we add a constant field NamedClassDecoder for |
| 117 # each possible class decoder method decode_named could return, or |
| 118 # that we could use in automatically generated tests. These fields |
| 119 # allow us to only create the corresponding decoder classes once |
| 120 # (during constructor initialization). |
| 121 # |
| 122 # Finally, we add a method corresponding to each defined decoder |
| 123 # table. The forms of these decoders is: |
| 124 # |
| 125 # inline const NamedClassDecoder& decode_TABLE( |
| 126 # const nacl_arm_dec::Instruction insn) const; |
| 127 # |
| 128 # Each of these methods are defined as inline methods so that they can |
| 129 # be optimized away in the corresponding top level methods (i.e. |
| 130 # decode_named and decode). |
| 131 # |
| 132 # For testing, there are three files generated: |
| 133 # |
| 134 # decoder_named_classes.h |
| 135 # decoder_named_decoder.h |
| 136 # decoder_named.cc |
| 137 # decoder_tests.cc |
| 138 # |
| 139 # File decoder_named_classes.h defines the class declarations for the |
| 140 # generated Rule classes, and named class decoder classes. File |
| 141 # decoder_named_decoder.h defines the decoder class NamedDecoder |
| 142 # (discussed above). decoder_named.cc contains the corresponding |
| 143 # implementations of the constructors and methods of these classes. |
| 144 # |
| 145 # decoder_tests.cc generates an automatic test harness executable, |
| 146 # that will test each instruction Rule. Each test generates all |
| 147 # possible matches the the corresponding Pattern of the table rule, |
| 148 # and calls the corresponding tester associated with the class decoder |
| 149 # of that row. By default, the tester is presumed to be named. |
| 150 # |
| 151 # InstClassTester |
| 152 # |
| 153 # If the row defines a Constraints identifier, then the tester |
| 154 # |
| 155 # InstClassTesterConstraints |
| 156 # |
| 157 # is used instead. |
| 158 |
| 159 import dgen_opt |
| 160 import dgen_output |
| 161 |
| 162 # Defines the header for decoder_named_classes.h |
| 163 NAMED_CLASSES_H_HEADER=""" |
| 164 %(FILE_HEADER)s |
| 165 %(NOT_TCB_MESSAGE)s |
| 166 |
| 167 #ifndef %(IFDEF_NAME)s |
| 168 #define %(IFDEF_NAME)s |
| 169 |
| 170 #include "native_client/src/trusted/validator_arm/named_class_decoder.h" |
| 171 |
| 172 """ |
| 173 |
| 174 RULE_CLASSES_HEADER=""" |
| 175 /* |
| 176 * Define rule decoder classes. |
| 177 */ |
| 178 namespace nacl_arm_dec { |
| 179 """ |
| 180 |
| 181 RULE_CLASS=""" |
| 182 class %(rule)s%(decoder)s |
| 183 : public %(decoder)s { |
| 184 public: |
| 185 virtual ~%(rule)s%(decoder)s() {} |
| 186 }; |
| 187 |
| 188 """ |
| 189 |
| 190 RULE_CLASSES_FOOTER=""" |
| 191 } // nacl_arm_dec |
| 192 """ |
| 193 |
| 194 NAMED_H_NAMESPACE=""" |
| 195 namespace nacl_arm_test { |
| 196 """ |
| 197 |
| 198 NAMED_DECODERS_HEADER=""" |
| 199 /* |
| 200 * Define named class decoders for each class decoder. |
| 201 * The main purpose of these classes is to introduce |
| 202 * instances that are named specifically to the class decoder |
| 203 * and/or rule that was used to parse them. This makes testing |
| 204 * much easier in that error messages use these named classes |
| 205 * to clarify what row in the corresponding table was used |
| 206 * to select this decoder. Without these names, debugging the |
| 207 * output of the test code would be nearly impossible |
| 208 */ |
| 209 |
| 210 """ |
| 211 |
| 212 NAMED_DECODER_DECLARE=""" |
| 213 class Named%(decoder)s : public NamedClassDecoder { |
| 214 public: |
| 215 inline Named%(decoder)s() |
| 216 : NamedClassDecoder(decoder_, "%(decoder)s") |
| 217 {} |
| 218 virtual ~Named%(decoder)s() {} |
| 219 protected: |
| 220 explicit inline Named%(decoder)s(const char* name) |
| 221 : NamedClassDecoder(decoder_, name) {} |
| 222 private: |
| 223 nacl_arm_dec::%(decoder)s decoder_; |
| 224 }; |
| 225 |
| 226 """ |
| 227 |
| 228 NAMED_RULE_DECLARE=""" |
| 229 class Named%(rule)s%(decoder)s |
| 230 : public Named%(decoder)s { |
| 231 public: |
| 232 inline Named%(rule)s%(decoder)s() |
| 233 : Named%(decoder)s("%(rule)s%(decoder)s") |
| 234 {} |
| 235 virtual ~Named%(rule)s%(decoder)s() {} |
| 236 }; |
| 237 |
| 238 """ |
| 239 |
| 240 NAMED_CLASSES_H_FOOTER=""" |
| 241 } // namespace nacl_arm_test |
| 242 #endif // %(IFDEF_NAME)s |
| 243 """ |
| 244 |
| 245 def generate_named_classes_h(decoder, decoder_name, filename, out): |
| 246 """Defines named classes needed for decoder testing. |
| 247 |
| 248 Args: |
| 249 tables: list of Table objects to process. |
| 250 decoder_name: The name of the decoder state to build. |
| 251 filename: The (localized) name for the .h file. |
| 252 out: a COutput object to write to. |
| 253 """ |
| 254 if not decoder.primary: raise Exception('No tables provided.') |
| 255 |
| 256 values = { |
| 257 'FILE_HEADER': dgen_output.HEADER_BOILERPLATE, |
| 258 'NOT_TCB_MESSAGE' : dgen_output.NOT_TCB_BOILERPLATE, |
| 259 'IFDEF_NAME' : dgen_output.ifdef_name(filename), |
| 260 'decoder_name': decoder_name, |
| 261 } |
| 262 out.write(NAMED_CLASSES_H_HEADER % values) |
| 263 _generate_rule_classes(decoder, values, out) |
| 264 out.write(NAMED_H_NAMESPACE) |
| 265 _generate_named_decoder_classes(decoder, values, out) |
| 266 out.write(NAMED_CLASSES_H_FOOTER % values) |
| 267 |
| 268 def _generate_named_decoder_classes(decoder, values, out): |
| 269 out.write(NAMED_DECODERS_HEADER) |
| 270 # Generate one for each type of decoder in the decoder. |
| 271 for d in decoder.action_filter(['name']).decoders(): |
| 272 values['decoder'] = d.name |
| 273 values['rule'] = '' |
| 274 out.write(NAMED_DECODER_DECLARE % values) |
| 275 # Now generate one for each decoder that has a rule associated with it. |
| 276 for d in decoder.action_filter(['name', 'rule']).rules(): |
| 277 values['decoder'] = d.name |
| 278 values['rule'] = d.rule |
| 279 out.write(NAMED_RULE_DECLARE % values) |
| 280 |
| 281 def _generate_rule_classes(decoder, values, out): |
| 282 # Note: we generate these classes in nacl_arm_dec, so that |
| 283 # all decoder classes generated by the pareser are in the |
| 284 # same namesapce. |
| 285 out.write(RULE_CLASSES_HEADER) |
| 286 for action in decoder.action_filter(['name', 'rule']).rules(): |
| 287 values['decoder'] = action.name |
| 288 values['rule'] = action.rule |
| 289 out.write(RULE_CLASS % values) |
| 290 out.write(RULE_CLASSES_FOOTER) |
| 291 |
| 292 NAMED_DECODER_H_HEADER=""" |
| 293 %(FILE_HEADER)s |
| 294 %(NOT_TCB_MESSAGE)s |
| 295 |
| 296 #ifndef %(IFDEF_NAME)s |
| 297 #define %(IFDEF_NAME)s |
| 298 |
| 299 #include "native_client/src/trusted/validator_arm/decode.h" |
| 300 #include "%(FILENAME_BASE)s_classes.h" |
| 301 #include "native_client/src/trusted/validator_arm/named_class_decoder.h" |
| 302 |
| 303 namespace nacl_arm_test { |
| 304 """ |
| 305 |
| 306 DECODER_STATE_HEADER=""" |
| 307 // Defines a stateless (named)decoder class selector for instructions |
| 308 class Named%(decoder_name)s : nacl_arm_dec::DecoderState { |
| 309 public: |
| 310 explicit Named%(decoder_name)s(); |
| 311 virtual ~Named%(decoder_name)s(); |
| 312 |
| 313 // Parses the given instruction, returning the named class |
| 314 // decoder to use. |
| 315 const NamedClassDecoder& decode_named( |
| 316 const nacl_arm_dec::Instruction) const; |
| 317 |
| 318 // Parses the given instruction, returning the class decoder |
| 319 // to use. |
| 320 virtual const nacl_arm_dec::ClassDecoder& decode( |
| 321 const nacl_arm_dec::Instruction) const; |
| 322 |
| 323 // Fields containing the named class decoders that can |
| 324 // be returned. |
| 325 """ |
| 326 |
| 327 DECODER_STATE_FIELD=""" |
| 328 const Named%(rule)s%(decoder)s %(rule)s%(decoder)s_instance_; |
| 329 """ |
| 330 |
| 331 DECODER_STATE_PRIVATE=""" |
| 332 private: |
| 333 """ |
| 334 |
| 335 DECODER_STATE_DECODER=""" |
| 336 inline const NamedClassDecoder& decode_%(table)s( |
| 337 const nacl_arm_dec::Instruction insn) const; |
| 338 """ |
| 339 |
| 340 DECODER_STATE_FOOTER=""" |
| 341 }; |
| 342 """ |
| 343 |
| 344 NAMED_DECODER_H_FOOTER=""" |
| 345 } // namespace nacl_arm_test |
| 346 #endif // %(IFDEF_NAME)s |
| 347 """ |
| 348 |
| 349 def generate_named_decoder_h(decoder, decoder_name, filename, out): |
| 350 """Generates the named decoder for testing. |
| 351 |
| 352 Args: |
| 353 tables: list of Table objects to process. |
| 354 decoder_name: The name of the decoder state to build. |
| 355 filename: The (localized) name for the .h file. |
| 356 out: a COutput object to write to. |
| 357 """ |
| 358 if not decoder.primary: raise Exception('No tables provided.') |
| 359 |
| 360 values = { |
| 361 'FILE_HEADER': dgen_output.HEADER_BOILERPLATE, |
| 362 'NOT_TCB_MESSAGE' : dgen_output.NOT_TCB_BOILERPLATE, |
| 363 'IFDEF_NAME' : dgen_output.ifdef_name(filename), |
| 364 'FILENAME_BASE': filename[:-len('_decoder.h')], |
| 365 'decoder_name': decoder_name, |
| 366 } |
| 367 out.write(NAMED_DECODER_H_HEADER % values) |
| 368 _generate_decoder_state_class(decoder, values, out) |
| 369 out.write(NAMED_DECODER_H_FOOTER % values) |
| 370 |
| 371 def _generate_decoder_state_class(decoder, values, out): |
| 372 # Generate a field for each type of decoder in the decoder. |
| 373 out.write(DECODER_STATE_HEADER % values) |
| 374 for d in decoder.action_filter(['name']).decoders(): |
| 375 values['decoder'] = d.name |
| 376 values['rule'] = '' |
| 377 out.write(DECODER_STATE_FIELD % values) |
| 378 # Now generate one for each decoder that has a rule associated with it. |
| 379 for d in decoder.action_filter(['name', 'rule']).rules(): |
| 380 values['decoder'] = d.name |
| 381 values['rule'] = d.rule |
| 382 out.write(DECODER_STATE_FIELD % values) |
| 383 out.write(DECODER_STATE_PRIVATE); |
| 384 for table in decoder.tables(): |
| 385 values['table'] = table.name |
| 386 out.write(DECODER_STATE_DECODER % values) |
| 387 out.write(DECODER_STATE_FOOTER % values) |
| 388 |
| 389 # Defines the source for DECODER_named.cc |
| 390 NAMED_CC_HEADER=""" |
| 391 %(FILE_HEADER)s |
| 392 %(NOT_TCB_MESSAGE)s |
| 393 #include "%(FILENAME_BASE)s_decoder.h" |
| 394 |
| 395 #include <stdio.h> |
| 396 |
| 397 using nacl_arm_dec::ClassDecoder; |
| 398 using nacl_arm_dec::Instruction; |
| 399 |
| 400 namespace nacl_arm_test { |
| 401 """ |
| 402 |
| 403 PARSE_CONSTRUCT_HEADER=""" |
| 404 Named%(decoder_name)s::Named%(decoder_name)s() |
| 405 : nacl_arm_dec::DecoderState() |
| 406 """ |
| 407 |
| 408 PARSE_CONSTRUCT_FIELDS=""" |
| 409 , %(rule)s%(decoder)s_instance_() |
| 410 """ |
| 411 |
| 412 PARSE_CONSTRUCT_FOOTER=""" |
| 413 {} |
| 414 |
| 415 Named%(decoder_name)s::~Named%(decoder_name)s() {} |
| 416 """ |
| 417 |
| 418 PARSE_TABLE_METHOD_HEADER=""" |
| 419 /* |
| 420 * Implementation of table %(table_name)s. |
| 421 * Specified by: %(citation)s |
| 422 */ |
| 423 const NamedClassDecoder& Named%(decoder_name)s::decode_%(table_name)s( |
| 424 const nacl_arm_dec::Instruction insn) const { |
| 425 """ |
| 426 |
| 427 PARSE_TABLE_METHOD_ROW=""" |
| 428 if (%(tests)s) { |
| 429 return %(action)s; |
| 430 } |
| 431 """ |
| 432 |
| 433 PARSE_TABLE_METHOD_FOOTER=""" |
| 434 // Catch any attempt to fall through... |
| 435 fprintf(stderr, "TABLE IS INCOMPLETE: %(table_name)s could not parse %%08X", |
| 436 insn.bits(31,0)); |
| 437 return Forbidden_instance_; |
| 438 } |
| 439 |
| 440 """ |
| 441 |
| 442 NAMED_CC_FOOTER=""" |
| 443 const NamedClassDecoder& Named%(decoder_name)s:: |
| 444 decode_named(const nacl_arm_dec::Instruction insn) const { |
| 445 return decode_%(entry_table_name)s(insn); |
| 446 } |
| 447 |
| 448 const nacl_arm_dec::ClassDecoder& Named%(decoder_name)s:: |
| 449 decode(const nacl_arm_dec::Instruction insn) const { |
| 450 return decode_named(insn).named_decoder(); |
| 451 } |
| 452 |
| 453 } // namespace nacl_arm_test |
| 454 """ |
| 455 |
| 456 def generate_named_cc(decoder, decoder_name, filename, out): |
| 457 """Implementation of the test decoder in .cc file |
| 458 |
| 459 Args: |
| 460 tables: list of Table objects to process. |
| 461 decoder_name: The name of the decoder state to build. |
| 462 filename: The (localized) name for the .h file. |
| 463 out: a COutput object to write to. |
| 464 """ |
| 465 if not decoder.primary: raise Exception('No tables provided.') |
| 466 |
| 467 values = { |
| 468 'FILE_HEADER': dgen_output.HEADER_BOILERPLATE, |
| 469 'NOT_TCB_MESSAGE' : dgen_output.NOT_TCB_BOILERPLATE, |
| 470 'FILENAME_BASE' : filename[:-len('.cc')], |
| 471 'decoder_name': decoder_name, |
| 472 'entry_table_name': decoder.primary.name, |
| 473 } |
| 474 out.write(NAMED_CC_HEADER % values) |
| 475 _generate_decoder_constructors(decoder, values, out) |
| 476 _generate_decoder_method_bodies(decoder, values, out) |
| 477 out.write(NAMED_CC_FOOTER % values) |
| 478 |
| 479 def _generate_decoder_constructors(decoder, values, out): |
| 480 out.write(PARSE_CONSTRUCT_HEADER % values) |
| 481 # Initialize each type of decoder in the decoder. |
| 482 for d in decoder.action_filter(['name']).decoders(): |
| 483 values['decoder'] = d.name |
| 484 values['rule'] = '' |
| 485 out.write(PARSE_CONSTRUCT_FIELDS % values) |
| 486 # Now initialize fields for each decoder with a rule. |
| 487 for d in decoder.action_filter(['name', 'rule']).rules(): |
| 488 values['decoder'] = d.name |
| 489 values['rule'] = d.rule |
| 490 out.write(PARSE_CONSTRUCT_FIELDS % values) |
| 491 out.write(PARSE_CONSTRUCT_FOOTER % values) |
| 492 |
| 493 def _generate_decoder_method_bodies(decoder, values, out): |
| 494 for table in decoder.tables(): |
| 495 opt_rows = dgen_opt.optimize_rows( |
| 496 table.action_filter(['name', 'rule']).rows) |
| 497 print ("Table %s: %d rows minimized to %d" |
| 498 % (table.name, len(table.rows), len(opt_rows))) |
| 499 |
| 500 values['table_name'] = table.name |
| 501 values['citation'] = table.citation, |
| 502 out.write(PARSE_TABLE_METHOD_HEADER % values) |
| 503 method_calls = filter( |
| 504 lambda(r): r.action.__class__.__name__ == 'DecoderMethod', opt_rows) |
| 505 if not method_calls: |
| 506 out.write(" UNREFERENCED_PARAMETER(insn);") |
| 507 |
| 508 for row in opt_rows: |
| 509 if row.action.__class__.__name__ == 'DecoderAction': |
| 510 values['decoder'] = row.action.name |
| 511 values['rule'] = row.action.rule if row.action.rule else '' |
| 512 action = '%(rule)s%(decoder)s_instance_' % values |
| 513 elif row.action.__class__.__name__ == 'DecoderMethod': |
| 514 action = 'decode_%s(insn)' % row.action.name |
| 515 else: |
| 516 raise Exception('Bad table action: %s' % row.action) |
| 517 values['tests'] = ' && '.join(['(%s)' % p.to_c_expr('insn') |
| 518 for p in row.patterns]) |
| 519 values['action'] = action |
| 520 out.write(PARSE_TABLE_METHOD_ROW % values) |
| 521 out.write(PARSE_TABLE_METHOD_FOOTER % values) |
| 522 |
| 523 # Define the source for DECODER_tests.cc |
| 524 TEST_CC_HEADER=""" |
| 525 %(FILE_HEADER)s |
| 526 %(NOT_TCB_MESSAGE)s |
| 527 |
| 528 #include "gtest/gtest.h" |
| 529 #include "native_client/src/trusted/validator_arm/inst_classes_testers.h" |
| 530 |
| 531 namespace nacl_arm_test { |
| 532 |
| 533 """ |
| 534 |
| 535 TESTER_CLASS=""" |
| 536 class %(rule)s%(decoder)sTester%(constraints)s |
| 537 : public %(decoder)sTester%(constraints)s { |
| 538 public: |
| 539 %(rule)s%(decoder)sTester%(constraints)s() |
| 540 : %(decoder)sTester%(constraints)s( |
| 541 state_.%(rule)s%(decoder)s_instance_) |
| 542 {} |
| 543 }; |
| 544 """ |
| 545 |
| 546 TEST_HARNESS=""" |
| 547 // Defines a gtest testing harness for tests. |
| 548 class %(decoder_name)sTests : public ::testing::Test { |
| 549 protected: |
| 550 %(decoder_name)sTests() {} |
| 551 }; |
| 552 """ |
| 553 |
| 554 TEST_FUNCTION=""" |
| 555 TEST_F(%(decoder_name)sTests, |
| 556 %(rule)s%(decoder)s%(constraints)s_%(pattern)s_Test) { |
| 557 %(rule)s%(decoder)sTester%(constraints)s tester; |
| 558 tester.Test("%(pattern)s"); |
| 559 } |
| 560 """ |
| 561 |
| 562 |
| 563 TEST_CC_FOOTER=""" |
| 564 } // namespace nacl_arm_test |
| 565 |
| 566 int main(int argc, char* argv[]) { |
| 567 testing::InitGoogleTest(&argc, argv); |
| 568 return RUN_ALL_TESTS(); |
| 569 } |
| 570 """ |
| 571 |
| 572 def generate_tests_cc(decoder, decoder_name, out): |
| 573 if not decoder.primary: raise Exception('No tables provided.') |
| 574 values = { |
| 575 'FILE_HEADER': dgen_output.HEADER_BOILERPLATE, |
| 576 'NOT_TCB_MESSAGE' : dgen_output.NOT_TCB_BOILERPLATE, |
| 577 'decoder_name': decoder_name, |
| 578 } |
| 579 out.write(TEST_CC_HEADER % values) |
| 580 _generate_rule_testers(decoder, values, out) |
| 581 out.write(TEST_HARNESS % values) |
| 582 _generate_test_patterns(decoder, values, out) |
| 583 out.write(TEST_CC_FOOTER % values) |
| 584 |
| 585 def _generate_rule_testers(decoder, values, out): |
| 586 for d in decoder.action_filter(['name', 'rule', 'constraints']).rules(): |
| 587 values['decoder'] = d.name |
| 588 values['rule'] = d.rule |
| 589 values['constraints'] = d.constraints if d.constraints else '' |
| 590 out.write(TESTER_CLASS % values) |
| 591 |
| 592 def _generate_test_patterns(decoder, values, out): |
| 593 for d in decoder.decoders(): |
| 594 if d.pattern: |
| 595 values['decoder'] = d.name |
| 596 values['rule'] = d.rule if d.rule else '' |
| 597 values['constraints'] = d.constraints if d.constraints else '' |
| 598 values['pattern'] = d.pattern |
| 599 out.write(TEST_FUNCTION % values) |
| OLD | NEW |