brutal 0.2.1 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 68550f0dd2c889c98a665a1ddd83dc0dccad1142858f5520af54f9ef3e0bd8e2
4
- data.tar.gz: 9756e39c673ef3a85b4556e85f8fff0d0841e207dfe414a2c230dc02c21a40e6
3
+ metadata.gz: 8e7af479b185bf19e8cb7050360c79d216af2916668e76efb0d7c550e553af4b
4
+ data.tar.gz: e917683e2edd247429cb9776444e6a97c10b9930265459a10ac8a3b4dbcf2cf6
5
5
  SHA512:
6
- metadata.gz: de1dd6a46db62eddebabc9f0211d99378f0770be1d096499de82c4a427fcde3eadc4e438e8752adafbf03feb1198e2d95134b7176c925d7995c15445a072d30c
7
- data.tar.gz: 14f650e0b87ef69d5e95b75e1beedc3ded6db3f8b21c20a675dfe1dd423dd2fc3f282af6056fdd0eedbf15f740b27dd30013b05a9aab95545bda59c9bc596392
6
+ metadata.gz: ad95d20234be22ed17de738afa0f1f1e0a5518cbf967fe87f9f1932f571e13d683a454354dd792f07d55010033dfd257b888422a880a4bd6c0f04ed19cf284ed
7
+ data.tar.gz: c4e82e9a5036e134e83f86c313277573926fe0773ef3e2e43145d30fb725ba6a7a196f881f090f083589ac447889b7aa10d1d7e450ec550f468792991bffb824
data/README.md CHANGED
@@ -1,14 +1,23 @@
1
- # Brutal
1
+ # Brutal 👹
2
2
 
3
- > Brutal test suite scaffold generator
4
-
5
- ![A lumberjack brutally cutting a tree.](https://raw.githubusercontent.com/fixrb/brutal/master/img/Ferdinand_Hodler_-_Woodcutter_-_Google_Art_Project.jpg)
3
+ > I don't like testing because it's redundant. If we are smart enough, we can avoid it. <br/>
4
+ > -- Matz
6
5
 
7
6
  [![Build Status](https://api.travis-ci.org/fixrb/brutal.svg?branch=master)][travis]
8
7
  [![Gem Version](https://badge.fury.io/rb/brutal.svg)][gem]
9
8
  [![Inline docs](https://inch-ci.org/github/fixrb/brutal.svg?branch=master)][inchpages]
10
9
  [![Documentation](http://img.shields.io/:yard-docs-38c800.svg)][rubydoc]
11
10
 
11
+ __Brutal__ is a _code-first_ approach that automates the writing of unit tests.
12
+
13
+ By being able to generate test cases from the code itself, developers can focus on their creation, save time and energy, for more happiness.
14
+
15
+ <p>
16
+ <img
17
+ src="https://github.com/fixrb/brutal/raw/master/img/Ferdinand_Hodler_-_Woodcutter_-_Google_Art_Project.jpg"
18
+ alt="A lumberjack brutally cutting a tree" />
19
+ </p>
20
+
12
21
  ## Installation
13
22
 
14
23
  Add this line to your application's Gemfile:
@@ -34,9 +43,10 @@ Just type `brutal` in a Ruby project's folder and watch the magic happen.
34
43
  The Brutal YAML file handles 4 keys:
35
44
 
36
45
  * `header` (optional): Some code to execute before the test suite.
37
- * `subject` (required): The front object of the test suite.
38
- * `variables` (required): A hash to decline the subject in to various contexts.
39
- * `challenges` (required): An array of methods to apply to each result.
46
+ * `front_object` (required): The front object of the test suite.
47
+ * `subject` (required): The object of each context.
48
+ * `variables` (required): A hash to generate the subject of each context.
49
+ * `actual_values` (required): A list of tests to challenge the subject.
40
50
 
41
51
  ## Example
42
52
 
@@ -44,61 +54,43 @@ Given this `.brutal.yml` config file:
44
54
 
45
55
  ```yaml
46
56
  ---
47
- header: |
48
- # Some string concatenation unit tests
57
+ front_object: |
58
+ "Hello "
49
59
 
50
60
  subject: |
51
- "Hello" + "%{hello_target}%{punctuation_mark}"
61
+ %{front_object} + %{string}
52
62
 
53
63
  variables:
54
- :hello_target:
55
- -
56
- - ", Bob"
57
-
58
- :punctuation_mark:
59
- - "!"
60
- - ...
64
+ string:
65
+ - "'Alice'"
66
+ - "'Bob'"
61
67
 
62
- challenges:
63
- - "%{actual}.to_s"
64
- - "%{actual}.length"
68
+ actual_values:
69
+ - "%{subject}.to_s"
70
+ - "%{subject}.length"
65
71
  ```
66
72
 
67
- The `brutal` command would generate the following file:
73
+ The `brutal` command would save this Plain Old Ruby in to a `test.rb` file:
68
74
 
69
75
  ```ruby
70
- # Some string concatenation unit tests
71
-
72
- # ------------------------------------------------------------------------------
73
-
74
- actual = "Hello" + "!"
75
-
76
- raise unless actual.to_s == "Hello!"
77
- raise unless actual.length == 6
78
-
79
- # ------------------------------------------------------------------------------
80
-
81
- actual = "Hello" + "..."
82
-
83
- raise unless actual.to_s == "Hello..."
84
- raise unless actual.length == 8
76
+ front_object = "Hello "
85
77
 
86
78
  # ------------------------------------------------------------------------------
87
79
 
88
- actual = "Hello" + ", Bob!"
89
-
90
- raise unless actual.to_s == "Hello, Bob!"
80
+ actual = front_object + 'Alice'
81
+ raise unless actual.to_s == "Hello Alice"
91
82
  raise unless actual.length == 11
92
83
 
93
84
  # ------------------------------------------------------------------------------
94
85
 
95
- actual = "Hello" + ", Bob..."
96
-
97
- raise unless actual.to_s == "Hello, Bob..."
98
- raise unless actual.length == 13
86
+ actual = front_object + 'Bob'
87
+ raise unless actual.to_s == "Hello Bob"
88
+ raise unless actual.length == 9
99
89
  ```
100
90
 
101
- ## Integration with Rake
91
+ [More examples](examples/) are available.
92
+
93
+ ## Rake integration example
102
94
 
103
95
  The generated brutal test suite `test.rb` file can be declared as follows:
104
96
 
@@ -119,6 +111,10 @@ end
119
111
  * [Rubinius](https://rubinius.com/)
120
112
  * [JRuby](https://www.jruby.org/)
121
113
 
114
+ ## Versioning
115
+
116
+ __Brutal__ follows [Semantic Versioning 2.0](https://semver.org/).
117
+
122
118
  ## Contributing
123
119
 
124
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).
@@ -135,3 +131,12 @@ Everyone interacting in the GreatGuardian project's codebases, issue trackers, c
135
131
  [travis]: https://travis-ci.org/fixrb/brutal
136
132
  [inchpages]: https://inch-ci.org/github/fixrb/brutal
137
133
  [rubydoc]: https://rubydoc.info/gems/brutal/frames
134
+
135
+ ***
136
+
137
+ <p>
138
+ This project is sponsored by:<br />
139
+ <a href="https://sashite.com/"><img
140
+ src="https://github.com/fixrb/brutal/raw/master/img/sashite.png"
141
+ alt="Sashite" /></a>
142
+ </p>
data/bin/brutal CHANGED
@@ -10,29 +10,34 @@ abort "File #{CONF_PATH} not found!" unless ::File.exist?(CONF_PATH)
10
10
 
11
11
  conf = ::YAML.load_file(CONF_PATH)
12
12
 
13
- header = conf.fetch('header', '')
14
- subject = conf.fetch('subject')
15
- challenges = conf.fetch('challenges')
16
- variables = conf.fetch('variables')
13
+ header = conf.fetch('header', '').to_s.chomp
14
+ front_object = conf.fetch('front_object')
15
+ subject = conf.fetch('subject')
16
+ variables = conf.fetch('variables', {})
17
+ actual_values = conf.fetch('actual_values')
17
18
 
18
- raise ::TypeError unless header.is_a?(::String)
19
- raise ::TypeError unless challenges.is_a?(::Array)
19
+ raise ::TypeError unless subject.is_a?(::String)
20
20
  raise ::TypeError unless variables.is_a?(::Hash)
21
+ raise ::TypeError unless actual_values.is_a?(::Array)
22
+
23
+ front_object = front_object.chomp if front_object.is_a?(::String)
21
24
 
22
25
  require_relative ::File.join('..', 'lib', 'brutal')
23
26
 
24
- brutal_scaffold = case ARGV.fetch(0, nil)
25
- when nil
26
- ::Brutal::Framework::Por
27
- else
28
- abort "Framework #{ARGV[0].inspect} not (yet) supported!"
29
- end
27
+ scaffold = case ARGV.fetch(0, nil)
28
+ when nil
29
+ ::Brutal::ScaffoldGenerator::Por
30
+ else
31
+ abort "#{ARGV[0].inspect} not (yet) supported!"
32
+ end
30
33
 
31
- eval(header)
34
+ eval(header) # rubocop:disable Security/Eval
32
35
 
33
- brutal_specs = header + brutal_scaffold.new(subject, *challenges, **variables)
34
- .to_s
36
+ doc = [
37
+ header,
38
+ scaffold.new(front_object, subject, *actual_values, **variables).to_s
39
+ ].reject(&:empty?).join("\n")
35
40
 
36
41
  file = ::File.open('test.rb', 'w')
37
- file.write(brutal_specs)
42
+ file.write(doc)
38
43
  file.close
data/lib/brutal.rb CHANGED
@@ -6,6 +6,6 @@
6
6
  module Brutal
7
7
  end
8
8
 
9
- Dir[File.join File.dirname(__FILE__), 'brutal', 'framework', '*.rb'].each do |fname|
9
+ Dir[File.join File.dirname(__FILE__), 'brutal', 'scaffold_generator', '*.rb'].each do |fname|
10
10
  require_relative fname
11
11
  end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Brutal
4
+ module ScaffoldGenerator
5
+ # Base class
6
+ class Base
7
+ # @api private
8
+ attr_reader :front_object_str, :front_object, :subject, :actual_values, :variables
9
+
10
+ # Initialize a new scaffold generator
11
+ def initialize(front_object, subject, *actual_values, **variables)
12
+ raise 'Empty actual values!' if actual_values.empty?
13
+ raise 'Empty variables!' if variables.empty?
14
+
15
+ @front_object_str = inspect(front_object)
16
+ @front_object = eval(@front_object_str) # rubocop:disable Security/Eval
17
+ @subject = subject
18
+ @actual_values = actual_values
19
+ @variables = variables
20
+ end
21
+
22
+ # Return a Ruby string that can be evaluated.
23
+ def inspect(object)
24
+ return object.to_s unless object.is_a?(::String)
25
+
26
+ object.strip
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,52 @@
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 Por < 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
+ blank_line +
24
+ "front_object = #{front_object_str}\n" +
25
+ blank_line +
26
+ test_params.map do |values|
27
+ attributes = names.each_with_index.inject(front_object: 'front_object') do |h, (name, i)|
28
+ h.merge(name.to_sym => inspect(values.fetch(i)))
29
+ end
30
+
31
+ actual_str = format(inspect(subject), **attributes)
32
+
33
+ string = "actual = #{actual_str}\n"
34
+ actual = eval(actual_str) # rubocop:disable Security/Eval, Lint/UselessAssignment
35
+
36
+ actual_values.each do |actual_value|
37
+ result_str = format(actual_value, subject: 'actual')
38
+ string += "raise unless #{result_str} == #{eval(result_str).inspect}\n" # rubocop:disable Security/Eval
39
+ end
40
+
41
+ string
42
+ end.join(blank_line)
43
+ end
44
+
45
+ def blank_line
46
+ "\n" \
47
+ "# #{('-' * 78)}\n" \
48
+ "\n"
49
+ end
50
+ end
51
+ end
52
+ 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.2.1
4
+ version: 0.3.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-17 00:00:00.000000000 Z
11
+ date: 2019-12-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -94,7 +94,7 @@ dependencies:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
96
  version: '0.9'
97
- description: Brutal test suite scaffold generator
97
+ description: Scaffolds test cases from the code itself.
98
98
  email: contact@cyril.email
99
99
  executables:
100
100
  - brutal
@@ -105,8 +105,8 @@ files:
105
105
  - README.md
106
106
  - bin/brutal
107
107
  - lib/brutal.rb
108
- - lib/brutal/framework/base.rb
109
- - lib/brutal/framework/por.rb
108
+ - lib/brutal/scaffold_generator/base.rb
109
+ - lib/brutal/scaffold_generator/por.rb
110
110
  homepage: https://github.com/fixrb/brutal
111
111
  licenses:
112
112
  - MIT
@@ -126,8 +126,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
126
126
  - !ruby/object:Gem::Version
127
127
  version: '0'
128
128
  requirements: []
129
- rubygems_version: 3.0.6
129
+ rubygems_version: 3.1.2
130
130
  signing_key:
131
131
  specification_version: 4
132
- summary: Brutal test suite scaffold generator
132
+ summary: Scaffolds test cases from the code itself.
133
133
  test_files: []
@@ -1,22 +0,0 @@
1
- module Brutal
2
- module Framework
3
- class Base
4
- # @api private
5
- attr_reader :subject, :challenges, :variables
6
-
7
- # Initialize a new framework
8
- def initialize(subject, *challenges, **variables)
9
- @subject = subject
10
- @challenges = challenges
11
- @variables = variables
12
- end
13
-
14
- # Return a string representation
15
- #
16
- # @api private
17
- def to_s
18
- raise ::NotImplementedError
19
- end
20
- end
21
- end
22
- end
@@ -1,41 +0,0 @@
1
- require_relative 'base'
2
-
3
- module Brutal
4
- module Framework
5
- # Plain Old Ruby
6
- class Por < Base
7
- # Return a string representation
8
- #
9
- # @return [String]
10
- #
11
- # @api public
12
- def to_s
13
- names = variables.keys.sort
14
- values_arr = names.map { |name| variables.fetch(name) }
15
- test_params = Array(values_arr[0]).product(*Array(values_arr[1..-1]))
16
-
17
- test_params.inject('') do |string, values|
18
- attributes = names.each_with_index.inject({}) do |h, (name, i)|
19
- h.merge(name.to_sym => values.fetch(i))
20
- end
21
-
22
- actual_str = subject % attributes
23
-
24
- string += "\n" \
25
- "# #{('-' * 78)}\n" \
26
- "\n" \
27
- "actual = #{actual_str}\n"
28
-
29
- actual = eval(actual_str)
30
-
31
- challenges.each do |challenge|
32
- result = challenge % { actual: 'actual' }
33
- string += "raise unless #{result} == #{eval(result).inspect}\n"
34
- end
35
-
36
- string
37
- end
38
- end
39
- end
40
- end
41
- end