Commit 5b0a998920d9357446c89ba7352f38622fb1323f

Authored by Dmitriy Zaporozhets
2 parents 8c44789e 97423a0b

Merge pull request #1333 from tsigo/model_specs

Increased model spec coverage
spec/factories.rb
... ... @@ -18,11 +18,15 @@ FactoryGirl.define do
18 18 Faker::Lorem.sentence
19 19 end
20 20  
  21 + sequence :name, aliases: [:file_name] do
  22 + Faker::Name.name
  23 + end
  24 +
21 25 sequence(:url) { Faker::Internet.uri('http') }
22 26  
23 27 factory :user, aliases: [:author, :assignee, :owner] do
24 28 email { Faker::Internet.email }
25   - name { Faker::Name.name }
  29 + name
26 30 password "123456"
27 31 password_confirmation "123456"
28 32  
... ... @@ -116,6 +120,11 @@ FactoryGirl.define do
116 120 author
117 121 title
118 122 content
119   - file_name { Faker::Lorem.sentence }
  123 + file_name
  124 + end
  125 +
  126 + factory :protected_branch do
  127 + name
  128 + project
120 129 end
121 130 end
... ...
spec/models/event_spec.rb
1   -# == Schema Information
2   -#
3   -# Table name: events
4   -#
5   -# id :integer(4) not null, primary key
6   -# target_type :string(255)
7   -# target_id :integer(4)
8   -# title :string(255)
9   -# data :text
10   -# project_id :integer(4)
11   -# created_at :datetime not null
12   -# updated_at :datetime not null
13   -# action :integer(4)
14   -# author_id :integer(4)
15   -#
16   -
17 1 require 'spec_helper'
18 2  
19 3 describe Event do
20 4 describe "Associations" do
21 5 it { should belong_to(:project) }
  6 + it { should belong_to(:target) }
22 7 end
23 8  
24 9 describe "Respond to" do
... ... @@ -29,16 +14,6 @@ describe Event do
29 14 it { should respond_to(:commits) }
30 15 end
31 16  
32   - describe "Creation" do
33   - before do
34   - @event = Factory :event
35   - end
36   -
37   - it "should create a valid event" do
38   - @event.should be_valid
39   - end
40   - end
41   -
42 17 describe "Push event" do
43 18 before do
44 19 project = Factory :project
... ...
spec/models/issue_spec.rb
... ... @@ -2,21 +2,16 @@ require 'spec_helper'
2 2  
3 3 describe Issue do
4 4 describe "Associations" do
5   - it { should belong_to(:project) }
6   - it { should belong_to(:author) }
7   - it { should belong_to(:assignee) }
8 5 it { should belong_to(:milestone) }
9 6 end
10 7  
11 8 describe "Validation" do
12   - it { should validate_presence_of(:title) }
13   - it { should validate_presence_of(:author_id) }
14   - it { should validate_presence_of(:project_id) }
  9 + it { should ensure_length_of(:description).is_within(0..2000) }
15 10 end
16 11  
17   - describe "Scope" do
18   - it { Issue.should respond_to :closed }
19   - it { Issue.should respond_to :opened }
  12 + describe 'modules' do
  13 + it { should include_module(IssueCommonality) }
  14 + it { should include_module(Upvote) }
20 15 end
21 16  
22 17 subject { Factory.create(:issue) }
... ... @@ -61,57 +56,4 @@ describe Issue do
61 56 subject.is_being_reopened?.should be_false
62 57 end
63 58 end
64   -
65   - describe "plus 1" do
66   - subject { Factory.create(:issue) }
67   -
68   - it "with no notes has a 0/0 score" do
69   - subject.upvotes.should == 0
70   - end
71   -
72   - it "should recognize non-+1 notes" do
73   - subject.notes << Factory(:note, note: "No +1 here")
74   - subject.should have(1).note
75   - subject.notes.first.upvote?.should be_false
76   - subject.upvotes.should == 0
77   - end
78   -
79   - it "should recognize a single +1 note" do
80   - subject.notes << Factory(:note, note: "+1 This is awesome")
81   - subject.upvotes.should == 1
82   - end
83   -
84   - it "should recognize a multiple +1 notes" do
85   - subject.notes << Factory(:note, note: "+1 This is awesome")
86   - subject.notes << Factory(:note, note: "+1 I want this")
87   - subject.upvotes.should == 2
88   - end
89   - end
90   -
91   - describe ".search" do
92   - let!(:issue) { Factory.create(:issue, title: "Searchable issue") }
93   -
94   - it "matches by title" do
95   - Issue.search('able').all.should == [issue]
96   - end
97   - end
98 59 end
99   -# == Schema Information
100   -#
101   -# Table name: issues
102   -#
103   -# id :integer(4) not null, primary key
104   -# title :string(255)
105   -# assignee_id :integer(4)
106   -# author_id :integer(4)
107   -# project_id :integer(4)
108   -# created_at :datetime not null
109   -# updated_at :datetime not null
110   -# closed :boolean(1) default(FALSE), not null
111   -# position :integer(4) default(0)
112   -# critical :boolean(1) default(FALSE), not null
113   -# branch_name :string(255)
114   -# description :text
115   -# milestone_id :integer(4)
116   -#
117   -
... ...
spec/models/key_spec.rb
... ... @@ -2,12 +2,15 @@ require &#39;spec_helper&#39;
2 2  
3 3 describe Key do
4 4 describe "Associations" do
5   - it { should belong_to(:user) or belong_to(:project) }
  5 + it { should belong_to(:user) }
  6 + it { should belong_to(:project) }
6 7 end
7 8  
8 9 describe "Validation" do
9 10 it { should validate_presence_of(:title) }
10 11 it { should validate_presence_of(:key) }
  12 + it { should ensure_length_of(:title).is_within(0..255) }
  13 + it { should ensure_length_of(:key).is_within(0..5000) }
11 14 end
12 15  
13 16 describe "Methods" do
... ... @@ -44,17 +47,3 @@ describe Key do
44 47 end
45 48 end
46 49 end
47   -# == Schema Information
48   -#
49   -# Table name: keys
50   -#
51   -# id :integer(4) not null, primary key
52   -# user_id :integer(4)
53   -# created_at :datetime not null
54   -# updated_at :datetime not null
55   -# key :text
56   -# title :string(255)
57   -# identifier :string(255)
58   -# project_id :integer(4)
59   -#
60   -
... ...
spec/models/merge_request_spec.rb
1 1 require 'spec_helper'
2 2  
3 3 describe MergeRequest do
4   - describe "Associations" do
5   - it { should belong_to(:project) }
6   - it { should belong_to(:author) }
7   - it { should belong_to(:assignee) }
8   - end
9   -
10 4 describe "Validation" do
11 5 it { should validate_presence_of(:target_branch) }
12 6 it { should validate_presence_of(:source_branch) }
13   - it { should validate_presence_of(:title) }
14   - it { should validate_presence_of(:author_id) }
15   - it { should validate_presence_of(:project_id) }
16   - end
17   -
18   - describe "Scope" do
19   - it { MergeRequest.should respond_to :closed }
20   - it { MergeRequest.should respond_to :opened }
21   - end
22   -
23   - describe "plus 1" do
24   - subject { Factory.create(:merge_request) }
25   -
26   - it "with no notes has a 0/0 score" do
27   - subject.upvotes.should == 0
28   - end
29   -
30   - it "should recognize non-+1 notes" do
31   - subject.notes << Factory(:note, note: "No +1 here")
32   - subject.should have(1).note
33   - subject.notes.first.upvote?.should be_false
34   - subject.upvotes.should == 0
35   - end
36   -
37   - it "should recognize a single +1 note" do
38   - subject.notes << Factory(:note, note: "+1 This is awesome")
39   - subject.upvotes.should == 1
40   - end
41   -
42   - it "should recognize a multiple +1 notes" do
43   - subject.notes << Factory(:note, note: "+1 This is awesome")
44   - subject.notes << Factory(:note, note: "+1 I want this")
45   - subject.upvotes.should == 2
46   - end
47 7 end
48 8  
49   - describe ".search" do
50   - let!(:issue) { Factory.create(:issue, title: "Searchable issue") }
51   -
52   - it "matches by title" do
53   - Issue.search('able').all.should == [issue]
54   - end
  9 + describe 'modules' do
  10 + it { should include_module(IssueCommonality) }
  11 + it { should include_module(Upvote) }
55 12 end
56 13 end
57   -# == Schema Information
58   -#
59   -# Table name: merge_requests
60   -#
61   -# id :integer(4) not null, primary key
62   -# target_branch :string(255) not null
63   -# source_branch :string(255) not null
64   -# project_id :integer(4) not null
65   -# author_id :integer(4)
66   -# assignee_id :integer(4)
67   -# title :string(255)
68   -# closed :boolean(1) default(FALSE), not null
69   -# created_at :datetime not null
70   -# updated_at :datetime not null
71   -# st_commits :text(2147483647
72   -# st_diffs :text(2147483647
73   -# merged :boolean(1) default(FALSE), not null
74   -# state :integer(4) default(1), not null
75   -#
76   -
... ...
spec/models/milestone_spec.rb
1   -# == Schema Information
2   -#
3   -# Table name: milestones
4   -#
5   -# id :integer(4) not null, primary key
6   -# title :string(255) not null
7   -# project_id :integer(4) not null
8   -# description :text
9   -# due_date :date
10   -# closed :boolean(1) default(FALSE), not null
11   -# created_at :datetime not null
12   -# updated_at :datetime not null
13   -#
14   -
15 1 require 'spec_helper'
16 2  
17 3 describe Milestone do
... ...
spec/models/note_spec.rb
... ... @@ -3,6 +3,8 @@ require &#39;spec_helper&#39;
3 3 describe Note do
4 4 describe "Associations" do
5 5 it { should belong_to(:project) }
  6 + it { should belong_to(:noteable) }
  7 + it { should belong_to(:author).class_name('User') }
6 8 end
7 9  
8 10 describe "Validation" do
... ... @@ -130,19 +132,3 @@ describe Note do
130 132 end
131 133 end
132 134 end
133   -# == Schema Information
134   -#
135   -# Table name: notes
136   -#
137   -# id :integer(4) not null, primary key
138   -# note :text
139   -# noteable_id :string(255)
140   -# noteable_type :string(255)
141   -# author_id :integer(4)
142   -# created_at :datetime not null
143   -# updated_at :datetime not null
144   -# project_id :integer(4)
145   -# attachment :string(255)
146   -# line_code :string(255)
147   -#
148   -
... ...
spec/models/project_spec.rb
... ... @@ -2,23 +2,52 @@ require &#39;spec_helper&#39;
2 2  
3 3 describe Project do
4 4 describe "Associations" do
  5 + it { should belong_to(:owner).class_name('User') }
5 6 it { should have_many(:users) }
6   - it { should have_many(:protected_branches).dependent(:destroy) }
7 7 it { should have_many(:events).dependent(:destroy) }
8   - it { should have_many(:wikis).dependent(:destroy) }
9 8 it { should have_many(:merge_requests).dependent(:destroy) }
10   - it { should have_many(:users_projects).dependent(:destroy) }
11 9 it { should have_many(:issues).dependent(:destroy) }
  10 + it { should have_many(:milestones).dependent(:destroy) }
  11 + it { should have_many(:users_projects).dependent(:destroy) }
12 12 it { should have_many(:notes).dependent(:destroy) }
13 13 it { should have_many(:snippets).dependent(:destroy) }
14   - it { should have_many(:hooks).dependent(:destroy) }
15 14 it { should have_many(:deploy_keys).dependent(:destroy) }
  15 + it { should have_many(:hooks).dependent(:destroy) }
  16 + it { should have_many(:wikis).dependent(:destroy) }
  17 + it { should have_many(:protected_branches).dependent(:destroy) }
16 18 end
17 19  
18 20 describe "Validation" do
  21 + let!(:project) { create(:project) }
  22 +
19 23 it { should validate_presence_of(:name) }
  24 + it { should validate_uniqueness_of(:name) }
  25 + it { should ensure_length_of(:name).is_within(0..255) }
  26 +
20 27 it { should validate_presence_of(:path) }
  28 + it { should validate_uniqueness_of(:path) }
  29 + it { should ensure_length_of(:path).is_within(0..255) }
  30 + # TODO: Formats
  31 +
  32 + it { should ensure_length_of(:description).is_within(0..2000) }
  33 +
21 34 it { should validate_presence_of(:code) }
  35 + it { should validate_uniqueness_of(:code) }
  36 + it { should ensure_length_of(:code).is_within(1..255) }
  37 + # TODO: Formats
  38 +
  39 + it { should validate_presence_of(:owner) }
  40 +
  41 + it "should not allow new projects beyond user limits" do
  42 + project.stub(:owner).and_return(double(can_create_project?: false, projects_limit: 1))
  43 + project.should_not be_valid
  44 + project.errors[:base].first.should match(/Your own projects limit is 1/)
  45 + end
  46 +
  47 + it "should not allow 'gitolite-admin' as repo name" do
  48 + should allow_value("blah").for(:path)
  49 + should_not allow_value("gitolite-admin").for(:path)
  50 + end
22 51 end
23 52  
24 53 describe "Respond to" do
... ... @@ -73,9 +102,11 @@ describe Project do
73 102 it { should respond_to(:trigger_post_receive) }
74 103 end
75 104  
76   - it "should not allow 'gitolite-admin' as repo name" do
77   - should allow_value("blah").for(:path)
78   - should_not allow_value("gitolite-admin").for(:path)
  105 + describe 'modules' do
  106 + it { should include_module(Repository) }
  107 + it { should include_module(PushObserver) }
  108 + it { should include_module(Authority) }
  109 + it { should include_module(Team) }
79 110 end
80 111  
81 112 it "should return valid url to repo" do
... ... @@ -236,23 +267,3 @@ describe Project do
236 267 end
237 268 end
238 269 end
239   -# == Schema Information
240   -#
241   -# Table name: projects
242   -#
243   -# id :integer(4) not null, primary key
244   -# name :string(255)
245   -# path :string(255)
246   -# description :text
247   -# created_at :datetime not null
248   -# updated_at :datetime not null
249   -# private_flag :boolean(1) default(TRUE), not null
250   -# code :string(255)
251   -# owner_id :integer(4)
252   -# default_branch :string(255) default("master"), not null
253   -# issues_enabled :boolean(1) default(TRUE), not null
254   -# wall_enabled :boolean(1) default(TRUE), not null
255   -# merge_requests_enabled :boolean(1) default(TRUE), not null
256   -# wiki_enabled :boolean(1) default(TRUE), not null
257   -#
258   -
... ...
spec/models/protected_branch_spec.rb
1   -# == Schema Information
2   -#
3   -# Table name: protected_branches
4   -#
5   -# id :integer(4) not null, primary key
6   -# project_id :integer(4) not null
7   -# name :string(255) not null
8   -# created_at :datetime not null
9   -# updated_at :datetime not null
10   -#
11   -
12 1 require 'spec_helper'
13 2  
14 3 describe ProtectedBranch do
15   - let(:project) { Factory(:project) }
16   -
17 4 describe 'Associations' do
18 5 it { should belong_to(:project) }
19 6 end
... ... @@ -24,26 +11,26 @@ describe ProtectedBranch do
24 11 end
25 12  
26 13 describe 'Callbacks' do
27   - subject { ProtectedBranch.new(project: project, name: 'branch_name') }
  14 + let(:branch) { build(:protected_branch) }
28 15  
29 16 it 'call update_repository after save' do
30   - subject.should_receive(:update_repository)
31   - subject.save
  17 + branch.should_receive(:update_repository)
  18 + branch.save
32 19 end
33 20  
34 21 it 'call update_repository after destroy' do
35   - subject.should_receive(:update_repository)
36   - subject.destroy
  22 + branch.save
  23 + branch.should_receive(:update_repository)
  24 + branch.destroy
37 25 end
38 26 end
39 27  
40 28 describe '#commit' do
41   - subject { ProtectedBranch.new(project: project, name: 'cant_touch_this') }
  29 + let(:branch) { create(:protected_branch) }
42 30  
43 31 it 'commits itself to its project' do
44   - project.should_receive(:commit).with('cant_touch_this')
45   -
46   - subject.commit
  32 + branch.project.should_receive(:commit).with(branch.name)
  33 + branch.commit
47 34 end
48 35 end
49 36 end
... ...
spec/models/snippet_spec.rb
... ... @@ -3,29 +3,21 @@ require &#39;spec_helper&#39;
3 3 describe Snippet do
4 4 describe "Associations" do
5 5 it { should belong_to(:project) }
6   - it { should belong_to(:author) }
  6 + it { should belong_to(:author).class_name('User') }
  7 + it { should have_many(:notes).dependent(:destroy) }
7 8 end
8 9  
9 10 describe "Validation" do
10   - it { should validate_presence_of(:title) }
11 11 it { should validate_presence_of(:author_id) }
12 12 it { should validate_presence_of(:project_id) }
  13 +
  14 + it { should validate_presence_of(:title) }
  15 + it { should ensure_length_of(:title).is_within(0..255) }
  16 +
13 17 it { should validate_presence_of(:file_name) }
  18 + it { should ensure_length_of(:title).is_within(0..255) }
  19 +
14 20 it { should validate_presence_of(:content) }
  21 + it { should ensure_length_of(:content).is_within(0..10_000) }
15 22 end
16 23 end
17   -# == Schema Information
18   -#
19   -# Table name: snippets
20   -#
21   -# id :integer(4) not null, primary key
22   -# title :string(255)
23   -# content :text
24   -# author_id :integer(4) not null
25   -# project_id :integer(4) not null
26   -# created_at :datetime not null
27   -# updated_at :datetime not null
28   -# file_name :string(255)
29   -# expires_at :datetime
30   -#
31   -
... ...
spec/models/user_spec.rb
... ... @@ -2,13 +2,26 @@ require &#39;spec_helper&#39;
2 2  
3 3 describe User do
4 4 describe "Associations" do
5   - it { should have_many(:projects) }
6 5 it { should have_many(:users_projects).dependent(:destroy) }
  6 + it { should have_many(:projects) }
  7 + it { should have_many(:my_own_projects).class_name('Project') }
  8 + it { should have_many(:keys).dependent(:destroy) }
  9 + it { should have_many(:events).class_name('Event').dependent(:destroy) }
  10 + it { should have_many(:recent_events).class_name('Event') }
7 11 it { should have_many(:issues).dependent(:destroy) }
  12 + it { should have_many(:notes).dependent(:destroy) }
8 13 it { should have_many(:assigned_issues).dependent(:destroy) }
9 14 it { should have_many(:merge_requests).dependent(:destroy) }
10 15 it { should have_many(:assigned_merge_requests).dependent(:destroy) }
11   - it { should have_many(:notes).dependent(:destroy) }
  16 + end
  17 +
  18 + describe 'validations' do
  19 + it { should validate_presence_of(:projects_limit) }
  20 + it { should validate_numericality_of(:projects_limit) }
  21 + it { should allow_value(0).for(:projects_limit) }
  22 + it { should_not allow_value(-1).for(:projects_limit) }
  23 +
  24 + it { should ensure_length_of(:bio).is_within(0..255) }
12 25 end
13 26  
14 27 describe "Respond to" do
... ... @@ -51,33 +64,3 @@ describe User do
51 64 user.authentication_token.should_not == ""
52 65 end
53 66 end
54   -# == Schema Information
55   -#
56   -# Table name: users
57   -#
58   -# id :integer(4) not null, primary key
59   -# email :string(255) default(""), not null
60   -# encrypted_password :string(128) default(""), not null
61   -# reset_password_token :string(255)
62   -# reset_password_sent_at :datetime
63   -# remember_created_at :datetime
64   -# sign_in_count :integer(4) default(0)
65   -# current_sign_in_at :datetime
66   -# last_sign_in_at :datetime
67   -# current_sign_in_ip :string(255)
68   -# last_sign_in_ip :string(255)
69   -# created_at :datetime not null
70   -# updated_at :datetime not null
71   -# name :string(255)
72   -# admin :boolean(1) default(FALSE), not null
73   -# projects_limit :integer(4) default(10)
74   -# skype :string(255) default(""), not null
75   -# linkedin :string(255) default(""), not null
76   -# twitter :string(255) default(""), not null
77   -# authentication_token :string(255)
78   -# dark_scheme :boolean(1) default(FALSE), not null
79   -# theme_id :integer(4) default(1), not null
80   -# bio :string(255)
81   -# blocked :boolean(1) default(FALSE), not null
82   -#
83   -
... ...
spec/models/users_project_spec.rb
... ... @@ -7,7 +7,11 @@ describe UsersProject do
7 7 end
8 8  
9 9 describe "Validation" do
  10 + let!(:users_project) { create(:users_project) }
  11 +
10 12 it { should validate_presence_of(:user_id) }
  13 + it { should validate_uniqueness_of(:user_id).scoped_to(:project_id) }
  14 +
11 15 it { should validate_presence_of(:project_id) }
12 16 end
13 17  
... ... @@ -16,15 +20,3 @@ describe UsersProject do
16 20 it { should respond_to(:user_email) }
17 21 end
18 22 end
19   -# == Schema Information
20   -#
21   -# Table name: users_projects
22   -#
23   -# id :integer(4) not null, primary key
24   -# user_id :integer(4) not null
25   -# project_id :integer(4) not null
26   -# created_at :datetime not null
27   -# updated_at :datetime not null
28   -# project_access :integer(4) default(0), not null
29   -#
30   -
... ...
spec/models/web_hook_spec.rb
... ... @@ -52,14 +52,3 @@ describe ProjectHook do
52 52 end
53 53 end
54 54 end
55   -# == Schema Information
56   -#
57   -# Table name: web_hooks
58   -#
59   -# id :integer(4) not null, primary key
60   -# url :string(255)
61   -# project_id :integer(4)
62   -# created_at :datetime not null
63   -# updated_at :datetime not null
64   -#
65   -
... ...
spec/models/wiki_spec.rb
... ... @@ -4,27 +4,13 @@ describe Wiki do
4 4 describe "Associations" do
5 5 it { should belong_to(:project) }
6 6 it { should belong_to(:user) }
  7 + it { should have_many(:notes).dependent(:destroy) }
7 8 end
8 9  
9 10 describe "Validation" do
10 11 it { should validate_presence_of(:title) }
  12 + it { should ensure_length_of(:title).is_within(1..250) }
11 13 it { should validate_presence_of(:content) }
12 14 it { should validate_presence_of(:user_id) }
13 15 end
14   -
15   - it { Factory(:wiki).should be_valid }
16 16 end
17   -# == Schema Information
18   -#
19   -# Table name: wikis
20   -#
21   -# id :integer(4) not null, primary key
22   -# title :string(255)
23   -# content :text
24   -# project_id :integer(4)
25   -# created_at :datetime not null
26   -# updated_at :datetime not null
27   -# slug :string(255)
28   -# user_id :integer(4)
29   -#
30   -
... ...
spec/roles/issue_commonality_spec.rb 0 → 100644
... ... @@ -0,0 +1,69 @@
  1 +require 'spec_helper'
  2 +
  3 +describe Issue, "IssueCommonality" do
  4 + let(:issue) { create(:issue) }
  5 +
  6 + describe "Associations" do
  7 + it { should belong_to(:project) }
  8 + it { should belong_to(:author) }
  9 + it { should belong_to(:assignee) }
  10 + it { should have_many(:notes).dependent(:destroy) }
  11 + end
  12 +
  13 + describe "Validation" do
  14 + it { should validate_presence_of(:project_id) }
  15 + it { should validate_presence_of(:author_id) }
  16 + it { should validate_presence_of(:title) }
  17 + it { should ensure_length_of(:title).is_at_least(0).is_at_most(255) }
  18 + end
  19 +
  20 + describe "Scope" do
  21 + it { described_class.should respond_to(:opened) }
  22 + it { described_class.should respond_to(:closed) }
  23 + it { described_class.should respond_to(:assigned) }
  24 + end
  25 +
  26 + it "has an :author_id_of_changes accessor" do
  27 + issue.should respond_to(:author_id_of_changes)
  28 + issue.should respond_to(:author_id_of_changes=)
  29 + end
  30 +
  31 + describe ".search" do
  32 + let!(:searchable_issue) { create(:issue, title: "Searchable issue") }
  33 +
  34 + it "matches by title" do
  35 + described_class.search('able').all.should == [searchable_issue]
  36 + end
  37 + end
  38 +
  39 + describe "#today?" do
  40 + it "returns true when created today" do
  41 + # Avoid timezone differences and just return exactly what we want
  42 + Date.stub(:today).and_return(issue.created_at.to_date)
  43 + issue.today?.should be_true
  44 + end
  45 +
  46 + it "returns false when not created today" do
  47 + Date.stub(:today).and_return(Date.yesterday)
  48 + issue.today?.should be_false
  49 + end
  50 + end
  51 +
  52 + describe "#new?" do
  53 + it "returns true when created today and record hasn't been updated" do
  54 + issue.stub(:today?).and_return(true)
  55 + issue.new?.should be_true
  56 + end
  57 +
  58 + it "returns false when not created today" do
  59 + issue.stub(:today?).and_return(false)
  60 + issue.new?.should be_false
  61 + end
  62 +
  63 + it "returns false when record has been updated" do
  64 + issue.stub(:today?).and_return(true)
  65 + issue.touch
  66 + issue.new?.should be_false
  67 + end
  68 + end
  69 +end
... ...
spec/roles/upvote_spec.rb 0 → 100644
... ... @@ -0,0 +1,27 @@
  1 +require 'spec_helper'
  2 +
  3 +describe Issue, "Upvote" do
  4 + let(:issue) { create(:issue) }
  5 +
  6 + it "with no notes has a 0/0 score" do
  7 + issue.upvotes.should == 0
  8 + end
  9 +
  10 + it "should recognize non-+1 notes" do
  11 + issue.notes << create(:note, note: "No +1 here")
  12 + issue.should have(1).note
  13 + issue.notes.first.upvote?.should be_false
  14 + issue.upvotes.should == 0
  15 + end
  16 +
  17 + it "should recognize a single +1 note" do
  18 + issue.notes << create(:note, note: "+1 This is awesome")
  19 + issue.upvotes.should == 1
  20 + end
  21 +
  22 + it "should recognize multiple +1 notes" do
  23 + issue.notes << create(:note, note: "+1 This is awesome")
  24 + issue.notes << create(:note, note: "+1 I want this")
  25 + issue.upvotes.should == 2
  26 + end
  27 +end
... ...
spec/support/matchers.rb
... ... @@ -28,6 +28,16 @@ RSpec::Matchers.define :be_404_for do |user|
28 28 end
29 29 end
30 30  
  31 +RSpec::Matchers.define :include_module do |expected|
  32 + match do
  33 + described_class.included_modules.include?(expected)
  34 + end
  35 +
  36 + failure_message_for_should do
  37 + "expected #{described_class} to include the #{expected} module"
  38 + end
  39 +end
  40 +
31 41 module UrlAccess
32 42 def url_allowed?(user, url)
33 43 emulate_user(user)
... ... @@ -57,3 +67,17 @@ module UrlAccess
57 67 login_with(user) if user
58 68 end
59 69 end
  70 +
  71 +# Extend shoulda-matchers
  72 +module Shoulda::Matchers::ActiveModel
  73 + class EnsureLengthOfMatcher
  74 + # Shortcut for is_at_least and is_at_most
  75 + def is_within(range)
  76 + if range.exclude_end?
  77 + is_at_least(range.first) && is_at_most(range.last - 1)
  78 + else
  79 + is_at_least(range.first) && is_at_most(range.last)
  80 + end
  81 + end
  82 + end
  83 +end
... ...