fitting 3.0.2 → 4.0.1

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 (85) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.ruby-version +1 -1
  4. data/CHANGELOG.md +16 -0
  5. data/README.md +327 -108
  6. data/fitting.gemspec +2 -2
  7. data/images/b1.png +0 -0
  8. data/images/b2.png +0 -0
  9. data/images/w1.png +0 -0
  10. data/images/w2.png +0 -0
  11. data/lib/fitting/action.rb +105 -0
  12. data/lib/fitting/cover/json_schema.rb +2 -2
  13. data/lib/fitting/cover/json_schema_one_of.rb +4 -2
  14. data/lib/fitting/debug.rb +47 -0
  15. data/lib/fitting/doc/action.rb +141 -0
  16. data/lib/fitting/doc/code.rb +53 -0
  17. data/lib/fitting/doc/combination_enum.rb +110 -0
  18. data/lib/fitting/doc/combination_one_of.rb +61 -0
  19. data/lib/fitting/doc/combination_optional.rb +54 -0
  20. data/lib/fitting/doc/combination_step.rb +48 -0
  21. data/lib/fitting/doc/content_type.rb +152 -0
  22. data/lib/fitting/doc/json_schema.rb +112 -0
  23. data/lib/fitting/doc/step.rb +102 -0
  24. data/lib/fitting/doc.rb +107 -0
  25. data/lib/fitting/host.rb +37 -0
  26. data/lib/fitting/log.rb +102 -0
  27. data/lib/fitting/nocov.rb +68 -0
  28. data/lib/fitting/prefix.rb +62 -0
  29. data/lib/fitting/railtie.rb +0 -1
  30. data/lib/fitting/records/spherical/request.rb +7 -4
  31. data/lib/fitting/records/spherical/response.rb +22 -16
  32. data/lib/fitting/records/tested/request.rb +6 -1
  33. data/lib/fitting/records/tested/response.rb +6 -1
  34. data/lib/fitting/rep/html.rb +32 -0
  35. data/lib/fitting/rep.rb +24 -0
  36. data/lib/fitting/report/action.rb +9 -15
  37. data/lib/fitting/report/actions.rb +22 -33
  38. data/lib/fitting/report/combination.rb +10 -6
  39. data/lib/fitting/report/combinations.rb +9 -29
  40. data/lib/fitting/report/prefix.rb +7 -24
  41. data/lib/fitting/report/prefixes.rb +11 -25
  42. data/lib/fitting/report/response.rb +12 -22
  43. data/lib/fitting/report/responses.rb +23 -27
  44. data/lib/fitting/report/tests.rb +4 -8
  45. data/lib/fitting/skip/action.rb +44 -0
  46. data/lib/fitting/skip/api.rb +29 -0
  47. data/lib/fitting/skip.rb +21 -0
  48. data/lib/fitting/version.rb +1 -1
  49. data/lib/fitting.rb +12 -28
  50. data/lib/tasks/fitting.rake +23 -84
  51. data/lib/templates/htmlcss/bootstrap-nightshade.min.css +12 -0
  52. data/lib/templates/htmlcss/bootstrap.min.js +7 -0
  53. data/lib/templates/htmlcss/darkmode.min.js +6 -0
  54. data/lib/templates/htmlcss/fitting.html +196 -0
  55. data/lib/templates/htmlcss/jquery-3.6.0.min.js +2 -0
  56. metadata +40 -39
  57. data/lib/fitting/configuration.rb +0 -17
  58. data/lib/fitting/records/spherical/requests.rb +0 -25
  59. data/lib/fitting/storage/responses.rb +0 -21
  60. data/lib/fitting/tests.rb +0 -31
  61. data/lib/tasks/fitting_outgoing.rake +0 -91
  62. data/lib/templates/bomboniere/.gitignore +0 -21
  63. data/lib/templates/bomboniere/.tool-versions +0 -1
  64. data/lib/templates/bomboniere/README.md +0 -19
  65. data/lib/templates/bomboniere/dist/css/app.aa2bcd8a.css +0 -1
  66. data/lib/templates/bomboniere/dist/css/chunk-vendors.ec5f6c3f.css +0 -1
  67. data/lib/templates/bomboniere/dist/favicon.ico +0 -0
  68. data/lib/templates/bomboniere/dist/index.html +0 -1
  69. data/lib/templates/bomboniere/dist/js/app.e5f1a5ec.js +0 -2
  70. data/lib/templates/bomboniere/dist/js/app.e5f1a5ec.js.map +0 -1
  71. data/lib/templates/bomboniere/dist/js/chunk-vendors.0f99b670.js +0 -13
  72. data/lib/templates/bomboniere/dist/js/chunk-vendors.0f99b670.js.map +0 -1
  73. data/lib/templates/bomboniere/package-lock.json +0 -9292
  74. data/lib/templates/bomboniere/package.json +0 -27
  75. data/lib/templates/bomboniere/public/favicon.ico +0 -0
  76. data/lib/templates/bomboniere/public/index.html +0 -17
  77. data/lib/templates/bomboniere/src/App.vue +0 -102
  78. data/lib/templates/bomboniere/src/assets/logo.png +0 -0
  79. data/lib/templates/bomboniere/src/components/HelloWorld.vue +0 -204
  80. data/lib/templates/bomboniere/src/main.js +0 -10
  81. data/lib/templates/bomboniere/src/router/index.js +0 -31
  82. data/lib/templates/bomboniere/src/views/About.vue +0 -5
  83. data/lib/templates/bomboniere/src/views/Action.vue +0 -173
  84. data/lib/templates/bomboniere/src/views/Home.vue +0 -17
  85. data/lib/templates/bomboniere/vue.config.js +0 -3
@@ -0,0 +1,62 @@
1
+ require 'fitting/report/actions'
2
+
3
+ module Fitting
4
+ class Prefix
5
+ KEYS = {
6
+ 'openapi2' => :openapi2_json_path,
7
+ 'openapi3' => :openapi3_yaml_path,
8
+ 'drafter' => :drafter_yaml_path,
9
+ 'crafter' => :crafter_yaml_path,
10
+ 'tomogram' => :tomogram_json_path
11
+ }.freeze
12
+
13
+ attr_reader :name, :actions
14
+
15
+ def initialize(name, schema_paths, type, skip = false)
16
+ @prefix = name
17
+ @cover = false
18
+
19
+ @actions = Fitting::Report::Actions.new([])
20
+ raise Skip if skip
21
+
22
+ schema_paths.each do |path|
23
+ tomogram = Tomograph::Tomogram.new(prefix: name, KEYS[type] => path)
24
+
25
+ @actions.push(Fitting::Report::Actions.new(tomogram))
26
+ end
27
+ end
28
+
29
+ class Skip < RuntimeError; end
30
+
31
+ class NotFound < RuntimeError
32
+ attr_reader :log
33
+
34
+ def initialize(msg, log)
35
+ @log = log
36
+ super(msg)
37
+ end
38
+ end
39
+
40
+ def self.find(host:, log:)
41
+ yaml = YAML.safe_load(File.read('.fitting.yml'))
42
+
43
+ prefixes = yaml['hosts'].find{|h| h.first.first == host.to_s}.first.last['prefixes']
44
+ raise NotFound.new("host: #{log.host}, path: #{log.path}", log) unless prefixes
45
+
46
+ prefix = prefixes.find do |prefix|
47
+ prefix['name'].nil? || log.path[0..prefix['name'].size - 1] == prefix['name']
48
+ end
49
+ raise NotFound.new("host: #{log.host}, path: #{log.path}", log) unless prefix
50
+
51
+ new(prefix['name'], prefix['schema_paths'], prefix['type'], prefix['skip'])
52
+ end
53
+
54
+ def cover!
55
+ @cover = true
56
+ end
57
+
58
+ def cover?
59
+ @cover
60
+ end
61
+ end
62
+ end
@@ -4,7 +4,6 @@ module Fitting
4
4
  class MyRailtie < Rails::Railtie
5
5
  rake_tasks do
6
6
  load 'tasks/fitting.rake'
7
- load 'tasks/fitting_outgoing.rake'
8
7
  end
9
8
  end
10
9
  end
@@ -5,15 +5,16 @@ module Fitting
5
5
  class Records
6
6
  class Spherical
7
7
  class Request
8
- attr_reader :method, :path, :body, :response, :title, :group
8
+ attr_reader :method, :path, :body, :response, :title, :group, :host
9
9
 
10
- def initialize(method:, path:, body:, response:, title:, group:)
10
+ def initialize(method:, path:, body:, response:, title:, group:, host:)
11
11
  @method = method
12
12
  @path = path
13
13
  @body = body
14
14
  @response = response
15
15
  @title = title
16
16
  @group = group
17
+ @host = host
17
18
  end
18
19
 
19
20
  def to_hash
@@ -23,7 +24,8 @@ module Fitting
23
24
  body: body,
24
25
  response: response.to_hash,
25
26
  title: title,
26
- group: group
27
+ group: group,
28
+ host: host
27
29
  }
28
30
  end
29
31
 
@@ -39,7 +41,8 @@ module Fitting
39
41
  body: hash['body'],
40
42
  response: Fitting::Records::Spherical::Response.load(hash['response']),
41
43
  title: hash['title'],
42
- group: hash['group']
44
+ group: hash['group'],
45
+ host: hash['host']
43
46
  )
44
47
  end
45
48
  end
@@ -6,32 +6,38 @@ module Fitting
6
6
  class Response
7
7
  attr_reader :status, :body
8
8
 
9
- def initialize(status:, body:)
9
+ def initialize(status:, body:, content_type:)
10
10
  @status = status
11
11
  @body = body
12
+ @content_type = content_type
12
13
  end
13
14
 
14
15
  def to_hash
15
- {
16
- status: status,
17
- body: JSON.parse(body)
18
- }
19
- rescue JSON::ParserError
20
- {
21
- status: status,
22
- body: {}
23
- }
16
+ begin
17
+ parse_body = JSON.parse(body)
18
+ rescue JSON::ParserError
19
+ parse_body = {}
20
+ end
21
+
22
+ if @content_type == nil || @content_type == ''
23
+ {
24
+ status: status,
25
+ content_type: 'application/json',
26
+ body: parse_body
27
+ }
28
+ else
29
+ ct = @content_type.split("; ")
30
+ {
31
+ status: status,
32
+ content_type: ct.first,
33
+ body: parse_body
34
+ }
35
+ end
24
36
  end
25
37
 
26
38
  def to_json(*_args)
27
39
  JSON.dump(to_hash)
28
40
  end
29
-
30
- class << self
31
- def load(hash)
32
- new(status: hash['status'], body: hash['body'])
33
- end
34
- end
35
41
  end
36
42
  end
37
43
  end
@@ -11,6 +11,10 @@ module Fitting
11
11
  @response = response
12
12
  end
13
13
 
14
+ def host
15
+ @host ||= @response.request.host
16
+ end
17
+
14
18
  def method
15
19
  @method ||= @response.request.request_method
16
20
  end
@@ -42,7 +46,8 @@ module Fitting
42
46
  body: body,
43
47
  response: fitting_response.to_spherical,
44
48
  title: test_path,
45
- group: test_file_path
49
+ group: test_file_path,
50
+ host: host
46
51
  )
47
52
  end
48
53
  end
@@ -16,10 +16,15 @@ module Fitting
16
16
  @body ||= @response.body
17
17
  end
18
18
 
19
+ def content_type
20
+ @content_type ||= @response.content_type
21
+ end
22
+
19
23
  def to_spherical
20
24
  Fitting::Records::Spherical::Response.new(
21
25
  status: status,
22
- body: body
26
+ body: body,
27
+ content_type: content_type
23
28
  )
24
29
  end
25
30
  end
@@ -0,0 +1,32 @@
1
+ module Fitting
2
+ class Rep
3
+ class HTML
4
+ def self.copy_file(folder, name)
5
+ File.open("#{folder}/#{name}", 'w') do |file|
6
+ file.write(
7
+ File.read("#{$LOAD_PATH.find { |i| i.include?('fitting') }}/templates/htmlcss/#{name}")
8
+ )
9
+ end
10
+ end
11
+
12
+ def self.copy_file_with_json(folder, name, fitting_json, fitting_lock_json)
13
+ res = File.read("#{$LOAD_PATH.find { |i| i.include?('fitting') }}/templates/htmlcss/#{name}")
14
+ File.open("#{folder}/#{name}", 'w') do |file|
15
+ file.write(
16
+ res
17
+ .gsub("{'fitting json': []}", ::JSON.pretty_generate(fitting_json))
18
+ .gsub("{'fitting lock json': []}", ::JSON.pretty_generate(fitting_lock_json))
19
+ )
20
+ end
21
+ end
22
+
23
+ def self.bootstrap(folder, fitting_json, fitting_lock_json)
24
+ copy_file_with_json(folder, 'fitting.html', fitting_json, fitting_lock_json)
25
+ copy_file(folder, 'bootstrap-nightshade.min.css')
26
+ copy_file(folder, 'darkmode.min.js')
27
+ copy_file(folder, 'jquery-3.6.0.min.js')
28
+ copy_file(folder, 'bootstrap.min.js')
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,24 @@
1
+ require 'fitting/rep/html'
2
+
3
+ module Fitting
4
+ class Rep
5
+ def initialize(apis)
6
+ @actions = apis
7
+ end
8
+
9
+ def save!
10
+ destination = 'coverage'
11
+ FileUtils.mkdir_p(destination)
12
+
13
+ fitting_json = @actions.inject({}) do |sum, action|
14
+ sum.merge(action.to_hash)
15
+ end
16
+ fitting_lock_json = @actions.inject({}) do |sum, action|
17
+ sum.merge(action.to_hash_lock)
18
+ end
19
+ File.open('coverage/.fitting.json', 'w') { |file| file.write(::JSON.pretty_generate(fitting_json)) }
20
+ File.open('coverage/.fitting.lock.json', 'w') { |file| file.write(::JSON.pretty_generate(fitting_lock_json)) }
21
+ Fitting::Rep::HTML.bootstrap('coverage', fitting_json, fitting_lock_json)
22
+ end
23
+ end
24
+ end
@@ -5,8 +5,16 @@ module Fitting
5
5
  class Action
6
6
  def initialize(action)
7
7
  @action = action
8
- @tests = Fitting::Report::Tests.new([])
9
8
  @responses = Fitting::Report::Responses.new(@action.responses)
9
+ @cover = false
10
+ end
11
+
12
+ def cover?
13
+ @cover
14
+ end
15
+
16
+ def cover!
17
+ @cover = true
10
18
  end
11
19
 
12
20
  def method
@@ -19,10 +27,6 @@ module Fitting
19
27
 
20
28
  attr_reader :responses, :tests
21
29
 
22
- def add_test(test)
23
- @tests.push(test)
24
- end
25
-
26
30
  def path_match(find_path)
27
31
  regexp =~ find_path
28
32
  end
@@ -35,16 +39,6 @@ module Fitting
35
39
  str = "\\A#{str}\\z"
36
40
  @regexp = Regexp.new(str)
37
41
  end
38
-
39
- def details
40
- {
41
- tests_without_responses: @tests.without_responses,
42
- responses_details: @responses.to_a.map do |r|
43
- { method: r.status, tests_size: r.tests.size, json_schema: r.id,
44
- combinations: r.details }
45
- end
46
- }
47
- end
48
42
  end
49
43
  end
50
44
  end
@@ -3,54 +3,43 @@ require 'fitting/report/action'
3
3
  module Fitting
4
4
  module Report
5
5
  class Actions
6
- def initialize(actions)
7
- @actions = []
8
- actions.to_a.map do |action|
9
- @actions.push(Fitting::Report::Action.new(action))
6
+ class Empty < RuntimeError; end
7
+ class NotFound < RuntimeError
8
+ attr_reader :log
9
+
10
+ def initialize(msg, log)
11
+ @log = log
12
+ super(msg)
10
13
  end
11
14
  end
12
15
 
13
- def to_a
14
- @actions
15
- end
16
+ def cover!
16
17
 
17
- def push(actions)
18
- @actions += actions.to_a
19
18
  end
20
19
 
21
- def join(tests)
22
- tests.to_a.map do |test|
23
- if there_a_suitable_action?(test)
24
- cram_into_the_appropriate_action(test)
25
- test.mark_action
26
- end
20
+ def initialize(actions)
21
+ @actions = []
22
+ actions.to_a.map do |action|
23
+ @actions.push(Fitting::Report::Action.new(action))
27
24
  end
28
25
  end
29
26
 
30
- def there_a_suitable_action?(test)
27
+ def find!(log)
28
+ raise Empty if @actions.empty?
31
29
  @actions.map do |action|
32
- return true if test.method == action.method && action.path_match(test.path)
30
+ if log.method == action.method && action.path_match(log.path)
31
+ return action
32
+ end
33
33
  end
34
-
35
- false
34
+ raise NotFound.new("method: #{log.method}, host: #{log.host}, path: #{log.path}", log)
36
35
  end
37
36
 
38
- def cram_into_the_appropriate_action(test)
39
- @actions.map do |action|
40
- if test.method == action.method && action.path_match(test.path)
41
- action.add_test(test)
42
- break
43
- end
44
- end
37
+ def to_a
38
+ @actions
45
39
  end
46
40
 
47
- def details(prefix)
48
- {
49
- tests_without_actions: prefix.tests.without_actions,
50
- actions_details: @actions.map do |a|
51
- { method: a.method, path: a.path, tests_size: a.tests.size, responses: a.details }
52
- end
53
- }
41
+ def push(actions)
42
+ @actions += actions.to_a
54
43
  end
55
44
  end
56
45
  end
@@ -5,18 +5,22 @@ module Fitting
5
5
  @json_schema = json_schema
6
6
  @type = type
7
7
  @combination = combination
8
- @tests = Fitting::Report::Tests.new([])
9
8
  @id = SecureRandom.hex
9
+ @cover = false
10
10
  end
11
11
 
12
- attr_reader :json_schema, :id, :type, :tests
12
+ attr_reader :json_schema, :id, :type
13
13
 
14
- def name
15
- @combination
14
+ def cover?
15
+ @cover
16
+ end
17
+
18
+ def cover!
19
+ @cover = true
16
20
  end
17
21
 
18
- def add_test(test)
19
- @tests.push(test)
22
+ def name
23
+ @combination
20
24
  end
21
25
  end
22
26
  end
@@ -1,6 +1,9 @@
1
1
  module Fitting
2
2
  module Report
3
3
  class Combinations
4
+ class Empty < RuntimeError; end
5
+ class NotFound < RuntimeError; end
6
+
4
7
  def initialize(combinations)
5
8
  @combinations = combinations
6
9
  end
@@ -9,37 +12,14 @@ module Fitting
9
12
  @combinations
10
13
  end
11
14
 
12
- def size
13
- @combinations.size
14
- end
15
-
16
- def size_with_tests
17
- @combinations.count { |c| c.tests.size != 0 }
18
- end
19
-
20
- def join(tests)
21
- tests.to_a.map do |test|
22
- if there_a_suitable_combination?(test)
23
- cram_into_the_appropriate_combinations(test)
24
- test.mark_combination
25
- end
26
- end
27
- end
28
-
29
- def there_a_suitable_combination?(test)
30
- return false if @combinations.nil?
31
-
32
- @combinations.map do |combination|
33
- return true if JSON::Validator.fully_validate(combination.json_schema, test.body) == []
34
- end
35
-
36
- false
37
- end
38
-
39
- def cram_into_the_appropriate_combinations(test)
15
+ def find!(test)
16
+ raise Empty if @combinations.empty?
40
17
  @combinations.map do |combination|
41
- combination.add_test(test) if JSON::Validator.fully_validate(combination.json_schema, test.body) == []
18
+ if JSON::Validator.fully_validate(combination.json_schema, test.body) == []
19
+ return combination
20
+ end
42
21
  end
22
+ raise NotFound
43
23
  end
44
24
  end
45
25
  end
@@ -11,15 +11,14 @@ module Fitting
11
11
  'tomogram' => :tomogram_json_path
12
12
  }.freeze
13
13
 
14
- attr_reader :name, :tests, :actions
14
+ attr_reader :name, :actions
15
15
 
16
16
  def initialize(schema_paths: nil, type: nil, name: '', skip: false, only: [])
17
17
  @name = name
18
- @tests = Fitting::Report::Tests.new([])
19
- @skip = skip
20
- return if skip
18
+ @cover = false
21
19
 
22
20
  @actions = Fitting::Report::Actions.new([])
21
+ return if skip
23
22
 
24
23
  schema_paths.each do |path|
25
24
  tomogram = Tomograph::Tomogram.new(prefix: name, KEYS[type] => path)
@@ -30,28 +29,12 @@ module Fitting
30
29
  end
31
30
  end
32
31
 
33
- def skip?
34
- @skip
35
- end
36
-
37
- def details
38
- if @skip
39
- {
40
- name: @name,
41
- tests_size: @tests.size,
42
- actions: { tests_without_actions: [], actions_details: [] }
43
- }
44
- else
45
- {
46
- name: @name,
47
- tests_size: @tests.size,
48
- actions: @actions.details(self)
49
- }
50
- end
32
+ def cover!
33
+ @cover = true
51
34
  end
52
35
 
53
- def add_test(test)
54
- @tests.push(test)
36
+ def cover?
37
+ @cover
55
38
  end
56
39
  end
57
40
  end
@@ -19,37 +19,23 @@ module Fitting
19
19
  end
20
20
  end
21
21
 
22
- def there_a_suitable_prefix?(test_path)
23
- @prefixes.map do |prefix|
24
- return true if prefix.name.nil?
25
- return true if prefix.name == ''
26
- return true if test_path[0..prefix.name.size - 1] == prefix.name
27
- end
28
-
29
- false
22
+ def to_a
23
+ @prefixes
30
24
  end
31
25
 
32
- def cram_into_the_appropriate_prefix(test)
26
+ def find!(test)
33
27
  @prefixes.map do |prefix|
34
- if prefix.name.nil? || prefix.name == '' || test.path[0..prefix.name.size - 1] == prefix.name
35
- prefix.add_test(test)
36
- break
28
+ puts test.path
29
+ puts test.host
30
+ puts test.method
31
+ puts test.status
32
+ puts test.body
33
+ puts prefix.name
34
+ if test.path[0..prefix.name.size - 1] == prefix.name
35
+ return prefix
37
36
  end
38
37
  end
39
38
  end
40
-
41
- def join(tests)
42
- tests.to_a.map do |test|
43
- if there_a_suitable_prefix?(test.path)
44
- cram_into_the_appropriate_prefix(test)
45
- test.mark_prefix
46
- end
47
- end
48
- end
49
-
50
- def to_a
51
- @prefixes
52
- end
53
39
  end
54
40
  end
55
41
  end
@@ -1,13 +1,24 @@
1
1
  require 'fitting/report/combinations'
2
2
  require 'fitting/report/combination'
3
+ require 'fitting/cover/json_schema'
4
+ require 'fitting/cover/json_schema_enum'
5
+ require 'fitting/cover/json_schema_one_of'
3
6
 
4
7
  module Fitting
5
8
  module Report
6
9
  class Response
7
10
  def initialize(response)
8
11
  @response = response
9
- @tests = Fitting::Report::Tests.new([])
10
12
  @id = SecureRandom.hex
13
+ @cover = false
14
+ end
15
+
16
+ def cover?
17
+ @cover
18
+ end
19
+
20
+ def cover!
21
+ @cover = true
11
22
  end
12
23
 
13
24
  def status
@@ -20,10 +31,6 @@ module Fitting
20
31
 
21
32
  attr_reader :id, :tests
22
33
 
23
- def add_test(test)
24
- @tests.push(test)
25
- end
26
-
27
34
  def combinations
28
35
  return @combinations if @combinations
29
36
 
@@ -45,23 +52,6 @@ module Fitting
45
52
 
46
53
  @combinations = Fitting::Report::Combinations.new(cmbntns)
47
54
  end
48
-
49
- def cover_percent
50
- return '0%' if @tests.size.zero?
51
- return '100%' if @combinations.size.zero?
52
-
53
- "#{(@combinations.size_with_tests + 1) * 100 / (@combinations.size + 1)}%"
54
- end
55
-
56
- def details
57
- {
58
- cover_percent: cover_percent,
59
- tests_without_combinations: @tests.without_combinations,
60
- combinations_details: @combinations.to_a.map do |c|
61
- { json_schema: c.id, tests_size: c.tests.size, type: c.type, name: c.name }
62
- end
63
- }
64
- end
65
55
  end
66
56
  end
67
57
  end