Skip to content

Instantly share code, notes, and snippets.

@mockdeep
Created October 19, 2013 03:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mockdeep/7051285 to your computer and use it in GitHub Desktop.
Save mockdeep/7051285 to your computer and use it in GitHub Desktop.
Script to convert spec files to mutation testing format
require 'active_support/inflector'
inflectors_path = File.expand_path('./config/initializers/inflections.rb')
load inflectors_path if File.exist?(inflectors_path)
class Mutagen
def initialize(path)
file_match_expression = File.join(File.expand_path(path), '**/*.rb')
@source_files = Dir.glob(file_match_expression).map do |file_path|
SourceFile.new(file_path, path)
end
end
def mutate!
@source_files.each do |source_file|
dir_path = source_file.dir_path
Dir.mkdir(dir_path) unless Dir.exist?(dir_path)
source_file.spec_groups.each do |spec_group|
dir_path = spec_group.dir_path
Dir.mkdir(dir_path) unless Dir.exist?(dir_path)
File.write(spec_group.target_path, spec_group.text)
end
end
end
end
class SourceFile
def initialize(file_path, base_path)
@file_path = file_path
@base_path = base_path
end
def old_spec_groups
@spec_groups ||= group_names.map do |group_name|
SpecGroup.new(group_name, dir_path, class_name)
end
end
def dir_path
File.join(@base_path, class_path)
end
def class_name
class_path.split('/').last.classify
end
def class_path
@file_path.match(/#{@base_path}\/(.*)_spec\.rb/).captures.first
end
def spec_groups
@spec_groups = []
block = ''
pre_block_text = ''
block_started = false
pre_block = false
block_name = ''
file_text.lines.each do |line|
if line.match(/^ describe '(\S*)' do$/)
block_name = $1
block_started = true
unless pre_block_text.strip == ''
@spec_groups << SpecGroup.new('__ungrouped', dir_path, class_name, pre_block_text)
end
pre_block = false
next
elsif !block_started && line.match(/^describe (\S*) do$/)
pre_block = true
pre_block_text = ''
next
elsif !block_started && pre_block
pre_block_text << line
next
elsif !block_started
next
end
if line.match(/^ end$/)
@spec_groups << SpecGroup.new(block_name, dir_path, class_name, block)
block = ''
block_started = false
else
line = line[2..-1] || "\n"
block << line
end
end
@spec_groups
end
private
def group_names
file_text.scan(/^ describe '(.*)' do$/).flatten.uniq
end
def file_text
file_text = File.read(@file_path)
end
end
class SpecGroup
attr_reader :name, :class_name, :base_path, :block
def initialize(name, base_path, class_name, block)
raise 'no spaces!' if name.match(/ /)
@name = name
@base_path = base_path
@class_name = class_name
@block = block
end
def target_path
File.join(dir_path, file_name)
end
def dir_path
[base_path, path_extension].compact.join('/')
end
def file_name
"#{stripped_name}#{modifier}_spec.rb"
end
def text
<<EOF
require 'spec_helper'
describe #{class_name}, '#{name}' do
#{block}
end
EOF
end
def path_extension
'class_methods' if name.match(/^\..*/)
end
def stripped_name
plain_name = name.match(/(\w+)/)
plain_name && plain_name.captures.first
end
def modifier
case name
when /<=>/
'spaceship_operator'
when /!$/
'_bang'
when /\?$/
'_predicate'
when /=$/
'_writer'
else
''
end
end
end
mutagen = Mutagen.new('spec/models')
mutagen.mutate!
@dkubb
Copy link

dkubb commented Oct 19, 2013

I'd recommend looking at using Pathname objects to represent file and directory paths rather than String objects.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment