From 18fe2cda0c72d34ae28244bf756504a9a4f9cb13 Mon Sep 17 00:00:00 2001 From: rjust Date: Wed, 9 Aug 2017 00:42:50 -0400 Subject: [PATCH 01/13] Added a triggering test for issue #87. --- framework/test/test_mutation_analysis.sh | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/framework/test/test_mutation_analysis.sh b/framework/test/test_mutation_analysis.sh index a7eb4ae3c..0b5e119e6 100755 --- a/framework/test/test_mutation_analysis.sh +++ b/framework/test/test_mutation_analysis.sh @@ -78,5 +78,29 @@ num_mutants_killed=$(tail -n1 "$summary_file" | cut -f3 -d',') # TODO Would be nice to test the number of excluded mutants. In order to do it # Major has to write that number to the '$pid_bid_dir/summary.csv' file. +######################################################################## +# Test mutation analysis when explicitly providing the classes to mutate + +# Exclude all generated mutants +instrument_classes="$pid_bid_dir/instrument_classes.txt" +echo "org.apache.commons.lang3.LocaleUtils" > "$instrument_classes" + +defects4j mutation -w "$pid_bid_dir" -i "$instrument_classes" || die "Mutation analysis (instrument LocaleUtils) failed!" + +# The last row of 'summary.csv' does not have an end of line character. +# Otherwise, using wc would be more intuitive. +num_rows=$(grep -c "^" "$summary_file") +[ "$num_rows" -eq "2" ] || die "Unexpected number of lines in '$summary_file'!" + +# Columns of summary (csv) file: +# MutantsGenerated,MutantsCovered,MutantsKilled,MutantsLive,RuntimePreprocSeconds,RuntimeAnalysisSeconds +num_mutants_generated=$(tail -n1 "$summary_file" | cut -f1 -d',') +num_mutants_covered=$(tail -n1 "$summary_file" | cut -f2 -d',') +num_mutants_killed=$(tail -n1 "$summary_file" | cut -f3 -d',') + +[ "$num_mutants_generated" -eq 184 ] || die "$num_mutants_generated mutants have been generated!" +[ "$num_mutants_covered" -eq 184 ] || die "$num_mutants_covered mutants have been covered!" +[ "$num_mutants_killed" -eq 158 ] || die "$num_mutants_killed mutants have been killed!" + # Clean up rm -rf "$pid_bid_dir" From 9e88766908679ecc365acfdb895e24b18965cbba Mon Sep 17 00:00:00 2001 From: rjust Date: Wed, 9 Aug 2017 01:04:59 -0400 Subject: [PATCH 02/13] Refactored a test script. --- framework/test/test_mutation_analysis.sh | 110 +++++++++++------------ 1 file changed, 53 insertions(+), 57 deletions(-) diff --git a/framework/test/test_mutation_analysis.sh b/framework/test/test_mutation_analysis.sh index 0b5e119e6..3ace886c0 100755 --- a/framework/test/test_mutation_analysis.sh +++ b/framework/test/test_mutation_analysis.sh @@ -13,7 +13,8 @@ HERE=$(cd `dirname $0` && pwd) source "$HERE/test.include" || exit 1 init -pid="Lang" # any pid-bid should work +# Any version should work, but the test cases below are specific to this version +pid="Lang" bid="1f" pid_bid_dir="$TMP_DIR/$pid-$bid" rm -rf "$pid_bid_dir" @@ -22,85 +23,80 @@ rm -rf "$pid_bid_dir" summary_file="$pid_bid_dir/summary.csv" mutants_file="$pid_bid_dir/mutants.log" +################################################################################ +# +# Check whether the mutation analysis results (summary.csv) match the expectations. +# +_check_mutation_result() { + [ $# -eq 3 ] || die "usage: ${FUNCNAME[0]} \ + \ + \ + " + local exp_mut_gen=$1 + local exp_mut_cov=$2 + local exp_mut_kill=$3 + + # Make sure Major generated the expected data files + [ -s "$mutants_file" ] || die "'$mutants_file' doesn't exist or is empty!" + [ -s "$summary_file" ] || die "'$summary_file' doesn't exist or is empty!" + + # The last row of 'summary.csv' does not have an end of line character. + # Otherwise, using wc would be more intuitive. + local num_rows=$(grep -c "^" "$summary_file") + [ "$num_rows" -eq "2" ] || die "Unexpected number of lines in '$summary_file'!" + + # Columns of summary (csv) file: + # MutantsGenerated,MutantsCovered,MutantsKilled,MutantsLive,RuntimePreprocSeconds,RuntimeAnalysisSeconds + local act_mut_gen=$(tail -n1 "$summary_file" | cut -f1 -d',') + local act_mut_cov=$(tail -n1 "$summary_file" | cut -f2 -d',') + local act_mut_kill=$(tail -n1 "$summary_file" | cut -f3 -d',') + + [ "$act_mut_gen" -eq "$exp_mut_gen" ] || die "Unexpected number of mutants generated (expected: $exp_mut_gen, actual: $act_mut_gen)!" + [ "$act_mut_cov" -eq "$exp_mut_cov" ] || die "Unexpected number of mutants covered (expected: $exp_mut_cov, actual: $act_mut_cov)!" + [ "$act_mut_kill" -eq "$exp_mut_kill" ] || die "Unexpected number of mutants killed (expected: $exp_mut_kill, actual: $act_mut_kill)!" + + # TODO Would be nice to test the number of excluded mutants. In order to do it + # Major has to write that number to the '$pid_bid_dir/summary.csv' file. +} +################################################################################ + # Checkout project-version defects4j checkout -p "$pid" -v "$bid" -w "$pid_bid_dir" || die "It was not possible to checkout $pid-$bid to '$pid_bid_dir'!" ###################################################### # Test mutation analysis without excluding any mutants -defects4j mutation -w "$pid_bid_dir" -r || die "Mutation analysis (including all mutants) failed!" - -# Make sure Major generated the expected data files -[ -s "$mutants_file" ] || die "'$mutants_file' doesn't exist or is empty!" -[ -s "$summary_file" ] || die "'$summary_file' doesn't exist or is empty!" - -# The last row of 'summary.csv' does not have an end of line character. -# Otherwise, using wc would be more intuitive. -num_rows=$(grep -c "^" "$summary_file") -[ "$num_rows" -eq "2" ] || die "Unexpected number of lines in '$summary_file'!" - -# Columns of summary (csv) file: -# MutantsGenerated,MutantsCovered,MutantsKilled,MutantsLive,RuntimePreprocSeconds,RuntimeAnalysisSeconds -num_mutants_covered=$(tail -n1 "$summary_file" | cut -f2 -d',') -num_mutants_killed=$(tail -n1 "$summary_file" | cut -f3 -d',') - -[ "$num_mutants_covered" -gt 0 ] || die "0 mutants covered!" -[ "$num_mutants_killed" -gt 0 ] || die "0 mutants killed!" - -# TODO Would be nice to test the number of excluded mutants. In order to do it -# Major has to write that number to the '$pid_bid_dir/summary.csv' file. - -# Remove the summary file to ensure it is regenerated later +# Remove the summary file to ensure it is regenerated rm "$summary_file" +defects4j mutation -w "$pid_bid_dir" -r || die "Mutation analysis (including all mutants) failed!" +_check_mutation_result 941 913 646 + ################################################### # Test mutation analysis when excluding all mutants +# Remove the summary file to ensure it is regenerated +rm "$summary_file" + # Exclude all generated mutants exclude_file="$pid_bid_dir/exclude_all_mutants.txt" cut -f1 -d':' "$mutants_file" > "$exclude_file" defects4j mutation -w "$pid_bid_dir" -r -e "$exclude_file" || die "Mutation analysis (excluding all mutants) failed!" +_check_mutation_result 941 0 0 -# The last row of 'summary.csv' does not have an end of line character. -# Otherwise, using wc would be more intuitive. -num_rows=$(grep -c "^" "$summary_file") -[ "$num_rows" -eq "2" ] || die "Unexpected number of lines in '$summary_file'!" - -# Columns of summary (csv) file: -# MutantsGenerated,MutantsCovered,MutantsKilled,MutantsLive,RuntimePreprocSeconds,RuntimeAnalysisSeconds -num_mutants_covered=$(tail -n1 "$summary_file" | cut -f2 -d',') -num_mutants_killed=$(tail -n1 "$summary_file" | cut -f3 -d',') - -[ "$num_mutants_covered" -eq 0 ] || die "$num_mutants_covered mutants have been covered!" -[ "$num_mutants_killed" -eq 0 ] || die "$num_mutants_killed mutants have been killed!" +########################################################################## +# Test mutation analysis when explicitly providing the class(es) to mutate -# TODO Would be nice to test the number of excluded mutants. In order to do it -# Major has to write that number to the '$pid_bid_dir/summary.csv' file. - -######################################################################## -# Test mutation analysis when explicitly providing the classes to mutate +# Remove the summary file to ensure it is regenerated +rm "$summary_file" -# Exclude all generated mutants +# Mutate an arbitrary, non-modified class instrument_classes="$pid_bid_dir/instrument_classes.txt" echo "org.apache.commons.lang3.LocaleUtils" > "$instrument_classes" defects4j mutation -w "$pid_bid_dir" -i "$instrument_classes" || die "Mutation analysis (instrument LocaleUtils) failed!" - -# The last row of 'summary.csv' does not have an end of line character. -# Otherwise, using wc would be more intuitive. -num_rows=$(grep -c "^" "$summary_file") -[ "$num_rows" -eq "2" ] || die "Unexpected number of lines in '$summary_file'!" - -# Columns of summary (csv) file: -# MutantsGenerated,MutantsCovered,MutantsKilled,MutantsLive,RuntimePreprocSeconds,RuntimeAnalysisSeconds -num_mutants_generated=$(tail -n1 "$summary_file" | cut -f1 -d',') -num_mutants_covered=$(tail -n1 "$summary_file" | cut -f2 -d',') -num_mutants_killed=$(tail -n1 "$summary_file" | cut -f3 -d',') - -[ "$num_mutants_generated" -eq 184 ] || die "$num_mutants_generated mutants have been generated!" -[ "$num_mutants_covered" -eq 184 ] || die "$num_mutants_covered mutants have been covered!" -[ "$num_mutants_killed" -eq 158 ] || die "$num_mutants_killed mutants have been killed!" +_check_mutation_result 184 184 158 # Clean up rm -rf "$pid_bid_dir" From 5c9f37fad3aff5822627f767f43d04a075edc047 Mon Sep 17 00:00:00 2001 From: rjust Date: Wed, 9 Aug 2017 01:25:59 -0400 Subject: [PATCH 03/13] Updated documentation of Project module. --- framework/core/Project.pm | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/framework/core/Project.pm b/framework/core/Project.pm index 7384a974c..65b7371e8 100644 --- a/framework/core/Project.pm +++ b/framework/core/Project.pm @@ -83,6 +83,10 @@ Commons lang (L backend) Commons math (L backend) +=item * L + +Mockito (L backend) + =item * L Joda-time (L backend) From 3e9d1172a28f4f6f009623dcb9a0f3e1c1d476d8 Mon Sep 17 00:00:00 2001 From: rjust Date: Wed, 9 Aug 2017 02:13:45 -0400 Subject: [PATCH 04/13] Added a util function for splitting a file path into directory + filename. --- framework/core/Utils.pm | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/framework/core/Utils.pm b/framework/core/Utils.pm index bea463641..916d54cb7 100644 --- a/framework/core/Utils.pm +++ b/framework/core/Utils.pm @@ -37,6 +37,7 @@ use warnings; use strict; use File::Basename; +use File::Spec; use Cwd qw(abs_path); use Carp qw(confess); @@ -77,6 +78,20 @@ sub get_abs_path { return abs_path($dir); } +=pod + + Utils::get_dir(file) + +Returns the directory of the absolute path of F. + +=cut +sub get_dir { + @_ == 1 or die $ARG_ERROR; + my $path = shift; + my ($volume,$dir,$file) = File::Spec->splitpath($path); + return get_abs_path($dir); +} + =pod Utils::get_failing_tests(test_result_file) From 50b04331fff9a7250992a67d6ba1d1895d441ca8 Mon Sep 17 00:00:00 2001 From: rjust Date: Wed, 9 Aug 2017 02:14:41 -0400 Subject: [PATCH 05/13] Avoid warning in test script. --- framework/test/test_mutation_analysis.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/framework/test/test_mutation_analysis.sh b/framework/test/test_mutation_analysis.sh index 3ace886c0..f88db363a 100755 --- a/framework/test/test_mutation_analysis.sh +++ b/framework/test/test_mutation_analysis.sh @@ -67,7 +67,7 @@ defects4j checkout -p "$pid" -v "$bid" -w "$pid_bid_dir" || die "It was not poss # Test mutation analysis without excluding any mutants # Remove the summary file to ensure it is regenerated -rm "$summary_file" +rm -f "$summary_file" defects4j mutation -w "$pid_bid_dir" -r || die "Mutation analysis (including all mutants) failed!" _check_mutation_result 941 913 646 @@ -76,7 +76,7 @@ _check_mutation_result 941 913 646 # Test mutation analysis when excluding all mutants # Remove the summary file to ensure it is regenerated -rm "$summary_file" +rm -f "$summary_file" # Exclude all generated mutants exclude_file="$pid_bid_dir/exclude_all_mutants.txt" @@ -89,7 +89,7 @@ _check_mutation_result 941 0 0 # Test mutation analysis when explicitly providing the class(es) to mutate # Remove the summary file to ensure it is regenerated -rm "$summary_file" +rm -f "$summary_file" # Mutate an arbitrary, non-modified class instrument_classes="$pid_bid_dir/instrument_classes.txt" From c09c767f98b0f97d8ce20878340a1bf0998cb8b4 Mon Sep 17 00:00:00 2001 From: rjust Date: Wed, 9 Aug 2017 02:15:46 -0400 Subject: [PATCH 06/13] Added create_mml to Mutation module. --- framework/core/Mutation.pm | 43 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/framework/core/Mutation.pm b/framework/core/Mutation.pm index 3b3d095c2..6cbf17c3c 100644 --- a/framework/core/Mutation.pm +++ b/framework/core/Mutation.pm @@ -54,6 +54,49 @@ my $SUMMARY_FILE = "summary.csv"; =head2 Static subroutines + Mutation::create_mml(project_ref, instrument_classes, out_dir, mml_file) + +Generates an mml file, enabling all mutation operators for all classes listed +in F. + +=cut +sub create_mml { + @_ >= 3 or die $ARG_ERROR; + my ($project, $instrument_classes, $out_file) = @_; + + my $OUT_DIR = Utils::get_dir($out_file); + my $TEMPLATE = `cat $MAJOR_ROOT/mml/template.mml` or die "Cannot read mml template: $!"; + + # The mutation operators that should be enabled in the mml file + my @ops =("AOR", "LOR","SOR", "COR", "ROR", "ORU", "LVR", "STD"); + + system("mkdir -p $OUT_DIR"); + + open(IN, $instrument_classes); + my @classes = ; + close(IN); + + # Generate mml file by enabling operators for listed classes only + open(FILE, ">$out_file") or die "Cannot write mml file ($out_file): $!"; + # Add operator definitions from template + print FILE $TEMPLATE; + # Enable operators for all classes + foreach my $class (@classes) { + chomp $class; + print FILE "\n// Enable operators for $class\n"; + foreach my $op (@ops) { + # Skip disabled operators + next if $TEMPLATE =~ /-$op<"$class">/; + print FILE "$op<\"$class\">;\n"; + } + } + close(FILE); + Utils::exec_cmd("$MAJOR_ROOT/bin/mmlc $out_file 2>&1", "Compiling mutant definition (mml)") + or die "Cannot compile mml file: $out_file!"; +} + +=pod + Mutation::mutation_analysis(project_ref, log_file [, exclude_file, base_map, single_test]) Runs mutation analysis for the developer-written test suites of the provided From 26d42cfce06a56e2da32eb0dd78463454cff68ba Mon Sep 17 00:00:00 2001 From: rjust Date: Wed, 9 Aug 2017 02:24:38 -0400 Subject: [PATCH 07/13] Improved documentation. --- framework/core/Mutation.pm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/framework/core/Mutation.pm b/framework/core/Mutation.pm index 6cbf17c3c..96a032cc0 100644 --- a/framework/core/Mutation.pm +++ b/framework/core/Mutation.pm @@ -54,14 +54,14 @@ my $SUMMARY_FILE = "summary.csv"; =head2 Static subroutines - Mutation::create_mml(project_ref, instrument_classes, out_dir, mml_file) + Mutation::create_mml(project_ref, instrument_classes, out_file) Generates an mml file, enabling all mutation operators for all classes listed in F. =cut sub create_mml { - @_ >= 3 or die $ARG_ERROR; + @_ == 3 or die $ARG_ERROR; my ($project, $instrument_classes, $out_file) = @_; my $OUT_DIR = Utils::get_dir($out_file); From cbd6c37e735fbed6501fdbeaa1b2cdd535c0eafe Mon Sep 17 00:00:00 2001 From: rjust Date: Wed, 9 Aug 2017 02:26:24 -0400 Subject: [PATCH 08/13] Extracted common code from mutation scripts. --- framework/bin/d4j/d4j-mutation | 11 +---------- framework/bin/run_mutation.pl | 10 +--------- framework/core/Project.pm | 20 +++++++++++++++++--- 3 files changed, 19 insertions(+), 22 deletions(-) diff --git a/framework/bin/d4j/d4j-mutation b/framework/bin/d4j/d4j-mutation index 53616aa1d..3091ebd35 100644 --- a/framework/bin/d4j/d4j-mutation +++ b/framework/bin/d4j/d4j-mutation @@ -140,16 +140,7 @@ $project->{prog_root} = $WORK_DIR; # Classes to mutate -- default is all modified classes my $classes = $INSTRUMENT // "$SCRIPT_DIR/projects/$pid/modified_classes/$bid.src"; -# Create mutation definitions (mml file) -my $mml_dir = "$WORK_DIR/mml"; - -system("$UTIL_DIR/create_mml.pl -p $pid -c $classes -o $mml_dir -b $bid"); -my $mml_file = "$mml_dir/${bid}.mml.bin"; --e $mml_file or die "Mml file does not exist: $mml_file!"; - -# Mutate and compile sources -$ENV{MML} = $mml_file; -$project->mutate() > 0 or die "Cannot mutate project!"; +$project->mutate($classes) > 0 or die "Cannot mutate project!"; my $log_file = "$WORK_DIR/.mutation.log"; # Run the test suite, according to the provided flags diff --git a/framework/bin/run_mutation.pl b/framework/bin/run_mutation.pl index 12eecc2fb..1adb8c8d8 100755 --- a/framework/bin/run_mutation.pl +++ b/framework/bin/run_mutation.pl @@ -285,15 +285,7 @@ sub _run_mutation { close(EXCL_FILE); } - # Create mutation definitions (mml file) - my $mml_dir = "$TMP_DIR/.mml"; - system("$UTIL_DIR/create_mml.pl -p $PID -c $TARGET_CLASSES_DIR/$bid.src -o $mml_dir -b $bid"); - my $mml_file = "$mml_dir/$bid.mml.bin"; - -e $mml_file or die "Mml file does not exist: $mml_file!"; - - # Mutate source code - $ENV{MML} = $mml_file; - my $gen_mutants = $project->mutate(); + my $gen_mutants = $project->mutate("$TARGET_CLASSES_DIR/$bid.src"); $gen_mutants > 0 or die "No mutants generated for $vid!"; # Compile generated tests diff --git a/framework/core/Project.pm b/framework/core/Project.pm index 65b7371e8..63189efc7 100644 --- a/framework/core/Project.pm +++ b/framework/core/Project.pm @@ -100,6 +100,7 @@ use warnings; use strict; use Constants; use Utils; +use Mutation; use Carp qw(confess); =pod @@ -691,14 +692,27 @@ sub coverage_report { =pod - $project->mutate() + $project->mutate(instrument_classes) -Mutates the checked-out program version. +Mutates all classes listed in F in the checked-out program version. Returns the number of generated mutants on success, -1 otherwise. =cut sub mutate { - my $self = shift; + @_ == 2 or die $ARG_ERROR; + my ($self, $instrument_classes) = @_; + + # Create mutation definitions (mml file) + my $mml_src = "$self->{prog_root}/.mml/default.mml"; + my $mml_bin = "${mml_src}.bin"; + + Mutation::create_mml($self, $instrument_classes, $mml_src); + -e "$mml_bin" or die "Mml file does not exist: $mml_bin!"; + + # Set environment variable MML, which is read by Major + $ENV{MML} = $mml_bin; + + # Mutate and compile sources if (! $self->_ant_call("mutate")) { return -1; } From a99d66426694e6e9da48ef4be96712ecf83d78a3 Mon Sep 17 00:00:00 2001 From: rjust Date: Wed, 9 Aug 2017 02:37:18 -0400 Subject: [PATCH 09/13] Removed unused parameter from create_mml subroutine. --- framework/core/Constants.pm | 6 ++++-- framework/core/Mutation.pm | 6 +++--- framework/core/Project.pm | 2 +- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/framework/core/Constants.pm b/framework/core/Constants.pm index e2a7b4ad2..923e3cf6a 100644 --- a/framework/core/Constants.pm +++ b/framework/core/Constants.pm @@ -196,8 +196,10 @@ our $CONFIG_VID = "vid"; # Filename which stores build properties our $PROP_FILE = "defects4j.build.properties"; -our $PROP_EXCLUDE = "d4j.tests.exclude"; -our $PROP_INSTRUMENT = "d4j.classes.instrument"; +# Keys of stored properties +our $PROP_EXCLUDE = "d4j.tests.exclude"; +our $PROP_INSTRUMENT = "d4j.classes.instrument"; +our $PROP_MUTATE = "d4j.classes.mutate"; our $PROP_DIR_SRC_CLASSES = "d4j.dir.src.classes"; our $PROP_DIR_SRC_TESTS = "d4j.dir.src.tests"; our $PROP_CLASSES_MODIFIED= "d4j.classes.modified"; diff --git a/framework/core/Mutation.pm b/framework/core/Mutation.pm index 96a032cc0..3eaa74ad8 100644 --- a/framework/core/Mutation.pm +++ b/framework/core/Mutation.pm @@ -54,15 +54,15 @@ my $SUMMARY_FILE = "summary.csv"; =head2 Static subroutines - Mutation::create_mml(project_ref, instrument_classes, out_file) + Mutation::create_mml(instrument_classes, out_file) Generates an mml file, enabling all mutation operators for all classes listed in F. =cut sub create_mml { - @_ == 3 or die $ARG_ERROR; - my ($project, $instrument_classes, $out_file) = @_; + @_ == 2 or die $ARG_ERROR; + my ($instrument_classes, $out_file) = @_; my $OUT_DIR = Utils::get_dir($out_file); my $TEMPLATE = `cat $MAJOR_ROOT/mml/template.mml` or die "Cannot read mml template: $!"; diff --git a/framework/core/Project.pm b/framework/core/Project.pm index 63189efc7..8b0a8fbc0 100644 --- a/framework/core/Project.pm +++ b/framework/core/Project.pm @@ -706,7 +706,7 @@ sub mutate { my $mml_src = "$self->{prog_root}/.mml/default.mml"; my $mml_bin = "${mml_src}.bin"; - Mutation::create_mml($self, $instrument_classes, $mml_src); + Mutation::create_mml($instrument_classes, $mml_src); -e "$mml_bin" or die "Mml file does not exist: $mml_bin!"; # Set environment variable MML, which is read by Major From bf5a6b943be355d24eb50b42badca0e7dcdde660 Mon Sep 17 00:00:00 2001 From: rjust Date: Wed, 9 Aug 2017 02:37:47 -0400 Subject: [PATCH 10/13] Simplified create_mml script: use functionality provided in Mutation module. --- framework/util/create_mml.pl | 37 +++++++----------------------------- 1 file changed, 7 insertions(+), 30 deletions(-) diff --git a/framework/util/create_mml.pl b/framework/util/create_mml.pl index b8bdedc50..afff475d0 100755 --- a/framework/util/create_mml.pl +++ b/framework/util/create_mml.pl @@ -73,6 +73,7 @@ =head1 OPTIONS use lib abs_path("$FindBin::Bin/../core"); use Constants; +use Mutation; use Utils; # @@ -83,6 +84,7 @@ =head1 OPTIONS pod2usage(1) unless defined $cmd_opts{p} and defined $cmd_opts{c} and defined $cmd_opts{o} and defined $cmd_opts{b}; +# TODO: Unused parameter: PID my $PID = $cmd_opts{p}; my $CLASSES = Utils::get_abs_path($cmd_opts{c}); my $OUT_DIR = Utils::get_abs_path($cmd_opts{o}); @@ -91,33 +93,8 @@ =head1 OPTIONS $BID =~ /^(\d+)$/ or die "Wrong bug id format (\\d+): $BID!"; -e $CLASSES or die "File with classes to mutate does not exist: $CLASSES"; -my $TEMPLATE = `cat $MAJOR_ROOT/mml/template.mml` or die "Cannot read mml template: $!"; - -# The mutation operators that should be enabled in the mml file -my @ops =("AOR", "LOR","SOR", "COR", "ROR", "ORU", "LVR", "STD"); - -system("mkdir -p $OUT_DIR"); - -open(IN, $CLASSES); -my @classes = ; -close(IN); - -my $file = "$OUT_DIR/$BID.mml"; - -# Generate mml file by enabling operators for listed classes only -open(FILE, ">$file") or die "Cannot write mml file ($file): $!"; -# Add operator definitions from template -print FILE $TEMPLATE; -# Enable operators for all classes -foreach my $class (@classes) { - chomp $class; - print FILE "\n// Enable operators for $class\n"; - foreach my $op (@ops) { - # Skip disabled operators - next if $TEMPLATE =~ /-$op<"$class">/; - print FILE "$op<\"$class\">;\n"; - } -} -close(FILE); -my $log = `$MAJOR_ROOT/bin/mmlc $file 2>&1`; -$? == 0 or die "Cannot compile mml file: $file\n$log"; +my $mml_src = "$OUT_DIR/$BID.mml"; +my $mml_bin = "${mml_src}.bin"; + +Mutation::create_mml($CLASSES, $mml_src); +-e "$mml_bin" or die "Mml file does not exist: $mml_bin!"; From e4124fe015ff4ae7267adb6e01311ad656680d33 Mon Sep 17 00:00:00 2001 From: rjust Date: Wed, 9 Aug 2017 03:12:03 -0400 Subject: [PATCH 11/13] Write the mutated classes to the properties file; fixes issue #87. --- framework/core/Constants.pm | 1 + framework/core/Project.pm | 16 ++++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/framework/core/Constants.pm b/framework/core/Constants.pm index 923e3cf6a..2935ba6d3 100644 --- a/framework/core/Constants.pm +++ b/framework/core/Constants.pm @@ -236,6 +236,7 @@ $CONFIG_VID $PROP_FILE $PROP_EXCLUDE $PROP_INSTRUMENT +$PROP_MUTATE $PROP_DIR_SRC_CLASSES $PROP_DIR_SRC_TESTS $PROP_CLASSES_MODIFIED diff --git a/framework/core/Project.pm b/framework/core/Project.pm index 8b0a8fbc0..ac76c1d2d 100644 --- a/framework/core/Project.pm +++ b/framework/core/Project.pm @@ -701,6 +701,22 @@ Returns the number of generated mutants on success, -1 otherwise. sub mutate { @_ == 2 or die $ARG_ERROR; my ($self, $instrument_classes) = @_; + my $work_dir = $self->{prog_root}; + + # Read all classes that should be mutated + -e $instrument_classes or die "Classes file ($instrument_classes) does not exist!"; + open(IN, "<$instrument_classes") or die "Cannot read $instrument_classes"; + my @classes = (); + while() { + s/\r?\n//; + push(@classes, $_); + } + close(IN); + # Update properties + my $list = join(",", @classes); + my $config = {$PROP_MUTATE => $list}; + Utils::write_config_file("$work_dir/$PROP_FILE", $config); + # Create mutation definitions (mml file) my $mml_src = "$self->{prog_root}/.mml/default.mml"; From dcb7e46af53d63b5ac3139ac14704e11281d0c7c Mon Sep 17 00:00:00 2001 From: rjust Date: Fri, 11 Aug 2017 09:44:31 -0400 Subject: [PATCH 12/13] Removed unnecessary empty line. --- framework/core/Project.pm | 1 - 1 file changed, 1 deletion(-) diff --git a/framework/core/Project.pm b/framework/core/Project.pm index ac76c1d2d..679d8554b 100644 --- a/framework/core/Project.pm +++ b/framework/core/Project.pm @@ -717,7 +717,6 @@ sub mutate { my $config = {$PROP_MUTATE => $list}; Utils::write_config_file("$work_dir/$PROP_FILE", $config); - # Create mutation definitions (mml file) my $mml_src = "$self->{prog_root}/.mml/default.mml"; my $mml_bin = "${mml_src}.bin"; From aa6955bd6bab25f14a259c15b206ed8bdc36e418 Mon Sep 17 00:00:00 2001 From: rjust Date: Sat, 12 Aug 2017 13:03:27 -0400 Subject: [PATCH 13/13] Made the set of mutation operators a parameter in the core modules; they are currently hard-coded in the mutation scripts, though. --- framework/bin/d4j/d4j-mutation | 5 ++++- framework/bin/run_mutation.pl | 5 ++++- framework/core/Mutation.pm | 17 ++++++++--------- framework/core/Project.pm | 11 ++++++----- framework/util/create_mml.pl | 5 ++++- 5 files changed, 26 insertions(+), 17 deletions(-) diff --git a/framework/bin/d4j/d4j-mutation b/framework/bin/d4j/d4j-mutation index 3091ebd35..149b8b343 100644 --- a/framework/bin/d4j/d4j-mutation +++ b/framework/bin/d4j/d4j-mutation @@ -133,6 +133,9 @@ if ($type eq "b") { exit 1; } +# The mutation operators that should be enabled +my @MUT_OPS = ("AOR", "LOR","SOR", "COR", "ROR", "ORU", "LVR", "STD"); + # Instantiate project and set working directory my $project = Project::create_project($pid); $project->{prog_root} = $WORK_DIR; @@ -140,7 +143,7 @@ $project->{prog_root} = $WORK_DIR; # Classes to mutate -- default is all modified classes my $classes = $INSTRUMENT // "$SCRIPT_DIR/projects/$pid/modified_classes/$bid.src"; -$project->mutate($classes) > 0 or die "Cannot mutate project!"; +$project->mutate($classes, \@MUT_OPS) > 0 or die "Cannot mutate project!"; my $log_file = "$WORK_DIR/.mutation.log"; # Run the test suite, according to the provided flags diff --git a/framework/bin/run_mutation.pl b/framework/bin/run_mutation.pl index 1adb8c8d8..548ca6db6 100755 --- a/framework/bin/run_mutation.pl +++ b/framework/bin/run_mutation.pl @@ -131,6 +131,9 @@ =head1 DESCRIPTION # Enable debugging if flag is set $DEBUG = 1 if defined $cmd_opts{D}; +# The mutation operators that should be enabled +my @MUT_OPS = ("AOR", "LOR","SOR", "COR", "ROR", "ORU", "LVR", "STD"); + # Set up project my $project = Project::create_project($PID); @@ -285,7 +288,7 @@ sub _run_mutation { close(EXCL_FILE); } - my $gen_mutants = $project->mutate("$TARGET_CLASSES_DIR/$bid.src"); + my $gen_mutants = $project->mutate("$TARGET_CLASSES_DIR/$bid.src", \@MUT_OPS); $gen_mutants > 0 or die "No mutants generated for $vid!"; # Compile generated tests diff --git a/framework/core/Mutation.pm b/framework/core/Mutation.pm index 3eaa74ad8..c77c88026 100644 --- a/framework/core/Mutation.pm +++ b/framework/core/Mutation.pm @@ -54,22 +54,21 @@ my $SUMMARY_FILE = "summary.csv"; =head2 Static subroutines - Mutation::create_mml(instrument_classes, out_file) + Mutation::create_mml(instrument_classes, out_file, mut_ops) -Generates an mml file, enabling all mutation operators for all classes listed -in F. +Generates an mml file, enabling all mutation operators defined by the array +reference C for all classes listed in F. The mml +(source) file is written to C. This subroutine also compiles the mml +file to F<'out_file'.bin>. =cut sub create_mml { - @_ == 2 or die $ARG_ERROR; - my ($instrument_classes, $out_file) = @_; + @_ == 3 or die $ARG_ERROR; + my ($instrument_classes, $out_file, $mut_ops) = @_; my $OUT_DIR = Utils::get_dir($out_file); my $TEMPLATE = `cat $MAJOR_ROOT/mml/template.mml` or die "Cannot read mml template: $!"; - # The mutation operators that should be enabled in the mml file - my @ops =("AOR", "LOR","SOR", "COR", "ROR", "ORU", "LVR", "STD"); - system("mkdir -p $OUT_DIR"); open(IN, $instrument_classes); @@ -84,7 +83,7 @@ sub create_mml { foreach my $class (@classes) { chomp $class; print FILE "\n// Enable operators for $class\n"; - foreach my $op (@ops) { + foreach my $op (@{$mut_ops}) { # Skip disabled operators next if $TEMPLATE =~ /-$op<"$class">/; print FILE "$op<\"$class\">;\n"; diff --git a/framework/core/Project.pm b/framework/core/Project.pm index 679d8554b..cc3e6bb22 100644 --- a/framework/core/Project.pm +++ b/framework/core/Project.pm @@ -692,15 +692,16 @@ sub coverage_report { =pod - $project->mutate(instrument_classes) + $project->mutate(instrument_classes, mut_ops) -Mutates all classes listed in F in the checked-out program version. +Mutates all classes listed in F, using all mutation operators +defined by the array reference C, in the checked-out program version. Returns the number of generated mutants on success, -1 otherwise. =cut sub mutate { - @_ == 2 or die $ARG_ERROR; - my ($self, $instrument_classes) = @_; + @_ == 3 or die $ARG_ERROR; + my ($self, $instrument_classes, $mut_ops) = @_; my $work_dir = $self->{prog_root}; # Read all classes that should be mutated @@ -721,7 +722,7 @@ sub mutate { my $mml_src = "$self->{prog_root}/.mml/default.mml"; my $mml_bin = "${mml_src}.bin"; - Mutation::create_mml($instrument_classes, $mml_src); + Mutation::create_mml($instrument_classes, $mml_src, $mut_ops); -e "$mml_bin" or die "Mml file does not exist: $mml_bin!"; # Set environment variable MML, which is read by Major diff --git a/framework/util/create_mml.pl b/framework/util/create_mml.pl index afff475d0..5b02b7256 100755 --- a/framework/util/create_mml.pl +++ b/framework/util/create_mml.pl @@ -93,8 +93,11 @@ =head1 OPTIONS $BID =~ /^(\d+)$/ or die "Wrong bug id format (\\d+): $BID!"; -e $CLASSES or die "File with classes to mutate does not exist: $CLASSES"; +# The mutation operators that should be enabled +my @MU_OPS = ("AOR", "LOR","SOR", "COR", "ROR", "ORU", "LVR", "STD"); + my $mml_src = "$OUT_DIR/$BID.mml"; my $mml_bin = "${mml_src}.bin"; -Mutation::create_mml($CLASSES, $mml_src); +Mutation::create_mml($CLASSES, $mml_src, \@MUT_OPS); -e "$mml_bin" or die "Mml file does not exist: $mml_bin!";