File: simple_example.feature

package info (click to toggle)
ruby-contracts 0.17-2
  • links: PTS, VCS
  • area: main
  • in suites: sid, trixie
  • size: 624 kB
  • sloc: ruby: 3,805; makefile: 4; sh: 2
file content (210 lines) | stat: -rw-r--r-- 5,730 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
Feature: Simple examples and Contract violations

  Contracts.ruby allows specification of contracts on per-method basis, where
  method arguments and return value will be validated upon method call.

  Example:

  ```ruby
  Contract C::Num, C::Num => C::Num
  def add(a, b)
    a + b
  end
  ```

  Here `Contract arg_contracts... => return_contract` defines list of argument
  contracts `args_contracts...` as `C::Num, C::Num` (i.e.: both arguments
  should be numbers) and return value contract `return_contract` as `C::Num`
  (i.e.: return value should be a number too).

  `Contract arg_contracts... => return_contract` affects next defined instance,
  class or singleton method, meaning that all of these work:

  - [Instance method](#instance-method),

  - [Class method](#class-method),

  - [Singleton method](#singleton-method).

  Whenever invalid argument is passed to a contracted method, corresponding
  `ContractError` will be raised. That happens right after bad value got into
  system protected by contracts and prevents error propagation: first
  non-contracts library frame in exception's backtrace is a culprit for passing
  an invalid argument - you do not need to verify 20-30 frames to find a
  culprit! Example of such error: [instance method contract
  violation](#instance-method-contract-violation).

  Whenever invalid return value is returned from a contracted method,
  corresponding `ContractError` will be raised. That happens right after method
  returned this value and prevents error propagation: `At: your_filename.rb:17`
  part of error message points directly to a culprit method. Example of such
  error: [return value contract
  violation](#singleton-method-return-value-contract-violation).

  Contract violation error consists of such parts:
  - Violation type:
    - `Contract violation for argument X of Y: (ParamContractError)`,
    - `Contract violation for return value (ReturnContractError)`.
  - Expected contract, example: `Expected: Num`.
  - Actual value, example: `Actual: "foo"`.
  - Location of violated contract, example: `Value guarded in: Example::add`.
  - Full contract, example: `With Contract: Num, Num => Num`.
  - Source code location of contracted method, example: `At: lib/your_library/some_class.rb:17`.

  Scenario: Instance method
    Given a file named "instance_method.rb" with:
    """ruby
    require "contracts"
    C = Contracts

    class Example
      include Contracts::Core

      Contract C::Num, C::Num => C::Num
      def add(a, b)
        a + b
      end
    end

    puts Example.new.add(2, 2)
    """
    When I run `ruby instance_method.rb`
    Then the output should contain:
    """
    4
    """

  Scenario: Instance method contract violation
    Given a file named "instance_method_violation.rb" with:
    """ruby
    require "contracts"
    C = Contracts

    class Example
      include Contracts::Core

      Contract C::Num, C::Num => C::Num
      def add(a, b)
        a + b
      end
    end

    puts Example.new.add(2, "foo")
    """
    When I run `ruby instance_method_violation.rb`
    Then the output should contain:
    """
    : Contract violation for argument 2 of 2: (ParamContractError)
            Expected: Num,
            Actual: "foo"
            Value guarded in: Example::add
            With Contract: Num, Num => Num
            At: instance_method_violation.rb:8
    """

  Scenario: Class method
    Given a file named "class_method.rb" with:
    """ruby
    require "contracts"
    C = Contracts

    class Example
      include Contracts::Core

      Contract C::Num, C::Num => C::Num
      def self.add(a, b)
        a + b
      end
    end

    puts Example.add(2, 2)
    """
    When I run `ruby class_method.rb`
    Then the output should contain:
    """
    4
    """

  Scenario: Class method contract violation
    Given a file named "class_method_violation.rb" with:
    """ruby
    require "contracts"
    C = Contracts

    class Example
      include Contracts::Core

      Contract C::Num, C::Num => C::Num
      def self.add(a, b)
        a + b
      end
    end

    puts Example.add(:foo, 2)
    """
    When I run `ruby class_method_violation.rb`
    Then the output should contain:
    """
    : Contract violation for argument 1 of 2: (ParamContractError)
            Expected: Num,
            Actual: :foo
            Value guarded in: Example::add
            With Contract: Num, Num => Num
            At: class_method_violation.rb:8
    """

  Scenario: Singleton method
    Given a file named "singleton_method.rb" with:
    """ruby
    require "contracts"
    C = Contracts

    class Example
      include Contracts::Core

      class << self
        Contract C::Num, C::Num => C::Num
        def add(a, b)
          a + b
        end
      end
    end

    puts Example.add(2, 2)
    """
    When I run `ruby singleton_method.rb`
    Then the output should contain:
    """
    4
    """

  Scenario: Singleton method return value contract violation
    Given a file named "singleton_method_violation.rb" with:
    """ruby
    require "contracts"
    C = Contracts

    class Example
      include Contracts::Core

      class << self
        Contract C::Num, C::Num => C::Num
        def add(a, b)
          # notice here non-number is returned
          nil
        end
      end
    end

    puts Example.add(2, 2)
    """
    When I run `ruby singleton_method_violation.rb`
    Then the output should contain:
    """
    : Contract violation for return value: (ReturnContractError)
            Expected: Num,
            Actual: nil
            Value guarded in: Example::add
            With Contract: Num, Num => Num
            At: singleton_method_violation.rb:9
    """