PageRenderTime 79ms CodeModel.GetById 9ms app.highlight 65ms RepoModel.GetById 1ms app.codeStats 0ms

/spec/rails_best_practices/prepares/model_prepare_spec.rb

http://github.com/flyerhzm/rails_best_practices
Ruby | 433 lines | 403 code | 29 blank | 1 comment | 0 complexity | 89eb64de8bbf3cfd333965da86a1705c MD5 | raw file
  1# frozen_string_literal: true
  2
  3require 'spec_helper'
  4
  5module RailsBestPractices
  6  module Prepares
  7    describe ModelPrepare do
  8      let(:runner) { Core::Runner.new(prepares: described_class.new) }
  9
 10      context 'models' do
 11        it 'class_name with modules ::' do
 12          content = <<-EOF
 13          class Blog::Post < ActiveRecord::Base
 14          end
 15          EOF
 16          runner.prepare('app/models/admin/post.rb', content)
 17          models = Prepares.models
 18          expect(models.map(&:to_s)).to eq(['Blog::Post'])
 19        end
 20
 21        it 'class_name with modules' do
 22          content = <<-EOF
 23          module Blog
 24            class Post < ActiveRecord::Base
 25            end
 26          end
 27          EOF
 28          runner.prepare('app/models/admin/post.rb', content)
 29          models = Prepares.models
 30          expect(models.map(&:to_s)).to eq(['Blog::Post'])
 31        end
 32      end
 33
 34      context 'associations' do
 35        it 'parses model associations' do
 36          content = <<-EOF
 37          class Project < ActiveRecord::Base
 38            belongs_to              :portfolio
 39            has_one                 :project_manager
 40            has_many                :milestones
 41            has_and_belongs_to_many :categories
 42          end
 43          EOF
 44          runner.prepare('app/models/project.rb', content)
 45          model_associations = Prepares.model_associations
 46          expect(model_associations.get_association('Project', 'portfolio')).to eq(
 47            'meta' => 'belongs_to', 'class_name' => 'Portfolio'
 48          )
 49          expect(model_associations.get_association('Project', 'project_manager')).to eq(
 50            'meta' => 'has_one', 'class_name' => 'ProjectManager'
 51          )
 52          expect(model_associations.get_association('Project', 'milestones')).to eq(
 53            'meta' => 'has_many', 'class_name' => 'Milestone'
 54          )
 55          expect(model_associations.get_association('Project', 'categories')).to eq(
 56            'meta' => 'has_and_belongs_to_many', 'class_name' => 'Category'
 57          )
 58        end
 59
 60        context 'with class_name option' do
 61          it 'parses belongs_to' do
 62            content = <<-EOF
 63            class Post < ActiveRecord::Base
 64              belongs_to :author, "class_name" => "Person"
 65            end
 66            EOF
 67            runner.prepare('app/models/post.rb', content)
 68            model_associations = Prepares.model_associations
 69            expect(model_associations.get_association('Post', 'author')).to eq(
 70              'meta' => 'belongs_to', 'class_name' => 'Person'
 71            )
 72          end
 73
 74          it 'parses has_one' do
 75            content = <<-EOF
 76            class Project < ActiveRecord::Base
 77              has_one :project_manager, "class_name" => "Person"
 78            end
 79            EOF
 80            runner.prepare('app/models/post.rb', content)
 81            model_associations = Prepares.model_associations
 82            expect(model_associations.get_association('Project', 'project_manager')).to eq(
 83              'meta' => 'has_one', 'class_name' => 'Person'
 84            )
 85          end
 86
 87          it 'parses has_many' do
 88            content = <<-EOF
 89            class Project < ActiveRecord::Base
 90              has_many :people, "class_name" => "Person"
 91            end
 92            EOF
 93            runner.prepare('app/models/project.rb', content)
 94            model_associations = Prepares.model_associations
 95            expect(model_associations.get_association('Project', 'people')).to eq(
 96              'meta' => 'has_many', 'class_name' => 'Person'
 97            )
 98          end
 99
100          it 'parses has_and_belongs_to_many' do
101            content = <<-EOF
102            class Citizen < ActiveRecord::Base
103              has_and_belongs_to_many :nations, "class_name" => "Country"
104            end
105            EOF
106            runner.prepare('app/models/citizen.rb', content)
107            model_associations = Prepares.model_associations
108            expect(model_associations.get_association('Citizen', 'nations')).to eq(
109              'meta' => 'has_and_belongs_to_many', 'class_name' => 'Country'
110            )
111          end
112
113          context 'namespace' do
114            it 'parses with namespace' do
115              content = <<-EOF
116              class Community < ActiveRecord::Base
117                has_many :members
118              end
119              EOF
120              runner.prepare('app/models/community.rb', content)
121              content = <<-EOF
122              class Community::Member < ActiveRecord::Base
123                belongs_to :community
124              end
125              EOF
126              runner.prepare('app/models/community/member.rb', content)
127              runner.after_prepare
128              model_associations = Prepares.model_associations
129              expect(model_associations.get_association('Community', 'members')).to eq(
130                'meta' => 'has_many', 'class_name' => 'Community::Member'
131              )
132              expect(model_associations.get_association('Community::Member', 'community')).to eq(
133                'meta' => 'belongs_to', 'class_name' => 'Community'
134              )
135            end
136
137            it 'parses without namespace' do
138              content = <<-EOF
139              class Community::Member::Rating < ActiveRecord::Base
140                belongs_to :member
141              end
142              EOF
143              runner.prepare('app/models/community/member/rating.rb', content)
144              content = <<-EOF
145              class Community::Member < ActiveRecord::Base
146                has_many :ratings
147              end
148              EOF
149              runner.prepare('app/models/community/member.rb', content)
150              runner.after_prepare
151              model_associations = Prepares.model_associations
152              expect(model_associations.get_association('Community::Member::Rating', 'member')).to eq(
153                'meta' => 'belongs_to', 'class_name' => 'Community::Member'
154              )
155              expect(model_associations.get_association('Community::Member', 'ratings')).to eq(
156                'meta' => 'has_many', 'class_name' => 'Community::Member::Rating'
157              )
158            end
159          end
160        end
161
162        context 'mongoid embeds' do
163          it 'parses embeds_many' do
164            content = <<-EOF
165            class Person
166              include Mongoid::Document
167              embeds_many :addresses
168            end
169            EOF
170            runner.prepare('app/models/person.rb', content)
171            model_associations = Prepares.model_associations
172            expect(model_associations.get_association('Person', 'addresses')).to eq(
173              'meta' => 'embeds_many', 'class_name' => 'Address'
174            )
175          end
176
177          it 'parses embeds_one' do
178            content = <<-EOF
179            class Lush
180              include Mongoid::Document
181              embeds_one :whiskey, class_name: "Drink", inverse_of: :alcoholic
182            end
183            EOF
184            runner.prepare('app/models/lush.rb', content)
185            model_associations = Prepares.model_associations
186            expect(model_associations.get_association('Lush', 'whiskey')).to eq(
187              'meta' => 'embeds_one', 'class_name' => 'Drink'
188            )
189          end
190
191          it 'parses embedded_in' do
192            content = <<-EOF
193            class Drink
194              include Mongoid::Document
195              embedded_in :alcoholic, class_name: "Lush", inverse_of: :whiskey
196            end
197            EOF
198            runner.prepare('app/models/drink.rb', content)
199            model_associations = Prepares.model_associations
200            expect(model_associations.get_association('Drink', 'alcoholic')).to eq(
201              'meta' => 'embedded_in', 'class_name' => 'Lush'
202            )
203          end
204        end
205
206        context 'mongomapper many/one' do
207          it 'parses one' do
208            content = <<-EOF
209            class Employee
210              include MongoMapper::Document
211              one :desk
212            end
213            EOF
214            runner.prepare('app/models/employee.rb', content)
215            model_associations = Prepares.model_associations
216            expect(model_associations.get_association('Employee', 'desk')).to eq(
217              'meta' => 'one', 'class_name' => 'Desk'
218            )
219          end
220
221          it 'parses many' do
222            content = <<-EOF
223            class Tree
224              include MongoMapper::Document
225              many :birds
226            end
227            EOF
228            runner.prepare('app/models/tree.rb', content)
229            model_associations = Prepares.model_associations
230            expect(model_associations.get_association('Tree', 'birds')).to eq('meta' => 'many', 'class_name' => 'Bird')
231          end
232        end
233      end
234
235      context 'methods' do
236        it 'parses model methods' do
237          content = <<-EOF
238          class Post < ActiveRecord::Base
239            def save; end
240            def find; end
241          end
242          EOF
243          runner.prepare('app/models/post.rb', content)
244          methods = Prepares.model_methods
245          expect(methods.get_methods('Post').map(&:method_name)).to eq(%w[save find])
246        end
247
248        it 'parses model methods with access control' do
249          content = <<-EOF
250          class Post < ActiveRecord::Base
251            def save; end
252            def find; end
253            protected
254            def create_or_update; end
255            private
256            def find_by_sql; end
257          end
258          EOF
259          runner.prepare('app/models/post.rb', content)
260          methods = Prepares.model_methods
261          expect(methods.get_methods('Post').map(&:method_name)).to eq(%w[save find create_or_update find_by_sql])
262          expect(methods.get_methods('Post', 'public').map(&:method_name)).to eq(%w[save find])
263          expect(methods.get_methods('Post', 'protected').map(&:method_name)).to eq(['create_or_update'])
264          expect(methods.get_methods('Post', 'private').map(&:method_name)).to eq(['find_by_sql'])
265        end
266
267        it 'parses model methods with module ::' do
268          content = <<-EOF
269          class Admin::Blog::Post < ActiveRecord::Base
270            def save; end
271            def find; end
272          end
273          EOF
274          runner.prepare('app/models/admin/blog/post.rb', content)
275          methods = Prepares.model_methods
276          expect(methods.get_methods('Admin::Blog::Post').map(&:method_name)).to eq(%w[save find])
277        end
278
279        it 'parses model methods with module' do
280          content = <<-EOF
281          module Admin
282            module Blog
283              class Post < ActiveRecord::Base
284                def save; end
285                def find; end
286              end
287            end
288          end
289          EOF
290          runner.prepare('app/models/admin/blog/post.rb', content)
291          methods = Prepares.model_methods
292          expect(methods.get_methods('Admin::Blog::Post').map(&:method_name)).to eq(%w[save find])
293        end
294
295        it 'does not add methods from module' do
296          content = <<-EOF
297            class Model < ActiveRecord::Base
298            end
299          EOF
300          runner.prepare('app/models/model.rb', content)
301          content = <<-EOF
302            module Mixin
303              def mixed_method
304              end
305            end
306          EOF
307          runner.prepare('app/models/mixins/mixin.rb', content)
308          methods = Prepares.model_methods
309          expect(methods.get_methods('Model')).to be_empty
310        end
311      end
312
313      context 'scope' do
314        it 'treats named_scope as method' do
315          content = <<-EOF
316          class Post < ActiveRecord::Base
317            named_scope :active, conditions: {active: true}
318          end
319          EOF
320          runner.prepare('app/models/post.rb', content)
321          methods = Prepares.model_methods
322          expect(methods.get_methods('Post').map(&:method_name)).to eq(['active'])
323        end
324
325        it 'treats scope as method' do
326          content = <<-EOF
327          class Post < ActiveRecord::Base
328            scope :active, where(active: true)
329          end
330          EOF
331          runner.prepare('app/models/post.rb', content)
332          methods = Prepares.model_methods
333          expect(methods.get_methods('Post').map(&:method_name)).to eq(['active'])
334        end
335      end
336
337      context 'alias' do
338        it 'treats alias as method' do
339          content = <<-EOF
340          class Post < ActiveRecord::Base
341            alias :new :old
342          end
343          EOF
344          runner.prepare('app/models/post.rb', content)
345          methods = Prepares.model_methods
346          expect(methods.get_methods('Post').map(&:method_name)).to eq(['new'])
347        end
348
349        it 'treats alias_method as method' do
350          content = <<-EOF
351          class Post < ActiveRecord::Base
352            alias_method :new, :old
353          end
354          EOF
355          runner.prepare('app/models/post.rb', content)
356          methods = Prepares.model_methods
357          expect(methods.get_methods('Post').map(&:method_name)).to eq(['new'])
358        end
359
360        it 'treats alias_method_chain as method' do
361          content = <<-EOF
362          class Post < ActiveRecord::Base
363            alias_method_chain :method, :feature
364          end
365          EOF
366          runner.prepare('app/models/post.rb', content)
367          methods = Prepares.model_methods
368          expect(methods.get_methods('Post').map(&:method_name)).to eq(%w[method_with_feature method])
369        end
370      end
371
372      context 'attributes' do
373        it 'parses mongoid field' do
374          content = <<-EOF
375          class Post
376            include Mongoid::Document
377            field :title
378            field :tags, type: Array
379            field :comments_count, type: Integer
380            field :deleted_at, type: DateTime
381            field :active, type: Boolean
382          end
383          EOF
384          runner.prepare('app/models/post.rb', content)
385          model_attributes = Prepares.model_attributes
386          expect(model_attributes.get_attribute_type('Post', 'title')).to eq('String')
387          expect(model_attributes.get_attribute_type('Post', 'tags')).to eq('Array')
388          expect(model_attributes.get_attribute_type('Post', 'comments_count')).to eq('Integer')
389          expect(model_attributes.get_attribute_type('Post', 'deleted_at')).to eq('DateTime')
390          expect(model_attributes.get_attribute_type('Post', 'active')).to eq('Boolean')
391        end
392
393        it 'parses mongomapper field' do
394          content = <<-EOF
395          class Post
396            include MongoMapper::Document
397            key :first_name,  String
398            key :last_name,   String
399            key :age,         Integer
400            key :born_at,     Time
401            key :active,      Boolean
402            key :fav_colors,  Array
403          end
404          EOF
405          runner.prepare('app/models/post.rb', content)
406          model_attributes = Prepares.model_attributes
407          expect(model_attributes.get_attribute_type('Post', 'first_name')).to eq('String')
408          expect(model_attributes.get_attribute_type('Post', 'last_name')).to eq('String')
409          expect(model_attributes.get_attribute_type('Post', 'age')).to eq('Integer')
410          expect(model_attributes.get_attribute_type('Post', 'born_at')).to eq('Time')
411          expect(model_attributes.get_attribute_type('Post', 'active')).to eq('Boolean')
412          expect(model_attributes.get_attribute_type('Post', 'fav_colors')).to eq('Array')
413        end
414      end
415
416      context 'no error' do
417        it 'raiseds for finder_sql option' do
418          content = <<-EOF
419          class EventSubscription < ActiveRecord::Base
420            has_many :event_notification_template, finder_sql: ?
421          end
422          EOF
423          content =
424            content.sub(
425              '?',
426              '\'SELECT event_notification_templates.* from event_notification_templates where event_type_id=#{event_type_id} and delivery_method_id=#{delivery_method_id}\''
427            )
428          expect { runner.prepare('app/models/event_subscription.rb', content) }.not_to raise_error
429        end
430      end
431    end
432  end
433end