spec_forge 0.6.0 → 0.7.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.
Files changed (83) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +112 -2
  3. data/README.md +133 -8
  4. data/flake.lock +3 -3
  5. data/flake.nix +3 -3
  6. data/lib/spec_forge/attribute/factory.rb +1 -1
  7. data/lib/spec_forge/callbacks.rb +9 -0
  8. data/lib/spec_forge/cli/docs/generate.rb +72 -0
  9. data/lib/spec_forge/cli/docs.rb +92 -0
  10. data/lib/spec_forge/cli/init.rb +39 -7
  11. data/lib/spec_forge/cli/new.rb +13 -3
  12. data/lib/spec_forge/cli/run.rb +12 -4
  13. data/lib/spec_forge/cli/serve.rb +155 -0
  14. data/lib/spec_forge/cli.rb +14 -6
  15. data/lib/spec_forge/configuration.rb +2 -2
  16. data/lib/spec_forge/context/store.rb +23 -40
  17. data/lib/spec_forge/core_ext/array.rb +27 -0
  18. data/lib/spec_forge/documentation/builder.rb +383 -0
  19. data/lib/spec_forge/documentation/document/operation.rb +47 -0
  20. data/lib/spec_forge/documentation/document/parameter.rb +22 -0
  21. data/lib/spec_forge/documentation/document/request_body.rb +24 -0
  22. data/lib/spec_forge/documentation/document/response.rb +39 -0
  23. data/lib/spec_forge/documentation/document/response_body.rb +27 -0
  24. data/lib/spec_forge/documentation/document.rb +48 -0
  25. data/lib/spec_forge/documentation/generators/base.rb +81 -0
  26. data/lib/spec_forge/documentation/generators/openapi/base.rb +100 -0
  27. data/lib/spec_forge/documentation/generators/openapi/error_formatter.rb +149 -0
  28. data/lib/spec_forge/documentation/generators/openapi/v3_0.rb +65 -0
  29. data/lib/spec_forge/documentation/generators/openapi.rb +59 -0
  30. data/lib/spec_forge/documentation/generators.rb +17 -0
  31. data/lib/spec_forge/documentation/loader/cache.rb +138 -0
  32. data/lib/spec_forge/documentation/loader.rb +159 -0
  33. data/lib/spec_forge/documentation/openapi/base.rb +33 -0
  34. data/lib/spec_forge/documentation/openapi/v3_0/example.rb +44 -0
  35. data/lib/spec_forge/documentation/openapi/v3_0/media_type.rb +42 -0
  36. data/lib/spec_forge/documentation/openapi/v3_0/operation.rb +175 -0
  37. data/lib/spec_forge/documentation/openapi/v3_0/response.rb +65 -0
  38. data/lib/spec_forge/documentation/openapi/v3_0/schema.rb +80 -0
  39. data/lib/spec_forge/documentation/openapi/v3_0/tag.rb +71 -0
  40. data/lib/spec_forge/documentation/openapi.rb +23 -0
  41. data/lib/spec_forge/documentation.rb +27 -0
  42. data/lib/spec_forge/error.rb +17 -0
  43. data/lib/spec_forge/factory.rb +2 -2
  44. data/lib/spec_forge/filter.rb +3 -4
  45. data/lib/spec_forge/forge.rb +5 -4
  46. data/lib/spec_forge/http/backend.rb +2 -0
  47. data/lib/spec_forge/http/request.rb +14 -3
  48. data/lib/spec_forge/loader.rb +14 -24
  49. data/lib/spec_forge/normalizer/default.rb +51 -0
  50. data/lib/spec_forge/normalizer/definition.rb +248 -0
  51. data/lib/spec_forge/normalizer/validators.rb +99 -0
  52. data/lib/spec_forge/normalizer.rb +356 -199
  53. data/lib/spec_forge/normalizers/_shared.yml +74 -0
  54. data/lib/spec_forge/normalizers/configuration.yml +23 -0
  55. data/lib/spec_forge/normalizers/constraint.yml +8 -0
  56. data/lib/spec_forge/normalizers/expectation.yml +47 -0
  57. data/lib/spec_forge/normalizers/factory.yml +12 -0
  58. data/lib/spec_forge/normalizers/factory_reference.yml +15 -0
  59. data/lib/spec_forge/normalizers/global_context.yml +28 -0
  60. data/lib/spec_forge/normalizers/spec.yml +50 -0
  61. data/lib/spec_forge/runner/adapter.rb +183 -0
  62. data/lib/spec_forge/runner/debug_proxy.rb +3 -3
  63. data/lib/spec_forge/runner/state.rb +4 -5
  64. data/lib/spec_forge/runner.rb +40 -124
  65. data/lib/spec_forge/spec/expectation/constraint.rb +13 -5
  66. data/lib/spec_forge/spec/expectation.rb +7 -3
  67. data/lib/spec_forge/spec.rb +13 -58
  68. data/lib/spec_forge/version.rb +1 -1
  69. data/lib/spec_forge.rb +30 -23
  70. data/lib/templates/openapi.yml.tt +22 -0
  71. data/lib/templates/redoc.html.tt +28 -0
  72. data/lib/templates/swagger.html.tt +59 -0
  73. metadata +92 -14
  74. data/lib/spec_forge/normalizer/configuration.rb +0 -90
  75. data/lib/spec_forge/normalizer/constraint.rb +0 -60
  76. data/lib/spec_forge/normalizer/expectation.rb +0 -105
  77. data/lib/spec_forge/normalizer/factory.rb +0 -78
  78. data/lib/spec_forge/normalizer/factory_reference.rb +0 -85
  79. data/lib/spec_forge/normalizer/global_context.rb +0 -88
  80. data/lib/spec_forge/normalizer/spec.rb +0 -97
  81. /data/lib/templates/{forge_helper.tt → forge_helper.rb.tt} +0 -0
  82. /data/lib/templates/{new_factory.tt → new_factory.yml.tt} +0 -0
  83. /data/lib/templates/{new_spec.tt → new_spec.yml.tt} +0 -0
@@ -1,60 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module SpecForge
4
- class Normalizer
5
- #
6
- # Normalizes constraint hash structure for expectations
7
- #
8
- # Ensures that expectation constraints (status, json, etc.)
9
- # have the correct structure and defaults.
10
- #
11
- class Constraint < Normalizer
12
- #
13
- # Defines the normalized structure for configuration validation
14
- #
15
- # Specifies validation rules for configuration attributes:
16
- # - Enforces specific data types
17
- # - Provides default values
18
- # - Supports alternative key names
19
- #
20
- # @return [Hash] Configuration attribute validation rules
21
- #
22
- STRUCTURE = {
23
- status: {
24
- type: [Integer, String]
25
- },
26
- json: {
27
- type: [Hash, Array],
28
- default: {}
29
- }
30
- }.freeze
31
- end
32
-
33
- # On Normalizer
34
- class << self
35
- #
36
- # Generates an empty constraint hash
37
- #
38
- # @return [Hash] Default constraint hash
39
- #
40
- def default_constraint
41
- Constraint.default
42
- end
43
-
44
- #
45
- # Normalize a constraint hash
46
- #
47
- # @param constraint [Hash] Constraint hash
48
- #
49
- # @return [Array] [normalized_hash, errors]
50
- #
51
- # @private
52
- #
53
- def normalize_constraint(constraint)
54
- raise Error::InvalidTypeError.new(constraint, Hash, for: "expect") unless Type.hash?(constraint)
55
-
56
- Normalizer::Constraint.new("expect", constraint).normalize
57
- end
58
- end
59
- end
60
- end
@@ -1,105 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module SpecForge
4
- class Normalizer
5
- #
6
- # Normalizes expectation hash structure
7
- #
8
- # Ensures that expectation definitions have the correct structure
9
- # and default values for all required settings.
10
- #
11
- class Expectation < Normalizer
12
- #
13
- # Defines the normalized structure for configuration validation
14
- #
15
- # Specifies validation rules for configuration attributes:
16
- # - Enforces specific data types
17
- # - Provides default values
18
- # - Supports alternative key names
19
- #
20
- # @return [Hash] Configuration attribute validation rules
21
- #
22
- STRUCTURE = {
23
- # Internal
24
- id: Normalizer::SHARED_ATTRIBUTES[:id],
25
- line_number: Normalizer::SHARED_ATTRIBUTES[:line_number],
26
-
27
- # User defined
28
- name: Normalizer::SHARED_ATTRIBUTES[:name],
29
- base_url: Normalizer::SHARED_ATTRIBUTES[:base_url],
30
- url: Normalizer::SHARED_ATTRIBUTES[:url],
31
- http_verb: Normalizer::SHARED_ATTRIBUTES[:http_verb],
32
- headers: Normalizer::SHARED_ATTRIBUTES[:headers],
33
- query: Normalizer::SHARED_ATTRIBUTES[:query],
34
- body: Normalizer::SHARED_ATTRIBUTES[:body],
35
- variables: Normalizer::SHARED_ATTRIBUTES[:variables],
36
- debug: Normalizer::SHARED_ATTRIBUTES[:debug],
37
- store_as: {type: String, default: ""},
38
- expect: {type: Hash}
39
- }.freeze
40
- end
41
-
42
- # On Normalizer
43
- class << self
44
- #
45
- # Generates an empty expectation hash
46
- #
47
- # @return [Hash] Default expectation hash
48
- #
49
- def default_expectation
50
- Expectation.default
51
- end
52
-
53
- #
54
- # Normalize an array of expectation hashes
55
- #
56
- # @param input [Array<Hash>] The array to normalize
57
- #
58
- # @return [Array<Hash>] Normalized array of expectation hashes
59
- #
60
- # @raise [Error::InvalidStructureError] If validation fails
61
- #
62
- def normalize_expectations!(input)
63
- raise_errors! do
64
- normalize_expectations(input)
65
- end
66
- end
67
-
68
- #
69
- # Normalize an array of expectation hashes
70
- #
71
- # @param expectations [Array<Hash>] Array of expectation hashes
72
- #
73
- # @return [Array] [normalized_array, errors]
74
- #
75
- # @private
76
- #
77
- def normalize_expectations(expectations)
78
- if !Type.array?(expectations)
79
- raise Error::InvalidTypeError.new(expectations, Array, for: "\"expectations\" on spec")
80
- end
81
-
82
- final_errors = Set.new
83
- final_output = expectations.map.with_index do |expectation, index|
84
- normalizer = Normalizer::Expectation.new("expectation (item #{index})", expectation)
85
- output, errors = normalizer.normalize
86
-
87
- # If expect is not provided, skip the constraints
88
- if (constraint = expectation[:expect])
89
- constraint_output, constraint_errors = Normalizer::Constraint.new(
90
- "expect (item #{index})", constraint
91
- ).normalize
92
-
93
- output[:expect] = constraint_output
94
- errors.merge(constraint_errors) if constraint_errors.size > 0
95
- end
96
-
97
- final_errors.merge(errors) if errors.size > 0
98
- output
99
- end
100
-
101
- [final_output, final_errors]
102
- end
103
- end
104
- end
105
- end
@@ -1,78 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module SpecForge
4
- class Normalizer
5
- #
6
- # Normalizes factory hash structure
7
- #
8
- # Ensures that factory definitions have the correct structure
9
- # and default values for all required settings.
10
- #
11
- class Factory < Normalizer
12
- #
13
- # Defines the normalized structure for configuration validation
14
- #
15
- # Specifies validation rules for configuration attributes:
16
- # - Enforces specific data types
17
- # - Provides default values
18
- # - Supports alternative key names
19
- #
20
- # @return [Hash] Configuration attribute validation rules
21
- #
22
- STRUCTURE = {
23
- model_class: {
24
- type: String,
25
- aliases: %i[class],
26
- default: ""
27
- },
28
- variables: Normalizer::SHARED_ATTRIBUTES[:variables],
29
- attributes: {
30
- type: Hash,
31
- default: {}
32
- }
33
- }.freeze
34
- end
35
-
36
- # On Normalizer
37
- class << self
38
- #
39
- # Generates an empty factory hash
40
- #
41
- # @return [Hash] Default factory hash
42
- #
43
- def default_factory
44
- Factory.default
45
- end
46
-
47
- #
48
- # Normalizes a factory hash with validation
49
- #
50
- # @param input [Hash] The hash to normalize
51
- #
52
- # @return [Hash] A normalized hash with defaults applied
53
- #
54
- # @raise [Error::InvalidStructureError] If validation fails
55
- #
56
- def normalize_factory!(input)
57
- raise_errors! do
58
- normalize_factory(input)
59
- end
60
- end
61
-
62
- #
63
- # Normalize a factory hash
64
- #
65
- # @param factory [Hash] Factory hash
66
- #
67
- # @return [Array] [normalized_hash, errors]
68
- #
69
- # @private
70
- #
71
- def normalize_factory(factory)
72
- raise Error::InvalidTypeError.new(factory, Hash, for: "factory") unless Type.hash?(factory)
73
-
74
- Normalizer::Factory.new("factory", factory).normalize
75
- end
76
- end
77
- end
78
- end
@@ -1,85 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module SpecForge
4
- class Normalizer
5
- #
6
- # Normalizes factory reference hash structure
7
- #
8
- # Ensures that factory references have the correct structure
9
- # and default values for all required settings.
10
- #
11
- class FactoryReference < Normalizer
12
- #
13
- # Defines the normalized structure for configuration validation
14
- #
15
- # Specifies validation rules for configuration attributes:
16
- # - Enforces specific data types
17
- # - Provides default values
18
- # - Supports alternative key names
19
- #
20
- # @return [Hash] Configuration attribute validation rules
21
- #
22
- STRUCTURE = {
23
- attributes: {
24
- type: Hash,
25
- default: {}
26
- },
27
- build_strategy: {
28
- type: String,
29
- aliases: %i[strategy],
30
- default: "create"
31
- },
32
- size: {
33
- type: Integer,
34
- aliases: %i[count],
35
- default: 0
36
- }
37
- }.freeze
38
- end
39
-
40
- # On Normalizer
41
- class << self
42
- #
43
- # Generates an empty factory reference hash
44
- #
45
- # @return [Hash] Default factory reference hash
46
- #
47
- def default_factory_reference
48
- FactoryReference.default
49
- end
50
-
51
- #
52
- # Normalizes a factory reference hash with validation
53
- #
54
- # @param input [Hash] The hash to normalize
55
- #
56
- # @return [Hash] A normalized hash with defaults applied
57
- #
58
- # @raise [Error::InvalidStructureError] If validation fails
59
- #
60
- def normalize_factory_reference!(input, **)
61
- raise_errors! do
62
- normalize_factory_reference(input, **)
63
- end
64
- end
65
-
66
- #
67
- # Normalize a factory reference hash
68
- #
69
- # @param factory [Hash] Factory reference hash
70
- # @param label [String] Label for error messages
71
- #
72
- # @return [Array] [normalized_hash, errors]
73
- #
74
- # @private
75
- #
76
- def normalize_factory_reference(factory, label: "factory reference")
77
- if !Type.hash?(factory)
78
- raise Error::InvalidTypeError.new(factory, Hash, for: "factory reference")
79
- end
80
-
81
- Normalizer::FactoryReference.new(label, factory).normalize
82
- end
83
- end
84
- end
85
- end
@@ -1,88 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module SpecForge
4
- class Normalizer
5
- #
6
- # Normalizes global context hash structure
7
- #
8
- # Ensures that global context definitions have the correct structure
9
- # and default values for all required settings.
10
- #
11
- class GlobalContext < Normalizer
12
- #
13
- # Defines the normalized structure for configuration validation
14
- #
15
- # Specifies validation rules for configuration attributes:
16
- # - Enforces specific data types
17
- # - Provides default values
18
- # - Supports alternative key names
19
- #
20
- # @return [Hash] Configuration attribute validation rules
21
- #
22
- STRUCTURE = {
23
- variables: Normalizer::SHARED_ATTRIBUTES[:variables],
24
- callbacks: {
25
- type: Array,
26
- default: [],
27
- structure: {
28
- type: Hash,
29
- default: {},
30
- structure: {
31
- before_file: Normalizer::SHARED_ATTRIBUTES[:callback],
32
- before_spec: Normalizer::SHARED_ATTRIBUTES[:callback],
33
- before_each: Normalizer::SHARED_ATTRIBUTES[:callback].merge(aliases: %i[before]),
34
- around_each: Normalizer::SHARED_ATTRIBUTES[:callback].merge(aliases: %i[around]),
35
- after_each: Normalizer::SHARED_ATTRIBUTES[:callback].merge(aliases: %i[after]),
36
- after_spec: Normalizer::SHARED_ATTRIBUTES[:callback],
37
- after_file: Normalizer::SHARED_ATTRIBUTES[:callback]
38
- }
39
- }
40
- }
41
- }.freeze
42
- end
43
-
44
- # On Normalizer
45
- class << self
46
- #
47
- # Generates an empty global context hash
48
- #
49
- # @return [Hash] Default global context hash
50
- #
51
- def default_global_context
52
- GlobalContext.default
53
- end
54
-
55
- #
56
- # Normalizes a global context hash with validation
57
- #
58
- # @param input [Hash] The hash to normalize
59
- #
60
- # @return [Hash] A normalized hash with defaults applied
61
- #
62
- # @raise [Error::InvalidStructureError] If validation fails
63
- #
64
- def normalize_global_context!(input)
65
- raise_errors! do
66
- normalize_global_context(input)
67
- end
68
- end
69
-
70
- #
71
- # Normalize a global context hash
72
- #
73
- # @param global [Hash] Global context hash
74
- #
75
- # @return [Array] [normalized_hash, errors]
76
- #
77
- # @private
78
- #
79
- def normalize_global_context(global)
80
- if !Type.hash?(global)
81
- raise Error::InvalidTypeError.new(global, Hash, for: "global context")
82
- end
83
-
84
- Normalizer::GlobalContext.new("global context", global).normalize
85
- end
86
- end
87
- end
88
- end
@@ -1,97 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module SpecForge
4
- class Normalizer
5
- #
6
- # Normalizes spec hash structure
7
- #
8
- # Ensures that spec definitions have the correct structure
9
- # and default values for all required settings.
10
- #
11
- class Spec < Normalizer
12
- #
13
- # Defines the normalized structure for configuration validation
14
- #
15
- # Specifies validation rules for configuration attributes:
16
- # - Enforces specific data types
17
- # - Provides default values
18
- # - Supports alternative key names
19
- #
20
- # @return [Hash] Configuration attribute validation rules
21
- #
22
- STRUCTURE = {
23
- # Internal
24
- id: Normalizer::SHARED_ATTRIBUTES[:id],
25
- name: Normalizer::SHARED_ATTRIBUTES[:name],
26
- file_name: {type: String},
27
- file_path: {type: String},
28
- line_number: Normalizer::SHARED_ATTRIBUTES[:line_number],
29
-
30
- # User defined
31
- base_url: Normalizer::SHARED_ATTRIBUTES[:base_url],
32
- url: Normalizer::SHARED_ATTRIBUTES[:url],
33
- http_verb: Normalizer::SHARED_ATTRIBUTES[:http_verb],
34
- headers: Normalizer::SHARED_ATTRIBUTES[:headers],
35
- query: Normalizer::SHARED_ATTRIBUTES[:query],
36
- body: Normalizer::SHARED_ATTRIBUTES[:body],
37
- variables: Normalizer::SHARED_ATTRIBUTES[:variables],
38
- debug: Normalizer::SHARED_ATTRIBUTES[:debug],
39
- expectations: {type: Array}
40
- }.freeze
41
- end
42
-
43
- # On Normalizer
44
- class << self
45
- #
46
- # Generates an empty spec hash
47
- #
48
- # @return [Hash] Default spec hash
49
- #
50
- def default_spec
51
- Spec.default
52
- end
53
-
54
- #
55
- # Normalizes a spec hash with validation and processes expectations
56
- #
57
- # @param input [Hash] The hash to normalize
58
- # @param label [String] Label for error messages
59
- #
60
- # @return [Hash] A normalized hash with defaults applied
61
- #
62
- # @raise [Error::InvalidStructureError] If validation fails
63
- #
64
- def normalize_spec!(input, label: "spec")
65
- raise_errors! do
66
- output, errors = normalize_spec(input, label:)
67
-
68
- # Process expectations
69
- if (expectations = input[:expectations]) && Type.array?(expectations)
70
- expectation_output, expectation_errors = normalize_expectations(expectations)
71
-
72
- output[:expectations] = expectation_output
73
- errors += expectation_errors if expectation_errors.size > 0
74
- end
75
-
76
- [output, errors]
77
- end
78
- end
79
-
80
- #
81
- # Normalize a spec hash
82
- #
83
- # @param spec [Hash] Spec hash
84
- # @param label [String] Label for error messages
85
- #
86
- # @return [Array] [normalized_hash, errors]
87
- #
88
- # @private
89
- #
90
- def normalize_spec(spec, label: "spec")
91
- raise Error::InvalidTypeError.new(spec, Hash, for: label) unless Type.hash?(spec)
92
-
93
- Normalizer::Spec.new(label, spec).normalize
94
- end
95
- end
96
- end
97
- end
File without changes