brutal 0.2.1 → 0.3.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 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