public
Description: The open source social networking platform in Ruby on Rails from the author of RailsSpace
Homepage: http://insoshi.com
Clone URL: git://github.com/insoshi/insoshi.git
Michael Hartl (author)
Thu May 08 10:54:15 -0700 2008
commit  ecb54f90dd7778d814c2bd09859d32618d349b19
tree    ce517c844277de45b71a60c74f7d5301e1c88bec
parent  36f34ca84b0d217e1d6b4b14a852a7a393fd2622
insoshi / spec / matchers / custom_model_matchers.rb
100644 151 lines (121 sloc) 3.378 kb
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
module CustomModelMatchers
  
  # Verify that a model instance has a maximum length on the given attribute.
  class MaximumLength
    def initialize(attribute, maxlength)
      @attribute = attribute
      @maxlength = maxlength
    end
    
    def matches?(model)
      @model = model
      just_right = model
      too_long = model.clone
      just_right.update_attributes(@attribute => "a" * @maxlength)
      too_long.update_attributes(@attribute => "a" * (@maxlength + 1))
      just_right.valid? and not too_long.valid?
    end
    
    def failure_message
      "#{@model.to_s} #{@attribute} should have maximum length #{@maxlength}"
    end
  end
  
  def have_maximum(attribute, maxlength)
    MaximumLength.new(attribute, maxlength)
  end
  
  # Test an array for distict elements.
  # If an array 'a' has distinct elements (no duplicates),
  # a.should have_distinct_elements
  # will pass.
  class DistinctElements
    
    def matches?(ary)
      ary == ary.uniq
    end
    
    def failure_message
      "Array should have distinct elements"
    end
    
    def negative_failure_message
      "Array should not have distinct elements"
    end
  end
  
  def have_distinct_elements
    DistinctElements.new
  end
  
  
  class ExistInDatabase
    def matches?(model)
      model.class.find(model)
      true
    rescue
      ActiveRecord::RecordNotFound
      false
    end
 
    def failure_message
      "Object should exist in the database but doesn't"
    end
    
    def negative_failure_message
      "Object shouldn't exist in the database but does"
    end
  end
  
  def exist_in_database
    ExistInDatabase.new
  end
  
  
  # Verify that an action destroys an associated attribute.
  # Usage:
  # @topic.should destroy_associated(:posts)
 
  class DestroyAssociated
 
    def initialize(attribute)
      @attribute = attribute
    end
 
    def matches?(parent)
      objects = parent.send(@attribute)
      # Objects must exist in the first place.
      raise ArgumentError, "Invalid initial association" unless found?(objects)
      parent.destroy
      not found?(objects)
    end
    
    def failure_message
      "Expected destruction of associated #{@attribute}"
    end
    
    def negative_failure_message
      "Expected destruction of associated #{@attribute}"
    end
    
    def found?(objects)
      if objects.is_a?(Array)
        # has_many
        objects.each do |object|
          object.class.find(object)
        end
      else
        # has_one
        object = objects
        object.class.find(object)
      end
      true
    rescue
      ActiveRecord::RecordNotFound
      false
    end
  end
  
  def destroy_associated(attribute)
    DestroyAssociated.new(attribute)
  end
  
  
  # Return true if an array includes the given attribute.
  # Usage: @person.contacts.should include_the(@contact)
  # N.B. We can't say 'include' instead of 'include_the' because
  # 'include' is a Ruby reserved word.
  class Include
  
    def initialize(attribute)
      @attribute = attribute
    end
    
    def matches?(object)
      object.include?(@attribute)
    end
    
    def failure_message
      "Expected array to include #{@attribute}"
    end
    
    def negative_failure_message
      "Expected array not to include #{@attribute}"
    end
  end
  
  #
  def include_the(attribute)
    Include.new(attribute)
  end
end