├── .gitignore ├── .travis.yml ├── LICENSE.txt ├── README.md ├── pom.xml └── src ├── main └── java │ └── metamutator │ ├── ArithmeticOperatorMetaMutator.java │ ├── Config.java │ ├── ISelector.java │ ├── IntegerConstantReplacementMetaMutator.java │ ├── LogicalExpressionMetaMutator.java │ ├── LoopExpressionMetaMutator.java │ ├── MutantReplay.java │ ├── MutantSearchSpaceExplorator.java │ ├── Null.java │ ├── NumericVariableMetaMutator.java │ ├── ReturnReplacementOperatorMetaMutator.java │ ├── RunnerThreaded.java │ ├── Selector.java │ ├── StatementDeletionMetaMutator.java │ ├── UniqueTestGenerator.java │ └── VariabletoNullMetaMutator.java └── test └── java ├── UniqueTestGeneratorTest.java ├── metamutator ├── ArithmeticOperatorMetaMutatorTest.java ├── BinaryOperatorMetaMutatorTest.java ├── ConstantReplacementMetaMutatorTest.java ├── LoopExpressionMetaMutatorTest.java ├── MutantSearchSpaceExploratorTest.java ├── NumericExpressionMetaMutatorTest.java ├── ReplayMutantTest.java ├── ReturnReplacementOperatorMetaMutatorTest.java ├── StatementDeletionMetaMutatorTest.java └── VariabletoNullMetaMutatorTest.java └── resources ├── Bar.java ├── Foo.java ├── StatementResource.java ├── foo └── Foo.java ├── foo_spooned └── Foo.java ├── footest └── FooTest.java ├── search_replay_spoon └── search_replay_src │ ├── SearchReplayClass.java │ └── SearchReplayClassBis.java ├── search_replay_src ├── SearchReplayClass.java └── SearchReplayClassBis.java └── search_replay_test ├── SearchReplayTestClass.java └── SearchReplayTestClassBis.java /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | spooned 3 | .classpath 4 | .project 5 | .settings 6 | results 7 | bin 8 | .idea 9 | *.iml 10 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: java 2 | 3 | jdk: openjdk8 4 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU General Public License is a free, copyleft license for 11 | software and other kinds of works. 12 | 13 | The licenses for most software and other practical works are designed 14 | to take away your freedom to share and change the works. By contrast, 15 | the GNU General Public License is intended to guarantee your freedom to 16 | share and change all versions of a program--to make sure it remains free 17 | software for all its users. We, the Free Software Foundation, use the 18 | GNU General Public License for most of our software; it applies also to 19 | any other work released this way by its authors. You can apply it to 20 | your programs, too. 21 | 22 | When we speak of free software, we are referring to freedom, not 23 | price. Our General Public Licenses are designed to make sure that you 24 | have the freedom to distribute copies of free software (and charge for 25 | them if you wish), that you receive source code or can get it if you 26 | want it, that you can change the software or use pieces of it in new 27 | free programs, and that you know you can do these things. 28 | 29 | To protect your rights, we need to prevent others from denying you 30 | these rights or asking you to surrender the rights. Therefore, you have 31 | certain responsibilities if you distribute copies of the software, or if 32 | you modify it: responsibilities to respect the freedom of others. 33 | 34 | For example, if you distribute copies of such a program, whether 35 | gratis or for a fee, you must pass on to the recipients the same 36 | freedoms that you received. You must make sure that they, too, receive 37 | or can get the source code. And you must show them these terms so they 38 | know their rights. 39 | 40 | Developers that use the GNU GPL protect your rights with two steps: 41 | (1) assert copyright on the software, and (2) offer you this License 42 | giving you legal permission to copy, distribute and/or modify it. 43 | 44 | For the developers' and authors' protection, the GPL clearly explains 45 | that there is no warranty for this free software. For both users' and 46 | authors' sake, the GPL requires that modified versions be marked as 47 | changed, so that their problems will not be attributed erroneously to 48 | authors of previous versions. 49 | 50 | Some devices are designed to deny users access to install or run 51 | modified versions of the software inside them, although the manufacturer 52 | can do so. This is fundamentally incompatible with the aim of 53 | protecting users' freedom to change the software. The systematic 54 | pattern of such abuse occurs in the area of products for individuals to 55 | use, which is precisely where it is most unacceptable. Therefore, we 56 | have designed this version of the GPL to prohibit the practice for those 57 | products. If such problems arise substantially in other domains, we 58 | stand ready to extend this provision to those domains in future versions 59 | of the GPL, as needed to protect the freedom of users. 60 | 61 | Finally, every program is threatened constantly by software patents. 62 | States should not allow patents to restrict development and use of 63 | software on general-purpose computers, but in those that do, we wish to 64 | avoid the special danger that patents applied to a free program could 65 | make it effectively proprietary. To prevent this, the GPL assures that 66 | patents cannot be used to render the program non-free. 67 | 68 | The precise terms and conditions for copying, distribution and 69 | modification follow. 70 | 71 | TERMS AND CONDITIONS 72 | 73 | 0. Definitions. 74 | 75 | "This License" refers to version 3 of the GNU General Public License. 76 | 77 | "Copyright" also means copyright-like laws that apply to other kinds of 78 | works, such as semiconductor masks. 79 | 80 | "The Program" refers to any copyrightable work licensed under this 81 | License. Each licensee is addressed as "you". "Licensees" and 82 | "recipients" may be individuals or organizations. 83 | 84 | To "modify" a work means to copy from or adapt all or part of the work 85 | in a fashion requiring copyright permission, other than the making of an 86 | exact copy. The resulting work is called a "modified version" of the 87 | earlier work or a work "based on" the earlier work. 88 | 89 | A "covered work" means either the unmodified Program or a work based 90 | on the Program. 91 | 92 | To "propagate" a work means to do anything with it that, without 93 | permission, would make you directly or secondarily liable for 94 | infringement under applicable copyright law, except executing it on a 95 | computer or modifying a private copy. Propagation includes copying, 96 | distribution (with or without modification), making available to the 97 | public, and in some countries other activities as well. 98 | 99 | To "convey" a work means any kind of propagation that enables other 100 | parties to make or receive copies. Mere interaction with a user through 101 | a computer network, with no transfer of a copy, is not conveying. 102 | 103 | An interactive user interface displays "Appropriate Legal Notices" 104 | to the extent that it includes a convenient and prominently visible 105 | feature that (1) displays an appropriate copyright notice, and (2) 106 | tells the user that there is no warranty for the work (except to the 107 | extent that warranties are provided), that licensees may convey the 108 | work under this License, and how to view a copy of this License. If 109 | the interface presents a list of user commands or options, such as a 110 | menu, a prominent item in the list meets this criterion. 111 | 112 | 1. Source Code. 113 | 114 | The "source code" for a work means the preferred form of the work 115 | for making modifications to it. "Object code" means any non-source 116 | form of a work. 117 | 118 | A "Standard Interface" means an interface that either is an official 119 | standard defined by a recognized standards body, or, in the case of 120 | interfaces specified for a particular programming language, one that 121 | is widely used among developers working in that language. 122 | 123 | The "System Libraries" of an executable work include anything, other 124 | than the work as a whole, that (a) is included in the normal form of 125 | packaging a Major Component, but which is not part of that Major 126 | Component, and (b) serves only to enable use of the work with that 127 | Major Component, or to implement a Standard Interface for which an 128 | implementation is available to the public in source code form. A 129 | "Major Component", in this context, means a major essential component 130 | (kernel, window system, and so on) of the specific operating system 131 | (if any) on which the executable work runs, or a compiler used to 132 | produce the work, or an object code interpreter used to run it. 133 | 134 | The "Corresponding Source" for a work in object code form means all 135 | the source code needed to generate, install, and (for an executable 136 | work) run the object code and to modify the work, including scripts to 137 | control those activities. However, it does not include the work's 138 | System Libraries, or general-purpose tools or generally available free 139 | programs which are used unmodified in performing those activities but 140 | which are not part of the work. For example, Corresponding Source 141 | includes interface definition files associated with source files for 142 | the work, and the source code for shared libraries and dynamically 143 | linked subprograms that the work is specifically designed to require, 144 | such as by intimate data communication or control flow between those 145 | subprograms and other parts of the work. 146 | 147 | The Corresponding Source need not include anything that users 148 | can regenerate automatically from other parts of the Corresponding 149 | Source. 150 | 151 | The Corresponding Source for a work in source code form is that 152 | same work. 153 | 154 | 2. Basic Permissions. 155 | 156 | All rights granted under this License are granted for the term of 157 | copyright on the Program, and are irrevocable provided the stated 158 | conditions are met. This License explicitly affirms your unlimited 159 | permission to run the unmodified Program. The output from running a 160 | covered work is covered by this License only if the output, given its 161 | content, constitutes a covered work. This License acknowledges your 162 | rights of fair use or other equivalent, as provided by copyright law. 163 | 164 | You may make, run and propagate covered works that you do not 165 | convey, without conditions so long as your license otherwise remains 166 | in force. You may convey covered works to others for the sole purpose 167 | of having them make modifications exclusively for you, or provide you 168 | with facilities for running those works, provided that you comply with 169 | the terms of this License in conveying all material for which you do 170 | not control copyright. Those thus making or running the covered works 171 | for you must do so exclusively on your behalf, under your direction 172 | and control, on terms that prohibit them from making any copies of 173 | your copyrighted material outside their relationship with you. 174 | 175 | Conveying under any other circumstances is permitted solely under 176 | the conditions stated below. Sublicensing is not allowed; section 10 177 | makes it unnecessary. 178 | 179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 180 | 181 | No covered work shall be deemed part of an effective technological 182 | measure under any applicable law fulfilling obligations under article 183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 184 | similar laws prohibiting or restricting circumvention of such 185 | measures. 186 | 187 | When you convey a covered work, you waive any legal power to forbid 188 | circumvention of technological measures to the extent such circumvention 189 | is effected by exercising rights under this License with respect to 190 | the covered work, and you disclaim any intention to limit operation or 191 | modification of the work as a means of enforcing, against the work's 192 | users, your or third parties' legal rights to forbid circumvention of 193 | technological measures. 194 | 195 | 4. Conveying Verbatim Copies. 196 | 197 | You may convey verbatim copies of the Program's source code as you 198 | receive it, in any medium, provided that you conspicuously and 199 | appropriately publish on each copy an appropriate copyright notice; 200 | keep intact all notices stating that this License and any 201 | non-permissive terms added in accord with section 7 apply to the code; 202 | keep intact all notices of the absence of any warranty; and give all 203 | recipients a copy of this License along with the Program. 204 | 205 | You may charge any price or no price for each copy that you convey, 206 | and you may offer support or warranty protection for a fee. 207 | 208 | 5. Conveying Modified Source Versions. 209 | 210 | You may convey a work based on the Program, or the modifications to 211 | produce it from the Program, in the form of source code under the 212 | terms of section 4, provided that you also meet all of these conditions: 213 | 214 | a) The work must carry prominent notices stating that you modified 215 | it, and giving a relevant date. 216 | 217 | b) The work must carry prominent notices stating that it is 218 | released under this License and any conditions added under section 219 | 7. This requirement modifies the requirement in section 4 to 220 | "keep intact all notices". 221 | 222 | c) You must license the entire work, as a whole, under this 223 | License to anyone who comes into possession of a copy. This 224 | License will therefore apply, along with any applicable section 7 225 | additional terms, to the whole of the work, and all its parts, 226 | regardless of how they are packaged. This License gives no 227 | permission to license the work in any other way, but it does not 228 | invalidate such permission if you have separately received it. 229 | 230 | d) If the work has interactive user interfaces, each must display 231 | Appropriate Legal Notices; however, if the Program has interactive 232 | interfaces that do not display Appropriate Legal Notices, your 233 | work need not make them do so. 234 | 235 | A compilation of a covered work with other separate and independent 236 | works, which are not by their nature extensions of the covered work, 237 | and which are not combined with it such as to form a larger program, 238 | in or on a volume of a storage or distribution medium, is called an 239 | "aggregate" if the compilation and its resulting copyright are not 240 | used to limit the access or legal rights of the compilation's users 241 | beyond what the individual works permit. Inclusion of a covered work 242 | in an aggregate does not cause this License to apply to the other 243 | parts of the aggregate. 244 | 245 | 6. Conveying Non-Source Forms. 246 | 247 | You may convey a covered work in object code form under the terms 248 | of sections 4 and 5, provided that you also convey the 249 | machine-readable Corresponding Source under the terms of this License, 250 | in one of these ways: 251 | 252 | a) Convey the object code in, or embodied in, a physical product 253 | (including a physical distribution medium), accompanied by the 254 | Corresponding Source fixed on a durable physical medium 255 | customarily used for software interchange. 256 | 257 | b) Convey the object code in, or embodied in, a physical product 258 | (including a physical distribution medium), accompanied by a 259 | written offer, valid for at least three years and valid for as 260 | long as you offer spare parts or customer support for that product 261 | model, to give anyone who possesses the object code either (1) a 262 | copy of the Corresponding Source for all the software in the 263 | product that is covered by this License, on a durable physical 264 | medium customarily used for software interchange, for a price no 265 | more than your reasonable cost of physically performing this 266 | conveying of source, or (2) access to copy the 267 | Corresponding Source from a network server at no charge. 268 | 269 | c) Convey individual copies of the object code with a copy of the 270 | written offer to provide the Corresponding Source. This 271 | alternative is allowed only occasionally and noncommercially, and 272 | only if you received the object code with such an offer, in accord 273 | with subsection 6b. 274 | 275 | d) Convey the object code by offering access from a designated 276 | place (gratis or for a charge), and offer equivalent access to the 277 | Corresponding Source in the same way through the same place at no 278 | further charge. You need not require recipients to copy the 279 | Corresponding Source along with the object code. If the place to 280 | copy the object code is a network server, the Corresponding Source 281 | may be on a different server (operated by you or a third party) 282 | that supports equivalent copying facilities, provided you maintain 283 | clear directions next to the object code saying where to find the 284 | Corresponding Source. Regardless of what server hosts the 285 | Corresponding Source, you remain obligated to ensure that it is 286 | available for as long as needed to satisfy these requirements. 287 | 288 | e) Convey the object code using peer-to-peer transmission, provided 289 | you inform other peers where the object code and Corresponding 290 | Source of the work are being offered to the general public at no 291 | charge under subsection 6d. 292 | 293 | A separable portion of the object code, whose source code is excluded 294 | from the Corresponding Source as a System Library, need not be 295 | included in conveying the object code work. 296 | 297 | A "User Product" is either (1) a "consumer product", which means any 298 | tangible personal property which is normally used for personal, family, 299 | or household purposes, or (2) anything designed or sold for incorporation 300 | into a dwelling. In determining whether a product is a consumer product, 301 | doubtful cases shall be resolved in favor of coverage. For a particular 302 | product received by a particular user, "normally used" refers to a 303 | typical or common use of that class of product, regardless of the status 304 | of the particular user or of the way in which the particular user 305 | actually uses, or expects or is expected to use, the product. A product 306 | is a consumer product regardless of whether the product has substantial 307 | commercial, industrial or non-consumer uses, unless such uses represent 308 | the only significant mode of use of the product. 309 | 310 | "Installation Information" for a User Product means any methods, 311 | procedures, authorization keys, or other information required to install 312 | and execute modified versions of a covered work in that User Product from 313 | a modified version of its Corresponding Source. The information must 314 | suffice to ensure that the continued functioning of the modified object 315 | code is in no case prevented or interfered with solely because 316 | modification has been made. 317 | 318 | If you convey an object code work under this section in, or with, or 319 | specifically for use in, a User Product, and the conveying occurs as 320 | part of a transaction in which the right of possession and use of the 321 | User Product is transferred to the recipient in perpetuity or for a 322 | fixed term (regardless of how the transaction is characterized), the 323 | Corresponding Source conveyed under this section must be accompanied 324 | by the Installation Information. But this requirement does not apply 325 | if neither you nor any third party retains the ability to install 326 | modified object code on the User Product (for example, the work has 327 | been installed in ROM). 328 | 329 | The requirement to provide Installation Information does not include a 330 | requirement to continue to provide support service, warranty, or updates 331 | for a work that has been modified or installed by the recipient, or for 332 | the User Product in which it has been modified or installed. Access to a 333 | network may be denied when the modification itself materially and 334 | adversely affects the operation of the network or violates the rules and 335 | protocols for communication across the network. 336 | 337 | Corresponding Source conveyed, and Installation Information provided, 338 | in accord with this section must be in a format that is publicly 339 | documented (and with an implementation available to the public in 340 | source code form), and must require no special password or key for 341 | unpacking, reading or copying. 342 | 343 | 7. Additional Terms. 344 | 345 | "Additional permissions" are terms that supplement the terms of this 346 | License by making exceptions from one or more of its conditions. 347 | Additional permissions that are applicable to the entire Program shall 348 | be treated as though they were included in this License, to the extent 349 | that they are valid under applicable law. If additional permissions 350 | apply only to part of the Program, that part may be used separately 351 | under those permissions, but the entire Program remains governed by 352 | this License without regard to the additional permissions. 353 | 354 | When you convey a copy of a covered work, you may at your option 355 | remove any additional permissions from that copy, or from any part of 356 | it. (Additional permissions may be written to require their own 357 | removal in certain cases when you modify the work.) You may place 358 | additional permissions on material, added by you to a covered work, 359 | for which you have or can give appropriate copyright permission. 360 | 361 | Notwithstanding any other provision of this License, for material you 362 | add to a covered work, you may (if authorized by the copyright holders of 363 | that material) supplement the terms of this License with terms: 364 | 365 | a) Disclaiming warranty or limiting liability differently from the 366 | terms of sections 15 and 16 of this License; or 367 | 368 | b) Requiring preservation of specified reasonable legal notices or 369 | author attributions in that material or in the Appropriate Legal 370 | Notices displayed by works containing it; or 371 | 372 | c) Prohibiting misrepresentation of the origin of that material, or 373 | requiring that modified versions of such material be marked in 374 | reasonable ways as different from the original version; or 375 | 376 | d) Limiting the use for publicity purposes of names of licensors or 377 | authors of the material; or 378 | 379 | e) Declining to grant rights under trademark law for use of some 380 | trade names, trademarks, or service marks; or 381 | 382 | f) Requiring indemnification of licensors and authors of that 383 | material by anyone who conveys the material (or modified versions of 384 | it) with contractual assumptions of liability to the recipient, for 385 | any liability that these contractual assumptions directly impose on 386 | those licensors and authors. 387 | 388 | All other non-permissive additional terms are considered "further 389 | restrictions" within the meaning of section 10. If the Program as you 390 | received it, or any part of it, contains a notice stating that it is 391 | governed by this License along with a term that is a further 392 | restriction, you may remove that term. If a license document contains 393 | a further restriction but permits relicensing or conveying under this 394 | License, you may add to a covered work material governed by the terms 395 | of that license document, provided that the further restriction does 396 | not survive such relicensing or conveying. 397 | 398 | If you add terms to a covered work in accord with this section, you 399 | must place, in the relevant source files, a statement of the 400 | additional terms that apply to those files, or a notice indicating 401 | where to find the applicable terms. 402 | 403 | Additional terms, permissive or non-permissive, may be stated in the 404 | form of a separately written license, or stated as exceptions; 405 | the above requirements apply either way. 406 | 407 | 8. Termination. 408 | 409 | You may not propagate or modify a covered work except as expressly 410 | provided under this License. Any attempt otherwise to propagate or 411 | modify it is void, and will automatically terminate your rights under 412 | this License (including any patent licenses granted under the third 413 | paragraph of section 11). 414 | 415 | However, if you cease all violation of this License, then your 416 | license from a particular copyright holder is reinstated (a) 417 | provisionally, unless and until the copyright holder explicitly and 418 | finally terminates your license, and (b) permanently, if the copyright 419 | holder fails to notify you of the violation by some reasonable means 420 | prior to 60 days after the cessation. 421 | 422 | Moreover, your license from a particular copyright holder is 423 | reinstated permanently if the copyright holder notifies you of the 424 | violation by some reasonable means, this is the first time you have 425 | received notice of violation of this License (for any work) from that 426 | copyright holder, and you cure the violation prior to 30 days after 427 | your receipt of the notice. 428 | 429 | Termination of your rights under this section does not terminate the 430 | licenses of parties who have received copies or rights from you under 431 | this License. If your rights have been terminated and not permanently 432 | reinstated, you do not qualify to receive new licenses for the same 433 | material under section 10. 434 | 435 | 9. Acceptance Not Required for Having Copies. 436 | 437 | You are not required to accept this License in order to receive or 438 | run a copy of the Program. Ancillary propagation of a covered work 439 | occurring solely as a consequence of using peer-to-peer transmission 440 | to receive a copy likewise does not require acceptance. However, 441 | nothing other than this License grants you permission to propagate or 442 | modify any covered work. These actions infringe copyright if you do 443 | not accept this License. Therefore, by modifying or propagating a 444 | covered work, you indicate your acceptance of this License to do so. 445 | 446 | 10. Automatic Licensing of Downstream Recipients. 447 | 448 | Each time you convey a covered work, the recipient automatically 449 | receives a license from the original licensors, to run, modify and 450 | propagate that work, subject to this License. You are not responsible 451 | for enforcing compliance by third parties with this License. 452 | 453 | An "entity transaction" is a transaction transferring control of an 454 | organization, or substantially all assets of one, or subdividing an 455 | organization, or merging organizations. If propagation of a covered 456 | work results from an entity transaction, each party to that 457 | transaction who receives a copy of the work also receives whatever 458 | licenses to the work the party's predecessor in interest had or could 459 | give under the previous paragraph, plus a right to possession of the 460 | Corresponding Source of the work from the predecessor in interest, if 461 | the predecessor has it or can get it with reasonable efforts. 462 | 463 | You may not impose any further restrictions on the exercise of the 464 | rights granted or affirmed under this License. For example, you may 465 | not impose a license fee, royalty, or other charge for exercise of 466 | rights granted under this License, and you may not initiate litigation 467 | (including a cross-claim or counterclaim in a lawsuit) alleging that 468 | any patent claim is infringed by making, using, selling, offering for 469 | sale, or importing the Program or any portion of it. 470 | 471 | 11. Patents. 472 | 473 | A "contributor" is a copyright holder who authorizes use under this 474 | License of the Program or a work on which the Program is based. The 475 | work thus licensed is called the contributor's "contributor version". 476 | 477 | A contributor's "essential patent claims" are all patent claims 478 | owned or controlled by the contributor, whether already acquired or 479 | hereafter acquired, that would be infringed by some manner, permitted 480 | by this License, of making, using, or selling its contributor version, 481 | but do not include claims that would be infringed only as a 482 | consequence of further modification of the contributor version. For 483 | purposes of this definition, "control" includes the right to grant 484 | patent sublicenses in a manner consistent with the requirements of 485 | this License. 486 | 487 | Each contributor grants you a non-exclusive, worldwide, royalty-free 488 | patent license under the contributor's essential patent claims, to 489 | make, use, sell, offer for sale, import and otherwise run, modify and 490 | propagate the contents of its contributor version. 491 | 492 | In the following three paragraphs, a "patent license" is any express 493 | agreement or commitment, however denominated, not to enforce a patent 494 | (such as an express permission to practice a patent or covenant not to 495 | sue for patent infringement). To "grant" such a patent license to a 496 | party means to make such an agreement or commitment not to enforce a 497 | patent against the party. 498 | 499 | If you convey a covered work, knowingly relying on a patent license, 500 | and the Corresponding Source of the work is not available for anyone 501 | to copy, free of charge and under the terms of this License, through a 502 | publicly available network server or other readily accessible means, 503 | then you must either (1) cause the Corresponding Source to be so 504 | available, or (2) arrange to deprive yourself of the benefit of the 505 | patent license for this particular work, or (3) arrange, in a manner 506 | consistent with the requirements of this License, to extend the patent 507 | license to downstream recipients. "Knowingly relying" means you have 508 | actual knowledge that, but for the patent license, your conveying the 509 | covered work in a country, or your recipient's use of the covered work 510 | in a country, would infringe one or more identifiable patents in that 511 | country that you have reason to believe are valid. 512 | 513 | If, pursuant to or in connection with a single transaction or 514 | arrangement, you convey, or propagate by procuring conveyance of, a 515 | covered work, and grant a patent license to some of the parties 516 | receiving the covered work authorizing them to use, propagate, modify 517 | or convey a specific copy of the covered work, then the patent license 518 | you grant is automatically extended to all recipients of the covered 519 | work and works based on it. 520 | 521 | A patent license is "discriminatory" if it does not include within 522 | the scope of its coverage, prohibits the exercise of, or is 523 | conditioned on the non-exercise of one or more of the rights that are 524 | specifically granted under this License. You may not convey a covered 525 | work if you are a party to an arrangement with a third party that is 526 | in the business of distributing software, under which you make payment 527 | to the third party based on the extent of your activity of conveying 528 | the work, and under which the third party grants, to any of the 529 | parties who would receive the covered work from you, a discriminatory 530 | patent license (a) in connection with copies of the covered work 531 | conveyed by you (or copies made from those copies), or (b) primarily 532 | for and in connection with specific products or compilations that 533 | contain the covered work, unless you entered into that arrangement, 534 | or that patent license was granted, prior to 28 March 2007. 535 | 536 | Nothing in this License shall be construed as excluding or limiting 537 | any implied license or other defenses to infringement that may 538 | otherwise be available to you under applicable patent law. 539 | 540 | 12. No Surrender of Others' Freedom. 541 | 542 | If conditions are imposed on you (whether by court order, agreement or 543 | otherwise) that contradict the conditions of this License, they do not 544 | excuse you from the conditions of this License. If you cannot convey a 545 | covered work so as to satisfy simultaneously your obligations under this 546 | License and any other pertinent obligations, then as a consequence you may 547 | not convey it at all. For example, if you agree to terms that obligate you 548 | to collect a royalty for further conveying from those to whom you convey 549 | the Program, the only way you could satisfy both those terms and this 550 | License would be to refrain entirely from conveying the Program. 551 | 552 | 13. Use with the GNU Affero General Public License. 553 | 554 | Notwithstanding any other provision of this License, you have 555 | permission to link or combine any covered work with a work licensed 556 | under version 3 of the GNU Affero General Public License into a single 557 | combined work, and to convey the resulting work. The terms of this 558 | License will continue to apply to the part which is the covered work, 559 | but the special requirements of the GNU Affero General Public License, 560 | section 13, concerning interaction through a network will apply to the 561 | combination as such. 562 | 563 | 14. Revised Versions of this License. 564 | 565 | The Free Software Foundation may publish revised and/or new versions of 566 | the GNU General Public License from time to time. Such new versions will 567 | be similar in spirit to the present version, but may differ in detail to 568 | address new problems or concerns. 569 | 570 | Each version is given a distinguishing version number. If the 571 | Program specifies that a certain numbered version of the GNU General 572 | Public License "or any later version" applies to it, you have the 573 | option of following the terms and conditions either of that numbered 574 | version or of any later version published by the Free Software 575 | Foundation. If the Program does not specify a version number of the 576 | GNU General Public License, you may choose any version ever published 577 | by the Free Software Foundation. 578 | 579 | If the Program specifies that a proxy can decide which future 580 | versions of the GNU General Public License can be used, that proxy's 581 | public statement of acceptance of a version permanently authorizes you 582 | to choose that version for the Program. 583 | 584 | Later license versions may give you additional or different 585 | permissions. However, no additional obligations are imposed on any 586 | author or copyright holder as a result of your choosing to follow a 587 | later version. 588 | 589 | 15. Disclaimer of Warranty. 590 | 591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 599 | 600 | 16. Limitation of Liability. 601 | 602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 610 | SUCH DAMAGES. 611 | 612 | 17. Interpretation of Sections 15 and 16. 613 | 614 | If the disclaimer of warranty and limitation of liability provided 615 | above cannot be given local legal effect according to their terms, 616 | reviewing courts shall apply local law that most closely approximates 617 | an absolute waiver of all civil liability in connection with the 618 | Program, unless a warranty or assumption of liability accompanies a 619 | copy of the Program in return for a fee. 620 | 621 | END OF TERMS AND CONDITIONS 622 | 623 | How to Apply These Terms to Your New Programs 624 | 625 | If you develop a new program, and you want it to be of the greatest 626 | possible use to the public, the best way to achieve this is to make it 627 | free software which everyone can redistribute and change under these terms. 628 | 629 | To do so, attach the following notices to the program. It is safest 630 | to attach them to the start of each source file to most effectively 631 | state the exclusion of warranty; and each file should have at least 632 | the "copyright" line and a pointer to where the full notice is found. 633 | 634 | 635 | Copyright (C) 636 | 637 | This program is free software: you can redistribute it and/or modify 638 | it under the terms of the GNU General Public License as published by 639 | the Free Software Foundation, either version 3 of the License, or 640 | (at your option) any later version. 641 | 642 | This program is distributed in the hope that it will be useful, 643 | but WITHOUT ANY WARRANTY; without even the implied warranty of 644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 645 | GNU General Public License for more details. 646 | 647 | You should have received a copy of the GNU General Public License 648 | along with this program. If not, see . 649 | 650 | Also add information on how to contact you by electronic and paper mail. 651 | 652 | If the program does terminal interaction, make it output a short 653 | notice like this when it starts in an interactive mode: 654 | 655 | Copyright (C) 656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 657 | This is free software, and you are welcome to redistribute it 658 | under certain conditions; type `show c' for details. 659 | 660 | The hypothetical commands `show w' and `show c' should show the appropriate 661 | parts of the General Public License. Of course, your program's commands 662 | might be different; for a GUI interface, you would use an "about box". 663 | 664 | You should also get your employer (if you work as a programmer) or school, 665 | if any, to sign a "copyright disclaimer" for the program, if necessary. 666 | For more information on this, and how to apply and follow the GNU GPL, see 667 | . 668 | 669 | The GNU General Public License does not permit incorporating your program 670 | into proprietary programs. If your program is a subroutine library, you 671 | may consider it more useful to permit linking proprietary applications with 672 | the library. If this is what you want to do, use the GNU Lesser General 673 | Public License instead of this License. But first, please read 674 | . 675 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | metamutator: a meta-mutation tool for Java 2 | =========== 3 | 4 | [![Build Status](https://travis-ci.org/SpoonLabs/metamutator.svg?branch=master)](https://travis-ci.org/SpoonLabs/metamutator) 5 | 6 | metamutator takes as input a program and produces a metaprogram which contains all possible mutations inserted at compile-time according to a mutant schemata. It is a Java implementation of ["Mutation analysis using mutant schemata"](http://cs.gmu.edu/~offutt/rsrch/papers/schema.pdf). 7 | However, the mutations are all deactivated by default, meaning that the metaprogram behaves as the original one. 8 | Metamutants can be activated and deactivated one by one at runtime. 9 | 10 | 11 | Mutation operators 12 | ------------------ 13 | 14 | * Logical comparison (switch between ">", ">=", "!=", etc) (`LogicalExpressionMetaMutator`). 15 | * Breaks the loops (no iteration, at 3 iterations, at 100 iterations) (`LoopExpressionMetaMutator`) 16 | * Adds unary operators to numeric values (absolute value, minus, increment (++), decrement (--)) (`NumericVariableMetaMutator`) 17 | * Sets variables to null at their declaration (`VariabletoNullMetaMutator`) 18 | * Replaces integer constants by 0, INT_MAX (`IntegerConstantReplacementMetaMutator`) 19 | * Metamutates return statements that returns Boolean (`ReturnReplacementOperatorMetaMutator`) 20 | * Skips statements (statement deletion operator) (`StatementDeletionMetaMutator`) 21 | 22 | Usage 23 | ------ 24 | 25 | Let's assume your project is called `foo` and contains two folders `src/main/java` and `src/test/java` with a test class `PgmTest`. 26 | 27 | Install metamutator 28 | 29 | git clone https://github.com/SpoonLabs/metamutator.git 30 | cd metamutator 31 | mvn package 32 | # now we have target/metamutator-*-jar-with-dependencies.jar 33 | 34 | 35 | Create the metaprogram 36 | 37 | java -jar target/metamutator-*-jar-with-dependencies.jar -i src/main/java -p metamutator.LogicalExpressionMetaMutator -o spooned 38 | 39 | Compile the metaprogram 40 | 41 | javac `find spooned -name "*.java"` 42 | 43 | Run the test class (with the metaprogram in the classpath and not the original program) 44 | 45 | MutantSearchSpaceExplorator.runMetaProgramWith(PgmTest.class) 46 | 47 | 48 | Credits 49 | ------- 50 | 51 | Based on awesome code by Carlos Fau and Alejandro Russel () 52 | 53 | Great contributions from University of Lille's students enrolled in IAGL 2015-2016. 54 | 55 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | fr.inria.spirals 5 | metamutator 6 | 0.1-SNAPSHOT 7 | 8 | 9 | junit 10 | junit 11 | 4.12 12 | 13 | 14 | fr.inria.gforge.spoon 15 | spoon-core 16 | 7.2.0-SNAPSHOT 17 | 18 | 19 | com.google.collections 20 | google-collections 21 | 1.0 22 | 23 | 24 | org.beanshell 25 | bsh 26 | 2.0b5 27 | 28 | 29 | commons-lang 30 | commons-lang 31 | 2.6 32 | 33 | 34 | 35 | 36 | 37 | org.apache.maven.plugins 38 | maven-compiler-plugin 39 | 3.1 40 | 41 | 1.8 42 | 1.8 43 | 1.8 44 | 1.8 45 | 46 | 47 | 48 | org.apache.maven.plugins 49 | maven-surefire-plugin 50 | 2.16 51 | 52 | 54 | false 55 | 56 | resources/footest/FooTest.java 57 | resources/search_replay_test/SearchReplayTestClass.java 58 | resources/search_replay_test/SearchReplayTestClassBis.java 59 | 60 | 61 | 62 | 63 | maven-assembly-plugin 64 | 65 | 66 | jar-with-dependencies 67 | 68 | 69 | 70 | 71 | make-assembly 72 | 73 | package 74 | 75 | 76 | single 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | gforge.inria.fr-snapshot 86 | https://repository.ow2.org/nexus/content/repositories/snapshots/ 87 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /src/main/java/metamutator/ArithmeticOperatorMetaMutator.java: -------------------------------------------------------------------------------- 1 | package metamutator; 2 | 3 | import java.util.EnumSet; 4 | import java.util.Set; 5 | 6 | import com.google.common.collect.Sets; 7 | 8 | import spoon.processing.AbstractProcessor; 9 | import spoon.reflect.code.BinaryOperatorKind; 10 | import spoon.reflect.code.CtBinaryOperator; 11 | import spoon.reflect.code.CtCodeSnippetExpression; 12 | import spoon.reflect.code.CtExpression; 13 | import spoon.reflect.declaration.CtAnonymousExecutable; 14 | import spoon.reflect.declaration.CtClass; 15 | import spoon.reflect.declaration.CtConstructor; 16 | import spoon.reflect.declaration.CtElement; 17 | import spoon.reflect.declaration.CtField; 18 | 19 | /** 20 | * inserts a mutation hotspot for each arithmetic operator 21 | */ 22 | public class ArithmeticOperatorMetaMutator extends 23 | AbstractProcessor> { 24 | 25 | public static final String PREFIX = "_arithmeticOperatorHotSpot"; 26 | private static int index = 0; 27 | private static final EnumSet ARITHMETIC_OPERATORS = EnumSet 28 | .of(BinaryOperatorKind.PLUS, BinaryOperatorKind.MINUS, BinaryOperatorKind.DIV, BinaryOperatorKind.MUL); 29 | private static final int procId = 7; 30 | 31 | private Set hostSpots = Sets.newHashSet(); 32 | 33 | private String permutations(BinaryOperatorKind value) { 34 | switch(value) { 35 | case PLUS : return "+"; 36 | case MINUS : return "-"; 37 | case DIV : return "/"; 38 | case MUL : return "*"; 39 | default : return ""; 40 | } 41 | } 42 | 43 | 44 | @Override 45 | public boolean isToBeProcessed(CtBinaryOperator element) { 46 | try { 47 | Selector.getTopLevelClass(element); 48 | } catch (NullPointerException e) { 49 | return false; 50 | } 51 | 52 | // not in constructors because we use static fields 53 | if (element.getParent(CtConstructor.class) != null) { 54 | return false; 55 | } 56 | 57 | // not in fields declaration because we use static fields 58 | if (element.getParent(CtField.class) != null) { 59 | return false; 60 | } 61 | 62 | return (ARITHMETIC_OPERATORS.contains(element.getKind())) 63 | && (element.getParent(CtAnonymousExecutable.class) == null); 64 | } 65 | 66 | public void process(CtBinaryOperator binaryOperator) { 67 | BinaryOperatorKind kind = binaryOperator.getKind(); 68 | if(ARITHMETIC_OPERATORS.contains(kind)){ 69 | if(binaryOperator.getLeftHandOperand().getType() != null && binaryOperator.getRightHandOperand().getType() != null) 70 | if ( isNumber(binaryOperator.getLeftHandOperand()) 71 | && isNumber(binaryOperator.getRightHandOperand())) 72 | { 73 | mutateOperator(binaryOperator, ARITHMETIC_OPERATORS); 74 | } 75 | } 76 | } 77 | 78 | private boolean isNumber(CtExpression operand) { 79 | return operand.getType().getSimpleName().equals("int") 80 | || operand.getType().getSimpleName().equals("long") 81 | || operand.getType().getSimpleName().equals("byte") 82 | || operand.getType().getSimpleName().equals("char") 83 | || operand.getType().getSimpleName().equals("float") 84 | || operand.getType().getSimpleName().equals("double") 85 | || Number.class.isAssignableFrom(operand.getType().getActualClass()); 86 | } 87 | 88 | /** 89 | * Converts "a op b" bean op one of "-", "+", "*", "/" 90 | * ( (op(1, 0, "-") && (a - b)) 91 | * || (op(1, 1, "+") && (a + b)) 92 | * || (op(1, 2, "*") && (a * b)) 93 | * || (op(1, 3, "/") && (a / b)) 94 | * ) 95 | * 96 | * @param expression 97 | * @param operators 98 | */ 99 | private void mutateOperator(final CtBinaryOperator expression, EnumSet operators) { 100 | 101 | if (!operators.contains(expression.getKind())) { 102 | throw new IllegalArgumentException("not consistent"); 103 | } 104 | 105 | if (alreadyInHotsSpot(expression) 106 | || expression.toString().contains(".is(\"")) { 107 | System.out 108 | .println(String 109 | .format("Expression '%s' ignored because it is included in previous hot spot", 110 | expression)); 111 | return; 112 | } 113 | 114 | int thisIndex = ++index; 115 | BinaryOperatorKind originalKind = expression.getKind(); 116 | String originalExpression = expression.toString(); 117 | 118 | String newExpression = ""; 119 | 120 | int cpt = 0; 121 | BinaryOperatorKind tmp = null; 122 | for(BinaryOperatorKind op : ARITHMETIC_OPERATORS){ 123 | expression.setKind(op); 124 | newExpression += "(" + PREFIX + thisIndex + ".is(" + op.getClass().getCanonicalName()+"."+op.toString() + ")) ? (" + expression + ")"; 125 | newExpression += " : "; 126 | } 127 | 128 | newExpression += "(" + originalExpression + ")"; 129 | CtCodeSnippetExpression codeSnippet = getFactory().Core() 130 | .createCodeSnippetExpression(); 131 | codeSnippet.setValue('(' + newExpression + ')'); 132 | expression.replace(codeSnippet); 133 | expression.replace(expression); 134 | Selector.generateSelector(expression, originalKind, thisIndex, operators, PREFIX); 135 | System.out.println("nb mutants " +index); 136 | 137 | hostSpots.add(expression); 138 | } 139 | 140 | /** 141 | * Check if this sub expression was already inside an uppermost expression 142 | * that was processed has a hot spot. This version does not allowed 143 | * conflicting hot spots 144 | * 145 | * @param element 146 | * the current expression to test 147 | * @return true if this expression is descendant of an already processed 148 | * expression 149 | */ 150 | private boolean alreadyInHotsSpot(CtElement element) { 151 | CtElement parent = element.getParent(); 152 | while (!isTopLevel(parent) && parent != null) { 153 | if (hostSpots.contains(parent)) 154 | return true; 155 | 156 | parent = parent.getParent(); 157 | } 158 | 159 | return false; 160 | } 161 | 162 | private boolean isTopLevel(CtElement parent) { 163 | return parent instanceof CtClass && ((CtClass) parent).isTopLevel(); 164 | } 165 | } 166 | -------------------------------------------------------------------------------- /src/main/java/metamutator/Config.java: -------------------------------------------------------------------------------- 1 | package metamutator; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.BufferedWriter; 5 | import java.io.File; 6 | import java.io.FileInputStream; 7 | import java.io.FileNotFoundException; 8 | import java.io.FileWriter; 9 | import java.io.InputStreamReader; 10 | import java.io.PrintWriter; 11 | import java.util.HashMap; 12 | import java.util.Map; 13 | 14 | // Configuration class 15 | public class Config { 16 | 17 | //unique instance of configuration 18 | public static Config instance ; 19 | 20 | //Read and Maped config 21 | private Map config; 22 | 23 | //File Writer 24 | private PrintWriter outputFile ; 25 | 26 | //File Reader 27 | private BufferedReader inputFile; 28 | 29 | 30 | //Path to the config file 31 | private String file = "config.txt"; 32 | 33 | //to test if init as been done 34 | private Boolean init =false; 35 | 36 | //to test is the file was already read 37 | private Boolean read = false; 38 | 39 | //to test if the file was changed 40 | private Boolean changed = false; 41 | 42 | 43 | 44 | /**private constructor cause of singleton pattern 45 | * 46 | */ 47 | private Config(){ 48 | 49 | //Init the Map 50 | config = new HashMap(); 51 | } 52 | 53 | /** 54 | * init the writer and read of the config file 55 | * @return true if no ioexception , false else. 56 | */ 57 | private boolean initWriter(){ 58 | 59 | //lecture du fichier texte 60 | try{ 61 | 62 | 63 | 64 | //writer 65 | FileWriter fw = new FileWriter (file); 66 | BufferedWriter bw = new BufferedWriter (fw); 67 | outputFile= new PrintWriter (bw); 68 | 69 | 70 | 71 | } 72 | catch (Exception e){ 73 | System.err.println("Error in opening Config file"+e.toString()); 74 | return false; 75 | } 76 | 77 | // we init the writer so notice it 78 | init=true; 79 | return init; 80 | 81 | } 82 | 83 | /** 84 | * Clear the config file and write the paramter all, and set it to true 85 | * @return true if the init append well , false else. 86 | */ 87 | public boolean initConfig(){ 88 | 89 | 90 | // we init the writer to clear the file 91 | initWriter(); 92 | 93 | //in case of initWriterReader false , init 94 | return init; 95 | } 96 | /** 97 | * We initialize the reader. 98 | */ 99 | private void initReader(String filename){ 100 | //reader 101 | 102 | if(filename == null) 103 | filename = file; 104 | 105 | FileInputStream ips; 106 | config= new HashMap(); 107 | try { 108 | ips = new FileInputStream(filename); 109 | 110 | InputStreamReader isr = new InputStreamReader(ips); 111 | inputFile = new BufferedReader(isr); 112 | 113 | } catch (FileNotFoundException e) { 114 | System.out.println("Error when opening the config file : "+e); 115 | } 116 | } 117 | 118 | 119 | /** 120 | * We will read the config file, and set the config map. 121 | * @return true if everythings append well, false else. 122 | */ 123 | private boolean readConfig(String filename){ 124 | 125 | //if already read and no changed we already got the data , dont read it again ! 126 | if(read && !changed){ 127 | return true; 128 | } 129 | 130 | try{ 131 | //reader initialisation 132 | initReader(filename); 133 | 134 | String line =""; 135 | 136 | //The option of the selector 0 by default 137 | int selOption = 0; 138 | 139 | 140 | //Boucle de lecture du fichier 141 | while ((line=inputFile.readLine())!=null){ 142 | //System.out.println(line); 143 | 144 | //On envoie la ligne s'enregistrer vers la map 145 | selOption = mapLine(line,selOption); 146 | } 147 | 148 | inputFile.close(); 149 | 150 | // we read the file we remain it 151 | read =true; 152 | //So there is no changed since the last read, so make the world know 153 | changed = false; 154 | } 155 | catch (Exception e){ 156 | System.err.println("Error in reading Config file"+e.toString()); 157 | return false; 158 | } 159 | return true; 160 | } 161 | 162 | /** 163 | * We transform the line to map for the program. 164 | * @param line the reading line 165 | * @param selOption the nbOptionOf the current selector, -1 if one true already found. 166 | * @return selOption, for the next line. 167 | */ 168 | private int mapLine(String line, int selOption){ 169 | String tabSelector[]; 170 | //we split the line 171 | tabSelector = line.split(":"); 172 | 173 | //If we detect a new class, we built a new map 174 | if(tabSelector.length >= 1 && !config.containsKey(tabSelector[0])){ 175 | config.put(tabSelector[0], new HashMap<>()); 176 | } 177 | 178 | //If we detect a new selector, we stock it. Option 0 by default 179 | if(tabSelector.length >=2 && !config.get(tabSelector[0]).containsKey(tabSelector[1])){ 180 | config.get(tabSelector[0]).put(tabSelector[1], 0); 181 | 182 | selOption = 0; 183 | } 184 | 185 | //if we found the arg ture off one option for a selector, we put it on the map 186 | if(tabSelector.length == 4 && tabSelector[3].equals("true") && selOption > -1){ 187 | config.get(tabSelector[0]).put(tabSelector[1], selOption); 188 | selOption = -1; 189 | 190 | } 191 | else if(tabSelector.length == 4 && tabSelector[3].equals("false")){ 192 | selOption++; 193 | } 194 | 195 | return selOption; 196 | 197 | } 198 | 199 | /** 200 | * According the singleton parttern we got only one instance of Config (Cause of multiple access risk) 201 | * @return the instance of Config 202 | */ 203 | public static Config getInstance(){ 204 | 205 | if (instance == null){ 206 | //if instance is null, we create the instance 207 | instance = new Config(); 208 | } 209 | 210 | return instance; 211 | } 212 | 213 | /** 214 | * Same as getInstance, but we initialize the instance. 215 | * @return the initialized instance 216 | */ 217 | public static Config getInitInstance() { 218 | if (instance == null){ 219 | //if instance is null, we create the instance 220 | instance = new Config(); 221 | } 222 | // we initialize the instance 223 | instance.initConfig(); 224 | 225 | return instance; 226 | } 227 | /** 228 | * write the mutant to the config file and set it to false by default. 229 | * @param mutant 230 | * @return 231 | */ 232 | public boolean write(String mutant){ 233 | 234 | //we change the file so we said it 235 | changed = true; 236 | 237 | if(!init){ 238 | //in case of not init, we init the reader writer 239 | initWriter(); 240 | } 241 | //add mutant in config file 242 | try { 243 | 244 | outputFile.println (mutant); 245 | outputFile.flush(); 246 | String value = (mutant.split(":"))[mutant.split(":").length - 1]; 247 | //System.out.println("Inserting \""+mutant+"\" performed, default setting = "+value); 248 | 249 | } 250 | 251 | catch (Exception e){ 252 | System.err.println("Error when writing in config file "+e); 253 | return false; 254 | } 255 | return true; 256 | } 257 | 258 | /** 259 | * To get the config wraped in a map, the key is the id of the Selector and the value is a tab with the number of the mutation and the value of the activation TODO 260 | * @return the map which contain the config 261 | */ 262 | public Map getConfig(){ 263 | 264 | readConfig(null); 265 | 266 | return config; 267 | } 268 | 269 | /** 270 | * To get the config wraped in a map, filtered by file name. 271 | * @param selector the selector wished 272 | * @return the map which contain the config for the selector 273 | */ 274 | public Map getConfig(String filename){ 275 | 276 | readConfig(filename); 277 | 278 | return config; 279 | } 280 | 281 | /** 282 | * A little help to the JVM, and because the streamWriter must be closed. 283 | */ 284 | public void close(){ 285 | 286 | //We close the streams to make the jvm a pretty clean place 287 | outputFile.close(); 288 | 289 | //try destroy the object when we finally don't need him ever. 290 | try { 291 | instance.finalize(); 292 | } catch (Throwable e) { 293 | System.err.println("Garbage failed is job : "+e); 294 | } 295 | } 296 | 297 | } 298 | -------------------------------------------------------------------------------- /src/main/java/metamutator/ISelector.java: -------------------------------------------------------------------------------- 1 | package metamutator; 2 | 3 | /** represents a meta-mutation point, for which one can select alternatives (one alternative is a mutation) */ 4 | public interface ISelector { 5 | 6 | /** activate the i-th alternative (by convention #0 is the original one) */ 7 | public void choose(int option); 8 | 9 | /** stats that the selector is in class */ 10 | public Selector in(Class locationClass); 11 | 12 | /** sets the id */ 13 | public Selector id(String identifier); 14 | 15 | /** returns true is the currently chosen option is "variant" */ 16 | public boolean is(E variant); 17 | 18 | /** returns the number of alternatives */ 19 | public int getAlternativeCount(); 20 | 21 | /** returns the identifier (setted is #id(String)) */ 22 | public String getIdentifier(); 23 | 24 | /** returns the readable name of the current alternative */ 25 | public String getChosenAlternativeDescription(); 26 | 27 | /** returns the class where the selector is */ 28 | public Class getLocationClass(); 29 | 30 | /** returns the set of opssible alternatives */ 31 | public E[] getAlternatives(); 32 | 33 | } -------------------------------------------------------------------------------- /src/main/java/metamutator/IntegerConstantReplacementMetaMutator.java: -------------------------------------------------------------------------------- 1 | package metamutator; 2 | 3 | import java.util.EnumSet; 4 | 5 | import spoon.processing.AbstractProcessor; 6 | import spoon.reflect.code.CtCodeSnippetExpression; 7 | import spoon.reflect.code.CtExpression; 8 | import spoon.reflect.code.CtVariableRead; 9 | import spoon.reflect.declaration.ModifierKind; 10 | 11 | /** replaces integer constants by 0, INT_MAX, 12 | */ 13 | public class IntegerConstantReplacementMetaMutator extends AbstractProcessor> { 14 | 15 | public static final String PREFIX = "_constantOperatorMetaMutator"; 16 | private static final int procId = 5; 17 | 18 | public enum CONSTANT_REP { 19 | ZERO, 20 | INT_MAX, 21 | INT_MIN 22 | }; 23 | 24 | private static int thisIndex = 0; 25 | 26 | private static final EnumSet consRep = EnumSet. 27 | of(CONSTANT_REP.ZERO, CONSTANT_REP.INT_MAX, CONSTANT_REP.INT_MIN); 28 | 29 | @Override 30 | public boolean isToBeProcessed(CtVariableRead element){ 31 | try { 32 | if((element.getType().toString().contains("int"))&& 33 | (!(element.getVariable().getDeclaration().getDefaultExpression() == null))){ 34 | if(!(element.getVariable().getDeclaration().getDefaultExpression().toString().contains(PREFIX)) 35 | && (!element.getVariable().getDeclaration().getModifiers().contains(ModifierKind.STATIC))) 36 | return true; 37 | } 38 | } catch (Exception e) { 39 | 40 | } 41 | return false; 42 | } 43 | 44 | private String permutations(CONSTANT_REP value) { 45 | switch(value) { 46 | case ZERO : return "0"; 47 | case INT_MAX : return Integer.toString(Integer.MAX_VALUE - 1); 48 | case INT_MIN : return Integer.toString(Integer.MIN_VALUE + 1); 49 | default : return "";} 50 | } 51 | 52 | 53 | @Override 54 | public void process(CtVariableRead element) { 55 | 56 | thisIndex++; 57 | CtExpression valToChange= null; 58 | try { 59 | valToChange = element.getVariable().getDeclaration().getDefaultExpression(); 60 | String expression = "("; 61 | for(CONSTANT_REP c : consRep){ 62 | expression += PREFIX+thisIndex + ".is(" + c.getClass().getCanonicalName() +"."+c.toString()+ ")?( "+permutations(c)+" ):("; 63 | } 64 | expression += valToChange + "))))"; 65 | 66 | CtCodeSnippetExpression codeSnippet = getFactory().Core() 67 | .createCodeSnippetExpression(); 68 | codeSnippet.setValue(expression); 69 | 70 | try { 71 | valToChange.replace(codeSnippet); 72 | Selector.generateSelector(element, CONSTANT_REP.ZERO, thisIndex, consRep, PREFIX); 73 | 74 | } catch (Exception e) { 75 | System.err.println("Element not changed"); 76 | } 77 | 78 | } catch (Exception e) { 79 | 80 | } finally { 81 | System.out.println("nb mutants " +thisIndex); 82 | } 83 | 84 | } 85 | 86 | } -------------------------------------------------------------------------------- /src/main/java/metamutator/LogicalExpressionMetaMutator.java: -------------------------------------------------------------------------------- 1 | package metamutator; 2 | 3 | import com.google.common.collect.Sets; 4 | import spoon.processing.AbstractProcessor; 5 | import spoon.reflect.code.BinaryOperatorKind; 6 | import spoon.reflect.code.CtBinaryOperator; 7 | import spoon.reflect.code.CtCodeSnippetExpression; 8 | import spoon.reflect.code.CtExpression; 9 | import spoon.reflect.declaration.CtAnonymousExecutable; 10 | import spoon.reflect.declaration.CtClass; 11 | import spoon.reflect.declaration.CtConstructor; 12 | import spoon.reflect.declaration.CtElement; 13 | import spoon.reflect.declaration.CtField; 14 | import spoon.reflect.reference.CtTypeReference; 15 | 16 | import java.util.EnumSet; 17 | import java.util.Set; 18 | import java.util.stream.Collectors; 19 | 20 | /** 21 | * inserts a mutation hotspot for each binary operator 22 | */ 23 | public class LogicalExpressionMetaMutator extends 24 | AbstractProcessor> { 25 | 26 | public static final String PREFIX = "_binaryLogicalOperatorHotSpot"; 27 | private static int index = 0; 28 | private static final int procId = 1; 29 | 30 | private static final EnumSet LOGICAL_OPERATORS = EnumSet 31 | .of(BinaryOperatorKind.AND, BinaryOperatorKind.OR); 32 | private static final EnumSet COMPARISON_OPERATORS = EnumSet 33 | .of(BinaryOperatorKind.EQ, BinaryOperatorKind.GE, 34 | BinaryOperatorKind.GT, BinaryOperatorKind.LE, 35 | BinaryOperatorKind.LT, BinaryOperatorKind.NE); 36 | private static final EnumSet REDUCED_COMPARISON_OPERATORS = EnumSet 37 | .of(BinaryOperatorKind.EQ, BinaryOperatorKind.NE); 38 | 39 | private Set hostSpots = Sets.newHashSet(); 40 | 41 | @Override 42 | public boolean isToBeProcessed(CtBinaryOperator element) { 43 | // if (element.getParent(CtAnonymousExecutable.class)!=null) { 44 | // System.out.println(element.getParent(CtAnonymousExecutable.class)); 45 | // } 46 | 47 | try { 48 | Selector.getTopLevelClass(element); 49 | } catch (NullPointerException e) { 50 | return false; 51 | } 52 | 53 | // not in constructors because we use static fields 54 | if (element.getParent(CtConstructor.class) != null) { 55 | return false; 56 | } 57 | 58 | // not in fields declaration because we use static fields 59 | if (element.getParent(CtField.class) != null) { 60 | return false; 61 | } 62 | 63 | return (LOGICAL_OPERATORS.contains(element.getKind()) || COMPARISON_OPERATORS 64 | .contains(element.getKind())) 65 | && (element.getParent(CtAnonymousExecutable.class) == null) // not 66 | // in 67 | // static 68 | // block 69 | ; 70 | } 71 | 72 | public void process(CtBinaryOperator binaryOperator) { 73 | BinaryOperatorKind kind = binaryOperator.getKind(); 74 | 75 | if (LOGICAL_OPERATORS.contains(kind)) { 76 | mutateOperator(binaryOperator, LOGICAL_OPERATORS); 77 | } else if (COMPARISON_OPERATORS.contains(kind)) { 78 | if (isNumber(binaryOperator.getLeftHandOperand()) 79 | && isNumber(binaryOperator.getRightHandOperand())) 80 | { 81 | mutateOperator(binaryOperator, COMPARISON_OPERATORS); 82 | } 83 | else { 84 | EnumSet clone = REDUCED_COMPARISON_OPERATORS.clone(); 85 | clone.add(kind); 86 | mutateOperator(binaryOperator, clone); 87 | } 88 | } 89 | } 90 | 91 | private boolean isNumber(CtExpression operand) { 92 | 93 | if (operand.getType().toString().equals(CtTypeReference.NULL_TYPE_NAME)) 94 | return false; 95 | 96 | if (operand.toString().contains(".class")) 97 | return false; 98 | 99 | return operand.getType().getSimpleName().equals("int") 100 | || operand.getType().getSimpleName().equals("long") 101 | || operand.getType().getSimpleName().equals("byte") 102 | || operand.getType().getSimpleName().equals("char") 103 | || operand.getType().getSimpleName().equals("float") 104 | || operand.getType().getSimpleName().equals("double") 105 | || operand.getType().isSubtypeOf(getFactory().Type().createReference(Number.class)); 106 | } 107 | 108 | /** 109 | * Converts "a op b" bean op one of "<", "<=", "==", ">=", "!=" to: 110 | * ( (op(1, 0, "<") && (a < b)) 111 | * || (op(1, 1, "<=") && (a <= b)) 112 | * || (op(1, 2, "==") && (a == b)) 113 | * || (op(1, 3, ">=") && (a >= b)) 114 | * || (op(1, 4, ">") && (a > b)) 115 | * ) 116 | * */ 117 | private void mutateOperator(final CtBinaryOperator expression, EnumSet operators) { 118 | 119 | if (!operators.contains(expression.getKind())) { 120 | throw new IllegalArgumentException("not consistent "); 121 | } 122 | 123 | if (alreadyInHotsSpot(expression) 124 | || expression.toString().contains(".is(\"")) { 125 | System.out 126 | .println(String 127 | .format("Expression '%s' ignored because it is included in previous hot spot", 128 | expression)); 129 | return; 130 | } 131 | 132 | int thisIndex = ++index; 133 | 134 | BinaryOperatorKind originalKind = expression.getKind(); 135 | String newExpression = operators 136 | .stream() 137 | .map(kind -> { 138 | expression.setKind(kind); 139 | return String.format("("+ PREFIX + "%s.is(%s) && (%s))", 140 | thisIndex, kind.getDeclaringClass().getName()+"."+kind.name(), expression); 141 | }).collect(Collectors.joining(" || ")); 142 | 143 | CtCodeSnippetExpression codeSnippet = getFactory().Core() 144 | .createCodeSnippetExpression(); 145 | codeSnippet.setValue('(' + newExpression + ')'); 146 | 147 | expression.replace(codeSnippet); 148 | expression.replace(expression); 149 | Selector.generateSelector(expression, originalKind, thisIndex, operators, PREFIX); 150 | 151 | hostSpots.add(expression); 152 | 153 | } 154 | 155 | /** 156 | * Check if this sub expression was already inside an uppermost expression 157 | * that was processed has a hot spot. This version does not allowed 158 | * conflicting hot spots 159 | * 160 | * @param element 161 | * the current expression to test 162 | * @return true if this expression is descendant of an already processed 163 | * expression 164 | */ 165 | private boolean alreadyInHotsSpot(CtElement element) { 166 | CtElement parent = element.getParent(); 167 | while (!isTopLevel(parent) && parent != null) { 168 | if (hostSpots.contains(parent)) 169 | return true; 170 | 171 | parent = parent.getParent(); 172 | } 173 | 174 | return false; 175 | } 176 | 177 | private boolean isTopLevel(CtElement parent) { 178 | return parent instanceof CtClass && ((CtClass) parent).isTopLevel(); 179 | } 180 | } 181 | -------------------------------------------------------------------------------- /src/main/java/metamutator/LoopExpressionMetaMutator.java: -------------------------------------------------------------------------------- 1 | package metamutator; 2 | import spoon.reflect.visitor.Filter; 3 | import java.util.EnumSet; 4 | 5 | import spoon.processing.AbstractProcessor; 6 | 7 | import spoon.reflect.code.CtCodeSnippetStatement; 8 | import spoon.reflect.code.CtDo; 9 | import spoon.reflect.code.CtLoop; 10 | import spoon.reflect.code.CtVariableRead; 11 | import spoon.reflect.declaration.CtElement; 12 | import spoon.reflect.visitor.filter.ReturnOrThrowFilter; 13 | import spoon.reflect.code.CtCFlowBreak; 14 | /** 15 | * inserts a mutation hotspot for DO statement 16 | */ 17 | public class LoopExpressionMetaMutator 18 | extends AbstractProcessor { 19 | 20 | public static final String PREFIX = "_doExpressionMetaMutator"; 21 | private static final int procId = 3 ; 22 | public enum NbRound { 23 | NoRound, 24 | Rounds3, 25 | Rounds100 26 | 27 | }; 28 | private static final EnumSet roundsSet = EnumSet 29 | .of(NbRound.NoRound,NbRound.Rounds3, NbRound.Rounds100); 30 | 31 | public static int thisIndex = 0; 32 | 33 | /** 34 | * Stop Do loop on 3 or 100 Rounds 35 | */ 36 | @Override 37 | public void process(CtLoop candidate) { 38 | thisIndex++; 39 | String constanteName = "_doExpressionMetaMutator"+thisIndex+"_Constante"; 40 | String expression = "int "+ constanteName +" = 1"; 41 | CtCodeSnippetStatement DeclareRoundStatement = getFactory().Core() 42 | .createCodeSnippetStatement(); 43 | DeclareRoundStatement.setValue(expression); 44 | 45 | 46 | 47 | 48 | String expression2 = "if((" + PREFIX + thisIndex + ".is("+ NbRound.Rounds3.getClass().getCanonicalName() + '.' + NbRound.Rounds3.toString() + ")) && "+ constanteName +" == 3) " 49 | + "{" + this.breakOrReturn(candidate) + "}" 50 | + "else if((" + PREFIX + thisIndex + ".is("+NbRound.NoRound.getClass().getCanonicalName() + '.' + NbRound.NoRound.toString() + "))) " 51 | + "{" + this.breakOrReturn(candidate) + "}" 52 | + "else if("+ constanteName +" == 100)" 53 | + "{" + this.breakOrReturn(candidate) + "}" 54 | + " "+ constanteName +"++"; 55 | CtCodeSnippetStatement ifRoundStatement = getFactory().Core() 56 | .createCodeSnippetStatement(); 57 | ifRoundStatement.setValue(expression2); 58 | 59 | candidate.insertBefore(DeclareRoundStatement); 60 | candidate.getBody().insertAfter(ifRoundStatement); 61 | Selector.generateSelector(candidate, NbRound.NoRound, thisIndex, roundsSet, PREFIX); 62 | } 63 | 64 | public String breakOrReturn(CtLoop candidate) { 65 | Filter filter = new ReturnOrThrowFilter(); 66 | if(candidate.getBody().getElements(filter).size() > 0) { 67 | return candidate.getBody().getElements(filter).get(0).toString() + ";"; 68 | }else { 69 | return "break;"; 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/main/java/metamutator/MutantReplay.java: -------------------------------------------------------------------------------- 1 | package metamutator; 2 | 3 | import java.io.File; 4 | import java.net.URL; 5 | import java.net.URLClassLoader; 6 | import java.util.Arrays; 7 | import java.util.Iterator; 8 | import java.util.List; 9 | import java.util.Map; 10 | import java.util.Set; 11 | 12 | import org.junit.internal.TextListener; 13 | import org.junit.runner.JUnitCore; 14 | import org.junit.runner.Result; 15 | 16 | import com.google.common.collect.Lists; 17 | import com.google.common.collect.Maps; 18 | import com.google.common.collect.Multimap; 19 | import com.google.common.collect.Multimaps; 20 | 21 | 22 | public class MutantReplay { 23 | 24 | static URL url; 25 | static URL[] urls; 26 | static ClassLoader cl; 27 | 28 | static int failures; 29 | static int successes; 30 | 31 | public static void replayMetaProgramIn(String target, String repertory) throws Exception { 32 | 33 | File filep = new File(target); 34 | File file = new File(target+"/"+repertory); 35 | 36 | // this function doesn't work for a file and for inexistant file 37 | if (!file.exists() || !filep.exists()) { 38 | throw new Exception("no such directory"); 39 | } 40 | if (file.isFile() || filep.isFile()) 41 | throw new Exception("not a directory"); 42 | 43 | 44 | failures = 0; 45 | successes = 0; 46 | 47 | // make urls for classloader 48 | url = filep.toURI().toURL(); 49 | urls = new URL[]{url}; 50 | // create classloader 51 | cl = new URLClassLoader(urls); 52 | 53 | // finally run program 54 | replayMetaProgramWith(file, getPackage(repertory)); 55 | 56 | System.out.println("******************"+file.getName()+"******************"); 57 | System.out.println("total killed "+failures); 58 | System.out.println("total alive "+successes); 59 | } 60 | 61 | public static void replayMetaProgramWith(File target, String _package) throws Exception { 62 | // if the target is a file, so load the class and apply the initial function 63 | if (target.isFile()) { 64 | Class clazz = cl.loadClass(_package+"."+target.getName().replace(".class", "")); 65 | 66 | int[] val = replayMetaProgramWith(clazz); 67 | 68 | failures += val[0]; 69 | successes += val[1]; 70 | 71 | } 72 | // if the target is a directory, do stuff for each under file 73 | else if (target.isDirectory()) { 74 | for (File file : target.listFiles()) { 75 | if (!_package.isEmpty()) 76 | replayMetaProgramWith(file, _package+"."+target.getName()); 77 | else 78 | replayMetaProgramWith(file, target.getName()); 79 | } 80 | } 81 | 82 | } 83 | 84 | public static int[] replayMetaProgramWith(Class TEST_CLASS) throws Exception { 85 | System.out.println("******************"+TEST_CLASS.getName()+"******************"); 86 | 87 | boolean debug = false; 88 | 89 | JUnitCore core = new JUnitCore(); 90 | 91 | //output folder 92 | File fail = new File("results/fail.replay/"+TEST_CLASS.getName().replace(".", "/")); 93 | fail.mkdirs(); 94 | File success = new File("results/success.replay/"+TEST_CLASS.getName().replace(".", "/")); 95 | success.mkdirs(); 96 | 97 | String path = "results/fail/"+TEST_CLASS.getName().replace(".", "/"); 98 | File source =new File(path); 99 | File[] mutants ; 100 | if(source.exists() && source.isDirectory()){ 101 | mutants= source.listFiles();} 102 | else{ 103 | throw new Exception("The directory fail or success dosen't exist, or is not a directory, please execute MutantSearchSpaceExplorator.runMetaProgramWith(Class TEST_CLASS) first."); 104 | } 105 | 106 | // we first run the test suite once to load all classes and their static 107 | // fields 108 | // this registers only the executed ifs, so indirectly 109 | // it collects a kind of trace 110 | Result result = core.run(TEST_CLASS); 111 | 112 | if (debug) { core.addListener(new TextListener(System.out)); } 113 | 114 | List selectors = Selector.getAllSelectors(); 115 | 116 | // if (selectors.isEmpty()) 117 | // // There's no hot spot in program. Add one to run it at least once 118 | // selectors = ImmutableList.of(Selector.of(0, "n/a")); 119 | 120 | List successes = Lists.newArrayList(); 121 | List failures = Lists.newArrayList(); 122 | Multimap failures2 = Multimaps.newListMultimap( 123 | Maps.newHashMap(), Lists::newArrayList); 124 | 125 | String[] strOptions = new String[selectors.size()]; 126 | // Execute the test for each hot spot permutation 127 | // for (int[] options : 128 | // permutations(selectors.stream().map(Selector::getOptionCount).collect(Collectors.toList()))) 129 | // { 130 | 131 | int nattempts=0; 132 | 133 | for(int mut = 0; mut < mutants.length;mut++ ){ 134 | Config conf = Config.getInitInstance(); 135 | 136 | Map mapedConf = conf.getConfig(mutants[mut].getPath()).get(selectors.get(0).getLocationClass().getName()); 137 | 138 | Set cles = mapedConf.keySet(); 139 | 140 | int[] options = new int[selectors.size()]; 141 | int sel = 0; 142 | for (String cle : cles) { 143 | 144 | Selector.getSelectorByName(cle).choose(mapedConf.get(cle)); 145 | strOptions[sel] = Selector.getSelectorByName(cle) 146 | .getChosenAlternativeDescription(); 147 | for(int o = 0; o < Selector.getSelectorByName(cle).getAlternativeCount();o++ ){ 148 | 149 | boolean value =(o == mapedConf.get(cle))?true:false; 150 | 151 | conf.write( Selector.getSelectorByName(cle).getLocationClass().getName()+":"+Selector.getSelectorByName(cle).getIdentifier()+":"+Selector.getSelectorByName(cle).getAlternatives()[o]+":"+value); 152 | 153 | } 154 | sel ++; 155 | } 156 | 157 | if (debug) 158 | System.out.println("Checking options: " 159 | + Arrays.toString(options)); 160 | 161 | result = core.run(TEST_CLASS); 162 | 163 | if (result.wasSuccessful()) { 164 | successes.add(" Worked !!! -> " 165 | + Arrays.toString(options) + " / " 166 | + Arrays.toString(strOptions)); 167 | 168 | // On essaye avec renameTo 169 | File dest = new File(success.getPath()+"/"+mutants[mut].getName()); 170 | new File("config.txt").renameTo(dest); 171 | } else { 172 | String txt = String 173 | .format("%s / %s -> It has %s failures out of %s runs in %s ms", 174 | Arrays.toString(options), 175 | Arrays.toString(strOptions), 176 | result.getFailureCount(), 177 | result.getRunCount(), result.getRunTime()); 178 | String txt_trace = String.format("%s", 179 | Arrays.toString(strOptions)); 180 | 181 | failures.add(txt); 182 | failures2.put(result.getFailureCount(), txt); 183 | System.out.println(result.getFailures().get(0).getException()); 184 | File dest = new File(fail.getPath()+"/"+mutants[mut].getName()); 185 | new File("config.txt").renameTo(dest); 186 | } 187 | } 188 | 189 | 190 | 191 | System.out.println("killed "+failures.size()); 192 | System.out.println("alive "+successes.size()); 193 | 194 | Selector.reset(); 195 | 196 | int[] val = {failures.size(),successes.size()}; 197 | 198 | return val; 199 | 200 | // Show result summary 201 | // Sets.newHashSet(failures2.keys()).forEach(k -> { 202 | // System.out.println(String.format("\n-- Cases with %s", k)); 203 | // Collection texts = failures2.get(k); 204 | // if (k <= 2 || texts.size() < 10) 205 | // texts.forEach(System.out::println); 206 | // else 207 | // System.out.println("There are " + texts.size()); 208 | // }); 209 | 210 | // failures.forEach(System.out::println); 211 | 212 | // System.out.println(); 213 | // 214 | // if (successes.isEmpty()) 215 | // System.out.println("Oops, sorry, we could find a successful option"); 216 | // else 217 | // successes.forEach(System.out::println); 218 | 219 | } 220 | 221 | /** 222 | * Computes an iterable though all the permutations or the values in the 223 | * ranges provided 224 | * 225 | * @param sizes 226 | * the number of elements in each range (from 0 to size - 1) 227 | * @return an Iterable 228 | */ 229 | private static Iterable permutations(List sizes) { 230 | int limits[] = new int[sizes.size()]; 231 | 232 | int last = sizes.size() - 1; 233 | for (int i = last; i >= 0; i--) 234 | limits[i] = sizes.get(i) - 1; 235 | 236 | return () -> new Iterator() { 237 | int current[] = new int[last + 1]; 238 | 239 | { 240 | current[last]--; // Force the first element 241 | } 242 | 243 | @Override 244 | public boolean hasNext() { 245 | return !Arrays.equals(limits, current); 246 | } 247 | 248 | @Override 249 | public int[] next() { 250 | for (int i = last; i >= 0; i--) { 251 | if (current[i] < limits[i]) { 252 | current[i]++; 253 | 254 | return current.clone(); 255 | } 256 | current[i] = 0; 257 | } 258 | 259 | return new int[0]; 260 | } 261 | 262 | @Override 263 | public void remove() { 264 | // TODO Auto-generated method stub 265 | 266 | } 267 | }; 268 | } 269 | 270 | public static String getPackage(String path){ 271 | 272 | 273 | int endIndex = path.lastIndexOf("/"); 274 | if(endIndex == -1) 275 | return ""; 276 | 277 | path = path.substring(0, endIndex); 278 | path = path.replace("/", "."); 279 | 280 | return path; 281 | } 282 | 283 | } 284 | -------------------------------------------------------------------------------- /src/main/java/metamutator/MutantSearchSpaceExplorator.java: -------------------------------------------------------------------------------- 1 | package metamutator; 2 | 3 | import java.io.File; 4 | import java.net.URL; 5 | import java.net.URLClassLoader; 6 | import java.util.ArrayList; 7 | import java.util.Arrays; 8 | import java.util.Iterator; 9 | import java.util.List; 10 | 11 | import org.junit.runner.JUnitCore; 12 | import org.junit.runner.Result; 13 | import org.junit.runner.notification.Failure; 14 | 15 | import com.google.common.collect.Lists; 16 | import com.google.common.collect.Maps; 17 | import com.google.common.collect.Multimap; 18 | import com.google.common.collect.Multimaps; 19 | 20 | public class MutantSearchSpaceExplorator { 21 | 22 | static URL url; 23 | static URL[] urls; 24 | static ClassLoader cl; 25 | 26 | static int failures; 27 | static int successes; 28 | 29 | static final long maxMutants = System.getProperty("MutantSearchSpaceExplorator.maxMutants")!=null?Long.parseLong(System.getProperty("MutantSearchSpaceExplorator.maxMutants")):Long.MAX_VALUE; 30 | /** 31 | * this function launch a parallel class 32 | * @param classes 33 | * @param core 34 | * @return Core Result or null on blocking 35 | */ 36 | public static Result runWithThread(Class classes, JUnitCore core) { 37 | int i = 0; 38 | // Define Runner 39 | RunnerThreaded runner = new RunnerThreaded(classes,core); 40 | 41 | runner.start(); 42 | try { 43 | runner.join(); 44 | } catch (InterruptedException e) { 45 | throw new RuntimeException("interrupted"); 46 | } 47 | if (runner.getResult()==null) { 48 | throw new RuntimeException("interrupted"); 49 | } 50 | 51 | return runner.getResult(); 52 | } 53 | 54 | public static void runMetaProgramIn(String target, String repertory) throws Exception { 55 | 56 | File filep = new File(target); 57 | File file = new File(target+"/"+repertory); 58 | 59 | // this function doesn't work for a file and for inexistant file 60 | if (!file.exists() || !filep.exists()) { 61 | throw new Exception("no such directory"); 62 | } 63 | if (file.isFile() || filep.isFile()) 64 | throw new Exception("not a directory"); 65 | 66 | failures = 0; 67 | successes = 0; 68 | 69 | // make urls for classloader 70 | url = filep.toURI().toURL(); 71 | urls = new URL[]{url}; 72 | // create classloader 73 | cl = new URLClassLoader(urls); 74 | 75 | // finally run program 76 | runMetaProgramWith(file, getPackage(repertory)); 77 | 78 | System.out.println("******************"+file.getName()+"******************"); 79 | System.out.println("total killed "+failures); 80 | System.out.println("total alive "+successes); 81 | } 82 | 83 | public static void runMetaProgramWith(File target, String _package) throws Exception { 84 | 85 | 86 | // if the target is a file, so load the class and apply the initial function 87 | if (target.isFile()) { 88 | Class clazz = cl.loadClass(_package+"."+target.getName().replace(".class", "")); 89 | 90 | int[] val = runMetaProgramWith(clazz); 91 | 92 | failures += val[0]; 93 | successes += val[1]; 94 | 95 | } 96 | // if the target is a directory, do stuff for each under file 97 | else if (target.isDirectory()) { 98 | for (File file : target.listFiles()) { 99 | if (!_package.isEmpty()) 100 | runMetaProgramWith(file, _package+"."+target.getName()); 101 | else 102 | runMetaProgramWith(file, target.getName()); 103 | } 104 | 105 | } 106 | 107 | } 108 | 109 | static void resetAllSelectors() { 110 | List selectors = Selector.getAllSelectors(); 111 | for (int sel = 0; sel < selectors.size(); sel++) { 112 | selectors.get(sel).choose(0); 113 | } 114 | } 115 | public static int[] runMetaProgramWith(Class TEST_CLASS) throws Exception { 116 | System.out.println("******************"+TEST_CLASS.getName()+"******************"); 117 | boolean debug = false; 118 | 119 | JUnitCore core = new JUnitCore(); 120 | //output folder 121 | File fail = new File("results/fail/"+TEST_CLASS.getName().replace(".", "/")); 122 | fail.mkdirs(); 123 | File success = new File("results/success/"+TEST_CLASS.getName().replace(".", "/")); 124 | success.mkdirs(); 125 | 126 | // we first run the test suite once to load all classes and their static 127 | // fields 128 | // this registers only the executed ifs, so indirectly 129 | // it collects a kind of trace 130 | 131 | checkThatAllTestsPass(TEST_CLASS); 132 | 133 | List selectors = Selector.getAllSelectors(); 134 | 135 | // if (selectors.isEmpty()) 136 | // // There's no hot spot in program. Add one to run it at least once 137 | // selectors = ImmutableList.of(Selector.of(0, "n/a")); 138 | 139 | List successes = Lists.newArrayList(); 140 | List failures = Lists.newArrayList(); 141 | Multimap failures2 = Multimaps.newListMultimap( 142 | Maps.newHashMap(), Lists::newArrayList); 143 | 144 | String[] strOptions = new String[selectors.size()]; 145 | // Execute the test for each hot spot permutation 146 | // for (int[] options : 147 | // permutations(selectors.stream().map(Selector::getOptionCount).collect(Collectors.toList()))) 148 | // { 149 | 150 | int nattempts=0; 151 | 152 | for (int sel = 0; sel < selectors.size(); sel++) { 153 | 154 | 155 | if (nattempts++>maxMutants) break; 156 | 157 | //int k=0; 158 | Selector currentSelector = selectors.get(sel); 159 | System.out.println(currentSelector.getAlternativeCount()); 160 | 161 | // k should always start at one otherwise we explore the original code as well 162 | for (int k = 1; k < currentSelector.getAlternativeCount(); k++) 163 | { 164 | Config conf = Config.getInitInstance(); 165 | 166 | 167 | int[] options = new int[selectors.size()]; 168 | // System.out.println(Arrays.toString(options)); 169 | 170 | // resetting all selectors to 0 171 | resetAllSelectors(); 172 | 173 | checkThatAllTestsPass(TEST_CLASS); 174 | 175 | // checking that the test is running again 176 | 177 | 178 | for (int i = options.length - 1; i >= 0; i--) { 179 | // saving the info 180 | for(int o = 0; o < selectors.get(i).getAlternativeCount();o++ ){ 181 | 182 | boolean value =(o == 0)?true:false; 183 | if(i == sel && o ==k){ 184 | conf.write(currentSelector.getLocationClass().getName()+":"+currentSelector.getIdentifier()+":"+currentSelector.getAlternatives()[k]+":true"); 185 | }else{ 186 | if(i == sel) 187 | value = false; 188 | 189 | conf.write(selectors.get(i).getLocationClass().getName()+":"+selectors.get(i).getIdentifier()+":"+selectors.get(i).getAlternatives()[o]+":"+value); 190 | } 191 | 192 | } 193 | } 194 | currentSelector.choose(k); 195 | 196 | if (debug) 197 | System.out.println("Checking options: " 198 | + Arrays.toString(options)); 199 | 200 | Result result; 201 | 202 | result = runWithThread(TEST_CLASS,core); 203 | 204 | // result is null if interrupted 205 | if (result.wasSuccessful()) { 206 | successes.add(" Worked !!! -> " 207 | + Arrays.toString(options) + " / " 208 | + Arrays.toString(strOptions)); 209 | 210 | // On essaye avec renameTo 211 | File dest = new File(success.getPath()+"/mutant"+currentSelector.getIdentifier()+"_Op"+(k+1)+".txt"); 212 | new File("config.txt").renameTo(dest); 213 | } else { 214 | String txt; 215 | // txt = String 216 | // .format("%s / %s -> It has %s failures out of %s runs in %s ms", 217 | // Arrays.toString(options), 218 | // Arrays.toString(strOptions), 219 | // result.getFailureCount(), 220 | // result.getRunCount(), result.getRunTime()); 221 | txt = sel+ "_"+k+" "+result.getFailures().get(0).getMessage(); 222 | String txt_trace = String.format("%s", 223 | Arrays.toString(strOptions)); 224 | 225 | failures.add(txt); 226 | failures2.put(result.getFailureCount(), txt); 227 | System.out.println(result.getFailures().get(0).getException()); 228 | File dest = new File(fail.getPath()+"/mutant"+currentSelector.getIdentifier()+"_Op"+(k+1)+".txt"); 229 | new File("config.txt").renameTo(dest); 230 | } 231 | } 232 | 233 | } 234 | 235 | for (String s : failures ) { 236 | System.out.println(s); 237 | } 238 | 239 | System.out.println("killed "+failures.size()); 240 | System.out.println("alive "+successes.size()); 241 | 242 | Selector.reset(); 243 | 244 | int[] val = {failures.size(),successes.size()}; 245 | 246 | return val; 247 | 248 | } 249 | 250 | private static void checkThatAllTestsPass(Class TEST_CLASS) { 251 | resetAllSelectors(); 252 | JUnitCore core = new JUnitCore(); 253 | Result result = core.run(TEST_CLASS); 254 | if (result.getFailureCount()>0) { 255 | // oops the tests are not valid before 256 | throw new RuntimeException("oops it does not pass anymore", result.getFailures().get(0).getException()); 257 | } 258 | } 259 | 260 | /** 261 | * Computes an iterable though all the permutations or the values in the 262 | * ranges provided 263 | * 264 | * @param sizes 265 | * the number of elements in each range (from 0 to size - 1) 266 | * @return an Iterable 267 | */ 268 | private static Iterable permutations(List sizes) { 269 | int limits[] = new int[sizes.size()]; 270 | 271 | int last = sizes.size() - 1; 272 | for (int i = last; i >= 0; i--) 273 | limits[i] = sizes.get(i) - 1; 274 | 275 | return () -> new Iterator() { 276 | int current[] = new int[last + 1]; 277 | 278 | { 279 | current[last]--; // Force the first element 280 | } 281 | 282 | @Override 283 | public boolean hasNext() { 284 | return !Arrays.equals(limits, current); 285 | } 286 | 287 | @Override 288 | public int[] next() { 289 | for (int i = last; i >= 0; i--) { 290 | if (current[i] < limits[i]) { 291 | current[i]++; 292 | 293 | return current.clone(); 294 | } 295 | current[i] = 0; 296 | } 297 | 298 | return new int[0]; 299 | } 300 | 301 | @Override 302 | public void remove() { 303 | // TODO Auto-generated method stub 304 | 305 | } 306 | }; 307 | } 308 | 309 | 310 | public static String getPackage(String path){ 311 | 312 | int endIndex = path.lastIndexOf("/"); 313 | if(endIndex == -1) 314 | return ""; 315 | 316 | path = path.substring(0, endIndex); 317 | path = path.replace("/", "."); 318 | 319 | return path; 320 | } 321 | } 322 | -------------------------------------------------------------------------------- /src/main/java/metamutator/Null.java: -------------------------------------------------------------------------------- 1 | package metamutator; 2 | 3 | public enum Null { 4 | YES, 5 | NO 6 | } 7 | -------------------------------------------------------------------------------- /src/main/java/metamutator/NumericVariableMetaMutator.java: -------------------------------------------------------------------------------- 1 | package metamutator; 2 | 3 | 4 | import java.util.ArrayList; 5 | import java.util.EnumSet; 6 | 7 | import spoon.processing.AbstractProcessor; 8 | import spoon.reflect.code.CtCodeSnippetExpression; 9 | import spoon.reflect.code.CtExpression; 10 | import spoon.reflect.code.CtVariableRead; 11 | import spoon.reflect.declaration.CtElement; 12 | import spoon.reflect.declaration.ModifierKind; 13 | import spoon.reflect.reference.CtTypeReference; 14 | import spoon.reflect.reference.CtVariableReference; 15 | import spoon.support.reflect.code.CtBinaryOperatorImpl; 16 | import spoon.support.reflect.code.CtUnaryOperatorImpl; 17 | 18 | /** 19 | * inserts a mutation hotspot for each Numeric Variable 20 | * @author abdelrhamanebenhammou 21 | * 22 | */ 23 | public class NumericVariableMetaMutator 24 | extends AbstractProcessor { 25 | 26 | public static final String PREFIX = "_numericExpressionMetaMutator"; 27 | private static final int procId = 4 ; 28 | 29 | /** 30 | * 31 | */ 32 | public enum UNARY { 33 | // NO CHANGE 34 | INIT, 35 | // Absolute Value 36 | ABS, 37 | // Unary minus 38 | MINUS, 39 | // Increment 40 | INC, 41 | // Decrement 42 | DEC 43 | }; 44 | private static final EnumSet absSet = EnumSet 45 | .of(UNARY.ABS, UNARY.MINUS, UNARY.INC, UNARY.DEC); 46 | 47 | /** 48 | * 49 | */ 50 | public static int thisIndex = 0; 51 | 52 | /** 53 | * Accept Numeric Variable 54 | */ 55 | @Override 56 | public boolean isToBeProcessed(CtVariableRead candidate) { 57 | 58 | // SKIP not declared variable and Finale variable 59 | if(candidate.getVariable() == null) return false; 60 | 61 | if(candidate.getVariable().getSimpleName().equals("class")) return false; 62 | 63 | if(candidate.getVariable().getModifiers().contains(ModifierKind.FINAL)) return false; 64 | 65 | 66 | // SKIP IF VARIABLE IS CASTED 67 | if(candidate.getTypeCasts().size() > 0) return false; 68 | for(CtTypeReference type : candidate.getReferencedTypes()) { 69 | if(!this.isNumber(type)) return false; 70 | } 71 | 72 | if( candidate.getParent().getClass().equals(CtUnaryOperatorImpl.class)) return false; 73 | 74 | if(this.isNumber(candidate.getVariable().getType())){ 75 | return true; 76 | } 77 | return false; 78 | } 79 | 80 | public boolean isNumber(CtTypeReference type) { 81 | return type.getSimpleName().equals("int") 82 | || type.getSimpleName().equals("long") 83 | || type.getSimpleName().equals("byte") 84 | || type.getSimpleName().equals("float") 85 | || type.getSimpleName().equals("double"); 86 | } 87 | 88 | /** 89 | * Add AbsoluteValue, Plus, Minus, Increment or Decrement Unary Operator on Numeric Variable 90 | */ 91 | @Override 92 | public void process(CtVariableRead candidate) { 93 | thisIndex++; 94 | 95 | String expression = "("; 96 | for(UNARY unary : absSet){ 97 | if(unary.equals(UNARY.INIT)) continue; 98 | /*expression += PREFIX+thisIndex + ".is(\"" + unary.toString() + "\")?( " + UnaryEquivalent(unary) + candidate.toString() + ")):";*/ 99 | expression += PREFIX+thisIndex + ".is(" + unary.getClass().getCanonicalName()+'.'+unary.toString()+ ")?( " + UnaryEquivalent(unary) + candidate.getVariable().getSimpleName() + ")):"; 100 | } 101 | expression += "(" + candidate.toString() + "))"; 102 | CtCodeSnippetExpression codeSnippet = getFactory().Core() 103 | .createCodeSnippetExpression(); 104 | codeSnippet.setValue(expression); 105 | candidate.replace(codeSnippet); 106 | 107 | Selector.generateSelector(candidate, UNARY.INIT, thisIndex, absSet, PREFIX); 108 | } 109 | 110 | /** 111 | * 112 | * @param value 113 | * @return 114 | */ 115 | private String UnaryEquivalent(UNARY value) { 116 | switch(value) { 117 | case ABS : return "Math.abs("; 118 | case MINUS : return "-("; 119 | case INC : return "(++"; 120 | case DEC : return "(--"; 121 | default : return "("; 122 | } 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /src/main/java/metamutator/ReturnReplacementOperatorMetaMutator.java: -------------------------------------------------------------------------------- 1 | package metamutator; 2 | 3 | import java.util.EnumSet; 4 | import java.util.Set; 5 | 6 | import com.google.common.collect.Sets; 7 | 8 | import spoon.processing.AbstractProcessor; 9 | import spoon.reflect.code.CtCodeSnippetExpression; 10 | import spoon.reflect.code.CtExpression; 11 | import spoon.reflect.code.CtReturn; 12 | import spoon.reflect.declaration.CtClass; 13 | import spoon.reflect.declaration.CtElement; 14 | 15 | /** metamutates return statements that returns Boolean */ 16 | public class ReturnReplacementOperatorMetaMutator extends AbstractProcessor { 17 | 18 | public static final String PREFIX = "_returnReplacementOperatorHotSpot"; 19 | private static int index = 0; 20 | private static final EnumSet int_replacement = EnumSet.of(RETURN_REPLACEMENT_INT.INT_MIN, RETURN_REPLACEMENT_INT.INT_MAX, RETURN_REPLACEMENT_INT.ZERO); 21 | private static final EnumSet object_replacement = EnumSet.of(RETURN_REPLACEMENT_OBJECT.NULL); 22 | private static final int procId = 6; 23 | 24 | 25 | public enum RETURN_REPLACEMENT_INT { 26 | INIT, // INIT VALUE 27 | INT_MIN, // CHANGE BY MIN INT 28 | INT_MAX, // CHANGE BY MAX INT, 29 | ZERO // CHANGE BY 0 30 | }; 31 | 32 | public enum RETURN_REPLACEMENT_OBJECT { 33 | INIT, // INIT VALUE 34 | NULL 35 | } 36 | 37 | 38 | private String permutations(RETURN_REPLACEMENT_INT value) { 39 | switch(value) { 40 | case INT_MIN : return Integer.toString(Integer.MIN_VALUE + 1); 41 | case INT_MAX : return Integer.toString(Integer.MAX_VALUE - 1); 42 | case ZERO : return Integer.toString(0); 43 | default : return ""; 44 | } 45 | } 46 | 47 | private Set hostSpots = Sets.newHashSet(); 48 | 49 | private boolean isInteger(CtExpression expression) { 50 | return expression.getType().getSimpleName().equals("int"); 51 | } 52 | 53 | private boolean isBoolean(CtExpression expression) { 54 | return expression.getType().getSimpleName().equals("Boolean"); 55 | } 56 | 57 | @Override 58 | public boolean isToBeProcessed(CtReturn element) { 59 | try { 60 | Selector.getTopLevelClass(element); 61 | } catch (NullPointerException e) { 62 | return false; 63 | } 64 | return (element.getReturnedExpression() != null && !element.getReturnedExpression().getType().getSimpleName().equals("Boolean")); 65 | } 66 | 67 | 68 | public void process(CtReturn returnStatement) { 69 | CtExpression returnValue = returnStatement.getReturnedExpression(); 70 | // test if the returned value is not null 71 | if(returnValue != null){ 72 | 73 | index++; 74 | String expression = "("; 75 | int cpt = 0; 76 | if (isInteger(returnValue)) { 77 | for(RETURN_REPLACEMENT_INT replacement : int_replacement){ 78 | if(cpt < RETURN_REPLACEMENT_INT.values().length){ 79 | if(replacement.equals(RETURN_REPLACEMENT_INT.INIT)) continue; 80 | if(returnValue.getTypeCasts().size() != 0){ 81 | expression += "(" + PREFIX + index + ".is(" + replacement.getClass().getCanonicalName()+"."+replacement.toString() + ")) ? (("+ returnValue.getTypeCasts().get(0) +")( " + permutations(replacement) + " ))"; 82 | expression += " : "; 83 | }else{ 84 | expression += "(" + PREFIX + index + ".is(" + replacement.getClass().getCanonicalName()+"."+replacement.toString() + ")) ? ( " + permutations(replacement) + " )"; 85 | expression += " : "; 86 | } 87 | }else{ 88 | expression += " (" + permutations(replacement) + ")"; 89 | } 90 | } 91 | 92 | expression += "(" + returnValue + "))"; 93 | CtCodeSnippetExpression codeSnippet = getFactory().Core() 94 | .createCodeSnippetExpression(); 95 | codeSnippet.setValue(expression); 96 | 97 | CtReturn newReturn = getFactory().Core().createReturn(); 98 | newReturn.setReturnedExpression(codeSnippet); 99 | returnStatement.replace(newReturn); 100 | Selector.generateSelector(returnStatement, RETURN_REPLACEMENT_INT.INIT, index ,int_replacement ,PREFIX); 101 | 102 | hostSpots.add(returnStatement); 103 | 104 | }else if (!isBoolean(returnValue)){ 105 | expression += "(" + PREFIX + index + ".is(" + RETURN_REPLACEMENT_OBJECT.NULL.getClass().getCanonicalName()+"."+RETURN_REPLACEMENT_OBJECT.NULL.toString() + ")) ? ( null )"; 106 | expression += " : "; 107 | expression += "(" + returnValue + "))"; 108 | CtCodeSnippetExpression codeSnippet = getFactory().Core() 109 | .createCodeSnippetExpression(); 110 | codeSnippet.setValue(expression); 111 | 112 | CtReturn newReturn = getFactory().Core().createReturn(); 113 | newReturn.setReturnedExpression(codeSnippet); 114 | returnStatement.replace(newReturn); 115 | Selector.generateSelector(returnStatement, RETURN_REPLACEMENT_OBJECT.INIT, index ,object_replacement ,PREFIX); 116 | hostSpots.add(returnStatement); 117 | } 118 | } 119 | } 120 | 121 | 122 | 123 | /** 124 | * Check if this sub expression was already inside an uppermost expression 125 | * that was processed has a hot spot. This version does not allowed 126 | * conflicting hot spots 127 | * 128 | * @param element 129 | * the current expression to test 130 | * @return true if this expression is descendant of an already processed 131 | * expression 132 | */ 133 | private boolean alreadyInHotsSpot(CtElement element) { 134 | CtElement parent = element.getParent(); 135 | while (!isTopLevel(parent) && parent != null) { 136 | if (hostSpots.contains(parent)) 137 | return true; 138 | 139 | parent = parent.getParent(); 140 | } 141 | 142 | return false; 143 | } 144 | 145 | private boolean isTopLevel(CtElement parent) { 146 | return parent instanceof CtClass && ((CtClass) parent).isTopLevel(); 147 | } 148 | } -------------------------------------------------------------------------------- /src/main/java/metamutator/RunnerThreaded.java: -------------------------------------------------------------------------------- 1 | package metamutator; 2 | 3 | import org.junit.runner.JUnitCore; 4 | import org.junit.runner.Result; 5 | 6 | /** 7 | * this class launches a test class 8 | * @author abdelrhamanebenhammou 9 | * 10 | */ 11 | public class RunnerThreaded extends Thread{ 12 | /** 13 | * myResult represents result of test class 14 | */ 15 | public Result myResult = null; 16 | private JUnitCore core; 17 | private Class classes; 18 | 19 | public RunnerThreaded(Class classes, JUnitCore core) { 20 | this.core = core; 21 | this.classes = classes; 22 | } 23 | 24 | /** 25 | * Launch Test Class 26 | */ 27 | public void run() { 28 | myResult = core.run(classes); 29 | } 30 | 31 | public Result getResult() { 32 | return myResult; 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/metamutator/Selector.java: -------------------------------------------------------------------------------- 1 | package metamutator; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Arrays; 5 | import java.util.EnumSet; 6 | import java.util.HashMap; 7 | import java.util.List; 8 | import java.util.Map; 9 | import java.util.NoSuchElementException; 10 | import java.util.UUID; 11 | 12 | import spoon.reflect.code.BinaryOperatorKind; 13 | import spoon.reflect.code.CtBinaryOperator; 14 | import spoon.reflect.code.CtCodeSnippetExpression; 15 | import spoon.reflect.declaration.CtClass; 16 | import spoon.reflect.declaration.CtElement; 17 | import spoon.reflect.declaration.CtField; 18 | import spoon.reflect.declaration.CtType; 19 | import spoon.reflect.declaration.ModifierKind; 20 | import spoon.reflect.reference.CtTypeReference; 21 | 22 | /** 23 | * A selector selects one of the variants for a given hot spot 24 | */ 25 | public class Selector implements ISelector { 26 | private static final Map selectors = new HashMap(); 27 | 28 | private long locationHashCode; 29 | private String _identifier; 30 | private Class locationClass; 31 | private E[] variants; 32 | private int chosenVariant = 0; 33 | 34 | private Selector() { 35 | } 36 | 37 | public static Selector of(Object ... variants) { 38 | // defensive copy 39 | Selector selector = new Selector(); 40 | 41 | // defensive copy 42 | selector.variants = variants.clone(); 43 | //selector.locationHashCode = locationHashCode; 44 | 45 | selector._identifier=UUID.randomUUID().toString(); 46 | selectors.put(selector._identifier, selector); 47 | 48 | return selector; 49 | } 50 | 51 | @Override 52 | public Selector in(Class locationClass) { 53 | this.locationClass= locationClass; 54 | return this; 55 | } 56 | 57 | @Override 58 | public Selector id(String identifier) { 59 | selectors.remove(this._identifier); 60 | this._identifier= identifier; 61 | if (selectors.get(identifier)!=null) { 62 | throw new IllegalArgumentException("identifier already used"); 63 | } 64 | selectors.put(identifier, this); 65 | return this; 66 | } 67 | 68 | @Override 69 | public void choose(int option) { 70 | if (option<0 || option>=variants.length) { 71 | throw new IllegalArgumentException(); 72 | } 73 | chosenVariant = option; 74 | } 75 | 76 | @Override 77 | public boolean is(E variant) { 78 | // if (System.currentTimeMillis() > stopTime) 79 | // throw new StopTimeExceededError("In selector " + hotSpot + " with option " + chosenVariant + " checking for " + variant); 80 | 81 | return chosenVariant >= 0 && variants[chosenVariant].equals(variant); 82 | } 83 | 84 | @Override public String toString() { 85 | return "chosenVariant " + chosenVariant +"\n" 86 | +"variants "+ variants+"\n" 87 | ; 88 | } 89 | 90 | public static List getAllSelectors() { 91 | return new ArrayList(selectors.values()); 92 | } 93 | 94 | public static Selector getSelectorByName(String name) { 95 | for (Selector s : selectors.values()) { 96 | if (name.equals(s._identifier)) { 97 | return s; 98 | } 99 | } 100 | throw new NoSuchElementException("no such selector"); 101 | } 102 | 103 | @Override 104 | public int getAlternativeCount() { 105 | return variants.length; 106 | } 107 | 108 | 109 | @Override 110 | public String getIdentifier() { 111 | return _identifier; 112 | } 113 | 114 | @Override 115 | public String getChosenAlternativeDescription() { 116 | 117 | return getIdentifier()+",v:"+variants[chosenVariant]; 118 | // if ((chosenVariant >= 0) && (chosenVariant < variants.length)) { 119 | // return variants[chosenVariant]; 120 | // } else { 121 | // return "n/a"; 122 | // } 123 | } 124 | 125 | public static class StopTimeExceededError extends RuntimeException { // TODO THis can be cached !! 126 | 127 | public StopTimeExceededError(String message) { 128 | super(message); 129 | } 130 | } 131 | /** Generates a field containing a new selector for this element and adds it to the current class 132 | * 133 | */ 134 | public static void generateSelector(CtElement element, E initialChoice, int selectorId, EnumSet possibleChoices, String prefix ) { 135 | 136 | Class choiceClass = possibleChoices.iterator().next().getClass(); 137 | 138 | long hashCode = (element.getPosition().toString() + element.getParent() 139 | .toString()).hashCode(); 140 | 141 | CtTypeReference fieldType = element.getFactory().Type().createTypeParameterReference(ISelector.class.getCanonicalName()); 142 | 143 | //doesn't work with spoon for the moment 144 | //CtTypeReference genericRefs = element.getFactory().Type().createTypeParameterReference(choiceClass.getCanonicalName()); 145 | //fieldType.addActualTypeArgument(genericRefs); 146 | 147 | String selectorFieldName = prefix + selectorId; 148 | 149 | CtCodeSnippetExpression codeSnippet = element.getFactory().Core() 150 | .createCodeSnippetExpression(); 151 | StringBuilder sb = new StringBuilder(Selector.class.getCanonicalName() + ".of("); 152 | 153 | // we disable the ids 154 | // sb.append(procId+""+selectorId); 155 | // sb.append(','); 156 | 157 | // now the options 158 | sb.append("new "+choiceClass.getCanonicalName()+"[]{"); 159 | 160 | // the original operator, always the first one 161 | sb.append(initialChoice.getClass().getCanonicalName()+"."+initialChoice.toString()); 162 | 163 | // the other alternatives 164 | for (Object choose : possibleChoices) { 165 | if (choose.equals(initialChoice)) { 166 | continue; 167 | } 168 | sb.append(',').append(choose.getClass().getCanonicalName()+"."+choose.toString()); 169 | } 170 | 171 | sb.append("})"); 172 | 173 | // adding location 174 | if (element.getParent(CtType.class).isTopLevel()) { 175 | sb.append(".in(" 176 | + element.getParent(CtType.class).getQualifiedName() 177 | + ".class)"); 178 | } 179 | 180 | // adding identifier 181 | sb.append(".id(\"" + selectorFieldName + "\")"); 182 | 183 | codeSnippet.setValue(sb.toString()); 184 | 185 | CtClass type = getTopLevelClass(element); 186 | 187 | CtField field = element.getFactory().Field().create( 188 | type, 189 | EnumSet.of(ModifierKind.FINAL, ModifierKind.PRIVATE, 190 | ModifierKind.STATIC), fieldType, selectorFieldName, 191 | codeSnippet); 192 | 193 | type.addField(field); 194 | } 195 | 196 | public static CtClass getTopLevelClass(CtElement element) { 197 | CtClass parent = element.getParent(CtClass.class); 198 | while (!parent.isTopLevel()) { 199 | parent = parent.getParent(CtClass.class); 200 | } 201 | return parent; 202 | } 203 | 204 | @Override 205 | public Class getLocationClass(){ 206 | if(locationClass == null) 207 | locationClass = Object.class; 208 | return locationClass; 209 | } 210 | 211 | @Override 212 | public E[] getAlternatives() { 213 | // defensive copy 214 | return Arrays.copyOf(variants, variants.length); 215 | } 216 | 217 | public static void reset() { 218 | selectors.clear(); 219 | } 220 | } 221 | -------------------------------------------------------------------------------- /src/main/java/metamutator/StatementDeletionMetaMutator.java: -------------------------------------------------------------------------------- 1 | package metamutator; 2 | 3 | import com.google.common.collect.Sets; 4 | import spoon.Launcher; 5 | import spoon.processing.AbstractProcessor; 6 | import spoon.reflect.code.CtAssert; 7 | import spoon.reflect.code.CtAssignment; 8 | import spoon.reflect.code.CtBlock; 9 | import spoon.reflect.code.CtCFlowBreak; 10 | import spoon.reflect.code.CtCodeSnippetExpression; 11 | import spoon.reflect.code.CtCodeSnippetStatement; 12 | import spoon.reflect.code.CtConstructorCall; 13 | import spoon.reflect.code.CtContinue; 14 | import spoon.reflect.code.CtDo; 15 | import spoon.reflect.code.CtFor; 16 | import spoon.reflect.code.CtForEach; 17 | import spoon.reflect.code.CtIf; 18 | import spoon.reflect.code.CtInvocation; 19 | import spoon.reflect.code.CtLiteral; 20 | import spoon.reflect.code.CtLocalVariable; 21 | import spoon.reflect.code.CtLoop; 22 | import spoon.reflect.code.CtNewClass; 23 | import spoon.reflect.code.CtOperatorAssignment; 24 | import spoon.reflect.code.CtReturn; 25 | import spoon.reflect.code.CtStatement; 26 | import spoon.reflect.code.CtSwitch; 27 | import spoon.reflect.code.CtSynchronized; 28 | import spoon.reflect.code.CtThrow; 29 | import spoon.reflect.code.CtUnaryOperator; 30 | import spoon.reflect.code.CtWhile; 31 | import spoon.reflect.declaration.CtClass; 32 | import spoon.reflect.declaration.CtElement; 33 | import spoon.reflect.declaration.CtEnum; 34 | import spoon.reflect.declaration.CtMethod; 35 | import spoon.reflect.factory.CoreFactory; 36 | import spoon.reflect.visitor.Filter; 37 | import spoon.reflect.visitor.filter.ReturnOrThrowFilter; 38 | import spoon.reflect.visitor.filter.TypeFilter; 39 | import spoon.support.reflect.code.CtLiteralImpl; 40 | 41 | import java.util.ArrayList; 42 | import java.util.Arrays; 43 | import java.util.Collections; 44 | import java.util.EnumSet; 45 | import java.util.HashMap; 46 | import java.util.List; 47 | import java.util.Map; 48 | import java.util.Set; 49 | 50 | public class StatementDeletionMetaMutator 51 | extends AbstractProcessor { 52 | 53 | public static final String PREFIX = "_StatementDeletionMutatorHotSpot"; 54 | private static final int procId = 6; 55 | private int selectorIndex = 0; 56 | 57 | public enum ACTIVABLE { 58 | // NO CHANGE 59 | ENABLED, 60 | // Absolute Value 61 | DISABLED 62 | }; 63 | 64 | private static final EnumSet ActivableSet = EnumSet 65 | .of(ACTIVABLE.ENABLED, ACTIVABLE.DISABLED); 66 | 67 | 68 | private Set hotSpots = Sets.newHashSet(); 69 | 70 | //break? si boucle infini 71 | //ctcflowbreak ? kesako? 72 | //invocation? private static final List MODIFIABLE_STATEMENTS = new ArrayList( 73 | private static final List MODIFIABLE_STATEMENTS = new ArrayList( 74 | Arrays.asList(CtAssert.class, CtContinue.class, CtDo.class, CtFor.class, CtForEach.class, 75 | CtIf.class, CtLoop.class, CtSwitch.class, CtThrow.class, CtWhile.class) 76 | ); 77 | 78 | 79 | //break? si boucle infini 80 | //ctcflowbreak ? kesako? 81 | private static final List UNMODIFIABLE_STATEMENTS = new ArrayList( 82 | Arrays.asList(CtAssignment.class, CtBlock.class, CtCFlowBreak.class, CtClass.class, 83 | CtCodeSnippetStatement.class, CtConstructorCall.class, CtEnum.class, CtInvocation.class, 84 | CtLocalVariable.class, CtNewClass.class, CtOperatorAssignment.class, CtReturn.class, 85 | CtSynchronized.class, CtUnaryOperator.class) 86 | ); 87 | 88 | 89 | 90 | //Templates of returned expressions, used when a function have a return in a statement which can be deleted. 91 | private static final Map PrimitiveTemplateExpressions; 92 | static { 93 | CoreFactory f = new Launcher().getFactory().Core(); 94 | HashMap map = new HashMap(); 95 | map.put(byte.class, f.createLiteral().setValue((byte) 0)); 96 | map.put(short.class, f.createLiteral().setValue((short) 0)); 97 | map.put(int.class, f.createLiteral().setValue(0)); 98 | map.put(long.class, f.createLiteral().setValue(0L)); 99 | map.put(float.class, f.createLiteral().setValue(0.0f)); 100 | map.put(double.class,f.createLiteral().setValue(0.0d)); 101 | map.put(boolean.class,f.createLiteral().setValue(false)); 102 | map.put(char.class,f.createLiteral().setValue('\u0000')); 103 | map.put(void.class,null); 104 | PrimitiveTemplateExpressions = Collections.unmodifiableMap(map); 105 | } 106 | 107 | 108 | @Override 109 | public boolean isToBeProcessed(CtStatement element) { 110 | for(Class c : MODIFIABLE_STATEMENTS){ 111 | if(c.isInstance(element)){ 112 | return true; 113 | } 114 | } 115 | return false; 116 | } 117 | 118 | 119 | @Override 120 | public void process(CtStatement element) { 121 | //System.out.println("process"); 122 | mutateOperator(element); 123 | } 124 | 125 | 126 | private void mutateOperator(final CtStatement expression) { 127 | 128 | 129 | /*if (alreadyInHotsSpot(expression)) { 130 | System.out 131 | .println(String 132 | .format("Expression '%s' ignored because it is included in previous hot spot", 133 | expression)); 134 | return; 135 | }*/ 136 | int thisIndex = ++selectorIndex; 137 | 138 | ACTIVABLE kind = ACTIVABLE.ENABLED; 139 | String expressionContent = String.format("("+ PREFIX + "%s.is(%s))", 140 | thisIndex, kind.getClass().getCanonicalName()+"."+kind.name()); 141 | 142 | //create IfChoice with right condition 143 | CtIf ifChoice = getFactory().Core().createIf(); 144 | CtCodeSnippetExpression expIf = getFactory().Code().createCodeSnippetExpression(expressionContent); 145 | ifChoice.setCondition(expIf); 146 | 147 | 148 | 149 | //create block from a clone of expression 150 | CtStatement exp2 = getFactory().Core().clone(expression); 151 | CtBlock thenBlock = getFactory().Code().createCtBlock(exp2); 152 | 153 | //set if and replace the expression with the new if 154 | ifChoice.setThenStatement(thenBlock); 155 | expression.replace(ifChoice); 156 | 157 | //to be sure 158 | ifChoice.getParent().updateAllParentsBelow(); 159 | 160 | //if there are return or throws, set else with value of return. 161 | Filter filterReturn = new ReturnOrThrowFilter(); 162 | if(!thenBlock.getElements(filterReturn).isEmpty()){ 163 | SetElseStatementWithReturn(ifChoice); 164 | } 165 | 166 | 167 | //to avoid to delete assignement in statement, we assign a default value to all local variable. 168 | Filter filterLocalVariable = new TypeFilter(CtLocalVariable.class); 169 | CtMethod method = ifChoice.getParent(CtMethod.class); 170 | if(method != null && !method.getElements(filterLocalVariable).isEmpty()){ 171 | for(CtLocalVariable var : method.getElements(filterLocalVariable)){ 172 | if(var.getAssignment() == null){ 173 | //create right side expression from template. 174 | Class classOfAssignment = var.getType().getActualClass(); 175 | CtLiteral rightHand = null; 176 | 177 | //Particular case of ForEach (int x : numbers) can't be (int x = 0 : numbers) 178 | if(var.getParent() instanceof CtForEach){ 179 | continue; 180 | } 181 | if(PrimitiveTemplateExpressions.containsKey(classOfAssignment)){ 182 | CtLiteral templateExpression = PrimitiveTemplateExpressions.get(classOfAssignment); 183 | rightHand = getFactory().Core().clone(templateExpression); 184 | }else{ 185 | rightHand = getFactory().createLiteral().setValue(null); 186 | } 187 | var.setAssignment(rightHand); 188 | } 189 | } 190 | } 191 | 192 | Selector.generateSelector(expression, ACTIVABLE.ENABLED, thisIndex, ActivableSet, PREFIX); 193 | //hotSpots.add(expression); 194 | 195 | } 196 | 197 | 198 | 199 | 200 | /* 201 | * set else statement with return. 202 | * This work only when the IfStatement contain a return. 203 | */ 204 | private void SetElseStatementWithReturn(CtIf ifStatement){ 205 | //search the first parent method 206 | CtMethod parentMethod = ifStatement.getParent(CtMethod.class); 207 | //we go out of while with null of a CtMethod. If null, return without method in parents...? 208 | if(parentMethod == null){ 209 | return; 210 | } 211 | 212 | 213 | //create returned expression from template. 214 | CtLiteral returnedExpression = null; 215 | Class classOfReturn = parentMethod.getType().getActualClass(); 216 | 217 | if(PrimitiveTemplateExpressions.containsKey(classOfReturn)){ 218 | CtLiteral templateExpression = PrimitiveTemplateExpressions.get(classOfReturn); 219 | returnedExpression = getFactory().Core().clone(templateExpression); 220 | }else{ 221 | returnedExpression = new CtLiteralImpl().setValue(null); 222 | } 223 | 224 | 225 | CtReturn theReturn = getFactory().Core().createReturn(); 226 | theReturn.setReturnedExpression(returnedExpression); 227 | CtBlock elseBlock = ifStatement.getElseStatement(); 228 | if(elseBlock == null){ 229 | elseBlock = getFactory().Core().createBlock(); 230 | } 231 | elseBlock.addStatement(theReturn); 232 | ifStatement.setElseStatement(elseBlock); 233 | } 234 | 235 | 236 | 237 | private boolean alreadyInHotsSpot(CtElement element) { 238 | CtElement parent = element.getParent(); 239 | while (!isTopLevel(parent) && parent != null) { 240 | if (hotSpots.contains(parent)) 241 | return true; 242 | 243 | parent = parent.getParent(); 244 | } 245 | 246 | return false; 247 | } 248 | 249 | private boolean isTopLevel(CtElement parent) { 250 | return parent instanceof CtClass && ((CtClass) parent).isTopLevel(); 251 | } 252 | } -------------------------------------------------------------------------------- /src/main/java/metamutator/UniqueTestGenerator.java: -------------------------------------------------------------------------------- 1 | package metamutator; 2 | 3 | import java.io.IOException; 4 | import java.lang.annotation.Annotation; 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | import java.util.Set; 8 | import java.util.TreeSet; 9 | 10 | import org.junit.Test; 11 | import org.junit.runner.Runner; 12 | import org.junit.runners.BlockJUnit4ClassRunner; 13 | 14 | import spoon.processing.AbstractProcessor; 15 | import spoon.reflect.code.CtBlock; 16 | import spoon.reflect.code.CtCodeSnippetStatement; 17 | import spoon.reflect.declaration.CtClass; 18 | import spoon.reflect.declaration.CtMethod; 19 | import spoon.reflect.declaration.CtPackage; 20 | import spoon.reflect.declaration.CtParameter; 21 | import spoon.reflect.declaration.ModifierKind; 22 | import spoon.reflect.reference.CtTypeReference; 23 | import spoon.reflect.visitor.filter.AnnotationFilter; 24 | 25 | /** 26 | * Creates a unique test case inside a unique test class. 27 | * 28 | * The created class is runnable as main or as a test case itself. 29 | * 30 | */ 31 | @SuppressWarnings("rawtypes") 32 | public class UniqueTestGenerator extends AbstractProcessor { 33 | 34 | // contais the block to be created 35 | CtBlock bWithBlock; 36 | 37 | @Override 38 | public void processingDone() { 39 | createClass("TestSuite"); 40 | System.out.println("done"); 41 | } 42 | 43 | private void createClass(String klassName) { 44 | CtClass c = getFactory().Core().createClass(); 45 | c.addModifier(ModifierKind.PUBLIC); 46 | c.setSimpleName(klassName.replace('-', '_').replace('.', '_')); 47 | 48 | 49 | // // main 50 | { 51 | CtMethod m = getFactory().Core().createMethod(); 52 | m.setSimpleName("main"); 53 | m.addModifier(ModifierKind.STATIC); 54 | m.addModifier(ModifierKind.PUBLIC); 55 | m.setBody(bWithBlock); 56 | m.setType(getFactory().Type().VOID_PRIMITIVE); 57 | List l = new ArrayList<>(); 58 | CtParameter par = getFactory().Core().createParameter(); 59 | par.setType((CtTypeReference) getFactory().Core().createTypeReference().setSimpleName("String[]")); 60 | par.setSimpleName("args"); 61 | l.add(par); 62 | m.setParameters(l); 63 | c.addMethod(m); 64 | m.addThrownType((CtTypeReference) getFactory().Core().createTypeReference().setSimpleName("Exception")); 65 | 66 | CtCodeSnippetStatement e = getFactory().Core().createCodeSnippetStatement (); 67 | e.setValue("new "+c.getSimpleName()+"().test()"); 68 | CtBlock bod= getFactory().Core().createBlock(); 69 | bod.addStatement(e); 70 | m.setBody(bod); 71 | } 72 | 73 | { 74 | CtMethod m = getFactory().Core().createMethod(); 75 | m.setSimpleName("test"); 76 | m.addModifier(ModifierKind.PUBLIC); 77 | getFactory().Annotation().annotate(m, Test.class); 78 | m.setBody(bWithBlock); 79 | m.addThrownType((CtTypeReference) getFactory().Core().createTypeReference().setSimpleName("Exception")); 80 | m.setType(getFactory().Type().VOID_PRIMITIVE); 81 | c.addMethod(m); 82 | } 83 | 84 | // adding the class 85 | CtPackage p = getFactory().Package().getOrCreate("test"); 86 | p.addType(c); 87 | } 88 | 89 | @Override 90 | public boolean isToBeProcessed(CtClass element) { 91 | return element.getElements(new AnnotationFilter<>((Class) Test.class)).size()>0 92 | && !element.getModifiers().contains(ModifierKind.ABSTRACT) 93 | && element.isTopLevel(); 94 | } 95 | 96 | @SuppressWarnings({ "unchecked"}) 97 | @Override 98 | public void process(CtClass element) { 99 | try { 100 | // run normal 101 | if (bWithBlock == null) { 102 | bWithBlock = getFactory().Core().createBlock(); 103 | } 104 | 105 | CtCodeSnippetStatement e = createTestSnippet(element, BlockJUnit4ClassRunner.class); 106 | bWithBlock.addStatement(e); 107 | 108 | } catch (Exception e) { 109 | throw new RuntimeException(e); 110 | } 111 | } 112 | 113 | private CtCodeSnippetStatement createTestSnippet(CtClass element, Class runner) { 114 | CtCodeSnippetStatement e = getFactory().Core() 115 | .createCodeSnippetStatement(); 116 | String val = " new "+runner.getCanonicalName()+"(" 117 | + element.getQualifiedName() 118 | + ".class).run(new org.junit.runner.notification.RunNotifier() {\n" 119 | + " @Override\n" 120 | + " public void fireTestFailure(org.junit.runner.notification.Failure failure) {\n" 121 | + " if (failure.getException() instanceof RuntimeException) throw (RuntimeException)failure.getException(); \n" 122 | + " if (failure.getException() instanceof Error) throw (Error)failure.getException(); \n" 123 | + " throw new RuntimeException(failure.getException());\n" 124 | + " }\n" + " })"; 125 | e.setValue(val); 126 | return e; 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /src/main/java/metamutator/VariabletoNullMetaMutator.java: -------------------------------------------------------------------------------- 1 | package metamutator; 2 | 3 | import java.util.EnumSet; 4 | import java.util.Set; 5 | import java.util.stream.Collectors; 6 | 7 | import com.google.common.collect.Sets; 8 | 9 | import spoon.processing.AbstractProcessor; 10 | import spoon.reflect.code.BinaryOperatorKind; 11 | import spoon.reflect.code.CtBinaryOperator; 12 | import spoon.reflect.code.CtCodeSnippetExpression; 13 | import spoon.reflect.code.CtConstructorCall; 14 | import spoon.reflect.code.CtExpression; 15 | import spoon.reflect.code.CtRHSReceiver; 16 | import spoon.reflect.code.CtStatement; 17 | import spoon.reflect.declaration.CtAnonymousExecutable; 18 | import spoon.reflect.declaration.CtClass; 19 | import spoon.reflect.declaration.CtConstructor; 20 | import spoon.reflect.declaration.CtElement; 21 | import spoon.reflect.declaration.CtField; 22 | import spoon.reflect.reference.CtTypeReference; 23 | import spoon.support.reflect.code.CtConstructorCallImpl; 24 | 25 | /** 26 | * inserts a mutation hotspot for each binary operator 27 | */ 28 | public class VariabletoNullMetaMutator extends 29 | AbstractProcessor { 30 | 31 | public static final String PREFIX = "_variableNullHotSpot"; 32 | private static int index = 0; 33 | private static final int procId = 2; 34 | 35 | private static final EnumSet NULLORNOTNULL = EnumSet 36 | .of(Null.NO, Null.YES); 37 | 38 | private Set hostSpots = Sets.newHashSet(); 39 | 40 | @Override 41 | public boolean isToBeProcessed(CtStatement element) { 42 | // if (element.getParent(CtAnonymousExecutable.class)!=null) { 43 | // System.out.println(element.getParent(CtAnonymousExecutable.class)); 44 | // } 45 | 46 | if(!(element instanceof CtRHSReceiver)) 47 | return false; 48 | try { 49 | Selector.getTopLevelClass(element); 50 | } catch (Exception e) { 51 | return false; 52 | } 53 | 54 | // not in constructors because we use static fields 55 | if (element.getParent(CtConstructor.class) != null) { 56 | return false; 57 | } 58 | 59 | if (((CtRHSReceiver)element).getAssignment() == null) 60 | return false; 61 | 62 | CtTypeReference type = ((CtRHSReceiver)element).getAssignment().getType(); 63 | 64 | if (type == null) 65 | return false; 66 | 67 | if (element.toString().contains("java.lang.String.format")) 68 | return false; 69 | 70 | return !((CtRHSReceiver)element).getAssignment().getType().isPrimitive() 71 | && (element.getParent(CtAnonymousExecutable.class) == null); 72 | } 73 | 74 | public void process(CtStatement assignment) { 75 | 76 | mutateOperator(((CtRHSReceiver)assignment).getAssignment(), NULLORNOTNULL); 77 | 78 | } 79 | 80 | /** 81 | * 82 | * @param expression 83 | * @param operators 84 | */ 85 | private void mutateOperator(final CtExpression expression, EnumSet operators) { 86 | 87 | if (alreadyInHotsSpot(expression) 88 | || expression.toString().contains(".is(\"")) { 89 | System.out 90 | .println(String 91 | .format("Expression '%s' ignored because it is included in previous hot spot", 92 | expression)); 93 | return; 94 | } 95 | 96 | int thisIndex = ++index; 97 | 98 | String actualExpression = expression.toString(); 99 | 100 | String newExpression = String.format("(%s%s.is(%s))?"+actualExpression+":null",PREFIX,thisIndex,"metamutator.Null.NO"); 101 | 102 | CtCodeSnippetExpression codeSnippet = getFactory().Core() 103 | .createCodeSnippetExpression(); 104 | codeSnippet.setValue('(' + newExpression + ')'); 105 | 106 | expression.replace(codeSnippet); 107 | expression.replace(expression); 108 | 109 | Selector.generateSelector(expression, Null.NO, thisIndex, operators, PREFIX); 110 | 111 | hostSpots.add(expression); 112 | 113 | } 114 | 115 | /** 116 | * Check if this sub expression was already inside an uppermost expression 117 | * that was processed has a hot spot. This version does not allowed 118 | * conflicting hot spots 119 | * 120 | * @param element 121 | * the current expression to test 122 | * @return true if this expression is descendant of an already processed 123 | * expression 124 | */ 125 | private boolean alreadyInHotsSpot(CtElement element) { 126 | CtElement parent = element.getParent(); 127 | while (!isTopLevel(parent) && parent != null) { 128 | if (hostSpots.contains(parent)) 129 | return true; 130 | 131 | parent = parent.getParent(); 132 | } 133 | 134 | return false; 135 | } 136 | 137 | private boolean isTopLevel(CtElement parent) { 138 | return parent instanceof CtClass && ((CtClass) parent).isTopLevel(); 139 | } 140 | } -------------------------------------------------------------------------------- /src/test/java/UniqueTestGeneratorTest.java: -------------------------------------------------------------------------------- 1 | import static org.junit.Assert.assertNotNull; 2 | import metamutator.UniqueTestGenerator; 3 | 4 | import org.junit.Test; 5 | 6 | import spoon.Launcher; 7 | import spoon.reflect.declaration.CtClass; 8 | 9 | 10 | public class UniqueTestGeneratorTest { 11 | 12 | @Test 13 | public void test() throws Exception { 14 | Launcher spoon = new Launcher(); 15 | spoon.addInputResource("src/test/java"); 16 | spoon.addProcessor(new UniqueTestGenerator()); 17 | spoon.run(); 18 | CtClass testClass = spoon.getFactory().Class().get("test.TestSuite"); 19 | System.out.println(testClass); 20 | assertNotNull(testClass); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/test/java/metamutator/ArithmeticOperatorMetaMutatorTest.java: -------------------------------------------------------------------------------- 1 | package metamutator; 2 | 3 | import static org.apache.commons.lang.reflect.MethodUtils.invokeExactMethod; 4 | import static org.junit.Assert.assertEquals; 5 | 6 | import org.junit.Test; 7 | 8 | import bsh.Interpreter; 9 | import spoon.Launcher; 10 | import spoon.reflect.declaration.CtClass; 11 | import spoon.reflect.visitor.filter.NamedElementFilter; 12 | 13 | public class ArithmeticOperatorMetaMutatorTest { 14 | 15 | @Test 16 | public void testArithmeticOperatorMetaMutator() throws Exception { 17 | // build the model and apply the transformation 18 | Launcher l = new Launcher(); 19 | l.addInputResource("src/test/java/resources/Bar.java"); 20 | l.addProcessor(new ArithmeticOperatorMetaMutator()); 21 | l.run(); 22 | 23 | // now we get the code of Foo 24 | CtClass c = l.getFactory().Package().getRootPackage().getElements(new NamedElementFilter<>(CtClass.class, "Bar")).get(0); 25 | 26 | // printing the metaprogram 27 | System.out.println("// Metaprogram: "); 28 | System.out.println(c.toString()); 29 | 30 | // we prepare an interpreter for the transformed code 31 | Interpreter bsh = new Interpreter(); 32 | 33 | // creating a new instance of the class 34 | Object o = ((Class)bsh.eval(c.toString())).newInstance(); 35 | 36 | // test with the first 37 | Selector sel=Selector.getSelectorByName(ArithmeticOperatorMetaMutator.PREFIX + "1"); 38 | 39 | // check PLUS 40 | sel.choose(0); 41 | assertEquals(5, invokeExactMethod(o, "op_add", new Object[] {2, 3})); 42 | 43 | // check MINUS 44 | sel.choose(1); 45 | assertEquals(5, invokeExactMethod(o, "op_add", new Object[] {10, 5})); 46 | 47 | // check MUL 48 | sel.choose(2); 49 | assertEquals(16, invokeExactMethod(o, "op_add", new Object[] {4, 4})); 50 | 51 | // check DIV 52 | sel.choose(3); 53 | assertEquals(4, invokeExactMethod(o, "op_add", new Object[] {20, 5})); 54 | 55 | // second selector 56 | sel=Selector.getSelectorByName(ArithmeticOperatorMetaMutator.PREFIX + "2"); 57 | 58 | 59 | // check MINUS 60 | sel.choose(0); 61 | assertEquals(5, invokeExactMethod(o, "op_minus", new Object[] {10, 5})); 62 | 63 | // check PLUS 64 | sel.choose(1); 65 | assertEquals(5, invokeExactMethod(o, "op_minus", new Object[] {2, 3})); 66 | 67 | // check MUL 68 | sel.choose(2); 69 | assertEquals(16, invokeExactMethod(o, "op_minus", new Object[] {4, 4})); 70 | 71 | // check DIV 72 | sel.choose(3); 73 | assertEquals(4, invokeExactMethod(o, "op_minus", new Object[] {20, 5})); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/test/java/metamutator/BinaryOperatorMetaMutatorTest.java: -------------------------------------------------------------------------------- 1 | package metamutator; 2 | import static org.apache.commons.lang.reflect.MethodUtils.invokeExactMethod; 3 | import static org.junit.Assert.assertEquals; 4 | import static org.junit.Assert.fail; 5 | 6 | import org.junit.Test; 7 | 8 | import spoon.Launcher; 9 | import spoon.reflect.declaration.CtClass; 10 | import bsh.Interpreter; 11 | import spoon.reflect.visitor.filter.NamedElementFilter; 12 | 13 | public class BinaryOperatorMetaMutatorTest { 14 | 15 | @Test 16 | public void testBinaryOperatorMetaMutator() throws Exception { 17 | int intialSelector = Selector.getAllSelectors().size(); 18 | // build the model and apply the transformation 19 | Launcher l = new Launcher(); 20 | l.addInputResource("src/test/java"); 21 | l.addProcessor(new LogicalExpressionMetaMutator()); 22 | l.run(); 23 | 24 | // now we get the code of Foo 25 | CtClass c = l.getFactory().Package().getRootPackage().getElements(new NamedElementFilter<>(CtClass.class, "Foo")).get(0); 26 | 27 | // printing the metaprogram 28 | System.out.println("// Metaprogram: "); 29 | System.out.println(c.toString()); 30 | 31 | // we prepare an interpreter for the transformed code 32 | Interpreter bsh = new Interpreter(); 33 | 34 | // there is no selector before loading the class 35 | assertEquals(intialSelector,Selector.getAllSelectors().size()); 36 | 37 | // creating a new instance of the class 38 | Object o = ((Class)bsh.eval(c.toString())).newInstance(); 39 | assertEquals(true,Selector.getAllSelectors().size() > 3); 40 | 41 | // test with the first 42 | Selector sel=Selector.getSelectorByName(LogicalExpressionMetaMutator.PREFIX + 2); 43 | 44 | // the initial version is OR 45 | assertEquals(true, invokeExactMethod(o, "op", new Object[] {Boolean.TRUE, Boolean.FALSE})); 46 | 47 | // now we activate the first metamutation (the initial OR) 48 | sel.choose(0); 49 | assertEquals(true, invokeExactMethod(o, "op", new Object[] {Boolean.TRUE, Boolean.FALSE})); 50 | 51 | // now we activate the second metamutation (AND) 52 | // and the expected result is false 53 | sel.choose(1); 54 | assertEquals(false, invokeExactMethod(o, "op", new Object[] {Boolean.TRUE, Boolean.FALSE})); 55 | 56 | // impossible option 57 | try { 58 | sel.choose(2); 59 | fail(); 60 | } 61 | catch (IllegalArgumentException expected){} 62 | 63 | // test with the second mutation hotspot 64 | Selector sel1=Selector.getSelectorByName( LogicalExpressionMetaMutator.PREFIX + "3"); 65 | sel1.choose(0);// GT 66 | assertEquals(false, invokeExactMethod(o, "op2", new Object[] {3, 3})); 67 | assertEquals(true, invokeExactMethod(o, "op2", new Object[] {5, 4})); 68 | sel1.choose(1); // EQ 69 | assertEquals(true, invokeExactMethod(o, "op2", new Object[] {3, 3})); 70 | assertEquals(false, invokeExactMethod(o, "op2", new Object[] {4, 3})); 71 | sel1.choose(2); // NE 72 | assertEquals(false, invokeExactMethod(o, "op2", new Object[] {3, 3})); 73 | assertEquals(true, invokeExactMethod(o, "op2", new Object[] {4, 3})); 74 | sel1.choose(3); // LT 75 | assertEquals(false, invokeExactMethod(o, "op2", new Object[] {3, 3})); 76 | assertEquals(true, invokeExactMethod(o, "op2", new Object[] {3, 4})); 77 | 78 | } 79 | } -------------------------------------------------------------------------------- /src/test/java/metamutator/ConstantReplacementMetaMutatorTest.java: -------------------------------------------------------------------------------- 1 | package metamutator; 2 | 3 | import static org.apache.commons.lang.reflect.MethodUtils.invokeExactMethod; 4 | import static org.junit.Assert.assertEquals; 5 | import org.junit.Test; 6 | import bsh.Interpreter; 7 | import spoon.Launcher; 8 | import spoon.reflect.declaration.CtClass; 9 | import spoon.reflect.visitor.filter.NamedElementFilter; 10 | 11 | public class ConstantReplacementMetaMutatorTest { 12 | 13 | @Test 14 | public void testConstantReplacementMetaMutator() throws Exception{ 15 | //clean selector 16 | Selector.reset(); 17 | 18 | Launcher l = new Launcher(); 19 | l.addInputResource("src/test/java/resources/Bar.java"); 20 | l.addProcessor(new IntegerConstantReplacementMetaMutator()); 21 | l.run(); 22 | // now we get the code of Foo 23 | CtClass c = l.getFactory().Package().getRootPackage().getElements(new NamedElementFilter<>(CtClass.class, "Bar")).get(0); 24 | 25 | // printing the metaprogram 26 | System.out.println("// Metaprogram: "); 27 | System.out.println(c.toString()); 28 | 29 | // we prepare an interpreter for the transformed code 30 | Interpreter bsh = new Interpreter(); 31 | // there is no selector before loading the class 32 | assertEquals(0,Selector.getAllSelectors().size()); 33 | // creating a new instance of the class 34 | Object o = ((Class)bsh.eval(c.toString())).newInstance(); 35 | assertEquals(1,Selector.getAllSelectors().size()); 36 | 37 | // test with the first 38 | Selector sel=Selector.getSelectorByName(IntegerConstantReplacementMetaMutator.PREFIX + "1"); 39 | 40 | sel.choose(0);//NULL 41 | assertEquals(0, invokeExactMethod(o, "op_constant", new Object[] {})); 42 | 43 | sel.choose(1); 44 | assertEquals(Integer.MAX_VALUE-1, invokeExactMethod(o, "op_constant", new Object[] {})); 45 | 46 | sel.choose(2); 47 | assertEquals(Integer.MIN_VALUE+1, invokeExactMethod(o, "op_constant", new Object[] {})); 48 | } 49 | } -------------------------------------------------------------------------------- /src/test/java/metamutator/LoopExpressionMetaMutatorTest.java: -------------------------------------------------------------------------------- 1 | package metamutator; 2 | import static org.junit.Assert.*; 3 | 4 | 5 | import org.junit.Test; 6 | 7 | import spoon.Launcher; 8 | import spoon.reflect.declaration.CtClass; 9 | import bsh.Interpreter; 10 | import spoon.reflect.visitor.filter.NamedElementFilter; 11 | 12 | import static org.apache.commons.lang.reflect.MethodUtils.*; 13 | 14 | public class LoopExpressionMetaMutatorTest { 15 | 16 | @Test 17 | public void testLoopExpressionMetaMutator() throws Exception { 18 | // build the model and apply the transformation 19 | Launcher l = new Launcher(); 20 | l.addInputResource("src/test/java/resources/Foo.java"); 21 | l.addProcessor(new LoopExpressionMetaMutator()); 22 | l.run(); 23 | 24 | // now we get the code of Foo 25 | CtClass c = l.getFactory().Package().getRootPackage().getElements(new NamedElementFilter<>(CtClass.class, "Foo")).get(0); 26 | 27 | // printing the metaprogram 28 | System.out.println("// Metaprogram: "); 29 | System.out.println(c.toString()); 30 | 31 | // we prepare an interpreter for the transformed code 32 | Interpreter bsh = new Interpreter(); 33 | // creating a new instance of the class 34 | Object o = ((Class)bsh.eval(c.toString())).newInstance(); 35 | 36 | Selector sel1=Selector.getSelectorByName( LoopExpressionMetaMutator.PREFIX + "1"); 37 | //sel1.choose(0);// NO ROUND 38 | // assertEquals(1, invokeExactMethod(o, "sum", new Object[] {15})); 39 | sel1.choose(1);// ROUNDS 3 40 | assertEquals(3, invokeExactMethod(o, "sum", new Object[] {15})); 41 | sel1.choose(2);// ROUNDS 100 42 | assertEquals(100, invokeExactMethod(o, "sum", new Object[] {150})); 43 | } 44 | } -------------------------------------------------------------------------------- /src/test/java/metamutator/MutantSearchSpaceExploratorTest.java: -------------------------------------------------------------------------------- 1 | package metamutator; 2 | import static org.junit.Assert.assertEquals; 3 | import static org.junit.Assert.assertFalse; 4 | import static org.junit.Assert.assertNotNull; 5 | import static org.junit.Assert.assertNull; 6 | import static org.junit.Assert.assertTrue; 7 | import static org.junit.Assert.fail; 8 | 9 | import java.io.File; 10 | import java.io.IOException; 11 | 12 | import org.junit.AfterClass; 13 | import org.junit.BeforeClass; 14 | 15 | import resources.footest.FooTest; 16 | 17 | import org.junit.Test; 18 | import org.junit.runner.JUnitCore; 19 | import org.junit.runner.Result; 20 | 21 | 22 | public class MutantSearchSpaceExploratorTest { 23 | 24 | 25 | @BeforeClass 26 | public static void before() { 27 | Selector.reset(); 28 | } 29 | 30 | @AfterClass 31 | public static void after() throws IOException { 32 | Selector.reset(); 33 | } 34 | 35 | static public class failingTest { 36 | @Test 37 | public void test() { 38 | 39 | } 40 | }; 41 | 42 | 43 | @Test 44 | public void testMutantSearchSpaceExplorator() throws Exception { 45 | 46 | JUnitCore core = new JUnitCore(); 47 | Result result = MutantSearchSpaceExplorator.runWithThread(Object.class, core); 48 | assertEquals(1,result.getFailureCount()); // no runnable methods, no test classes, message change between Junit'4.12 and Junit4.13 49 | 50 | Result result2 = MutantSearchSpaceExplorator.runWithThread(failingTest.class, core); 51 | assertEquals(0,result2.getFailureCount()); 52 | assertEquals(1,result2.getRunCount()); 53 | } 54 | 55 | 56 | 57 | /** 58 | * We launch the search of selector and try them 59 | * @throws Exception 60 | */ 61 | 62 | @Test 63 | public void TestMutantSearchFile () throws Exception 64 | { 65 | 66 | 67 | File f = new File("results/fail/resources/footest/FooTest"); 68 | File successFile = new File("results/success/resources/footest/FooTest"); 69 | 70 | f.mkdirs(); 71 | successFile.mkdirs(); 72 | 73 | // cleaning 74 | for (File i :f.listFiles()) { i.delete(); } 75 | for (File i :successFile.listFiles()) { i.delete(); } 76 | 77 | MutantSearchSpaceExplorator.runMetaProgramWith(FooTest.class); 78 | 79 | //Then we check the if the wanted file are created. 80 | 81 | assertTrue(f.exists()); 82 | assertTrue(successFile.exists()); 83 | 84 | File fm02 = new File("results/fail/resources/footest/FooTest/mutant_binaryLogicalOperatorHotSpot1_Op2.txt"); 85 | 86 | File fm04 = new File("results/fail/resources/footest/FooTest/mutant_binaryLogicalOperatorHotSpot2_Op2.txt"); 87 | File fm05 = new File("results/fail/resources/footest/FooTest/mutant_binaryLogicalOperatorHotSpot2_Op3.txt"); 88 | File fm06 = new File("results/fail/resources/footest/FooTest/mutant_binaryLogicalOperatorHotSpot2_Op4.txt"); 89 | File fm07 = new File("results/fail/resources/footest/FooTest/mutant_binaryLogicalOperatorHotSpot2_Op5.txt"); 90 | File fm08 = new File("results/fail/resources/footest/FooTest/mutant_binaryLogicalOperatorHotSpot2_Op6.txt"); 91 | 92 | File fm10 = new File("results/fail/resources/footest/FooTest/mutant_binaryLogicalOperatorHotSpot3_Op2.txt"); 93 | 94 | File fm12 = new File("results/fail/resources/footest/FooTest/mutant_binaryLogicalOperatorHotSpot4_Op2.txt"); 95 | 96 | File fm14 = new File("results/fail/resources/footest/FooTest/mutant_variableNullHotSpot1_Op2.txt"); 97 | 98 | 99 | assertEquals(9,f.listFiles().length); 100 | assertEquals(0,successFile.listFiles().length); 101 | 102 | assertTrue(fm02.exists()); 103 | assertTrue(fm04.exists()); 104 | assertTrue(fm05.exists()); 105 | assertTrue(fm06.exists()); 106 | assertTrue(fm07.exists()); 107 | assertTrue(fm08.exists()); 108 | assertTrue(fm10.exists()); 109 | assertTrue(fm12.exists()); 110 | assertTrue(fm14.exists()); 111 | 112 | } 113 | 114 | 115 | @Test 116 | public void TestMutantSearchDir () throws Exception 117 | { 118 | 119 | 120 | 121 | File f = new File("results/fail/resources/search_replay_test/SearchReplayTestClass"); 122 | File s = new File("results/success/resources/search_replay_test/SearchReplayTestClass"); 123 | 124 | f.mkdirs(); 125 | s.mkdirs(); 126 | 127 | // cleaning 128 | for (File i :f.listFiles()) { i.delete(); } 129 | for (File i :s.listFiles()) { i.delete(); } 130 | 131 | MutantSearchSpaceExplorator.runMetaProgramIn("target/test-classes","resources/search_replay_test"); 132 | 133 | 134 | assertTrue(f.exists()); 135 | assertTrue(s.exists()); 136 | 137 | 138 | File fm01 = new File("results/fail/resources/search_replay_test/SearchReplayTestClass/mutant_binaryLogicalOperatorHotSpot3_Op2.txt"); 139 | File fm11 = new File("results/fail/resources/search_replay_test/SearchReplayTestClass/mutant_binaryLogicalOperatorHotSpot3_Op3.txt"); 140 | File fm12 = new File("results/fail/resources/search_replay_test/SearchReplayTestClass/mutant_binaryLogicalOperatorHotSpot3_Op4.txt"); 141 | File fm13 = new File("results/fail/resources/search_replay_test/SearchReplayTestClass/mutant_variableNullHotSpot3_Op2.txt"); 142 | 143 | File fm00 = new File("results/fail/resources/search_replay_test/SearchReplayTestClass/mutant_binaryLogicalOperatorHotSpot3_Op1.txt"); 144 | File fm10 = new File("results/fail/resources/search_replay_test/SearchReplayTestClass/mutant_binaryLogicalOperatorHotSpot3_Op5.txt"); 145 | File fm14 = new File("results/fail/resources/search_replay_test/SearchReplayTestClass/mutant_binaryLogicalOperatorHotSpot3_Op6.txt"); 146 | File fm15 = new File("results/fail/resources/search_replay_test/SearchReplayTestClass/mutant_variableNullHotSpot3_Op1.txt"); 147 | 148 | File sm01 = new File("results/success/resources/search_replay_test/SearchReplayTestClass/mutant_binaryLogicalOperatorHotSpot3_Op2.txt"); 149 | File sm11 = new File("results/success/resources/search_replay_test/SearchReplayTestClass/mutant_binaryLogicalOperatorHotSpot3_Op3.txt"); 150 | File sm12 = new File("results/success/resources/search_replay_test/SearchReplayTestClass/mutant_binaryLogicalOperatorHotSpot3_Op4.txt"); 151 | File sm13 = new File("results/success/resources/search_replay_test/SearchReplayTestClass/mutant_variableNullHotSpot3_Op2.txt"); 152 | 153 | 154 | 155 | File sm00 = new File("results/success/resources/search_replay_test/SearchReplayTestClass/mutant_binaryLogicalOperatorHotSpot3_Op1.txt"); 156 | File sm10 = new File("results/success/resources/search_replay_test/SearchReplayTestClass/mutant_binaryLogicalOperatorHotSpot3_Op5.txt"); 157 | File sm14 = new File("results/success/resources/search_replay_test/SearchReplayTestClass/mutant_binaryLogicalOperatorHotSpot3_Op6.txt"); 158 | File sm15 = new File("results/success/resources/search_replay_test/SearchReplayTestClass/mutant_variableNullHotSpot3_Op1.txt"); 159 | 160 | assertTrue(fm01.exists()); 161 | assertTrue(fm11.exists()); 162 | assertTrue(fm12.exists()); 163 | assertTrue(fm13.exists()); 164 | 165 | assertFalse(fm00.exists()); 166 | assertFalse(fm10.exists()); 167 | assertFalse(fm14.exists()); 168 | assertFalse(fm15.exists()); 169 | 170 | 171 | 172 | assertFalse(sm01.exists()); 173 | assertFalse(sm11.exists()); 174 | assertFalse(sm12.exists()); 175 | assertFalse(sm13.exists()); 176 | 177 | 178 | //assertTrue(sm00.exists()); 179 | assertTrue(sm10.exists()); 180 | assertTrue(sm14.exists()); 181 | //assertTrue(sm15.exists()); 182 | 183 | File fm31 = new File("results/fail/resources/search_replay_test/SearchReplayTestClassBis/mutant_binaryLogicalOperatorHotSpot4_Op2.txt"); 184 | File fm41 = new File("results/fail/resources/search_replay_test/SearchReplayTestClassBis/mutant_binaryLogicalOperatorHotSpot4_Op3.txt"); 185 | File fm42 = new File("results/fail/resources/search_replay_test/SearchReplayTestClassBis/mutant_binaryLogicalOperatorHotSpot4_Op4.txt"); 186 | File fm43 = new File("results/fail/resources/search_replay_test/SearchReplayTestClassBis/mutant_variableNullHotSpot4_Op2.txt"); 187 | 188 | File fm30 = new File("results/fail/resources/search_replay_test/SearchReplayTestClassBis/mutant_binaryLogicalOperatorHotSpot4_Op1.txt"); 189 | File fm40 = new File("results/fail/resources/search_replay_test/SearchReplayTestClassBis/mutant_binaryLogicalOperatorHotSpot4_Op5.txt"); 190 | File fm44 = new File("results/fail/resources/search_replay_test/SearchReplayTestClassBis/mutant_binaryLogicalOperatorHotSpot4_Op6.txt"); 191 | File fm45 = new File("results/fail/resources/search_replay_test/SearchReplayTestClassBis/mutant_variableNullHotSpot4_Op1.txt"); 192 | 193 | File sm31 = new File("results/success/resources/search_replay_test/SearchReplayTestClassBis/mutant_binaryLogicalOperatorHotSpot4_Op2.txt"); 194 | File sm41 = new File("results/success/resources/search_replay_test/SearchReplayTestClassBis/mutant_binaryLogicalOperatorHotSpot4_Op3.txt"); 195 | File sm42 = new File("results/success/resources/search_replay_test/SearchReplayTestClassBis/mutant_binaryLogicalOperatorHotSpot4_Op4.txt"); 196 | File sm43 = new File("results/success/resources/search_replay_test/SearchReplayTestClassBis/mutant_variableNullHotSpot4_Op2.txt"); 197 | 198 | 199 | 200 | File sm30 = new File("results/success/resources/search_replay_test/SearchReplayTestClassBis/mutant_binaryLogicalOperatorHotSpot4_Op1.txt"); 201 | File sm40 = new File("results/success/resources/search_replay_test/SearchReplayTestClassBis/mutant_binaryLogicalOperatorHotSpot4_Op5.txt"); 202 | File sm44 = new File("results/success/resources/search_replay_test/SearchReplayTestClassBis/mutant_binaryLogicalOperatorHotSpot4_Op6.txt"); 203 | File sm45 = new File("results/success/resources/search_replay_test/SearchReplayTestClassBis/mutant_variableNullHotSpot4_Op1.txt"); 204 | 205 | assertTrue(fm31.exists()); 206 | assertTrue(fm41.exists()); 207 | assertTrue(fm42.exists()); 208 | assertTrue(fm43.exists()); 209 | 210 | assertFalse(fm30.exists()); 211 | assertFalse(fm40.exists()); 212 | assertFalse(fm44.exists()); 213 | assertFalse(fm45.exists()); 214 | 215 | 216 | 217 | assertFalse(sm31.exists()); 218 | assertFalse(sm41.exists()); 219 | assertFalse(sm42.exists()); 220 | assertFalse(sm43.exists()); 221 | 222 | 223 | //assertTrue(sm30.getAbsolutePath(),sm30.exists()); 224 | assertTrue(sm40.exists()); 225 | assertTrue(sm44.exists()); 226 | //assertTrue(sm45.exists()); 227 | 228 | 229 | } 230 | 231 | @Test 232 | public void testGetPackage(){ 233 | 234 | assertTrue(MutantSearchSpaceExplorator.getPackage("toto").equals("")); 235 | assertTrue(MutantSearchSpaceExplorator.getPackage("toto/titi").equals("toto")); 236 | assertTrue(MutantSearchSpaceExplorator.getPackage("toto/titi/tata").equals("toto.titi")); 237 | assertTrue(MutantSearchSpaceExplorator.getPackage("toto/titi/tata/tutu").equals("toto.titi.tata")); 238 | 239 | } 240 | 241 | 242 | 243 | } 244 | -------------------------------------------------------------------------------- /src/test/java/metamutator/NumericExpressionMetaMutatorTest.java: -------------------------------------------------------------------------------- 1 | package metamutator; 2 | import static org.junit.Assert.*; 3 | 4 | import java.util.List; 5 | 6 | import org.junit.Test; 7 | 8 | import spoon.Launcher; 9 | import spoon.reflect.code.CtVariableRead; 10 | import spoon.reflect.declaration.CtClass; 11 | import spoon.reflect.reference.CtTypeReference; 12 | import spoon.reflect.visitor.filter.NamedElementFilter; 13 | import bsh.Interpreter; 14 | import static org.apache.commons.lang.reflect.MethodUtils.*; 15 | 16 | public class NumericExpressionMetaMutatorTest { 17 | 18 | @Test 19 | public void testNumericExpressionMetaMutator() throws Exception { 20 | // build the model and apply the transformation 21 | Launcher l = new Launcher(); 22 | l.addInputResource("src/test/java/resources/Foo.java"); 23 | l.addProcessor(new NumericVariableMetaMutator()); 24 | l.run(); 25 | 26 | // now we get the code of Foo 27 | CtClass c = l.getFactory().Package().getRootPackage().getElements(new NamedElementFilter<>(CtClass.class, "Foo")).get(0); 28 | 29 | // printing the metaprogram 30 | System.out.println("// Metaprogram: "); 31 | System.out.println(c.toString()); 32 | 33 | // we prepare an interpreter for the transformed code 34 | Interpreter bsh = new Interpreter(); 35 | // creating a new instance of the class 36 | Object o = ((Class)bsh.eval(c.toString())).newInstance(); 37 | 38 | // test with the second mutation hotspot 39 | Selector sel1=Selector.getSelectorByName(NumericVariableMetaMutator.PREFIX + "1"); 40 | 41 | sel1.choose(0);// INIT B 42 | assertEquals(-1, invokeExactMethod(o, "add", new Object[] {3, -4})); 43 | sel1.choose(1);// ABS B 44 | assertEquals(1, invokeExactMethod(o, "add", new Object[] {3, -4})); 45 | sel1.choose(2);// MINUS B 46 | assertEquals(-6, invokeExactMethod(o, "add", new Object[] {3, 3})); 47 | sel1.choose(3);// INC B 48 | assertEquals(0, invokeExactMethod(o, "add", new Object[] {3, -4})); 49 | sel1.choose(4);// DEC B 50 | assertEquals(-2, invokeExactMethod(o, "add", new Object[] {3, -4})); 51 | 52 | NumericVariableMetaMutator numericPROC = new NumericVariableMetaMutator(); 53 | 54 | CtVariableRead candidate = l.getFactory().Core().createVariableRead(); 55 | 56 | // TEST IsNumeric() on typeReference 57 | // TEST GOOD TYPE 58 | CtTypeReference type = l.getFactory().Core().createTypeReference().setSimpleName(int.class.getName()); 59 | assertEquals(true,numericPROC.isNumber(type)); 60 | type = l.getFactory().Core().createTypeReference().setSimpleName(long.class.getName()); 61 | assertEquals(true,numericPROC.isNumber(type)); 62 | type = l.getFactory().Core().createTypeReference().setSimpleName(byte.class.getName()); 63 | assertEquals(true,numericPROC.isNumber(type)); 64 | type = l.getFactory().Core().createTypeReference().setSimpleName(float.class.getName()); 65 | assertEquals(true,numericPROC.isNumber(type)); 66 | type = l.getFactory().Core().createTypeReference().setSimpleName(double.class.getName()); 67 | assertEquals(true,numericPROC.isNumber(type)); 68 | 69 | // TEST NOT ALLOW TYPE 70 | type = l.getFactory().Core().createTypeReference().setSimpleName(String.class.getName()); 71 | assertEquals(false,numericPROC.isNumber(type)); 72 | type = l.getFactory().Core().createTypeReference().setSimpleName(boolean.class.getName()); 73 | assertEquals(false,numericPROC.isNumber(type)); 74 | type = l.getFactory().Core().createTypeReference().setSimpleName(Object.class.getName()); 75 | assertEquals(false,numericPROC.isNumber(type)); 76 | type = l.getFactory().Core().createTypeReference().setSimpleName(List.class.getName()); 77 | assertEquals(false,numericPROC.isNumber(type)); 78 | } 79 | } -------------------------------------------------------------------------------- /src/test/java/metamutator/ReplayMutantTest.java: -------------------------------------------------------------------------------- 1 | package metamutator; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | import static org.junit.Assert.assertFalse; 5 | import static org.junit.Assert.assertTrue; 6 | 7 | import java.io.File; 8 | import java.io.IOException; 9 | 10 | import org.apache.commons.io.FileUtils; 11 | import org.junit.AfterClass; 12 | import org.junit.Ignore; 13 | import org.junit.Test; 14 | 15 | import resources.footest.FooTest; 16 | import metamutator.MutantReplay; 17 | import metamutator.Selector; 18 | 19 | /* 20 | * This test class works only if you run MutantSearchTest before... 21 | */ 22 | @Ignore 23 | public class ReplayMutantTest { 24 | 25 | 26 | /** 27 | * Here we test one class in the replay mutant and check if the result is good 28 | * @throws Exception 29 | */ 30 | 31 | 32 | @Test 33 | public void TestMutantReplayFile() throws Exception{ 34 | 35 | MutantReplay.replayMetaProgramWith(FooTest.class); 36 | 37 | File f = new File("results/fail.replay/resources/footest/FooTest"); 38 | File s = new File("results/success.replay/resources/footest/FooTest"); 39 | 40 | 41 | //Then we check the if the wanted file are created. 42 | 43 | assertTrue(f.exists()); 44 | assertTrue(s.exists()); 45 | 46 | File fm02 = new File("results/fail.replay/resources/footest/FooTest/mutant_binaryLogicalOperatorHotSpot1_Op2.txt"); 47 | 48 | File fm04 = new File("results/fail.replay/resources/footest/FooTest/mutant_binaryLogicalOperatorHotSpot2_Op2.txt"); 49 | File fm05 = new File("results/fail.replay/resources/footest/FooTest/mutant_binaryLogicalOperatorHotSpot2_Op3.txt"); 50 | File fm06 = new File("results/fail.replay/resources/footest/FooTest/mutant_binaryLogicalOperatorHotSpot2_Op4.txt"); 51 | File fm07 = new File("results/fail.replay/resources/footest/FooTest/mutant_binaryLogicalOperatorHotSpot2_Op5.txt"); 52 | File fm08 = new File("results/fail.replay/resources/footest/FooTest/mutant_binaryLogicalOperatorHotSpot2_Op6.txt"); 53 | 54 | File fm10 = new File("results/fail.replay/resources/footest/FooTest/mutant_binaryLogicalOperatorHotSpot3_Op2.txt"); 55 | 56 | File fm12 = new File("results/fail.replay/resources/footest/FooTest/mutant_binaryLogicalOperatorHotSpot4_Op2.txt"); 57 | 58 | File fm14 = new File("results/fail.replay/resources/footest/FooTest/mutant_variableNullHotSpot1_Op2.txt"); 59 | 60 | 61 | assertEquals(9,f.listFiles().length); 62 | assertEquals(0,s.listFiles().length); 63 | 64 | assertTrue(fm02.exists()); 65 | assertTrue(fm04.exists()); 66 | assertTrue(fm05.exists()); 67 | assertTrue(fm06.exists()); 68 | assertTrue(fm07.exists()); 69 | assertTrue(fm08.exists()); 70 | assertTrue(fm10.exists()); 71 | assertTrue(fm12.exists()); 72 | assertTrue(fm14.exists()); 73 | 74 | Selector.reset(); 75 | } 76 | 77 | @Test 78 | public void TestMutantReplayDir() throws Exception{ 79 | File f; 80 | File s ; 81 | File fb; 82 | File sb ; 83 | 84 | MutantReplay.replayMetaProgramIn("target/test-classes/","resources/search_replay_test"); 85 | 86 | 87 | f = new File("results/fail.replay/resources/search_replay_test/SearchReplayTestClass"); 88 | s = new File("results/success.replay/resources/search_replay_test/SearchReplayTestClass"); 89 | fb = new File("results/fail.replay/resources/search_replay_test/SearchReplayTestClassBis"); 90 | sb = new File("results/success.replay/resources/search_replay_test/SearchReplayTestClassBis"); 91 | assertTrue(f.exists()); 92 | assertTrue(s.exists()); 93 | assertTrue(fb.exists()); 94 | assertTrue(sb.exists()); 95 | 96 | File fm01 = new File("results/fail.replay/resources/search_replay_test/SearchReplayTestClass/mutant_binaryLogicalOperatorHotSpot3_Op2.txt"); 97 | File fm11 = new File("results/fail.replay/resources/search_replay_test/SearchReplayTestClass/mutant_binaryLogicalOperatorHotSpot3_Op3.txt"); 98 | File fm12 = new File("results/fail.replay/resources/search_replay_test/SearchReplayTestClass/mutant_binaryLogicalOperatorHotSpot3_Op4.txt"); 99 | File fm13 = new File("results/fail.replay/resources/search_replay_test/SearchReplayTestClass/mutant_variableNullHotSpot3_Op2.txt"); 100 | 101 | File fm00 = new File("results/fail.replay/resources/search_replay_test/SearchReplayTestClass/mutant_binaryLogicalOperatorHotSpot3_Op1.txt"); 102 | File fm10 = new File("results/fail.replay/resources/search_replay_test/SearchReplayTestClass/mutant_binaryLogicalOperatorHotSpot3_Op5.txt"); 103 | File fm14 = new File("results/fail.replay/resources/search_replay_test/SearchReplayTestClass/mutant_binaryLogicalOperatorHotSpot3_Op6.txt"); 104 | File fm15 = new File("results/fail.replay/resources/search_replay_test/SearchReplayTestClass/mutant_variableNullHotSpot3_Op1.txt"); 105 | 106 | File sm01 = new File("results/success.replay/resources/search_replay_test/SearchReplayTestClass/mutant_binaryLogicalOperatorHotSpot3_Op2.txt"); 107 | File sm11 = new File("results/success.replay/resources/search_replay_test/SearchReplayTestClass/mutant_binaryLogicalOperatorHotSpot3_Op3.txt"); 108 | File sm12 = new File("results/success.replay/resources/search_replay_test/SearchReplayTestClass/mutant_binaryLogicalOperatorHotSpot3_Op4.txt"); 109 | File sm13 = new File("results/success.replay/resources/search_replay_test/SearchReplayTestClass/mutant_variableNullHotSpot3_Op2.txt"); 110 | 111 | 112 | 113 | File sm00 = new File("results/success.replay/resources/search_replay_test/SearchReplayTestClass/mutant_binaryLogicalOperatorHotSpot3_Op1.txt"); 114 | File sm10 = new File("results/success.replay/resources/search_replay_test/SearchReplayTestClass/mutant_binaryLogicalOperatorHotSpot3_Op5.txt"); 115 | File sm14 = new File("results/success.replay/resources/search_replay_test/SearchReplayTestClass/mutant_binaryLogicalOperatorHotSpot3_Op6.txt"); 116 | File sm15 = new File("results/success.replay/resources/search_replay_test/SearchReplayTestClass/mutant_variableNullHotSpot3_Op1.txt"); 117 | 118 | assertTrue(fm01.exists()); 119 | assertTrue(fm11.exists()); 120 | assertTrue(fm12.exists()); 121 | assertTrue(fm13.exists()); 122 | 123 | assertFalse(fm00.exists()); 124 | assertFalse(fm10.exists()); 125 | assertFalse(fm14.exists()); 126 | assertFalse(fm15.exists()); 127 | 128 | 129 | 130 | assertFalse(sm01.exists()); 131 | assertFalse(sm11.exists()); 132 | assertFalse(sm12.exists()); 133 | assertFalse(sm13.exists()); 134 | 135 | 136 | assertFalse(sm00.exists()); 137 | assertFalse(sm10.exists()); 138 | assertFalse(sm14.exists()); 139 | assertFalse(sm15.exists()); 140 | 141 | File fm31 = new File("results/fail.replay/resources/search_replay_test/SearchReplayTestClassBis/mutant_binaryLogicalOperatorHotSpot4_Op2.txt"); 142 | File fm41 = new File("results/fail.replay/resources/search_replay_test/SearchReplayTestClassBis/mutant_binaryLogicalOperatorHotSpot4_Op3.txt"); 143 | File fm42 = new File("results/fail.replay/resources/search_replay_test/SearchReplayTestClassBis/mutant_binaryLogicalOperatorHotSpot4_Op4.txt"); 144 | File fm43 = new File("results/fail.replay/resources/search_replay_test/SearchReplayTestClassBis/mutant_variableNullHotSpot4_Op2.txt"); 145 | 146 | File fm30 = new File("results/fail.replay/resources/search_replay_test/SearchReplayTestClassBis/mutant_binaryLogicalOperatorHotSpot4_Op1.txt"); 147 | File fm40 = new File("results/fail.replay/resources/search_replay_test/SearchReplayTestClassBis/mutant_binaryLogicalOperatorHotSpot4_Op5.txt"); 148 | File fm44 = new File("results/fail.replay/resources/search_replay_test/SearchReplayTestClassBis/mutant_binaryLogicalOperatorHotSpot4_Op6.txt"); 149 | File fm45 = new File("results/fail.replay/resources/search_replay_test/SearchReplayTestClassBis/mutant_variableNullHotSpot4_Op1.txt"); 150 | 151 | File sm31 = new File("results/success.replay/resources/search_replay_test/SearchReplayTestClassBis/mutant_binaryLogicalOperatorHotSpot4_Op2.txt"); 152 | File sm41 = new File("results/success.replay/resources/search_replay_test/SearchReplayTestClassBis/mutant_binaryLogicalOperatorHotSpot4_Op3.txt"); 153 | File sm42 = new File("results/success.replay/resources/search_replay_test/SearchReplayTestClassBis/mutant_binaryLogicalOperatorHotSpot4_Op4.txt"); 154 | File sm43 = new File("results/success.replay/resources/search_replay_test/SearchReplayTestClassBis/mutant_variableNullHotSpot4_Op2.txt"); 155 | 156 | 157 | 158 | File sm30 = new File("results/success.replay/resources/search_replay_test/SearchReplayTestClassBis/mutant_binaryLogicalOperatorHotSpot4_Op1.txt"); 159 | File sm40 = new File("results/success.replay/resources/search_replay_test/SearchReplayTestClassBis/mutant_binaryLogicalOperatorHotSpot4_Op5.txt"); 160 | File sm44 = new File("results/success.replay/resources/search_replay_test/SearchReplayTestClassBis/mutant_binaryLogicalOperatorHotSpot4_Op6.txt"); 161 | File sm45 = new File("results/success.replay/resources/search_replay_test/SearchReplayTestClassBis/mutant_variableNullHotSpot4_Op1.txt"); 162 | 163 | assertTrue(fm31.exists()); 164 | assertTrue(fm41.exists()); 165 | assertTrue(fm42.exists()); 166 | assertTrue(fm43.exists()); 167 | 168 | assertFalse(fm30.exists()); 169 | assertFalse(fm40.exists()); 170 | assertFalse(fm44.exists()); 171 | assertFalse(fm45.exists()); 172 | 173 | 174 | 175 | assertFalse(sm31.exists()); 176 | assertFalse(sm41.exists()); 177 | assertFalse(sm42.exists()); 178 | assertFalse(sm43.exists()); 179 | 180 | 181 | assertFalse(sm30.exists()); 182 | assertFalse(sm40.exists()); 183 | assertFalse(sm44.exists()); 184 | assertFalse(sm45.exists()); 185 | 186 | 187 | 188 | 189 | } 190 | 191 | @Test 192 | public void testGetPackage(){ 193 | 194 | assertTrue(MutantReplay.getPackage("toto").equals("")); 195 | assertTrue(MutantReplay.getPackage("toto/titi").equals("toto")); 196 | assertTrue(MutantReplay.getPackage("toto/titi/tata").equals("toto.titi")); 197 | assertTrue(MutantReplay.getPackage("toto/titi/tata/tutu").equals("toto.titi.tata")); 198 | 199 | } 200 | 201 | 202 | @AfterClass 203 | public static void after() throws IOException { 204 | Selector.reset(); 205 | File results = new File("results"); 206 | FileUtils.deleteDirectory(results); 207 | } 208 | 209 | } 210 | -------------------------------------------------------------------------------- /src/test/java/metamutator/ReturnReplacementOperatorMetaMutatorTest.java: -------------------------------------------------------------------------------- 1 | package metamutator; 2 | 3 | import static org.apache.commons.lang.reflect.MethodUtils.invokeExactMethod; 4 | import static org.junit.Assert.assertEquals; 5 | 6 | import org.junit.Test; 7 | 8 | import bsh.Interpreter; 9 | import spoon.Launcher; 10 | import spoon.reflect.declaration.CtClass; 11 | import spoon.reflect.visitor.filter.NamedElementFilter; 12 | 13 | public class ReturnReplacementOperatorMetaMutatorTest { 14 | 15 | @Test 16 | public void testReturnReplacementOperatorMetaMutator() throws Exception { 17 | // build the model and apply the transformation 18 | Launcher l = new Launcher(); 19 | l.addInputResource("src/test/java/resources/Bar.java"); 20 | l.addProcessor(new ReturnReplacementOperatorMetaMutator()); 21 | l.run(); 22 | 23 | // now we get the code of Foo 24 | CtClass c = l.getFactory().Package().getRootPackage().getElements(new NamedElementFilter<>(CtClass.class, "Bar")).get(0); 25 | 26 | // printing the metaprogram 27 | System.out.println("// Metaprogram: "); 28 | System.out.println(c.toString()); 29 | 30 | // we prepare an interpreter for the transformed code 31 | Interpreter bsh = new Interpreter(); 32 | 33 | // creating a new instance of the class 34 | Object o = ((Class)bsh.eval(c.toString())).newInstance(); 35 | 36 | // test with the first 37 | Selector sel = Selector.getSelectorByName(ReturnReplacementOperatorMetaMutator.PREFIX + "4"); 38 | 39 | // INIT 40 | sel.choose(0); 41 | assertEquals(5, invokeExactMethod(o, "op_add", new Object[] {2, 3})); 42 | 43 | // INT_MIN 44 | sel.choose(1); 45 | assertEquals(Integer.MIN_VALUE + 1, invokeExactMethod(o, "op_add", new Object[] {0, 0})); 46 | 47 | // INT_MAX 48 | sel.choose(2); 49 | assertEquals(Integer.MAX_VALUE - 1, invokeExactMethod(o, "op_add", new Object[] {0, 0})); 50 | 51 | // ZERO 52 | sel.choose(3); 53 | assertEquals(0, invokeExactMethod(o, "op_add", new Object[] {20, 5})); 54 | 55 | // test with the second 56 | sel = Selector.getSelectorByName(ReturnReplacementOperatorMetaMutator.PREFIX + "8"); 57 | 58 | // INIT 59 | sel.choose(0); 60 | assertEquals("Hello World", invokeExactMethod(o, "op_get_s", new Object[] {"Hello World"})); 61 | 62 | // NULL 63 | sel.choose(1); 64 | assertEquals(null, invokeExactMethod(o, "op_get_s", new Object[] {"Hello World"})); 65 | 66 | } 67 | } -------------------------------------------------------------------------------- /src/test/java/metamutator/StatementDeletionMetaMutatorTest.java: -------------------------------------------------------------------------------- 1 | package metamutator; 2 | 3 | import static org.apache.commons.lang.reflect.MethodUtils.invokeExactMethod; 4 | import static org.junit.Assert.assertEquals; 5 | import static org.junit.Assert.fail; 6 | 7 | import org.junit.Test; 8 | 9 | import bsh.Interpreter; 10 | import spoon.Launcher; 11 | import spoon.reflect.declaration.CtClass; 12 | import spoon.reflect.visitor.filter.NamedElementFilter; 13 | 14 | public class StatementDeletionMetaMutatorTest { 15 | 16 | public Object createStatementResourceObjectTransformed() throws Exception{ 17 | Selector.reset(); 18 | 19 | Launcher l = new Launcher(); 20 | l.addInputResource("src/test/java/resources/StatementResource.java"); 21 | l.addProcessor(new StatementDeletionMetaMutator()); 22 | l.run(); 23 | 24 | // now we get the code of StatementResource 25 | CtClass c = l.getFactory().Package().getRootPackage().getElements(new NamedElementFilter<>(CtClass.class, "StatementResource")).get(0); 26 | 27 | // printing the metaprogram 28 | System.out.println("// Metaprogram: "); 29 | System.out.println(c.toString()); 30 | 31 | // we prepare an interpreter for the transformed code 32 | Interpreter bsh = new Interpreter(); 33 | 34 | // creating a new instance of the class 35 | Object o = ((Class)bsh.eval(c.toString())).newInstance(); 36 | 37 | return o; 38 | 39 | } 40 | 41 | 42 | @Test 43 | public void testSwitchDeletionMetaMutator() throws Exception { 44 | Object o = createStatementResourceObjectTransformed(); 45 | // test with the first (SWITCH DELETION) 46 | Selector sel1=Selector.getSelectorByName(StatementDeletionMetaMutator.PREFIX + "7"); 47 | assertEquals('C', invokeExactMethod(o, "returnLetterFromSwitchCase", new Object[] {3})); 48 | sel1.choose(0); 49 | assertEquals('C', invokeExactMethod(o, "returnLetterFromSwitchCase", new Object[] {3})); 50 | sel1.choose(1); 51 | assertEquals('\u0000', invokeExactMethod(o, "returnLetterFromSwitchCase", new Object[] {3})); 52 | 53 | try { 54 | sel1.choose(2); 55 | fail(); 56 | } 57 | catch (IllegalArgumentException expected){} 58 | } 59 | 60 | @Test 61 | public void testIfDeletionMetaMutator() throws Exception { 62 | Object o = createStatementResourceObjectTransformed(); 63 | //IF DELETION 64 | Selector sel5=Selector.getSelectorByName(StatementDeletionMetaMutator.PREFIX + "1"); 65 | assertEquals(10, invokeExactMethod(o, "returnMax10", new Object[] {13})); 66 | sel5.choose(0); 67 | assertEquals(10, invokeExactMethod(o, "returnMax10", new Object[] {13})); 68 | sel5.choose(1); 69 | assertEquals(0, invokeExactMethod(o, "returnMax10", new Object[] {13})); 70 | try { 71 | sel5.choose(2); 72 | fail(); 73 | } 74 | catch (IllegalArgumentException expected){} 75 | } 76 | 77 | @Test 78 | public void testDoDeletionMetaMutator() throws Exception { 79 | Object o = createStatementResourceObjectTransformed(); 80 | //DO DELETION 81 | Selector sel6=Selector.getSelectorByName(StatementDeletionMetaMutator.PREFIX + "5"); 82 | assertEquals(18, invokeExactMethod(o, "returnTotalFromDo", new Object[] {18})); 83 | sel6.choose(0); 84 | assertEquals(18, invokeExactMethod(o, "returnTotalFromDo", new Object[] {18})); 85 | sel6.choose(1); 86 | assertEquals(0, invokeExactMethod(o, "returnTotalFromDo", new Object[] {18})); 87 | try { 88 | sel6.choose(2); 89 | fail(); 90 | } 91 | catch (IllegalArgumentException expected){} 92 | } 93 | 94 | @Test 95 | public void testForDeletionMetaMutator() throws Exception { 96 | Object o = createStatementResourceObjectTransformed(); 97 | //FOR DELETION 98 | Selector sel7=Selector.getSelectorByName(StatementDeletionMetaMutator.PREFIX + "3"); 99 | assertEquals(18, invokeExactMethod(o, "returnTotalFromFor", new Object[] {18})); 100 | sel7.choose(0); 101 | assertEquals(18, invokeExactMethod(o, "returnTotalFromFor", new Object[] {18})); 102 | sel7.choose(1); 103 | assertEquals(0, invokeExactMethod(o, "returnTotalFromFor", new Object[] {18})); 104 | try { 105 | sel7.choose(2); 106 | fail(); 107 | } 108 | catch (IllegalArgumentException expected){} 109 | 110 | } 111 | 112 | @Test 113 | public void testWhileDeletionMetaMutator() throws Exception { 114 | Object o = createStatementResourceObjectTransformed(); 115 | Selector sel8=Selector.getSelectorByName(StatementDeletionMetaMutator.PREFIX + "4"); 116 | assertEquals(18, invokeExactMethod(o, "returnTotalFromWhile", new Object[] {18})); 117 | sel8.choose(0); 118 | assertEquals(18, invokeExactMethod(o, "returnTotalFromWhile", new Object[] {18})); 119 | sel8.choose(1); 120 | assertEquals(0, invokeExactMethod(o, "returnTotalFromWhile", new Object[] {18})); 121 | try { 122 | sel8.choose(2); 123 | fail(); 124 | } 125 | catch (IllegalArgumentException expected){} 126 | 127 | } 128 | 129 | @Test 130 | public void testForEachDeletionMetaMutator() throws Exception { 131 | Object o = createStatementResourceObjectTransformed(); 132 | //FOREACH DELETION 133 | Selector sel9=Selector.getSelectorByName(StatementDeletionMetaMutator.PREFIX + "6"); 134 | assertEquals(13, invokeExactMethod(o, "returntotalFromForEachFromArray", new Object[] {new int[]{2,5,6}})); 135 | sel9.choose(0); 136 | assertEquals(13, invokeExactMethod(o, "returntotalFromForEachFromArray", new Object[] {new int[]{2,5,6}})); 137 | sel9.choose(1); 138 | assertEquals(0, invokeExactMethod(o, "returntotalFromForEachFromArray", new Object[] {new int[]{2,5,6}})); 139 | try { 140 | sel9.choose(2); 141 | fail(); 142 | } 143 | catch (IllegalArgumentException expected){} 144 | 145 | } 146 | 147 | @Test 148 | public void testAssignmentInIf() throws Exception { 149 | Object o = createStatementResourceObjectTransformed(); 150 | //FOREACH DELETION 151 | Selector sel10=Selector.getSelectorByName(StatementDeletionMetaMutator.PREFIX + "11"); 152 | assertEquals("Bonjour", invokeExactMethod(o, "BonjourOrHello", new Object[] {true})); 153 | sel10.choose(0); 154 | assertEquals("Bonjour", invokeExactMethod(o, "BonjourOrHello", new Object[] {true})); 155 | sel10.choose(1); 156 | assertEquals(null, invokeExactMethod(o, "BonjourOrHello", new Object[] {true})); 157 | try { 158 | sel10.choose(2); 159 | fail(); 160 | } 161 | catch (IllegalArgumentException expected){} 162 | 163 | } 164 | 165 | } -------------------------------------------------------------------------------- /src/test/java/metamutator/VariabletoNullMetaMutatorTest.java: -------------------------------------------------------------------------------- 1 | package metamutator; 2 | import static org.apache.commons.lang.reflect.MethodUtils.invokeExactMethod; 3 | import static org.junit.Assert.assertEquals; 4 | import static org.junit.Assert.fail; 5 | 6 | import org.junit.BeforeClass; 7 | 8 | import org.junit.Test; 9 | 10 | import spoon.Launcher; 11 | import spoon.reflect.declaration.CtClass; 12 | import bsh.Interpreter; 13 | import spoon.reflect.visitor.filter.NamedElementFilter; 14 | 15 | public class VariabletoNullMetaMutatorTest { 16 | 17 | @BeforeClass 18 | public static void before() { 19 | Selector.reset(); 20 | } 21 | 22 | 23 | @Test 24 | public void testChangetoNullMetaMutator() throws Exception { 25 | 26 | // build the model and apply the transformation 27 | Launcher l = new Launcher(); 28 | l.addInputResource("src/test/java/resources/foo"); 29 | l.addProcessor(new VariabletoNullMetaMutator()); 30 | l.run(); 31 | // now we get the code of Foo 32 | CtClass c = l.getFactory().Package().getRootPackage().getElements(new NamedElementFilter<>(CtClass.class, "Foo")).get(0); 33 | 34 | // printing the metaprogram 35 | System.out.println("// Metaprogram: "); 36 | System.out.println(c.toString()); 37 | 38 | // we prepare an interpreter for the transformed code 39 | Interpreter bsh = new Interpreter(); 40 | 41 | // there is no selector before loading the class 42 | assertEquals(0,Selector.getAllSelectors().size()); 43 | 44 | // creating a new instance of the class 45 | Object o = ((Class)bsh.eval(c.toString())).newInstance(); 46 | assertEquals(1,Selector.getAllSelectors().size()); 47 | 48 | // test with the first 49 | Selector sel=Selector.getSelectorByName("_variableNullHotSpot1"); 50 | 51 | // the initial version normaly, don't affect anythings 52 | assertEquals(true, invokeExactMethod(o, "op4", new Object[] {})); 53 | 54 | // now we activate the first metamutation (we dont touch the affectation) 55 | sel.choose(0); 56 | assertEquals(true, invokeExactMethod(o, "op4", new Object[] {})); 57 | 58 | // now we activate the second metamutation (Null) 59 | // and the expected result is false 60 | sel.choose(1); 61 | assertEquals(false, invokeExactMethod(o, "op4", new Object[] {})); 62 | 63 | // impossible option 64 | try { 65 | sel.choose(2); 66 | fail(); 67 | } 68 | catch (IllegalArgumentException expected){} 69 | 70 | 71 | } 72 | 73 | 74 | } -------------------------------------------------------------------------------- /src/test/java/resources/Bar.java: -------------------------------------------------------------------------------- 1 | package resources; 2 | public class Bar { 3 | 4 | public boolean op(Boolean a, Boolean b) { 5 | return a || b; 6 | } 7 | 8 | public boolean op2(Integer a, Integer b) { 9 | return a > b; 10 | } 11 | 12 | public boolean op3(Class c) { 13 | return Foo.class == c; 14 | } 15 | 16 | public Integer op_add(Integer a, Integer b){ 17 | return a + b; 18 | } 19 | 20 | public Integer op_minus(Integer a, Integer b){ 21 | return a - b; 22 | } 23 | 24 | public String op_concat_ss(String a, String b){ 25 | return a + b; 26 | } 27 | 28 | public String op_concat_is(Integer a, String b){ 29 | return a + b; 30 | } 31 | 32 | public String op_get_s(String a){ 33 | return a; 34 | } 35 | 36 | public boolean op_get_b(Boolean a){ 37 | return a; 38 | } 39 | 40 | public int op_constant() { 41 | int i = 42; 42 | return i; 43 | } 44 | } -------------------------------------------------------------------------------- /src/test/java/resources/Foo.java: -------------------------------------------------------------------------------- 1 | 2 | package resources; 3 | 4 | public class Foo { 5 | final int varinchangeable = 1; 6 | public boolean op(Boolean a, Boolean b) { 7 | return a || b; 8 | } 9 | 10 | public boolean op2(Integer a, Integer b) { 11 | return a > b; 12 | } 13 | 14 | public boolean op3(Class c) { 15 | return Foo.class==c; 16 | } 17 | 18 | public int add(Integer a, Integer b) { 19 | int c = a + b; 20 | return c; 21 | } 22 | 23 | public int sum(Integer a) { 24 | int b = 0; 25 | do{ 26 | b++; 27 | a--; 28 | }while(a > 1); 29 | return b; 30 | } 31 | } -------------------------------------------------------------------------------- /src/test/java/resources/StatementResource.java: -------------------------------------------------------------------------------- 1 | package resources; 2 | 3 | public class StatementResource { 4 | 5 | 6 | public StatementResource(){ 7 | 8 | } 9 | 10 | public int returnMax10(Integer a) { 11 | if(a < 10){ 12 | return a; 13 | } 14 | else{ 15 | return 10; 16 | } 17 | } 18 | 19 | public void throwException() throws Exception{ 20 | throw new Exception(); 21 | } 22 | 23 | public int returnTotalFromFor(Integer total){ 24 | int i = 0; 25 | for(i=0; i b; 11 | } 12 | 13 | public boolean op3(Class c) { 14 | return Foo.class==c; 15 | } 16 | 17 | public boolean op4(){ 18 | String medt = "Theobaldie"; 19 | return medt != null; 20 | } 21 | } -------------------------------------------------------------------------------- /src/test/java/resources/foo_spooned/Foo.java: -------------------------------------------------------------------------------- 1 | package resources.foo_spooned; 2 | 3 | 4 | public class Foo { 5 | public boolean op(java.lang.Boolean a, java.lang.Boolean b) { 6 | return ((_binaryLogicalOperatorHotSpot1.is(spoon.reflect.code.BinaryOperatorKind.OR) && (a || b)) || (_binaryLogicalOperatorHotSpot1.is(spoon.reflect.code.BinaryOperatorKind.AND) && (a && b))); 7 | } 8 | 9 | public boolean op2(java.lang.Integer a, java.lang.Integer b) { 10 | return ((_binaryLogicalOperatorHotSpot2.is(spoon.reflect.code.BinaryOperatorKind.EQ) && (a == b)) || (_binaryLogicalOperatorHotSpot2.is(spoon.reflect.code.BinaryOperatorKind.NE) && (a != b)) || (_binaryLogicalOperatorHotSpot2.is(spoon.reflect.code.BinaryOperatorKind.LT) && (a < b)) || (_binaryLogicalOperatorHotSpot2.is(spoon.reflect.code.BinaryOperatorKind.GT) && (a > b)) || (_binaryLogicalOperatorHotSpot2.is(spoon.reflect.code.BinaryOperatorKind.LE) && (a <= b)) || (_binaryLogicalOperatorHotSpot2.is(spoon.reflect.code.BinaryOperatorKind.GE) && (a >= b))); 11 | } 12 | 13 | public boolean op3(java.lang.Class c) { 14 | return ((_binaryLogicalOperatorHotSpot3.is(spoon.reflect.code.BinaryOperatorKind.EQ) && ((resources.foo.Foo.class) == c)) || (_binaryLogicalOperatorHotSpot3.is(spoon.reflect.code.BinaryOperatorKind.NE) && ((resources.foo.Foo.class) != c))); 15 | } 16 | 17 | public boolean op4() { 18 | java.lang.String medt = ((_variableNullHotSpot1.is(metamutator.Null.NO))?"Theobaldie":null); 19 | return ((_binaryLogicalOperatorHotSpot4.is(spoon.reflect.code.BinaryOperatorKind.EQ) && (medt == null)) || (_binaryLogicalOperatorHotSpot4.is(spoon.reflect.code.BinaryOperatorKind.NE) && (medt != null))); 20 | } 21 | 22 | private static final metamutator.Selector _binaryLogicalOperatorHotSpot1 = metamutator.Selector.of(new spoon.reflect.code.BinaryOperatorKind[]{spoon.reflect.code.BinaryOperatorKind.OR,spoon.reflect.code.BinaryOperatorKind.AND}).in(resources.foo.Foo.class).id("_binaryLogicalOperatorHotSpot1"); 23 | 24 | private static final metamutator.Selector _binaryLogicalOperatorHotSpot2 = metamutator.Selector.of(new spoon.reflect.code.BinaryOperatorKind[]{spoon.reflect.code.BinaryOperatorKind.GT,spoon.reflect.code.BinaryOperatorKind.EQ,spoon.reflect.code.BinaryOperatorKind.NE,spoon.reflect.code.BinaryOperatorKind.LT,spoon.reflect.code.BinaryOperatorKind.LE,spoon.reflect.code.BinaryOperatorKind.GE}).in(resources.foo.Foo.class).id("_binaryLogicalOperatorHotSpot2"); 25 | 26 | private static final metamutator.Selector _binaryLogicalOperatorHotSpot3 = metamutator.Selector.of(new spoon.reflect.code.BinaryOperatorKind[]{spoon.reflect.code.BinaryOperatorKind.EQ,spoon.reflect.code.BinaryOperatorKind.NE}).in(resources.foo.Foo.class).id("_binaryLogicalOperatorHotSpot3"); 27 | 28 | private static final metamutator.Selector _binaryLogicalOperatorHotSpot4 = metamutator.Selector.of(new spoon.reflect.code.BinaryOperatorKind[]{spoon.reflect.code.BinaryOperatorKind.NE,spoon.reflect.code.BinaryOperatorKind.EQ}).in(resources.foo.Foo.class).id("_binaryLogicalOperatorHotSpot4"); 29 | 30 | private static final metamutator.Selector _variableNullHotSpot1 = metamutator.Selector.of(new metamutator.Null[]{metamutator.Null.NO,metamutator.Null.YES}).in(resources.foo.Foo.class).id("_variableNullHotSpot1"); 31 | } 32 | 33 | -------------------------------------------------------------------------------- /src/test/java/resources/footest/FooTest.java: -------------------------------------------------------------------------------- 1 | package resources.footest; 2 | 3 | import java.nio.channels.Selector; 4 | 5 | import org.junit.Assert; 6 | import org.junit.Test; 7 | 8 | import resources.foo_spooned.Foo; 9 | 10 | public class FooTest { 11 | 12 | static Foo foo = new Foo(); 13 | 14 | @Test 15 | public void testOp() { 16 | Assert.assertEquals(true, foo.op(false, true)); 17 | Assert.assertEquals(true, foo.op(true, false)); 18 | Assert.assertEquals(true, foo.op(true, true)); 19 | Assert.assertEquals(false, foo.op(false, false)); 20 | } 21 | 22 | @Test 23 | public void testOp2() { 24 | Assert.assertEquals(true, foo.op2(7, 2)); 25 | Assert.assertEquals(false, foo.op2(1, 2)); 26 | Assert.assertEquals(false, foo.op2(2, 2)); 27 | } 28 | 29 | @Test 30 | public void testOp3() { 31 | Assert.assertEquals(false, foo.op3(new java.lang.String().getClass())); 32 | 33 | } 34 | 35 | @Test 36 | public void testOp4() { 37 | Assert.assertEquals(true, foo.op4()); 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /src/test/java/resources/search_replay_spoon/search_replay_src/SearchReplayClass.java: -------------------------------------------------------------------------------- 1 | package resources.search_replay_spoon.search_replay_src; 2 | 3 | 4 | public class SearchReplayClass { 5 | public SearchReplayClass() { 6 | } 7 | 8 | public boolean op() { 9 | int a = 2; 10 | java.lang.String b = ((_variableNullHotSpot3.is(metamutator.Null.NO))?"2":null); 11 | return ((_binaryLogicalOperatorHotSpot3.is(spoon.reflect.code.BinaryOperatorKind.EQ) && (a == (java.lang.Integer.parseInt(b)))) || (_binaryLogicalOperatorHotSpot3.is(spoon.reflect.code.BinaryOperatorKind.NE) && (a != (java.lang.Integer.parseInt(b)))) || (_binaryLogicalOperatorHotSpot3.is(spoon.reflect.code.BinaryOperatorKind.LT) && (a < (java.lang.Integer.parseInt(b)))) || (_binaryLogicalOperatorHotSpot3.is(spoon.reflect.code.BinaryOperatorKind.GT) && (a > (java.lang.Integer.parseInt(b)))) || (_binaryLogicalOperatorHotSpot3.is(spoon.reflect.code.BinaryOperatorKind.LE) && (a <= (java.lang.Integer.parseInt(b)))) || (_binaryLogicalOperatorHotSpot3.is(spoon.reflect.code.BinaryOperatorKind.GE) && (a >= (java.lang.Integer.parseInt(b))))); 12 | } 13 | 14 | private static final metamutator.Selector _binaryLogicalOperatorHotSpot3 = metamutator.Selector.of(new spoon.reflect.code.BinaryOperatorKind[]{spoon.reflect.code.BinaryOperatorKind.EQ,spoon.reflect.code.BinaryOperatorKind.NE,spoon.reflect.code.BinaryOperatorKind.LT,spoon.reflect.code.BinaryOperatorKind.GT,spoon.reflect.code.BinaryOperatorKind.LE,spoon.reflect.code.BinaryOperatorKind.GE}).in(resources.search_replay_src.SearchReplayClass.class).id("_binaryLogicalOperatorHotSpot3"); 15 | 16 | private static final metamutator.Selector _variableNullHotSpot3 = metamutator.Selector.of(new metamutator.Null[]{metamutator.Null.NO,metamutator.Null.YES}).in(resources.search_replay_src.SearchReplayClass.class).id("_variableNullHotSpot3"); 17 | } 18 | 19 | -------------------------------------------------------------------------------- /src/test/java/resources/search_replay_spoon/search_replay_src/SearchReplayClassBis.java: -------------------------------------------------------------------------------- 1 | package resources.search_replay_spoon.search_replay_src; 2 | 3 | 4 | public class SearchReplayClassBis { 5 | public SearchReplayClassBis() { 6 | } 7 | 8 | public boolean op() { 9 | int a = 1; 10 | java.lang.String b = ((_variableNullHotSpot4.is(metamutator.Null.NO))?"1":null); 11 | return ((_binaryLogicalOperatorHotSpot4.is(spoon.reflect.code.BinaryOperatorKind.EQ) && (a == (java.lang.Integer.parseInt(b)))) || (_binaryLogicalOperatorHotSpot4.is(spoon.reflect.code.BinaryOperatorKind.NE) && (a != (java.lang.Integer.parseInt(b)))) || (_binaryLogicalOperatorHotSpot4.is(spoon.reflect.code.BinaryOperatorKind.LT) && (a < (java.lang.Integer.parseInt(b)))) || (_binaryLogicalOperatorHotSpot4.is(spoon.reflect.code.BinaryOperatorKind.GT) && (a > (java.lang.Integer.parseInt(b)))) || (_binaryLogicalOperatorHotSpot4.is(spoon.reflect.code.BinaryOperatorKind.LE) && (a <= (java.lang.Integer.parseInt(b)))) || (_binaryLogicalOperatorHotSpot4.is(spoon.reflect.code.BinaryOperatorKind.GE) && (a >= (java.lang.Integer.parseInt(b))))); 12 | } 13 | 14 | private static final metamutator.Selector _binaryLogicalOperatorHotSpot4 = metamutator.Selector.of(new spoon.reflect.code.BinaryOperatorKind[]{spoon.reflect.code.BinaryOperatorKind.EQ,spoon.reflect.code.BinaryOperatorKind.NE,spoon.reflect.code.BinaryOperatorKind.LT,spoon.reflect.code.BinaryOperatorKind.GT,spoon.reflect.code.BinaryOperatorKind.LE,spoon.reflect.code.BinaryOperatorKind.GE}).in(resources.search_replay_src.SearchReplayClassBis.class).id("_binaryLogicalOperatorHotSpot4"); 15 | 16 | private static final metamutator.Selector _variableNullHotSpot4 = metamutator.Selector.of(new metamutator.Null[]{metamutator.Null.NO,metamutator.Null.YES}).in(resources.search_replay_src.SearchReplayClassBis.class).id("_variableNullHotSpot4"); 17 | } 18 | 19 | -------------------------------------------------------------------------------- /src/test/java/resources/search_replay_src/SearchReplayClass.java: -------------------------------------------------------------------------------- 1 | package resources.search_replay_src; 2 | 3 | public class SearchReplayClass { 4 | 5 | public SearchReplayClass() 6 | { 7 | 8 | } 9 | 10 | public boolean op(){ 11 | int a = 2; 12 | String b = "2"; 13 | return a == Integer.parseInt(b); 14 | } 15 | 16 | } -------------------------------------------------------------------------------- /src/test/java/resources/search_replay_src/SearchReplayClassBis.java: -------------------------------------------------------------------------------- 1 | package resources.search_replay_src; 2 | 3 | 4 | public class SearchReplayClassBis { 5 | 6 | public SearchReplayClassBis() 7 | { 8 | 9 | } 10 | 11 | public boolean op(){ 12 | int a = 1; 13 | String b = "1"; 14 | return a == Integer.parseInt(b); 15 | } 16 | 17 | } -------------------------------------------------------------------------------- /src/test/java/resources/search_replay_test/SearchReplayTestClass.java: -------------------------------------------------------------------------------- 1 | package resources.search_replay_test; 2 | import static org.junit.Assert.assertTrue; 3 | 4 | import org.junit.Test; 5 | 6 | import resources.search_replay_spoon.search_replay_src.SearchReplayClass; 7 | 8 | public class SearchReplayTestClass { 9 | 10 | static SearchReplayClass sRC = new SearchReplayClass(); 11 | @Test 12 | public void op(){ 13 | 14 | assertTrue(sRC.op()); 15 | } 16 | 17 | } -------------------------------------------------------------------------------- /src/test/java/resources/search_replay_test/SearchReplayTestClassBis.java: -------------------------------------------------------------------------------- 1 | 2 | package resources.search_replay_test; 3 | import static org.junit.Assert.assertTrue; 4 | 5 | import org.junit.Test; 6 | 7 | import resources.search_replay_spoon.search_replay_src.SearchReplayClassBis; 8 | 9 | public class SearchReplayTestClassBis { 10 | 11 | static SearchReplayClassBis sRCB = new SearchReplayClassBis(); 12 | 13 | @Test 14 | public void op(){ 15 | 16 | assertTrue(sRCB.op()); 17 | } 18 | 19 | } --------------------------------------------------------------------------------