Files
codeocean/spec/models/exercise_spec.rb
Sebastian Serth 99bd46af1a Align project files with CodeHarbor
Since both projects are developed together and by the same team, we also want to have the same code structure and utility methods available in both projects. Therefore, this commit changes many files, but without a functional change.
2023-10-11 00:18:33 +02:00

171 lines
4.9 KiB
Ruby

# frozen_string_literal: true
require 'rails_helper'
RSpec.describe Exercise do
let(:exercise) { described_class.create.tap {|exercise| exercise.update(public: nil, token: nil) } }
let(:users) { create_list(:external_user, 10) }
def create_submissions
create_list(:submission, 10, cause: 'submit', exercise:, score: Forgery(:basic).number, contributor: users.sample)
end
it 'validates the number of main files' do
exercise = create(:dummy)
exercise.files += create_pair(:file)
expect(exercise).to receive(:valid_main_file?).and_call_original
exercise.save
expect(exercise.errors[:files]).to be_present
end
it 'validates the presence of a description' do
expect(exercise.errors[:description]).to be_present
end
it 'validates the presence of the public flag' do
expect(exercise.errors[:public]).to be_present
exercise.update(public: false)
expect(exercise.errors[:public]).to be_blank
end
it 'validates the presence of a title' do
expect(exercise.errors[:title]).to be_present
end
it 'validates the presence of a token' do
expect(exercise.errors[:token]).to be_present
end
it 'validates the presence of a user' do
expect(exercise.errors[:user]).to be_present
end
context 'when exercise is unpublished' do
subject { build(:dummy, unpublished: true) }
it { is_expected.not_to validate_presence_of(:execution_environment) }
end
context 'when exercise is not unpublished' do
subject { build(:dummy, unpublished: false) }
it { is_expected.to validate_presence_of(:execution_environment) }
end
context 'with uuid' do
subject { build(:dummy, uuid: SecureRandom.uuid) }
it { is_expected.to validate_uniqueness_of(:uuid).case_insensitive }
end
context 'without uuid' do
subject { build(:dummy, uuid: nil) }
it { is_expected.not_to validate_uniqueness_of(:uuid) }
end
describe '#average_percentage' do
let(:exercise) { create(:fibonacci) }
context 'without submissions' do
it 'returns nil' do
expect(exercise.average_percentage).to be 0
end
end
context 'with submissions' do
before { create_submissions }
it 'returns the average score expressed as a percentage' do
maximum_percentages = exercise.submissions.group_by do |s|
[s.contributor_type,
s.contributor_id]
end.values.map {|submission| submission.max_by(&:score).score / exercise.maximum_score * 100 }
expect(exercise.average_percentage).to eq(maximum_percentages.average.round(2))
end
end
end
describe '#average_score' do
let(:exercise) { create(:fibonacci) }
context 'without submissions' do
it 'returns nil' do
expect(exercise.average_score).to be 0.0
end
end
context 'with submissions' do
before { create_submissions }
it "returns the average of all users' maximum scores" do
maximum_scores = exercise.submissions.group_by do |s|
[s.contributor_type,
s.contributor_id]
end.values.map {|submission| submission.max_by(&:score).score }
expect(exercise.average_score).to be_within(0.1).of(maximum_scores.average)
end
end
end
describe '#duplicate' do
let(:exercise) { create(:fibonacci) }
after { exercise.duplicate }
it 'duplicates the exercise' do
expect(exercise).to receive(:dup).and_call_original
end
it 'overwrites the supplied attributes' do
title = Forgery(:basic).text
expect(exercise.duplicate(title:).title).to eq(title)
end
it 'duplicates all associated files' do
expect(exercise.files).to all(receive(:dup).and_call_original)
end
it 'returns the duplicated exercise' do
expect(exercise.duplicate).to be_a(described_class)
end
end
describe '#teacher_defined_assessment?' do
let(:exercise) { create(:dummy) }
context 'when no assessment is defined' do
it 'returns false' do
expect(exercise).not_to be_teacher_defined_assessment
end
end
context 'when unit tests are defined' do
before { create(:test_file, context: exercise) }
it 'returns true' do
expect(exercise.reload).to be_teacher_defined_assessment
end
end
context 'when linter tests are defined' do
before { create(:test_file, context: exercise, role: 'teacher_defined_linter') }
it 'returns true' do
expect(exercise.reload).to be_teacher_defined_assessment
end
end
context 'when unit and linter tests are defined' do
before do
create(:test_file, context: exercise)
create(:test_file, context: exercise, role: 'teacher_defined_linter')
end
it 'returns true' do
expect(exercise.reload).to be_teacher_defined_assessment
end
end
end
end