rspec-api-matchers 0.6.1 → 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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d7bafa7be5d9a9a73eec85c9c1fa473844e348a1
4
- data.tar.gz: b95d6c0afaa31f027647e56645e97030e4bd654e
3
+ metadata.gz: 20a535eed35e5707a7481654ed0b950564909105
4
+ data.tar.gz: 7f0bd00909ec5a02ad347d32e208ae6fc7e88365
5
5
  SHA512:
6
- metadata.gz: e7bf0a450c8600f4b1d93f7ca503fe50280356700b34b72701cd1bde563dcdb96498d3ef3620e62ff81be6587cb130db2645c06404650084f3ff1b11e02cb1a8
7
- data.tar.gz: 500abca1395d180d69c261e486af6821a52102f3603762369a1984d81db200dc9e0bfd7450854407bc0297207c4ae7034db12d57f8ffe8c32199612fd007c51b
6
+ metadata.gz: e5aac6339f3c1a600d56f3a606cbd9c62c87b3c1019aa9eecfa49cc9800e6815d8851fc4952ec8c56dc98cd387690f40f19b90b40ad38bf1121d89afde4ceff4
7
+ data.tar.gz: ddbc5ed30cd8e3f9ba422bfc7091737e276775c300d33bcefa7d748b5dace486c9fd3ab5a16f436e316249756e76d23907a2d4e2ba5d38fbdbf594b0b22cef00
data/README.md CHANGED
@@ -5,7 +5,9 @@ RSpecApi::Matchers lets you express outcomes on the response of web APIs.
5
5
 
6
6
  expect(response).to have_status(:not_found)
7
7
 
8
- More documentation and examples about RSpecApi are available at [http://rspec-api.github.io](http://rspec-api.github.io)
8
+ The full documentation is available at [rubydoc.info](http://rubydoc.info/github/rspec-api/rspec-api-matchers/master/frames).
9
+
10
+ More information about the parent project RSpecApi is available at [rspec-api.github.io](http://rspec-api.github.io)
9
11
 
10
12
  [![Build Status](https://travis-ci.org/rspec-api/rspec-api-matchers.png?branch=master)](https://travis-ci.org/rspec-api/rspec-api-matchers)
11
13
  [![Code Climate](https://codeclimate.com/github/rspec-api/rspec-api-matchers.png)](https://codeclimate.com/github/rspec-api/rspec-api-matchers)
@@ -21,10 +23,9 @@ Available matchers
21
23
  expect(response).to be_a_collection
22
24
  expect(response).to be_wrapped_in_callback('alert')
23
25
  expect(response).to be_sorted(by: :id, verse: :desc)
24
- expect(response).to be_filtered(by: :id, value: 10)
26
+ expect(response).to be_filtered(by: :id, value: 10, compare_with: :>)
25
27
  expect(response).to have_attributes(id: {value: 1.2}, url: {type: {string: :url}})
26
28
 
27
-
28
29
  How to install
29
30
  ==============
30
31
 
@@ -41,7 +42,6 @@ Indicating the full version in your Gemfile (*major*.*minor*.*patch*) guarantees
41
42
  that your project won’t occur in any error when you `bundle update` and a new
42
43
  version of RSpecApi::Matchers is released.
43
44
 
44
-
45
45
  How to contribute
46
46
  =================
47
47
 
@@ -11,6 +11,22 @@ require 'rspec-api/matchers/sort/be_sorted'
11
11
  require 'rspec-api/matchers/status/have_status'
12
12
 
13
13
  module RSpecApi
14
+ # Provides RSpec Matchers for RESTful web APIs.
15
+ #
16
+ # To have these matchers available inside of an RSpec `describe` block,
17
+ # tag that block with the `:rspec_api` metadata, or explicitly include the
18
+ # RSpecApi::Matchers module inside the example group
19
+ #
20
+ # @example Tag a `describe` block as `:rspec_api`:
21
+ # describe "Artists", rspec_api: true do
22
+ # ... # here you can write `expect(response).to have_status :ok`, etc.
23
+ # end
24
+ #
25
+ # @example Explicitly include the RSpecApi::Matchers module
26
+ # describe "Artists" do
27
+ # include RSpecApi::Matchers
28
+ # ... # here you can write `expect(response).to have_status :ok`, etc.
29
+ # end
14
30
  module Matchers
15
31
  include Attributes
16
32
  include Collection
@@ -25,20 +41,4 @@ module RSpecApi
25
41
  end
26
42
  end
27
43
 
28
- # RSpecApi::Matchers adds matchers to test RESTful APIs.
29
- #
30
- # To have these matchers available inside of an RSpec `describe` block, tag that
31
- # block with the `:rspec_api` metadata:
32
- #
33
- # describe "Artists", rspec_api: true do
34
- # ... # here you can write `expect(response).to have_status :ok`, etc.
35
- # end
36
- RSpec.configuration.include RSpecApi::Matchers, rspec_api: true
37
-
38
- # You can also explicitly include the RSpec::Api module inside the example group:
39
- #
40
- # describe "Artists" do
41
- # include RSpecApi::Matchers
42
- # ... # here you can write `expect(response).to have_status :ok`, etc.
43
- # end
44
- #
44
+ RSpec.configuration.include RSpecApi::Matchers, rspec_api: true
@@ -3,18 +3,28 @@ require 'rspec-api/matchers/attributes/matcher'
3
3
  module RSpecApi
4
4
  module Matchers
5
5
  module Attributes
6
- # Passes if the response body is either a JSON object or a collection of
7
- # JSON objects that include all the +attributes+.
6
+ # Passes if the object includes the expected attributes in the body.
8
7
  #
9
- # @example
8
+ # @example Passes if the body is a collection of objects with a URL site
9
+ # require 'rspec-api-matchers'
10
10
  #
11
- # # Passes if the body is an object with a URL-formatted String :site
12
- # response = OpenStruct.new body: '{"site": "http://www.example.com"}'
13
- # expect(response).to have_attributes(site: {type: {string: :url}})
11
+ # body = '[{"site": "http://www.foo.com"}, {"site": "http://bar.com"}]'
12
+ # obj = OpenStruct.new body: body
14
13
  #
15
- # For more examples check +have_attributes_spec.rb+.
16
-
17
- # TODO: add &block options
14
+ # describe 'have_attributes' do
15
+ # include RSpecApi::Matchers::Attributes
16
+ # it { expect(obj).to have_attributes(site: {type: {string: :url}}) }
17
+ # end
18
+ #
19
+ # # => (rspec) 1 example, 0 failures
20
+ #
21
+ # @param [Hash] attributes The expected attributes in the body
22
+ #
23
+ # The method works only if the object is a JSON object or a collection of
24
+ # JSON objects; in the latter case all the objects need to include the
25
+ # expected attributes for the expectation to pass.
26
+ #
27
+ # @see http://git.io/w2dLnw have_attributes_spec.rb for more examples
18
28
  def have_attributes(*attributes)
19
29
  RSpecApi::Matchers::Attributes::Matcher.new *attributes
20
30
  end
@@ -27,7 +27,7 @@ module RSpecApi
27
27
  private
28
28
 
29
29
  def has_attributes?(items, attrs)
30
- attrs.deep_symbolize_keys!
30
+ attrs.symbolize_keys!
31
31
  attrs.all?{|name, options| has_attribute? items, name, options}
32
32
  end
33
33
 
@@ -3,15 +3,22 @@ require 'rspec-api/matchers/collection/matcher'
3
3
  module RSpecApi
4
4
  module Matchers
5
5
  module Collection
6
- # Passes if the response body is a collection of JSON objects
6
+ # Passes if the object has a collection of JSON objects in the body.
7
7
  #
8
- # @example
8
+ # @example Passes if the body is a JSON array
9
+ # require 'rspec-api-matchers'
9
10
  #
10
- # # Passes if the body is a JSON array
11
- # body = '[{"id": 1}]'
12
- # expect(OpenStruct.new body: body).to be_a_collection
11
+ # body = '[{"id": 1}, {"name": "foo"}, {"name": "bar"}]'
12
+ # obj = OpenStruct.new body: body
13
13
  #
14
- # For more examples check +be_a_collection_spec.rb+.
14
+ # describe 'be_a_collection' do
15
+ # include RSpecApi::Matchers::Collection
16
+ # it { expect(obj).to be_a_collection }
17
+ # end
18
+ #
19
+ # # => (rspec) 1 example, 0 failures
20
+ #
21
+ # @see http://git.io/Bl5qJQ be_a_collection_spec.rb for more examples
15
22
  def be_a_collection
16
23
  RSpecApi::Matchers::Collection::Matcher.new
17
24
  end
@@ -3,15 +3,26 @@ require 'rspec-api/matchers/content_type/matcher'
3
3
  module RSpecApi
4
4
  module Matchers
5
5
  module ContentType
6
- # Passes if the response headers specify the provided content +type+
6
+ # Passes if the object includes the expected content type in the headers.
7
7
  #
8
- # @example
8
+ # @param [Symbol or String] type The expected content type. Can either
9
+ # be the exact Content-Type string or just the format. The special
10
+ # value +:any+ matches any content type.
11
+ #
12
+ # @example Passes if the headers matches the provided JSON content type
13
+ # require 'rspec-api-matchers'
9
14
  #
10
- # # Passes if the headers matches the provided JSON content type
11
15
  # headers ={'Content-Type' => 'application/json; charset=utf-8'}
12
- # expect(OpenStruct.new headers: headers).to have_content_type(:json)
16
+ # obj = OpenStruct.new headers: headers
17
+ #
18
+ # describe 'have_content_type' do
19
+ # include RSpecApi::Matchers::ContentType
20
+ # it { expect(obj).to have_content_type(:json) }
21
+ # end
22
+ #
23
+ # # => (rspec) 1 example, 0 failures
13
24
  #
14
- # For more examples check +have_content_type_spec.rb+.
25
+ # @see http://git.io/qwv-RQ have_content_type_spec.rb for more examples
15
26
  def have_content_type(type = nil)
16
27
  content_type = case type
17
28
  when :json then 'application/json; charset=utf-8'
@@ -3,15 +3,28 @@ require 'rspec-api/matchers/filter/matcher'
3
3
  module RSpecApi
4
4
  module Matchers
5
5
  module Filter
6
- # Passes if the response body is a non-empty filtered JSON collection
6
+ # Passes if the object has a non-empty filtered JSON collection in the body.
7
7
  #
8
- # @example
8
+ # @param [Hash] options how the body is expected to be filtered.
9
+ # @option options [Symbol or String] :by The JSON key to be filtered by
10
+ # @option options [Object] :value The expected value for the field
11
+ # @option options [Proc or Symbol] :compare_with (:==) The operator used
12
+ # to compare the expected value with the values in the collection
9
13
  #
10
- # # Passes if the body only contains objects with ID = 1
11
- # body = '[{"id": 1}, {"id": 1}, {"id": 1}]'
12
- # expect(OpenStruct.new body: body).to be_filtered by: :id, value: 1
14
+ # @example Passes if the body only contains objects with ID > 1
15
+ # require 'rspec-api-matchers'
13
16
  #
14
- # For more examples check +be_filtered_spec.rb+.
17
+ # body = '[{"id": 2}, {"id": 3}]'
18
+ # obj = OpenStruct.new body: body
19
+ #
20
+ # describe 'be_filtered' do
21
+ # include RSpecApi::Matchers::Filter
22
+ # it { expect(obj).to be_filtered by: :id, value: 1, compare_with: :> }
23
+ # end
24
+ #
25
+ # # => (rspec) 1 example, 0 failures
26
+ #
27
+ # @see http://git.io/lHO7nw be_filtered_spec.rb for more examples
15
28
  def be_filtered(options = {})
16
29
  RSpecApi::Matchers::Filter::Matcher.new options
17
30
  end
@@ -13,7 +13,7 @@ module RSpecApi
13
13
  end
14
14
 
15
15
  def matches?(response)
16
- super && all_objects_have_field? && has_two_objects? && is_filtered?
16
+ super && all_objects_have_field? && has_one_object? && is_filtered?
17
17
  end
18
18
 
19
19
  def description
@@ -34,8 +34,8 @@ module RSpecApi
34
34
  end
35
35
  end
36
36
 
37
- def has_two_objects?
38
- if json.length < 2
37
+ def has_one_object?
38
+ if json.length < 1
39
39
  msg = "Cannot test filtering on an array with #{json.length} items"
40
40
  raise RSpec::Core::Pending::PendingDeclaredInExample.new msg
41
41
  else
@@ -45,7 +45,13 @@ module RSpecApi
45
45
 
46
46
  def is_filtered?
47
47
  values = json.map{|item| item[field]}
48
- values.all?{|v| v.send compare_with, value}
48
+ values.all? do |v|
49
+ if compare_with.is_a?(Proc)
50
+ compare_with.call value, v
51
+ elsif compare_with.is_a?(Symbol)
52
+ v.send compare_with, value
53
+ end
54
+ end
49
55
  end
50
56
 
51
57
  def reverse?
@@ -3,15 +3,22 @@ require 'rspec-api/matchers/headers/matcher'
3
3
  module RSpecApi
4
4
  module Matchers
5
5
  module Headers
6
- # Passes if the response has a non-empty headers Hash.
6
+ # Passes if the object has a non-empty Hash in the headers.
7
7
  #
8
- # @example
8
+ # @example Passes if the headers include the content length
9
+ # require 'rspec-api-matchers'
9
10
  #
10
- # # Passes if the headers include the content length
11
11
  # headers = {'Content-Length' => 17372}
12
- # expect(OpenStruct.new headers: headers).to have_headers
12
+ # obj = OpenStruct.new headers: headers
13
13
  #
14
- # For more examples check +have_headers_spec.rb+.
14
+ # describe 'have_headers' do
15
+ # include RSpecApi::Matchers::Headers
16
+ # it { expect(obj).to have_headers }
17
+ # end
18
+ #
19
+ # # => (rspec) 1 example, 0 failures
20
+ #
21
+ # @see http://git.io/-Wb61A have_headers_spec.rb for more examples
15
22
  def have_headers
16
23
  RSpecApi::Matchers::Headers::Matcher.new
17
24
  end
@@ -3,15 +3,25 @@ require 'rspec-api/matchers/json/matcher'
3
3
  module RSpecApi
4
4
  module Matchers
5
5
  module Json
6
- # Passes if response body is a valid JSON or callback-wrapped JSON
6
+ # Passes if the object has valid JSON or JSONP in the body
7
7
  #
8
- # @example
8
+ # @example Passes if the body is valid JSON
9
+ # require 'rspec-api-matchers'
9
10
  #
10
- # # Passes if the body is valid JSON
11
11
  # body = '[{"id": 1}]'
12
- # expect(OpenStruct.new body: body).to be_valid_json
12
+ # obj = OpenStruct.new body: body
13
13
  #
14
- # For more examples check +be_valid_json_spec.rb+.
14
+ # describe 'be_valid_json' do
15
+ # include RSpecApi::Matchers::Json
16
+ # it { expect(obj).to be_valid_json }
17
+ # end
18
+ #
19
+ # # => (rspec) 1 example, 0 failures
20
+ #
21
+ # @note The JSONP option is debatable, since an API that returns a JSONP
22
+ # should probably set the content-type to application/javascript.
23
+ #
24
+ # @see http://git.io/Rq3lVg be_valid_json_spec.rb for more examples
15
25
  def be_valid_json
16
26
  RSpecApi::Matchers::Json::Matcher.new
17
27
  end
@@ -3,19 +3,24 @@ require 'rspec-api/matchers/jsonp/matcher'
3
3
  module RSpecApi
4
4
  module Matchers
5
5
  module Jsonp
6
- # Passes if response body is a valid JSON wrapped in a JSONP callback
6
+ # Passes if the object has a JSONP callback-wrapped body
7
7
  #
8
- # @example
8
+ # @param [Symbol or String] callback Name of the wrapping JSONP callback
9
+ #
10
+ # @example Passes if the body is wrapped in the function "alert"
11
+ # require 'rspec-api-matchers'
9
12
  #
10
- # # Passes if the body is wrapped in "alert"
11
13
  # body = 'alert([{"id": 1}])'
12
- # expect(OpenStruct.new body: body).to be_wrapped_in_callback(:alert)
14
+ # obj = OpenStruct.new body: body
13
15
  #
14
- # @note
16
+ # describe 'be_wrapped_in_callback' do
17
+ # include RSpecApi::Matchers::Jsonp
18
+ # it { expect(obj).to be_wrapped_in_callback(:alert) }
19
+ # end
15
20
  #
16
- # A JSONP should actually return application/javascript...
21
+ # # => (rspec) 1 example, 0 failures
17
22
  #
18
- # For more examples check +be_wrapped_in_callback_spec.rb+.
23
+ # @see http://git.io/XLeIOg be_wrapped_in_callback_spec.rb for more examples
19
24
  def be_wrapped_in_callback(callback = nil)
20
25
  RSpecApi::Matchers::Jsonp::Matcher.new callback
21
26
  end
@@ -3,20 +3,27 @@ require 'rspec-api/matchers/page_links/matcher'
3
3
  module RSpecApi
4
4
  module Matchers
5
5
  module PageLinks
6
- # Passes if response headers include pagination links ()
6
+ # Passes if the object includes pagination links in the headers
7
7
  #
8
- # @example
8
+ # @example Passes if the headers include a link to the previous page
9
+ # require 'rspec-api-matchers'
9
10
  #
10
- # # Passes if the headers include a link to the previous page
11
11
  # headers = {'Link' => '<https://example.com/1>; rel="prev"'}
12
- # expect(OpenStruct.new headers: headers).to have_page_links
12
+ # obj = OpenStruct.new headers: headers
13
13
  #
14
- # @note
14
+ # describe 'have_page_links' do
15
+ # include RSpecApi::Matchers::PageLinks
16
+ # it { expect(obj).to have_page_links }
17
+ # end
15
18
  #
16
- # Checking for the rel="prev" is probably enough for the purpose.
17
- # See http://tools.ietf.org/html/rfc5988#page-6 for Link specification.
19
+ # # => (rspec) 1 example, 0 failures
18
20
  #
19
- # For more examples check +have_page_links_spec.rb+.
21
+ # @note The method only checks the presence of a rel="prev" link.
22
+ # This may be extended in future versions.
23
+ #
24
+ # @see http://tools.ietf.org/html/rfc5988#page-6 RFC 5988 Link header specification
25
+ #
26
+ # @see http://git.io/yRiqYQ have_page_links_spec.rb for more examples
20
27
  def have_page_links
21
28
  RSpecApi::Matchers::PageLinks::Matcher.new
22
29
  end
@@ -3,15 +3,21 @@ require 'rspec-api/matchers/response/matcher'
3
3
  module RSpecApi
4
4
  module Matchers
5
5
  module Response
6
- # Passes if response is present
6
+ # Passes if the object has either a status, headers or a body.
7
7
  #
8
- # @example
8
+ # @example Passes if the response has a status
9
+ # require 'rspec-api-matchers'
9
10
  #
10
- # # Passes if the response has a status
11
- # response = OpenStruct.new status: 100
12
- # expect(response).to be_a_valid_response
11
+ # obj = OpenStruct.new status: 100
13
12
  #
14
- # For more examples check +be_a_valid_response_spec.rb+.
13
+ # describe 'be_a_valid_response' do
14
+ # include RSpecApi::Matchers::Response
15
+ # it { expect(obj).to be_a_valid_response }
16
+ # end
17
+ #
18
+ # # => (rspec) 1 example, 0 failures
19
+ #
20
+ # @see http://git.io/dc2QFg be_a_valid_response_spec.rb for more examples
15
21
  def be_a_valid_response
16
22
  RSpecApi::Matchers::Response::Matcher.new
17
23
  end
@@ -3,15 +3,28 @@ require 'rspec-api/matchers/sort/matcher'
3
3
  module RSpecApi
4
4
  module Matchers
5
5
  module Sort
6
- # Passes if the response body is a non-empty sorted JSON collection
6
+ # Passes if the object has a non-empty sorted JSON collection in the body.
7
7
  #
8
- # @example
8
+ # @param [Hash] options how the body is expected to be sorted.
9
+ # @option options [Symbol or String] :by The JSON key to sort by
10
+ # @option options [Symbol or String] :verse (:asc) The sorting direction
11
+ #
12
+ # Sorting is ascending unless +verse.to_s+ is 'desc' or 'descending'
13
+ #
14
+ # @example Passes if the body is sorted by descending IDs
15
+ # require 'rspec-api-matchers'
9
16
  #
10
- # # Passes if the body is sorted by descending IDs
11
17
  # body = '[{"id": 3}, {"id": 2}, {"id": 1}]'
12
- # expect(OpenStruct.new body: body).to be_sorted(by: :id, verse: :desc)
18
+ # obj = OpenStruct.new body: body
19
+ #
20
+ # describe 'be_sorted' do
21
+ # include RSpecApi::Matchers::Sort
22
+ # it { expect(obj).to be_sorted(by: :id, verse: :desc) }
23
+ # end
24
+ #
25
+ # # => (rspec) 1 example, 0 failures
13
26
  #
14
- # For more examples check +be_sorted_spec.rb+.
27
+ # @see http://git.io/UhC4MQ be_sorted_spec.rb for more examples
15
28
  def be_sorted(options = {})
16
29
  RSpecApi::Matchers::Sort::Matcher.new options
17
30
  end
@@ -3,20 +3,25 @@ require 'rspec-api/matchers/status/matcher'
3
3
  module RSpecApi
4
4
  module Matchers
5
5
  module Status
6
- # Passes if the response has a status that matches +status+.
6
+ # Passes if the object has a status that matches +status+.
7
7
  #
8
- # @example
8
+ # @param [Symbol or Integer] status The expected status code
9
9
  #
10
- # # Passes if the response status matches :ok
11
- # status = :ok
12
- # expect(OpenStruct.new status: status).to have_status 200
10
+ # @example Passes if the response status matches :ok
11
+ # require 'rspec-api-matchers'
13
12
  #
14
- # @note
13
+ # obj = OpenStruct.new status: 200
15
14
  #
16
- # The full list of symbolic HTTP status codes is available at:
17
- # http://git.io/YwpDnA#L542
15
+ # describe 'have_status' do
16
+ # include RSpecApi::Matchers::Status
17
+ # it { expect(obj).to have_status :ok }
18
+ # end
18
19
  #
19
- # For more examples check +have_headers_spec.rb+.
20
+ # # => (rspec) 1 example, 0 failures
21
+ #
22
+ # @see http://git.io/YwpDnA#L542 List of symbolic HTTP status codes
23
+ #
24
+ # @see http://git.io/Gvb-nQ have_headers_spec.rb for more examples
20
25
  def have_status(status)
21
26
  RSpecApi::Matchers::Status::Matcher.new status
22
27
  end
@@ -1,5 +1,5 @@
1
1
  module RSpecApi
2
2
  module Matchers
3
- VERSION = '0.6.1'
3
+ VERSION = '0.7.0'
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rspec-api-matchers
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.1
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - claudiob
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-11-10 00:00:00.000000000 Z
11
+ date: 2013-11-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec
@@ -80,6 +80,20 @@ dependencies:
80
80
  - - '>='
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: yard
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - '>='
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - '>='
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
83
97
  - !ruby/object:Gem::Dependency
84
98
  name: coveralls
85
99
  requirement: !ruby/object:Gem::Requirement
@@ -154,3 +168,4 @@ specification_version: 4
154
168
  summary: Methods extracted from rspec-api to chech validity of the response of pragmatic
155
169
  RESTful web APIs.
156
170
  test_files: []
171
+ has_rdoc: