vident 0.2.2 → 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: 2279071e93c86a27cab51ac5e30ce0d84ae5696434120043c6a2ebfaab40a4a3
4
- data.tar.gz: 0e85654cb617dfffdfd42c6263f09c41c20a6d527dfb70d74fc71404b97cda13
3
+ metadata.gz: c2f2d014f440bdd33f9910c04ba79846825afb4c8a61bd6e5079079fd07c0473
4
+ data.tar.gz: fb730836ba6c63a582f97afcaceed12467a1b8ac92f2f5d9a0d871a4791c3de4
5
5
  SHA512:
6
- metadata.gz: 127bf0f2146fed5560fac39c40ec15f967ca55e96af800cb128d1524ed91be7aef13078d070de1b06a7801af32d7f79563a583709dbd0a20e0f72913ea9c0c02
7
- data.tar.gz: 75aee42b5f6942857bcbd3267914ec3aa031c9a2bfa3ef2b3489f57fde5d172f75508a17b8ce6a89a95791a2b270d182e1194906a1e21eee818ffdc8068f3c70
6
+ metadata.gz: da7e90adb10d5301803cde48f06685983478c01eec44bfe0c8db9a0909734572ccc1ee72490850655bc915f4c2de17d27b1191d3d649c53d7a23d2d1e40b83a2
7
+ data.tar.gz: 2626db1242b53e3abe20c75a8269125e564e1bc89a178f6e76feccda869ef2c41d671d0ece1a48f55441d6e4483e4962c76118ba48beba991529fe2e0ed322cc
data/Gemfile CHANGED
@@ -27,5 +27,7 @@ gem "sqlite3"
27
27
  gem "rake", "~> 13.0"
28
28
 
29
29
  gem "minitest", "~> 5.0"
30
+ gem "minitest-hooks"
31
+ gem "faker"
30
32
 
31
33
  gem "standard", "~> 1.3"
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ # TODO: what about when used with Phlex?
4
+ module Vident
5
+ class TestCase < ::ViewComponent::TestCase
6
+ include Vident::Testing::AutoTest
7
+ end
8
+ end
@@ -0,0 +1,176 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Vident
4
+ module Testing
5
+ class AttributesTester
6
+ def initialize(test_configurations)
7
+ @test_configurations = test_configurations
8
+ end
9
+
10
+ # Generates attribute hashes for all permutations of the given valid values.
11
+ def valid_configurations
12
+ # Expands any auto generated values and returns all attributes and their values
13
+ test_attrs = prepare_attributes_to_test
14
+
15
+ # The first permutation is the initial state
16
+ initial_state = prepare_initial_test_state(test_attrs)
17
+
18
+ # Create remaining permutations
19
+ test_attrs.flat_map do |attr_name, values|
20
+ values.map { |v| initial_state.merge(attr_name => v) }
21
+ end
22
+ end
23
+
24
+ # Generates attribute hashes for all permutations of the given invalid values.
25
+ def invalid_configurations
26
+ return [] unless invalid_configured?
27
+
28
+ # prepare a valid initial state, then add any attrs that have :invalid
29
+ initial_state = prepare_initial_test_state(prepare_attributes_to_test)
30
+
31
+ # Merge in the invalid permutations
32
+ test_configurations.inject([]) do |memo, attr|
33
+ key, opts = attr
34
+ next memo += nil if opts == :strict_boolean
35
+ if opts.is_a?(Hash)
36
+ values = if opts[:invalid].nil? && opts[:valid].is_a?(Hash)
37
+ # If no invalid key specified we generate based on whats valid
38
+ config = invalid_attribute_test_values_for(opts[:valid][:type], opts[:valid])
39
+ (config&.fetch(:invalid, []) || []) + (config&.fetch(:converts, []) || [])
40
+ elsif opts[:invalid].is_a?(Array)
41
+ opts[:invalid]
42
+ end
43
+
44
+ memo += values.map { |i| initial_state.merge(key => i) } if values
45
+ end
46
+ memo
47
+ end
48
+ end
49
+
50
+ private
51
+
52
+ attr_reader :test_configurations
53
+
54
+ def invalid_configured?
55
+ test_configurations.values.any? { |v| v.respond_to?(:key?) && v.key?(:invalid) }
56
+ end
57
+
58
+ def prepare_attributes_to_test
59
+ test_configurations.transform_values do |attr_config|
60
+ next [true, false, nil] if attr_config == :boolean
61
+ next [true, false] if attr_config == :strict_boolean
62
+ valid = attr_config[:valid]
63
+ raise "Ensure :valid attributes configuration is provided" unless valid
64
+ next valid if valid.is_a?(Array)
65
+ attribute_test_values_for(valid)
66
+ end
67
+ end
68
+
69
+ def prepare_initial_test_state(test_attrs)
70
+ initial_state = {}
71
+ test_attrs.each { |attr_name, values| initial_state[attr_name] = values.first }
72
+ initial_state
73
+ end
74
+
75
+ def attribute_test_values_for(options)
76
+ type = parse_type(options[:type])
77
+ return options[:in] if options[:in]
78
+ values =
79
+ case type
80
+ when :string, "String"
81
+ s = (1..8).map { |l| ::Faker::String.random(length: l) }
82
+ s.prepend "test string"
83
+ s = s.select(&:present?)
84
+ s << "" if options[:allow_blank]
85
+ s
86
+ when :boolean
87
+ [false, true]
88
+ when :float, "Float"
89
+ (1..3).map { Faker::Number.positive } + (1..3).map { Faker::Number.negative }
90
+ when :numeric, "Numeric"
91
+ (1..3).map { Faker::Number.positive } + [1, 5]
92
+ when :integer, "Integer"
93
+ min = options[:min] || -10_000
94
+ max = options[:max] || 10_000
95
+ (1..3).map { Kernel.rand(min..max) }
96
+ when :array, "Array"
97
+ a =
98
+ if options[:sub_type] == Numeric
99
+ [[1, 2, 3], [0.3, 2, 0.002]]
100
+ elsif options[:sub_type]
101
+ [[options[:sub_type].new]]
102
+ else
103
+ [%i[a b c], [1, 2, 3], %w[a b]]
104
+ end
105
+ a << [] if options[:allow_blank]
106
+ a
107
+ when :any
108
+ [false, 1245, {}, :df, "hi"]
109
+ when :hash, "Hash"
110
+ a = [{a: 1}]
111
+ a << {} if options[:allow_blank]
112
+ a
113
+ when :symbol, "Symbol"
114
+ %i[a b c]
115
+ else
116
+ raise StandardError, "Attribute type not understood (#{type})"
117
+ end
118
+
119
+ if options[:allow_nil] || !options[:default].nil? || (options[:allow_blank] && options[:allow_nil].nil?)
120
+ values << nil
121
+ end
122
+ values
123
+ end
124
+
125
+ def invalid_attribute_test_values_for(type, options)
126
+ values = case parse_type(type)
127
+ when :string, "String"
128
+ # All values are also convertable to string
129
+ a = {converts: [false, 1245, 1.0, {}, :df, []], invalid: []}
130
+ a[:invalid] << "" if options[:allow_blank] == false
131
+ a
132
+ when :boolean
133
+ # All values are also convertable to boolean with !!
134
+ {converts: ["sdf", 234, 3.5, {}, :sdf, []], invalid: []}
135
+ when :float, "Float"
136
+ # Not all values are convertable to float
137
+ {converts: [234, "12.2"], invalid: ["sdf", 234, {}, :sdf, [], false]}
138
+ when :numeric, "Numeric"
139
+ {converts: ["12.2"], invalid: ["sdf", {}, :sdf, [], false]}
140
+ when :integer, "Integer"
141
+ # Not all values are convertable to integer
142
+ {converts: [234.0, "123", "sdf"], invalid: [{}, :sdf, [], false]}
143
+ when :array, "Array"
144
+ # Not all values are convertable to array
145
+ a = if options[:sub_type]
146
+ {converts: [{}, [{}]], invalid: ["sdf", [123], [Class.new]]}
147
+ else
148
+ {converts: [{}], invalid: ["sdf", 234, 3.5, :sdf, false]}
149
+ end
150
+ a[:invalid] << [] if options[:allow_blank] == false
151
+ a
152
+ when :any
153
+ # There are no invalid values
154
+ {converts: [], invalid: []}
155
+ when :hash, "Hash"
156
+ a = {converts: [[], [[:a, 1], [:b, 2]]], invalid: [:sdf, false, "boo", 123]}
157
+ a[:invalid] << {} if options[:allow_blank] == false
158
+ a
159
+ when :symbol, "Symbol"
160
+ {converts: ["foo"], invalid: [{}, false, [], 123]}
161
+ else
162
+ raise StandardError, "Attribute type not understood (#{type})"
163
+ end
164
+
165
+ if options[:default].nil? && (!options[:allow_nil] || (!options[:allow_blank] && options[:allow_nil] != true))
166
+ values[:invalid] << nil
167
+ end
168
+ values
169
+ end
170
+
171
+ def parse_type(type)
172
+ type.is_a?(Symbol) ? type : type.name
173
+ end
174
+ end
175
+ end
176
+ end
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "minitest/hooks"
4
+
5
+ module Vident
6
+ module Testing
7
+ module AutoTest
8
+ extend ActiveSupport::Concern
9
+
10
+ included do
11
+ include Minitest::Hooks
12
+
13
+ def before_all
14
+ @results_content = []
15
+ ::Vident::StableId.set_current_sequence_generator
16
+ end
17
+
18
+ def after_all
19
+ html = <<~HTML
20
+ <!doctype html>
21
+ <html lang="en">
22
+ <head>
23
+ <meta charset="UTF-8">
24
+ <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
25
+ <meta http-equiv="X-UA-Compatible" content="ie=edge">
26
+ <title>Test run output</title>
27
+ </head>
28
+ <body>
29
+ #{@results_content.map(&:to_s).join("<hr>\n").html_safe}
30
+ </body>
31
+ </html>
32
+ HTML
33
+
34
+ # TODO: configurable layout
35
+ filename = self.class.name.gsub("::", "_")
36
+ File.write("render_results_#{filename}.html", html) # TODO: path for outputs (eg default tmp/)
37
+ end
38
+ end
39
+
40
+ class_methods do
41
+ def auto_test(class_under_test, **param_config)
42
+ attribute_tester = Vident::Testing::AttributesTester.new(param_config)
43
+ attribute_tester.valid_configurations.each_with_index do |test, index|
44
+ class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
45
+ def test_renders_with_valid_attrs_#{index}
46
+ test_attrs = #{test}
47
+ begin
48
+ render_inline(#{class_under_test}.new(**test_attrs))
49
+ rescue => error
50
+ assert(false, "Should not raise with #{test.to_s.tr("\"", "'")} but did raise \#{error}")
51
+ end
52
+ end
53
+ RUBY
54
+ end
55
+
56
+ attribute_tester.invalid_configurations.each_with_index do |test, index|
57
+ class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
58
+ def test_raises_with_invalid_attrs_#{index}
59
+ test_attrs = #{test}
60
+ assert_raises(StandardError, "Should raise with #{test.to_s.tr("\"", "'")}") do
61
+ render_inline(#{class_under_test}.new(**test_attrs))
62
+ end
63
+ end
64
+ RUBY
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Vident
4
- VERSION = "0.2.2"
4
+ VERSION = "0.3.0"
5
5
  end
data/lib/vident.rb CHANGED
@@ -32,3 +32,9 @@ require_relative "vident/base"
32
32
  require_relative "vident/component"
33
33
  require_relative "vident/typed_component"
34
34
  require_relative "vident/caching/cache_key"
35
+
36
+ require_relative "vident/testing/attributes_tester"
37
+ require_relative "vident/testing/auto_test"
38
+
39
+ # TODO: what if not using view_component?
40
+ require_relative "vident/test_case"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: vident
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.2
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Stephen Ierodiaconou
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-01-04 00:00:00.000000000 Z
11
+ date: 2023-01-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -60,6 +60,9 @@ files:
60
60
  - lib/vident/root_component/using_phlex_html.rb
61
61
  - lib/vident/root_component/using_view_component.rb
62
62
  - lib/vident/stable_id.rb
63
+ - lib/vident/test_case.rb
64
+ - lib/vident/testing/attributes_tester.rb
65
+ - lib/vident/testing/auto_test.rb
63
66
  - lib/vident/typed_component.rb
64
67
  - lib/vident/version.rb
65
68
  - sig/vident.rbs