Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ gem "rake", "~> 13.0"
gem "minitest", "~> 5.0"

gem "rubocop", "~> 1.21"
gem "debug"
41 changes: 40 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,12 @@ It's early days and this work is still experimental. Here's what it can do now

### Capabilities
- describe -> class
- context -> class
- it -> def test_*
- expect(actual).to eq(expected) -> assert_equal(expected, actual)
- expect(actual).to be_falsey -> refute(actual)
- expect(actual).to be_truthy -> assert(actual)
- expect(actual).to be_empty -> assert_empty(actual)

## Installation

Expand All @@ -22,7 +26,11 @@ If bundler is not being used to manage dependencies, install the gem by executin
## Usage

```
minitestify print FILES # Convert one or more specs to minitest and print to standard out
Usage: minitestify [options] <spec_files>
-v, --version Print version
-h, --help Prints this help
-r, --rails Use more railsy syntax
-s, --save Replace spec with test in path & file name. Write to new file
```

## Development
Expand All @@ -31,6 +39,37 @@ After checking out the repo, run `bin/setup` to install dependencies. Then, run

To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).

### Testing

```
rake test
```

### Development Tips

Use the `stree` cli to output matchers.

```bash
=> stree expr -e 'expect(false).to be_falsey'
SyntaxTree::CommandCall[
receiver: SyntaxTree::CallNode[
receiver: nil,
operator: nil,
message: SyntaxTree::Ident[value: "expect"],
arguments: SyntaxTree::ArgParen[
arguments: SyntaxTree::Args[
parts: [SyntaxTree::VarRef[value: SyntaxTree::Kw[value: "false"]]]
]
]
],
operator: SyntaxTree::Period[value: "."],
message: SyntaxTree::Ident[value: "to"],
arguments: SyntaxTree::Args[
parts: [SyntaxTree::VCall[value: SyntaxTree::Ident[value: "be_falsey"]]]
]
]
```

## Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/minitestify. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/[USERNAME]/minitestify/blob/master/CODE_OF_CONDUCT.md).
Expand Down
21 changes: 17 additions & 4 deletions lib/minitestify/cli.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
module Minitestify::CLI
module_function def run
options = {}
save = false
OptionParser
.new do |parser|
parser.banner = "Usage: minitestify [options] <spec_files>"
Expand All @@ -21,14 +22,26 @@ module Minitestify::CLI
puts(parser)
exit
end

parser.on("-r", "--rails", "Use more railsy syntax") do
options[:rails] = true
end

parser.on("-s", "--save", "Replace spec with test in path & file name. Write to new file") do
save = true
end
end
.parse!

ARGV.each do |file|
spec = Minitestify::Spec.new(file: file)
puts("# #{spec.to_test_filepath}")
puts(spec.to_test_code)
puts
spec = Minitestify::Spec.new(file: file, **options)
if save
puts("Writing to #{spec.to_test_filepath}")
File.write(spec.to_test_filepath, spec.to_test_code)
else
puts(spec.to_test_code)
end
end
puts
end
end
12 changes: 12 additions & 0 deletions lib/minitestify/mutations/base.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
module Minitestify
module Mutations
class Base
attr_reader :file, :rails

def initialize file:, rails: false, **args
@file = file
@rails = rails
end
end
end
end
64 changes: 64 additions & 0 deletions lib/minitestify/mutations/be_empty.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
require_relative "base"

module Minitestify
module Mutations
class BeEmpty < Base
def add_mutation!(visitor)
expect_be_empty_search =
'CommandCall[
receiver: CallNode[
message: Ident[value: "expect"],
],
operator: Period[value: "."],
message: Ident[value: "to"],
arguments: Args[
parts: [VCall[
value: Ident[value: "be_empty"]
]]
]
]'
visitor.mutate(expect_be_empty_search) do |node|
node => SyntaxTree::CommandCall[
receiver: SyntaxTree::CallNode[
receiver: nil,
operator: nil,
message: SyntaxTree::Ident[value: "expect"],
arguments: SyntaxTree::ArgParen[
arguments: SyntaxTree::Args[parts: [actual_expr]]
]
],
operator: SyntaxTree::Period[value: "."],
message: SyntaxTree::Ident[value: "to"],
arguments: SyntaxTree::Args[
parts: [
SyntaxTree::VCall[
value: SyntaxTree::Ident[value: "be_empty"],
]
]
]
]

SyntaxTree::CallNode.new(
message:
SyntaxTree::Ident.new(
value: "assert_empty",
location: node.location
),
arguments:
SyntaxTree::ArgParen.new(
arguments:
SyntaxTree::Args.new(
parts: [actual_expr],
location: node.location
),
location: node.location
),
location: node.location,
receiver: nil,
operator: nil
)
end
end
end
end
end
64 changes: 64 additions & 0 deletions lib/minitestify/mutations/be_falsey.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
require_relative "base"

module Minitestify
module Mutations
class BeFalsey < Base
def add_mutation!(visitor)
expect_be_falsey_search =
'CommandCall[
receiver: CallNode[
message: Ident[value: "expect"],
],
operator: Period[value: "."],
message: Ident[value: "to"],
arguments: Args[
parts: [VCall[
value: Ident[value: "be_falsey"]
]]
]
]'
visitor.mutate(expect_be_falsey_search) do |node|
node => SyntaxTree::CommandCall[
receiver: SyntaxTree::CallNode[
receiver: nil,
operator: nil,
message: SyntaxTree::Ident[value: "expect"],
arguments: SyntaxTree::ArgParen[
arguments: SyntaxTree::Args[parts: [actual_expr]]
]
],
operator: SyntaxTree::Period[value: "."],
message: SyntaxTree::Ident[value: "to"],
arguments: SyntaxTree::Args[
parts: [
SyntaxTree::VCall[
value: SyntaxTree::Ident[value: "be_falsey"],
]
]
]
]

SyntaxTree::CallNode.new(
message:
SyntaxTree::Ident.new(
value: "refute",
location: node.location
),
arguments:
SyntaxTree::ArgParen.new(
arguments:
SyntaxTree::Args.new(
parts: [actual_expr],
location: node.location
),
location: node.location
),
location: node.location,
receiver: nil,
operator: nil
)
end
end
end
end
end
64 changes: 64 additions & 0 deletions lib/minitestify/mutations/be_truthy.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
require_relative "base"

module Minitestify
module Mutations
class BeTruthy < Base
def add_mutation!(visitor)
expect_be_truthy_search =
'CommandCall[
receiver: CallNode[
message: Ident[value: "expect"],
],
operator: Period[value: "."],
message: Ident[value: "to"],
arguments: Args[
parts: [VCall[
value: Ident[value: "be_truthy"]
]]
]
]'
visitor.mutate(expect_be_truthy_search) do |node|
node => SyntaxTree::CommandCall[
receiver: SyntaxTree::CallNode[
receiver: nil,
operator: nil,
message: SyntaxTree::Ident[value: "expect"],
arguments: SyntaxTree::ArgParen[
arguments: SyntaxTree::Args[parts: [actual_expr]]
]
],
operator: SyntaxTree::Period[value: "."],
message: SyntaxTree::Ident[value: "to"],
arguments: SyntaxTree::Args[
parts: [
SyntaxTree::VCall[
value: SyntaxTree::Ident[value: "be_truthy"],
]
]
]
]

SyntaxTree::CallNode.new(
message:
SyntaxTree::Ident.new(
value: "assert",
location: node.location
),
arguments:
SyntaxTree::ArgParen.new(
arguments:
SyntaxTree::Args.new(
parts: [actual_expr],
location: node.location
),
location: node.location
),
location: node.location,
receiver: nil,
operator: nil
)
end
end
end
end
end
73 changes: 73 additions & 0 deletions lib/minitestify/mutations/describe.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
require_relative "base"

module Minitestify
module Mutations
class Describe < Base
def add_mutation!(visitor)
inflector = Dry::Inflector.new

# describe|context -> class
describe_node = ->(node) do
case node
in SyntaxTree::Command[
message: SyntaxTree::Ident[value: "describe"],
arguments: SyntaxTree::Args[
parts: [SyntaxTree::VarRef[value: SyntaxTree::Const[value: value]]]
]
] => node
in SyntaxTree::Command[
message: SyntaxTree::Ident[value: "describe"],
arguments: SyntaxTree::Args[
SyntaxTree::StringLiteral[
parts: [SyntaxTree::TStringContent[value: value]]
]
]
] => node
in SyntaxTree::Command[
message: SyntaxTree::Ident[value: "context"],
arguments: SyntaxTree::Args[
SyntaxTree::StringLiteral[
parts: [SyntaxTree::TStringContent[value: value]]
]
]
] => node
end

value = value.tr("'", "").gsub(/\W/, "_")

SyntaxTree::ClassDeclaration.new(
constant:
SyntaxTree::ConstRef.new(
constant:
SyntaxTree::Const.new(
value: "#{inflector.camelize_upper(value)}Test",
location: node.location
),
location: node.location
),
superclass:
SyntaxTree::ConstPathRef.new(
parent:
SyntaxTree::VarRef.new(
value:
SyntaxTree::Const.new(
value: "Minitest",
location: node.location
),
location: node.location
),
constant:
SyntaxTree::Const.new(value: "Test", location: node.location),
location: node.location
),
bodystmt: node.child_nodes.last.bodystmt,
location: node.location
)
end

visitor.mutate("Command[ message: Ident[value: \"describe\"] ]", &describe_node)
visitor.mutate("Command[ message: Ident[value: \"context\"] ]", &describe_node)
end
end
end
end
Loading