saharspec 0.0.4 → 0.0.5

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
  SHA1:
3
- metadata.gz: 320e576aeec4fa534c88058a6f93a617adffa1ef
4
- data.tar.gz: 3bb428585c9c78cb5da1ee565fbf7cfd1e5d8ea4
3
+ metadata.gz: 627f1f82b546e7a3e096497b74f25cab346d0fa2
4
+ data.tar.gz: d7efe0bcc330cdd47d426fb502b5114fbffa85e6
5
5
  SHA512:
6
- metadata.gz: 67c2f6364699e87103723d7a679e07da03a4b53a6a7b57f43cc2c9bd93b496453d3ebfe4923440df94a7d6c61176308aba164254cbcea386e762864af483034a
7
- data.tar.gz: c5cbcf7972f063618e66ee9feea61ba80005942cf38cbe9a4735e30cd2a603f623bc25d5bd19b4553cdb21d573f46cac371cbb722aa5fd0e25016e56b3138997
6
+ metadata.gz: e2249769358166c5b72bee55ca94b9b0ed698715afc71e439e7687fba8f745b63641312e4cb7d52340c3e4f6a805458c0f7e0b7be9b23e4eeccb90487d6699a2
7
+ data.tar.gz: 945e11582fd5c21b7cb7fd8b0d7f1021611d546bb957446df2f8b1c7b2d5c1b060e19dfd80956b5dec8a0d6a4949cda0981e216d1093d9084d44e005cf25dd49
data/LICENSE.txt CHANGED
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2014-15 Victor 'Zverok' Shepelev
3
+ Copyright (c) 2017-18 Victor 'Zverok' Shepelev
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining
6
6
  a copy of this software and associated documentation files (the
data/README.md CHANGED
@@ -9,7 +9,8 @@ specs dry as a desert.
9
9
 
10
10
  ## Usage
11
11
 
12
- Install it as a usual gem `saharspec`.
12
+ Install it as a usual gem `saharspec` with `gem install` or `gem "saharspec"` in `:test` group of
13
+ your `Gemfile`.
13
14
 
14
15
  Then, probably in your `spec_helper.rb`
15
16
 
@@ -102,6 +103,27 @@ end
102
103
 
103
104
  Plays really well with `its_call` shown below.
104
105
 
106
+ #### `be_json(value)` and `be_json_sym(value)` matchers
107
+
108
+ Simple matcher to check if string is valid JSON and optionally if it matches to expected values:
109
+
110
+ ```ruby
111
+ expect('{}').to be_json # ok
112
+ expect('garbage').to be_json
113
+ # expected value to be a valid JSON string but failed: 765: unexpected token at 'garbage'
114
+
115
+ expect('{"foo": "bar"}').to be_json('foo' => 'bar') # ok
116
+
117
+ # be_json_sym is more convenient to check with hash keys, parses JSON to symbols
118
+ expect('{"foo": "bar"}').to be_json_sym(foo: 'bar')
119
+
120
+ # nested matchers work, too
121
+ expect('{"foo": [1, 2, 3]').to be_json_sym(foo: array_including(3))
122
+
123
+ # We need to go deeper!
124
+ expect(something_large).to be_json_sym(include(meta: include(next_page: Integer)))
125
+ ```
126
+
105
127
  #### `eq_multiline(text)` matcher
106
128
 
107
129
  Dedicated to checking some multiline text generators.
@@ -241,4 +263,4 @@ checking them). Stay tuned.
241
263
 
242
264
  ## License
243
265
 
244
- [MIT](https://github.com/zverok/time_math2/blob/master/LICENSE.txt).
266
+ [MIT](https://github.com/zverok/saharspec/blob/master/LICENSE.txt).
data/lib/saharspec/its.rb CHANGED
@@ -3,9 +3,29 @@ module Saharspec
3
3
  #
4
4
  # See:
5
5
  #
6
- # * {Map#its_map #its_map}
7
- # * {Block#its_block #its_block}
8
- # * {Call#its_call #its_call}
6
+ # ## {Map#its_map #its_map}
7
+ #
8
+ # ```ruby
9
+ # subject { %w[1 2 3] }
10
+ # its_map(:to_s) { is_expected.to eq [1, 2, 3] }
11
+ # ```
12
+ #
13
+ # ## {Call#its_call #its_call}
14
+ #
15
+ # ```ruby
16
+ # subject { [1, 2, 3].method(:[]) }
17
+ # its_call(2) { is_expected.to ret 3 }
18
+ # its_call('foo') { is_expected.to raise_error }
19
+ # ```
20
+ #
21
+ # ## {Block#its_block #its_block}
22
+ #
23
+ # ```ruby
24
+ # subject { something_action }
25
+ # its_block { is_expected.not_to raise_error }
26
+ # its_block { is_expected.to change(some, :value).by(1) }
27
+ # ```
28
+ #
9
29
  module Its
10
30
  end
11
31
  end
@@ -11,7 +11,7 @@ module Saharspec
11
11
  # its_map(:length) { is_expected.to eq [4, 2, 6] }
12
12
  #
13
13
  # # with attribute chain
14
- # its_map(:'reverse.upcase') { is_expected.to eq %w[TSET EM ESAELP] }
14
+ # its_map('reverse.upcase') { is_expected.to eq %w[TSET EM ESAELP] }
15
15
  #
16
16
  # # with Hash (or any other object responding to `#[]`)
17
17
  # subject {
@@ -35,8 +35,8 @@ module Saharspec
35
35
  # TODO: better desciption for different cases
36
36
  describe("map(&:#{attribute})") do
37
37
  let(:__its_map_subject) do
38
- if Array === attribute # rubocop:disable Style/CaseEquality
39
- if subject.all? { |s| Hash === s } # rubocop:disable Style/CaseEquality
38
+ if Array === attribute
39
+ if subject.all? { |s| Hash === s }
40
40
  subject.map do |s|
41
41
  attribute.inject(s) { |inner, attr| inner[attr] }
42
42
  end
@@ -3,10 +3,11 @@ module Saharspec
3
3
  #
4
4
  # See:
5
5
  #
6
- # * {RSpec::Matchers#dont #dont}
7
- # * {RSpec::Matchers#send_message #send_message}
8
- # * {RSpec::Matchers#eq_multiline #eq_multiline}
9
- # * {RSpec::Matchers#ret #ret}
6
+ # * {RSpec::Matchers#dont #dont}: `expect { block }.to change(this).and dont.change(that)`
7
+ # * {RSpec::Matchers#send_message #send_message}: `expect { block }.to send_message(File, :write)`
8
+ # * {RSpec::Matchers#ret #ret}: `expect { block }.to ret value`
9
+ # * {RSpec::Matchers#be_json #be_json}: `expect(response.body).to be_json('foo' => 'bar')`
10
+ # * {RSpec::Matchers#eq_multiline #eq_multiline}: multiline equality akin to squiggly heredoc
10
11
  #
11
12
  module Matchers
12
13
  end
@@ -15,3 +16,5 @@ end
15
16
  require_relative 'matchers/eq_multiline'
16
17
  require_relative 'matchers/send_message'
17
18
  require_relative 'matchers/ret'
19
+ require_relative 'matchers/dont'
20
+ require_relative 'matchers/be_json'
@@ -0,0 +1,99 @@
1
+ require 'json'
2
+
3
+ module Saharspec
4
+ module Matchers
5
+ # @private
6
+ class BeJson
7
+ NONE = Object.new.freeze
8
+ include RSpec::Matchers::Composable
9
+ include RSpec::Matchers # to have #match
10
+
11
+ attr_reader :actual, :expected
12
+
13
+ def initialize(expected, **parse_opts)
14
+ @expected_matcher = @expected = expected
15
+ # wrap to make be_json('foo' => matcher) work, too
16
+ @expected_matcher = match(expected) unless expected == NONE || expected.respond_to?(:matches?)
17
+ @parse_opts = parse_opts
18
+ end
19
+
20
+ def matches?(json)
21
+ @actual = JSON.parse(json, **@parse_opts)
22
+ @expected_matcher == NONE || @expected_matcher === @actual
23
+ rescue JSON::ParserError => parse_error
24
+ @parser_error = parse_error
25
+ false
26
+ end
27
+
28
+ def does_not_match?(*args)
29
+ !matches?(*args)
30
+ end
31
+
32
+ def diffable?
33
+ true
34
+ end
35
+
36
+ def description
37
+ if @expected == NONE
38
+ 'be a valid JSON string'
39
+ else
40
+ expected = @expected.respond_to?(:description) ? @expected.description : @expected
41
+ "be a valid JSON matching (#{expected})"
42
+ end
43
+ end
44
+
45
+ def failure_message
46
+ failed =
47
+ case
48
+ when @parser_error
49
+ "failed: #{@parser_error}"
50
+ when @expected != NONE
51
+ "was #{@actual}"
52
+ end
53
+ "expected value to #{description} but #{failed}"
54
+ end
55
+
56
+ def failure_message_when_negated
57
+ 'expected value not to be parsed as JSON, but succeeded'
58
+ end
59
+ end
60
+ end
61
+ end
62
+
63
+ module RSpec
64
+ module Matchers
65
+ # `be_json` checks if provided value is JSON, and optionally checks it contents.
66
+ #
67
+ # If you need to check against some hashes, it is more convenient to use `be_json_sym`, which
68
+ # parses JSON with `symbolize_names: true`.
69
+ #
70
+ # @example
71
+ #
72
+ # expect('{}').to be_json # ok
73
+ # expect('garbage').to be_json
74
+ # # expected value to be a valid JSON string but failed: 765: unexpected token at 'garbage'
75
+ #
76
+ # expect('{"foo": "bar"}').to be_json('foo' => 'bar') # ok
77
+ # expect('{"foo": "bar"}').to be_json_sym(foo: 'bar') # more convenient
78
+ #
79
+ # expect('{"foo": [1, 2, 3]').to be_json_sym(foo: array_including(3)) # nested matchers work
80
+ # expect(something_large).to be_json_sym(include(meta: include(next_page: Integer)))
81
+ #
82
+ # @param expected Value or matcher to check JSON against. It should implement `#===` method,
83
+ # so all standard and custom RSpec matchers work.
84
+ def be_json(expected = Saharspec::Matchers::BeJson::NONE)
85
+ Saharspec::Matchers::BeJson.new(expected)
86
+ end
87
+
88
+ # `be_json_sym` checks if value is a valid JSON and parses it with `symbolize_names: true`. This
89
+ # way, it is convenient to check hashes content with Ruby's short symbolic keys syntax.
90
+ #
91
+ # See {#be_json_sym} for examples.
92
+ #
93
+ # @param expected Value or matcher to check JSON against. It should implement `#===` method,
94
+ # so all standard and custom RSpec matchers work.
95
+ def be_json_sym(expected = Saharspec::Matchers::BeJson::NONE)
96
+ Saharspec::Matchers::BeJson.new(expected, symbolize_names: true)
97
+ end
98
+ end
99
+ end
@@ -4,6 +4,8 @@ module Saharspec
4
4
  class Ret
5
5
  include RSpec::Matchers::Composable
6
6
 
7
+ attr_reader :actual, :expected
8
+
7
9
  def initialize(expected)
8
10
  @expected = expected
9
11
  end
@@ -12,13 +14,17 @@ module Saharspec
12
14
  @subject = subject
13
15
  return false unless subject.respond_to?(:call)
14
16
  @actual = subject.call
15
- @expected === @actual # rubocop:disable Style/CaseEquality
17
+ @expected === @actual
16
18
  end
17
19
 
18
20
  def supports_block_expectations?
19
21
  true
20
22
  end
21
23
 
24
+ def diffable?
25
+ true
26
+ end
27
+
22
28
  def description
23
29
  "return #{@expected.respond_to?(:description) ? @expected.description : @expected.inspect}"
24
30
  end
@@ -42,7 +48,8 @@ module RSpec
42
48
  # It should be considered instead of simple value matchers (like `eq`) in the situations:
43
49
  #
44
50
  # 1. Several block behaviors tested in the same test, joined with `.and`, or in separate tests
45
- # 2. You test what some block or method returns with arguments, using {Call#its_call #its_call}
51
+ # 2. You test what some block or method returns with arguments, using
52
+ # {Saharspec::Its::Call#its_call #its_call}
46
53
  #
47
54
  # Values are tested with `===`, which allows chaining other matchers and patterns to the check.
48
55
  #
@@ -16,8 +16,8 @@ module Saharspec
16
16
  self
17
17
  end
18
18
 
19
- def returning(res)
20
- @res = res
19
+ def returning(*res)
20
+ @res = [*res]
21
21
  self
22
22
  end
23
23
 
@@ -91,7 +91,7 @@ module Saharspec
91
91
 
92
92
  def allower
93
93
  receive(@method).tap do |a|
94
- a.and_return(@res) if @res
94
+ a.and_return(*@res) if @res
95
95
  a.and_call_original if @call_original
96
96
  end
97
97
  end
@@ -1,9 +1,6 @@
1
1
  module Saharspec
2
- # @private
3
2
  MAJOR = 0
4
- # @private
5
3
  MINOR = 0
6
- # @private
7
- PATCH = 4
4
+ PATCH = 5
8
5
  VERSION = [MAJOR, MINOR, PATCH].join('.')
9
6
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: saharspec
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.0.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Victor Shepelev
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-11-07 00:00:00.000000000 Z
11
+ date: 2018-03-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rubocop
@@ -125,6 +125,7 @@ files:
125
125
  - lib/saharspec/its/call.rb
126
126
  - lib/saharspec/its/map.rb
127
127
  - lib/saharspec/matchers.rb
128
+ - lib/saharspec/matchers/be_json.rb
128
129
  - lib/saharspec/matchers/dont.rb
129
130
  - lib/saharspec/matchers/eq_multiline.rb
130
131
  - lib/saharspec/matchers/request_webmock.rb
@@ -153,7 +154,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
153
154
  version: '0'
154
155
  requirements: []
155
156
  rubyforge_project:
156
- rubygems_version: 2.6.10
157
+ rubygems_version: 2.6.14
157
158
  signing_key:
158
159
  specification_version: 4
159
160
  summary: Several additions for DRYer RSpec code