brutal 0.3.0 → 0.4.0
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 +4 -4
- data/README.md +104 -28
- data/bin/brutal +10 -8
- data/lib/brutal/scaffold_generator/por.rb +2 -2
- data/lib/brutal/scaffold_generator/rspec.rb +55 -0
- metadata +7 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4b21dc72c3687aa3893272f404e01d0329a528a61caa2b6f5ec251b5de66a3a4
|
4
|
+
data.tar.gz: 9aeb0ad4c455bb747700dc3af6bdf8957376e100af6e7b11bc6b377218e12426
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7a818e0951d2993387caf80e699a989ffecca901f43ebf00b430b1de2ce330eb8da486c75800fd936a32b6f9b3286703d5ce4e85995b1a652f945ee9261162d3
|
7
|
+
data.tar.gz: afeedf7b04fc5be914e400a2b1a2149b0f82fb45f069654f2cc0bcf72e64cc84fc1c906b52c780d5199c2897059e1fc8e6125c6667e32c8a26fd656ae645a0c8
|
data/README.md
CHANGED
@@ -1,22 +1,77 @@
|
|
1
|
-
# Brutal
|
2
|
-
|
3
|
-
> I don't like testing because it's redundant. If we are smart enough, we can avoid it. <br/>
|
4
|
-
> -- Matz
|
1
|
+
# Brutal 💎🔨
|
5
2
|
|
6
3
|
[][travis]
|
7
4
|
[][gem]
|
8
5
|
[][inchpages]
|
9
6
|
[][rubydoc]
|
10
7
|
|
11
|
-
|
8
|
+
> A _code-first_ approach to automate the writing of unit tests.
|
12
9
|
|
13
|
-
|
10
|
+
## Intro
|
14
11
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
12
|
+
[](https://www.youtube.com/embed/cmOt9HhszCI?start=1732&end=1736 "I don't like tests. It's not DRY.")
|
13
|
+
|
14
|
+
> I don't like tests. It's not DRY.<br/>
|
15
|
+
> -- [Matz](https://github.com/matz)
|
16
|
+
|
17
|
+
## Purpose
|
18
|
+
|
19
|
+
Take a break and let __Brutal__ shape for you the actual behavior of your code against as many combinations of challenges as needed.
|
20
|
+
|
21
|
+
Without giving the power to test everything, it makes it easy to generate in no time a set of tests for all relevant contexts.
|
22
|
+
|
23
|
+
By delegating to __Brutal__ the repetitive and redundant task of writing tests, you'll be able to focus on your core business: writing code.
|
24
|
+
|
25
|
+
## Warning
|
26
|
+
|
27
|
+
__Brutal__ does not prevent from bugs.
|
28
|
+
As a picture of the behavior of the code, its generated tests would be wrong if the code is wrong.
|
29
|
+
|
30
|
+
This is why it is important to carefully read the generated test suite, to ensure that it describes the behavior of the code as it is supposed to behave.
|
31
|
+
|
32
|
+
However, when the `brutal` command is executed successfully,
|
33
|
+
we can consider that both __Brutal__'s configuration file (`.brutal.yml`) and evaluated code as syntactically correct.
|
34
|
+
|
35
|
+
In the context of a versioned project, to avoid regressions,
|
36
|
+
the integrity of the behavior of the code can easily be checked by re-generating a picture to be compared with the previous one.
|
37
|
+
Here is an example with [The Greeter class](https://github.com/fixrb/brutal/raw/master/examples/the_greeter_class/) code:
|
38
|
+
|
39
|
+
```sh
|
40
|
+
git diff
|
41
|
+
```
|
42
|
+
|
43
|
+
The code:
|
44
|
+
|
45
|
+
```diff
|
46
|
+
# The Greeter class
|
47
|
+
class Greeter
|
48
|
+
def initialize(name)
|
49
|
+
- @name = name
|
50
|
+
+ @name = name.capitalize
|
51
|
+
end
|
52
|
+
|
53
|
+
def salute
|
54
|
+
"Hello #{@name}!"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
```
|
58
|
+
|
59
|
+
The generated test of the code:
|
60
|
+
|
61
|
+
```diff
|
62
|
+
require './greeter'
|
63
|
+
|
64
|
+
# ------------------------------------------------------------------------------
|
65
|
+
|
66
|
+
front_object = Greeter
|
67
|
+
|
68
|
+
# ------------------------------------------------------------------------------
|
69
|
+
|
70
|
+
actual = front_object.new('world')
|
71
|
+
|
72
|
+
- raise unless actual.salute == "Hello world!"
|
73
|
+
+ raise unless actual.salute == "Hello World!"
|
74
|
+
```
|
20
75
|
|
21
76
|
## Installation
|
22
77
|
|
@@ -40,7 +95,8 @@ Just type `brutal` in a Ruby project's folder and watch the magic happen.
|
|
40
95
|
|
41
96
|
## Usage
|
42
97
|
|
43
|
-
|
98
|
+
__Brutal__'s configuration file is `.brutal.yml`, which acts like a meta-spec.
|
99
|
+
This YAML file can contains the following keys:
|
44
100
|
|
45
101
|
* `header` (optional): Some code to execute before the test suite.
|
46
102
|
* `front_object` (required): The front object of the test suite.
|
@@ -48,9 +104,15 @@ The Brutal YAML file handles 4 keys:
|
|
48
104
|
* `variables` (required): A hash to generate the subject of each context.
|
49
105
|
* `actual_values` (required): A list of tests to challenge the subject.
|
50
106
|
|
107
|
+
### Optional parameters
|
108
|
+
|
109
|
+
It would also be possible to ask for an RSpec template by passing "`rspec`" argument:
|
110
|
+
|
111
|
+
> brutal rspec
|
112
|
+
|
51
113
|
## Example
|
52
114
|
|
53
|
-
Given this
|
115
|
+
Given this config file:
|
54
116
|
|
55
117
|
```yaml
|
56
118
|
---
|
@@ -70,7 +132,7 @@ actual_values:
|
|
70
132
|
- "%{subject}.length"
|
71
133
|
```
|
72
134
|
|
73
|
-
The `brutal` command would
|
135
|
+
The `brutal` command would generate and write in to a `test.rb` file the following "Plain Old Ruby":
|
74
136
|
|
75
137
|
```ruby
|
76
138
|
front_object = "Hello "
|
@@ -88,7 +150,29 @@ raise unless actual.to_s == "Hello Bob"
|
|
88
150
|
raise unless actual.length == 9
|
89
151
|
```
|
90
152
|
|
91
|
-
|
153
|
+
And the `brutal rspec` command would generate and write in to a `test_spec.rb` file the following spec:
|
154
|
+
|
155
|
+
```ruby
|
156
|
+
RSpec.describe do
|
157
|
+
let(:front_object) { "Hello " }
|
158
|
+
|
159
|
+
context do
|
160
|
+
let(:actual) { front_object + 'Alice' }
|
161
|
+
|
162
|
+
it { expect(actual.to_s).to eq("Hello Alice") }
|
163
|
+
it { expect(actual.length).to eq(11) }
|
164
|
+
end
|
165
|
+
|
166
|
+
context do
|
167
|
+
let(:actual) { front_object + 'Bob' }
|
168
|
+
|
169
|
+
it { expect(actual.to_s).to eq("Hello Bob") }
|
170
|
+
it { expect(actual.length).to eq(9) }
|
171
|
+
end
|
172
|
+
end
|
173
|
+
```
|
174
|
+
|
175
|
+
More examples are available [here](https://github.com/fixrb/brutal/raw/master/examples/).
|
92
176
|
|
93
177
|
## Rake integration example
|
94
178
|
|
@@ -115,23 +199,10 @@ end
|
|
115
199
|
|
116
200
|
__Brutal__ follows [Semantic Versioning 2.0](https://semver.org/).
|
117
201
|
|
118
|
-
## Contributing
|
119
|
-
|
120
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/fixrb/brutal. 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/fixrb/brutal/blob/master/CODE_OF_CONDUCT.md).
|
121
|
-
|
122
202
|
## License
|
123
203
|
|
124
204
|
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
125
205
|
|
126
|
-
## Code of Conduct
|
127
|
-
|
128
|
-
Everyone interacting in the GreatGuardian project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/fixrb/brutal/blob/master/CODE_OF_CONDUCT.md).
|
129
|
-
|
130
|
-
[gem]: https://rubygems.org/gems/brutal
|
131
|
-
[travis]: https://travis-ci.org/fixrb/brutal
|
132
|
-
[inchpages]: https://inch-ci.org/github/fixrb/brutal
|
133
|
-
[rubydoc]: https://rubydoc.info/gems/brutal/frames
|
134
|
-
|
135
206
|
***
|
136
207
|
|
137
208
|
<p>
|
@@ -140,3 +211,8 @@ Everyone interacting in the GreatGuardian project's codebases, issue trackers, c
|
|
140
211
|
src="https://github.com/fixrb/brutal/raw/master/img/sashite.png"
|
141
212
|
alt="Sashite" /></a>
|
142
213
|
</p>
|
214
|
+
|
215
|
+
[gem]: https://rubygems.org/gems/brutal
|
216
|
+
[travis]: https://travis-ci.org/fixrb/brutal
|
217
|
+
[inchpages]: https://inch-ci.org/github/fixrb/brutal
|
218
|
+
[rubydoc]: https://rubydoc.info/gems/brutal/frames
|
data/bin/brutal
CHANGED
@@ -24,20 +24,22 @@ front_object = front_object.chomp if front_object.is_a?(::String)
|
|
24
24
|
|
25
25
|
require_relative ::File.join('..', 'lib', 'brutal')
|
26
26
|
|
27
|
-
scaffold = case ARGV.fetch(0, nil)
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
27
|
+
scaffold, file_name = case ARGV.fetch(0, nil)
|
28
|
+
when nil
|
29
|
+
[::Brutal::ScaffoldGenerator::Por, 'test.rb']
|
30
|
+
when 'rspec'
|
31
|
+
[::Brutal::ScaffoldGenerator::RSpec, 'test_spec.rb']
|
32
|
+
else
|
33
|
+
abort "#{ARGV[0].inspect} not (yet) supported!"
|
34
|
+
end
|
33
35
|
|
34
36
|
eval(header) # rubocop:disable Security/Eval
|
35
37
|
|
36
38
|
doc = [
|
37
39
|
header,
|
38
40
|
scaffold.new(front_object, subject, *actual_values, **variables).to_s
|
39
|
-
].reject(&:empty?).join("\n")
|
41
|
+
].reject(&:empty?).join("\n\n")
|
40
42
|
|
41
|
-
file = ::File.open(
|
43
|
+
file = ::File.open(file_name, 'w')
|
42
44
|
file.write(doc)
|
43
45
|
file.close
|
@@ -20,7 +20,7 @@ module Brutal
|
|
20
20
|
|
21
21
|
test_params = Array(values_arr[0]).product(*Array(values_arr[1..-1]))
|
22
22
|
|
23
|
-
blank_line +
|
23
|
+
blank_line.gsub(/\A\n/, '') +
|
24
24
|
"front_object = #{front_object_str}\n" +
|
25
25
|
blank_line +
|
26
26
|
test_params.map do |values|
|
@@ -30,7 +30,7 @@ module Brutal
|
|
30
30
|
|
31
31
|
actual_str = format(inspect(subject), **attributes)
|
32
32
|
|
33
|
-
string = "actual = #{actual_str}\n"
|
33
|
+
string = "actual = #{actual_str}\n\n"
|
34
34
|
actual = eval(actual_str) # rubocop:disable Security/Eval, Lint/UselessAssignment
|
35
35
|
|
36
36
|
actual_values.each do |actual_value|
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'base'
|
4
|
+
|
5
|
+
module Brutal
|
6
|
+
module ScaffoldGenerator
|
7
|
+
# Plain Old Ruby.
|
8
|
+
#
|
9
|
+
# @api private
|
10
|
+
#
|
11
|
+
class RSpec < Base
|
12
|
+
# Return a string representation
|
13
|
+
#
|
14
|
+
# @return [String]
|
15
|
+
#
|
16
|
+
# @api public
|
17
|
+
def to_s
|
18
|
+
names = variables.keys.sort
|
19
|
+
values_arr = names.map { |name| variables.fetch(name) }
|
20
|
+
|
21
|
+
test_params = Array(values_arr[0]).product(*Array(values_arr[1..-1]))
|
22
|
+
|
23
|
+
"RSpec.describe do\n" \
|
24
|
+
" let(:front_object) { #{front_object_str} }\n" \
|
25
|
+
"\n" +
|
26
|
+
test_params.map do |values|
|
27
|
+
string = " context do\n"
|
28
|
+
|
29
|
+
attributes = names.each_with_index.inject(front_object: 'front_object') do |h, (name, i)|
|
30
|
+
h.merge(name.to_sym => inspect(values.fetch(i)))
|
31
|
+
end
|
32
|
+
|
33
|
+
actual_str = format(inspect(subject), **attributes)
|
34
|
+
|
35
|
+
string += " let(:actual) { #{actual_str} }\n\n"
|
36
|
+
actual = eval(actual_str) # rubocop:disable Security/Eval, Lint/UselessAssignment
|
37
|
+
|
38
|
+
actual_values.each do |actual_value|
|
39
|
+
result_str = format(actual_value, subject: 'actual')
|
40
|
+
string += " it { expect(#{result_str}).to eq(#{eval(result_str).inspect}) }\n" # rubocop:disable Security/Eval
|
41
|
+
end
|
42
|
+
|
43
|
+
string += " end\n"
|
44
|
+
|
45
|
+
string
|
46
|
+
end.join(blank_line) +
|
47
|
+
"end\n"
|
48
|
+
end
|
49
|
+
|
50
|
+
def blank_line
|
51
|
+
"\n"
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: brutal
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Cyril Kato
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-12-
|
11
|
+
date: 2019-12-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '2.
|
19
|
+
version: '2.1'
|
20
20
|
type: :development
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '2.
|
26
|
+
version: '2.1'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: rake
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -94,7 +94,7 @@ dependencies:
|
|
94
94
|
- - "~>"
|
95
95
|
- !ruby/object:Gem::Version
|
96
96
|
version: '0.9'
|
97
|
-
description:
|
97
|
+
description: A code-first approach to automate the writing of unit tests.
|
98
98
|
email: contact@cyril.email
|
99
99
|
executables:
|
100
100
|
- brutal
|
@@ -107,6 +107,7 @@ files:
|
|
107
107
|
- lib/brutal.rb
|
108
108
|
- lib/brutal/scaffold_generator/base.rb
|
109
109
|
- lib/brutal/scaffold_generator/por.rb
|
110
|
+
- lib/brutal/scaffold_generator/rspec.rb
|
110
111
|
homepage: https://github.com/fixrb/brutal
|
111
112
|
licenses:
|
112
113
|
- MIT
|
@@ -129,5 +130,5 @@ requirements: []
|
|
129
130
|
rubygems_version: 3.1.2
|
130
131
|
signing_key:
|
131
132
|
specification_version: 4
|
132
|
-
summary:
|
133
|
+
summary: A code-first approach to automate the writing of unit tests.
|
133
134
|
test_files: []
|