File: double.rb

package info (click to toggle)
ruby-rr 1.2.0-1
  • links: PTS, VCS
  • area: main
  • in suites: stretch
  • size: 1,436 kB
  • ctags: 1,404
  • sloc: ruby: 11,657; makefile: 5
file content (155 lines) | stat: -rw-r--r-- 4,329 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
module RR
  # RR::Double is the use case for a method call.
  # It has the ArgumentEqualityExpectation, TimesCalledExpectation,
  # and the implementation.
  class Double
    extend(Module.new do
      def formatted_name(method_name, args)
        formatted_errors = args.collect {|arg| arg.inspect}.join(', ')
        "#{method_name}(#{formatted_errors})"
      end

      def list_message_part(doubles)
        doubles.collect do |double|
          "- #{formatted_name(double.method_name, double.expected_arguments)}"
        end.join("\n")
      end
    end)

    attr_reader :times_called, :double_injection, :definition, :times_called_expectation

    include Space::Reader

    def initialize(double_injection, definition)
      @double_injection = double_injection
      @definition = definition
      @times_called = 0
      @times_called_expectation = Expectations::TimesCalledExpectation.new(self)
      definition.double = self
      verify_method_signature if definition.verify_method_signature?
      double_injection.register_double self
    end

    # Double#exact_match? returns true when the passed in arguments
    # exactly match the ArgumentEqualityExpectation arguments.
    def exact_match?(*arguments)
      definition.exact_match?(*arguments)
    end

    # Double#wildcard_match? returns true when the passed in arguments
    # wildcard match the ArgumentEqualityExpectation arguments.
    def wildcard_match?(*arguments)
      definition.wildcard_match?(*arguments)
    end

    # Double#attempt? returns true when the
    # TimesCalledExpectation is satisfied.
    def attempt?
      verify_times_matcher_is_set
      times_called_expectation.attempt?
    end

    # Double#verify verifies the the TimesCalledExpectation
    # is satisfied for this double. A TimesCalledError
    # is raised if the TimesCalledExpectation is not met.
    def verify
      verify_times_matcher_is_set
      times_called_expectation.verify!
      true
    end

    def terminal?
      verify_times_matcher_is_set
      times_called_expectation.terminal?
    end

    # The method name that this Double is attatched to
    def method_name
      double_injection.method_name
    end

    # The Arguments that this Double expects
    def expected_arguments
      verify_argument_expectation_is_set
      argument_expectation.expected_arguments
    end

    # The TimesCalledMatcher for the TimesCalledExpectation
    def times_matcher
      definition.times_matcher
    end

    def formatted_name
      self.class.formatted_name(method_name, expected_arguments)
    end

    def method_call(args)
      if verbose?
        puts Double.formatted_name(method_name, args)
      end
      times_called_expectation.attempt if definition.times_matcher
      space.verify_ordered_double(self) if ordered?
    end

    def implementation_is_original_method?
      definition.implementation_is_original_method?
    end

  protected
    def ordered?
      definition.ordered?
    end

    def verbose?
      definition.verbose?
    end

    def verify_times_matcher_is_set
      unless definition.times_matcher
        raise RR::Errors.build_error(:DoubleDefinitionError, "#definition.times_matcher is not set")
      end
    end

    def verify_argument_expectation_is_set
      unless definition.argument_expectation
        raise RR::Errors.build_error(:DoubleDefinitionError, "#definition.argument_expectation is not set")
      end
    end

    def verify_method_signature
      unless double_injection.subject_has_original_method?
        raise RR::Errors.build_error(:SubjectDoesNotImplementMethodError)
      end
      raise RR::Errors.build_error(:SubjectHasDifferentArityError) unless arity_matches?
    end

    def subject_arity
      double_injection.original_method.arity
    end

    def subject_accepts_only_varargs?
      subject_arity == -1
    end

    def subject_accepts_varargs?
      subject_arity < 0
    end

    def arity_matches?
      return true if subject_accepts_only_varargs?
      if subject_accepts_varargs?
        return ((subject_arity * -1) - 1) <= args.size
      else
        return subject_arity == args.size
      end
    end

    def args
      definition.argument_expectation.expected_arguments
    end

    def argument_expectation
      definition.argument_expectation
    end
  end
end