aboutsummaryrefslogtreecommitdiff
blob: 61e23a896ac87023355af13a8275963c2e28c186 (plain)
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
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
require 'spec_helper.rb'
describe Answer do

  include Permissions::TestPermissions

  it 'any user (not guest) should be allowed to create, read, update and delete owned answers' do
    for user in fabricate_all_roles
      new_answer = Factory(:answer, :owner => user)
      cud_allowed([user], new_answer)
      view_allowed([user], new_answer)
    end
  end

  it 'should be prohibited to create, update and delete answers someone else owns' do
    for user in fabricate_all_roles
      ud_denied(fabricate_all_roles + [Guest.new], Factory(:answer, :owner => user))
      # updatable_by? blocks changing db
      # mentor is covered in separate test
    end
  end

  it 'should be creatable by any logged in user' do
    for user in fabricate_all_roles
      new_answer = Answer.new(:owner => user)
      new_answer.should be_creatable_by user
    end
  end

  it 'should not be creatable by guest' do
    Factory(:answer).should_not be_creatable_by Guest.new
  end

  it 'should allow owner to edit answer as whole and content field' do
    for user in fabricate_all_roles
      new_answer = Answer.new(:owner => user)
      new_answer.should be_editable_by user
      new_answer.should be_editable_by user, :content
    end
  end

  it 'should prohibited editing of non-reference answer as whole and content field to non-owners' do
    for user in fabricate_all_roles
      new_answer = Answer.new(:owner => user)
      edit_denied(fabricate_all_roles, new_answer)
      edit_denied(fabricate_all_roles, new_answer, :content)
    end
  end

  it 'should be prohibited for non-recruiters to view answers someone else owns' do
    for user in fabricate_all_roles
      new_answer = Answer.new(:owner => user)
      view_denied(fabricate_users(:recruit, :mentor)+ [Guest.new], new_answer)
    end
  end

  it 'should be allowed for recruiters to view all answers' do
    for user in fabricate_all_roles
      new_answer = Answer.new(:owner => user)
      view_allowed(fabricate_users(:recruiter, :administrator), new_answer)
    end
  end

  it "should be viewable by mentor of it's owner" do
    mentor  = Factory(:mentor)
    recruit = Factory(:recruit, :mentor => mentor)
    new_answer = Factory(:answer, :owner => recruit)
    view_allowed([mentor], new_answer)
  end

  it { should belong_to(:question) }
  it { should have_readonly_attribute(:owner) }

  it "should prohibit CUD and view of reference ans to non-recruiters" do
    new_answer  = Factory(:answer, :reference => true)
    cud_denied(fabricate_users(:recruit, :mentor), new_answer)
    view_denied(fabricate_users(:recruit, :mentor), new_answer)
  end

  it "should allow CUD, view and edit of reference answers to recruiters" do
    new_answer  = Factory(:answer, :reference => true)
    cud_allowed(fabricate_users(:recruiter, :administrator), new_answer)
    edit_allowed(fabricate_users(:recruiter, :administrator), new_answer)
    edit_allowed(fabricate_users(:recruiter, :administrator), new_answer, :content)
  end

  it "should allow mentor of owner to approve and disapprove" do
    r = recruit_with_answers_in_categories(nil, 1, 1)
    answer = r.all_answers.first
    for i in 1..2
      answer.approved = !answer.approved
      answer.should be_updatable_by(r.mentor)
      answer.should be_editable_by(r.mentor)
      answer.should be_editable_by(r.mentor, :approved)
      answer.save!
    end
  end

  it "should prohibit mentor of owner to edit content" do
    answer  = Factory(:answer)

    answer.content      = "changed"
    answer.should_not   be_updatable_by(answer.owner.mentor)
  end

  it "should prohibit owner to save changed answer as approved" do
    answer  = Factory(:answer)

    answer.approved = true
    answer.save!

    answer.content  = "changed"
    answer.should_not be_updatable_by(answer.owner)
  end

  it "should allow owner to save changed answer as unapproved" do
    answer  = Factory(:answer)

    answer.approved = true
    answer.save!

    answer.content  = "changed"
    answer.approved = false
    answer.should be_updatable_by(answer.owner)
  end

  it "should mark questions with changed content as unapproved" do
    answer  = Factory(:answer)

    answer.approved = true
    answer.save!

    answer.content  = "changed"
    answer.save!
    answer.approved.should be_false
  end

  it "should send email notification to mentor when created" do
    question  = Factory(:question)
    recruit   = Factory(:recruit)

    #can't use Factory Girl here, because we want to save it after setting expectation to get email
    answer    = Answer.new(:owner => recruit, :question => question, :content => "Some answer.")

    UserMailer.should_receive_delayed(:deliver_new_answer, recruit.mentor, answer)

    answer.save!
  end

  it "should send email notification to mentor when changed" do
    answer = Factory(:answer)
    UserMailer.should_receive_delayed(:deliver_changed_answer, answer.owner.mentor, answer)
    answer.content = "changed"
    answer.save!
  end

  it "shouldn't try to send notifications to mentor of mentorless recruit" do
    recruit =  Factory(:recruit, :mentor => nil)
    UserMailer.should_not_receive(:deliver_changed_answer)
    answer  = Factory(:answer, :owner => recruit)
    answer.save!
    answer.content = "changed"
    answer.save!
  end

  it "should prohibit editing of reference and approved fields to recruits" do
    answer = Factory(:answer)
    answer.should_not be_editable_by(answer.owner, :approved)
    answer.should_not be_editable_by(answer.owner, :reference)
  end

  it "should return proper answers_of_mentored_by" do
    mentor    = Factory(:mentor)
    r1        = recruit_with_answers_in_categories(mentor)
    r2        = recruit_with_answers_in_categories(mentor)
    r3        = recruit_with_answers_in_categories

    for ans in (r1.all_answers + r2.all_answers)
      Answer.of_mentored_by(mentor).include?(ans).should be_true
    end

    for ans in r3.all_answers
      Answer.of_mentored_by(mentor).include?(ans).should be_false
    end
  end

  it "should return in_category" do
    n_categories = 5
    r = recruit_with_answers_in_categories(nil, n_categories)
    for i in 0..(n_categories-1)
      cat = r.categories[i]
      ans = r.answers_in_cat[i]

      for answer in ans
        Answer.in_category(cat).include?(answer).should be_true
      end

      for answer in r.all_answers - ans
        Answer.in_category(cat).include?(answer).should be_false
      end

      Answer.in_category(cat).should ==
        Answer.in_category(cat).uniq
    end
  end

  it "should allow only owner to change feedback" do
    ans     = Factory(:answer)
    owner   = ans.owner
    others  = fabricate_users(:administrator, :recruit, :mentor, :recruiter) + [Guest.new, ans.owner.mentor]

    ans.should be_editable_by(owner, :feedback)
    edit_denied(others, ans, :feedback)

    ans.feedback = 'changed'
    ans.should be_updatable_by(owner)
    ud_denied(others, ans)
  end

  it "should allow editing of reference only to recruiters on new answers" do
    answer = Answer.new(:reference => true, :owner => Factory(:recruiter))
    answer.should     be_editable_by(Factory(:recruiter), :reference)
    answer.should_not be_editable_by(Factory(:recruit), :reference)
    answer.should_not be_editable_by(Factory(:mentor), :reference)
    answer.should_not be_editable_by(Guest.new, :reference)
  end

  it "should produce proper answer from params" do
    ans_hash = { 'reference' => false, 'owner_id' => Factory(:recruit).id,
                  'approved' => false, 'content' => 'example' }
    produced_ans  = Answer.new_from("answer" => ans_hash)

    produced_ans.class.should == Answer
    for i in ans_hash
      if i[1]
        produced_ans.attributes[i[0]].should == i[1]
      else
        (!produced_ans.attributes[i[0]]).should be_true # it can be nil or false
      end
    end

    ans_hash = { 'reference' => false, 'owner_id' => Factory(:recruit).id,
                  'approved' => false, 'content' => 'example' }
    produced_ans  = Answer.new_from("multiple_choice_answer" => ans_hash)

    produced_ans.class.should == MultipleChoiceAnswer
    for i in ans_hash
      if i[1]
        produced_ans.attributes[i[0]].should == i[1]
      else
        (!produced_ans.attributes[i[0]]).should be_true # it can be nil or false
      end
    end
  end

  it "should produce proper updated answer from params" do
    ans = Factory(:answer)
    upd = Answer.update_from('id' => ans.id.to_s, 'answer' => { 'content' => 'changed' })
    upd['id'].should == ans.id
    upd['owner_id'].should == ans.owner_id
    upd['content'].should == 'changed'

    ans = Factory(:multiple_choice_answer)
    upd = Answer.update_from('id' => ans.id.to_s, 'multiple_choice_answer' => { 'content' => 'changed' })
    upd['id'].should == ans.id
    upd['owner_id'].should == ans.owner_id
    upd['content'].should == 'changed'
  end

  it "should properly return wrong answers of recruit" do
    recruit = Factory(:recruit)
    cat     = Factory(:category)
    q1      = Factory(:question_category, :category => cat).question
    q2      = Factory(:question_category, :category => cat).question
    q3      = Factory(:question_category, :category => cat).question
    q4      = Factory(:question_category, :category => cat).question

              Factory(:question_content_text, :question => q4)

    for i in [q1, q2, q3]
      Factory(:question_content_multiple_choice, :question => i)
      i.reload
      ["1", "2", "3"].each{ |j| Factory(:option, :option_owner => i.content, :content => j) }
      i.reload
      Factory(:multiple_choice_answer, :question => i,
              :options => [i.content.options.first.id], :reference => true)
    end

    wrong_ans = []
    not_wrong_ans = []

    wrong_ans.push Factory(:multiple_choice_answer, :question => q1,
                            :options => [q1.content.options.second.id], :owner => recruit)

    wrong_ans.push Factory(:multiple_choice_answer, :question => q2,
                            :options => [q1.content.options.first.id, q1.content.options.second.id],
                            :owner => recruit)

    not_wrong_ans.push Factory(:multiple_choice_answer, :question => q3,
                            :options => [q1.content.options.first.id])

    not_wrong_ans.push Factory(:answer, :question => q4,
                                :content => "wrong",
                                :owner => recruit)

    not_wrong_ans.push Factory(:answer, :question => q4,
                                :content => "good",
                                :reference => true)

    for i in wrong_ans
      Answer.wrong_answers_of(recruit).include?(i).should be_true
    end

    for i in not_wrong_ans
      Answer.wrong_answers_of(recruit).include?(i).should be_false
    end

    Answer.wrong_answers_of(recruit).count.should == Answer.wrong_answers_of(recruit).uniq.count
  end

  it "should prohibit mentor of owner to destroy" do
    a = Factory(:answer)
    a.should_not be_destroyable_by(a.owner.mentor)
  end

  it "should allow editing of reference only to recruiters" do
    for user in fabricate_users(:recruit, :mentor)
      Answer.new(:owner => user).should_not be_editable_by(user, :reference)
    end

    for user in fabricate_users(:recruiter, :administrator)
      Answer.new(:owner => user).should be_editable_by(user, :reference)
    end
  end

  it "should properly return answers with feedback" do

    with_feedback = (Answer.new.feedback.class.values - ['']).collect do |fb|
      Factory(:answer, :feedback => fb)
    end

    without_feedback = ['', nil].collect do |fb|
      Factory(:answer, :feedback => fb)
    end

    with_feedback.each{ |ans| Answer.with_some_feedback.include?(ans).should be_true }
    without_feedback.each{ |ans| Answer.with_some_feedback.include?(ans).should be_false }

    Answer.with_some_feedback.count.should == Answer.with_some_feedback.uniq.count
  end
end