webspicy 0.20.1 → 0.20.6

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 (50) hide show
  1. checksums.yaml +4 -4
  2. data/bin/sandr +14 -0
  3. data/bin/search +2 -0
  4. data/bin/webspicy +3 -4
  5. data/lib/finitio/webspicy/shared.fio +10 -0
  6. data/lib/webspicy.rb +22 -53
  7. data/lib/webspicy/configuration.rb +17 -0
  8. data/lib/webspicy/configuration/scope.rb +3 -2
  9. data/lib/webspicy/configuration/single_url.rb +35 -25
  10. data/lib/webspicy/configuration/single_yml_file.rb +7 -2
  11. data/lib/webspicy/specification.rb +0 -55
  12. data/lib/webspicy/specification/oldies/bridge.rb +4 -1
  13. data/lib/webspicy/specification/post/missing_condition_impl.rb +2 -2
  14. data/lib/webspicy/specification/post/unexpected_condition_impl.rb +2 -2
  15. data/lib/webspicy/specification/service.rb +4 -5
  16. data/lib/webspicy/specification/test_case.rb +3 -49
  17. data/lib/webspicy/support/colorize.rb +7 -1
  18. data/lib/webspicy/tester.rb +21 -20
  19. data/lib/webspicy/tester/assertions.rb +2 -2
  20. data/lib/webspicy/tester/fakesmtp/email.rb +13 -0
  21. data/lib/webspicy/tester/reporter.rb +5 -0
  22. data/lib/webspicy/tester/reporter/documentation.rb +30 -8
  23. data/lib/webspicy/tester/reporter/error_count.rb +11 -7
  24. data/lib/webspicy/tester/reporter/file_progress.rb +2 -2
  25. data/lib/webspicy/tester/reporter/file_summary.rb +2 -2
  26. data/lib/webspicy/tester/reporter/progress.rb +4 -4
  27. data/lib/webspicy/tester/reporter/summary.rb +8 -7
  28. data/lib/webspicy/tester/result.rb +2 -2
  29. data/lib/webspicy/tester/result/errcondition_met.rb +1 -3
  30. data/lib/webspicy/tester/result/postcondition_met.rb +1 -3
  31. data/lib/webspicy/version.rb +1 -1
  32. data/lib/webspicy/web.rb +46 -0
  33. data/lib/webspicy/{formaldoc.fio → web/formaldoc.fio} +5 -13
  34. data/lib/webspicy/web/invocation.rb +1 -0
  35. data/lib/webspicy/web/specification.rb +68 -0
  36. data/lib/webspicy/web/specification/file_upload.rb +39 -0
  37. data/lib/webspicy/web/specification/service.rb +13 -0
  38. data/lib/webspicy/web/specification/test_case.rb +58 -0
  39. data/spec/unit/configuration/scope/test_expand_example.rb +11 -5
  40. data/spec/unit/specification/pre/test_global_request_headers.rb +3 -3
  41. data/spec/unit/specification/service/test_dress_params.rb +2 -2
  42. data/spec/unit/test_configuration.rb +1 -0
  43. data/spec/unit/tester/fakesmtp/test_email.rb +93 -0
  44. data/spec/unit/web/specification/test_instantiate_url.rb +36 -0
  45. data/spec/unit/web/specification/test_url_placeholders.rb +23 -0
  46. data/tasks/test.rake +2 -1
  47. metadata +28 -19
  48. data/lib/webspicy/specification/file_upload.rb +0 -37
  49. data/spec/unit/specification/test_instantiate_url.rb +0 -34
  50. data/spec/unit/specification/test_url_placeholders.rb +0 -21
@@ -4,9 +4,9 @@ module Webspicy
4
4
  class MissingConditionImpl
5
5
  include Post
6
6
 
7
- def check
7
+ def check!
8
8
  msg = matching_description.gsub(/\(x\)/, "<!>")
9
- raise "#{msg} (not instrumented)"
9
+ fail!("#{msg} (not instrumented)")
10
10
  end
11
11
 
12
12
  end # class MissingConditionImpl
@@ -4,9 +4,9 @@ module Webspicy
4
4
  class UnexpectedConditionImpl
5
5
  include Post
6
6
 
7
- def check
7
+ def check!
8
8
  msg = matching_description.gsub(/\( \)/, "<x>")
9
- raise "#{msg} (is instrumented)"
9
+ fail!("#{msg} (is instrumented)")
10
10
  end
11
11
 
12
12
  end # class UnexpectedConditionImpl
@@ -10,6 +10,9 @@ module Webspicy
10
10
  end
11
11
  attr_accessor :specification
12
12
 
13
+ # Deprecated
14
+ alias :resource :specification
15
+
13
16
  def self.info(raw)
14
17
  new(raw)
15
18
  end
@@ -18,10 +21,6 @@ module Webspicy
18
21
  specification.config
19
22
  end
20
23
 
21
- def method
22
- @raw[:method]
23
- end
24
-
25
24
  def description
26
25
  @raw[:description]
27
26
  end
@@ -65,7 +64,7 @@ module Webspicy
65
64
  def generated_counterexamples
66
65
  preconditions.map{|pre|
67
66
  pre.counterexamples(self).map{|tc|
68
- tc = Webspicy.test_case(tc, Webspicy.current_scope)
67
+ tc = config.factory.test_case(tc, Webspicy.current_scope)
69
68
  tc.bind(self, true)
70
69
  }
71
70
  }.flatten
@@ -28,6 +28,9 @@ module Webspicy
28
28
  service.specification
29
29
  end
30
30
 
31
+ # Deprecated
32
+ alias :resource :specification
33
+
31
34
  def self.info(raw)
32
35
  new(raw)
33
36
  end
@@ -40,10 +43,6 @@ module Webspicy
40
43
  @raw[:seeds]
41
44
  end
42
45
 
43
- def headers
44
- @raw[:headers] ||= {}
45
- end
46
-
47
46
  def metadata
48
47
  @raw[:metadata] ||= {}
49
48
  end
@@ -52,47 +51,10 @@ module Webspicy
52
51
  @raw[:tags] ||= []
53
52
  end
54
53
 
55
- def dress_params
56
- @raw.fetch(:dress_params){ true }
57
- end
58
- alias :dress_params? :dress_params
59
-
60
- def params
61
- @raw[:params] || {}
62
- end
63
-
64
- def body
65
- @raw[:body]
66
- end
67
-
68
- def file_upload
69
- @raw[:file_upload]
70
- end
71
-
72
- def located_file_upload
73
- file_upload ? file_upload.locate(specification) : nil
74
- end
75
-
76
54
  def expected
77
55
  @raw[:expected] || {}
78
56
  end
79
57
 
80
- def expected_content_type
81
- expected[:content_type]
82
- end
83
-
84
- def expected_status
85
- expected[:status]
86
- end
87
-
88
- def is_expected_status?(status)
89
- expected_status === status
90
- end
91
-
92
- def has_expected_status?
93
- not expected[:status].nil?
94
- end
95
-
96
58
  def expected_error
97
59
  expected[:error]
98
60
  end
@@ -101,14 +63,6 @@ module Webspicy
101
63
  !expected_error.nil?
102
64
  end
103
65
 
104
- def expected_headers
105
- expected[:headers] || {}
106
- end
107
-
108
- def has_expected_headers?
109
- !expected_headers.empty?
110
- end
111
-
112
66
  def assert
113
67
  @raw[:assert] || []
114
68
  end
@@ -3,11 +3,17 @@ module Webspicy
3
3
  module Colorize
4
4
 
5
5
  def colorize(str, kind, config = nil)
6
+ return str if config && !config.colorize
6
7
  color = (config || self.config).colors[kind]
7
- ColorizedString[str].colorize(color)
8
+ Paint[str, color]
8
9
  end
9
10
  module_function :colorize
10
11
 
12
+ def colorize_section(str, cfg = nil)
13
+ colorize(str, :section, cfg)
14
+ end
15
+ module_function :colorize_section
16
+
11
17
  def colorize_highlight(str, cfg = nil)
12
18
  colorize(str, :highlight, cfg)
13
19
  end
@@ -15,7 +15,7 @@ module Webspicy
15
15
  @test_case = nil
16
16
  @invocation = nil
17
17
  @invocation_error = nil
18
- @reporter = default_reporter
18
+ @reporter = @config.reporter
19
19
  end
20
20
  attr_reader :config, :scope, :hooks, :client
21
21
  attr_reader :specification, :spec_file
@@ -31,15 +31,6 @@ module Webspicy
31
31
  config.failfast
32
32
  end
33
33
 
34
- def default_reporter
35
- @reporter = Reporter::Composite.new
36
- #@reporter << Reporter::Progress.new
37
- @reporter << Reporter::Documentation.new
38
- @reporter << Reporter::Exceptions.new
39
- @reporter << Reporter::Summary.new
40
- @reporter << Reporter::ErrorCount.new
41
- end
42
-
43
34
  def call
44
35
  reporter.init(self)
45
36
  begin
@@ -50,6 +41,11 @@ module Webspicy
50
41
  reporter.find(Reporter::ErrorCount).report
51
42
  end
52
43
 
44
+ def call!
45
+ res = call
46
+ abort("KO") unless res == 0
47
+ end
48
+
53
49
  def find_and_call(method, url, mutation)
54
50
  unless tc = scope.find_test_case(method, url)
55
51
  raise Error, "No such service `#{method} #{url}`"
@@ -61,6 +57,11 @@ module Webspicy
61
57
  end
62
58
  end
63
59
 
60
+ def bind_condition(c)
61
+ c = Specification::Oldies::Bridge.new(c) unless c.respond_to?(:bind)
62
+ c.bind(self)
63
+ end
64
+
64
65
  protected
65
66
 
66
67
  def run_config
@@ -68,19 +69,15 @@ module Webspicy
68
69
  @scope = scope
69
70
  @hooks = Support::Hooks.for(scope.config)
70
71
  @client = scope.get_client
71
- reporter.before_all
72
- @hooks.fire_before_all(self)
73
- reporter.before_all_done
74
- reporter.before_scope
75
72
  run_scope
76
- reporter.scope_done
77
- reporter.after_all
78
- @hooks.fire_after_all(self)
79
- reporter.after_all_done
80
73
  end
81
74
  end
82
75
 
83
76
  def run_scope
77
+ reporter.before_all
78
+ hooks.fire_before_all(self)
79
+ reporter.before_all_done
80
+ reporter.before_scope
84
81
  scope.each_specification_file do |spec_file|
85
82
  @specification = load_specification(spec_file)
86
83
  if @specification
@@ -92,12 +89,16 @@ module Webspicy
92
89
  raise FailFast
93
90
  end
94
91
  end
92
+ reporter.scope_done
93
+ reporter.after_all
94
+ hooks.fire_after_all(self)
95
+ reporter.after_all_done
95
96
  end
96
97
 
97
98
  def load_specification(spec_file)
98
99
  @spec_file = spec_file
99
100
  reporter.before_spec_file
100
- Webspicy.specification(spec_file.load, spec_file, scope)
101
+ config.factory.specification(spec_file.load, spec_file, scope)
101
102
  rescue *PASSTHROUGH_EXCEPTIONS
102
103
  raise
103
104
  rescue Exception => e
@@ -176,7 +177,7 @@ module Webspicy
176
177
  end
177
178
 
178
179
  def instrument_one(condition)
179
- condition.bind(self).instrument
180
+ bind_condition(condition).instrument
180
181
  rescue ArgumentError
181
182
  raise "#{condition.class} implements old PRE/POST contract"
182
183
  end
@@ -40,7 +40,7 @@ module Webspicy
40
40
  actual_size(target, path) == expected
41
41
  end
42
42
 
43
- def actual_size(target, path)
43
+ def actual_size(target, path)
44
44
  target = extract_path(target, path)
45
45
  respond_to!(target, :size).size
46
46
  end
@@ -68,7 +68,7 @@ module Webspicy
68
68
  an_array(target).find { |t| t[:id] == id }
69
69
  end
70
70
 
71
- def idFD(element, expected)
71
+ def idFD(element, expected)
72
72
  expected.keys.all? do |k|
73
73
  value_equal(expected[k], element[k])
74
74
  end
@@ -21,6 +21,19 @@ module Webspicy
21
21
  .map{|h| h["line"][/To:\s*(.*)$/, 1] }
22
22
  end
23
23
 
24
+ def reply_to
25
+ @reply_to ||= data["headerLines"]
26
+ .select{|h| h["key"] == "reply-to" }
27
+ .map{|h| h["line"][/Reply-To:\s*(.*)$/, 1] }
28
+ end
29
+
30
+ def subject
31
+ @subject ||= data["headerLines"]
32
+ .select{|h| h["key"] == "subject" }
33
+ .map{|h| h["line"][/Subject:\s*(.*)$/, 1] }
34
+ .first
35
+ end
36
+
24
37
  end # class Email
25
38
  end # class Fakesmtp
26
39
  end # class Tester
@@ -66,6 +66,11 @@ module Webspicy
66
66
  }
67
67
  end
68
68
 
69
+ def find(kind)
70
+ return self if self.is_a?(kind)
71
+ raise "Missing reporter #{kind}"
72
+ end
73
+
69
74
  protected
70
75
 
71
76
  def plural(word, count)
@@ -4,41 +4,63 @@ module Webspicy
4
4
  class Documentation < Reporter
5
5
 
6
6
  module Helpers
7
+ INDENT = " ".freeze
8
+
9
+ def spec_file_line(spec_file)
10
+ path = Path(spec_file).expand_path
11
+ path = path.relative_to(config.folder)
12
+ path = spec_file if path.to_s.start_with?(".")
13
+ colorize_section(">> #{path}", config)
14
+ end
15
+
7
16
  def spec_file_error_line(spec_file, ex)
8
- str = colorize_highlight(spec_file.to_s)
9
- str += "\n " + colorize_error("X #{ex.message}")
17
+ str = ""
18
+ str += colorize_error(INDENT + "X #{ex.message}", config)
10
19
  if ex.root_cause && ex.root_cause != ex
11
- str += "\n " + colorize_error("#{ex.root_cause.message}")
20
+ str += "\n"
21
+ str += INDENT + colorize_error("#{ex.root_cause.message}", config)
12
22
  end
13
23
  str
14
24
  end
15
25
 
16
26
  def service_line(service, test_case)
17
- str = service.to_s + ", " + test_case.to_s
18
- str = colorize_highlight(str)
27
+ str = "#{service}, #{test_case}"
28
+ str = colorize_highlight(str, config)
19
29
  end
20
30
 
21
31
  def check_success_line(check)
22
- " " + colorize_success("v") + " " + check.behavior
32
+ INDENT + colorize_success("v " + check.behavior, config)
23
33
  end
24
34
 
25
35
  def check_failure_line(check, ex)
26
- " " + colorize_error("F " + ex.message)
36
+ INDENT + colorize_error("F " + ex.message, config)
27
37
  end
28
38
 
29
39
  def check_error_line(check, ex)
30
- " " + colorize_error("E " + ex.message)
40
+ INDENT + colorize_error("E " + ex.message, config)
31
41
  end
32
42
  end
33
43
  include Helpers
34
44
 
35
45
  def spec_file_error(e)
46
+ io.puts spec_file_line(spec_file)
47
+ io.puts
36
48
  io.puts spec_file_error_line(spec_file, e)
37
49
  io.puts
38
50
  io.flush
39
51
  end
40
52
 
53
+ def before_service
54
+ @spec_file_line_printed = false
55
+ end
56
+
41
57
  def before_test_case
58
+ unless @spec_file_line_printed
59
+ io.puts spec_file_line(spec_file)
60
+ io.puts
61
+ io.flush
62
+ @spec_file_line_printed = true
63
+ end
42
64
  io.puts service_line(service, test_case)
43
65
  io.flush
44
66
  end
@@ -5,18 +5,22 @@ module Webspicy
5
5
 
6
6
  def initialize(*args, &bl)
7
7
  super
8
- @error_count = 0
8
+ @errors = Hash.new{|h,k| 0 }
9
9
  end
10
+ attr_reader :errors
10
11
 
11
- def on_error(*args, &bl)
12
- @error_count += 1
12
+ [
13
+ :spec_file_error,
14
+ :check_error,
15
+ :check_failure
16
+ ].each do |meth|
17
+ define_method(meth) do |*args, &bl|
18
+ @errors[meth] += 1
19
+ end
13
20
  end
14
- alias :spec_file_error :on_error
15
- alias :check_failure :on_error
16
- alias :check_error :on_error
17
21
 
18
22
  def report
19
- @error_count
23
+ @errors.values.inject(0){|memo,x| memo+x }
20
24
  end
21
25
 
22
26
  end # class ErrorCount
@@ -4,12 +4,12 @@ module Webspicy
4
4
  class FileProgress < Reporter
5
5
 
6
6
  def spec_file_error(e)
7
- io.print colorize_error("X")
7
+ io.print colorize_error("X", config)
8
8
  io.flush
9
9
  end
10
10
 
11
11
  def spec_file_done
12
- io.print colorize_success(".")
12
+ io.print colorize_success(".", config)
13
13
  io.flush
14
14
  end
15
15
 
@@ -22,9 +22,9 @@ module Webspicy
22
22
  msg = "#{plural('spec file', spec_files_count)}, "\
23
23
  "#{plural('error', errors_count)}"
24
24
  if success?
25
- msg = colorize_success(msg)
25
+ msg = colorize_success(msg, config)
26
26
  else
27
- msg = colorize_error(msg)
27
+ msg = colorize_error(msg, config)
28
28
  end
29
29
  io.puts(msg)
30
30
  io.puts
@@ -4,16 +4,16 @@ module Webspicy
4
4
  class Progress < Reporter
5
5
 
6
6
  def spec_file_error(e)
7
- io.print colorize_error("X")
7
+ io.print colorize_error("X", config)
8
8
  end
9
9
 
10
10
  def after_each_done
11
11
  if result.success?
12
- io.print colorize_success(".")
12
+ io.print colorize_success(".", config)
13
13
  elsif result.failure?
14
- io.print colorize_error("F")
14
+ io.print colorize_error("F", config)
15
15
  elsif result.error?
16
- io.print colorize_error("E")
16
+ io.print colorize_error("E", config)
17
17
  end
18
18
  io.flush
19
19
  end