File: attribute_spec.rb

package info (click to toggle)
ruby-virtus 2.0.0-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 660 kB
  • sloc: ruby: 4,378; makefile: 2
file content (229 lines) | stat: -rw-r--r-- 5,350 bytes parent folder | download | duplicates (3)
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
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
require 'spec_helper'

describe Virtus, '#attribute' do
  let(:name)    { :test }
  let(:options) { {} }

  shared_examples_for 'a class with boolean attribute' do
    subject { Test }

    let(:object) { subject.new }

    it 'defines reader and writer' do
      object.test = true

      expect(object).to be_test
    end

    it 'defines predicate method' do
      object.test = false

      expect(object).to_not be_test
    end
  end

  shared_examples_for 'an object with string attribute' do
    it { is_expected.to respond_to(:test) }
    it { is_expected.to respond_to(:test=) }

    it 'can write and read the attribute' do
      subject.test = :foo
      expect(subject.test).to eql('foo')
    end
  end

  it 'returns self' do
    klass = Class.new { include Virtus }
    expect(klass.attribute(:test, String)).to be(klass)
  end

  it 'raises error when :name is a reserved name on a class' do
    klass = Class.new { include Virtus }
    expect { klass.attribute(:attributes, Set) }.to raise_error(
      ArgumentError, ':attributes is not allowed as an attribute name'
    )
  end

  it 'raises error when :name is a reserved name on an instance' do
    object = Class.new.new.extend(Virtus)
    expect { object.attribute(:attributes, Set) }.to raise_error(
      ArgumentError, ':attributes is not allowed as an attribute name'
    )
  end

  it 'allows :attributes as an attribute name when mass-assignment is not included' do
    klass = Class.new { include Virtus::Model::Core }
    klass.attribute(:attributes, Set)
    expect(klass.attribute_set[:attributes]).to be_instance_of(Virtus::Attribute::Collection)
  end

  it 'allows specifying attribute without type' do
    klass = Class.new { include Virtus::Model::Core }
    klass.attribute(:name)
    expect(klass.attribute_set[:name]).to be_instance_of(Virtus::Attribute)
  end

  context 'with a class' do
    context 'when type is Boolean' do
      before :all do
        class Test
          include Virtus

          attribute :test, Boolean
        end
      end

      after :all do
        Object.send(:remove_const, :Test)
      end

      it_behaves_like 'a class with boolean attribute'
    end

    context 'when type is "Boolean"' do
      before :all do
        class Test
          include Virtus

          attribute :test, 'Boolean'
        end
      end

      after :all do
        Object.send(:remove_const, :Test)
      end

      it_behaves_like 'a class with boolean attribute'
    end

    context 'when type is Axiom::Types::Boolean' do
      before :all do
        class Test
          include Virtus

          attribute :test, Axiom::Types::Boolean
        end
      end

      after :all do
        Object.send(:remove_const, :Test)
      end

      it_behaves_like 'a class with boolean attribute' do
        before do
          pending 'this will be fixed once Attribute::Boolean subclass is gone'
        end
      end
    end

    context 'when type is :Boolean' do
      before :all do
        class Test
          include Virtus

          attribute :test, 'Boolean'
        end
      end

      after :all do
        Object.send(:remove_const, :Test)
      end

      it_behaves_like 'a class with boolean attribute'

      context 'with a subclass' do
        it_behaves_like 'a class with boolean attribute' do
          subject { Class.new(Test) }

          it 'gets attributes from the parent class' do
            Test.attribute :other, Integer
            expect(subject.attribute_set[:other]).to eql(Test.attribute_set[:other])
          end
        end
      end
    end

    context 'when type is Decimal' do
      before :all do
        class Test
          include Virtus

          attribute :test, Decimal
        end
      end

      after :all do
        Object.send(:remove_const, :Test)
      end

      it 'maps type to the corresponding axiom type' do
        expect(Test.attribute_set[:test].type).to be(Axiom::Types::Decimal)
      end
    end
  end

  context 'with a module' do
    let(:mod) {
      Module.new {
        include Virtus

        attribute :test, String
      }
    }

    let(:model) { Class.new }

    context 'included in the class' do
      before do
        model.send(:include, mod)
      end

      it 'adds attributes from the module to a class that includes it' do
        expect(model.attribute_set[:test]).to be_instance_of(Virtus::Attribute)
      end

      it_behaves_like 'an object with string attribute' do
        subject { model.new }
      end
    end

    context 'included in the class' do
      it_behaves_like 'an object with string attribute' do
        subject { model.new.extend(mod) }
      end
    end
  end

  context 'with an instance' do
    subject { model.new }

    let(:model) { Class.new }

    before do
      subject.extend(Virtus)
      subject.attribute(:test, String)
    end

    it_behaves_like 'an object with string attribute'
  end

  context 'using custom module' do
    subject { model.new }

    let(:model) {
      Class.new {
        include Virtus.model { |config| config.coerce = false }

        attribute :test, String
      }
    }

    it { is_expected.to respond_to(:test) }
    it { is_expected.to respond_to(:test=) }

    it 'writes and reads attributes' do
      subject.test = :foo
      expect(subject.test).to be(:foo)
    end
  end
end