tset 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +14 -0
- data/.rspec +3 -0
- data/Gemfile +6 -0
- data/LICENSE.txt +22 -0
- data/README.md +49 -0
- data/Rakefile +6 -0
- data/bin/tset +4 -0
- data/lib/tset/analyzers/abstract.rb +15 -0
- data/lib/tset/analyzers/action.rb +17 -0
- data/lib/tset/analyzers/model.rb +56 -0
- data/lib/tset/cli.rb +23 -0
- data/lib/tset/commands/generate.rb +37 -0
- data/lib/tset/generators/abstract.rb +21 -0
- data/lib/tset/generators/controller_test/ctrl_spec.rspec.tt +0 -0
- data/lib/tset/generators/controller_test/ctrl_test.minitest.tt +0 -0
- data/lib/tset/generators/controller_test.rb +18 -0
- data/lib/tset/generators/model_test/model_spec.rspec.tt +4 -0
- data/lib/tset/generators/model_test/model_test.minitest.tt +1 -0
- data/lib/tset/generators/model_test.rb +52 -0
- data/lib/tset/test.rb +17 -0
- data/lib/tset/testable.rb +34 -0
- data/lib/tset/translators/abstract.rb +14 -0
- data/lib/tset/translators/minitest.rb +19 -0
- data/lib/tset/translators/rspec.rb +67 -0
- data/lib/tset/version.rb +3 -0
- data/lib/tset/writers/abstract.rb +15 -0
- data/lib/tset/writers/model_test.rb +89 -0
- data/lib/tset.rb +6 -0
- data/spec/analyzers/model_spec.rb +39 -0
- data/spec/commands/generate_spec.rb +61 -0
- data/spec/integration/generate_model_test_spec.rb +54 -0
- data/spec/spec_helper.rb +21 -0
- data/spec/support/setup_macros.rb +34 -0
- data/spec/translators/rspec_spec.rb +89 -0
- data/spec/writers/model_test_spec.rb +29 -0
- data/tset.gemspec +27 -0
- metadata +158 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: f27830bfa45780af901203d61a7fc1b52dc906dd
|
4
|
+
data.tar.gz: 73e19fa5e554d5ee50f6737bc05dbad47e077d43
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: cf6b9261c29093169b72eb15291375d5fbce2e9190c9d163b10a6c71bee4137301d9609f8b6bab82a75036e9270508875c29375bc29befda0cb09677e56e0f70
|
7
|
+
data.tar.gz: 650a7258cad0b33de4f6df0075e2142dcea56e056d648d6d0d224881127e91bd8c3482b3236c4e387e1ad7c2a1a39b90449af5ca7cd28bf30fd7b114ab21315e
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2015 Sung Won Cho
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
# Tset
|
2
|
+
|
3
|
+
Tset generates tests for your models in your Rails application.
|
4
|
+
|
5
|
+
## Why?
|
6
|
+
|
7
|
+
TDD is great, but sometimes you just want to write some codes.
|
8
|
+
|
9
|
+
Enter 'Development Driven Test'. Tset enables you to just write codes and worry about tests later.
|
10
|
+
|
11
|
+
## Installation
|
12
|
+
|
13
|
+
Run installation command.
|
14
|
+
|
15
|
+
```
|
16
|
+
gem install tset
|
17
|
+
```
|
18
|
+
|
19
|
+
OR if you are using bundler,
|
20
|
+
|
21
|
+
```ruby
|
22
|
+
gem 'tset', group: :development
|
23
|
+
```
|
24
|
+
|
25
|
+
Run `bundle`
|
26
|
+
|
27
|
+
## Usage
|
28
|
+
|
29
|
+
In your application root directory, run the generator.
|
30
|
+
|
31
|
+
```
|
32
|
+
tset generate model YOUR_MODEL_NAME
|
33
|
+
```
|
34
|
+
|
35
|
+
Tset will read your model and generate a test accordingly.
|
36
|
+
|
37
|
+
By default, the Tset will use RSpec. Help us add MiniTest support by contributing.
|
38
|
+
|
39
|
+
## Fact
|
40
|
+
|
41
|
+
* Tset is a test spelled backwards.
|
42
|
+
|
43
|
+
## Contributing
|
44
|
+
|
45
|
+
### TODO
|
46
|
+
|
47
|
+
* Help us improve Tset by adding more test rules located in translators.
|
48
|
+
* Support MiniTest.
|
49
|
+
* Support controllers.
|
data/Rakefile
ADDED
data/bin/tset
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
#
|
2
|
+
# Representation of action and its content in a controller
|
3
|
+
#
|
4
|
+
# @param name [String] a name of an action
|
5
|
+
# @param body [String] a content of an action
|
6
|
+
#
|
7
|
+
module Tset
|
8
|
+
module Analyzers
|
9
|
+
class Action
|
10
|
+
|
11
|
+
def initialize(name, body)
|
12
|
+
@name = name
|
13
|
+
@body = body
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require "tset/analyzers/abstract"
|
2
|
+
require "tset/translators/rspec"
|
3
|
+
require "tset/testable"
|
4
|
+
require "pathname"
|
5
|
+
|
6
|
+
# Reads the model file and breaks it down into an array of testables.
|
7
|
+
#
|
8
|
+
# @param name [String] the name of the model
|
9
|
+
# @return [Array] the model codes for which tests can be generated.
|
10
|
+
#
|
11
|
+
module Tset
|
12
|
+
module Analyzers
|
13
|
+
class Model < Abstract
|
14
|
+
|
15
|
+
attr_reader :name, :target
|
16
|
+
|
17
|
+
def initialize(name)
|
18
|
+
@name = name
|
19
|
+
@target = Pathname.pwd.join('app/models')
|
20
|
+
end
|
21
|
+
|
22
|
+
def start
|
23
|
+
detect_testable_lines
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def detect_testable_lines
|
29
|
+
testable_lines = []
|
30
|
+
|
31
|
+
content = _model_file.read
|
32
|
+
|
33
|
+
testable_patterns.each do |pattern|
|
34
|
+
testable_lines << content.each_line.grep(pattern) do |matching_line|
|
35
|
+
Tset::Testable.new('model', matching_line.strip)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
testable_lines.flatten
|
40
|
+
end
|
41
|
+
|
42
|
+
def _model_file
|
43
|
+
target.join("#{ name }.rb")
|
44
|
+
end
|
45
|
+
|
46
|
+
def testable_patterns
|
47
|
+
Tset::Translators::Rspec::MODEL_TRANSLATION_RULES.flat_map do |category|
|
48
|
+
category.values.flat_map do |rule|
|
49
|
+
rule.keys
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
data/lib/tset/cli.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
require "thor"
|
2
|
+
require "tset/commands/generate"
|
3
|
+
|
4
|
+
module Tset
|
5
|
+
class Cli < Thor
|
6
|
+
include Thor::Actions
|
7
|
+
|
8
|
+
desc 'version', 'prints Tset version'
|
9
|
+
def version
|
10
|
+
puts "v#{ Tset::VERSION }"
|
11
|
+
end
|
12
|
+
|
13
|
+
desc 'generate', 'generates tests'
|
14
|
+
def generate(type = nil, name = nil, framework = 'rspec')
|
15
|
+
if options[:help] || (type.nil? && name.nil?)
|
16
|
+
invoke :help, ['generate']
|
17
|
+
else
|
18
|
+
require "tset/commands/generate"
|
19
|
+
Tset::Commands::Generate.new(type, name, framework, self).start
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require "pathname"
|
2
|
+
require "active_support/inflector"
|
3
|
+
|
4
|
+
module Tset
|
5
|
+
module Commands
|
6
|
+
class Generate
|
7
|
+
|
8
|
+
GENERATOR_NAMESPACE = "Tset::Generators::%sTest".freeze
|
9
|
+
|
10
|
+
class Error < ::StandardError ; end
|
11
|
+
|
12
|
+
attr_reader :type, :name, :framework, :cli, :source, :target
|
13
|
+
|
14
|
+
def initialize(type, name, framework, cli)
|
15
|
+
@type = type
|
16
|
+
@name = name.downcase
|
17
|
+
@framework = framework
|
18
|
+
|
19
|
+
@cli = cli
|
20
|
+
@source = Pathname.new(::File.dirname(__FILE__) + "/../generators/#{ @type }_test").realpath
|
21
|
+
@target = Pathname.pwd.realpath
|
22
|
+
end
|
23
|
+
|
24
|
+
def start
|
25
|
+
generator.start
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def generator
|
31
|
+
require "tset/generators/#{ @type }_test"
|
32
|
+
class_name = @type.classify
|
33
|
+
Object.const_get(GENERATOR_NAMESPACE % class_name).new(self)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require "delegate"
|
2
|
+
|
3
|
+
module Tset
|
4
|
+
module Generators
|
5
|
+
#
|
6
|
+
# An abstract superclass of Generators
|
7
|
+
#
|
8
|
+
# @param command [Tset::Commands::Generate] An instance of generate command
|
9
|
+
# @abstract
|
10
|
+
#
|
11
|
+
class Abstract < SimpleDelegator
|
12
|
+
def initialize(command)
|
13
|
+
super(command)
|
14
|
+
end
|
15
|
+
|
16
|
+
def start
|
17
|
+
raise NotImplementedError
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
File without changes
|
File without changes
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'test_helper'
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require "tset/generators/abstract"
|
2
|
+
require "tset/analyzers/model"
|
3
|
+
require "tset/writers/model_test"
|
4
|
+
require "active_support/inflector"
|
5
|
+
|
6
|
+
module Tset
|
7
|
+
module Generators
|
8
|
+
#
|
9
|
+
# Generates blank test files in the application
|
10
|
+
# Uses analyzers, translators, and writers to insert appropriate tests into the files.
|
11
|
+
#
|
12
|
+
# @param command [Tset::Commands::Generate] An instance of generate command
|
13
|
+
#
|
14
|
+
class ModelTest < Abstract
|
15
|
+
|
16
|
+
attr_reader :model_name
|
17
|
+
|
18
|
+
def initialize(command)
|
19
|
+
super
|
20
|
+
@model_name = name.classify
|
21
|
+
|
22
|
+
cli.class.source_root(source)
|
23
|
+
end
|
24
|
+
|
25
|
+
def start
|
26
|
+
assert_model_exists!
|
27
|
+
|
28
|
+
opts = {
|
29
|
+
model_name: @model_name
|
30
|
+
}
|
31
|
+
|
32
|
+
case framework
|
33
|
+
when 'rspec'
|
34
|
+
cli.template(source.join('model_spec.rspec.tt'), target.join("spec/models/#{ name }_spec.rb"), opts)
|
35
|
+
when 'minitest'
|
36
|
+
cli.template(source.join('model_test.minitest.tt'), target.join("test/models/#{ name }_test.rb"), opts)
|
37
|
+
end
|
38
|
+
|
39
|
+
testables = Tset::Analyzers::Model.new(name).start
|
40
|
+
Tset::Writers::ModelTest.new(name, testables, framework).start!
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def assert_model_exists!
|
46
|
+
unless target.join("app/models/#{ name }.rb").exist?
|
47
|
+
raise Tset::Commands::Generate::Error.new("Unknown model: `#{ name }`")
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
data/lib/tset/test.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
module Tset
|
2
|
+
#
|
3
|
+
# Contains the translated test code and the category it belongs to
|
4
|
+
#
|
5
|
+
# @param code [String] The actual test code translated from testable
|
6
|
+
# @param category [String] A category used for describe block
|
7
|
+
#
|
8
|
+
class Test
|
9
|
+
|
10
|
+
attr_reader :code, :category
|
11
|
+
|
12
|
+
def initialize(code, category)
|
13
|
+
@code = code
|
14
|
+
@category = category
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require "tset/translators/rspec"
|
2
|
+
require "tset/translators/minitest"
|
3
|
+
require "active_support/inflector"
|
4
|
+
|
5
|
+
module Tset
|
6
|
+
#
|
7
|
+
# Snippet of code that can be converted to a test by Writers
|
8
|
+
#
|
9
|
+
# @param type [String] The part of application from which the code originate (e.g. controller, model)
|
10
|
+
# @param code [String] The testable code itself
|
11
|
+
#
|
12
|
+
class Testable
|
13
|
+
|
14
|
+
TRANSLATOR_NAMESPACE = "Tset::Translators::%s"
|
15
|
+
|
16
|
+
attr_reader :type, :code
|
17
|
+
|
18
|
+
def initialize(type, code)
|
19
|
+
@type = type
|
20
|
+
@code = code
|
21
|
+
end
|
22
|
+
|
23
|
+
def to_test(framework = 'rspec')
|
24
|
+
translator(framework).start
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def translator(framework)
|
30
|
+
class_name = framework.classify
|
31
|
+
Object.const_get(TRANSLATOR_NAMESPACE % class_name).new(self)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Tset
|
2
|
+
module Translators
|
3
|
+
#
|
4
|
+
# Translates testable to a minitest test
|
5
|
+
#
|
6
|
+
# @param testable [Test::Testable] An instance of testable
|
7
|
+
#
|
8
|
+
class MiniTest < Abstract
|
9
|
+
|
10
|
+
def initialize(testable)
|
11
|
+
@testable = testable
|
12
|
+
end
|
13
|
+
|
14
|
+
def start
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require "tset/translators/abstract"
|
2
|
+
|
3
|
+
module Tset
|
4
|
+
module Translators
|
5
|
+
#
|
6
|
+
# Translates testable to an RSpec test
|
7
|
+
#
|
8
|
+
# @param testable [Test::Testable] An instance of testable
|
9
|
+
#
|
10
|
+
class Rspec < Abstract
|
11
|
+
|
12
|
+
MODEL_TRANSLATION_RULES = [
|
13
|
+
{
|
14
|
+
'validations' => {
|
15
|
+
%r(validates_presence_of (.*)) => "it { is.expected_to validate_presence_of(%s) }",
|
16
|
+
%r(validates_uniqueness_of (.*)) => "it { is.expected_to validate_uniqueness_of(%s) }",
|
17
|
+
%r(validates_length_of (.*), maximum: (\d*)) => "it { is.expected_to ensure_length_of(%s).is_at_most(%s) }",
|
18
|
+
%r(validates_length_of (.*), minimum: (\d*)) => "it { is.expected_to ensure_length_of(%s).is_at_least(%s) }",
|
19
|
+
%r(validates (\S*), presence: true) => "it { is.expected_to validate_presence_of(%s) }"
|
20
|
+
}
|
21
|
+
},
|
22
|
+
|
23
|
+
{
|
24
|
+
'associations' => {
|
25
|
+
%r(belongs_to (.*)) => "it { is.expected_to belong_to(%s) }",
|
26
|
+
%r(has_many (.*)) => "it { is.expected_to have_many(%s) }",
|
27
|
+
%r(has_one (.*)) => "it { is.expected_to have_one(%s) }",
|
28
|
+
%r(has_and_belongs_to_many (.*)) => "it { is.expected_to have_and_belong_to_many(%s) }",
|
29
|
+
%r(has_attached_file (\S*)) => "it { is.expected_to have_attached_file(%s) }"
|
30
|
+
}
|
31
|
+
}
|
32
|
+
]
|
33
|
+
|
34
|
+
attr_reader :testable
|
35
|
+
|
36
|
+
def initialize(testable)
|
37
|
+
@testable = testable
|
38
|
+
end
|
39
|
+
|
40
|
+
#
|
41
|
+
# @return [Tset::Test] An object containing RSpec test corresponding to the testable and category
|
42
|
+
#
|
43
|
+
def start
|
44
|
+
send("translate_#{ testable.type }")
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
#
|
50
|
+
# Translates the testable from the object using MODEL_TRANSLATION_RULES
|
51
|
+
#
|
52
|
+
# @return [Tset::Test] an object containing corresponding test_code and category
|
53
|
+
#
|
54
|
+
def translate_model
|
55
|
+
MODEL_TRANSLATION_RULES.each do |rule|
|
56
|
+
rule.values.first.each do |pattern, outcome|
|
57
|
+
if testable.code =~ pattern
|
58
|
+
test_code = outcome % [$1, $2]
|
59
|
+
return Tset::Test.new(test_code, rule.keys.first)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
data/lib/tset/version.rb
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
require "tset/writers/abstract"
|
2
|
+
require "active_support/inflector"
|
3
|
+
|
4
|
+
module Tset
|
5
|
+
module Writers
|
6
|
+
#
|
7
|
+
# Writes the test for a model for each testable codes given
|
8
|
+
#
|
9
|
+
# @param model_name [String] a name of the model (e.g. post)
|
10
|
+
# @param testables [Array] an array of lines of code returned by Tset::Analyzers::Model
|
11
|
+
# @param framework [String] a test framework. Default to 'rspec'.
|
12
|
+
#
|
13
|
+
class ModelTest < Abstract
|
14
|
+
|
15
|
+
attr_reader :model_name, :testables, :framework, :target
|
16
|
+
|
17
|
+
def initialize(model_name, testables, framework = 'rspec')
|
18
|
+
@model_name = model_name
|
19
|
+
@testables = testables
|
20
|
+
@framework = framework
|
21
|
+
|
22
|
+
@target = Pathname.pwd.realpath
|
23
|
+
end
|
24
|
+
|
25
|
+
#
|
26
|
+
# @return [String] A classified version of the name (e.g. Post)
|
27
|
+
#
|
28
|
+
def class_name
|
29
|
+
@class_name ||= model_name.classify
|
30
|
+
end
|
31
|
+
|
32
|
+
def start!
|
33
|
+
case framework
|
34
|
+
when 'rspec'
|
35
|
+
testables.each { |testable| write_rspec(testable) }
|
36
|
+
when 'minitest'
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
#
|
43
|
+
# Translates the testable into rspec and writes to rspec file
|
44
|
+
#
|
45
|
+
# @param testable [Tset::Testable]
|
46
|
+
#
|
47
|
+
def write_rspec(testable)
|
48
|
+
test = testable.to_test('rspec')
|
49
|
+
|
50
|
+
file_contents = File.read(_rspec_file)
|
51
|
+
|
52
|
+
describe(test.category) unless file_contents =~ /describe "#{test.category}" do/
|
53
|
+
expectation(test)
|
54
|
+
end
|
55
|
+
|
56
|
+
#
|
57
|
+
# Writes a describe block
|
58
|
+
#
|
59
|
+
# @param category [String] notion that is being described
|
60
|
+
#
|
61
|
+
def describe(category)
|
62
|
+
file_contents = File.read(_rspec_file)
|
63
|
+
replacement = %Q(describe #{class_name} do
|
64
|
+
|
65
|
+
describe "#{category}" do
|
66
|
+
end)
|
67
|
+
file_contents.gsub!(/describe #{class_name} do/, replacement)
|
68
|
+
File.write(_rspec_file, file_contents)
|
69
|
+
end
|
70
|
+
|
71
|
+
#
|
72
|
+
# Writes an expectation
|
73
|
+
#
|
74
|
+
# @param test [Tset::Tset]
|
75
|
+
#
|
76
|
+
def expectation(test)
|
77
|
+
file_contents = File.read(_rspec_file)
|
78
|
+
replacement = %Q( describe "#{test.category}" do
|
79
|
+
#{test.code})
|
80
|
+
file_contents.gsub!(/\s\sdescribe "#{test.category}" do/, replacement)
|
81
|
+
File.write(_rspec_file, file_contents)
|
82
|
+
end
|
83
|
+
|
84
|
+
def _rspec_file
|
85
|
+
target.join("spec/models/#{ @model_name }_spec.rb")
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
data/lib/tset.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Tset::Analyzers::Model do
|
4
|
+
let(:name) { 'post' }
|
5
|
+
let(:analyzer) { Tset::Analyzers::Model.new(name) }
|
6
|
+
|
7
|
+
before do
|
8
|
+
set_up_testing_directory
|
9
|
+
create_file("app/models/#{name}.rb")
|
10
|
+
end
|
11
|
+
|
12
|
+
before(:each) do
|
13
|
+
erase_file_content("app/models/#{name}.rb")
|
14
|
+
end
|
15
|
+
|
16
|
+
after do
|
17
|
+
chdir_back_to_root
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'returns an array of testable codes' do
|
21
|
+
content = "
|
22
|
+
belongs_to :author
|
23
|
+
has_one :tipjar
|
24
|
+
has_many :comments
|
25
|
+
has_many :likes
|
26
|
+
lets_validate_this :forum
|
27
|
+
validates_presence_of :post
|
28
|
+
acts_as_votable
|
29
|
+
validates_presence_of :author
|
30
|
+
validates :category, presence: true
|
31
|
+
"
|
32
|
+
insert_into_file("app/models/#{name}.rb", content)
|
33
|
+
result = analyzer.start
|
34
|
+
|
35
|
+
expect(result.map(&:code)).to match_array ['validates_presence_of :post', 'validates_presence_of :author', 'validates :category, presence: true',
|
36
|
+
'belongs_to :author', 'has_one :tipjar', 'has_many :comments', 'has_many :likes']
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Tset::Commands::Generate do
|
4
|
+
let(:name) { 'post' }
|
5
|
+
let(:cli) { Tset::Cli.new }
|
6
|
+
let(:command) { Tset::Commands::Generate.new(type, name, framework, cli) }
|
7
|
+
|
8
|
+
before do
|
9
|
+
set_up_testing_directory
|
10
|
+
end
|
11
|
+
|
12
|
+
after do
|
13
|
+
chdir_back_to_root
|
14
|
+
end
|
15
|
+
|
16
|
+
describe 'model' do
|
17
|
+
let(:type) { 'model' }
|
18
|
+
let(:framework) { 'rspec' }
|
19
|
+
|
20
|
+
context 'when the model exists' do
|
21
|
+
before do
|
22
|
+
create_file("app/models/#{name}.rb")
|
23
|
+
end
|
24
|
+
|
25
|
+
context 'with rspec' do
|
26
|
+
|
27
|
+
before do
|
28
|
+
command.start
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'generates a model spec' do
|
32
|
+
content = @root.join('spec/models/post_spec.rb').read
|
33
|
+
expect(content).to match %(require 'spec_helper')
|
34
|
+
expect(content).to match %(describe Post do)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
context 'with minitest' do
|
39
|
+
let(:framework) { 'minitest' }
|
40
|
+
|
41
|
+
before do
|
42
|
+
command.start
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'generates a model test' do
|
46
|
+
content = @root.join('test/models/post_test.rb').read
|
47
|
+
expect(content).to match %(require 'test_helper')
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
context 'when the model does not exist' do
|
53
|
+
it 'raises error' do
|
54
|
+
expect {
|
55
|
+
command.start
|
56
|
+
}.to raise_error(Tset::Commands::Generate::Error)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe 'tset generate model post' do
|
4
|
+
let(:name) { 'post' }
|
5
|
+
let(:cli) { Tset::Cli.new }
|
6
|
+
let(:command) { Tset::Commands::Generate.new(type, name, framework, cli) }
|
7
|
+
let(:type) { 'model' }
|
8
|
+
let(:model_content) {
|
9
|
+
"validates_presence_of :author
|
10
|
+
validates_presence_of :title
|
11
|
+
validates_presence_of :body
|
12
|
+
validates_length_of :title, maximum: 30
|
13
|
+
validates_length_of :body, minimum: 50
|
14
|
+
belongs_to :author
|
15
|
+
has_and_belongs_to_many :categories
|
16
|
+
has_many :comments" }
|
17
|
+
|
18
|
+
before do
|
19
|
+
set_up_testing_directory
|
20
|
+
create_file("app/models/#{name}.rb")
|
21
|
+
insert_into_file("app/models/#{name}.rb", model_content)
|
22
|
+
end
|
23
|
+
|
24
|
+
after do
|
25
|
+
chdir_back_to_root
|
26
|
+
end
|
27
|
+
|
28
|
+
context 'with rspec' do
|
29
|
+
let(:framework) { 'rspec' }
|
30
|
+
|
31
|
+
before(:each) do
|
32
|
+
command.start
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'generates the correct spec' do
|
36
|
+
content = @root.join('spec/models/post_spec.rb').read
|
37
|
+
expect(content).to match %(require 'spec_helper')
|
38
|
+
expect(content).to match %(describe Post do)
|
39
|
+
expect(content).to match %( describe "associations" do)
|
40
|
+
expect(content).to match %r( it { is.expected_to have_and_belong_to_many\(:categories\) })
|
41
|
+
expect(content).to match %r( it { is.expected_to have_many\(:comments\) })
|
42
|
+
expect(content).to match %r( it { is.expected_to belong_to\(:author\) })
|
43
|
+
expect(content).to match %( end)
|
44
|
+
expect(content).to match %( describe "validations" do)
|
45
|
+
expect(content).to match %r( it { is.expected_to validate_presence_of\(:author\))
|
46
|
+
expect(content).to match %r( it { is.expected_to validate_presence_of\(:title\) })
|
47
|
+
expect(content).to match %r( it { is.expected_to validate_presence_of\(:body\) })
|
48
|
+
expect(content).to match %r( it { is.expected_to ensure_length_of\(:title\).is_at_most\(30\) })
|
49
|
+
expect(content).to match %r( it { is.expected_to ensure_length_of\(:body\).is_at_least\(50\) })
|
50
|
+
expect(content).to match %( end)
|
51
|
+
expect(content).to match %(end)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# Require all files under /lib
|
2
|
+
Dir[File.expand_path('../../lib/**/*.rb', __FILE__)].each { |f| require f }
|
3
|
+
|
4
|
+
# Require all spec support files
|
5
|
+
Dir[File.expand_path('../support/**/*.rb', __FILE__)].each { |f| require f }
|
6
|
+
|
7
|
+
RSpec.configure do |config|
|
8
|
+
config.expect_with :rspec do |expectations|
|
9
|
+
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
|
10
|
+
end
|
11
|
+
|
12
|
+
config.mock_with :rspec do |mocks|
|
13
|
+
mocks.verify_partial_doubles = true
|
14
|
+
end
|
15
|
+
|
16
|
+
# Include support modules from support files
|
17
|
+
config.include SetupMacros
|
18
|
+
|
19
|
+
# Do not display console outputs when running tests
|
20
|
+
config.before { allow($stdout).to receive(:write) }
|
21
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module SetupMacros
|
2
|
+
def set_up_testing_directory
|
3
|
+
@tmp = Pathname.new(@pwd = Dir.pwd).join('tmp')
|
4
|
+
@tmp.rmtree if @tmp.exist?
|
5
|
+
@tmp.mkpath
|
6
|
+
|
7
|
+
@tmp.join('apps/controllers').mkpath
|
8
|
+
@tmp.join('apps/models').mkpath
|
9
|
+
|
10
|
+
Dir.chdir(@tmp)
|
11
|
+
@root = @tmp
|
12
|
+
end
|
13
|
+
|
14
|
+
def chdir_back_to_root
|
15
|
+
Dir.chdir(@pwd)
|
16
|
+
end
|
17
|
+
|
18
|
+
def create_file(path)
|
19
|
+
file = @root.join(path)
|
20
|
+
file.dirname.rmtree if file.dirname.exist?
|
21
|
+
file.dirname.mkpath
|
22
|
+
FileUtils.touch(file)
|
23
|
+
end
|
24
|
+
|
25
|
+
def erase_file_content(path)
|
26
|
+
file = @root.join(path)
|
27
|
+
File.open(file, 'w') {}
|
28
|
+
end
|
29
|
+
|
30
|
+
def insert_into_file(path, content)
|
31
|
+
file = @root.join(path)
|
32
|
+
File.write(file, content)
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Tset::Translators::Rspec do
|
4
|
+
let(:translator) { Tset::Translators::Rspec.new(testable) }
|
5
|
+
let(:testable) { Tset::Testable.new('model', code) }
|
6
|
+
let(:result) { translator.start }
|
7
|
+
|
8
|
+
context 'for models' do
|
9
|
+
context 'validates_presence_of :post' do
|
10
|
+
let(:code) { 'validates_presence_of :post' }
|
11
|
+
|
12
|
+
it 'returns a proper test' do
|
13
|
+
expect(result.code).to eq "it { is.expected_to validate_presence_of(:post) }"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
context 'validates_uniqueness_of :title' do
|
18
|
+
let(:code) { 'validates_uniqueness_of :title' }
|
19
|
+
|
20
|
+
it 'returns a proper test' do
|
21
|
+
expect(result.code).to eq "it { is.expected_to validate_uniqueness_of(:title) }"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
context 'validates_uniqueness_of :title' do
|
26
|
+
let(:code) { 'validates_uniqueness_of :title' }
|
27
|
+
|
28
|
+
it 'returns a proper test' do
|
29
|
+
expect(result.code).to eq "it { is.expected_to validate_uniqueness_of(:title) }"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
context 'validates_length_of :body, maximum: 300' do
|
34
|
+
let(:code) { 'validates_length_of :body, maximum: 300' }
|
35
|
+
|
36
|
+
it 'returns a proper test' do
|
37
|
+
expect(result.code).to eq "it { is.expected_to ensure_length_of(:body).is_at_most(300) }"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
context 'validates_length_of :body, minimum: 100' do
|
42
|
+
let(:code) { 'validates_length_of :body, minimum: 100' }
|
43
|
+
|
44
|
+
it 'returns a proper test' do
|
45
|
+
expect(result.code).to eq "it { is.expected_to ensure_length_of(:body).is_at_least(100) }"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
context 'belongs_to :author' do
|
50
|
+
let(:code) { 'belongs_to :author' }
|
51
|
+
|
52
|
+
it 'returns a proper test' do
|
53
|
+
expect(result.code).to eq "it { is.expected_to belong_to(:author) }"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
context 'has_many :comments' do
|
58
|
+
let(:code) { 'has_many :comments' }
|
59
|
+
|
60
|
+
it 'returns a proper test' do
|
61
|
+
expect(result.code).to eq "it { is.expected_to have_many(:comments) }"
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
context 'has_one :tag' do
|
66
|
+
let(:code) { 'has_one :tag' }
|
67
|
+
|
68
|
+
it 'returns a proper test' do
|
69
|
+
expect(result.code).to eq "it { is.expected_to have_one(:tag) }"
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
context 'has_and_belongs_to_many :admins' do
|
74
|
+
let(:code) { 'has_and_belongs_to_many :admins' }
|
75
|
+
|
76
|
+
it 'returns a proper test' do
|
77
|
+
expect(result.code).to eq "it { is.expected_to have_and_belong_to_many(:admins) }"
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
context 'has_attached_file :profile_picture' do
|
82
|
+
let(:code) { 'has_attached_file :profile_picture' }
|
83
|
+
|
84
|
+
it 'returns a proper test' do
|
85
|
+
expect(result.code).to eq "it { is.expected_to have_attached_file(:profile_picture) }"
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Tset::Writers::ModelTest do
|
4
|
+
let(:writer) { Tset::Writers::ModelTest.new(model_name, testables, framework) }
|
5
|
+
let(:model_name) { 'post' }
|
6
|
+
|
7
|
+
before do
|
8
|
+
set_up_testing_directory
|
9
|
+
create_file('app/models/post.rb')
|
10
|
+
create_file('spec/models/post_spec.rb')
|
11
|
+
insert_into_file('spec/models/post_spec.rb', "describe Post do")
|
12
|
+
end
|
13
|
+
|
14
|
+
after do
|
15
|
+
chdir_back_to_root
|
16
|
+
end
|
17
|
+
|
18
|
+
context 'rsepc' do
|
19
|
+
let(:framework) { 'rspec' }
|
20
|
+
let(:testables) { [Tset::Testable.new('model', 'validates_presence_of :author')] }
|
21
|
+
|
22
|
+
it 'writes a test' do
|
23
|
+
writer.start!
|
24
|
+
|
25
|
+
content = @root.join('spec/models/post_spec.rb').read
|
26
|
+
expect(content).to match %r(it { is.expected_to validate_presence_of\(:author\) })
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
data/tset.gemspec
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'tset/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "tset"
|
8
|
+
spec.version = Tset::VERSION
|
9
|
+
spec.authors = ["Sung Won Cho"]
|
10
|
+
spec.email = ["mikeswcho@gmail.com"]
|
11
|
+
spec.summary = %q{Generate tests for your Rails model.}
|
12
|
+
spec.description = %q{Generate tests for your Rails model. Enter Development Driven Test.}
|
13
|
+
spec.homepage = "https://github.com/sungwoncho/tset"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_development_dependency "bundler", "~> 1.7"
|
22
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
23
|
+
spec.add_development_dependency "rspec", "~> 3.2.0"
|
24
|
+
|
25
|
+
spec.add_dependency "thor", "~> 0.19.1"
|
26
|
+
spec.add_dependency "activesupport", "~> 4.2.1"
|
27
|
+
end
|
metadata
ADDED
@@ -0,0 +1,158 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: tset
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Sung Won Cho
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-04-10 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.7'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.7'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 3.2.0
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 3.2.0
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: thor
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 0.19.1
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 0.19.1
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: activesupport
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 4.2.1
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 4.2.1
|
83
|
+
description: Generate tests for your Rails model. Enter Development Driven Test.
|
84
|
+
email:
|
85
|
+
- mikeswcho@gmail.com
|
86
|
+
executables:
|
87
|
+
- tset
|
88
|
+
extensions: []
|
89
|
+
extra_rdoc_files: []
|
90
|
+
files:
|
91
|
+
- ".gitignore"
|
92
|
+
- ".rspec"
|
93
|
+
- Gemfile
|
94
|
+
- LICENSE.txt
|
95
|
+
- README.md
|
96
|
+
- Rakefile
|
97
|
+
- bin/tset
|
98
|
+
- lib/tset.rb
|
99
|
+
- lib/tset/analyzers/abstract.rb
|
100
|
+
- lib/tset/analyzers/action.rb
|
101
|
+
- lib/tset/analyzers/model.rb
|
102
|
+
- lib/tset/cli.rb
|
103
|
+
- lib/tset/commands/generate.rb
|
104
|
+
- lib/tset/generators/abstract.rb
|
105
|
+
- lib/tset/generators/controller_test.rb
|
106
|
+
- lib/tset/generators/controller_test/ctrl_spec.rspec.tt
|
107
|
+
- lib/tset/generators/controller_test/ctrl_test.minitest.tt
|
108
|
+
- lib/tset/generators/model_test.rb
|
109
|
+
- lib/tset/generators/model_test/model_spec.rspec.tt
|
110
|
+
- lib/tset/generators/model_test/model_test.minitest.tt
|
111
|
+
- lib/tset/test.rb
|
112
|
+
- lib/tset/testable.rb
|
113
|
+
- lib/tset/translators/abstract.rb
|
114
|
+
- lib/tset/translators/minitest.rb
|
115
|
+
- lib/tset/translators/rspec.rb
|
116
|
+
- lib/tset/version.rb
|
117
|
+
- lib/tset/writers/abstract.rb
|
118
|
+
- lib/tset/writers/model_test.rb
|
119
|
+
- spec/analyzers/model_spec.rb
|
120
|
+
- spec/commands/generate_spec.rb
|
121
|
+
- spec/integration/generate_model_test_spec.rb
|
122
|
+
- spec/spec_helper.rb
|
123
|
+
- spec/support/setup_macros.rb
|
124
|
+
- spec/translators/rspec_spec.rb
|
125
|
+
- spec/writers/model_test_spec.rb
|
126
|
+
- tset.gemspec
|
127
|
+
homepage: https://github.com/sungwoncho/tset
|
128
|
+
licenses:
|
129
|
+
- MIT
|
130
|
+
metadata: {}
|
131
|
+
post_install_message:
|
132
|
+
rdoc_options: []
|
133
|
+
require_paths:
|
134
|
+
- lib
|
135
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
136
|
+
requirements:
|
137
|
+
- - ">="
|
138
|
+
- !ruby/object:Gem::Version
|
139
|
+
version: '0'
|
140
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
141
|
+
requirements:
|
142
|
+
- - ">="
|
143
|
+
- !ruby/object:Gem::Version
|
144
|
+
version: '0'
|
145
|
+
requirements: []
|
146
|
+
rubyforge_project:
|
147
|
+
rubygems_version: 2.4.5
|
148
|
+
signing_key:
|
149
|
+
specification_version: 4
|
150
|
+
summary: Generate tests for your Rails model.
|
151
|
+
test_files:
|
152
|
+
- spec/analyzers/model_spec.rb
|
153
|
+
- spec/commands/generate_spec.rb
|
154
|
+
- spec/integration/generate_model_test_spec.rb
|
155
|
+
- spec/spec_helper.rb
|
156
|
+
- spec/support/setup_macros.rb
|
157
|
+
- spec/translators/rspec_spec.rb
|
158
|
+
- spec/writers/model_test_spec.rb
|